From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794335330; b=DwAmBgQDFdUwTTJZx9CWwZP2pi1YYoFTAy0T4kvoof9Fh9WIfp+HmIWsWdnN7/jmu9sk Vvec4g3nnxmeIfbjdbFxc++ySMJCS95Eqg43XgpSAkGTnt8Z5n062ar9YfSi84Mu/1krO okUfKHNIFu6Wf2VXShxfAguOKu34eeRO+IuN1riCMTzoEH2ggNvMJuoG+sCszdajk08Ha alrttPN29OyztuCPo3I3doNbKjGEoyBcoX0yddb70hYsRXzPkMQtbFAEdoLwRACNc+NvH L8UnkG49ijDFCVmPqvgQNU36yL6UNsRnlAIdRwGHsFGYi5putfk7K8UvZx+ip+M90xQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794335330; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Type: Content-Transfer-Encoding; bh=g+GRgZV3YjEjziZCC12b2MMnsYYjt03Q/KADeCdOyto=; b=jtt1WJzoPR82o+QIe4ZsesXthRUhhwJnhN2wbHfp2yuOFhyOjvEqCloGOFYTlD8R1b/k evFlx+BIY9Dz4OcpCeIYHreF93/4xf4f5owWbgNd4vTIdhrPZtWcCmhNOwC9Z3rippyYN v32HDANK29AqdrtP+BT+yHEDBPAYlYAQ8o3k9pRU2VfjhRgQNtwLQwwVyJNPc0FzdFyNa riVYQm2PReBCrUX7MiqKaBdiQeAQezwrt9uIxffRkpxJU/4+iVD5cF6DRg0WHVEyxSPxO IMVpcdcb6DZOf8pRpsvRi8I0V0C4RqCoFcm8HRx5fj83lOY/YTZtGr9OAmPlYFabpCg== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=z5pdVRt6; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E9C6A606A321; Tue, 10 Nov 2026 18:28:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=z5pdVRt6 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 80E391F008A1; Tue, 10 Nov 2026 18:28:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794335327; bh=g+GRgZV3YjEjziZCC12b2MMnsYYjt03Q/KADeCdOyto=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=z5pdVRt678pp4ZTaK9VJ7zbfWnnGHK4ldbxkllk4msFfqAEFTcJltJ0+E91aKUDa3 yiIZdgH3eZKNecePcvVhbAl7kTa4oDuQE2yTTDAyvfNpGkZ/+Eyyle+Gf8HWV7S0wr /a2eYQTKL8lTDuRYn87unP8SZ9nv20gSs6oqiGrg= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org, akpm@linux-foundation.org, torvalds@linux-foundation.org, stable@vger.kernel.org Cc: lwn@lwn.net, jslaby@suse.cz, Greg Kroah-Hartman Subject: Re: Linux 6.18.63 Date: Tue, 10 Nov 2026 13:28:36 -0500 Message-ID: <2026111036-cringe-stylishly-9aca@gregkh> X-Mailer: git-send-email 2.56.0 In-Reply-To: <2026111036-racoon-landing-be00@gregkh> References: <2026111036-racoon-landing-be00@gregkh> X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit diff --git a/Documentation/devicetree/bindings/clock/nuvoton,ma35d1-clk.yaml b/Documentation/devicetree/bindings/clock/nuvoton,ma35d1-clk.yaml index 8f0c43683729..9649feda8d7a 100644 --- a/Documentation/devicetree/bindings/clock/nuvoton,ma35d1-clk.yaml +++ b/Documentation/devicetree/bindings/clock/nuvoton,ma35d1-clk.yaml @@ -29,7 +29,18 @@ properties: const: 1 clocks: - maxItems: 1 + minItems: 1 + maxItems: 2 + description: + The controller takes 2 crystal oscillator inputs from the board. + HXT is a 24 MHz crystal feeding the internal PLLs. LXT is a 32.768 + kHz crystal, for RTC and low power operations. + + clock-names: + minItems: 1 + items: + - const: hxt + - const: lxt nuvoton,pll-mode: description: @@ -58,6 +69,7 @@ examples: compatible = "nuvoton,ma35d1-clk"; reg = <0x40460200 0x100>; #clock-cells = <1>; - clocks = <&clk_hxt>; + clocks = <&clk_hxt>, <&clk_lxt>; + clock-names = "hxt", "lxt"; }; ... diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 27a861053b2f..9b8a1980bb54 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -1088,6 +1088,8 @@ tcp_tso_rtt_log - INTEGER If you want to use the old autosizing, set this sysctl to 0. + Possible values are [0, 31], inclusive. + Default: 9 (2^9 = 512 usec) tcp_pacing_ss_ratio - INTEGER @@ -3729,5 +3731,6 @@ l3mdev_accept - BOOLEAN max_dgram_qlen - INTEGER The maximum length of dgram socket receive queue - Default: 10 + Possible values: 0 - INT_MAX + Default: 10 diff --git a/Documentation/userspace-api/check_exec.rst b/Documentation/userspace-api/check_exec.rst index 05dfe3b56f71..0904810e1d8d 100644 --- a/Documentation/userspace-api/check_exec.rst +++ b/Documentation/userspace-api/check_exec.rst @@ -99,6 +99,10 @@ This secure bit may be set by user session managers, service managers, container runtimes, sandboxer tools... Except for test environments, the related ``SECBIT_EXEC_DENY_INTERACTIVE_LOCKED`` bit should also be set. +Both secure bits and their locks are inherited across :manpage:`fork(2)` and +:manpage:`execve(2)`, and they are kept when a task creates or joins a user +namespace. + Here is the expected behavior for a script interpreter according to combination of any exec securebits: diff --git a/Documentation/virt/hyperv/vmbus.rst b/Documentation/virt/hyperv/vmbus.rst index 654bb4849972..c546e821ce6b 100644 --- a/Documentation/virt/hyperv/vmbus.rst +++ b/Documentation/virt/hyperv/vmbus.rst @@ -141,14 +141,15 @@ Three functions exist to send VMBus channel messages: 1. vmbus_sendpacket(): Control-only messages and messages with embedded data -- no GPAs -2. vmbus_sendpacket_pagebuffer(): Message with list of GPAs - identifying data to transfer. An offset and length is - associated with each GPA so that multiple discontinuous areas - of guest memory can be targeted. -3. vmbus_sendpacket_mpb_desc(): Message with list of GPAs - identifying data to transfer. A single offset and length is - associated with a list of GPAs. The GPAs must describe a - single logical area of guest memory to be targeted. +2. vmbus_sendpacket_getid(): Similar to vmbus_sendpacket() but returns + a transaction ID that is matched against a reply from the Hyper-V + host. Useful when the struct completion (or other rendezvous data) + must reside on the caller's stack. By invalidating the transaction + ID before exiting the function due to a timeout or other error, a + late arriving interrupt is assured to not trash the stack. +3. vmbus_sendpacket_mpb_desc(): Message with one or more data ranges + to target. Each range consists of a single offset and length plus + a list of GPAs that describe a logical area of guest memory. Historically, Linux guests have trusted Hyper-V to send well-formed and valid messages, and Linux drivers for synthetic devices did not diff --git a/Makefile b/Makefile index ae234882e7e5..124ecd981272 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 18 -SUBLEVEL = 62 +SUBLEVEL = 63 EXTRAVERSION = NAME = Baby Opossum Posse diff --git a/arch/alpha/include/asm/mmu_context.h b/arch/alpha/include/asm/mmu_context.h index eee8fe836a59..09f356934b90 100644 --- a/arch/alpha/include/asm/mmu_context.h +++ b/arch/alpha/include/asm/mmu_context.h @@ -130,6 +130,8 @@ __get_new_mm_context(struct mm_struct *mm, long cpu) return next; } +extern void __load_new_mm_context(struct mm_struct *); + __EXTERN_INLINE void ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm, struct task_struct *next) @@ -139,6 +141,16 @@ ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm, unsigned long mmc; long cpu = smp_processor_id(); + /* + * kthread_use_mm(), sched_force_init_mm() and do_shoot_lazy_tlb() + * switch current's mm without alpha_switch_to(), which loads the + * context. The latter two require options Alpha does not select. + */ + if (next == current) { + __load_new_mm_context(next_mm); + return; + } + #ifdef CONFIG_SMP cpu_data[cpu].asn_lock = 1; barrier(); @@ -147,11 +159,16 @@ ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm, mmc = next_mm->context[cpu]; if ((mmc ^ asn) & ~HARDWARE_ASN_MASK) { mmc = __get_new_mm_context(next_mm, cpu); - next_mm->context[cpu] = mmc; + /* + * Ordered before any user access through the mm by the + * mb() in arch_spin_unlock(), when finish_lock_switch() + * drops the rq lock. + */ + WRITE_ONCE(next_mm->context[cpu], mmc); } #ifdef CONFIG_SMP - else - cpu_data[cpu].need_new_asn = 1; + /* A deferred shootdown can also invalidate a newly allocated ASN. */ + cpu_data[cpu].need_new_asn = 1; #endif /* Always update the PCB ASN. Another thread may have allocated @@ -160,7 +177,6 @@ ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm, task_thread_info(next)->pcb.asn = mmc & HARDWARE_ASN_MASK; } -extern void __load_new_mm_context(struct mm_struct *); asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr, long cause, struct pt_regs *regs); @@ -181,6 +197,17 @@ do { \ #define check_mmu_context() do { } while(0) #endif +/* + * Also called from kthread_use_mm() with preemption enabled. Alpha has + * no kernel preemption, so the task is still on the CPU that ran + * switch_mm(). + */ +#define finish_arch_post_lock_switch finish_arch_post_lock_switch +static inline void finish_arch_post_lock_switch(void) +{ + check_mmu_context(); +} + __EXTERN_INLINE void ev5_activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm) { diff --git a/arch/alpha/include/asm/sfp-machine.h b/arch/alpha/include/asm/sfp-machine.h index 5fe63afbd474..bff1ad963c68 100644 --- a/arch/alpha/include/asm/sfp-machine.h +++ b/arch/alpha/include/asm/sfp-machine.h @@ -59,6 +59,10 @@ R##_c = FP_CLS_NAN; \ } while (0) +/* Alpha determines tininess after rounding, so the emulation must do the + same as the hardware does for the results it produces itself. */ +#define _FP_TININESS_AFTER_ROUNDING 1 + /* Obtain the current rounding mode. */ #define FP_ROUNDMODE mode #define FP_RND_NEAREST (FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT) diff --git a/arch/alpha/include/asm/switch_to.h b/arch/alpha/include/asm/switch_to.h index 762b7f975310..35c4b2c9d992 100644 --- a/arch/alpha/include/asm/switch_to.h +++ b/arch/alpha/include/asm/switch_to.h @@ -9,7 +9,6 @@ extern struct task_struct *alpha_switch_to(unsigned long, struct task_struct *); #define switch_to(P,N,L) \ do { \ (L) = alpha_switch_to(virt_to_phys(&task_thread_info(N)->pcb), (P)); \ - check_mmu_context(); \ } while (0) #endif /* __ALPHA_SWITCH_TO_H */ diff --git a/arch/alpha/include/asm/tlbflush.h b/arch/alpha/include/asm/tlbflush.h index 0c8529997f54..9ae1902faf8e 100644 --- a/arch/alpha/include/asm/tlbflush.h +++ b/arch/alpha/include/asm/tlbflush.h @@ -87,7 +87,8 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { struct mm_struct *mm = vma->vm_mm; - if (mm == current->active_mm) + /* A targeted tbi() needs a thread of MM to be current. */ + if (mm == current->mm) flush_tlb_current_page(mm, vma, addr); else flush_tlb_other(mm); diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index ed06367ece57..11768aa292a4 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -625,12 +625,30 @@ static void ipi_flush_tlb_mm(void *x) { struct mm_struct *mm = x; - if (mm == current->active_mm && !asn_locked()) + if (mm == current->mm && !asn_locked()) flush_tlb_current(mm); else flush_tlb_other(mm); } +/* True if a CPU other than this one holds an ASN for MM. */ +static bool +mm_context_elsewhere(struct mm_struct *mm) +{ + int cpu, this_cpu = smp_processor_id(); + + /* Pairs with the barrier the publishing CPU issues before using MM. */ + smp_mb(); + + for_each_online_cpu(cpu) { + if (cpu == this_cpu) + continue; + if (READ_ONCE(mm->context[cpu])) + return true; + } + return false; +} + void flush_tlb_mm(struct mm_struct *mm) { @@ -638,17 +656,14 @@ flush_tlb_mm(struct mm_struct *mm) if (mm == current->active_mm) { flush_tlb_current(mm); - if (atomic_read(&mm->mm_users) <= 1) { - int cpu, this_cpu = smp_processor_id(); - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (!cpu_online(cpu) || cpu == this_cpu) - continue; - if (mm->context[cpu]) - mm->context[cpu] = 0; - } + if (atomic_read(&mm->mm_users) <= 1 && + !mm_context_elsewhere(mm)) { preempt_enable(); return; } + } else { + /* smp_call_function() does not call back into this CPU. */ + flush_tlb_other(mm); } smp_call_function(ipi_flush_tlb_mm, mm, 1); @@ -669,7 +684,8 @@ ipi_flush_tlb_page(void *x) struct flush_tlb_page_struct *data = x; struct mm_struct * mm = data->mm; - if (mm == current->active_mm && !asn_locked()) + /* A targeted tbi() needs a thread of MM to be current. */ + if (mm == current->mm && !asn_locked()) flush_tlb_current_page(mm, data->vma, data->addr); else flush_tlb_other(mm); @@ -683,19 +699,17 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) preempt_disable(); - if (mm == current->active_mm) { + /* As in ipi_flush_tlb_page(): a targeted tbi() needs MM current. */ + if (mm == current->mm) { flush_tlb_current_page(mm, vma, addr); - if (atomic_read(&mm->mm_users) <= 1) { - int cpu, this_cpu = smp_processor_id(); - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (!cpu_online(cpu) || cpu == this_cpu) - continue; - if (mm->context[cpu]) - mm->context[cpu] = 0; - } + if (atomic_read(&mm->mm_users) <= 1 && + !mm_context_elsewhere(mm)) { preempt_enable(); return; } + } else { + /* smp_call_function() does not call back into this CPU. */ + flush_tlb_other(mm); } data.vma = vma; @@ -720,7 +734,7 @@ static void ipi_flush_icache_page(void *x) { struct mm_struct *mm = (struct mm_struct *) x; - if (mm == current->active_mm && !asn_locked()) + if (mm == current->mm && !asn_locked()) __load_new_mm_context(mm); else flush_tlb_other(mm); @@ -739,17 +753,14 @@ flush_icache_user_page(struct vm_area_struct *vma, struct page *page, if (mm == current->active_mm) { __load_new_mm_context(mm); - if (atomic_read(&mm->mm_users) <= 1) { - int cpu, this_cpu = smp_processor_id(); - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (!cpu_online(cpu) || cpu == this_cpu) - continue; - if (mm->context[cpu]) - mm->context[cpu] = 0; - } + if (atomic_read(&mm->mm_users) <= 1 && + !mm_context_elsewhere(mm)) { preempt_enable(); return; } + } else { + /* smp_call_function() does not call back into this CPU. */ + flush_tlb_other(mm); } smp_call_function(ipi_flush_icache_page, mm, 1); diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index a9816bbc9f34..53e170e96591 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #define __EXTERN_INLINE inline @@ -45,7 +46,9 @@ __load_new_mm_context(struct mm_struct *next_mm) struct pcb_struct *pcb; mmc = __get_new_mm_context(next_mm, smp_processor_id()); - next_mm->context[smp_processor_id()] = mmc; + WRITE_ONCE(next_mm->context[smp_processor_id()], mmc); + /* Publish the context before this CPU can access the mm. */ + smp_mb(); pcb = ¤t_thread_info()->pcb; pcb->asn = mmc & HARDWARE_ASN_MASK; @@ -89,6 +92,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr, struct mm_struct *mm = current->mm; const struct exception_table_entry *fixup; int si_code = SEGV_MAPERR; + unsigned int lsb; vm_fault_t fault; unsigned int flags = FAULT_FLAG_DEFAULT; @@ -161,6 +165,8 @@ do_page_fault(unsigned long address, unsigned long mmcsr, goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; + else if (fault & (VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE)) + goto do_sigbus_mceerr; BUG(); } @@ -222,6 +228,21 @@ do_page_fault(unsigned long address, unsigned long mmcsr, goto no_context; return; + do_sigbus_mceerr: + mmap_read_unlock(mm); + if (!user_mode(regs)) + goto no_context; + /* + * Report the size of the poisoned area, which for a hugetlb fault + * is the size of the huge page that could not be mapped. + */ + lsb = PAGE_SHIFT; + if (fault & VM_FAULT_HWPOISON_LARGE) + lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); + show_signal_msg(regs, address, SIGBUS, "hardware memory error"); + force_sig_mceerr(BUS_MCEERR_AR, (void __user *) address, lsb); + return; + do_sigsegv: force_sig_fault(SIGSEGV, si_code, (void __user *) address); return; diff --git a/arch/alpha/mm/tlbflush.c b/arch/alpha/mm/tlbflush.c index ccbc317b9a34..a2aef90e6234 100644 --- a/arch/alpha/mm/tlbflush.c +++ b/arch/alpha/mm/tlbflush.c @@ -66,7 +66,7 @@ static void ipi_flush_mm_and_page(void *x) struct tlb_mm_and_addr *d = x; /* Part 1: mm context side (Alpha uses ASN/context as a key mechanism). */ - if (d->mm == current->active_mm && !asn_locked()) + if (d->mm == current->mm && !asn_locked()) __load_new_mm_context(d->mm); else flush_tlb_other(d->mm); @@ -90,22 +90,6 @@ void migrate_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) */ preempt_disable(); on_each_cpu(ipi_flush_mm_and_page, &d, 1); - - /* - * mimic flush_tlb_mm()'s mm_users<=1 optimization. - */ - if (atomic_read(&mm->mm_users) <= 1) { - - int cpu, this_cpu; - this_cpu = smp_processor_id(); - - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (!cpu_online(cpu) || cpu == this_cpu) - continue; - if (READ_ONCE(mm->context[cpu])) - WRITE_ONCE(mm->context[cpu], 0); - } - } preempt_enable(); } diff --git a/arch/arm/include/asm/linkage.h b/arch/arm/include/asm/linkage.h index c4670694ada7..bba992f5d7a8 100644 --- a/arch/arm/include/asm/linkage.h +++ b/arch/arm/include/asm/linkage.h @@ -9,4 +9,33 @@ .type name, %function; \ END(name) +#ifdef __ASSEMBLY__ + +/* + * Variants of SYM_TYPED_START/SYM_TYPED_FUNC_START that align the + * function entry itself instead of the kCFI type hash preceding it, + * for functions whose entry point must meet an alignment requirement, + * such as the 8-byte alignment fncpy() demands of its source. + */ +#ifdef CONFIG_CFI + +#define SYM_TYPED_START_ALIGNED(name, linkage, align) \ + linkage(name) ASM_NL \ + .balign align ASM_NL \ + .fill (align) - 4, 1, 0 ASM_NL \ + __CFI_TYPE(name) ASM_NL \ + name: + +#else /* CONFIG_CFI */ + +#define SYM_TYPED_START_ALIGNED(name, linkage, align) \ + SYM_START(name, linkage, .balign align) + +#endif /* CONFIG_CFI */ + +#define SYM_TYPED_FUNC_START_ALIGNED(name, align) \ + SYM_TYPED_START_ALIGNED(name, SYM_L_GLOBAL, align) + +#endif /* __ASSEMBLY__ */ + #endif diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index 8c05a7f374d8..84aa6a663e81 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -43,7 +43,7 @@ extern void set_smp_ipi_range(int ipi_base, int nr_ipi); * Called from platform specific assembly code, this is the * secondary CPU entry point. */ -asmlinkage void secondary_start_kernel(struct task_struct *task); +asmlinkage void secondary_start_kernel(void); /* diff --git a/arch/arm/kernel/cacheinfo.c b/arch/arm/kernel/cacheinfo.c index e1469b641780..993c8a134786 100644 --- a/arch/arm/kernel/cacheinfo.c +++ b/arch/arm/kernel/cacheinfo.c @@ -80,19 +80,21 @@ static void ci_leaf_init(struct cacheinfo *this_leaf, this_leaf->type = type; } -static int detect_cache_level(unsigned int *level_p, unsigned int *leaves_p) +static bool clidr_present(void) { - unsigned int ctype, level, leaves; - u32 ctr, format; - /* CLIDR is not present before ARMv7/v7m */ if (cpu_architecture() < CPU_ARCH_ARMv7) - return -EOPNOTSUPP; + return false; /* Don't try reading CLIDR if CTR declares old format */ - ctr = read_cpuid_cachetype(); - format = FIELD_GET(CTR_FORMAT_MASK, ctr); - if (format != CTR_FORMAT_ARMV7) + return FIELD_GET(CTR_FORMAT_MASK, read_cpuid_cachetype()) == CTR_FORMAT_ARMV7; +} + +static int detect_cache_level(unsigned int *level_p, unsigned int *leaves_p) +{ + unsigned int ctype, level, leaves; + + if (!clidr_present()) return -EOPNOTSUPP; for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) { @@ -111,13 +113,6 @@ static int detect_cache_level(unsigned int *level_p, unsigned int *leaves_p) return 0; } -int early_cache_level(unsigned int cpu) -{ - struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); - - return detect_cache_level(&this_cpu_ci->num_levels, &this_cpu_ci->num_leaves); -} - int init_cache_level(unsigned int cpu) { unsigned int level, leaves; @@ -146,26 +141,32 @@ int init_cache_level(unsigned int cpu) return 0; } +int early_cache_level(unsigned int cpu) +{ + return init_cache_level(cpu); +} + int populate_cache_leaves(unsigned int cpu) { unsigned int level, idx; enum cache_type type; struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); - struct cacheinfo *this_leaf = this_cpu_ci->info_list; - unsigned int arch = cpu_architecture(); + struct cacheinfo *infos = this_cpu_ci->info_list; - /* CLIDR is not present before ARMv7/v7m */ - if (arch < CPU_ARCH_ARMv7) - return -EOPNOTSUPP; + /* The device tree can describe caches CLIDR cannot fill in. */ + if (!clidr_present()) + return -ENOENT; for (idx = 0, level = 1; level <= this_cpu_ci->num_levels && - idx < this_cpu_ci->num_leaves; idx++, level++) { + idx < this_cpu_ci->num_leaves; level++) { type = get_cache_type(level); if (type == CACHE_TYPE_SEPARATE) { - ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level); - ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level); + if (idx + 1 >= this_cpu_ci->num_leaves) + break; + ci_leaf_init(&infos[idx++], CACHE_TYPE_DATA, level); + ci_leaf_init(&infos[idx++], CACHE_TYPE_INST, level); } else { - ci_leaf_init(this_leaf++, type, level); + ci_leaf_init(&infos[idx++], type, level); } } diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index b9d6818f1ee1..f80bbfbd3a6f 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S @@ -116,6 +116,7 @@ ENTRY(secondary_startup) ldr r7, __secondary_data @ reload r7 ldr sp, [r7, #12] @ set up the stack pointer ldr r0, [r7, #16] @ set up task pointer + set_current r0, r1 mov fp, #0 b secondary_start_kernel ENDPROC(secondary_startup) diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index f22c50d4bd41..a22403a629ef 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -442,6 +442,7 @@ ENTRY(__secondary_switched) adr_l r7, secondary_data + 12 @ get secondary_data.stack ldr sp, [r7] ldr r0, [r7, #4] @ get secondary_data.task + set_current r0, r1 mov fp, #0 b secondary_start_kernel ENDPROC(__secondary_switched) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 50999886a8b5..e30206365877 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -371,12 +371,9 @@ void __noreturn arch_cpu_idle_dead(void) */ __asm__("mov sp, %0\n" " mov fp, #0\n" - " mov r0, %1\n" " b secondary_start_kernel" : - : "r" (task_stack_page(current) + THREAD_SIZE - 8), - "r" (current) - : "r0"); + : "r" (task_stack_page(current) + THREAD_SIZE - 8)); unreachable(); } @@ -397,23 +394,15 @@ static void smp_store_cpu_info(unsigned int cpuid) check_cpu_icache_size(cpuid); } -static void set_current(struct task_struct *cur) -{ - /* Set TPIDRURO */ - asm("mcr p15, 0, %0, c13, c0, 3" :: "r"(cur) : "memory"); -} - /* * This is the secondary CPU boot entry. We're using this CPUs * idle thread stack, but a set of temporary page tables. */ -asmlinkage void secondary_start_kernel(struct task_struct *task) +asmlinkage void secondary_start_kernel(void) { struct mm_struct *mm = &init_mm; unsigned int cpu; - set_current(task); - secondary_biglittle_init(); /* diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index 2336ee2aa44a..e6b50cd43ce5 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -238,8 +239,20 @@ void store_cpu_topology(unsigned int cpuid) */ void __init init_cpu_topology(void) { + int cpu, ret; + reset_cpu_topology(); smp_wmb(); parse_dt_topology(); + + for_each_possible_cpu(cpu) { + ret = fetch_cache_info(cpu); + if (!ret) + continue; + /* CPUs without a usable CLIDR return -EOPNOTSUPP. */ + if (ret != -ENOENT && ret != -EOPNOTSUPP) + pr_err("Early cacheinfo failed, ret = %d\n", ret); + return; + } } diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c index a671ca498f88..3c73e2cdb8ce 100644 --- a/arch/arm/mach-imx/pm-imx6.c +++ b/arch/arm/mach-imx/pm-imx6.c @@ -4,6 +4,8 @@ * Copyright 2011 Linaro Ltd. */ +#include +#include #include #include #include @@ -18,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -61,9 +64,9 @@ #define MX6Q_SUSPEND_OCRAM_SIZE 0x1000 #define MX6_MAX_MMDC_IO_NUM 33 -static void __iomem *ccm_base; -static void __iomem *suspend_ocram_base; -static void (*imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase); +static void __iomem *ccm_base __ro_after_init; +static void __iomem *suspend_ocram_base __ro_after_init; +static void (*imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase) __ro_after_init; /* * suspend ocram space layout: @@ -229,8 +232,18 @@ struct imx6_cpu_pm_info { struct imx6_pm_base l2_base; u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */ u32 mmdc_io_val[MX6_MAX_MMDC_IO_NUM][2]; /* To save offset and value */ + u32 cfi_type; /* kCFI type hash of imx6_suspend() */ } __aligned(8); +/* + * The ocram copy of imx6_suspend() starts right after struct imx6_cpu_pm_info, + * and the CFI check on the indirect call reads the kCFI type hash from the + * four bytes preceding the function entry, so cfi_type must occupy the last + * four bytes of the struct, i.e. fit into its tail padding. + */ +static_assert(offsetofend(struct imx6_cpu_pm_info, cfi_type) == + sizeof(struct imx6_cpu_pm_info)); + void imx6_set_int_mem_clk_lpm(bool enable) { u32 val = readl_relaxed(ccm_base + CGPR); @@ -568,6 +581,13 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) mmdc_offset_array[i]); } + /* + * Mask out the Thumb bit, as cfi_get_func_hash() expects the + * function's actual start address. Returns 0 if CONFIG_CFI=n. + */ + pm_info->cfi_type = + cfi_get_func_hash((void *)((uintptr_t)&imx6_suspend & ~1UL)); + imx6_suspend_in_ocram_fn = fncpy( suspend_ocram_base + sizeof(*pm_info), &imx6_suspend, diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S index 63ccc2d0e920..95d5f723ea0e 100644 --- a/arch/arm/mach-imx/suspend-imx6.S +++ b/arch/arm/mach-imx/suspend-imx6.S @@ -3,6 +3,7 @@ * Copyright 2014 Freescale Semiconductor, Inc. */ +#include #include #include #include @@ -148,7 +149,8 @@ .endm -ENTRY(imx6_suspend) +/* fncpy() requires an 8-byte-aligned entry; see arch/arm/include/asm/fncpy.h */ +SYM_TYPED_FUNC_START_ALIGNED(imx6_suspend, 8) ldr r1, [r0, #PM_INFO_PBASE_OFFSET] ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET] ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET] @@ -329,4 +331,4 @@ resume: resume_mmdc ret lr -ENDPROC(imx6_suspend) +SYM_FUNC_END(imx6_suspend) diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 812380f30ae3..2b470a419dda 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -341,6 +341,8 @@ static int do_alignment_ldrhstrh(unsigned long addr, u32 instr, struct pt_regs *regs) { unsigned int rd = RD_BITS(instr); + unsigned int ua_flags; + bool ua_saved = false; ai_half += 1; @@ -364,10 +366,11 @@ do_alignment_ldrhstrh(unsigned long addr, u32 instr, struct pt_regs *regs) user: if (LDST_L_BIT(instr)) { unsigned long val; - unsigned int __ua_flags = uaccess_save_and_enable(); + ua_flags = uaccess_save_and_enable(); + ua_saved = true; get16t_unaligned_check(val, addr); - uaccess_restore(__ua_flags); + uaccess_restore(ua_flags); /* signed half-word? */ if (instr & 0x40) @@ -375,14 +378,17 @@ do_alignment_ldrhstrh(unsigned long addr, u32 instr, struct pt_regs *regs) regs->uregs[rd] = val; } else { - unsigned int __ua_flags = uaccess_save_and_enable(); + ua_flags = uaccess_save_and_enable(); + ua_saved = true; put16t_unaligned_check(regs->uregs[rd], addr); - uaccess_restore(__ua_flags); + uaccess_restore(ua_flags); } return TYPE_LDST; fault: + if (ua_saved) + uaccess_restore(ua_flags); return TYPE_FAULT; } @@ -391,6 +397,8 @@ do_alignment_ldrdstrd(unsigned long addr, u32 instr, struct pt_regs *regs) { unsigned int rd = RD_BITS(instr); unsigned int rd2; + unsigned int ua_flags; + bool ua_saved = false; int load; if ((instr & 0xfe000000) == 0xe8000000) { @@ -425,26 +433,30 @@ do_alignment_ldrdstrd(unsigned long addr, u32 instr, struct pt_regs *regs) user: if (load) { unsigned long val, val2; - unsigned int __ua_flags = uaccess_save_and_enable(); + ua_flags = uaccess_save_and_enable(); + ua_saved = true; get32t_unaligned_check(val, addr); get32t_unaligned_check(val2, addr + 4); - uaccess_restore(__ua_flags); + uaccess_restore(ua_flags); regs->uregs[rd] = val; regs->uregs[rd2] = val2; } else { - unsigned int __ua_flags = uaccess_save_and_enable(); + ua_flags = uaccess_save_and_enable(); + ua_saved = true; put32t_unaligned_check(regs->uregs[rd], addr); put32t_unaligned_check(regs->uregs[rd2], addr + 4); - uaccess_restore(__ua_flags); + uaccess_restore(ua_flags); } return TYPE_LDST; bad: return TYPE_ERROR; fault: + if (ua_saved) + uaccess_restore(ua_flags); return TYPE_FAULT; } @@ -452,6 +464,8 @@ static int do_alignment_ldrstr(unsigned long addr, u32 instr, struct pt_regs *regs) { unsigned int rd = RD_BITS(instr); + unsigned int ua_flags; + bool ua_saved = false; ai_word += 1; @@ -469,18 +483,22 @@ do_alignment_ldrstr(unsigned long addr, u32 instr, struct pt_regs *regs) trans: if (LDST_L_BIT(instr)) { unsigned int val; - unsigned int __ua_flags = uaccess_save_and_enable(); + ua_flags = uaccess_save_and_enable(); + ua_saved = true; get32t_unaligned_check(val, addr); - uaccess_restore(__ua_flags); + uaccess_restore(ua_flags); regs->uregs[rd] = val; } else { - unsigned int __ua_flags = uaccess_save_and_enable(); + ua_flags = uaccess_save_and_enable(); + ua_saved = true; put32t_unaligned_check(regs->uregs[rd], addr); - uaccess_restore(__ua_flags); + uaccess_restore(ua_flags); } return TYPE_LDST; fault: + if (ua_saved) + uaccess_restore(ua_flags); return TYPE_FAULT; } @@ -502,6 +520,8 @@ do_alignment_ldmstm(unsigned long addr, u32 instr, struct pt_regs *regs) { unsigned int rd, rn, correction, nr_regs, regbits; unsigned long eaddr, newaddr; + unsigned int ua_flags; + bool ua_saved = false; if (LDM_S_BIT(instr)) goto bad; @@ -547,7 +567,8 @@ do_alignment_ldmstm(unsigned long addr, u32 instr, struct pt_regs *regs) #endif if (user_mode(regs)) { - unsigned int __ua_flags = uaccess_save_and_enable(); + ua_flags = uaccess_save_and_enable(); + ua_saved = true; for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1) if (regbits & 1) { @@ -559,7 +580,7 @@ do_alignment_ldmstm(unsigned long addr, u32 instr, struct pt_regs *regs) put32t_unaligned_check(regs->uregs[rd], eaddr); eaddr += 4; } - uaccess_restore(__ua_flags); + uaccess_restore(ua_flags); } else { for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1) @@ -581,6 +602,8 @@ do_alignment_ldmstm(unsigned long addr, u32 instr, struct pt_regs *regs) return TYPE_DONE; fault: + if (ua_saved) + uaccess_restore(ua_flags); regs->ARM_pc -= correction; return TYPE_FAULT; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-ivy.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-verdin-ivy.dtsi index 29075ff5eda6..b64751aa31d5 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-verdin-ivy.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-ivy.dtsi @@ -270,8 +270,8 @@ &gpio3 { "", "", "", - "DIG_1", /* SODIMM 56 */ - "DIG_2", /* SODIMM 58 */ + "DIGI_1", /* SODIMM 56 */ + "DIGI_2", /* SODIMM 58 */ "REL1", /* SODIMM 60 */ "REL2", /* SODIMM 62 */ "", /* 10 */ diff --git a/arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc.dtsi index bebe19eb360f..576da7875601 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-toradex-smarc.dtsi @@ -323,7 +323,7 @@ &gpio3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lvds_dsi_sel>; gpio-line-names = "ETH_0_INT#", /* 0 */ - "SLEEP#", + "SMARC_SLEEP#", "", "", "", diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-ivy.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin-ivy.dtsi index db1b4ee7728c..bf021e85cfc9 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-verdin-ivy.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-ivy.dtsi @@ -333,8 +333,8 @@ &gpio3 { "", "", "", - "DIG_1", /* SODIMM 56 */ - "DIG_2", /* SODIMM 58 */ + "DIGI_1", /* SODIMM 56 */ + "DIGI_2", /* SODIMM 58 */ "REL1", /* SODIMM 60 */ "REL2", /* SODIMM 62 */ "", /* 10 */ diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-yavia.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin-yavia.dtsi index cc389cda2af2..20d99012d4f3 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-verdin-yavia.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-yavia.dtsi @@ -117,6 +117,11 @@ &flexcan1 { status = "okay"; }; +&gpio3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpios_ext_yavia>; +}; + &gpio4 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ctrl_sleep_moci>; @@ -262,7 +267,7 @@ MX8MP_IOMUXC_NAND_DATA03__GPIO3_IO09 0x106 /* SODIMM 62 */ pinctrl_gpios_ext_yavia: gpiosextyaviagrp { fsl,pins = < - MX8MP_IOMUXC_NAND_CE1_B__GPIO3_IO02 0x106 /* SODIMM 64 */ + MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16 0x106 /* SODIMM 64 */ MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14 0x106 /* SODIMM 66 */ >; }; diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi index 6786e5b590e8..df5f7d831d81 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi @@ -653,6 +653,7 @@ cpu_trip_active_low: active-low { timer { compatible = "arm,armv8-timer"; interrupt-parent = <&gic>; + clock-frequency = <12986200>; interrupts = , , , diff --git a/arch/arm64/boot/dts/qcom/ipq9574.dtsi b/arch/arm64/boot/dts/qcom/ipq9574.dtsi index 86c9cb9fffc9..d3895259f25c 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq9574.dtsi @@ -432,7 +432,7 @@ gcc: clock-controller@1800000 { <&pcie1_phy>, <&pcie2_phy>, <&pcie3_phy>, - <0>; + <&usb_0_qmpphy>; #clock-cells = <1>; #reset-cells = <1>; #interconnect-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi index dbd5f08b5cdd..3db935a7442e 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi @@ -27,6 +27,7 @@ /delete-node/ &slpi_mem; /delete-node/ &spss_mem; /delete-node/ &rmtfs_mem; +/delete-node/ &xbl_mem; / { chassis-type = "handset"; @@ -55,6 +56,11 @@ key-vol-up { /* Reserved memory changes from downstream */ reserved-memory { + xbl-mem@85d00000 { + reg = <0 0x85d00000 0 0x200000>; + no-map; + }; + tz_mem: memory@86200000 { reg = <0 0x86200000 0 0x4900000>; no-map; diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts index 1c50a0563bc4..8fc7cbc087ed 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts @@ -32,6 +32,7 @@ /delete-node/ &mba_region; /delete-node/ &slpi_mem; /delete-node/ &spss_mem; +/delete-node/ &xbl_mem; / { model = "Xiaomi Mi MIX 2S"; @@ -63,6 +64,11 @@ key-vol-up { }; reserved-memory { + xbl-mem@85d00000 { + reg = <0 0x85d00000 0 0x200000>; + no-map; + }; + adsp_mem: memory@8c500000 { reg = <0 0x8c500000 0 0x1e00000>; no-map; diff --git a/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts b/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts index 5ed757c19db6..fc79641d7bb5 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts @@ -86,7 +86,7 @@ main_mmc0_pins_default: main-mmc0-default-pins { bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x220, PIN_INPUT, 0) /* (V3) MMC0_CMD */ - AM62X_IOPAD(0x218, PIN_INPUT, 0) /* (Y1) MMC0_CLK */ + AM62X_IOPAD(0x218, PIN_OUTPUT, 0) /* (Y1) MMC0_CLK */ AM62X_IOPAD(0x214, PIN_INPUT, 0) /* (V2) MMC0_DAT0 */ AM62X_IOPAD(0x210, PIN_INPUT_PULLUP, 0) /* (V1) MMC0_DAT1 */ AM62X_IOPAD(0x20c, PIN_INPUT_PULLUP, 0) /* (W2) MMC0_DAT2 */ diff --git a/arch/arm64/boot/dts/ti/k3-am62-phycore-som.dtsi b/arch/arm64/boot/dts/ti/k3-am62-phycore-som.dtsi index eeca643fedbe..19ac2dbe66cb 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-phycore-som.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-phycore-som.dtsi @@ -146,7 +146,7 @@ AM62X_IOPAD(0x15c, PIN_INPUT, 0) /* (AB22) MDIO0_MDIO */ main_mmc0_pins_default: main-mmc0-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x220, PIN_INPUT_PULLUP, 0) /* (Y3) MMC0_CMD */ - AM62X_IOPAD(0x218, PIN_INPUT_PULLDOWN, 0) /* (AB1) MMC0_CLK */ + AM62X_IOPAD(0x218, PIN_OUTPUT_PULLDOWN, 0) /* (AB1) MMC0_CLK */ AM62X_IOPAD(0x214, PIN_INPUT_PULLUP, 0) /* (AA2) MMC0_DAT0 */ AM62X_IOPAD(0x210, PIN_INPUT_PULLUP, 0) /* (AA1) MMC0_DAT1 */ AM62X_IOPAD(0x20c, PIN_INPUT_PULLUP, 0) /* (AA3) MMC0_DAT2 */ diff --git a/arch/arm64/boot/dts/ti/k3-am62-pocketbeagle2.dts b/arch/arm64/boot/dts/ti/k3-am62-pocketbeagle2.dts index 7a4cffc27bda..1c691629d4ad 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-pocketbeagle2.dts +++ b/arch/arm64/boot/dts/ti/k3-am62-pocketbeagle2.dts @@ -235,7 +235,7 @@ AM62X_IOPAD(0x0020, PIN_OUTPUT, 3) /* (J25) OSPI0_D5.UART6_TXD */ main_mmc1_pins_default: main-mmc1-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x23c, PIN_INPUT, 0) /* (A21/C18) MMC1_CMD */ - AM62X_IOPAD(0x234, PIN_INPUT, 0) /* (B22/A20) MMC1_CLK */ + AM62X_IOPAD(0x234, PIN_OUTPUT, 0) /* (B22/A20) MMC1_CLK */ AM62X_IOPAD(0x230, PIN_INPUT, 0) /* (A22/A19) MMC1_DAT0 */ AM62X_IOPAD(0x22c, PIN_INPUT, 0) /* (B21/B19) MMC1_DAT1 */ AM62X_IOPAD(0x228, PIN_INPUT, 0) /* (C21/B20) MMC1_DAT2 */ diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi index 059ec492a973..5e8830fffb94 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi @@ -573,7 +573,7 @@ AM62X_IOPAD(0x15c, PIN_INPUT, 0) /* (AB22) MDIO0_MDIO */ /* ETH_1_MDIO, SODIMM pinctrl_sdhci0: main-mmc0-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x220, PIN_INPUT, 0) /* (Y3) MMC0_CMD */ - AM62X_IOPAD(0x218, PIN_INPUT, 0) /* (AB1) MMC0_CLK */ + AM62X_IOPAD(0x218, PIN_OUTPUT, 0) /* (AB1) MMC0_CLK */ AM62X_IOPAD(0x214, PIN_INPUT, 0) /* (AA2) MMC0_DAT0 */ AM62X_IOPAD(0x210, PIN_INPUT_PULLUP, 0) /* (AA1) MMC0_DAT1 */ AM62X_IOPAD(0x20c, PIN_INPUT_PULLUP, 0) /* (AA3) MMC0_DAT2 */ @@ -589,7 +589,7 @@ AM62X_IOPAD(0x1f8, PIN_INPUT_PULLUP, 0) /* (AC2) MMC0_DAT7 */ pinctrl_sdhci1: main-mmc1-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x23c, PIN_INPUT, 0) /* (A21) MMC1_CMD */ /* SODIMM 74 */ - AM62X_IOPAD(0x234, PIN_INPUT, 0) /* (B22) MMC1_CLK */ /* SODIMM 78 */ + AM62X_IOPAD(0x234, PIN_OUTPUT, 0) /* (B22) MMC1_CLK */ /* SODIMM 78 */ AM62X_IOPAD(0x230, PIN_INPUT, 0) /* (A22) MMC1_DAT0 */ /* SODIMM 80 */ AM62X_IOPAD(0x22c, PIN_INPUT, 0) /* (B21) MMC1_DAT1 */ /* SODIMM 82 */ AM62X_IOPAD(0x228, PIN_INPUT, 0) /* (C21) MMC1_DAT2 */ /* SODIMM 70 */ @@ -601,7 +601,7 @@ AM62X_IOPAD(0x224, PIN_INPUT, 0) /* (D22) MMC1_DAT3 */ /* SODIMM 72 */ pinctrl_sdhci2: main-mmc2-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x120, PIN_INPUT, 0) /* (C24) MMC2_CMD */ /* WiFi_SDIO_CMD */ - AM62X_IOPAD(0x118, PIN_INPUT, 0) /* (D25) MMC2_CLK */ /* WiFi_SDIO_CLK */ + AM62X_IOPAD(0x118, PIN_OUTPUT,0) /* (D25) MMC2_CLK */ /* WiFi_SDIO_CLK */ AM62X_IOPAD(0x114, PIN_INPUT, 0) /* (B24) MMC2_DAT0 */ /* WiFi_SDIO_DATA0 */ AM62X_IOPAD(0x110, PIN_INPUT, 0) /* (C25) MMC2_DAT1 */ /* WiFi_SDIO_DATA1 */ AM62X_IOPAD(0x10c, PIN_INPUT, 0) /* (E23) MMC2_DAT2 */ /* WiFi_SDIO_DATA2 */ diff --git a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts index 7028d9835c4a..5d05f4b9a6d9 100644 --- a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts @@ -323,7 +323,7 @@ emmc_pins_default: emmc-default-pins { bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x0220, PIN_INPUT, 0) /* (Y3) MMC0_CMD */ - AM62X_IOPAD(0x0218, PIN_INPUT, 0) /* (AB1) MMC0_CLK */ + AM62X_IOPAD(0x0218, PIN_OUTPUT, 0) /* (AB1) MMC0_CLK */ AM62X_IOPAD(0x0214, PIN_INPUT, 0) /* (AA2) MMC0_DAT0 */ AM62X_IOPAD(0x0210, PIN_INPUT, 0) /* (AA1) MMC0_DAT1 */ AM62X_IOPAD(0x020c, PIN_INPUT, 0) /* (AA3) MMC0_DAT2 */ @@ -346,7 +346,7 @@ sd_pins_default: sd-default-pins { bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x023c, PIN_INPUT, 0) /* (A21) MMC1_CMD */ - AM62X_IOPAD(0x0234, PIN_INPUT, 0) /* (B22) MMC1_CLK */ + AM62X_IOPAD(0x0234, PIN_OUTPUT, 0) /* (B22) MMC1_CLK */ AM62X_IOPAD(0x0230, PIN_INPUT, 0) /* (A22) MMC1_DAT0 */ AM62X_IOPAD(0x022c, PIN_INPUT, 0) /* (B21) MMC1_DAT1 */ AM62X_IOPAD(0x0228, PIN_INPUT, 0) /* (C21) MMC1_DAT2 */ @@ -358,7 +358,7 @@ AM62X_IOPAD(0x0240, PIN_INPUT, 7) /* (D17) MMC1_SDCD.GPIO1_48 */ wifi_pins_default: wifi-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x0120, PIN_INPUT, 0) /* (C24) MMC2_CMD */ - AM62X_IOPAD(0x0118, PIN_INPUT, 0) /* (D25) MMC2_CLK */ + AM62X_IOPAD(0x0118, PIN_OUTPUT, 0) /* (D25) MMC2_CLK */ AM62X_IOPAD(0x0114, PIN_INPUT, 0) /* (B24) MMC2_DAT0 */ AM62X_IOPAD(0x0110, PIN_INPUT, 0) /* (C25) MMC2_DAT1 */ AM62X_IOPAD(0x010c, PIN_INPUT, 0) /* (E23) MMC2_DAT2 */ diff --git a/arch/arm64/boot/dts/ti/k3-am625-sk-common.dtsi b/arch/arm64/boot/dts/ti/k3-am625-sk-common.dtsi index fe0b98e1d105..d492ff34c5b1 100644 --- a/arch/arm64/boot/dts/ti/k3-am625-sk-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am625-sk-common.dtsi @@ -98,7 +98,7 @@ main_mmc0_pins_default: main-mmc0-default-pins { bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x220, PIN_INPUT, 0) /* (Y3) MMC0_CMD */ - AM62X_IOPAD(0x218, PIN_INPUT, 0) /* (AB1) MMC0_CLK */ + AM62X_IOPAD(0x218, PIN_OUTPUT, 0) /* (AB1) MMC0_CLK */ AM62X_IOPAD(0x214, PIN_INPUT, 0) /* (AA2) MMC0_DAT0 */ AM62X_IOPAD(0x210, PIN_INPUT_PULLUP, 0) /* (AA1) MMC0_DAT1 */ AM62X_IOPAD(0x20c, PIN_INPUT_PULLUP, 0) /* (AA3) MMC0_DAT2 */ diff --git a/arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi index b3d012a5a26a..9da48a54855e 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi @@ -120,7 +120,7 @@ AM62AX_IOPAD(0x15c, PIN_INPUT, 0) /* (V13) MDIO0_MDIO */ main_mmc0_pins_default: main-mmc0-default-pins { pinctrl-single,pins = < AM62AX_IOPAD(0x220, PIN_INPUT_PULLUP, 0) /* (Y6) MMC0_CMD */ - AM62AX_IOPAD(0x218, PIN_INPUT_PULLDOWN, 0) /* (AB7) MMC0_CLK */ + AM62AX_IOPAD(0x218, PIN_OUTPUT_PULLDOWN, 0) /* (AB7) MMC0_CLK */ AM62AX_IOPAD(0x214, PIN_INPUT_PULLUP, 0) /* (AA6) MMC0_DAT0 */ AM62AX_IOPAD(0x210, PIN_INPUT_PULLUP, 0) /* (AB6) MMC0_DAT1 */ AM62AX_IOPAD(0x20c, PIN_INPUT_PULLUP, 0) /* (Y7) MMC0_DAT2 */ diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts index a902b8806209..17ae6f0ceecf 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts @@ -313,8 +313,7 @@ AM62AX_IOPAD(0x0b4, PIN_INPUT_PULLUP, 1) /* (K24) GPMC0_CSn3.I2C2_SDA */ main_mmc0_pins_default: main-mmc0-default-pins { pinctrl-single,pins = < AM62AX_IOPAD(0x220, PIN_INPUT, 0) /* (Y3) MMC0_CMD */ - AM62AX_IOPAD(0x218, PIN_INPUT, 0) /* (AB1) MMC0_CLKLB */ - AM62AX_IOPAD(0x21c, PIN_INPUT, 0) /* (AB1) MMC0_CLK */ + AM62AX_IOPAD(0x218, PIN_OUTPUT, 0) /* (AB1) MMC0_CLK */ AM62AX_IOPAD(0x214, PIN_INPUT, 0) /* (AA2) MMC0_DAT0 */ AM62AX_IOPAD(0x210, PIN_INPUT_PULLUP, 0) /* (AA1) MMC0_DAT1 */ AM62AX_IOPAD(0x20c, PIN_INPUT_PULLUP, 0) /* (AA3) MMC0_DAT2 */ @@ -330,7 +329,7 @@ AM62AX_IOPAD(0x1f8, PIN_INPUT_PULLUP, 0) /* (AC2) MMC0_DAT7 */ main_mmc1_pins_default: main-mmc1-default-pins { pinctrl-single,pins = < AM62AX_IOPAD(0x23c, PIN_INPUT, 0) /* (A21) MMC1_CMD */ - AM62AX_IOPAD(0x234, PIN_INPUT, 0) /* (B22) MMC1_CLK */ + AM62AX_IOPAD(0x234, PIN_OUTPUT, 0) /* (B22) MMC1_CLK */ AM62AX_IOPAD(0x230, PIN_INPUT, 0) /* (A22) MMC1_DAT0 */ AM62AX_IOPAD(0x22c, PIN_INPUT, 0) /* (B21) MMC1_DAT1 */ AM62AX_IOPAD(0x228, PIN_INPUT, 0) /* (C21) MMC1_DAT2 */ diff --git a/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra.dtsi b/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra.dtsi index aab74d6019b0..5a09b4c1b659 100644 --- a/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra.dtsi @@ -227,7 +227,7 @@ AM62X_IOPAD(0x068, PIN_INPUT, 3) /* (R21) GPMC0_AD11.MCASP2_AXR3 */ main_mmc1_pins_default: main-mmc1-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x23c, PIN_INPUT_PULLUP, 0) /* (A21) MMC1_CMD */ - AM62X_IOPAD(0x234, PIN_INPUT_PULLDOWN, 0) /* (B22) MMC1_CLK */ + AM62X_IOPAD(0x234, PIN_OUTPUT_PULLDOWN, 0) /* (B22) MMC1_CLK */ AM62X_IOPAD(0x230, PIN_INPUT_PULLUP, 0) /* (A22) MMC1_DAT0 */ AM62X_IOPAD(0x22c, PIN_INPUT_PULLUP, 0) /* (B21) MMC1_DAT1 */ AM62X_IOPAD(0x228, PIN_INPUT_PULLUP, 0) /* (C21) MMC1_DAT2 */ diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi index 58f78c0de292..3c5ef8fc9cdd 100644 --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi @@ -187,7 +187,7 @@ main_mmc1_pins_default: main-mmc1-default-pins { bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x23c, PIN_INPUT, 0) /* (A21/C18) MMC1_CMD */ - AM62X_IOPAD(0x234, PIN_INPUT, 0) /* (B22/A20) MMC1_CLK */ + AM62X_IOPAD(0x234, PIN_OUTPUT, 0) /* (B22/A20) MMC1_CLK */ AM62X_IOPAD(0x230, PIN_INPUT, 0) /* (A22/A19) MMC1_DAT0 */ AM62X_IOPAD(0x22c, PIN_INPUT, 0) /* (B21/B19) MMC1_DAT1 */ AM62X_IOPAD(0x228, PIN_INPUT, 0) /* (C21/B20) MMC1_DAT2 */ diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 1da290aeedce..641276868a65 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -98,7 +98,7 @@ * TID1: Trap REVIDR_EL1, AIDR_EL1, and SMIDR_EL1 */ #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \ - HCR_BSU_IS | HCR_FB | HCR_TACR | \ + SYS_FIELD_PREP_ENUM(HCR_EL2, BSU, IS) | HCR_EL2_FB | HCR_EL2_TACR | \ HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \ HCR_FMO | HCR_IMO | HCR_PTW | HCR_TID3 | HCR_TID1) #define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK | HCR_ATA) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 419e37112a6f..b7334f98deaa 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -833,11 +833,10 @@ struct kvm_vcpu_arch { /* * Don't run the guest (internal implementation need). * - * Contrary to the flags above, this is set/cleared outside of - * a vcpu context, and thus cannot be mixed with the flags - * themselves (or the flag accesses need to be made atomic). + * Contrary to the flags above, this is updated outside of + * a vcpu context, and thus cannot be mixed with the flags. */ - bool pause; + atomic_t pause; /* * We maintain more than a single set of debug registers to support diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 1765e484fb9f..2ce69d64e60c 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -1675,6 +1675,9 @@ extern void modify_prot_commit_ptes(struct vm_area_struct *vma, unsigned long ad * The contpte APIs are used to transparently manage the contiguous bit in ptes * where it is possible and makes sense to do so. The PTE_CONT bit is considered * a private implementation detail of the public ptep API (see below). + * Single-PTE transparent contpte helpers use pte_valid_cont() to identify + * grouped PTEs; explicit contiguous-encoding users such as hugetlb manage + * their entries separately. */ extern void __contpte_try_fold(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte); diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 6c371b158b99..a3c0d5c2e9f7 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -116,8 +116,14 @@ static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data) const efi_memory_desc_t *md = spd->md; pte_t pte = __ptep_get(ptep); + /* + * Clear PTE_WRITE as well: it doubles as the DBM bit, and leaving it + * set would permit the hardware to make the mapping writable again + * when TCR_EL1.HD is set. + */ if (md->attribute & EFI_MEMORY_RO) - pte = set_pte_bit(pte, __pgprot(PTE_RDONLY)); + pte = set_pte_bit(clear_pte_bit(pte, __pgprot(PTE_WRITE)), + __pgprot(PTE_RDONLY)); if (md->attribute & EFI_MEMORY_XP) pte = set_pte_bit(pte, __pgprot(PTE_PXN)); else if (system_supports_bti_kernel() && spd->has_bti) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index b52c162cb380..4e0db01a528a 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -500,6 +500,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) kvm_arm_pvtime_vcpu_init(&vcpu->arch); vcpu->arch.hw_mmu = &vcpu->kvm->arch.mmu; + atomic_set(&vcpu->arch.pause, 0); /* * This vCPU may have been created after mpidr_data was initialized. @@ -765,6 +766,11 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, return ret; } +static bool vcpu_can_run(struct kvm_vcpu *vcpu) +{ + return !kvm_arm_vcpu_stopped(vcpu) && !atomic_read(&vcpu->arch.pause); +} + /** * kvm_arch_vcpu_runnable - determine if the vcpu can be scheduled * @v: The VCPU pointer @@ -780,8 +786,7 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) (kvm_timer_should_notify_user(v) || kvm_pmu_should_notify_user(v))); - return ((irq_lines || kvm_vgic_vcpu_pending_irq(v)) - && !kvm_arm_vcpu_stopped(v) && !v->arch.pause); + return ((irq_lines || kvm_vgic_vcpu_pending_irq(v)) && vcpu_can_run(v)); } bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu) @@ -937,7 +942,7 @@ void kvm_arm_halt_guest(struct kvm *kvm) struct kvm_vcpu *vcpu; kvm_for_each_vcpu(i, vcpu, kvm) - vcpu->arch.pause = true; + atomic_inc(&vcpu->arch.pause); kvm_make_all_cpus_request(kvm, KVM_REQ_SLEEP); } @@ -947,8 +952,8 @@ void kvm_arm_resume_guest(struct kvm *kvm) struct kvm_vcpu *vcpu; kvm_for_each_vcpu(i, vcpu, kvm) { - vcpu->arch.pause = false; - __kvm_vcpu_wake_up(vcpu); + if (atomic_dec_and_test(&vcpu->arch.pause)) + __kvm_vcpu_wake_up(vcpu); } } @@ -956,11 +961,9 @@ static void kvm_vcpu_sleep(struct kvm_vcpu *vcpu) { struct rcuwait *wait = kvm_arch_vcpu_get_wait(vcpu); - rcuwait_wait_event(wait, - (!kvm_arm_vcpu_stopped(vcpu)) && (!vcpu->arch.pause), - TASK_INTERRUPTIBLE); + rcuwait_wait_event(wait, vcpu_can_run(vcpu), TASK_INTERRUPTIBLE); - if (kvm_arm_vcpu_stopped(vcpu) || vcpu->arch.pause) { + if (!vcpu_can_run(vcpu)) { /* Awaken to handle a signal, request we sleep again later. */ kvm_make_request(KVM_REQ_SLEEP, vcpu); } @@ -1229,31 +1232,33 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) local_irq_disable(); - kvm_vgic_flush_hwstate(vcpu); - - kvm_pmu_update_vcpu_events(vcpu); - /* * Ensure we set mode to IN_GUEST_MODE after we disable * interrupts and before the final VCPU requests check. * See the comment in kvm_vcpu_exiting_guest_mode() and * Documentation/virt/kvm/vcpu-requests.rst + * + * Requests to self must be posted before this point, or + * won't be taken into account until the next exit. No state + * loading other than what happens at vcpu_load() time can + * be done before we have checked for pending requests. */ smp_store_mb(vcpu->mode, IN_GUEST_MODE); if (ret <= 0 || kvm_vcpu_exit_request(vcpu, &ret)) { - vcpu->mode = OUTSIDE_GUEST_MODE; - isb(); /* Ensure work in x_flush_hwstate is committed */ - if (kvm_vcpu_has_pmu(vcpu)) - kvm_pmu_sync_hwstate(vcpu); if (unlikely(!irqchip_in_kernel(vcpu->kvm))) kvm_timer_sync_user(vcpu); - kvm_vgic_sync_hwstate(vcpu); + smp_store_release(&vcpu->mode, OUTSIDE_GUEST_MODE); local_irq_enable(); preempt_enable(); continue; } + /* From here onwards, we are commited to entering the guest */ + kvm_vgic_flush_hwstate(vcpu); + + kvm_pmu_update_vcpu_events(vcpu); + kvm_arch_vcpu_ctxflush_fp(vcpu); /************************************************************** @@ -1264,7 +1269,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) ret = kvm_arm_vcpu_enter_exit(vcpu); - vcpu->mode = OUTSIDE_GUEST_MODE; vcpu->stat.exits++; /* * Back from guest @@ -1298,6 +1302,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) kvm_arch_vcpu_ctxsync_fp(vcpu); + /* + * The state that was pushed into the CPU on entering + * the guest has been synchronised back, let's + * advertise we're outside of the guest. + */ + smp_store_release(&vcpu->mode, OUTSIDE_GUEST_MODE); + /* * We must ensure that any pending interrupts are taken before * we exit guest timing so that timer ticks are accounted as diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c index bef40ddb16db..c041142896e3 100644 --- a/arch/arm64/kvm/hyp/exception.c +++ b/arch/arm64/kvm/hyp/exception.c @@ -86,6 +86,7 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode, enum exception_type type) { unsigned long sctlr, vbar, old, new, mode; + struct kvm *kvm; u64 exc_offset; mode = *vcpu_cpsr(vcpu) & (PSR_MODE_MASK | PSR_MODE32_BIT); @@ -125,8 +126,10 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode, new |= (old & PSR_C_BIT); new |= (old & PSR_V_BIT); - if (kvm_has_mte(kern_hyp_va(vcpu->kvm))) + kvm = vcpu_get_kvm(vcpu); + if (kvm && kvm_has_mte(kvm)) new |= PSR_TCO_BIT; + vcpu_put_kvm(vcpu, kvm); new |= (old & PSR_DIT_BIT); diff --git a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h index 4fdfeabefeb4..f55950ee2a7e 100644 --- a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h +++ b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h @@ -13,6 +13,34 @@ #include #include +#ifdef __KVM_NVHE_HYPERVISOR__ +#include + +/* Under pKVM a host vCPU's ->kvm is host-writable. */ +static inline struct kvm *vcpu_get_kvm(struct kvm_vcpu *vcpu) +{ + if (is_protected_kvm_enabled()) + return pkvm_vcpu_get_kvm(vcpu); + + return kern_hyp_va(vcpu->kvm); +} + +static inline void vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm) +{ + if (is_protected_kvm_enabled()) + pkvm_vcpu_put_kvm(vcpu, kvm); +} +#else +static inline struct kvm *vcpu_get_kvm(struct kvm_vcpu *vcpu) +{ + return vcpu->kvm; +} + +static inline void vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm) +{ +} +#endif + static inline void kvm_skip_instr(struct kvm_vcpu *vcpu) { if (vcpu_mode_is_32bit(vcpu)) { diff --git a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h index 184ad7a39950..25b2f477bb5b 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h +++ b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h @@ -79,6 +79,8 @@ struct pkvm_hyp_vcpu *pkvm_load_hyp_vcpu(pkvm_handle_t handle, unsigned int vcpu_idx); void pkvm_put_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu); struct pkvm_hyp_vcpu *pkvm_get_loaded_hyp_vcpu(void); +struct kvm *pkvm_vcpu_get_kvm(struct kvm_vcpu *vcpu); +void pkvm_vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm); struct pkvm_hyp_vm *get_pkvm_hyp_vm(pkvm_handle_t handle); struct pkvm_hyp_vm *get_np_pkvm_hyp_vm(pkvm_handle_t handle); diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index bf0250806a78..136c4008b936 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -306,6 +306,43 @@ struct pkvm_hyp_vcpu *pkvm_get_loaded_hyp_vcpu(void) } +static struct pkvm_hyp_vm *pkvm_get_loaded_hyp_vm(struct kvm_vcpu *vcpu) +{ + struct pkvm_hyp_vcpu *hyp_vcpu = pkvm_get_loaded_hyp_vcpu(); + + if (hyp_vcpu && + (vcpu == &hyp_vcpu->vcpu || vcpu == hyp_vcpu->host_vcpu)) + return pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu); + + return NULL; +} + +/* + * A loaded vCPU's VM is the hyp VM. An unloaded host vCPU's is mapped at + * EL2 only while pinned, so it's read once and pinned; the pin fails for + * memory the host isn't sharing. + */ +struct kvm *pkvm_vcpu_get_kvm(struct kvm_vcpu *vcpu) +{ + struct pkvm_hyp_vm *hyp_vm = pkvm_get_loaded_hyp_vm(vcpu); + struct kvm *kvm; + + if (hyp_vm) + return &hyp_vm->kvm; + + kvm = kern_hyp_va(READ_ONCE(vcpu->kvm)); + if (hyp_pin_shared_mem(kvm, kvm + 1)) + return NULL; + + return kvm; +} + +void pkvm_vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm) +{ + if (kvm && !pkvm_get_loaded_hyp_vm(vcpu)) + hyp_unpin_shared_mem(kvm, kvm + 1); +} + struct pkvm_hyp_vm *get_pkvm_hyp_vm(pkvm_handle_t handle) { struct pkvm_hyp_vm *hyp_vm; diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c index 3108b5185c20..168d473e084b 100644 --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c @@ -115,6 +115,9 @@ static const struct pvm_ftr_bits pvmid_aa64mmfr0[] = { MAX_FEAT(ID_AA64MMFR0_EL1, SNSMEM, IMP), MAX_FEAT(ID_AA64MMFR0_EL1, BIGENDEL0, IMP), MAX_FEAT(ID_AA64MMFR0_EL1, EXS, IMP), + MAX_FEAT(ID_AA64MMFR0_EL1, TGRAN4, IMP), + MAX_FEAT(ID_AA64MMFR0_EL1, TGRAN16, IMP), + MAX_FEAT(ID_AA64MMFR0_EL1, TGRAN64, IMP), FEAT_END }; diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index 051d9bf73879..79e018cec0f9 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -818,16 +818,21 @@ int vgic_register_redist_iodev(struct kvm_vcpu *vcpu) rd_dev->nr_regions = ARRAY_SIZE(vgic_v3_rd_registers); rd_dev->redist_vcpu = vcpu; + /* Protected by slots_lock */ + rdreg->free_index++; + mutex_unlock(&kvm->arch.config_lock); ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, rd_base, 2 * SZ_64K, &rd_dev->dev); - if (ret) - return ret; + if (ret) { + guard(mutex)(&vcpu->kvm->arch.config_lock); + vgic_cpu->rdreg->free_index--; + vgic_cpu->rdreg = NULL; + vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF; + } - /* Protected by slots_lock */ - rdreg->free_index++; - return 0; + return ret; out_unlock: mutex_unlock(&kvm->arch.config_lock); @@ -841,7 +846,8 @@ void vgic_unregister_redist_iodev(struct kvm_vcpu *vcpu) kvm_io_bus_unregister_dev(vcpu->kvm, KVM_MMIO_BUS, &rd_dev->dev); } -static int vgic_register_all_redist_iodevs(struct kvm *kvm) +static int vgic_register_all_redist_iodevs(struct kvm *kvm, + struct vgic_redist_region *rdreg) { struct kvm_vcpu *vcpu; unsigned long c; @@ -861,7 +867,14 @@ static int vgic_register_all_redist_iodevs(struct kvm *kvm) for (i = 0; i < c; i++) { vcpu = kvm_get_vcpu(kvm, i); + if (vcpu->arch.vgic_cpu.rdreg != rdreg) + continue; + vgic_unregister_redist_iodev(vcpu); + + guard(mutex)(&vcpu->kvm->arch.config_lock); + vcpu->arch.vgic_cpu.rdreg = NULL; + vcpu->arch.vgic_cpu.rd_iodev.base_addr = VGIC_ADDR_UNDEF; } } @@ -970,10 +983,13 @@ void vgic_v3_free_redist_region(struct kvm *kvm, struct vgic_redist_region *rdre int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count) { + struct vgic_redist_region *rdreg; int ret; mutex_lock(&kvm->arch.config_lock); ret = vgic_v3_alloc_redist_region(kvm, index, addr, count); + if (!ret) + rdreg = vgic_v3_rdist_region_from_index(kvm, index); mutex_unlock(&kvm->arch.config_lock); if (ret) return ret; @@ -982,12 +998,9 @@ int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count) * Register iodevs for each existing VCPU. Adding more VCPUs * afterwards will register the iodevs when needed. */ - ret = vgic_register_all_redist_iodevs(kvm); + ret = vgic_register_all_redist_iodevs(kvm, rdreg); if (ret) { - struct vgic_redist_region *rdreg; - mutex_lock(&kvm->arch.config_lock); - rdreg = vgic_v3_rdist_region_from_index(kvm, index); vgic_v3_free_redist_region(kvm, rdreg); mutex_unlock(&kvm->arch.config_lock); return ret; diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c index 29024e20e876..c39a290c6b5a 100644 --- a/arch/arm64/mm/contpte.c +++ b/arch/arm64/mm/contpte.c @@ -444,8 +444,10 @@ void contpte_set_ptes(struct mm_struct *mm, unsigned long addr, */ VM_WARN_ON(nr == 1); - if (!mm_is_user(mm)) + if (!mm_is_user(mm) || !pte_valid(pte)) { + VM_WARN_ON_ONCE(!pte_valid(pte) && pte_cont(pte)); return __set_ptes(mm, addr, ptep, pte, nr); + } end = addr + (nr << PAGE_SHIFT); pfn = pte_pfn(pte); diff --git a/arch/loongarch/include/asm/barrier.h b/arch/loongarch/include/asm/barrier.h index 4b663f197706..84c6d739119d 100644 --- a/arch/loongarch/include/asm/barrier.h +++ b/arch/loongarch/include/asm/barrier.h @@ -57,9 +57,6 @@ #define __WEAK_LLSC_MB " \n" #endif -#define __smp_mb__before_atomic() barrier() -#define __smp_mb__after_atomic() barrier() - /** * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise * @index: array element index diff --git a/arch/loongarch/include/asm/hw_breakpoint.h b/arch/loongarch/include/asm/hw_breakpoint.h index 5faa97a87a9e..d202052df8a1 100644 --- a/arch/loongarch/include/asm/hw_breakpoint.h +++ b/arch/loongarch/include/asm/hw_breakpoint.h @@ -116,8 +116,8 @@ extern void arch_uninstall_hw_breakpoint(struct perf_event *bp); extern int hw_breakpoint_slots(int type); extern void hw_breakpoint_pmu_read(struct perf_event *bp); -void breakpoint_handler(struct pt_regs *regs); -void watchpoint_handler(struct pt_regs *regs); +bool breakpoint_handler(struct pt_regs *regs); +bool watchpoint_handler(struct pt_regs *regs); #ifdef CONFIG_HAVE_HW_BREAKPOINT extern void ptrace_hw_copy_thread(struct task_struct *task); diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h index 58a4a3b6b035..642dc9adddce 100644 --- a/arch/loongarch/include/asm/loongarch.h +++ b/arch/loongarch/include/asm/loongarch.h @@ -1090,8 +1090,8 @@ #define LOONGARCH_CSR_DERA 0x501 /* debug era */ #define LOONGARCH_CSR_DESAVE 0x502 /* debug save */ -#define CSR_FWPC_SKIP_SHIFT 16 -#define CSR_FWPC_SKIP (_ULCAST_(1) << CSR_FWPC_SKIP_SHIFT) +#define CSR_FWPS_SKIP_SHIFT 16 +#define CSR_FWPS_SKIP (_ULCAST_(1) << CSR_FWPS_SKIP_SHIFT) /* * CSR_ECFG IM diff --git a/arch/loongarch/include/asm/numa.h b/arch/loongarch/include/asm/numa.h index bbf9f70bd25f..c9654ff900a3 100644 --- a/arch/loongarch/include/asm/numa.h +++ b/arch/loongarch/include/asm/numa.h @@ -14,7 +14,7 @@ #define NODE_ADDRSPACE_SHIFT 44 #define pa_to_nid(addr) (((addr) & 0xf00000000000) >> NODE_ADDRSPACE_SHIFT) -#define nid_to_addrbase(nid) (_ULCAST_(nid) << NODE_ADDRSPACE_SHIFT) +#define nid_to_addrbase(nid) (_U64CAST_(nid) << NODE_ADDRSPACE_SHIFT) #ifdef CONFIG_NUMA diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-probe.c index 4ac9c9599167..9f0f9fdac011 100644 --- a/arch/loongarch/kernel/cpu-probe.c +++ b/arch/loongarch/kernel/cpu-probe.c @@ -93,7 +93,7 @@ static int __init cpu_final_simd(void) return 0; } -arch_initcall(cpu_final_simd); +pure_initcall(cpu_final_simd); static inline void set_elf_platform(int cpu, const char *plat) { diff --git a/arch/loongarch/kernel/hw_breakpoint.c b/arch/loongarch/kernel/hw_breakpoint.c index c35f9bf38033..1a05350159f7 100644 --- a/arch/loongarch/kernel/hw_breakpoint.c +++ b/arch/loongarch/kernel/hw_breakpoint.c @@ -233,7 +233,7 @@ static int hw_breakpoint_control(struct perf_event *bp, } enable = csr_read64(LOONGARCH_CSR_CRMD); csr_write64(CSR_CRMD_WE | enable, LOONGARCH_CSR_CRMD); - if (bp->hw.target && test_tsk_thread_flag(bp->hw.target, TIF_LOAD_WATCH)) + if (bp->hw.target) regs->csr_prmd |= CSR_PRMD_PWE; break; case HW_BREAKPOINT_UNINSTALL: @@ -453,7 +453,6 @@ static void update_bp_registers(struct pt_regs *regs, int enable, int type) if (enable) { if ((info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) && (type == 0)) { write_wb_reg(CSR_CFG_CTRL, i, 0, CTRL_PLV_ENABLE); - write_wb_reg(CSR_CFG_CTRL, i, 0, CTRL_PLV_ENABLE); } else { ctrl = read_wb_reg(CSR_CFG_CTRL, i, 1); if (info->ctrl.type == LOONGARCH_BREAKPOINT_LOAD) @@ -469,9 +468,9 @@ static void update_bp_registers(struct pt_regs *regs, int enable, int type) } else { ctrl = read_wb_reg(CSR_CFG_CTRL, i, 1); if (info->ctrl.type == LOONGARCH_BREAKPOINT_LOAD) - ctrl &= ~0x1 << MWPnCFG3_LoadEn; + ctrl &= ~(0x1 << MWPnCFG3_LoadEn); if (info->ctrl.type == LOONGARCH_BREAKPOINT_STORE) - ctrl &= ~0x1 << MWPnCFG3_StoreEn; + ctrl &= ~(0x1 << MWPnCFG3_StoreEn); write_wb_reg(CSR_CFG_CTRL, i, 1, ctrl); } regs->csr_prmd &= ~CSR_PRMD_PWE; @@ -483,9 +482,10 @@ NOKPROBE_SYMBOL(update_bp_registers); /* * Debug exception handlers. */ -void breakpoint_handler(struct pt_regs *regs) +bool breakpoint_handler(struct pt_regs *regs) { int i; + bool need_sigtrap = false; struct perf_event *bp, **slots; slots = this_cpu_ptr(bp_on_reg); @@ -495,17 +495,24 @@ void breakpoint_handler(struct pt_regs *regs) bp = slots[i]; if (bp == NULL) continue; + perf_bp_event(bp, regs); + if (bp->attr.sigtrap) + need_sigtrap = true; + csr_write32(0x1 << i, LOONGARCH_CSR_FWPS); update_bp_registers(regs, 0, 0); } } + + return need_sigtrap; } NOKPROBE_SYMBOL(breakpoint_handler); -void watchpoint_handler(struct pt_regs *regs) +bool watchpoint_handler(struct pt_regs *regs) { int i; + bool need_sigtrap = false; struct perf_event *wp, **slots; slots = this_cpu_ptr(wp_on_reg); @@ -515,11 +522,17 @@ void watchpoint_handler(struct pt_regs *regs) wp = slots[i]; if (wp == NULL) continue; + perf_bp_event(wp, regs); + if (wp->attr.sigtrap) + need_sigtrap = true; + csr_write32(0x1 << i, LOONGARCH_CSR_MWPS); update_bp_registers(regs, 0, 1); } } + + return need_sigtrap; } NOKPROBE_SYMBOL(watchpoint_handler); @@ -551,7 +564,7 @@ void hw_breakpoint_thread_switch(struct task_struct *next) addr = read_wb_reg(CSR_CFG_ADDR, 0, 0); mask = read_wb_reg(CSR_CFG_MASK, 0, 0); if (!((regs->csr_era ^ addr) & ~mask)) - csr_write32(CSR_FWPC_SKIP, LOONGARCH_CSR_FWPS); + csr_write32(CSR_FWPS_SKIP, LOONGARCH_CSR_FWPS); regs->csr_prmd |= CSR_PRMD_PWE; } else { /* Update breakpoints */ diff --git a/arch/loongarch/kernel/irq.c b/arch/loongarch/kernel/irq.c index 80946cafaec1..130954ab9ee2 100644 --- a/arch/loongarch/kernel/irq.c +++ b/arch/loongarch/kernel/irq.c @@ -19,6 +19,7 @@ #include #include +#include #include DEFINE_PER_CPU(unsigned long, irq_stack); @@ -68,7 +69,7 @@ static int __init early_pci_mcfg_parse(struct acpi_table_header *header) for (i = 0; i < n; i++, mptr++) { msi_group[i].pci_segment = mptr->pci_segment; - pch_group[i].node = msi_group[i].node = (mptr->address >> 44) & 0xf; + pch_group[i].node = msi_group[i].node = pa_to_nid(mptr->address); } return 0; diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c index 8e51ce004572..9ce12327d64e 100644 --- a/arch/loongarch/kernel/traps.c +++ b/arch/loongarch/kernel/traps.c @@ -807,6 +807,8 @@ asmlinkage void noinstr do_watch(struct pt_regs *regs) #ifndef CONFIG_HAVE_HW_BREAKPOINT pr_warn("Hardware watch point handler not implemented!\n"); #else + bool need_sigtrap = !!current->ptrace; + if (kgdb_breakpoint_handler(regs)) goto out; @@ -821,7 +823,7 @@ asmlinkage void noinstr do_watch(struct pt_regs *regs) * instruction. So don't clear llbit and reset CSR.FWPS.Skip until * the llsc execution is completed. */ - csr_write32(CSR_FWPC_SKIP, LOONGARCH_CSR_FWPS); + csr_write32(CSR_FWPS_SKIP, LOONGARCH_CSR_FWPS); csr_write32(CSR_LLBCTL_KLO, LOONGARCH_CSR_LLBCTL); goto out; } @@ -838,16 +840,17 @@ asmlinkage void noinstr do_watch(struct pt_regs *regs) * current pc, If yes, then we should not set the CSR.FWPS.SKIP * bit to break the original instruction stream. */ - csr_write32(CSR_FWPC_SKIP, LOONGARCH_CSR_FWPS); + csr_write32(CSR_FWPS_SKIP, LOONGARCH_CSR_FWPS); goto out; } } } else { - breakpoint_handler(regs); - watchpoint_handler(regs); + need_sigtrap |= breakpoint_handler(regs); + need_sigtrap |= watchpoint_handler(regs); } - force_sig(SIGTRAP); + if (need_sigtrap) + force_sig(SIGTRAP); out: #endif irqentry_exit(regs, state); diff --git a/arch/loongarch/pci/pci.c b/arch/loongarch/pci/pci.c index f33c7ea1443d..0b99b32110a5 100644 --- a/arch/loongarch/pci/pci.c +++ b/arch/loongarch/pci/pci.c @@ -12,6 +12,7 @@ #include #include #include +#include #define PCI_DEVICE_ID_LOONGSON_HOST 0x7a00 #define PCI_DEVICE_ID_LOONGSON_DC1 0x7a06 @@ -43,7 +44,7 @@ int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, phys_addr_t mcfg_addr_init(int node) { - return (((u64)node << 44) | MCFG_EXT_PCICFG_BASE); + return (nid_to_addrbase(node) | MCFG_EXT_PCICFG_BASE); } static int __init pcibios_init(void) diff --git a/arch/microblaze/include/asm/entry.h b/arch/microblaze/include/asm/entry.h index 9efadf12397c..05acf4d7bc4b 100644 --- a/arch/microblaze/include/asm/entry.h +++ b/arch/microblaze/include/asm/entry.h @@ -21,6 +21,19 @@ #define PER_CPU(var) var +/* + * The MicroBlaze ABI has the caller reserve an argument home area: + * REG_PARM_STACK_SPACE is 24 and OUTGOING_REG_PARM_STACK_SPACE is 1, so a + * callee may write to [caller_sp + 4, caller_sp + 28). The kernel calls C + * with r1 at the frame base, so reserve that area below pt_regs and reach + * the saved registers through PTO. This restores what 6e83557c38b4 + * ("microblaze: Remove r0_ram pointer and PTO alignment") removed; the old + * value of 24 was one word short and left the last argument slot + * overlapping pt_regs' r0. + */ +#define PTO 28 +#define STATE_SAVE_SIZE (PT_SIZE + PTO) + # ifndef __ASSEMBLER__ DECLARE_PER_CPU(unsigned int, KSP); /* Saved kernel stack pointer */ DECLARE_PER_CPU(unsigned int, KM); /* Kernel/user mode */ diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h index d59bdfffca7c..595c24db2728 100644 --- a/arch/microblaze/include/asm/processor.h +++ b/arch/microblaze/include/asm/processor.h @@ -73,7 +73,7 @@ unsigned long __get_wchan(struct task_struct *p); # define task_regs(task) ((struct pt_regs *)task_tos(task) - 1) # define task_pt_regs_plus_args(tsk) \ - ((void *)task_pt_regs(tsk)) + (((void *)task_pt_regs(tsk)) - PTO) # define task_sp(task) (task_regs(task)->r1) # define task_pc(task) (task_regs(task)->pc) diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 582d7256d815..ebc8bcb98c52 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -177,78 +177,78 @@ syscall_debug_table: 1: #define SAVE_REGS \ - swi r2, r1, PT_R2; /* Save SDA */ \ - swi r3, r1, PT_R3; \ - swi r4, r1, PT_R4; \ - swi r5, r1, PT_R5; \ - swi r6, r1, PT_R6; \ - swi r7, r1, PT_R7; \ - swi r8, r1, PT_R8; \ - swi r9, r1, PT_R9; \ - swi r10, r1, PT_R10; \ - swi r11, r1, PT_R11; /* save clobbered regs after rval */\ - swi r12, r1, PT_R12; \ - swi r13, r1, PT_R13; /* Save SDA2 */ \ - swi r14, r1, PT_PC; /* PC, before IRQ/trap */ \ - swi r15, r1, PT_R15; /* Save LP */ \ - swi r16, r1, PT_R16; \ - swi r17, r1, PT_R17; \ - swi r18, r1, PT_R18; /* Save asm scratch reg */ \ - swi r19, r1, PT_R19; \ - swi r20, r1, PT_R20; \ - swi r21, r1, PT_R21; \ - swi r22, r1, PT_R22; \ - swi r23, r1, PT_R23; \ - swi r24, r1, PT_R24; \ - swi r25, r1, PT_R25; \ - swi r26, r1, PT_R26; \ - swi r27, r1, PT_R27; \ - swi r28, r1, PT_R28; \ - swi r29, r1, PT_R29; \ - swi r30, r1, PT_R30; \ - swi r31, r1, PT_R31; /* Save current task reg */ \ + swi r2, r1, PTO+PT_R2; /* Save SDA */ \ + swi r3, r1, PTO+PT_R3; \ + swi r4, r1, PTO+PT_R4; \ + swi r5, r1, PTO+PT_R5; \ + swi r6, r1, PTO+PT_R6; \ + swi r7, r1, PTO+PT_R7; \ + swi r8, r1, PTO+PT_R8; \ + swi r9, r1, PTO+PT_R9; \ + swi r10, r1, PTO+PT_R10; \ + swi r11, r1, PTO+PT_R11; /* save clobbered regs after rval */\ + swi r12, r1, PTO+PT_R12; \ + swi r13, r1, PTO+PT_R13; /* Save SDA2 */ \ + swi r14, r1, PTO+PT_PC; /* PC, before IRQ/trap */ \ + swi r15, r1, PTO+PT_R15; /* Save LP */ \ + swi r16, r1, PTO+PT_R16; \ + swi r17, r1, PTO+PT_R17; \ + swi r18, r1, PTO+PT_R18; /* Save asm scratch reg */ \ + swi r19, r1, PTO+PT_R19; \ + swi r20, r1, PTO+PT_R20; \ + swi r21, r1, PTO+PT_R21; \ + swi r22, r1, PTO+PT_R22; \ + swi r23, r1, PTO+PT_R23; \ + swi r24, r1, PTO+PT_R24; \ + swi r25, r1, PTO+PT_R25; \ + swi r26, r1, PTO+PT_R26; \ + swi r27, r1, PTO+PT_R27; \ + swi r28, r1, PTO+PT_R28; \ + swi r29, r1, PTO+PT_R29; \ + swi r30, r1, PTO+PT_R30; \ + swi r31, r1, PTO+PT_R31; /* Save current task reg */ \ mfs r11, rmsr; /* save MSR */ \ - swi r11, r1, PT_MSR; + swi r11, r1, PTO+PT_MSR; #define RESTORE_REGS_GP \ - lwi r2, r1, PT_R2; /* restore SDA */ \ - lwi r3, r1, PT_R3; \ - lwi r4, r1, PT_R4; \ - lwi r5, r1, PT_R5; \ - lwi r6, r1, PT_R6; \ - lwi r7, r1, PT_R7; \ - lwi r8, r1, PT_R8; \ - lwi r9, r1, PT_R9; \ - lwi r10, r1, PT_R10; \ - lwi r11, r1, PT_R11; /* restore clobbered regs after rval */\ - lwi r12, r1, PT_R12; \ - lwi r13, r1, PT_R13; /* restore SDA2 */ \ - lwi r14, r1, PT_PC; /* RESTORE_LINK PC, before IRQ/trap */\ - lwi r15, r1, PT_R15; /* restore LP */ \ - lwi r16, r1, PT_R16; \ - lwi r17, r1, PT_R17; \ - lwi r18, r1, PT_R18; /* restore asm scratch reg */ \ - lwi r19, r1, PT_R19; \ - lwi r20, r1, PT_R20; \ - lwi r21, r1, PT_R21; \ - lwi r22, r1, PT_R22; \ - lwi r23, r1, PT_R23; \ - lwi r24, r1, PT_R24; \ - lwi r25, r1, PT_R25; \ - lwi r26, r1, PT_R26; \ - lwi r27, r1, PT_R27; \ - lwi r28, r1, PT_R28; \ - lwi r29, r1, PT_R29; \ - lwi r30, r1, PT_R30; \ - lwi r31, r1, PT_R31; /* Restore cur task reg */ + lwi r2, r1, PTO+PT_R2; /* restore SDA */ \ + lwi r3, r1, PTO+PT_R3; \ + lwi r4, r1, PTO+PT_R4; \ + lwi r5, r1, PTO+PT_R5; \ + lwi r6, r1, PTO+PT_R6; \ + lwi r7, r1, PTO+PT_R7; \ + lwi r8, r1, PTO+PT_R8; \ + lwi r9, r1, PTO+PT_R9; \ + lwi r10, r1, PTO+PT_R10; \ + lwi r11, r1, PTO+PT_R11; /* restore clobbered regs after rval */\ + lwi r12, r1, PTO+PT_R12; \ + lwi r13, r1, PTO+PT_R13; /* restore SDA2 */ \ + lwi r14, r1, PTO+PT_PC; /* RESTORE_LINK PC, before IRQ/trap */\ + lwi r15, r1, PTO+PT_R15; /* restore LP */ \ + lwi r16, r1, PTO+PT_R16; \ + lwi r17, r1, PTO+PT_R17; \ + lwi r18, r1, PTO+PT_R18; /* restore asm scratch reg */ \ + lwi r19, r1, PTO+PT_R19; \ + lwi r20, r1, PTO+PT_R20; \ + lwi r21, r1, PTO+PT_R21; \ + lwi r22, r1, PTO+PT_R22; \ + lwi r23, r1, PTO+PT_R23; \ + lwi r24, r1, PTO+PT_R24; \ + lwi r25, r1, PTO+PT_R25; \ + lwi r26, r1, PTO+PT_R26; \ + lwi r27, r1, PTO+PT_R27; \ + lwi r28, r1, PTO+PT_R28; \ + lwi r29, r1, PTO+PT_R29; \ + lwi r30, r1, PTO+PT_R30; \ + lwi r31, r1, PTO+PT_R31; /* Restore cur task reg */ #define RESTORE_REGS \ - lwi r11, r1, PT_MSR; \ + lwi r11, r1, PTO+PT_MSR; \ mts rmsr , r11; \ RESTORE_REGS_GP #define RESTORE_REGS_RTBD \ - lwi r11, r1, PT_MSR; \ + lwi r11, r1, PTO+PT_MSR; \ andni r11, r11, MSR_EIP; /* clear EIP */ \ ori r11, r11, MSR_EE | MSR_BIP; /* set EE and BIP */ \ mts rmsr , r11; \ @@ -265,11 +265,11 @@ syscall_debug_table: lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ /* FIXME: I can add these two lines to one */ \ /* tophys(r1,r1); */ \ - /* addik r1, r1, -PT_SIZE; */ \ - addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \ + /* addik r1, r1, -STATE_SAVE_SIZE; */ \ + addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; \ SAVE_REGS \ brid 2f; \ - swi r1, r1, PT_MODE; \ + swi r1, r1, PTO+PT_MODE; \ 1: /* User-mode state save. */ \ lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\ tophys(r1,r1); \ @@ -277,12 +277,13 @@ syscall_debug_table: /* MS these three instructions can be added to one */ \ /* addik r1, r1, THREAD_SIZE; */ \ /* tophys(r1,r1); */ \ - /* addik r1, r1, -PT_SIZE; */ \ - addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \ + /* addik r1, r1, -STATE_SAVE_SIZE; */ \ + addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR \ + - CONFIG_KERNEL_START - STATE_SAVE_SIZE; \ SAVE_REGS \ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ - swi r11, r1, PT_R1; /* Store user SP. */ \ - swi r0, r1, PT_MODE; /* Was in user-mode. */ \ + swi r11, r1, PTO+PT_R1; /* Store user SP. */ \ + swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ \ /* MS: I am clearing UMS even in case when I come from kernel space */ \ clear_ums; \ 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); @@ -292,7 +293,7 @@ syscall_debug_table: .extern cpuinfo C_ENTRY(mb_flush_dcache): - addik r1, r1, -PT_SIZE + addik r1, r1, -STATE_SAVE_SIZE SAVE_REGS addik r3, r0, cpuinfo @@ -305,12 +306,12 @@ C_ENTRY(mb_flush_dcache): addk r9, r9, r8 RESTORE_REGS - addik r1, r1, PT_SIZE + addik r1, r1, STATE_SAVE_SIZE rtsd r15, 8 nop C_ENTRY(mb_invalidate_icache): - addik r1, r1, -PT_SIZE + addik r1, r1, -STATE_SAVE_SIZE SAVE_REGS addik r3, r0, cpuinfo @@ -323,7 +324,7 @@ C_ENTRY(mb_invalidate_icache): addk r9, r9, r8 RESTORE_REGS - addik r1, r1, PT_SIZE + addik r1, r1, STATE_SAVE_SIZE rtsd r15, 8 nop @@ -350,18 +351,18 @@ C_ENTRY(_user_exception): addik r1, r1, THREAD_SIZE; tophys(r1,r1); - addik r1, r1, -PT_SIZE; /* Make room on the stack. */ + addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ SAVE_REGS - swi r0, r1, PT_R3 - swi r0, r1, PT_R4 + swi r0, r1, PTO+PT_R3 + swi r0, r1, PTO+PT_R4 - swi r0, r1, PT_MODE; /* Was in user-mode. */ + swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); - swi r11, r1, PT_R1; /* Store user SP. */ + swi r11, r1, PTO+PT_R1; /* Store user SP. */ clear_ums; 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* Save away the syscall number. */ - swi r12, r1, PT_R0; + swi r12, r1, PTO+PT_R0; tovirt(r1,r1) /* where the trap should return need -8 to adjust for rtsd r15, 8*/ @@ -380,18 +381,18 @@ C_ENTRY(_user_exception): beqi r11, 4f addik r3, r0, -ENOSYS - swi r3, r1, PT_R3 + swi r3, r1, PTO+PT_R3 brlid r15, do_syscall_trace_enter - addik r5, r1, PT_R0 + addik r5, r1, PTO+PT_R0 # do_syscall_trace_enter returns the new syscall nr. addk r12, r0, r3 - lwi r5, r1, PT_R5; - lwi r6, r1, PT_R6; - lwi r7, r1, PT_R7; - lwi r8, r1, PT_R8; - lwi r9, r1, PT_R9; - lwi r10, r1, PT_R10; + lwi r5, r1, PTO+PT_R5; + lwi r6, r1, PTO+PT_R6; + lwi r7, r1, PTO+PT_R7; + lwi r8, r1, PTO+PT_R8; + lwi r9, r1, PTO+PT_R9; + lwi r10, r1, PTO+PT_R10; 4: /* Jump to the appropriate function for the system call number in r12 * (r12 is not preserved), or return an error if r12 is not valid. @@ -432,10 +433,16 @@ C_ENTRY(_user_exception): /* Entry point used to return from a syscall/trap */ /* We re-enable BIP bit before state restore */ C_ENTRY(ret_from_trap): - swi r3, r1, PT_R3 - swi r4, r1, PT_R4 - - lwi r11, r1, PT_MODE; + swi r3, r1, PTO+PT_R3 + swi r4, r1, PTO+PT_R4 +/* + * Entry point for returns that must not store r3/r4 back into pt_regs, + * i.e. rt_sigreturn, which has already restored them from the signal + * context. Reached as "rtsd r15, 8" with r15 set to this label minus 8, + * so it stays correct if the number of stores above ever changes. + */ +ret_from_trap_no_rval: + lwi r11, r1, PTO+PT_MODE; /* See if returning to kernel mode, if so, skip resched &c. */ bnei r11, 2f; /* We're returning to user mode, so check for various conditions that @@ -447,7 +454,7 @@ C_ENTRY(ret_from_trap): beqi r11, 1f brlid r15, do_syscall_trace_leave - addik r5, r1, PT_R0 + addik r5, r1, PTO+PT_R0 1: /* We're returning to user mode, so check for various conditions that * trigger rescheduling. */ @@ -466,7 +473,7 @@ C_ENTRY(ret_from_trap): andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; beqi r11, 4f; /* Signals to handle, handle them */ - addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ + addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ bralid r15, do_notify_resume; /* Handle any signals */ add r6, r30, r0; /* Arg 2: int in_syscall */ add r30, r0, r0 /* no more restarts */ @@ -478,7 +485,11 @@ C_ENTRY(ret_from_trap): VM_OFF; tophys(r1,r1); RESTORE_REGS_RTBD; - addik r1, r1, PT_SIZE /* Clean up stack space. */ + addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ + /* + * Deliberately PT_SIZE, not STATE_SAVE_SIZE: r1 is back at the stack + * top, so PTO cancels and the saved SP sits at PT_R1 - PT_SIZE. + */ lwi r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */ bri 6f; @@ -487,7 +498,7 @@ C_ENTRY(ret_from_trap): VM_OFF; tophys(r1,r1); RESTORE_REGS_RTBD; - addik r1, r1, PT_SIZE /* Clean up stack space. */ + addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ tovirt(r1,r1); 6: TRAP_return: /* Make global symbol for debugging */ @@ -518,8 +529,17 @@ C_ENTRY(ret_from_kernel_thread): C_ENTRY(sys_rt_sigreturn_wrapper): addik r30, r0, 0 /* no restarts */ + /* + * rt_sigreturn restores the full register set from the signal + * context, so it must skip the r3/r4 syscall-return stores at the + * head of ret_from_trap which would otherwise overwrite the + * just-restored r3/r4. Every C function returns with "rtsd r15, 8" + * -- the ABI return, where the 8 skips the caller's branch and its + * delay slot -- so bias r15 by -8 to land on ret_from_trap_no_rval. + */ + addik r15, r0, ret_from_trap_no_rval - 8 brid sys_rt_sigreturn /* Do real work */ - addik r5, r1, 0; /* add user context as 1st arg */ + addik r5, r1, PTO; /* add user context as 1st arg */ /* * HW EXCEPTION rutine start @@ -530,7 +550,7 @@ C_ENTRY(full_exception_trap): addik r17, r17, -4 SAVE_STATE /* Save registers */ /* PC, before IRQ/trap - this is one instruction above */ - swi r17, r1, PT_PC; + swi r17, r1, PTO+PT_PC; tovirt(r1,r1) /* FIXME this can be store directly in PT_ESR reg. * I tested it but there is a fault */ @@ -540,7 +560,7 @@ C_ENTRY(full_exception_trap): mfs r7, rfsr; /* save FSR */ mts rfsr, r0; /* Clear sticky fsr */ rted r0, full_exception - addik r5, r1, 0 /* parameter struct pt_regs * regs */ + addik r5, r1, PTO /* parameter struct pt_regs * regs */ /* * Unaligned data trap. @@ -566,14 +586,14 @@ C_ENTRY(unaligned_data_trap): lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); SAVE_STATE /* Save registers.*/ /* PC, before IRQ/trap - this is one instruction above */ - swi r17, r1, PT_PC; + swi r17, r1, PTO+PT_PC; tovirt(r1,r1) /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc-8 mfs r3, resr /* ESR */ mfs r4, rear /* EAR */ rtbd r0, _unaligned_data_exception - addik r7, r1, 0 /* parameter struct pt_regs * regs */ + addik r7, r1, PTO /* parameter struct pt_regs * regs */ /* * Page fault traps. @@ -596,30 +616,30 @@ C_ENTRY(unaligned_data_trap): C_ENTRY(page_fault_data_trap): SAVE_STATE /* Save registers.*/ /* PC, before IRQ/trap - this is one instruction above */ - swi r17, r1, PT_PC; + swi r17, r1, PTO+PT_PC; tovirt(r1,r1) /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc-8 mfs r6, rear /* parameter unsigned long address */ mfs r7, resr /* parameter unsigned long error_code */ rted r0, do_page_fault - addik r5, r1, 0 /* parameter struct pt_regs * regs */ + addik r5, r1, PTO /* parameter struct pt_regs * regs */ C_ENTRY(page_fault_instr_trap): SAVE_STATE /* Save registers.*/ /* PC, before IRQ/trap - this is one instruction above */ - swi r17, r1, PT_PC; + swi r17, r1, PTO+PT_PC; tovirt(r1,r1) /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc-8 mfs r6, rear /* parameter unsigned long address */ ori r7, r0, 0 /* parameter unsigned long error_code */ rted r0, do_page_fault - addik r5, r1, 0 /* parameter struct pt_regs * regs */ + addik r5, r1, PTO /* parameter struct pt_regs * regs */ /* Entry point used to return from an exception. */ C_ENTRY(ret_from_exc): - lwi r11, r1, PT_MODE; + lwi r11, r1, PTO+PT_MODE; bnei r11, 2f; /* See if returning to kernel mode, */ /* ... if so, skip resched &c. */ @@ -651,7 +671,7 @@ C_ENTRY(ret_from_exc): * complete register state. Here we save anything not saved by * the normal entry sequence, so that it may be safely restored * (in a possibly modified form) after do_notify_resume returns. */ - addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ + addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ bralid r15, do_notify_resume; /* Handle any signals */ addi r6, r0, 0; /* Arg 2: int in_syscall */ bri 1b @@ -663,7 +683,7 @@ C_ENTRY(ret_from_exc): tophys(r1,r1); RESTORE_REGS_RTBD; - addik r1, r1, PT_SIZE /* Clean up stack space. */ + addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */ bri 6f; @@ -672,7 +692,7 @@ C_ENTRY(ret_from_exc): VM_OFF; tophys(r1,r1); RESTORE_REGS_RTBD; - addik r1, r1, PT_SIZE /* Clean up stack space. */ + addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ tovirt(r1,r1); 6: @@ -705,10 +725,10 @@ C_ENTRY(_interrupt): tophys(r1,r1); /* MS: I have in r1 physical address where stack is */ /* save registers */ /* MS: Make room on the stack -> activation record */ - addik r1, r1, -PT_SIZE; + addik r1, r1, -STATE_SAVE_SIZE; SAVE_REGS brid 2f; - swi r1, r1, PT_MODE; /* 0 - user mode, 1 - kernel mode */ + swi r1, r1, PTO+PT_MODE; /* 0 - user mode, 1 - kernel mode */ 1: /* User-mode state save. */ /* MS: get the saved current */ @@ -718,23 +738,23 @@ C_ENTRY(_interrupt): addik r1, r1, THREAD_SIZE; tophys(r1,r1); /* save registers */ - addik r1, r1, -PT_SIZE; + addik r1, r1, -STATE_SAVE_SIZE; SAVE_REGS /* calculate mode */ - swi r0, r1, PT_MODE; + swi r0, r1, PTO+PT_MODE; lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); - swi r11, r1, PT_R1; + swi r11, r1, PTO+PT_R1; clear_ums; 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); tovirt(r1,r1) addik r15, r0, irq_call; irq_call:rtbd r0, do_IRQ; - addik r5, r1, 0; + addik r5, r1, PTO; /* MS: we are in virtual mode */ ret_from_irq: - lwi r11, r1, PT_MODE; + lwi r11, r1, PTO+PT_MODE; bnei r11, 2f; 1: @@ -750,7 +770,7 @@ ret_from_irq: 5: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; beqid r11, no_intr_resched /* Handle a signal return; Pending signals should be in r18. */ - addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ + addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ bralid r15, do_notify_resume; /* Handle any signals */ addi r6, r0, 0; /* Arg 2: int in_syscall */ bri 1b @@ -763,7 +783,7 @@ no_intr_resched: VM_OFF; tophys(r1,r1); RESTORE_REGS - addik r1, r1, PT_SIZE /* MS: Clean up stack space. */ + addik r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */ lwi r1, r1, PT_R1 - PT_SIZE; bri 6f; /* MS: Return to kernel state. */ @@ -786,7 +806,7 @@ restore: VM_OFF /* MS: turn off MMU */ tophys(r1,r1) RESTORE_REGS - addik r1, r1, PT_SIZE /* MS: Clean up stack space. */ + addik r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */ tovirt(r1,r1); 6: IRQ_return: /* MS: Make global symbol for debugging */ @@ -805,29 +825,29 @@ C_ENTRY(_xtmr_manager_reset): lwi r1, r0, xmb_manager_stackpointer /* Restore MSR */ - lwi r2, r1, PT_MSR + lwi r2, r1, PTO+PT_MSR mts rmsr, r2 bri 4 /* restore Special purpose registers */ - lwi r2, r1, PT_PID + lwi r2, r1, PTO+PT_PID mts rpid, r2 - lwi r2, r1, PT_TLBI + lwi r2, r1, PTO+PT_TLBI mts rtlbx, r2 - lwi r2, r1, PT_ZPR + lwi r2, r1, PTO+PT_ZPR mts rzpr, r2 #if CONFIG_XILINX_MICROBLAZE0_USE_FPU - lwi r2, r1, PT_FSR + lwi r2, r1, PTO+PT_FSR mts rfsr, r2 #endif /* restore all the tlb's */ addik r3, r0, TOPHYS(tlb_skip) - addik r6, r0, PT_TLBL0 - addik r7, r0, PT_TLBH0 + addik r6, r0, PTO+PT_TLBL0 + addik r7, r0, PTO+PT_TLBH0 restore_tlb: add r6, r6, r1 add r7, r7, r1 @@ -853,9 +873,9 @@ ret_from_reset: VM_OFF /* MS: Restore all regs */ RESTORE_REGS - lwi r14, r1, PT_R14 - lwi r16, r1, PT_PC - addik r1, r1, PT_SIZE + 36 + lwi r14, r1, PTO+PT_R14 + lwi r16, r1, PTO+PT_PC + addik r1, r1, STATE_SAVE_SIZE + 36 rtbd r16, 0 nop @@ -870,11 +890,11 @@ C_ENTRY(_xmb_manager_break): * Reserve memory in the stack for context store/restore * (which includes memory for storing tlbs (max two tlbs)) */ - addik r1, r1, -PT_SIZE - 36 + addik r1, r1, -STATE_SAVE_SIZE - 36 swi r1, r0, xmb_manager_stackpointer SAVE_REGS - swi r14, r1, PT_R14 /* rewrite saved R14 value */ - swi r16, r1, PT_PC; /* PC and r16 are the same */ + swi r14, r1, PTO+PT_R14 /* rewrite saved R14 value */ + swi r16, r1, PTO+PT_PC; /* PC and r16 are the same */ lwi r6, r0, TOPHYS(xmb_manager_baseaddr) lwi r7, r0, TOPHYS(xmb_manager_crval) @@ -888,25 +908,25 @@ C_ENTRY(_xmb_manager_break): /* Save the special purpose registers */ mfs r2, rpid - swi r2, r1, PT_PID + swi r2, r1, PTO+PT_PID mfs r2, rtlbx - swi r2, r1, PT_TLBI + swi r2, r1, PTO+PT_TLBI mfs r2, rzpr - swi r2, r1, PT_ZPR + swi r2, r1, PTO+PT_ZPR #if CONFIG_XILINX_MICROBLAZE0_USE_FPU mfs r2, rfsr - swi r2, r1, PT_FSR + swi r2, r1, PTO+PT_FSR #endif mfs r2, rmsr - swi r2, r1, PT_MSR + swi r2, r1, PTO+PT_MSR /* Save all the tlb's */ addik r3, r0, TOPHYS(tlb_skip) - addik r6, r0, PT_TLBL0 - addik r7, r0, PT_TLBH0 + addik r6, r0, PTO+PT_TLBL0 + addik r7, r0, PTO+PT_TLBH0 save_tlb: add r6, r6, r1 add r7, r7, r1 @@ -943,7 +963,7 @@ ret_from_break: mbar 1 mbar 2 bri 4 - suspend + mbar 24 /* suspend */ nop #endif @@ -963,28 +983,28 @@ C_ENTRY(_debug_exception): lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ /* BIP bit is set on entry, no interrupts can occur */ - addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; + addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; SAVE_REGS; /* save all regs to pt_reg structure */ - swi r0, r1, PT_R0; /* R0 must be saved too */ - swi r14, r1, PT_R14 /* rewrite saved R14 value */ - swi r16, r1, PT_PC; /* PC and r16 are the same */ + swi r0, r1, PTO+PT_R0; /* R0 must be saved too */ + swi r14, r1, PTO+PT_R14 /* rewrite saved R14 value */ + swi r16, r1, PTO+PT_PC; /* PC and r16 are the same */ /* save special purpose registers to pt_regs */ mfs r11, rear; - swi r11, r1, PT_EAR; + swi r11, r1, PTO+PT_EAR; mfs r11, resr; - swi r11, r1, PT_ESR; + swi r11, r1, PTO+PT_ESR; mfs r11, rfsr; - swi r11, r1, PT_FSR; + swi r11, r1, PTO+PT_FSR; /* stack pointer is in physical address at it is decrease - * by PT_SIZE but we need to get correct R1 value */ - addik r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + PT_SIZE; - swi r11, r1, PT_R1 + * by STATE_SAVE_SIZE but we need to get correct R1 value */ + addik r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + STATE_SAVE_SIZE; + swi r11, r1, PTO+PT_R1 /* MS: r31 - current pointer isn't changed */ tovirt(r1,r1) #ifdef CONFIG_KGDB - addi r5, r1, 0 /* pass pt_reg address as the first arg */ + addi r5, r1, PTO /* pass pt_reg address as the first arg */ addik r15, r0, dbtrap_call; /* return address */ rtbd r0, microblaze_kgdb_break nop; @@ -1000,16 +1020,16 @@ C_ENTRY(_debug_exception): addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */ tophys(r1,r1); - addik r1, r1, -PT_SIZE; /* Make room on the stack. */ + addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ SAVE_REGS; - swi r16, r1, PT_PC; /* Save LP */ - swi r0, r1, PT_MODE; /* Was in user-mode. */ + swi r16, r1, PTO+PT_PC; /* Save LP */ + swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); - swi r11, r1, PT_R1; /* Store user SP. */ + swi r11, r1, PTO+PT_R1; /* Store user SP. */ lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); tovirt(r1,r1) set_vms; - addik r5, r1, 0; + addik r5, r1, PTO; addik r15, r0, dbtrap_call; dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */ rtbd r0, sw_exception @@ -1017,7 +1037,7 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */ /* MS: The first instruction for the second part of the gdb/kgdb */ set_bip; /* Ints masked for state restore */ - lwi r11, r1, PT_MODE; + lwi r11, r1, PTO+PT_MODE; bnei r11, 2f; /* MS: Return to user space - gdb */ 1: @@ -1036,7 +1056,7 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */ 5: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; beqi r11, 4f; /* Signals to handle, handle them */ - addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ + addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ bralid r15, do_notify_resume; /* Handle any signals */ addi r6, r0, 0; /* Arg 2: int in_syscall */ bri 1b @@ -1047,7 +1067,7 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */ tophys(r1,r1); /* MS: Restore all regs */ RESTORE_REGS_RTBD - addik r1, r1, PT_SIZE /* Clean up stack space */ + addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space */ lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */ DBTRAP_return_user: /* MS: Make global symbol for debugging */ rtbd r16, 0; /* MS: Instructions to return from a debug trap */ @@ -1058,9 +1078,9 @@ DBTRAP_return_user: /* MS: Make global symbol for debugging */ tophys(r1,r1); /* MS: Restore all regs */ RESTORE_REGS_RTBD - lwi r14, r1, PT_R14; - lwi r16, r1, PT_PC; - addik r1, r1, PT_SIZE; /* MS: Clean up stack space */ + lwi r14, r1, PTO+PT_R14; + lwi r16, r1, PTO+PT_PC; + addik r1, r1, STATE_SAVE_SIZE; /* MS: Clean up stack space */ tovirt(r1,r1); DBTRAP_return_kernel: /* MS: Make global symbol for debugging */ rtbd r16, 0; /* MS: Instructions to return from a debug trap */ @@ -1158,7 +1178,7 @@ ENTRY(_switch_to) .ent xmb_inject_err .type xmb_inject_err, @function xmb_inject_err: - addik r1, r1, -PT_SIZE + addik r1, r1, -STATE_SAVE_SIZE SAVE_REGS /* Switch to real mode */ @@ -1182,7 +1202,7 @@ xmb_inject_err: nop; 1: RESTORE_REGS - addik r1, r1, PT_SIZE + addik r1, r1, STATE_SAVE_SIZE rtsd r15, 8; nop; .end xmb_inject_err diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index 07ea23965f81..4693916be526 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S @@ -313,6 +313,11 @@ _MB_HW_ExceptionVectorTable: .align 4 .ent _hw_exception_handler _hw_exception_handler: + /* + * This handler saves into the static pt_pool_space buffer, not into a + * stack frame, so the plain PT_* offsets are right here -- do not add + * the PTO of entry.S's frames. + */ swi r1, r0, TOPHYS(pt_pool_space + PT_R1); /* GET_SP */ /* Save date to kernel memory. Here is the problem * when you came from user space */ diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index 6cbf642d7b80..090e1697ea7a 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c @@ -19,6 +19,7 @@ #include #include #include +#include void show_regs(struct pt_regs *regs) { @@ -65,7 +66,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) * the registers. That's OK for a brand new thread.*/ memset(childregs, 0, sizeof(struct pt_regs)); memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); - ti->cpu_context.r1 = (unsigned long)childregs; + ti->cpu_context.r1 = (unsigned long)childregs - PTO; ti->cpu_context.r20 = (unsigned long)args->fn; ti->cpu_context.r19 = (unsigned long)args->fn_arg; childregs->pt_mode = 1; @@ -79,7 +80,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) childregs->r1 = usp; memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); - ti->cpu_context.r1 = (unsigned long)childregs; + ti->cpu_context.r1 = (unsigned long)childregs - PTO; childregs->msr |= MSR_UMS; /* we should consider the fact that childregs is a copy of the parent diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index c78a0ff48066..6bbc16f98d5e 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,14 @@ struct sigframe { }; struct rt_sigframe { + /* + * Home area for the handler's register arguments: the MicroBlaze + * ABI reserves [r1+0] for the return address and lets the callee + * store r5..r10 at [r1+4]..[r1+24], and r1 points at this frame + * when the handler is entered. Without the gap those stores + * corrupt frame->info. + */ + unsigned long abi_gap[7]; struct siginfo info; struct ucontext uc; unsigned long tramp[2]; /* signal trampoline */ @@ -73,6 +82,22 @@ static int restore_sigcontext(struct pt_regs *regs, COPY(pc); COPY(ear); COPY(esr); COPY(fsr); #undef COPY + /* + * The frame is user-writable, so restore only the user-writable + * status flags (carry) and keep the kernel-controlled MSR bits + * (UMS/VMS/IE/EE/...) from regs->msr: rtbd derives the resumed mode + * from UMS/VMS, so a verbatim restore would hand userspace the + * privileged return state. Same idea as x86 masking the restored + * EFLAGS to FIX_EFLAGS. + */ + { + unsigned long msr; + + err |= __get_user(msr, &sc->regs.msr); + regs->msr = (regs->msr & ~(MSR_C | MSR_CC)) | + (msr & (MSR_C | MSR_CC)); + } + *rval_p = regs->r3; return err; @@ -132,6 +157,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, COPY(r26); COPY(r27); COPY(r28); COPY(r29); COPY(r30); COPY(r31); COPY(pc); COPY(ear); COPY(esr); COPY(fsr); + COPY(msr); /* restore_sigcontext() accepts only carry state */ #undef COPY err |= __put_user(mask, &sc->oldmask); diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c index 5d2a1225785b..119edaa928f3 100644 --- a/arch/mips/mm/mmap.c +++ b/arch/mips/mm/mmap.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -72,8 +73,11 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp, } info.length = len; - info.align_mask = do_color_align ? (PAGE_MASK & shm_align_mask) : 0; info.align_offset = pgoff << PAGE_SHIFT; + if (filp && is_file_hugepages(filp)) + info.align_mask = huge_page_mask_align(filp); + else + info.align_mask = do_color_align ? (PAGE_MASK & shm_align_mask) : 0; if (dir == DOWN) { info.flags = VM_UNMAPPED_AREA_TOPDOWN; diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 24fe85fa169d..78bafa317fa6 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -332,6 +332,19 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) /* this could be a huge page */ if (pmd_leaf(*pmdp)) { unsigned long lo; + + /* + * The probe above only covers the 8K pair at @address, and + * a huge mapping is installed with the huge-aligned address + * while the refill that started the fault left a 4K entry + * for the faulting page elsewhere in the range. Writing the + * huge entry to a random index would leave two entries + * matching the faulting address; leave it to the refill and + * TLBL/TLBS handlers, which probe the faulting address. + */ + if (idx < 0) + goto out; + write_c0_pagemask(PM_HUGE_MASK); ptep = (pte_t *)pmdp; lo = pte_to_entrylo(pte_val(*ptep)); @@ -339,10 +352,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) write_c0_entrylo1(lo + (HPAGE_SIZE >> 7)); mtc0_tlbw_hazard(); - if (idx < 0) - tlb_write_random(); - else - tlb_write_indexed(); + tlb_write_indexed(); tlbw_use_hazard(); write_c0_pagemask(PM_DEFAULT_MASK); } else @@ -380,6 +390,9 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) tlb_write_indexed(); } tlbw_use_hazard(); +#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT +out: +#endif htw_start(); flush_micro_tlb_vm(vma); diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c index b1667ed05f98..719f7e513c5a 100644 --- a/arch/powerpc/platforms/pseries/plpks.c +++ b/arch/powerpc/platforms/pseries/plpks.c @@ -434,6 +434,9 @@ int plpks_signed_update_var(struct plpks_var *var, u64 flags) u64 continuetoken = 0; u64 timeout = 0; + if (!var) + return -EINVAL; + if (!var->data || var->datalen <= 0 || var->namelen > PLPKS_MAX_NAME_SIZE) return -EINVAL; @@ -476,7 +479,7 @@ int plpks_signed_update_var(struct plpks_var *var, u64 flags) kfree(label); out: - kfree(auth); + kfree_sensitive(auth); return rc; } @@ -515,7 +518,7 @@ int plpks_write_var(struct plpks_var var) rc = pseries_status_to_err(rc); kfree(label); out: - kfree(auth); + kfree_sensitive(auth); return rc; } @@ -549,7 +552,7 @@ int plpks_remove_var(char *component, u8 varos, struct plpks_var_name vname) rc = pseries_status_to_err(rc); kfree(label); out: - kfree(auth); + kfree_sensitive(auth); return rc; } @@ -562,6 +565,9 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var) u8 *output; int rc; + if (!var) + return -EINVAL; + if (var->namelen > PLPKS_MAX_NAME_SIZE) return -EINVAL; @@ -593,28 +599,27 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var) virt_to_phys(var->name), var->namelen, virt_to_phys(output), maxobjsize); - if (rc != H_SUCCESS) { rc = pseries_status_to_err(rc); - goto out_free_output; + if (rc != -EPERM || !retbuf[1]) + goto out_free_output; + goto out_copy_policy; } if (!var->data || var->datalen > retbuf[0]) var->datalen = retbuf[0]; - var->policy = retbuf[1]; - if (var->data) memcpy(var->data, output, var->datalen); - rc = 0; - +out_copy_policy: + var->policy = retbuf[1]; out_free_output: - kfree(output); + kfree_sensitive(output); out_free_label: kfree(label); out_free_auth: - kfree(auth); + kfree_sensitive(auth); return rc; } diff --git a/arch/powerpc/platforms/pseries/plpks_sed_ops.c b/arch/powerpc/platforms/pseries/plpks_sed_ops.c index 7c873c9589ef..ac3ec2ca7fbe 100644 --- a/arch/powerpc/platforms/pseries/plpks_sed_ops.c +++ b/arch/powerpc/platforms/pseries/plpks_sed_ops.c @@ -84,14 +84,16 @@ int sed_read_key(char *keyname, char *key, u_int *keylen) ret = plpks_read_os_var(&var); if (ret != 0) - return ret; + goto out; len = min_t(u16, be32_to_cpu(data.key_len), var.datalen); memcpy(key, data.key, len); key[len] = '\0'; *keylen = len; - return 0; +out: + memzero_explicit(&data, sizeof(data)); + return ret; } /* @@ -102,6 +104,7 @@ int sed_write_key(char *keyname, char *key, u_int keylen) struct plpks_var var; struct plpks_sed_object_data data; struct plpks_var_name vname; + int ret; plpks_init_var(&var, keyname); @@ -127,5 +130,8 @@ int sed_write_key(char *keyname, char *key, u_int keylen) vname.name = var.name; plpks_remove_var(var.component, var.os, vname); - return plpks_write_var(var); + ret = plpks_write_var(var); + memzero_explicit(&data, sizeof(data)); + + return ret; } diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index 9b2e967c9fe0..420d402336d0 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -833,7 +833,14 @@ static inline bool pte_user_accessible_page(pte_t pte) static inline bool pmd_user_accessible_page(pmd_t pmd) { - return pmd_leaf(pmd) && pmd_user(pmd); + /* + * page_table_check() must ignore THP split invalidation entries created by + * pmd_mkinvalid(). These retain _PAGE_LEAF so pmd_present()/pmd_leaf() stay + * true during the split, but they no longer describe a user-accessible + * mapping once both _PAGE_PRESENT and _PAGE_PROT_NONE are cleared. + */ + return (pmd_val(pmd) & (_PAGE_PRESENT | _PAGE_PROT_NONE)) && + (pmd_val(pmd) & _PAGE_LEAF) && pmd_user(pmd); } static inline bool pud_user_accessible_page(pud_t pud) diff --git a/arch/riscv/kvm/vcpu_sbi_replace.c b/arch/riscv/kvm/vcpu_sbi_replace.c index b490ed1428a6..df3818fec0bf 100644 --- a/arch/riscv/kvm/vcpu_sbi_replace.c +++ b/arch/riscv/kvm/vcpu_sbi_replace.c @@ -64,8 +64,17 @@ static int kvm_sbi_ext_ipi_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, if (tmp->vcpu_id < hbase) continue; hart_bit = tmp->vcpu_id - hbase; + /* + * kvm_for_each_vcpu() walks kvm->vcpus[] by + * vcpu_idx, i.e. the creation order, which has + * nothing to do with the vcpu_id (hart id) space + * that the SBI IPI operates on. vcpu_ids need not + * increase along the iteration, so harts outside + * the hart_mask window must be skipped instead of + * aborting the loop. + */ if (hart_bit >= __riscv_xlen) - goto done; + continue; if (!(hmask & (1UL << hart_bit))) continue; } @@ -76,7 +85,6 @@ static int kvm_sbi_ext_ipi_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, kvm_riscv_vcpu_pmu_incr_fw(tmp, SBI_PMU_FW_IPI_RCVD); } -done: if (hbase != -1UL && (hmask ^ sentmask)) retdata->err_val = SBI_ERR_INVALID_PARAM; diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index b60b4a82ea20..de7da218835e 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -502,6 +502,7 @@ #define X86_FEATURE_IBPB_EXIT_TO_USER (21*32+14) /* Use IBPB on exit-to-userspace, see VMSCAPE bug */ #define X86_FEATURE_ABMC (21*32+15) /* Assignable Bandwidth Monitoring Counters */ #define X86_FEATURE_MSR_IMM (21*32+16) /* MSR immediate form instructions */ +#define X86_FEATURE_TSA_FILL_NO (21*32+17) /* AMD CPU not vulnerable to TSA-FILL */ /* * BUG word(s) diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index c85c50019523..a9daddd84ad6 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -20,6 +20,14 @@ #include #include +/* + * UNDEFINED is a KVM-defined value used to indicate that the basic exit reason + * is undefined/invalid, e.g. on VM-Fail or if TDX never attempted VM-Enter. + * The value itself is arbitrary, it just needs to not collide with a real exit + * reason. + */ +#define EXIT_REASON_UNDEFINED 0xdead + #define VMCS_CONTROL_BIT(x) BIT(VMX_FEATURE_##x & 0x1f) /* diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index ca4265a1f4bb..bd274c2b4c6a 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -413,9 +413,14 @@ static void tsa_init(struct cpuinfo_x86 *c) else pr_debug("%s: current revision: 0x%x\n", __func__, c->microcode); } else { - setup_force_cpu_cap(X86_FEATURE_TSA_SQ_NO); - setup_force_cpu_cap(X86_FEATURE_TSA_L1_NO); + if (!cpu_has(c, X86_FEATURE_ZEN5)) { + setup_force_cpu_cap(X86_FEATURE_TSA_SQ_NO); + setup_force_cpu_cap(X86_FEATURE_TSA_L1_NO); + } } + + if (!cpu_has(c, X86_FEATURE_ZEN5)) + setup_force_cpu_cap(X86_FEATURE_TSA_FILL_NO); } static void bsp_init_amd(struct cpuinfo_x86 *c) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index a39d97eee8bd..90d0488d54c5 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -2103,7 +2103,7 @@ early_param("spectre_v2", spectre_v2_parse_cmdline); static enum spectre_v2_mitigation __init spectre_v2_select_retpoline(void) { if (!IS_ENABLED(CONFIG_MITIGATION_RETPOLINE)) { - pr_err("Kernel not compiled with retpoline; no mitigation available!"); + pr_err("Kernel not compiled with retpoline"); return SPECTRE_V2_NONE; } diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 3ffeadad0244..b0de3aabcd79 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1299,7 +1299,7 @@ static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = { VULNBL_AMD(0x17, RETBLEED | SMT_RSB | SRSO | VMSCAPE), VULNBL_HYGON(0x18, RETBLEED | SMT_RSB | SRSO | VMSCAPE), VULNBL_AMD(0x19, SRSO | TSA | VMSCAPE), - VULNBL_AMD(0x1a, SRSO | VMSCAPE), + VULNBL_AMD(0x1a, SRSO | TSA | VMSCAPE), {} }; @@ -1564,7 +1564,8 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) if (c->x86_vendor == X86_VENDOR_AMD) { if (!cpu_has(c, X86_FEATURE_TSA_SQ_NO) || - !cpu_has(c, X86_FEATURE_TSA_L1_NO)) { + !cpu_has(c, X86_FEATURE_TSA_L1_NO) || + !cpu_has(c, X86_FEATURE_TSA_FILL_NO)) { if (cpu_matches(cpu_vuln_blacklist, TSA) || /* Enable bug on Zen guests to allow for live migration. */ (cpu_has(c, X86_FEATURE_HYPERVISOR) && cpu_has(c, X86_FEATURE_ZEN))) diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index c4bc3c259f3f..083403886da2 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -55,6 +55,7 @@ static const struct cpuid_bit cpuid_bits[] = { { X86_FEATURE_ABMC, CPUID_EBX, 5, 0x80000020, 0 }, { X86_FEATURE_TSA_SQ_NO, CPUID_ECX, 1, 0x80000021, 0 }, { X86_FEATURE_TSA_L1_NO, CPUID_ECX, 2, 0x80000021, 0 }, + { X86_FEATURE_TSA_FILL_NO, CPUID_ECX, 7, 0x80000021, 0 }, { X86_FEATURE_AMD_WORKLOAD_CLASS, CPUID_EAX, 22, 0x80000021, 0 }, { X86_FEATURE_BTB_CTX_ISOLATION, CPUID_ECX, 8, 0x80000021, 0 }, { X86_FEATURE_PERFMON_V2, CPUID_EAX, 0, 0x80000022, 0 }, diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 913ffb995279..a35ca056fe3e 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -1231,6 +1231,7 @@ void kvm_set_cpu_caps(void) kvm_cpu_cap_init(CPUID_8000_0021_ECX, SYNTHESIZED_F(TSA_SQ_NO), SYNTHESIZED_F(TSA_L1_NO), + SYNTHESIZED_F(TSA_FILL_NO), ); kvm_cpu_cap_init(CPUID_8000_0022_EAX, diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h index 743ab25ba787..dcd8ed7c5ed4 100644 --- a/arch/x86/kvm/reverse_cpuid.h +++ b/arch/x86/kvm/reverse_cpuid.h @@ -58,6 +58,7 @@ /* CPUID level 0x80000021 (ECX) */ #define KVM_X86_FEATURE_TSA_SQ_NO KVM_X86_FEATURE(CPUID_8000_0021_ECX, 1) #define KVM_X86_FEATURE_TSA_L1_NO KVM_X86_FEATURE(CPUID_8000_0021_ECX, 2) +#define KVM_X86_FEATURE_TSA_FILL_NO KVM_X86_FEATURE(CPUID_8000_0021_ECX, 7) struct cpuid_reg { u32 function; @@ -133,6 +134,7 @@ static __always_inline u32 __feature_translate(int x86_feature) KVM_X86_TRANSLATE_FEATURE(TSA_SQ_NO); KVM_X86_TRANSLATE_FEATURE(TSA_L1_NO); KVM_X86_TRANSLATE_FEATURE(MSR_IMM); + KVM_X86_TRANSLATE_FEATURE(TSA_FILL_NO); default: return x86_feature; } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 8da96a6c6177..ced20415a14f 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -6151,6 +6151,8 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { static const int kvm_vmx_max_exit_handlers = ARRAY_SIZE(kvm_vmx_exit_handlers); +static_assert(EXIT_REASON_UNDEFINED >= ARRAY_SIZE(kvm_vmx_exit_handlers)); + void vmx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason, u64 *info1, u64 *info2, u32 *intr_info, u32 *error_code) { @@ -7333,7 +7335,7 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu, vmx_enable_fb_clear(vmx); if (unlikely(vmx->fail)) { - vmx->vt.exit_reason.full = 0xdead; + vmx->vt.exit_reason.full = EXIT_REASON_UNDEFINED; goto out; } diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c index 12b7de5f0957..9fc18a091311 100644 --- a/arch/x86/mm/pat/set_memory.c +++ b/arch/x86/mm/pat/set_memory.c @@ -718,6 +718,21 @@ static inline pgprot_t verify_rwx(pgprot_t old, pgprot_t new, unsigned long star return new; end = start + npg * PAGE_SIZE - 1; + + /* + * If the kernel text is still RWX, gently complain, this could be a + * false positive. + * Once debug_checkwx() becomes mandatory for CONFIG_STRICT_KERNEL_RWX, + * the warning can be removed completely. + */ + if (!kernel_set_to_readonly) { + pr_warn_once("CPA detected W^X violation: %016llx -> %016llx range: 0x%016lx - 0x%016lx PFN %lx\n", + (unsigned long long)pgprot_val(old), + (unsigned long long)pgprot_val(new), + start, end, pfn); + return new; + } + WARN_ONCE(1, "CPA detected W^X violation: %016llx -> %016llx range: 0x%016lx - 0x%016lx PFN %lx\n", (unsigned long long)pgprot_val(old), (unsigned long long)pgprot_val(new), diff --git a/block/blk-iocost.c b/block/blk-iocost.c index d0b13580c6b6..5c7cdb493768 100644 --- a/block/blk-iocost.c +++ b/block/blk-iocost.c @@ -1965,6 +1965,7 @@ static void transfer_surpluses(struct list_head *surpluses, struct ioc_now *now) pr_cont(": active=%u donating=%u after=%u\n", iocg->hweight_active, iocg->hweight_donating, iocg->hweight_after_donation); + goto out; } } @@ -2063,6 +2064,7 @@ static void transfer_surpluses(struct list_head *surpluses, struct ioc_now *now) __propagate_weights(iocg, iocg->active, inuse, true, now); } +out: /* walk list should be dissolved after use */ list_for_each_entry_safe(iocg, tiocg, &inner_walk, walk_list) list_del_init(&iocg->walk_list); diff --git a/block/blk-mq.c b/block/blk-mq.c index ba0c48d58e13..cced68a0e3c5 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1428,6 +1428,7 @@ static void blk_add_rq_to_plug(struct blk_plug *plug, struct request *rq) (!blk_queue_nomerges(rq->q) && blk_rq_bytes(last) >= BLK_PLUG_FLUSH_SIZE)) { blk_mq_flush_plug_list(plug, false); + blk_plug_invalidate_ts(); last = NULL; trace_block_plug(rq->q); } @@ -4015,6 +4016,7 @@ static int blk_mq_init_hctx(struct request_queue *q, goto fail; hctx->queue_num = hctx_idx; + clear_bit(BLK_MQ_S_INACTIVE, &hctx->state); hctx->tags = set->tags[hctx_idx]; diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 35ebc3e0201b..b245d37db76b 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -116,12 +116,16 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, * full block size buffers. */ if (ctx->more || len < ctx->used) { - if (len < bs) { + size_t excess = len % bs; + + len -= excess; + iov_iter_revert(&msg->msg_iter, excess); + + if (!len) { err = -EINVAL; goto free; } - len -= len % bs; cflags |= CRYPTO_SKCIPHER_REQ_NOTFINAL; } diff --git a/crypto/ecc.c b/crypto/ecc.c index f97ff234086f..a289d47d5651 100644 --- a/crypto/ecc.c +++ b/crypto/ecc.c @@ -1410,9 +1410,22 @@ static void ecc_point_add(const struct ecc_point *result, vli_set(result->x, q->x, ndigits); vli_set(result->y, q->y, ndigits); vli_mod_sub(z, result->x, p->x, curve->p, ndigits); + if (vli_is_zero(z, ndigits)) { + if (vli_cmp(p->y, q->y, ndigits)) { + /* P + (-P) is the point at infinity. */ + vli_clear(result->x, ndigits); + vli_clear(result->y, ndigits); + return; + } + /* The co-Z addition formula does not handle P == Q. */ + z[0] = 1; + ecc_point_double_jacobian(result->x, result->y, z, curve); + goto out; + } vli_set(px, p->x, ndigits); vli_set(py, p->y, ndigits); xycz_add(px, py, result->x, result->y, curve); +out: vli_mod_inv(z, z, curve->p, ndigits); apply_z(result->x, result->y, z, curve); } @@ -1452,22 +1465,38 @@ void ecc_point_mult_shamir(const struct ecc_point *result, vli_set(rx, point->x, ndigits); vli_set(ry, point->y, ndigits); vli_clear(z + 1, ndigits - 1); - z[0] = 1; + z[0] = !ecc_point_is_zero(point); for (--i; i >= 0; i--) { ecc_point_double_jacobian(rx, ry, z, curve); idx = !!vli_test_bit(u1, i); idx |= (!!vli_test_bit(u2, i)) << 1; point = points[idx]; - if (point) { + if (point && !ecc_point_is_zero(point)) { u64 tx[ECC_MAX_DIGITS]; u64 ty[ECC_MAX_DIGITS]; u64 tz[ECC_MAX_DIGITS]; + if (vli_is_zero(z, ndigits)) { + /* Adding to infinity starts a new accumulator. */ + vli_set(rx, point->x, ndigits); + vli_set(ry, point->y, ndigits); + z[0] = 1; + continue; + } vli_set(tx, point->x, ndigits); vli_set(ty, point->y, ndigits); apply_z(tx, ty, z, curve); vli_mod_sub(tz, rx, tx, curve->p, ndigits); + if (vli_is_zero(tz, ndigits)) { + if (!vli_cmp(ry, ty, ndigits)) + ecc_point_double_jacobian(rx, ry, z, + curve); + else + /* Adding opposite points yields infinity. */ + vli_clear(z, ndigits); + continue; + } xycz_add(tx, ty, rx, ry, curve); vli_mod_mult_fast(z, z, tz, curve); } diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 6a490aaa71b9..8543e21a4259 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -4061,16 +4061,17 @@ static int test_sig_one(struct crypto_sig *tfm, const struct sig_testvec *vecs) */ err = crypto_sig_verify(tfm, vecs->c, vecs->c_size, vecs->m, vecs->m_size); - if (err) { - pr_err("alg: sig: verify test failed: err %d\n", err); - return err; + if (err != vecs->verify_error) { + pr_err("alg: sig: verify test failed: expected %d, got %d\n", + vecs->verify_error, err); + return err ?: -EINVAL; } /* * Don't invoke sign test (which requires a private key) - * for vectors with only a public key. + * for vectors with only a public key or an invalid signature. */ - if (vecs->public_key_vec) + if (vecs->public_key_vec || vecs->verify_error) return 0; sig_size = crypto_sig_maxsize(tfm); diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 268231227282..210dafb684fd 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -165,6 +165,7 @@ struct sig_testvec { unsigned int param_len; unsigned int m_size; unsigned int c_size; + int verify_error; bool public_key_vec; enum OID algo; }; @@ -1447,6 +1448,140 @@ static const struct sig_testvec x962_ecdsa_nist_p192_tv_template[] = { }; static const struct sig_testvec x962_ecdsa_nist_p256_tv_template[] = { + /* Invalid signature: Q = G, r = s, e = 3r mod n. */ + { + .key = + "\x04\x6b\x17\xd1\xf2\xe1\x2c\x42\x47\xf8\xbc\xe6\xe5\x63\xa4\x40" + "\xf2\x77\x03\x7d\x81\x2d\xeb\x33\xa0\xf4\xa1\x39\x45\xd8\x98\xc2" + "\x96\x4f\xe3\x42\xe2\xfe\x1a\x7f\x9b\x8e\xe7\xeb\x4a\x7c\x0f\x9e" + "\x16\x2b\xce\x33\x57\x6b\x31\x5e\xce\xcb\xb6\x40\x68\x37\xbf\x51" + "\xf5", + .key_len = 65, + .m = + "\xb2\xc3\x09\x72\x03\x17\x9d\xaa\x5c\x4a\xd8\xff\x02\xfe\xcb\x15" + "\x21\x53\x81\x77\x45\xec\x45\x24\x3d\x68\x10\xb9\xf2\xa5\x88\x3a", + .m_size = 32, + .c = + "\x30\x46\x02\x21\x00\x90\xeb\xad\xd0\x56\x5d\x34\x8e\x74\x18\xf2" + "\xff\xab\xaa\x43\xb1\x9f\x68\xd4\x0c\x4f\x01\x4b\xe3\x10\x60\x9e" + "\x7e\xfa\x58\x39\xd9\x02\x21\x00\x90\xeb\xad\xd0\x56\x5d\x34\x8e" + "\x74\x18\xf2\xff\xab\xaa\x43\xb1\x9f\x68\xd4\x0c\x4f\x01\x4b\xe3" + "\x10\x60\x9e\x7e\xfa\x58\x39\xd9", + .c_size = 72, + .verify_error = -EKEYREJECTED, + .public_key_vec = true, + }, + /* Invalid signature: Q = -G, r = s, e = 3r mod n. */ + { + .key = + "\x04\x6b\x17\xd1\xf2\xe1\x2c\x42\x47\xf8\xbc\xe6\xe5\x63\xa4\x40" + "\xf2\x77\x03\x7d\x81\x2d\xeb\x33\xa0\xf4\xa1\x39\x45\xd8\x98\xc2" + "\x96\xb0\x1c\xbd\x1c\x01\xe5\x80\x65\x71\x18\x14\xb5\x83\xf0\x61" + "\xe9\xd4\x31\xcc\xa9\x94\xce\xa1\x31\x34\x49\xbf\x97\xc8\x40\xae" + "\x0a", + .key_len = 65, + .m = + "\xb2\xc3\x09\x72\x03\x17\x9d\xaa\x5c\x4a\xd8\xff\x02\xfe\xcb\x15" + "\x21\x53\x81\x77\x45\xec\x45\x24\x3d\x68\x10\xb9\xf2\xa5\x88\x3a", + .m_size = 32, + .c = + "\x30\x46\x02\x21\x00\x90\xeb\xad\xd0\x56\x5d\x34\x8e\x74\x18\xf2" + "\xff\xab\xaa\x43\xb1\x9f\x68\xd4\x0c\x4f\x01\x4b\xe3\x10\x60\x9e" + "\x7e\xfa\x58\x39\xd9\x02\x21\x00\x90\xeb\xad\xd0\x56\x5d\x34\x8e" + "\x74\x18\xf2\xff\xab\xaa\x43\xb1\x9f\x68\xd4\x0c\x4f\x01\x4b\xe3" + "\x10\x60\x9e\x7e\xfa\x58\x39\xd9", + .c_size = 72, + .verify_error = -EKEYREJECTED, + .public_key_vec = true, + }, + /* Wycheproof secp256r1/SHA-256 tcId 60. */ + { + .key = + "\x04\x29\x27\xb1\x05\x12\xba\xe3\xed\xdc\xfe\x46\x78\x28\x12\x8b" + "\xad\x29\x03\x26\x99\x19\xf7\x08\x60\x69\xc8\xc4\xdf\x6c\x73\x28" + "\x38\xc7\x78\x79\x64\xea\xac\x00\xe5\x92\x1f\xb1\x49\x8a\x60\xf4" + "\x60\x67\x66\xb3\xd9\x68\x50\x01\x55\x8d\x1a\x97\x4e\x73\x41\x51" + "\x3e", + .key_len = 65, + .m = + "\x70\x23\x9d\xd8\x77\xf7\xc9\x44\xc4\x22\xf4\x4d\xea\x4e\xd1\xa5" + "\x2f\x26\x27\x41\x6f\xaf\x2f\x07\x2f\xa5\x0c\x77\x2e\xd6\xf8\x07", + .m_size = 32, + .c = + "\x30\x44\x02\x20\x64\xa1\xaa\xb5\x00\x0d\x0e\x80\x4f\x3e\x2f\xc0" + "\x2b\xde\xe9\xbe\x8f\xf3\x12\x33\x4e\x2b\xa1\x6d\x11\x54\x7c\x97" + "\x71\x1c\x89\x8e\x02\x20\x6a\xf0\x15\x97\x1c\xc3\x0b\xe6\xd1\xa2" + "\x06\xd4\xe0\x13\xe0\x99\x77\x72\xa2\xf9\x1d\x73\x28\x6f\xfd\x68" + "\x3b\x9b\xb2\xcf\x4f\x1b", + .c_size = 70, + .public_key_vec = true, + }, + /* Wycheproof secp256r1/SHA-256 tcId 210. */ + { + .key = + "\x04\xc6\xa7\x71\x52\x70\x24\x22\x77\x92\x17\x0a\x6f\x8e\xee\x73" + "\x5b\xf3\x2b\x7f\x98\xaf\x66\x9e\xad\x29\x98\x02\xe3\x2d\x7c\x31" + "\x07\xbc\x3b\x4b\x5e\x65\xab\x88\x7b\xbd\x34\x35\x72\xb3\xe5\x61" + "\x92\x61\xfe\x3a\x07\x3e\x2f\xfd\x78\x41\x2f\x72\x68\x67\xdb\x58" + "\x9e", + .key_len = 65, + .m = + "\xbb\x5a\x52\xf4\x2f\x9c\x92\x61\xed\x43\x61\xf5\x94\x22\xa1\xe3" + "\x00\x36\xe7\xc3\x2b\x27\x0c\x88\x07\xa4\x19\xfe\xca\x60\x50\x23", + .m_size = 32, + .c = + "\x30\x45\x02\x20\x7c\xf2\x7b\x18\x8d\x03\x4f\x7e\x8a\x52\x38\x03" + "\x04\xb5\x1a\xc3\xc0\x89\x69\xe2\x77\xf2\x1b\x35\xa6\x0b\x48\xfc" + "\x47\x66\x99\x78\x02\x21\x00\xb6\xdb\x6d\xb6\x24\x92\x49\x25\x49" + "\x24\x92\x49\x24\x92\x49\x24\x62\x5b\xd7\xa0\x9b\xec\x4c\xa8\x1b" + "\xcd\xd9\xf8\xfd\x6b\x63\xcc", + .c_size = 71, + .public_key_vec = true, + }, + /* Q = G, d = 1, k = 2. */ + { + .key = + "\x04\x6b\x17\xd1\xf2\xe1\x2c\x42\x47\xf8\xbc\xe6\xe5\x63\xa4\x40" + "\xf2\x77\x03\x7d\x81\x2d\xeb\x33\xa0\xf4\xa1\x39\x45\xd8\x98\xc2" + "\x96\x4f\xe3\x42\xe2\xfe\x1a\x7f\x9b\x8e\xe7\xeb\x4a\x7c\x0f\x9e" + "\x16\x2b\xce\x33\x57\x6b\x31\x5e\xce\xcb\xb6\x40\x68\x37\xbf\x51" + "\xf5", + .key_len = 65, + .m = + "\x35\x9d\x17\x29\xb9\x1a\x52\xe9\x8b\xb5\x95\xc3\x86\x28\x3c\x10" + "\x30\x44\x95\x1a\xa1\x08\x20\xf0\xa0\x22\xc4\x18\xc2\x71\xa0\xcc", + .m_size = 32, + .c = + "\x30\x44\x02\x20\x7c\xf2\x7b\x18\x8d\x03\x4f\x7e\x8a\x52\x38\x03" + "\x04\xb5\x1a\xc3\xc0\x89\x69\xe2\x77\xf2\x1b\x35\xa6\x0b\x48\xfc" + "\x47\x66\x99\x78\x02\x20\x59\x47\xc9\x21\x23\x0e\xd1\x34\x0b\x03" + "\xe6\xe3\x45\x6e\xab\x69\xf8\x66\xff\x7e\x8c\x7d\x1e\x13\x23\x17" + "\x06\x8a\x84\xec\x1d\x22", + .c_size = 70, + .public_key_vec = true, + }, + /* Q = -G, d = n - 1, k = 2. */ + { + .key = + "\x04\x6b\x17\xd1\xf2\xe1\x2c\x42\x47\xf8\xbc\xe6\xe5\x63\xa4\x40" + "\xf2\x77\x03\x7d\x81\x2d\xeb\x33\xa0\xf4\xa1\x39\x45\xd8\x98\xc2" + "\x96\xb0\x1c\xbd\x1c\x01\xe5\x80\x65\x71\x18\x14\xb5\x83\xf0\x61" + "\xe9\xd4\x31\xcc\xa9\x94\xce\xa1\x31\x34\x49\xbf\x97\xc8\x40\xae" + "\x0a", + .key_len = 65, + .m = + "\x35\x9d\x17\x29\xb9\x1a\x52\xe9\x8b\xb5\x95\xc3\x86\x28\x3c\x10" + "\x30\x44\x95\x1a\xa1\x08\x20\xf0\xa0\x22\xc4\x18\xc2\x71\xa0\xcc", + .m_size = 32, + .c = + "\x30\x45\x02\x20\x7c\xf2\x7b\x18\x8d\x03\x4f\x7e\x8a\x52\x38\x03" + "\x04\xb5\x1a\xc3\xc0\x89\x69\xe2\x77\xf2\x1b\x35\xa6\x0b\x48\xfc" + "\x47\x66\x99\x78\x02\x21\x00\xdc\x55\x4e\x07\x96\x0b\x81\xb6\x80" + "\xb1\xae\xe0\x40\xb9\x90\xa5\xf4\xc4\x90\x49\xbb\xa2\xa1\x62\x70" + "\xc5\x88\x51\x39\xe8\xa8\xfb", + .c_size = 71, + .public_key_vec = true, + }, { .key = /* secp256r1(sha1) */ "\x04\xb9\x7b\xbb\xd7\x17\x64\xd2\x7e\xfc\x81\x5d\x87\x06\x83\x41" @@ -1831,7 +1966,8 @@ static const struct sig_testvec p1363_ecdsa_nist_p256_tv_template[] = { }; /* - * EC-RDSA test vectors are generated by gost-engine. + * EC-RDSA test vectors generated by gost-engine, followed by constructed + * exceptional-point regression vectors. */ static const struct sig_testvec ecrdsa_tv_template[] = { { @@ -1977,6 +2113,195 @@ static const struct sig_testvec ecrdsa_tv_template[] = { .m_size = 64, .public_key_vec = true, }, + /* + * Constructed EC-RDSA exceptional-point vectors. + * With Q = dG, choose k = z1 + d*z2 (mod n), r = x(kG) mod n, + * e = -r/z2 (mod n), and s = r*d + k*e (mod n). + * The input digest is e, encoded little-endian. + */ + /* cp256a: Q=G, z1 = 3, z2 = 1. */ + { + .key = + "\x04\x40\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x14\x1e\x9f\x9e\x9c\xc9\xac\x22\xb1\xe3\x23\xdf\x2d\x4f" + "\x29\x35\x76\x2b\x3f\x45\x5a\x50\xdf\x27\xda\x9c\x98\xe0\x71\xe4" + "\x91\x8d", + .key_len = 66, + .params = /* OID_gostCPSignA */ + "\x30\x13\x06\x07\x2a\x85\x03\x02\x02\x23\x01\x06\x08\x2a\x85\x03" + "\x07\x01\x01\x02\x02", + .param_len = 21, + .c = + "\x1a\xed\x44\xae\xd4\x4a\xed\x44\xae\xd4\x4a\xed\x44\xae\xd4\x49" + "\x32\x67\xe0\x26\x16\xfd\xb7\xaf\xa4\xd7\x3e\x61\xd4\xf9\x7b\x94" + "\xf7\x06\x3e\x70\x63\xe7\x06\x3e\x70\x63\xe7\x06\x3e\x70\x63\xe7" + "\x06\x3e\x70\x63\xe7\x06\x3e\x70\x63\xe7\x06\x3e\x70\x63\xe4\xb7", + .c_size = 64, + .m = + "\xdc\xd3\xfd\x46\xcb\x14\x9d\xe1\x8f\x92\x54\xb2\x0c\xa0\x22\x66" + "\x18\x9c\x8f\xc1\xf9\x18\x9c\x8f\xc1\xf9\x18\x9c\x8f\xc1\xf9\x08", + .m_size = 32, + .algo = OID_gost2012PKey256, + .public_key_vec = true, + }, + /* cp256a: Q=-G, z1 = 7, z2 = 6. */ + { + .key = + "\x04\x40\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x83\xdf\x60\x61\x63\x36\x53\xdd\x4e\x1c\xdc\x20\xd2\xb0" + "\xd6\xca\x89\xd4\xc0\xba\xa5\xaf\x20\xd8\x25\x63\x67\x1f\x8e\x1b" + "\x6e\x72", + .key_len = 66, + .params = /* OID_gostCPSignA */ + "\x30\x13\x06\x07\x2a\x85\x03\x02\x02\x23\x01\x06\x08\x2a\x85\x03" + "\x07\x01\x01\x02\x02", + .param_len = 21, + .c = + "\x2a\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\x92\x10\x2d\x68\x19\x8f\x22\xd5\x60\xeb\x59\xd6\xf3\xe5\x9e\xc2" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", + .c_size = 64, + .m = + "\xc3\x9e\xe5\xf3\xd6\x59\xeb\x60\xd5\x22\x8f\x19\x68\x2d\x10\x92" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\x2a", + .m_size = 32, + .algo = OID_gost2012PKey256, + .public_key_vec = true, + }, + /* cp256a: Q=-2G, z1 = 5, z2 = 2. */ + { + .key = + "\x04\x40\x95\xfd\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\x14\x1e\x9f\x9e\x9c\xc9\xac\x22\xb1\xe3\x23\xdf\x2d\x4f" + "\x29\x35\x76\x2b\x3f\x45\x5a\x50\xdf\x27\xda\x9c\x98\xe0\x71\xe4" + "\x91\x8d", + .key_len = 66, + .params = /* OID_gostCPSignA */ + "\x30\x13\x06\x07\x2a\x85\x03\x02\x02\x23\x01\x06\x08\x2a\x85\x03" + "\x07\x01\x01\x02\x02", + .param_len = 21, + .c = + "\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xb6\x30\x88\x38\x4c\xad\x68\x80\x22\xc2\x0d\x84\xdb\xb0\xdc\x47" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", + .c_size = 64, + .m = + "\x49\xdc\xb0\xdb\x84\x0d\xc2\x22\x80\x68\xad\x4c\x38\x88\x30\xb6" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x7f", + .m_size = 32, + .algo = OID_gost2012PKey256, + .public_key_vec = true, + }, + /* tc512a: Q=G, z1 = 3, z2 = 1. */ + { + .key = + "\x04\x81\x80\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\xa4\xf2\x15\x52\xcb\x89\xa5\x89\xb8\xf5\x35\xc2\x5f" + "\xfe\x28\x80\xe9\x41\x3a\x0e\xa5\xe6\x75\x3d\xe9\x36\xd0\x4f\xbe" + "\x26\x16\xdf\x21\xa9\xef\xcb\xfd\x64\x80\x77\xc1\xab\xf1\xac\x93" + "\x1c\x5e\xce\xe6\x50\x54\xe2\x16\x88\x1b\xa6\xe3\x6a\x83\x7a\xe8" + "\xcf\x03\x75", + .key_len = 131, + .params = /* OID_gostTC26Sign512A */ + "\x30\x0b\x06\x09\x2a\x85\x03\x07\x01\x02\x01\x02\x01", + .param_len = 13, + .c = + "\xd8\xc0\xd7\xe3\xfb\xa6\xca\xff\x6a\xd1\xb4\xb4\x82\x1d\x15\x6f" + "\xa7\xc7\xbd\x63\x95\xb8\x29\x0d\xd4\xfa\xb1\x1c\x36\xbd\x32\x8d" + "\x1a\xba\xf1\x2e\xbc\x7b\xf2\x02\x96\xf8\xef\x2a\x5e\x72\x64\x86" + "\x67\x62\xfb\x62\x8e\x83\x53\x63\xb7\xe6\x78\x3c\x42\xd7\x0d\x1d" + "\xb7\xbf\xb8\x09\x56\xc8\x67\x00\x31\xba\x19\x19\x29\xf6\x4e\x30" + "\x1d\x68\x16\x34\x23\x6d\x47\xa6\x0e\x57\x1a\x4b\xed\xc0\xef\x25" + "\x74\x52\xef\x78\xb5\xb9\x8d\xbb\x3d\x9f\x31\x29\xd9\x34\x94\x33" + "\xce\x2a\x3a\x35\xcb\x51\x9c\x91\xe2\xd6\x33\xd7\xb3\x73\xae\x16", + .c_size = 128, + .m = + "\x5f\x04\x9d\x6b\x69\x7d\xf7\xe7\xcb\x1b\x81\x2f\x76\xfe\x20\xcd" + "\x2c\xcc\xd0\x74\x63\xfa\x52\x32\x56\xfb\xd3\x3e\xba\xa5\x93\xb3" + "\xd9\x10\x3f\x12\xb4\xe5\xa8\xf1\x59\xb8\x92\xdc\xcb\xe9\x97\xe2" + "\xcf\xb1\x09\xd6\xe6\xe6\x45\xce\xff\x98\x37\xa9\xf6\x47\x40\x48", + .m_size = 64, + .algo = OID_gost2012PKey512, + .public_key_vec = true, + }, + /* tc512a: Q=-G, z1 = 7, z2 = 6. */ + { + .key = + "\x04\x81\x80\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x23\x0b\xea\xad\x34\x76\x5a\x76\x47\x0a\xca\x3d\xa0" + "\x01\xd7\x7f\x16\xbe\xc5\xf1\x5a\x19\x8a\xc2\x16\xc9\x2f\xb0\x41" + "\xd9\xe9\x20\xde\x56\x10\x34\x02\x9b\x7f\x88\x3e\x54\x0e\x53\x6c" + "\xe3\xa1\x31\x19\xaf\xab\x1d\xe9\x77\xe4\x59\x1c\x95\x7c\x85\x17" + "\x30\xfc\x8a", + .key_len = 131, + .params = /* OID_gostTC26Sign512A */ + "\x30\x0b\x06\x09\x2a\x85\x03\x07\x01\x02\x01\x02\x01", + .param_len = 13, + .c = + "\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\x93\xf3\x4a\x99\x7a\x46\xc4\x88\xb7\xf9\x15\xc6\xa7\x02\xb0\x30" + "\x4d\xa5\x9c\x55\xfd\x69\x5c\x2e\xe5\x66\xd8\xa0\x8f\x88\x59\x37" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03", + .c_size = 128, + .m = + "\x3a\x59\x88\x8f\xa0\xd8\x66\xe5\x2e\x5c\x69\xfd\x55\x9c\xa5\x4d" + "\x30\xb0\x02\xa7\xc6\x15\xf9\xb7\x88\xc4\x46\x7a\x99\x4a\xf3\x93" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x7f", + .m_size = 64, + .algo = OID_gost2012PKey512, + .public_key_vec = true, + }, + /* tc512a: Q=-2G, z1 = 5, z2 = 2. */ + { + .key = + "\x04\x81\x80\x7c\x13\xea\xd2\xd9\xaf\x82\xb9\x1f\xb2\xfd\xe1\x8d" + "\xf4\x5b\x37\xe4\xf2\x04\x6a\x2a\x1d\x15\x16\x95\x2a\x5d\x40\xcd" + "\xbb\x34\x44\x2f\x2b\x13\x0a\x47\xb0\xf6\xe5\xa5\x58\x3a\xf4\x54" + "\x09\xb0\x1d\xf5\x5c\xf1\xbf\x9d\x86\xa5\x97\xab\x96\x29\x62\xfc" + "\xdc\x89\x3b\x76\x3d\x50\x6e\x8a\xcf\x02\x4c\x74\x0e\x6e\xe0\x1f" + "\x28\xab\x27\x9b\x20\x02\xc8\xc4\x12\xcb\x8a\xe3\xa4\x27\xce\x39" + "\x62\xdf\x35\x6d\xc1\x65\x7f\x7b\x48\x90\x11\x8f\x19\x7c\x1e\x67" + "\x91\x97\xeb\x90\x85\x25\xfc\x86\xb3\x88\x6e\x5c\x57\x1f\x1d\x1d" + "\x3b\xec\x37", + .key_len = 131, + .params = /* OID_gostTC26Sign512A */ + "\x30\x0b\x06\x09\x2a\x85\x03\x07\x01\x02\x01\x02\x01", + .param_len = 13, + .c = + "\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\x93\xf3\x4a\x99\x7a\x46\xc4\x88\xb7\xf9\x15\xc6\xa7\x02\xb0\x30" + "\x4d\xa5\x9c\x55\xfd\x69\x5c\x2e\xe5\x66\xd8\xa0\x8f\x88\x59\x33" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03", + .c_size = 128, + .m = + "\x39\x59\x88\x8f\xa0\xd8\x66\xe5\x2e\x5c\x69\xfd\x55\x9c\xa5\x4d" + "\x30\xb0\x02\xa7\xc6\x15\xf9\xb7\x88\xc4\x46\x7a\x99\x4a\xf3\x93" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x7f", + .m_size = 64, + .algo = OID_gost2012PKey512, + .public_key_vec = true, + }, }; /* diff --git a/drivers/accessibility/speakup/selection.c b/drivers/accessibility/speakup/selection.c index 7df7afad5ab4..463a7ef19315 100644 --- a/drivers/accessibility/speakup/selection.c +++ b/drivers/accessibility/speakup/selection.c @@ -61,6 +61,9 @@ static struct speakup_selection_work speakup_sel_work = { int speakup_set_selection(struct tty_struct *tty) { + if (!tty) + return -ENODEV; + /* we get kref here first in order to avoid a subtle race when * cancelling selection work. getting kref first establishes the * invariant that if speakup_sel_work.tty is not NULL when @@ -120,6 +123,9 @@ static struct speakup_selection_work speakup_paste_work = { int speakup_paste_selection(struct tty_struct *tty) { + if (!tty) + return -ENODEV; + tty_kref_get(tty); if (cmpxchg(&speakup_paste_work.tty, NULL, tty)) { tty_kref_put(tty); diff --git a/drivers/acpi/pfr_update.c b/drivers/acpi/pfr_update.c index 9afd2c52fdbd..98ace679601b 100644 --- a/drivers/acpi/pfr_update.c +++ b/drivers/acpi/pfr_update.c @@ -422,7 +422,7 @@ static int start_update(int action, struct pfru_device *pfru_dev) static long pfru_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct pfru_update_cap_info cap_hdr; + struct pfru_update_cap_info cap_hdr = {}; struct pfru_device *pfru_dev = to_pfru_dev(file); void __user *p = (void __user *)arg; u32 rev; diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c index 4336c8a6e208..eea75961038c 100644 --- a/drivers/ata/ahci_st.c +++ b/drivers/ata/ahci_st.c @@ -83,18 +83,27 @@ static int st_ahci_deassert_resets(struct ahci_host_priv *hpriv, return 0; } -static void st_ahci_host_stop(struct ata_host *host) +static int st_ahci_assert_pwrdwn(struct ahci_host_priv *hpriv, + struct device *dev) { - struct ahci_host_priv *hpriv = host->private_data; struct st_ahci_drv_data *drv_data = hpriv->plat_data; - struct device *dev = host->dev; int err; - if (drv_data->pwr) { - err = reset_control_assert(drv_data->pwr); - if (err) - dev_err(dev, "unable to pwrdwn\n"); - } + if (!drv_data->pwr) + return 0; + + err = reset_control_assert(drv_data->pwr); + if (err) + dev_err(dev, "unable to pwrdwn\n"); + + return err; +} + +static void st_ahci_host_stop(struct ata_host *host) +{ + struct ahci_host_priv *hpriv = host->private_data; + + st_ahci_assert_pwrdwn(hpriv, host->dev); ahci_platform_disable_resources(hpriv); } @@ -104,23 +113,20 @@ static int st_ahci_probe_resets(struct ahci_host_priv *hpriv, { struct st_ahci_drv_data *drv_data = hpriv->plat_data; - drv_data->pwr = devm_reset_control_get(dev, "pwr-dwn"); - if (IS_ERR(drv_data->pwr)) { - dev_info(dev, "power reset control not defined\n"); - drv_data->pwr = NULL; - } + drv_data->pwr = devm_reset_control_get_optional(dev, "pwr-dwn"); + if (IS_ERR(drv_data->pwr)) + return dev_err_probe(dev, PTR_ERR(drv_data->pwr), + "failed to get pwr-dwn reset\n"); - drv_data->sw_rst = devm_reset_control_get(dev, "sw-rst"); - if (IS_ERR(drv_data->sw_rst)) { - dev_info(dev, "soft reset control not defined\n"); - drv_data->sw_rst = NULL; - } + drv_data->sw_rst = devm_reset_control_get_optional(dev, "sw-rst"); + if (IS_ERR(drv_data->sw_rst)) + return dev_err_probe(dev, PTR_ERR(drv_data->sw_rst), + "failed to get sw-rst reset\n"); - drv_data->pwr_rst = devm_reset_control_get(dev, "pwr-rst"); - if (IS_ERR(drv_data->pwr_rst)) { - dev_dbg(dev, "power soft reset control not defined\n"); - drv_data->pwr_rst = NULL; - } + drv_data->pwr_rst = devm_reset_control_get_optional(dev, "pwr-rst"); + if (IS_ERR(drv_data->pwr_rst)) + return dev_err_probe(dev, PTR_ERR(drv_data->pwr_rst), + "failed to get pwr-rst reset\n"); return st_ahci_deassert_resets(hpriv, dev); } @@ -162,38 +168,38 @@ static int st_ahci_probe(struct platform_device *pdev) err = ahci_platform_enable_resources(hpriv); if (err) - return err; + goto assert_pwrdwn; st_ahci_configure_oob(hpriv->mmio); err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info, &ahci_platform_sht); - if (err) { - ahci_platform_disable_resources(hpriv); - return err; - } + if (err) + goto disable_resources; return 0; + +disable_resources: + ahci_platform_disable_resources(hpriv); +assert_pwrdwn: + st_ahci_assert_pwrdwn(hpriv, &pdev->dev); + + return err; } static int st_ahci_suspend(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); struct ahci_host_priv *hpriv = host->private_data; - struct st_ahci_drv_data *drv_data = hpriv->plat_data; int err; err = ahci_platform_suspend_host(dev); if (err) return err; - if (drv_data->pwr) { - err = reset_control_assert(drv_data->pwr); - if (err) { - dev_err(dev, "unable to pwrdwn"); - return err; - } - } + err = st_ahci_assert_pwrdwn(hpriv, dev); + if (err) + return err; ahci_platform_disable_resources(hpriv); diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index ecb56bb50fd7..50b2c997b6ba 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -2739,11 +2739,35 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, 0, pp->irq_desc, host->ports[i]); if (rc) - return rc; + goto free_irqs; ata_port_desc_misc(host->ports[i], irq); } - return ata_host_register(host, sht); + rc = ata_host_register(host, sht); + if (rc) + goto free_irqs; + + return 0; + +free_irqs: + /* + * Free the IRQs which have been requested, so that the handlers can no + * longer access the MMIO of the host once we return, e.g. after the + * caller has disabled the clocks of the host. + */ + while (--i >= 0) { + struct ahci_port_priv *pp = host->ports[i]->private_data; + + if (!pp) + continue; + + devm_free_irq(host->dev, hpriv->get_irq_vector(host, i), + host->ports[i]); + } + + ata_host_undo_start(host); + + return rc; } /** diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 7308d48cf748..7703c22ef532 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -692,6 +692,10 @@ EXPORT_SYMBOL_GPL(ahci_platform_get_resources); * ahci-platform host, note any necessary resources (ie clks, phys, etc.) * must be initialized / enabled before calling this. * + * On failure, ->host_stop() is not called, so the caller has to release the + * resources it enabled (clocks, regulators, resets, PHYs) in its probe() + * error path. + * * RETURNS: * 0 on success otherwise a negative error code */ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index cd9c96560ddd..cb74c6a5d9aa 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5976,6 +5976,46 @@ int ata_host_start(struct ata_host *host) } EXPORT_SYMBOL_GPL(ata_host_start); +/** + * ata_host_undo_start - undo ata_host_start() + * @host: ATA host to undo_start + * + * Stop the ports of @host and drop the devres action registered by + * ata_host_start(), without calling ->host_stop(). Nothing is done if + * @host has not been started. + * + * This gives the release of the host resources back to the caller, which + * is what a driver whose probe() error path releases those resources + * itself needs when starting or activating the host fails. + * + * LOCKING: + * Inherited from calling layer (may sleep). + */ +void ata_host_undo_start(struct ata_host *host) +{ + int i; + + if (!(host->flags & ATA_HOST_STARTED)) + return; + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap->ops->port_stop) + ap->ops->port_stop(ap); + } + + /* + * Drop the action added by ata_host_start() without calling it. + * It does not exist if neither ->port_stop() nor ->host_stop() is + * implemented, in which case there is nothing to drop. + */ + devres_destroy(host->dev, ata_host_stop, NULL, NULL); + + host->flags &= ~ATA_HOST_STARTED; +} +EXPORT_SYMBOL_GPL(ata_host_undo_start); + /** * ata_host_init - Initialize a host struct for sas (ipr, libsas) * @host: host to initialize @@ -6048,6 +6088,12 @@ static void async_port_probe(void *data, async_cookie_t cookie) * starts ports, registers @host with ATA and SCSI layers and * probe registered devices. * + * On failure, the host remains started, i.e. the devres action + * registered by ata_host_start() is kept, so ->host_stop() is called by + * the driver core when probe() fails. A caller which releases the host + * resources in its own probe() error path must therefore call + * ata_host_undo_start(). + * * LOCKING: * Inherited from calling layer (may sleep). * @@ -6141,6 +6187,10 @@ EXPORT_SYMBOL_GPL(ata_host_register); * have set polling mode on the port. In this case, @irq_handler * should be NULL. * + * On failure, the ports are stopped again and the devres action + * registered by ata_host_start() is dropped without calling + * ->host_stop(), so releasing the host resources is left to the caller. + * * LOCKING: * Inherited from calling layer (may sleep). * @@ -6161,27 +6211,40 @@ int ata_host_activate(struct ata_host *host, int irq, /* Special case for polling mode */ if (!irq) { WARN_ON(irq_handler); - return ata_host_register(host, sht); + rc = ata_host_register(host, sht); + if (rc) + goto undo_start; + + return 0; } irq_desc = devm_kasprintf(host->dev, GFP_KERNEL, "%s[%s]", dev_driver_string(host->dev), dev_name(host->dev)); - if (!irq_desc) - return -ENOMEM; + if (!irq_desc) { + rc = -ENOMEM; + goto undo_start; + } rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags, irq_desc, host); if (rc) - return rc; + goto undo_start; for (i = 0; i < host->n_ports; i++) ata_port_desc_misc(host->ports[i], irq); rc = ata_host_register(host, sht); - /* if failed, just free the IRQ and leave ports alone */ - if (rc) + if (rc) { + /* Free the IRQ, so that the handler can no longer run */ devm_free_irq(host->dev, irq, host); + goto undo_start; + } + + return 0; + +undo_start: + ata_host_undo_start(host); return rc; } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index c780a7f15738..8b9530c50531 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3474,6 +3474,11 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) if (is_multi_taskfile(tf)) { unsigned int multi_count = 1 << (cdb[1] >> 5); + if (!dev->multi_count) { + ata_scsi_set_sense(dev, scmd, ABORTED_COMMAND, 0, 0); + return 1; + } + /* compare the passed through multi_count * with the cached multi_count of libata */ diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 1e2a2c33cdc8..142347b5428d 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -2256,6 +2256,11 @@ EXPORT_SYMBOL_GPL(ata_pci_sff_prepare_host); * hosts. This separate helper is necessary because SFF hosts * use two separate interrupts in legacy mode. * + * Note that, unlike ata_host_activate(), the devres action registered + * by ata_host_start() is kept on failure, i.e. ->host_stop() is called + * by the driver core when probe() fails. All callers of this function + * rely on that, none of them releases the host resources itself. + * * LOCKING: * Inherited from calling layer (may sleep). * diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 040e5c3f635a..a04e38cd4170 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1489,8 +1489,10 @@ static int sata_fsl_probe(struct platform_device *ofdev) * device discovery process, invoking our port_start() handler & * error_handler() to execute a dummy Softreset EH session */ - ata_host_activate(host, irq, sata_fsl_interrupt, SATA_FSL_IRQ_FLAG, - &sata_fsl_sht); + retval = ata_host_activate(host, irq, sata_fsl_interrupt, + SATA_FSL_IRQ_FLAG, &sata_fsl_sht); + if (retval) + goto error_exit_with_cleanup; host_priv->intr_coalescing.show = fsl_sata_intr_coalescing_show; host_priv->intr_coalescing.store = fsl_sata_intr_coalescing_store; diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index cfb9b5b61cd7..b2be1ce87878 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -584,8 +584,12 @@ static int qs_ata_init_one(struct pci_dev *pdev, qs_host_init(host, board_idx); pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, qs_intr, IRQF_SHARED, - &qs_ata_sht); + rc = ata_host_activate(host, pdev->irq, qs_intr, IRQF_SHARED, + &qs_ata_sht); + if (rc) + qs_host_stop(host); + + return rc; } module_pci_driver(qs_ata_pci_driver); diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 2932b6653b6f..a477ada6b1ef 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -265,6 +265,8 @@ static struct fd_data_type data_types[] = { static struct amiga_floppy_struct unit[FD_MAX_UNITS]; static struct timer_list flush_track_timer[FD_MAX_UNITS]; +static DEFINE_SPINLOCK(flush_track_timer_lock); +static bool flush_track_timer_stopped[FD_MAX_UNITS]; static struct timer_list post_write_timer; static unsigned long post_write_timer_drive; static struct timer_list motor_on_timer; @@ -1370,11 +1372,22 @@ static void flush_track_callback(struct timer_list *timer) sizeof(flush_track_timer[0]); nr&=3; + spin_lock(&flush_track_timer_lock); + if (flush_track_timer_stopped[nr]) { + spin_unlock(&flush_track_timer_lock); + return; + } + spin_unlock(&flush_track_timer_lock); + writefromint = 1; if (!try_fdc(nr)) { /* we might block in an interrupt, so try again later */ - flush_track_timer[nr].expires = jiffies + 1; - add_timer(flush_track_timer + nr); + spin_lock(&flush_track_timer_lock); + if (!flush_track_timer_stopped[nr]) { + flush_track_timer[nr].expires = jiffies + 1; + add_timer(flush_track_timer + nr); + } + spin_unlock(&flush_track_timer_lock); return; } get_fdc(nr); @@ -1421,6 +1434,35 @@ static int non_int_flush_track (unsigned long nr) return 1; } +static void flush_track_timer_stop(unsigned int drive) +{ + unsigned long flags; + + spin_lock_irqsave(&flush_track_timer_lock, flags); + flush_track_timer_stopped[drive] = true; + spin_unlock_irqrestore(&flush_track_timer_lock, flags); + + timer_delete_sync(flush_track_timer + drive); +} + +static void flush_track_timer_start(unsigned int drive) +{ + unsigned long flags; + + spin_lock_irqsave(&flush_track_timer_lock, flags); + flush_track_timer_stopped[drive] = false; + if (unit[drive].dirty) + mod_timer(flush_track_timer + drive, jiffies + 1); + spin_unlock_irqrestore(&flush_track_timer_lock, flags); +} + +static void flush_track_timer_sync(unsigned int drive) +{ + flush_track_timer_stop(drive); + non_int_flush_track(drive); + flush_track_timer_start(drive); +} + static int get_track(int drive, int track) { int error, errcnt; @@ -1435,8 +1477,7 @@ static int get_track(int drive, int track) } if (unit[drive].dirty == 1) { - timer_delete(flush_track_timer + drive); - non_int_flush_track (drive); + flush_track_timer_sync(drive); } errcnt = 0; while (errcnt < MAX_ERRORS) { @@ -1562,6 +1603,12 @@ static int fd_locked_ioctl(struct block_device *bdev, blk_mode_t mode, case FDFMTTRK: if (param < p->type->tracks * p->type->heads) { + flush_track_timer_stop(drive); + if (unit[drive].dirty == 1 && + !non_int_flush_track(drive)) { + flush_track_timer_start(drive); + return -EIO; + } get_fdc(drive); if (fd_seek(drive,param) != 0){ memset(p->trackbuf, FD_FILL_BYTE, @@ -1570,6 +1617,7 @@ static int fd_locked_ioctl(struct block_device *bdev, blk_mode_t mode, } floppy_off(drive); rel_fdc(); + flush_track_timer_start(drive); } else return -EINVAL; @@ -1591,8 +1639,7 @@ static int fd_locked_ioctl(struct block_device *bdev, blk_mode_t mode, case FDDEFPRM: return -EINVAL; case FDFLUSH: /* unconditionally, even if not needed */ - timer_delete(flush_track_timer + drive); - non_int_flush_track(drive); + flush_track_timer_sync(drive); break; #ifdef RAW_IOCTL case IOCTL_RAW_TRACK: @@ -1611,9 +1658,15 @@ static int fd_ioctl(struct block_device *bdev, blk_mode_t mode, unsigned int cmd, unsigned long param) { int ret; + unsigned int memflags = 0; + bool freeze_queue = cmd == FDFMTTRK || cmd == FDFLUSH; mutex_lock(&amiflop_mutex); + if (freeze_queue) + memflags = blk_mq_freeze_queue(bdev->bd_disk->queue); ret = fd_locked_ioctl(bdev, mode, cmd, param); + if (freeze_queue) + blk_mq_unfreeze_queue(bdev->bd_disk->queue, memflags); mutex_unlock(&amiflop_mutex); return ret; @@ -1711,11 +1764,12 @@ static void floppy_release(struct gendisk *disk) { struct amiga_floppy_struct *p = disk->private_data; int drive = p - unit; + unsigned int memflags; mutex_lock(&amiflop_mutex); + memflags = blk_mq_freeze_queue(disk->queue); if (unit[drive].dirty == 1) { - timer_delete(flush_track_timer + drive); - non_int_flush_track (drive); + flush_track_timer_sync(drive); } if (!fd_ref[drive]--) { @@ -1725,6 +1779,7 @@ static void floppy_release(struct gendisk *disk) #ifdef MODULE floppy_off (drive); #endif + blk_mq_unfreeze_queue(disk->queue, memflags); mutex_unlock(&amiflop_mutex); } diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index 66e617664c14..cd7c735bb43b 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -131,9 +131,7 @@ static int aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct net_device *orig_dev) { struct aoe_hdr *h; - struct aoe_atahdr *ah; u32 n; - int sn; if (dev_net(ifp) != &init_net) goto exit; @@ -144,12 +142,8 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, if (!is_aoe_netif(ifp)) goto exit; skb_push(skb, ETH_HLEN); /* (1) */ - sn = sizeof(*h) + sizeof(*ah); - if (skb->len >= sn) { - sn -= skb_headlen(skb); - if (sn > 0 && !__pskb_pull_tail(skb, sn)) - goto exit; - } + if (!pskb_may_pull(skb, sizeof(*h))) + goto exit; h = (struct aoe_hdr *) skb->data; n = get_unaligned_be32(&h->tag); if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31)) @@ -171,10 +165,14 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, switch (h->cmd) { case AOECMD_ATA: + if (!pskb_may_pull(skb, sizeof(*h) + sizeof(struct aoe_atahdr))) + goto exit; /* ata_rsp may keep skb for later processing or give it back */ skb = aoecmd_ata_rsp(skb); break; case AOECMD_CFG: + if (!pskb_may_pull(skb, sizeof(*h) + sizeof(struct aoe_cfghdr))) + goto exit; aoecmd_cfg_rsp(skb); break; default: diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index c28786e0fe1c..eed7de727e54 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -2278,11 +2278,10 @@ static void request_done(int uptodate) { struct request *req = current_req; int block; - char msg[sizeof("request done ") + sizeof(int) * 3]; probing = 0; - snprintf(msg, sizeof(msg), "request done %d", uptodate); - reschedule_timeout(MAXTIMEOUT, msg); + reschedule_timeout(MAXTIMEOUT, + uptodate ? "request done 1" : "request done 0"); if (!req) { pr_info("floppy.c: no request in request_done\n"); @@ -3603,7 +3602,7 @@ struct compat_floppy_drive_params { }; struct compat_floppy_drive_struct { - signed char flags; + compat_ulong_t flags; compat_ulong_t spinup_date; compat_ulong_t select_date; compat_ulong_t first_read_date; @@ -3787,6 +3786,7 @@ static int compat_getdrvstat(int drive, bool poll, goto Eintr; process_fd_request(); } + v.flags = drive_state[drive].flags; v.spinup_date = drive_state[drive].spinup_date; v.select_date = drive_state[drive].select_date; v.first_read_date = drive_state[drive].first_read_date; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 13ce229d450c..57d3babbd63b 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1686,8 +1686,10 @@ static int lo_compat_ioctl(struct block_device *bdev, blk_mode_t mode, switch(cmd) { case LOOP_SET_STATUS: - err = loop_set_status_compat(lo, - (const struct compat_loop_info __user *)arg); + err = -EPERM; + if ((mode & BLK_OPEN_WRITE) || capable(CAP_SYS_ADMIN)) + err = loop_set_status_compat(lo, + (const struct compat_loop_info __user *)arg); break; case LOOP_GET_STATUS: err = loop_get_status_compat(lo, diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index f44512ed1217..8c33a5f86c3d 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -1761,12 +1761,15 @@ static void ublk_ch_release_work_fn(struct work_struct *work) } /* - * disk isn't attached yet, either device isn't live, or it has - * been removed already, so we needn't to do anything + * No disk: the device isn't live, or it has been removed already. + * There are no requests to abort, but the round still has to be + * reset, so that a new server can fetch and start the device. */ disk = ublk_get_disk(ub); - if (!disk) - goto out; + if (!disk) { + mutex_lock(&ub->mutex); + goto reset; + } /* * All uring_cmd are done now, so abort any request outstanding to @@ -1798,7 +1801,7 @@ static void ublk_ch_release_work_fn(struct work_struct *work) /* double check after grabbing lock */ if (!ub->ub_disk) - goto unlock; + goto reset; /* * Transition the device to the nosrv state. What exactly this @@ -1824,17 +1827,19 @@ static void ublk_ch_release_work_fn(struct work_struct *work) WRITE_ONCE(ublk_get_queue(ub, i)->fail_io, true); } } -unlock: +reset: + /* + * All uring_cmd has been done now, reset device & ubq. Under + * ub->mutex, so START_DEV sees the round either ready or reset. + */ + ublk_reset_ch_dev(ub); mutex_unlock(&ub->mutex); ublk_put_disk(disk); - - /* all uring_cmd has been done now, reset device & ubq */ - 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); + module_put(THIS_MODULE); } static int ublk_ch_release(struct inode *inode, struct file *filp) @@ -1847,6 +1852,8 @@ static int ublk_ch_release(struct inode *inode, struct file *filp) */ ublk_get_device(ub); + /* Keep the worker's callback and final device release code resident. */ + __module_get(THIS_MODULE); INIT_DELAYED_WORK(&ub->exit_work, ublk_ch_release_work_fn); schedule_delayed_work(&ub->exit_work, 0); return 0; diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index f37290fd3c5d..79fe0b107887 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -2133,10 +2133,8 @@ static void blkfront_closing(struct blkfront_info *info) return; /* No more blkif_request(). */ - if (info->rq && info->gd) { - blk_mq_stop_hw_queues(info->rq); + if (info->gd) blk_mark_disk_dead(info->gd); - } for_each_rinfo(info, rinfo, i) { /* No more gnttab callback work. */ diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 0b8c2ecf0a64..5b8b71efffac 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -843,6 +843,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x37ad, 0x0600), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x14b0, 0x047a), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, /* Additional Realtek 8821AE Bluetooth devices */ { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c index 9a24d19236dc..cc65d40a5598 100644 --- a/drivers/char/hw_random/amd-rng.c +++ b/drivers/char/hw_random/amd-rng.c @@ -80,7 +80,7 @@ static int amd_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) if (timeout-- == 0) return read; } else { - return 0; + return read; } } else { *data = ioread32(priv->iobase + RNGDATA); diff --git a/drivers/char/hw_random/ba431-rng.c b/drivers/char/hw_random/ba431-rng.c index 9de7466e6896..c33fbc25b7cd 100644 --- a/drivers/char/hw_random/ba431-rng.c +++ b/drivers/char/hw_random/ba431-rng.c @@ -148,7 +148,7 @@ static int ba431_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait) } } - n *= sizeof(data); + n *= sizeof(*data); return (n || !wait) ? n : -EIO; } diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 054ffbc9e422..6412bfa792a2 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -381,6 +381,7 @@ static ssize_t rng_current_store(struct device *dev, cur_rng_set_by_user = 1; drop_current_rng(); } else { + err = -ENODEV; list_for_each_entry(rng, &rng_list, list) { if (sysfs_streq(rng->name, buf)) { err = set_current_rng(rng); diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c index f2a5e09257dd..a856b4ddbdc2 100644 --- a/drivers/char/tpm/tpm-dev-common.c +++ b/drivers/char/tpm/tpm-dev-common.c @@ -134,6 +134,9 @@ ssize_t tpm_common_read(struct file *file, char __user *buf, ssize_t ret_size = 0; int rc; + if (!size) + return 0; + mutex_lock(&priv->buffer_mutex); if (priv->response_length) { diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 879ac88f5783..bcfa2a1a208a 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -259,7 +259,12 @@ static struct platform_device *pdev = NULL; static void tpm_nsc_remove(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); - struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev); + struct tpm_nsc_priv *priv; + + if (!chip) + return; + + priv = dev_get_drvdata(&chip->dev); tpm_chip_unregister(chip); release_region(priv->base, 2); @@ -322,7 +327,6 @@ static int __init init_nsc(void) pdev->num_resources = 0; pdev->dev.driver = &nsc_drv.driver; - pdev->dev.release = tpm_nsc_remove; if ((rc = platform_device_add(pdev)) < 0) goto err_put_dev; diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c index df83bd939492..153e7405eae4 100644 --- a/drivers/clk/imx/clk.c +++ b/drivers/clk/imx/clk.c @@ -95,11 +95,16 @@ struct clk_hw *imx_obtain_fixed_clock_hw( const char *name, unsigned long rate) { struct clk *clk; + struct clk_hw *hw; clk = imx_obtain_fixed_clock_from_dt(name); if (IS_ERR(clk)) - clk = imx_clk_fixed(name, rate); - return __clk_get_hw(clk); + return __clk_get_hw(imx_clk_fixed(name, rate)); + + hw = __clk_get_hw(clk); + clk_put(clk); + + return hw; } struct clk_hw *imx_obtain_fixed_of_clock(struct device_node *np, @@ -119,12 +124,16 @@ struct clk_hw *imx_obtain_fixed_of_clock(struct device_node *np, struct clk_hw *imx_get_clk_hw_by_name(struct device_node *np, const char *name) { struct clk *clk; + struct clk_hw *hw; clk = of_clk_get_by_name(np, name); if (IS_ERR(clk)) return ERR_PTR(-ENOENT); - return __clk_get_hw(clk); + hw = __clk_get_hw(clk); + clk_put(clk); + + return hw; } EXPORT_SYMBOL_GPL(imx_get_clk_hw_by_name); diff --git a/drivers/clk/mstar/clk-msc313-mpll.c b/drivers/clk/mstar/clk-msc313-mpll.c index 61beb4e87525..bd45aa0aec01 100644 --- a/drivers/clk/mstar/clk-msc313-mpll.c +++ b/drivers/clk/mstar/clk-msc313-mpll.c @@ -105,7 +105,7 @@ static int msc313_mpll_probe(struct platform_device *pdev) return PTR_ERR(mpll->loop_div_second); mpll->clk_data = devm_kzalloc(dev, struct_size(mpll->clk_data, hws, - ARRAY_SIZE(output_dividers)), GFP_KERNEL); + NUMOUTPUTS), GFP_KERNEL); if (!mpll->clk_data) return -ENOMEM; diff --git a/drivers/clk/mvebu/ap-cpu-clk.c b/drivers/clk/mvebu/ap-cpu-clk.c index 1e44ace7d951..ed3ca59e0ee9 100644 --- a/drivers/clk/mvebu/ap-cpu-clk.c +++ b/drivers/clk/mvebu/ap-cpu-clk.c @@ -284,6 +284,8 @@ static int ap_cpu_clock_probe(struct platform_device *pdev) if (!ap_cpu_data) return -ENOMEM; + ap_cpu_data->num = nclusters; + for_each_of_cpu_node(dn) { char *clk_name = "cpu-cluster-0"; struct clk_init_data init; @@ -333,8 +335,6 @@ static int ap_cpu_clock_probe(struct platform_device *pdev) ap_cpu_data->hws[cluster_index] = &ap_cpu_clk[cluster_index].hw; } - ap_cpu_data->num = cluster_index + 1; - ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, ap_cpu_data); if (ret) dev_err(dev, "failed to register OF clock provider\n"); diff --git a/drivers/clk/qcom/gcc-ipq5018.c b/drivers/clk/qcom/gcc-ipq5018.c index 64792cda0620..78ccd70199fc 100644 --- a/drivers/clk/qcom/gcc-ipq5018.c +++ b/drivers/clk/qcom/gcc-ipq5018.c @@ -69,6 +69,15 @@ static struct clk_alpha_pll gpll0_main = { .parent_data = gcc_xo_data, .num_parents = ARRAY_SIZE(gcc_xo_data), .ops = &clk_alpha_pll_stromer_ops, + /* + * During system boot, this PLL feeds the CPUs. + * Mark it as critical to ensure that CCF does + * not disable it, even if there are no active + * consumers. This is needed to avoid a system + * hang caused by turning off the clock driving + * the CPUs. + */ + .flags = CLK_IS_CRITICAL, }, }, }; @@ -1261,6 +1270,7 @@ static struct clk_rcg2 usb0_master_clk_src = { }; static const struct freq_tbl ftbl_usb0_mock_utmi_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), F(60000000, P_GPLL4, 10, 1, 2), { } }; diff --git a/drivers/clk/qcom/gcc-ipq5332.c b/drivers/clk/qcom/gcc-ipq5332.c index 9246e97d785a..1d02c35c6722 100644 --- a/drivers/clk/qcom/gcc-ipq5332.c +++ b/drivers/clk/qcom/gcc-ipq5332.c @@ -1039,6 +1039,7 @@ static struct clk_rcg2 gcc_usb0_master_clk_src = { }; static const struct freq_tbl ftbl_gcc_usb0_mock_utmi_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), F(60000000, P_GPLL4_OUT_AUX, 10, 1, 2), { } }; diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c index 369798d1ce42..e01c8ccf1731 100644 --- a/drivers/clk/qcom/ipq-cmn-pll.c +++ b/drivers/clk/qcom/ipq-cmn-pll.c @@ -351,6 +351,8 @@ static int ipq_cmn_pll_register_clks(struct platform_device *pdev) if (!hw_data) return -ENOMEM; + hw_data->num = num_clks + 1; + /* * Register the CMN PLL clock, which is the parent clock of * the fixed rate output clocks. @@ -377,7 +379,6 @@ static int ipq_cmn_pll_register_clks(struct platform_device *pdev) * is configured to 12 GHZ by DT property assigned-clock-rates-u64. */ hw_data->hws[CMN_PLL_CLK] = cmn_pll_hw; - hw_data->num = num_clks + 1; ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, hw_data); if (ret) diff --git a/drivers/clk/starfive/clk-starfive-jh7110-isp.c b/drivers/clk/starfive/clk-starfive-jh7110-isp.c index f3fa069db193..c02c8b29a123 100644 --- a/drivers/clk/starfive/clk-starfive-jh7110-isp.c +++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c @@ -130,7 +130,7 @@ static int jh7110_ispcrg_probe(struct platform_device *pdev) /* enable power domain and clocks */ pm_runtime_enable(priv->dev); - ret = pm_runtime_get_sync(priv->dev); + ret = pm_runtime_resume_and_get(priv->dev); if (ret < 0) return dev_err_probe(priv->dev, ret, "failed to turn on power\n"); diff --git a/drivers/clocksource/timer-digicolor.c b/drivers/clocksource/timer-digicolor.c index 559aa96089c3..46e0c329957a 100644 --- a/drivers/clocksource/timer-digicolor.c +++ b/drivers/clocksource/timer-digicolor.c @@ -190,6 +190,8 @@ static int __init digicolor_timer_init(struct device_node *node) &dc_timer_dev.ce); if (ret) { pr_warn("request of timer irq %d failed (%d)\n", irq, ret); + clk_disable_unprepare(clk); + clk_put(clk); return ret; } diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c index 126fb1f259b2..0003d49768f6 100644 --- a/drivers/clocksource/timer-fttmr010.c +++ b/drivers/clocksource/timer-fttmr010.c @@ -292,6 +292,7 @@ static int __init fttmr010_common_init(struct device_node *np, ret = clk_prepare_enable(clk); if (ret) { pr_err("failed to enable PCLK\n"); + clk_put(clk); return ret; } @@ -432,6 +433,7 @@ static int __init fttmr010_common_init(struct device_node *np, kfree(fttmr010); out_disable_clock: clk_disable_unprepare(clk); + clk_put(clk); return ret; } diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 78702a08364f..73c1b62c1b37 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -289,6 +289,7 @@ endif if LOONGARCH config LOONGSON3_CPUFREQ tristate "Loongson3 CPUFreq Driver" + depends on MACH_LOONGSON64 help This option adds a CPUFreq driver for Loongson processors which support software configurable cpu frequency. diff --git a/drivers/cpufreq/airoha-cpufreq.c b/drivers/cpufreq/airoha-cpufreq.c index b6b1cdc4d11d..ec9b2fc00f5e 100644 --- a/drivers/cpufreq/airoha-cpufreq.c +++ b/drivers/cpufreq/airoha-cpufreq.c @@ -64,7 +64,7 @@ static int airoha_cpufreq_probe(struct platform_device *pdev) /* Attach PM for OPP */ ret = dev_pm_domain_attach_list(cpu_dev, &attach_data, &priv->pd_list); - if (ret) + if (ret < 0) goto clear_opp_config; cpufreq_dt = platform_device_register_simple("cpufreq-dt", -1, NULL, 0); diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index b1a200531628..0b06bbd7215f 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -469,8 +469,10 @@ static int shmem_init_perf(struct amd_cpudata *cpudata) return 0; } - ret = cppc_set_auto_sel(cpudata->cpu, - (cppc_state == AMD_PSTATE_PASSIVE) ? 0 : 1); + if ((cppc_state != AMD_PSTATE_PASSIVE) == auto_sel) + return 0; + + ret = cppc_set_auto_sel(cpudata->cpu, !auto_sel); if (ret) pr_warn("failed to set auto_sel, ret: %d\n", ret); diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 60bab2b71b1b..4ee6990ab2ba 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -85,10 +85,12 @@ static unsigned int cs_dbs_update(struct cpufreq_policy *policy) freq_step = get_freq_step(cs_tuners, policy); /* - * Decrease requested_freq one freq_step for each idle period that - * we didn't update the frequency. + * Apply deferred down steps only when the policy sample load is + * below down_threshold. Otherwise, multiple deferred down steps may + * cause a net frequency decrease outside the downscaling region. */ - if (policy_dbs->idle_periods < UINT_MAX) { + if (policy_dbs->max_sample_load < cs_tuners->down_threshold && + policy_dbs->idle_periods < UINT_MAX) { unsigned int freq_steps = policy_dbs->idle_periods * freq_step; if (requested_freq > policy->min + freq_steps) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 00a26fa6292c..a10cf44600ff 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -116,7 +116,8 @@ unsigned int dbs_update(struct cpufreq_policy *policy) struct policy_dbs_info *policy_dbs = policy->governor_data; struct dbs_data *dbs_data = policy_dbs->dbs_data; unsigned int ignore_nice = dbs_data->ignore_nice_load; - unsigned int max_load = 0, idle_periods = UINT_MAX; + unsigned int max_load = 0, max_sample_load = 0; + unsigned int idle_periods = UINT_MAX; unsigned int sampling_rate, io_busy, j; /* @@ -138,7 +139,7 @@ unsigned int dbs_update(struct cpufreq_policy *policy) struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j); u64 update_time, cur_idle_time; unsigned int idle_time, time_elapsed; - unsigned int load; + unsigned int load, sample_load; cur_idle_time = get_cpu_idle_time(j, &update_time, io_busy); @@ -171,6 +172,20 @@ unsigned int dbs_update(struct cpufreq_policy *policy) j_cdbs->prev_cpu_nice = cur_nice; } + /* + * Compute the sample load separately from the prev_load value + * that may be reused after a long idle interval. The conservative + * governor uses it to decide whether to apply deferred down steps. + * If no time has elapsed, retain the existing behavior and use + * prev_load. + */ + if (unlikely(!time_elapsed)) + sample_load = j_cdbs->prev_load; + else if (time_elapsed > idle_time) + sample_load = 100 * (time_elapsed - idle_time) / time_elapsed; + else + sample_load = 0; + if (unlikely(!time_elapsed)) { /* * That can only happen when this function is called @@ -205,11 +220,7 @@ unsigned int dbs_update(struct cpufreq_policy *policy) load = j_cdbs->prev_load; j_cdbs->prev_load = 0; } else { - if (time_elapsed > idle_time) - load = 100 * (time_elapsed - idle_time) / time_elapsed; - else - load = 0; - + load = sample_load; j_cdbs->prev_load = load; } @@ -222,9 +233,13 @@ unsigned int dbs_update(struct cpufreq_policy *policy) if (load > max_load) max_load = load; + + if (sample_load > max_sample_load) + max_sample_load = sample_load; } policy_dbs->idle_periods = idle_periods; + policy_dbs->max_sample_load = max_sample_load; return max_load; } diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 1462d59277bd..ceb33336b2b3 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -94,6 +94,8 @@ struct policy_dbs_info { /* Multiplier for increasing sample delay temporarily. */ unsigned int rate_mult; unsigned int idle_periods; /* For conservative */ + /* Maximum load from the current policy sample. */ + unsigned int max_sample_load; /* Status indicators */ bool is_shared; /* This object is used by multiple CPUs */ bool work_in_progress; /* Work is being queued up or in progress */ diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 40a9ff18da06..d457848b3eab 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -52,6 +52,10 @@ static void cpufreq_stats_reset_table(struct cpufreq_stats *stats) * reset_pending accesses in cpufreq_stats_record_transition(). */ smp_rmb(); + + if (stats->last_index == -1) + return; + cpufreq_stats_update(stats, READ_ONCE(stats->reset_time)); } diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 1de12358c0b9..a498d66883b5 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -3458,6 +3458,8 @@ static void intel_pstate_driver_cleanup(void) if (intel_pstate_driver == &intel_pstate) intel_pstate_clear_update_util_hook(cpu); + intel_pstate_disable_hwp_interrupt(all_cpu_data[cpu]); + kfree(all_cpu_data[cpu]); WRITE_ONCE(all_cpu_data[cpu], NULL); } diff --git a/drivers/cpufreq/loongson3_cpufreq.c b/drivers/cpufreq/loongson3_cpufreq.c index 1e8715ea1b77..aea7c31e155a 100644 --- a/drivers/cpufreq/loongson3_cpufreq.c +++ b/drivers/cpufreq/loongson3_cpufreq.c @@ -16,14 +16,16 @@ #include #include #include +#include +#include /* Message */ union smc_message { u32 value; struct { - u32 id : 4; + u32 id : 8; u32 info : 4; - u32 val : 16; + u32 val : 12; u32 cmd : 6; u32 extra : 1; u32 complete : 1; @@ -164,27 +166,47 @@ union smc_message { #define FREQ_MAX_LEVEL 16 +#define MMIO_SMCMBX(node) \ + ((void __iomem *)(nid_to_addrbase(node) | IO_BASE | LOONGSON_REG_BASE | LOONGARCH_IOCSR_SMCMBX)) + +#define MMIO_MISC_FUNC(node) \ + ((void __iomem *)(nid_to_addrbase(node) | IO_BASE | LOONGSON_REG_BASE | LOONGARCH_IOCSR_MISC_FUNC)) + struct loongson3_freq_data { unsigned int def_freq_level; struct cpufreq_frequency_table table[]; }; -static struct mutex cpufreq_mutex[MAX_PACKAGES]; +static struct mutex cpufreq_mutex[MAX_NUMNODES]; static struct cpufreq_driver loongson3_cpufreq_driver; static DEFINE_PER_CPU(struct loongson3_freq_data *, freq_data); static inline int do_service_request(u32 id, u32 info, u32 cmd, u32 val, u32 extra) { int retries; - unsigned int cpu = raw_smp_processor_id(); - unsigned int package = cpu_data[cpu].package; + unsigned int cpu = 0, nid; union smc_message msg, last; - mutex_lock(&cpufreq_mutex[package]); +#ifdef CONFIG_SMP + switch (cmd) { + case CMD_GET_FREQ_INFO: + case CMD_SET_FREQ_INFO: + case CMD_GET_FREQ_LEVEL_NUM: + case CMD_GET_FREQ_LEVEL_INFO: + case CMD_GET_FREQ_BOOST_LEVEL: + cpu = cpu_number_map(id); + break; + default: + cpu = raw_smp_processor_id(); + } +#endif + nid = cpu_to_node(cpu); - last.value = iocsr_read32(LOONGARCH_IOCSR_SMCMBX); + mutex_lock(&cpufreq_mutex[nid]); + + last.value = readl(MMIO_SMCMBX(nid)); if (!last.complete) { - mutex_unlock(&cpufreq_mutex[package]); + mutex_unlock(&cpufreq_mutex[nid]); return -EPERM; } @@ -195,12 +217,11 @@ static inline int do_service_request(u32 id, u32 info, u32 cmd, u32 val, u32 ext msg.extra = extra; msg.complete = 0; - iocsr_write32(msg.value, LOONGARCH_IOCSR_SMCMBX); - iocsr_write32(iocsr_read32(LOONGARCH_IOCSR_MISC_FUNC) | IOCSR_MISC_FUNC_SOFT_INT, - LOONGARCH_IOCSR_MISC_FUNC); + writel(msg.value, MMIO_SMCMBX(nid)); + writel(readl(MMIO_MISC_FUNC(nid)) | IOCSR_MISC_FUNC_SOFT_INT, MMIO_MISC_FUNC(nid)); for (retries = 0; retries < 10000; retries++) { - msg.value = iocsr_read32(LOONGARCH_IOCSR_SMCMBX); + msg.value = readl(MMIO_SMCMBX(nid)); if (msg.complete) break; @@ -208,49 +229,51 @@ static inline int do_service_request(u32 id, u32 info, u32 cmd, u32 val, u32 ext } if (!msg.complete || msg.cmd != CMD_OK) { - mutex_unlock(&cpufreq_mutex[package]); + mutex_unlock(&cpufreq_mutex[nid]); return -EPERM; } - mutex_unlock(&cpufreq_mutex[package]); + mutex_unlock(&cpufreq_mutex[nid]); return msg.val; } static unsigned int loongson3_cpufreq_get(unsigned int cpu) { - int ret; + int ret, core = cpu_logical_map(cpu); - ret = do_service_request(cpu, FREQ_INFO_TYPE_FREQ, CMD_GET_FREQ_INFO, 0, 0); + ret = do_service_request(core, FREQ_INFO_TYPE_FREQ, CMD_GET_FREQ_INFO, 0, 0); - return ret * KILO; + return (ret < 0) ? 0 : ret * KILO; } static int loongson3_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) { - int ret; + int ret, core = cpu_logical_map(policy->cpu); - ret = do_service_request(cpu_data[policy->cpu].core, - FREQ_INFO_TYPE_LEVEL, CMD_SET_FREQ_INFO, index, 0); + ret = do_service_request(core, FREQ_INFO_TYPE_LEVEL, CMD_SET_FREQ_INFO, + index, 0); return (ret >= 0) ? 0 : ret; } static int configure_freq_table(int cpu) { - int i, ret, boost_level, max_level, freq_level; + int i, ret, core, boost_level, max_level, freq_level; struct platform_device *pdev = cpufreq_get_driver_data(); struct loongson3_freq_data *data; if (per_cpu(freq_data, cpu)) return 0; - ret = do_service_request(cpu, 0, CMD_GET_FREQ_LEVEL_NUM, 0, 0); + core = cpu_logical_map(cpu); + + ret = do_service_request(core, 0, CMD_GET_FREQ_LEVEL_NUM, 0, 0); if (ret < 0) return ret; max_level = ret; - ret = do_service_request(cpu, 0, CMD_GET_FREQ_BOOST_LEVEL, 0, 0); + ret = do_service_request(core, 0, CMD_GET_FREQ_BOOST_LEVEL, 0, 0); if (ret < 0) return ret; boost_level = ret; @@ -263,7 +286,7 @@ static int configure_freq_table(int cpu) data->def_freq_level = boost_level - 1; for (i = 0; i < freq_level; i++) { - ret = do_service_request(cpu, FREQ_INFO_TYPE_FREQ, CMD_GET_FREQ_LEVEL_INFO, i, 0); + ret = do_service_request(core, FREQ_INFO_TYPE_FREQ, CMD_GET_FREQ_LEVEL_INFO, i, 0); if (ret < 0) { devm_kfree(&pdev->dev, data); return ret; @@ -337,7 +360,7 @@ static int loongson3_cpufreq_probe(struct platform_device *pdev) { int i, ret; - for (i = 0; i < MAX_PACKAGES; i++) { + for (i = 0; i < MAX_NUMNODES; i++) { ret = devm_mutex_init(&pdev->dev, &cpufreq_mutex[i]); if (ret) return ret; diff --git a/drivers/crypto/amlogic/amlogic-gxl-core.c b/drivers/crypto/amlogic/amlogic-gxl-core.c index 6cb33949915f..7194117518b9 100644 --- a/drivers/crypto/amlogic/amlogic-gxl-core.c +++ b/drivers/crypto/amlogic/amlogic-gxl-core.c @@ -37,12 +37,13 @@ static irqreturn_t meson_irq_handler(int irq, void *data) complete(&mc->chanlist[flow].complete); return IRQ_HANDLED; } - dev_err(mc->dev, "%s %d Got irq for flow %d but ctrl is empty\n", __func__, irq, flow); + dev_err_ratelimited(mc->dev, "%s %d Got irq for flow %d but ctrl is empty\n", __func__, irq, flow); + return IRQ_NONE; } } - dev_err(mc->dev, "%s %d from unknown irq\n", __func__, irq); - return IRQ_HANDLED; + dev_err_ratelimited(mc->dev, "%s %d from unknown irq\n", __func__, irq); + return IRQ_NONE; } static struct meson_alg_template mc_algs[] = { diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index b393689400b4..e057be7fc713 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -1272,7 +1272,7 @@ static int atmel_aes_gcm_ghash_init(struct atmel_aes_dev *dd) struct atmel_aes_gcm_ctx *ctx = atmel_aes_gcm_ctx_cast(dd->ctx); /* Set the data length. */ - atmel_aes_write(dd, AES_AADLENR, dd->total); + atmel_aes_write(dd, AES_AADLENR, dd->datalen); atmel_aes_write(dd, AES_CLENR, 0); /* If needed, overwrite the GCM Intermediate Hash Word Registers */ diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index d380f6741a2c..ac0be3c4cd01 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -373,6 +373,8 @@ static int atmel_tdes_crypt_pdc(struct atmel_tdes_dev *dd, if (!(dd->flags & TDES_FLAGS_FAST)) { dma_sync_single_for_device(dd->dev, dma_addr_in, length, DMA_TO_DEVICE); + dma_sync_single_for_device(dd->dev, dma_addr_out, length, + DMA_FROM_DEVICE); } len32 = DIV_ROUND_UP(length, sizeof(u32)); @@ -405,6 +407,8 @@ static int atmel_tdes_crypt_dma(struct atmel_tdes_dev *dd, if (!(dd->flags & TDES_FLAGS_FAST)) { dma_sync_single_for_device(dd->dev, dma_addr_in, length, DMA_TO_DEVICE); + dma_sync_single_for_device(dd->dev, dma_addr_out, length, + DMA_FROM_DEVICE); } addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -945,7 +949,7 @@ static int atmel_tdes_probe(struct platform_device *pdev) struct resource *tdes_res; int err; - tdes_dd = devm_kmalloc(&pdev->dev, sizeof(*tdes_dd), GFP_KERNEL); + tdes_dd = devm_kzalloc(&pdev->dev, sizeof(*tdes_dd), GFP_KERNEL); if (!tdes_dd) return -ENOMEM; diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c index cb001aa1de66..ac515ed8c575 100644 --- a/drivers/crypto/caam/caampkc.c +++ b/drivers/crypto/caam/caampkc.c @@ -1033,16 +1033,22 @@ static int caam_rsa_set_priv_key_form(struct caam_rsa_ctx *ctx, free_dq: kfree_sensitive(rsa_key->dq); + rsa_key->dq = NULL; free_dp: kfree_sensitive(rsa_key->dp); + rsa_key->dp = NULL; free_tmp2: kfree_sensitive(rsa_key->tmp2); + rsa_key->tmp2 = NULL; free_tmp1: kfree_sensitive(rsa_key->tmp1); + rsa_key->tmp1 = NULL; free_q: kfree_sensitive(rsa_key->q); + rsa_key->q = NULL; free_p: kfree_sensitive(rsa_key->p); + rsa_key->p = NULL; return -ENOMEM; } diff --git a/drivers/crypto/ccp/dbc.c b/drivers/crypto/ccp/dbc.c index 410084a9039c..4db49a14550c 100644 --- a/drivers/crypto/ccp/dbc.c +++ b/drivers/crypto/ccp/dbc.c @@ -236,6 +236,8 @@ int dbc_dev_init(struct psp_device *psp) goto cleanup_mbox; } + mutex_init(&dbc_dev->ioctl_mutex); + dbc_dev->char_dev.minor = MISC_DYNAMIC_MINOR; dbc_dev->char_dev.name = "dbc"; dbc_dev->char_dev.fops = &dbc_fops; @@ -244,8 +246,6 @@ int dbc_dev_init(struct psp_device *psp) if (ret) goto cleanup_mbox; - mutex_init(&dbc_dev->ioctl_mutex); - return 0; cleanup_mbox: diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c index 839c1f677143..af5d10add106 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c +++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c @@ -138,6 +138,7 @@ struct hpre_asym_request { int err; hpre_cb cb; struct timespec64 req_time; + u32 flags; }; static inline unsigned int hpre_align_sz(void) @@ -186,6 +187,7 @@ static int hpre_prepare_dma_buf(struct hpre_asym_request *hpre_req, struct scatterlist *data, unsigned int len, int is_src, dma_addr_t *tmp) { + gfp_t gfp = hpre_req->flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC; struct hpre_ctx *ctx = hpre_req->ctx; struct device *dev = ctx->dev; void *ptr; @@ -195,7 +197,7 @@ static int hpre_prepare_dma_buf(struct hpre_asym_request *hpre_req, if (unlikely(shift < 0)) return -EINVAL; - ptr = dma_alloc_coherent(dev, ctx->key_sz, tmp, GFP_ATOMIC); + ptr = dma_alloc_coherent(dev, ctx->key_sz, tmp, gfp); if (unlikely(!ptr)) return -ENOMEM; @@ -419,6 +421,7 @@ static int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa) h_req = PTR_ALIGN(tmp, hpre_align_sz()); h_req->cb = hpre_rsa_cb; h_req->areq.rsa = akreq; + h_req->flags = akreq->base.flags; msg = &h_req->req; memset(msg, 0, sizeof(*msg)); } else { @@ -433,6 +436,7 @@ static int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa) h_req = PTR_ALIGN(tmp, hpre_align_sz()); h_req->cb = hpre_dh_cb; h_req->areq.dh = kreq; + h_req->flags = kreq->base.flags; msg = &h_req->req; memset(msg, 0, sizeof(*msg)); msg->key = cpu_to_le64(ctx->dh.dma_xa_p); @@ -720,7 +724,7 @@ static void hpre_dh_exit_tfm(struct crypto_kpp *tfm) static void hpre_rsa_drop_leading_zeros(const char **ptr, size_t *len) { - while (!**ptr && *len) { + while (*len && !**ptr) { (*ptr)++; (*len)--; } @@ -1460,13 +1464,14 @@ static int hpre_ecdh_msg_request_set(struct hpre_ctx *ctx, if (req->dst_len < ctx->key_sz << 1) { req->dst_len = ctx->key_sz << 1; - return -EINVAL; + return -EOVERFLOW; } tmp = kpp_request_ctx(req); h_req = PTR_ALIGN(tmp, hpre_align_sz()); h_req->cb = hpre_ecdh_cb; h_req->areq.ecdh = req; + h_req->flags = req->base.flags; msg = &h_req->req; memset(msg, 0, sizeof(*msg)); msg->in = cpu_to_le64(DMA_MAPPING_ERROR); @@ -1485,6 +1490,7 @@ static int hpre_ecdh_msg_request_set(struct hpre_ctx *ctx, static int hpre_ecdh_src_data_init(struct hpre_asym_request *hpre_req, struct scatterlist *data, unsigned int len) { + gfp_t gfp = hpre_req->flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC; struct hpre_sqe *msg = &hpre_req->req; struct hpre_ctx *ctx = hpre_req->ctx; struct device *dev = ctx->dev; @@ -1498,7 +1504,7 @@ static int hpre_ecdh_src_data_init(struct hpre_asym_request *hpre_req, if (unlikely(shift < 0)) return -EINVAL; - ptr = dma_alloc_coherent(dev, ctx->key_sz << 2, &dma, GFP_KERNEL); + ptr = dma_alloc_coherent(dev, ctx->key_sz << 2, &dma, gfp); if (unlikely(!ptr)) return -ENOMEM; @@ -1520,13 +1526,13 @@ static int hpre_ecdh_dst_data_init(struct hpre_asym_request *hpre_req, struct device *dev = ctx->dev; dma_addr_t dma; - if (unlikely(!data || !sg_is_last(data) || len != ctx->key_sz << 1)) { - dev_err(dev, "data or data length is illegal!\n"); + if (unlikely(!data || !sg_is_last(data))) { + dev_err(dev, "data is illegal!\n"); return -EINVAL; } hpre_req->dst = NULL; - dma = dma_map_single(dev, sg_virt(data), len, DMA_FROM_DEVICE); + dma = dma_map_single(dev, sg_virt(data), ctx->key_sz << 1, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(dev, dma))) { dev_err(dev, "dma map data err!\n"); return -ENOMEM; diff --git a/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c b/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c index 81dd22d2083f..833d3c8e4650 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c +++ b/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c @@ -137,6 +137,13 @@ int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev, mutex_lock(&table_lock); atomic_set(&accel_dev->ref_count, 0); + mutex_init(&accel_dev->state_lock); + /* + * The VF2PF lock is used to send messages to the PF outside of the + * device up/down cycle, so it must live as long as the accel device. + */ + if (accel_dev->is_vf) + mutex_init(&accel_dev->vf.vf2pf_lock); /* PF on host or VF on guest - optimized to remove redundant is_vf */ if (!accel_dev->is_vf || !pf) { @@ -210,7 +217,6 @@ int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev, map->attached = true; list_add_tail(&map->list, &vfs_table); } - mutex_init(&accel_dev->state_lock); unlock: mutex_unlock(&table_lock); return ret; @@ -257,6 +263,8 @@ void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev, } } unlock: + if (accel_dev->is_vf) + mutex_destroy(&accel_dev->vf.vf2pf_lock); mutex_destroy(&accel_dev->state_lock); list_del(&accel_dev->list); mutex_unlock(&table_lock); diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_vf_mig.c b/drivers/crypto/intel/qat/qat_common/adf_gen4_vf_mig.c index adb21656a3ba..91eff18a505b 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_gen4_vf_mig.c +++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_vf_mig.c @@ -837,6 +837,9 @@ static int adf_gen4_vfmig_save_state(struct qat_mig_dev *mdev) return ret; } + memset(mdev->state + mdev->setup_size, 0, + mdev->state_size - mdev->setup_size); + adf_mstate_mgr_init(vfmig->mstate_mgr, mdev->state + mdev->setup_size, mdev->state_size - mdev->setup_size); if (!adf_mstate_preamble_add(vfmig->mstate_mgr)) @@ -934,6 +937,8 @@ static int adf_gen4_vfmig_save_setup(struct qat_mig_dev *mdev) if (mdev->setup_size) return 0; + memset(mdev->state, 0, mdev->state_size); + adf_mstate_mgr_init(vfmig->mstate_mgr, mdev->state, mdev->state_size); if (!adf_mstate_preamble_add(vfmig->mstate_mgr)) return -EINVAL; diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen6_ras.c b/drivers/crypto/intel/qat/qat_common/adf_gen6_ras.c index 967253082a98..902c4b1a23e3 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_gen6_ras.c +++ b/drivers/crypto/intel/qat/qat_common/adf_gen6_ras.c @@ -323,14 +323,26 @@ static void adf_handle_ti_cd_par_sts(struct adf_accel_dev *accel_dev, void __iom u32 ti_cd_par_sts; ti_cd_par_sts = ADF_CSR_RD(csr, ADF_GEN6_TI_CD_PAR_STS); - ti_cd_par_sts &= ADF_GEN6_TI_CD_PAR_STS_MASK; + ti_cd_par_sts &= ADF_GEN6_TI_CD_PAR_STS_TI_INT_ERR_DEVHALT_MASK; if (ti_cd_par_sts) { dev_err(&GET_DEV(accel_dev), "TI CD parity error: %#x\n", ti_cd_par_sts); - ADF_RAS_ERR_CTR_INC(accel_dev->ras_errors, ADF_RAS_UNCORR); ADF_CSR_WR(csr, ADF_GEN6_TI_CD_PAR_STS, ti_cd_par_sts); } } +static void adf_handle_ti_misc_cd_par_sts(struct adf_accel_dev *accel_dev, void __iomem *csr) +{ + u32 ti_misc_cd_par_sts; + + ti_misc_cd_par_sts = ADF_CSR_RD(csr, ADF_GEN6_TI_CD_PAR_STS); + ti_misc_cd_par_sts &= ADF_GEN6_TI_CD_PAR_STS_TI_MISC_MASK; + if (ti_misc_cd_par_sts) { + dev_err(&GET_DEV(accel_dev), "TI MISC CD parity error: %#x\n", ti_misc_cd_par_sts); + ADF_RAS_ERR_CTR_INC(accel_dev->ras_errors, ADF_RAS_UNCORR); + ADF_CSR_WR(csr, ADF_GEN6_TI_CD_PAR_STS, ti_misc_cd_par_sts); + } +} + static void adf_handle_ti_trnsb_par_sts(struct adf_accel_dev *accel_dev, void __iomem *csr) { u32 ti_trnsb_par_sts; @@ -367,7 +379,6 @@ static void adf_handle_ti_err(struct adf_accel_dev *accel_dev, void __iomem *csr adf_handle_ti_ci_par_sts(accel_dev, csr); adf_handle_ti_pullfub_par_sts(accel_dev, csr); adf_handle_ti_pushfub_par_sts(accel_dev, csr); - adf_handle_ti_cd_par_sts(accel_dev, csr); adf_handle_ti_trnsb_par_sts(accel_dev, csr); adf_handle_iosfp_cmd_parerr(accel_dev, csr); } @@ -591,6 +602,8 @@ static void adf_handle_timiscsts(struct adf_accel_dev *accel_dev, void __iomem * if (!(errsou & ADF_GEN6_ERRSOU3_TIMISCSTS_BIT)) return; + adf_handle_ti_misc_cd_par_sts(accel_dev, csr); + timiscsts = ADF_CSR_RD(csr, ADF_GEN6_TIMISCSTS); if (timiscsts) { dev_err(&GET_DEV(accel_dev), "Fatal error in transmit interface: %#x\n", @@ -730,6 +743,7 @@ static void adf_handle_ti_int_err_devhalt(struct adf_accel_dev *accel_dev, void if (!(errsou & ADF_GEN6_ERRSOU3_TI_INT_ERR_DEVHALT_BIT)) return; + adf_handle_ti_cd_par_sts(accel_dev, csr); dev_err(&GET_DEV(accel_dev), "DEVHALT due to a TI internal memory error\n"); ADF_RAS_ERR_CTR_INC(accel_dev->ras_errors, ADF_RAS_FATAL); } diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen6_ras.h b/drivers/crypto/intel/qat/qat_common/adf_gen6_ras.h index 66ced271d173..11f7b2986f56 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_gen6_ras.h +++ b/drivers/crypto/intel/qat/qat_common/adf_gen6_ras.h @@ -170,23 +170,25 @@ struct adf_ras_ops; #define ADF_GEN6_TI_CD_PAR_ERR_MASK 0x500638 /* - * TI CD parity status mask + * TI CD parity status mask - TI_INT_ERR_DEVHALT bits * BIT(0) - BIT(15) - CtxMdRam[0:15]_sts parity status * BIT(16) - Leaf2ClusterRam_sts parity status * BIT(17) - BIT(18) - Ring2LeafRam[0:1]_sts parity status - * BIT(19) - VirtualQ_sts parity status - * BIT(20) - DtRdQ_sts parity status - * BIT(21) - DtWrQ_sts parity status - * BIT(22) - RiCmdQ_sts parity status - * BIT(23) - BypassQ_sts parity status - * BIT(24) - DtRdQ_sc_sts parity status - * BIT(25) - DtWrQ_sc_sts parity status */ -#define ADF_GEN6_TI_CD_PAR_STS_MASK \ +#define ADF_GEN6_TI_CD_PAR_STS_TI_INT_ERR_DEVHALT_MASK \ (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | \ BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | BIT(12) | BIT(13) | \ - BIT(14) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | \ - BIT(21) | BIT(22) | BIT(23) | BIT(24) | BIT(25)) + BIT(14) | BIT(15) | BIT(16) | BIT(17) | BIT(18)) + +/* + * TI CD parity status mask - TIMISCSTS bit + * BIT(19) - VirtualQ_sts parity status + */ +#define ADF_GEN6_TI_CD_PAR_STS_TI_MISC_MASK BIT(19) + +#define ADF_GEN6_TI_CD_PAR_STS_MASK \ + (ADF_GEN6_TI_CD_PAR_STS_TI_INT_ERR_DEVHALT_MASK | \ + ADF_GEN6_TI_CD_PAR_STS_TI_MISC_MASK) /* TI TRNSB parity status */ #define ADF_GEN6_TI_TRNSB_PAR_STS 0x500648 diff --git a/drivers/crypto/intel/qat/qat_common/adf_vf_isr.c b/drivers/crypto/intel/qat/qat_common/adf_vf_isr.c index a4636ec9f9ca..9ff6f6648301 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_vf_isr.c +++ b/drivers/crypto/intel/qat/qat_common/adf_vf_isr.c @@ -118,7 +118,6 @@ static int adf_setup_pf2vf_bh(struct adf_accel_dev *accel_dev) tasklet_init(&accel_dev->vf.pf2vf_bh_tasklet, (void *)adf_pf2vf_bh_handler, (unsigned long)accel_dev); - mutex_init(&accel_dev->vf.vf2pf_lock); return 0; } @@ -126,7 +125,6 @@ static void adf_cleanup_pf2vf_bh(struct adf_accel_dev *accel_dev) { tasklet_disable(&accel_dev->vf.pf2vf_bh_tasklet); tasklet_kill(&accel_dev->vf.pf2vf_bh_tasklet); - mutex_destroy(&accel_dev->vf.vf2pf_lock); } static irqreturn_t adf_isr(int irq, void *privdata) diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c index 8b1dc05df8c8..ade5361571f1 100644 --- a/drivers/crypto/nx/nx-842.c +++ b/drivers/crypto/nx/nx-842.c @@ -421,6 +421,8 @@ static int decompress(struct nx842_crypto_ctx *ctx, slen -= spadding; + if (ignore > dlen) + return -EINVAL; dlen -= ignore; if (ignore) pr_debug("ignoring last %x bytes\n", ignore); diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index 16d5c617d5ee..96b399c7eca6 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -1084,6 +1084,8 @@ static void omap_des_remove(struct platform_device *pdev) omap_des_unregister_algs(dd->pdata); + crypto_engine_exit(dd->engine); + cancel_work_sync(&dd->done_task); omap_des_dma_cleanup(dd); pm_runtime_disable(dd->dev); diff --git a/drivers/crypto/xilinx/zynqmp-sha.c b/drivers/crypto/xilinx/zynqmp-sha.c index 5813017b6b79..cd051e1f4275 100644 --- a/drivers/crypto/xilinx/zynqmp-sha.c +++ b/drivers/crypto/xilinx/zynqmp-sha.c @@ -59,7 +59,7 @@ static int zynqmp_sha_init_tfm(struct crypto_shash *hash) return PTR_ERR(fallback_tfm); if (crypto_shash_descsize(hash) < - crypto_shash_statesize(tfm_ctx->fbk_tfm)) { + crypto_shash_statesize(fallback_tfm)) { crypto_free_shash(fallback_tfm); return -EINVAL; } diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index bd2e282ca93a..eeb6921950fc 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -205,9 +205,10 @@ cxl_acpi_evaluate_qtg_dsm(acpi_handle handle, struct access_coordinate *coord, int entries, int *qos_class) { union acpi_object *out_obj, *out_buf, *obj; + /* QTG _DSM expects latencies in picoseconds. */ union acpi_object in_array[4] = { - [0].integer = { ACPI_TYPE_INTEGER, coord->read_latency }, - [1].integer = { ACPI_TYPE_INTEGER, coord->write_latency }, + [0].integer = { ACPI_TYPE_INTEGER, coord->read_latency * 1000ULL }, + [1].integer = { ACPI_TYPE_INTEGER, coord->write_latency * 1000ULL }, [2].integer = { ACPI_TYPE_INTEGER, coord->read_bandwidth }, [3].integer = { ACPI_TYPE_INTEGER, coord->write_bandwidth }, }; @@ -225,6 +226,11 @@ cxl_acpi_evaluate_qtg_dsm(acpi_handle handle, struct access_coordinate *coord, if (!entries) return -EINVAL; + /* Latency inputs must fit in the DWORD fields defined by the spec. */ + if (coord->read_latency > U32_MAX / 1000 || + coord->write_latency > U32_MAX / 1000) + return -ERANGE; + out_obj = acpi_evaluate_dsm(handle, &acpi_cxl_qtg_id_guid, 1, 1, &in_obj); if (!out_obj) return -ENXIO; @@ -892,13 +898,17 @@ static int pair_cxl_resource(struct device *dev, void *data) static int cxl_acpi_probe(struct platform_device *pdev) { - int rc; + struct cxl_cfmws_context ctx; + struct acpi_device *adev; struct resource *cxl_res; struct cxl_root *cxl_root; struct cxl_port *root_port; struct device *host = &pdev->dev; - struct acpi_device *adev = ACPI_COMPANION(host); - struct cxl_cfmws_context ctx; + int rc; + + adev = ACPI_COMPANION(host); + if (!adev) + return -ENODEV; device_lock_set_class(&pdev->dev, &cxl_root_key); rc = devm_add_action_or_reset(&pdev->dev, cxl_acpi_lock_reset_class, diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index 68859eba30db..48c1f3854b79 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -738,8 +738,8 @@ long cxl_pci_get_latency(struct pci_dev *pdev) { long bw; - bw = pcie_link_speed_mbps(pdev); - if (bw < 0) + bw = pcie_link_bandwidth_mbps(pdev); + if (bw <= 0) return 0; bw /= BITS_PER_BYTE; @@ -777,18 +777,12 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_reset_detected, "CXL"); int cxl_pci_get_bandwidth(struct pci_dev *pdev, struct access_coordinate *c) { - int speed, bw; - u16 lnksta; - u32 width; - - speed = pcie_link_speed_mbps(pdev); - if (speed < 0) - return speed; - speed /= BITS_PER_BYTE; + int bw; - pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnksta); - width = FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta); - bw = speed * width; + bw = pcie_link_bandwidth_mbps(pdev); + if (bw < 0) + return bw; + bw /= BITS_PER_BYTE; for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) { c[i].read_bandwidth = bw; @@ -860,7 +854,7 @@ static int update_gpf_port_dvsec(struct pci_dev *pdev, int dvsec, int phase) rc = pci_read_config_word(pdev, dvsec + offset, &ctrl); if (rc) - return rc; + return pcibios_err_to_errno(rc); if (FIELD_GET(base, ctrl) == GPF_TIMEOUT_BASE_MAX && FIELD_GET(scale, ctrl) == GPF_TIMEOUT_SCALE_MAX) @@ -870,11 +864,17 @@ static int update_gpf_port_dvsec(struct pci_dev *pdev, int dvsec, int phase) ctrl |= FIELD_PREP(scale, GPF_TIMEOUT_SCALE_MAX); rc = pci_write_config_word(pdev, dvsec + offset, ctrl); - if (!rc) - pci_dbg(pdev, "Port GPF phase %d timeout: %d0 secs\n", - phase, GPF_TIMEOUT_BASE_MAX); + if (rc) { + rc = pcibios_err_to_errno(rc); + pci_warn(pdev, "Port GPF phase %d timeout write failed: %d\n", + phase, rc); + return rc; + } - return rc; + pci_dbg(pdev, "Port GPF phase %d timeout: %d0 secs\n", + phase, GPF_TIMEOUT_BASE_MAX); + + return 0; } int cxl_gpf_port_setup(struct cxl_dport *dport) @@ -884,16 +884,22 @@ int cxl_gpf_port_setup(struct cxl_dport *dport) if (!dport->gpf_dvsec) { struct pci_dev *pdev; - int dvsec; + int dvsec, rc; dvsec = cxl_gpf_get_dvsec(dport->dport_dev); if (!dvsec) return -EINVAL; - dport->gpf_dvsec = dvsec; pdev = to_pci_dev(dport->dport_dev); - update_gpf_port_dvsec(pdev, dport->gpf_dvsec, 1); - update_gpf_port_dvsec(pdev, dport->gpf_dvsec, 2); + rc = update_gpf_port_dvsec(pdev, dvsec, 1); + if (rc) + return rc; + + rc = update_gpf_port_dvsec(pdev, dvsec, 2); + if (rc) + return rc; + + dport->gpf_dvsec = dvsec; } return 0; diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 8d2dc4b74178..599aa9d9eddc 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -2286,6 +2286,9 @@ EXPORT_SYMBOL_NS_GPL(schedule_cxl_memdev_detach, "CXL"); static void add_latency(struct access_coordinate *c, long latency) { + /* Convert link latency from picoseconds to nanoseconds. */ + latency = DIV_ROUND_UP(latency, 1000); + for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) { c[i].write_latency += latency; c[i].read_latency += latency; diff --git a/drivers/dax/super.c b/drivers/dax/super.c index efa5f6186019..9b46166fd214 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -601,7 +601,7 @@ static int __init dax_core_init(void) unregister_chrdev_region(dax_devt, MINORMASK+1); err_chrdev: dax_fs_exit(); - return 0; + return rc; } static void __exit dax_core_exit(void) diff --git a/drivers/dma/altera-msgdma.c b/drivers/dma/altera-msgdma.c index e1811a9be0bb..2d4bca495b3d 100644 --- a/drivers/dma/altera-msgdma.c +++ b/drivers/dma/altera-msgdma.c @@ -849,11 +849,6 @@ static int msgdma_probe(struct platform_device *pdev) if (mdev->irq < 0) return -ENXIO; - ret = devm_request_irq(&pdev->dev, mdev->irq, msgdma_irq_handler, - 0, dev_name(&pdev->dev), mdev); - if (ret) - return ret; - tasklet_setup(&mdev->irq_tasklet, msgdma_tasklet); dma_cookie_init(&mdev->dmachan); @@ -865,6 +860,11 @@ static int msgdma_probe(struct platform_device *pdev) INIT_LIST_HEAD(&mdev->done_list); INIT_LIST_HEAD(&mdev->free_list); + ret = devm_request_irq(&pdev->dev, mdev->irq, msgdma_irq_handler, + 0, dev_name(&pdev->dev), mdev); + if (ret) + return ret; + dma_dev = &mdev->dmadev; /* Set DMA capabilities */ diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index dfd49412f319..59d359f3f3fb 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -834,6 +834,7 @@ static int i10nm_get_ddr_munits(void) mbase = ioremap(base + off, size); if (!mbase) { + pci_dev_put(mdev); i10nm_printk(KERN_ERR, "Failed to ioremap 0x%llx\n", base + off); return -ENODEV; diff --git a/drivers/firewire/ohci-serdes-test.c b/drivers/firewire/ohci-serdes-test.c index 258f668619ef..87b136e041de 100644 --- a/drivers/firewire/ohci-serdes-test.c +++ b/drivers/firewire/ohci-serdes-test.c @@ -43,7 +43,7 @@ static void test_self_id_receive_buffer_deserialization(struct kunit *test) static void test_at_data_serdes(struct kunit *test) { static const __le32 expected[] = { - cpu_to_le32(0x00020e80), + cpu_to_le32(0x00820e80), cpu_to_le32(0xffc2ffff), cpu_to_le32(0xe0000000), }; @@ -56,7 +56,7 @@ static void test_at_data_serdes(struct kunit *test) unsigned int destination_id = ohci1394_at_data_get_destination_id(expected); u64 destination_offset = ohci1394_at_data_get_destination_offset(expected); - KUNIT_EXPECT_FALSE(test, has_src_bus_id); + KUNIT_EXPECT_TRUE(test, has_src_bus_id); KUNIT_EXPECT_EQ(test, 0x02, speed); KUNIT_EXPECT_EQ(test, 0x03, tlabel); KUNIT_EXPECT_EQ(test, 0x02, retry); diff --git a/drivers/firewire/ohci.h b/drivers/firewire/ohci.h index 218666cfe14a..63ccf2f44504 100644 --- a/drivers/firewire/ohci.h +++ b/drivers/firewire/ohci.h @@ -178,7 +178,7 @@ static inline bool ohci1394_at_data_get_src_bus_id(const __le32 *data) { - return !!((data[0] & OHCI1394_AT_DATA_Q0_srcBusID_MASK) >> OHCI1394_AT_DATA_Q0_srcBusID_SHIFT); + return !!((le32_to_cpu(data[0]) & OHCI1394_AT_DATA_Q0_srcBusID_MASK) >> OHCI1394_AT_DATA_Q0_srcBusID_SHIFT); } static inline void ohci1394_at_data_set_src_bus_id(__le32 *data, bool src_bus_id) diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 94b05e4451dd..c532ba550352 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -22,7 +22,7 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -std=gnu11 \ # arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly # disable the stackleak plugin -cflags-$(CONFIG_ARM64) += -fpie $(DISABLE_KSTACK_ERASE) \ +cflags-$(CONFIG_ARM64) += -fpie $(DISABLE_KSTACK_ERASE) -ffixed-x18 \ -fno-unwind-tables -fno-asynchronous-unwind-tables cflags-$(CONFIG_ARM) += -DEFI_HAVE_STRLEN -DEFI_HAVE_STRNLEN \ -DEFI_HAVE_MEMCHR -DEFI_HAVE_STRRCHR \ diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c index 874f63b4a383..adc5d121a33c 100644 --- a/drivers/firmware/efi/libstub/efi-stub.c +++ b/drivers/firmware/efi/libstub/efi-stub.c @@ -73,6 +73,14 @@ static void install_memreserve_table(void) efi_guid_t memreserve_table_guid = LINUX_EFI_MEMRESERVE_TABLE_GUID; efi_status_t status; + /* + * If an earlier boot stage installed a memreserve table already, e.g., + * a kexec loader passing on the persistent reservations made by the + * previous kernel, use it as is: installing a new one would replace it. + */ + if (get_efi_config_table(memreserve_table_guid)) + return; + status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(*rsv), (void **)&rsv); if (status != EFI_SUCCESS) { diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 0f4035b089a2..f6856aabf27d 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -744,7 +744,7 @@ EXPORT_SYMBOL_GPL(fpga_mgr_put); * @mgr: fpga manager * * Given a pointer to FPGA Manager (from fpga_mgr_get() or - * of_fpga_mgr_put()) attempt to get the mutex. The user should call + * of_fpga_mgr_get()) attempt to get the mutex. The user should call * fpga_mgr_lock() and verify that it returns 0 before attempting to * program the FPGA. Likewise, the user should call fpga_mgr_unlock * when done programming the FPGA. diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 5de42f1143da..80b3b36cf703 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -593,10 +593,10 @@ static void davinci_gpio_save_context(struct davinci_gpio_controller *chips, context->set_data = readl_relaxed(&g->set_data); context->set_rising = readl_relaxed(&g->set_rising); context->set_falling = readl_relaxed(&g->set_falling); - } - /* Clear all interrupt status registers */ - writel_relaxed(GENMASK(31, 0), &g->intstat); + /* Clear stale interrupt status for this bank. */ + writel_relaxed(GENMASK(31, 0), &g->intstat); + } } static void davinci_gpio_restore_context(struct davinci_gpio_controller *chips, diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 4eeac12ad0ed..7ebc4f9662c9 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -863,6 +863,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) DECLARE_BITMAP(irq_mask, MAX_LINE); DECLARE_BITMAP(reg_direction, MAX_LINE); int level; + int ret; guard(mutex)(&chip->i2c_lock); @@ -877,7 +878,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) } /* Switch direction to input if needed */ - pca953x_read_regs(chip, chip->regs->direction, reg_direction); + ret = pca953x_read_regs(chip, chip->regs->direction, reg_direction); + if (ret) + goto out; bitmap_or(irq_mask, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio); bitmap_or(irq_mask, irq_mask, chip->irq_trig_level_high, gc->ngpio); @@ -889,6 +892,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) for_each_set_bit(level, irq_mask, gc->ngpio) pca953x_gpio_direction_input_unlocked(&chip->gpio_chip, level); +out: mutex_unlock(&chip->irq_lock); } @@ -983,7 +987,9 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin } /* Remove output pins from the equation */ - pca953x_read_regs(chip, chip->regs->direction, reg_direction); + ret = pca953x_read_regs(chip, chip->regs->direction, reg_direction); + if (ret) + return false; bitmap_copy(old_stat, chip->irq_stat, gc->ngpio); @@ -1084,7 +1090,9 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base) * interrupt. We have to rely on the previous read for * this purpose. */ - pca953x_read_regs(chip, chip->regs->direction, reg_direction); + ret = pca953x_read_regs(chip, chip->regs->direction, reg_direction); + if (ret) + return ret; bitmap_and(chip->irq_stat, irq_stat, reg_direction, gc->ngpio); mutex_init(&chip->irq_lock); diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index d67d361cc456..1afda8ea5769 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -1253,11 +1253,6 @@ static void gpio_v2_line_config_flags_to_desc_flags(u64 lflags, assign_bit(GPIOD_FLAG_ACTIVE_LOW, &flags, lflags & GPIO_V2_LINE_FLAG_ACTIVE_LOW); - if (lflags & GPIO_V2_LINE_FLAG_OUTPUT) - set_bit(GPIOD_FLAG_IS_OUT, &flags); - else if (lflags & GPIO_V2_LINE_FLAG_INPUT) - clear_bit(GPIOD_FLAG_IS_OUT, &flags); - assign_bit(GPIOD_FLAG_EDGE_RISING, &flags, lflags & GPIO_V2_LINE_FLAG_EDGE_RISING); assign_bit(GPIOD_FLAG_EDGE_FALLING, &flags, diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d0efcb96d276..c23ba5e94cd6 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2464,10 +2464,13 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) ret = desc_set_label(desc, label ? : "?"); if (ret) - goto out_clear_bit; + goto out_free_gpio; return 0; +out_free_gpio: + if (guard.gc->free) + guard.gc->free(guard.gc, offset); out_clear_bit: clear_bit(GPIOD_FLAG_REQUESTED, &desc->flags); return ret; @@ -2553,6 +2556,7 @@ void gpiod_free(struct gpio_desc *desc) char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset) { struct gpio_desc *desc; + const char *name; char *label; desc = gpiochip_get_desc(gc, offset); @@ -2564,7 +2568,11 @@ char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset) guard(srcu)(&desc->gdev->desc_srcu); - label = kstrdup(gpiod_get_label(desc), GFP_KERNEL); + name = gpiod_get_label(desc); + if (!name) + return NULL; + + label = kstrdup(name, GFP_KERNEL); if (!label) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 803b6fc360a0..034f2d03e367 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1195,8 +1195,17 @@ struct amdgpu_device { struct mutex mn_lock; DECLARE_HASHTABLE(mn_hash, 7); - /* tracking pinned memory */ + /* tracking pinned memory + * + * vram_pin_size = sum(vram_pin_size_xcp[]) + vram_pin_size_common + * + * vram_pin_size total pin size in device + * vram_pin_size_xcp[i] pins owned by partition i (bo->xcp_id = i, i >= 0) + * vram_pin_size_common pins not owned by any partition, bo->xcp_id = -1 + */ atomic64_t vram_pin_size; + atomic64_t vram_pin_size_xcp[MAX_XCP]; + atomic64_t vram_pin_size_common; atomic64_t visible_pin_size; atomic64_t gart_pin_size; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index c59b5d9cd36b..21dbc8675f4e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -40,6 +40,12 @@ extern uint64_t amdgpu_amdkfd_total_mem_size; +/* + * Align VRAM availability to 2MB to avoid fragmentation caused by 4K + * allocations in the tail 2MB BO chunk. + */ +#define VRAM_AVAILABLITY_ALIGN (1 << 21) + enum TLB_FLUSH_TYPE { TLB_FLUSH_LEGACY = 0, TLB_FLUSH_LIGHTWEIGHT, @@ -104,6 +110,7 @@ struct amdgpu_kfd_dev { struct kfd_dev *dev; int64_t vram_used[MAX_XCP]; uint64_t vram_used_aligned[MAX_XCP]; + atomic64_t vram_pinned[MAX_XCP]; bool init_complete; struct work_struct reset_work; @@ -374,6 +381,8 @@ void amdgpu_amdkfd_gpuvm_destroy_cb(struct amdgpu_device *adev, * Allows KFD to release its resources associated with the GEM object. */ void amdgpu_amdkfd_release_notify(struct amdgpu_bo *bo); +void amdgpu_amdkfd_account_vram_pin(struct amdgpu_bo *bo, int xcp_id); +void amdgpu_amdkfd_account_vram_unpin(struct amdgpu_bo *bo, int xcp_id); void amdgpu_amdkfd_reserve_system_mem(uint64_t size); #else static inline @@ -391,6 +400,16 @@ static inline void amdgpu_amdkfd_release_notify(struct amdgpu_bo *bo) { } + +static inline +void amdgpu_amdkfd_account_vram_pin(struct amdgpu_bo *bo, int xcp_id) +{ +} + +static inline +void amdgpu_amdkfd_account_vram_unpin(struct amdgpu_bo *bo, int xcp_id) +{ +} #endif #if IS_ENABLED(CONFIG_HSA_AMD_SVM) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index d56728b257f4..6de7dfa30ce5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -46,12 +46,6 @@ #define AMDGPU_USERPTR_RESTORE_DELAY_MS 1 #define AMDGPU_RESERVE_MEM_LIMIT (3UL << 29) -/* - * Align VRAM availability to 2MB to avoid fragmentation caused by 4K allocations in the tail 2MB - * BO chunk - */ -#define VRAM_AVAILABLITY_ALIGN (1 << 21) - /* Impose limit on how much memory KFD can use */ static struct { uint64_t max_system_mem_limit; @@ -73,6 +67,8 @@ static const char * const domain_bit_to_string[] = { #define domain_string(domain) domain_bit_to_string[ffs(domain)-1] static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work); +static size_t __get_available_memory(struct amdgpu_device *adev, + uint8_t xcp_id, int64_t vram_used); static bool kfd_mem_is_attached(struct amdgpu_vm *avm, struct kgd_mem *mem) @@ -169,13 +165,8 @@ void amdgpu_amdkfd_reserve_system_mem(uint64_t size) int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev, uint64_t size, u32 alloc_flag, int8_t xcp_id) { - uint64_t reserved_for_pt = - ESTIMATE_PT_SIZE(amdgpu_amdkfd_total_mem_size); - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - uint64_t reserved_for_ras = (con ? con->reserved_pages_in_bytes : 0); size_t system_mem_needed, ttm_mem_needed, vram_needed; int ret = 0; - uint64_t vram_size = 0; system_mem_needed = 0; ttm_mem_needed = 0; @@ -196,7 +187,6 @@ int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev, if (WARN_ONCE(xcp_id < 0, "invalid XCP ID %d", xcp_id)) return -EINVAL; - vram_size = KFD_XCP_MEMORY_SIZE(adev, xcp_id); if (adev->apu_prefer_gtt) { system_mem_needed = size; ttm_mem_needed = size; @@ -232,14 +222,11 @@ int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev, * VRAM check since ttm_mem_limit check already cover this allocation */ - if (adev && xcp_id >= 0 && (!adev->apu_prefer_gtt || adev->gmc.is_app_apu)) { - uint64_t vram_available = - vram_size - reserved_for_pt - reserved_for_ras - - atomic64_read(&adev->vram_pin_size); - if (adev->kfd.vram_used[xcp_id] + vram_needed > vram_available) { - ret = -ENOMEM; - goto release; - } + if (adev && xcp_id >= 0 && (!adev->apu_prefer_gtt || adev->gmc.is_app_apu) && + vram_needed > __get_available_memory(adev, xcp_id, + adev->kfd.vram_used[xcp_id])) { + ret = -ENOMEM; + goto release; } /* Update memory accounting by decreasing available system @@ -318,6 +305,30 @@ void amdgpu_amdkfd_release_notify(struct amdgpu_bo *bo) kfree(bo->kfd_bo); } +void amdgpu_amdkfd_account_vram_pin(struct amdgpu_bo *bo, int xcp_id) +{ + if (!bo->kfd_bo) + return; + + if (WARN_ONCE(xcp_id < 0, "KFD BO pinned in VRAM with no partition")) + return; + + atomic64_add(amdgpu_bo_size(bo), + &amdgpu_ttm_adev(bo->tbo.bdev)->kfd.vram_pinned[xcp_id]); +} + +void amdgpu_amdkfd_account_vram_unpin(struct amdgpu_bo *bo, int xcp_id) +{ + if (!bo->kfd_bo) + return; + + if (WARN_ONCE(xcp_id < 0, "KFD BO unpinned in VRAM with no partition")) + return; + + atomic64_sub(amdgpu_bo_size(bo), + &amdgpu_ttm_adev(bo->tbo.bdev)->kfd.vram_pinned[xcp_id]); +} + /** * create_dmamap_sg_bo() - Creates a amdgpu_bo object to reflect information * about USERPTR or DOOREBELL or MMIO BO. @@ -1518,6 +1529,7 @@ static int amdgpu_amdkfd_gpuvm_pin_bo(struct amdgpu_bo *bo, u32 domain) pr_err("Error in Pinning BO to domain: %d\n", domain); amdgpu_bo_sync_wait(bo, AMDGPU_FENCE_OWNER_KFD, false); + out: amdgpu_bo_unreserve(bo); return ret; @@ -1540,6 +1552,7 @@ static void amdgpu_amdkfd_gpuvm_unpin_bo(struct amdgpu_bo *bo) return; amdgpu_bo_unpin(bo); + amdgpu_bo_unreserve(bo); } @@ -1643,8 +1656,9 @@ int amdgpu_amdkfd_criu_resume(void *p) return ret; } -size_t amdgpu_amdkfd_get_available_memory(struct amdgpu_device *adev, - uint8_t xcp_id) +/* Caller must hold kfd_mem_limit.mem_limit_lock. */ +static size_t __get_available_memory(struct amdgpu_device *adev, + uint8_t xcp_id, int64_t vram_used) { uint64_t reserved_for_pt = ESTIMATE_PT_SIZE(amdgpu_amdkfd_total_mem_size); @@ -1653,14 +1667,17 @@ size_t amdgpu_amdkfd_get_available_memory(struct amdgpu_device *adev, ssize_t available; uint64_t vram_available, system_mem_available, ttm_mem_available; - spin_lock(&kfd_mem_limit.mem_limit_lock); + lockdep_assert_held(&kfd_mem_limit.mem_limit_lock); + if (adev->apu_prefer_gtt && !adev->gmc.is_app_apu) vram_available = KFD_XCP_MEMORY_SIZE(adev, xcp_id) - - adev->kfd.vram_used_aligned[xcp_id]; + - vram_used; else vram_available = KFD_XCP_MEMORY_SIZE(adev, xcp_id) - - adev->kfd.vram_used_aligned[xcp_id] - - atomic64_read(&adev->vram_pin_size) + - vram_used + - atomic64_read(&adev->vram_pin_size_xcp[xcp_id]) + - atomic64_read(&adev->vram_pin_size_common) + + atomic64_read(&adev->kfd.vram_pinned[xcp_id]) - reserved_for_pt - reserved_for_ras; @@ -1675,19 +1692,29 @@ size_t amdgpu_amdkfd_get_available_memory(struct amdgpu_device *adev, available = min3(system_mem_available, ttm_mem_available, vram_available); - available = ALIGN_DOWN(available, PAGE_SIZE); } else { - available = ALIGN_DOWN(vram_available, VRAM_AVAILABLITY_ALIGN); + available = vram_available; } - spin_unlock(&kfd_mem_limit.mem_limit_lock); - if (available < 0) available = 0; return available; } +size_t amdgpu_amdkfd_get_available_memory(struct amdgpu_device *adev, + uint8_t xcp_id) +{ + size_t available; + + spin_lock(&kfd_mem_limit.mem_limit_lock); + available = __get_available_memory(adev, xcp_id, + adev->kfd.vram_used_aligned[xcp_id]); + spin_unlock(&kfd_mem_limit.mem_limit_lock); + + return available; +} + int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( struct amdgpu_device *adev, uint64_t va, uint64_t size, void *drm_priv, struct kgd_mem **mem, @@ -2797,6 +2824,7 @@ static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work) struct task_struct *usertask; struct mm_struct *mm; uint32_t evicted_bos; + int ret; mutex_lock(&process_info->notifier_lock); evicted_bos = process_info->evicted_bos; @@ -2816,14 +2844,16 @@ static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work) mutex_lock(&process_info->lock); - if (update_invalid_user_pages(process_info, mm)) + ret = update_invalid_user_pages(process_info, mm); + if (ret) goto unlock_out; /* userptr_inval_list can be empty if all evicted userptr BOs * have been freed. In that case there is nothing to validate * and we can just restart the queues. */ if (!list_empty(&process_info->userptr_inval_list)) { - if (validate_invalid_user_pages(process_info)) + ret = validate_invalid_user_pages(process_info); + if (ret) goto unlock_out; } /* Final check for concurrent evicton and atomic update. If @@ -2832,11 +2862,14 @@ static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work) * reference counting inside KFD will handle this case. */ mutex_lock(&process_info->notifier_lock); - if (process_info->evicted_bos != evicted_bos) + if (process_info->evicted_bos != evicted_bos) { + ret = -EAGAIN; goto unlock_notifier_out; + } if (confirm_valid_user_pages_locked(process_info)) { WARN(1, "User pages unexpectedly invalid"); + ret = -EINVAL; goto unlock_notifier_out; } @@ -2854,8 +2887,10 @@ static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work) unlock_out: mutex_unlock(&process_info->lock); - /* If validation failed, reschedule another attempt */ - if (evicted_bos) { + /* If validation failed, reschedule another attempt, unless the + * device is gone for good + */ + if (evicted_bos && ret != -ENODEV) { queue_delayed_work(system_freezable_wq, &process_info->restore_userptr_work, msecs_to_jiffies(AMDGPU_USERPTR_RESTORE_DELAY_MS)); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index f8a2c9e41ca3..efcd2322afa6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -235,6 +235,12 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, size = p->chunks[i].length_dw; + if (size > INT_MAX / sizeof(uint32_t)) { + ret = -EINVAL; + i--; + goto free_partial_kdata; + } + p->chunks[i].kdata = vmemdup_array_user(u64_to_user_ptr(user_chunk.chunk_data), size, sizeof(uint32_t)); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 88dda7dd2cd1..2e0998de67ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -442,10 +442,8 @@ bool amdgpu_device_supports_boco(struct amdgpu_device *adev) if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) return false; - if (adev->has_pr3 || - ((adev->flags & AMD_IS_PX) && amdgpu_is_atpx_hybrid())) - return true; - return false; + /* BOCO needs a platform power resource (_PR3) to cut the power */ + return adev->has_pr3; } /** @@ -3591,6 +3589,12 @@ static int amdgpu_device_ip_late_init(struct amdgpu_device *adev) amdgpu_device_set_cg_state(adev, AMD_CG_STATE_GATE); amdgpu_device_set_pg_state(adev, AMD_PG_STATE_GATE); + r = amdgpu_dpm_reapply_umd_profile(adev); + if (r) { + dev_err(adev->dev, "Failed to restore UMD profile state: %d\n", r); + return r; + } + amdgpu_device_fill_reset_magic(adev); r = amdgpu_device_enable_mgpu_fan_boost(); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 845ebe041563..fc2823771cc4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -2904,19 +2904,6 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev) return 0; } -static void amdgpu_restore_umd_profile_pstate_after_runpm(struct amdgpu_device *adev) -{ - enum amd_dpm_forced_level level; - uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD | - AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK | - AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK | - AMD_DPM_FORCED_LEVEL_PROFILE_PEAK; - - level = amdgpu_dpm_get_performance_level(adev); - if (level & profile_mode_mask) - amdgpu_asic_update_umd_stable_pstate(adev, true); -} - static int amdgpu_pmops_runtime_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); @@ -2962,7 +2949,6 @@ static int amdgpu_pmops_runtime_resume(struct device *dev) if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX) drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; - amdgpu_restore_umd_profile_pstate_after_runpm(adev); adev->in_runpm = false; return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c index db2bb5cb671d..fa3676c5babc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c @@ -173,7 +173,6 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, const u64 max_bytes = SZ_2G; struct hmm_range *hmm_range; - unsigned long timeout; unsigned long *pfns; unsigned long end; int r; @@ -204,15 +203,9 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, pr_debug("hmm range: start = 0x%lx, end = 0x%lx", hmm_range->start, hmm_range->end); - timeout = jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT); - -retry: r = hmm_range_fault(hmm_range); - if (unlikely(r)) { - if (r == -EBUSY && !time_after(jiffies, timeout)) - goto retry; + if (unlikely(r)) goto out_free_pfns; - } if (hmm_range->end == end) break; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index cdab2c098cfa..c2f13584a5a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -917,6 +917,19 @@ void amdgpu_bo_unref(struct amdgpu_bo **bo) *bo = NULL; } +/* Map a BO onto vram_pin_size_xcp[]. bo->xcp_id < 0 means "any partition": + * such pins are not owned by a single partition and go to + * vram_pin_size_common, which every partition subtracts. + */ +static int amdgpu_bo_get_xcp(struct amdgpu_bo *bo) +{ + s8 xcp = bo->xcp_id; + + if (xcp >= 0 && xcp < MAX_XCP) + return xcp; + return -1; +} + /** * amdgpu_bo_pin - pin an &amdgpu_bo buffer object * @bo: &amdgpu_bo buffer object to be pinned @@ -997,7 +1010,17 @@ int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain) ttm_bo_pin(&bo->tbo); if (bo->tbo.resource->mem_type == TTM_PL_VRAM) { + int xcp = amdgpu_bo_get_xcp(bo); + atomic64_add(amdgpu_bo_size(bo), &adev->vram_pin_size); + if (xcp >= 0) { + atomic64_add(amdgpu_bo_size(bo), + &adev->vram_pin_size_xcp[xcp]); + } else { + atomic64_add(amdgpu_bo_size(bo), + &adev->vram_pin_size_common); + } + amdgpu_amdkfd_account_vram_pin(bo, xcp); atomic64_add(amdgpu_vram_mgr_bo_visible_size(bo), &adev->visible_pin_size); } else if (bo->tbo.resource->mem_type == TTM_PL_TT) { @@ -1030,7 +1053,17 @@ void amdgpu_bo_unpin(struct amdgpu_bo *bo) dma_buf_unpin(bo->tbo.base.import_attach); if (bo->tbo.resource->mem_type == TTM_PL_VRAM) { + int xcp = amdgpu_bo_get_xcp(bo); + atomic64_sub(amdgpu_bo_size(bo), &adev->vram_pin_size); + if (xcp >= 0) { + atomic64_sub(amdgpu_bo_size(bo), + &adev->vram_pin_size_xcp[xcp]); + } else { + atomic64_sub(amdgpu_bo_size(bo), + &adev->vram_pin_size_common); + } + amdgpu_amdkfd_account_vram_unpin(bo, xcp); atomic64_sub(amdgpu_vram_mgr_bo_visible_size(bo), &adev->visible_pin_size); } else if (bo->tbo.resource->mem_type == TTM_PL_TT) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 08c31d78b3fa..918f38965cf2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -766,7 +766,8 @@ int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, goto out_unlock; } if (unlikely((gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) && - vma->vm_file)) { + (vma->vm_file || + vma->vm_end < start + (u64)ttm->num_pages * PAGE_SIZE))) { r = -EPERM; goto out_unlock; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index f78ac6777ee5..c9614a99b40d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2720,10 +2720,7 @@ int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm) if (vm->use_cpu_for_update) { /* Sync with last SDMA update/clear before switching to CPU */ - r = amdgpu_bo_sync_wait(vm->root.bo, - AMDGPU_FENCE_OWNER_UNDEFINED, true); - if (r) - goto unreserve_bo; + dma_fence_wait(vm->last_update, false); vm->update_funcs = &amdgpu_vm_cpu_funcs; r = amdgpu_vm_pt_map_tables(adev, vm); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c index f794fb1cc06e..a05f34259d57 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c @@ -421,7 +421,7 @@ int amdgpu_vm_pt_clear(struct amdgpu_device *adev, struct amdgpu_vm *vm, if (r) goto exit; - r = vm->update_funcs->commit(¶ms, NULL); + r = vm->update_funcs->commit(¶ms, &vm->last_update); exit: drm_dev_exit(idx); return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c index 36805dcfa159..902d0a538e41 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c @@ -254,6 +254,11 @@ static int amdgpu_vm_sdma_update(struct amdgpu_vm_update_params *p, AMDGPU_KERNEL_JOB_ID_VM_UPDATE); if (r) return r; + + /* The estimate above describes the job which was just + * submitted, take the budget of the newly allocated one. + */ + ndw = p->num_dw_left; } if (!p->pages_addr) { diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 9cd63b4177bf..4bc35b5f7c47 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -1932,6 +1932,16 @@ static bool cik_need_reset_on_init(struct amdgpu_device *adev) { u32 clock_cntl, pc; + /* + * MacBookPros with switchable graphics put VRAM at 0 when the iGPU + * is enabled. Any later post (S3 resume, GPU reset) moves it back to + * the vbios default, so reset and post on load to start with the + * vbios layout. + */ + if (adev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE && + !(RREG32(mmMC_VM_FB_LOCATION) & MC_VM_FB_LOCATION__FB_BASE_MASK)) + return true; + if (adev->flags & AMD_IS_APU) return false; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 0f0d6cd52d91..230a346db3b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -2186,10 +2186,22 @@ static int gmc_v9_0_hw_init(struct amdgpu_ip_block *ip_block) * (type 2), which flushes both. Due to a race condition with * concurrent memory accesses using the same TLB cache line, we still * need a second TLB flush after this. + * + * GC 9.4.3, 9.4.4 and 9.5.0 hit a similar race. */ - adev->gmc.flush_tlb_needs_extra_type_2 = - amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 0) && - adev->gmc.xgmi.num_physical_nodes; + switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { + case IP_VERSION(9, 4, 0): + adev->gmc.flush_tlb_needs_extra_type_2 = + adev->gmc.xgmi.num_physical_nodes; + break; + case IP_VERSION(9, 4, 3): + case IP_VERSION(9, 4, 4): + case IP_VERSION(9, 5, 0): + adev->gmc.flush_tlb_needs_extra_type_2 = true; + break; + default: + break; + } /* The sequence of these two function calls matters.*/ gmc_v9_0_init_golden_registers(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index e0f139de7991..0c96a40fe4b4 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -1524,6 +1524,16 @@ static bool si_need_full_reset(struct amdgpu_device *adev) static bool si_need_reset_on_init(struct amdgpu_device *adev) { + /* + * MacBookPros with switchable graphics put VRAM at 0 when the iGPU + * is enabled. Any later post (S3 resume, GPU reset) moves it back to + * the vbios default, so reset and post on load to start with the + * vbios layout. + */ + if (adev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE && + !(RREG32(mmMC_VM_FB_LOCATION) & MC_VM_FB_LOCATION__FB_BASE_MASK)) + return true; + return false; } diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index ce54e2938107..bb8125131908 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -1425,6 +1425,16 @@ static bool vi_need_reset_on_init(struct amdgpu_device *adev) unsigned int i; u32 clock_cntl, pc; + /* + * MacBookPros with switchable graphics put VRAM at 0 when the iGPU + * is enabled. Any later post (S3 resume, GPU reset) moves it back to + * the vbios default, so reset and post on load to start with the + * vbios layout. + */ + if (adev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE && + !(RREG32(mmMC_VM_FB_LOCATION) & MC_VM_FB_LOCATION__FB_BASE_MASK)) + return true; + for (i = 0; i < ARRAY_SIZE(vi_reset_quirks); i++) if (adev->pdev->device == vi_reset_quirks[i].device && adev->pdev->subsystem_vendor == vi_reset_quirks[i].subsystem_vendor && diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 04c2d412fa7d..e4a6100d036a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -352,12 +352,10 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p, } } - if (!pdd->qpd.proc_doorbells) { - err = kfd_alloc_process_doorbells(dev->kfd, pdd); - if (err) { - pr_debug("failed to allocate process doorbells\n"); - goto err_bind_process; - } + err = kfd_alloc_process_doorbells(dev->kfd, pdd); + if (err) { + pr_debug("failed to allocate process doorbells\n"); + goto err_bind_process; } err = kfd_queue_acquire_buffers(pdd, &q_properties); @@ -1037,11 +1035,19 @@ static int kfd_ioctl_get_available_memory(struct file *filep, { struct kfd_ioctl_get_available_memory_args *args = data; struct kfd_process_device *pdd = kfd_lock_pdd_by_id(p, args->gpu_id); + struct amdgpu_device *adev; + size_t available; if (!pdd) return -EINVAL; - args->available = amdgpu_amdkfd_get_available_memory(pdd->dev->adev, - pdd->dev->node_id); + + adev = pdd->dev->adev; + available = amdgpu_amdkfd_get_available_memory(adev, pdd->dev->node_id); + if (adev->apu_prefer_gtt) + args->available = ALIGN_DOWN(available, PAGE_SIZE); + else + args->available = ALIGN_DOWN(available, VRAM_AVAILABLITY_ALIGN); + kfd_unlock_pdd(pdd); return 0; } @@ -1224,6 +1230,9 @@ static int kfd_ioctl_free_memory_of_gpu(struct file *filep, goto err_unlock; } + /* Queues a reset could not stop may still access the buffer */ + kfd_process_wait_gpu_reset_complete(p); + ret = amdgpu_amdkfd_gpuvm_free_memory_of_gpu(pdd->dev->adev, (struct kgd_mem *)mem, pdd->drm_priv, &size); @@ -2282,11 +2291,9 @@ static int criu_restore_devices(struct kfd_process *p, goto exit; } - if (!pdd->qpd.proc_doorbells) { - ret = kfd_alloc_process_doorbells(dev->kfd, pdd); - if (ret) - goto exit; - } + ret = kfd_alloc_process_doorbells(dev->kfd, pdd); + if (ret) + goto exit; } /* @@ -2696,6 +2703,7 @@ static int criu_process_info(struct file *filep, struct kfd_process *p, struct kfd_ioctl_criu_args *args) { + bool paused_here = false; int ret = 0; mutex_lock(&p->mutex); @@ -2706,11 +2714,15 @@ static int criu_process_info(struct file *filep, goto err_unlock; } - ret = kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_CRIU_CHECKPOINT); - if (ret) - goto err_unlock; + /* UNPAUSE restores the queues once, so evict them only once */ + if (!p->queues_paused) { + ret = kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_CRIU_CHECKPOINT); + if (ret) + goto err_unlock; - p->queues_paused = true; + p->queues_paused = true; + paused_here = true; + } args->pid = task_pid_nr_ns(p->lead_thread, task_active_pid_ns(p->lead_thread)); @@ -2725,7 +2737,7 @@ static int criu_process_info(struct file *filep, args->priv_data_size); err_unlock: - if (ret) { + if (ret && paused_here) { kfd_process_restore_queues(p); p->queues_paused = false; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index b0e87bdc2911..ee6c17e88976 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -2051,27 +2051,33 @@ static void kfd_find_numa_node_in_srat(struct kfd_node *kdev) return; } + if (table_header->length < sizeof(struct acpi_table_srat)) + goto invalid_srat; + table_end = (unsigned long)table_header + table_header->length; /* Parse all entries looking for a match. */ sub_header = (struct acpi_subtable_header *) ((unsigned long)table_header + sizeof(struct acpi_table_srat)); - subtable_len = sub_header->length; - while (((unsigned long)sub_header) + subtable_len < table_end) { - /* - * If length is 0, break from this loop to avoid - * infinite loop. - */ - if (subtable_len == 0) { - pr_err("SRAT invalid zero length\n"); - break; - } + while ((unsigned long)sub_header < table_end) { + unsigned long start = (unsigned long)sub_header; + + if (table_end - start < sizeof(*sub_header)) + goto invalid_srat; + + subtable_len = sub_header->length; + if (subtable_len < sizeof(*sub_header) || + subtable_len > table_end - start) + goto invalid_srat; switch (sub_header->type) { case ACPI_SRAT_TYPE_CPU_AFFINITY: cpu = (struct acpi_srat_cpu_affinity *)sub_header; + if (subtable_len < sizeof(*cpu)) + goto invalid_srat; + pxm = *((u32 *)cpu->proximity_domain_hi) << 8 | cpu->proximity_domain_lo; if (pxm > max_pxm) @@ -2079,6 +2085,9 @@ static void kfd_find_numa_node_in_srat(struct kfd_node *kdev) break; case ACPI_SRAT_TYPE_GENERIC_AFFINITY: gpu = (struct acpi_srat_generic_affinity *)sub_header; + if (subtable_len < sizeof(*gpu)) + goto invalid_srat; + bdf = *((u16 *)(&gpu->device_handle[0])) << 16 | *((u16 *)(&gpu->device_handle[2])); if (bdf == pci_id) { @@ -2095,9 +2104,13 @@ static void kfd_find_numa_node_in_srat(struct kfd_node *kdev) sub_header = (struct acpi_subtable_header *) ((unsigned long)sub_header + subtable_len); - subtable_len = sub_header->length; } + goto out; + +invalid_srat: + pr_err("SRAT contains an invalid subtable\n"); +out: acpi_put_table(table_header); /* Workaround bad cpu-gpu binding case */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c index fdcf7f2d1b5b..6af268a031f2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c @@ -239,11 +239,9 @@ phys_addr_t kfd_get_process_doorbells(struct kfd_process_device *pdd) struct amdgpu_device *adev = pdd->dev->adev; uint32_t first_db_index; - if (!pdd->qpd.proc_doorbells) { - if (kfd_alloc_process_doorbells(pdd->dev->kfd, pdd)) - /* phys_addr_t 0 is error */ - return 0; - } + if (kfd_alloc_process_doorbells(pdd->dev->kfd, pdd)) + /* phys_addr_t 0 is error */ + return 0; first_db_index = amdgpu_doorbell_index_on_bar(adev, pdd->qpd.proc_doorbells, @@ -257,12 +255,21 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device * int r; struct qcm_process_device *qpd = &pdd->qpd; + mutex_lock(&pdd->doorbell_mutex); + + /* Another thread may have won the check-and-allocate race */ + if (qpd->proc_doorbells) { + mutex_unlock(&pdd->doorbell_mutex); + return 0; + } + /* Allocate bitmap for dynamic doorbell allocation */ qpd->doorbell_bitmap = bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS, GFP_KERNEL); if (!qpd->doorbell_bitmap) { DRM_ERROR("Failed to allocate process doorbell bitmap\n"); - return -ENOMEM; + r = -ENOMEM; + goto unlock; } r = init_doorbell_bitmap(&pdd->qpd, kfd); @@ -284,11 +291,15 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device * DRM_ERROR("Failed to allocate process doorbells\n"); goto err; } + + mutex_unlock(&pdd->doorbell_mutex); return 0; err: bitmap_free(qpd->doorbell_bitmap); qpd->doorbell_bitmap = NULL; +unlock: + mutex_unlock(&pdd->doorbell_mutex); return r; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index f2cda82cbed4..1f5f52818898 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -769,6 +769,9 @@ struct kfd_process_device { /* per-process-per device QCM data structure */ struct qcm_process_device qpd; + /* Serializes process doorbell allocation for this device */ + struct mutex doorbell_mutex; + /*Apertures*/ uint64_t lds_base; uint64_t lds_limit; @@ -1081,6 +1084,7 @@ void kfd_unref_process(struct kfd_process *p); int kfd_process_evict_queues(struct kfd_process *p, uint32_t trigger); int kfd_process_restore_queues(struct kfd_process *p); void kfd_suspend_all_processes(void); +void kfd_process_wait_gpu_reset_complete(struct kfd_process *p); int kfd_resume_all_processes(void); struct kfd_process_device *kfd_process_device_data_by_id(struct kfd_process *process, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 8ed513a77d38..1c591953cc80 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -1089,6 +1089,7 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) } atomic_dec(&pdd->dev->kfd->kfd_processes_count); + mutex_destroy(&pdd->doorbell_mutex); kfree(pdd); p->pdds[i] = NULL; @@ -1143,7 +1144,7 @@ static void kfd_process_remove_sysfs(struct kfd_process *p) /* * If any GPU is ongoing reset, wait for reset complete. */ -static void kfd_process_wait_gpu_reset_complete(struct kfd_process *p) +void kfd_process_wait_gpu_reset_complete(struct kfd_process *p) { int i; @@ -1628,6 +1629,7 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev, pdd->dev = dev; INIT_LIST_HEAD(&pdd->qpd.queues_list); INIT_LIST_HEAD(&pdd->qpd.priv_queue_list); + mutex_init(&pdd->doorbell_mutex); pdd->qpd.dqm = dev->dqm; pdd->qpd.pqm = &p->pqm; pdd->qpd.evicted = 0; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c index 6f06516da32a..eaa284e55182 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c @@ -231,6 +231,15 @@ void kfd_queue_buffer_put(struct amdgpu_bo **bo) amdgpu_bo_unref(bo); } +static void kfd_queue_put_bos(struct queue_properties *properties) +{ + kfd_queue_buffer_put(&properties->wptr_bo); + kfd_queue_buffer_put(&properties->rptr_bo); + kfd_queue_buffer_put(&properties->ring_bo); + kfd_queue_buffer_put(&properties->eop_buf_bo); + kfd_queue_buffer_put(&properties->cwsr_bo); +} + int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_properties *properties) { struct kfd_topology_device *topo_dev; @@ -341,7 +350,13 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope * dropping the VM reservation. */ kfd_queue_unref_bo_vas(pdd, properties); - kfd_queue_release_buffers(pdd, properties); + /* + * The SVM CWSR range is the last thing acquired and a failed + * kfd_queue_buffer_svm_get() takes nothing, so only the BOs are held + * here. Dropping the SVM reference would drop the one of another queue + * using the same CWSR address. + */ + kfd_queue_put_bos(properties); return err; } @@ -350,11 +365,7 @@ int kfd_queue_release_buffers(struct kfd_process_device *pdd, struct queue_prope struct kfd_topology_device *topo_dev; u64 total_cwsr_size; - kfd_queue_buffer_put(&properties->wptr_bo); - kfd_queue_buffer_put(&properties->rptr_bo); - kfd_queue_buffer_put(&properties->ring_bo); - kfd_queue_buffer_put(&properties->eop_buf_bo); - kfd_queue_buffer_put(&properties->cwsr_bo); + kfd_queue_put_bos(properties); topo_dev = kfd_topology_device_by_id(pdd->dev->id); if (!topo_dev) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 1b29dee7948d..cd2cfb9a3bae 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -987,9 +987,12 @@ svm_range_split_pages(struct svm_range *new, struct svm_range *old, uint64_t start, uint64_t last) { uint64_t npages = last - start + 1; + bool has_dma_addr = false; int i, r; for (i = 0; i < MAX_GPU_INSTANCE; i++) { + if (old->dma_addr[i]) + has_dma_addr = true; r = svm_range_split_array(&new->dma_addr[i], &old->dma_addr[i], sizeof(*old->dma_addr[i]), old->start, npages, new->start, new->npages, @@ -997,8 +1000,16 @@ svm_range_split_pages(struct svm_range *new, struct svm_range *old, if (r) return r; } - if (old->actual_loc) + if (old->actual_loc) { + /* + * Pages migrated by prefetch have no dma_addr until they are + * mapped on a GPU. A fully resident range still splits exactly, + * old->npages isn't adjusted yet here. + */ + if (!has_dma_addr && old->vram_pages == old->npages) + new->vram_pages = new->npages; old->vram_pages -= new->vram_pages; + } return 0; } @@ -1853,7 +1864,7 @@ static void svm_range_restore_work(struct work_struct *work) struct mm_struct *mm; int evicted_ranges; int invalid; - int r; + int r = 0; svms = container_of(dwork, struct svm_range_list, restore_work); evicted_ranges = atomic_read(&svms->evicted_ranges); @@ -1927,8 +1938,10 @@ static void svm_range_restore_work(struct work_struct *work) mmap_write_unlock(mm); mutex_unlock(&process_info->lock); - /* If validation failed, reschedule another attempt */ - if (evicted_ranges) { + /* If validation failed, reschedule another attempt, unless the + * device is gone for good + */ + if (evicted_ranges && r != -ENODEV) { pr_debug("reschedule to restore svm range\n"); queue_delayed_work(system_freezable_wq, &svms->restore_work, msecs_to_jiffies(AMDGPU_SVM_RANGE_RESTORE_DELAY_MS)); 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 bb1fae39cd39..a77b55ff9321 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -10550,8 +10550,6 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, if (dm_old_crtc_state->stream) remove_stream(adev, acrtc, dm_old_crtc_state->stream); - pm_runtime_get_noresume(dev->dev); - acrtc->enabled = true; acrtc->hw_mode = new_crtc_state->mode; crtc->hwmode = new_crtc_state->mode; @@ -11024,8 +11022,13 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) #ifdef CONFIG_DEBUG_FS enum amdgpu_dm_pipe_crc_source cur_crc_src; #endif - /* Count number of newly disabled CRTCs for dropping PM refs later. */ - if (old_crtc_state->active && !new_crtc_state->active) + /* + * One runtime PM reference per active CRTC: take it when the + * CRTC turns on, count it when it turns off for dropping later. + */ + if (!old_crtc_state->active && new_crtc_state->active) + pm_runtime_get_noresume(dev->dev); + else if (old_crtc_state->active && !new_crtc_state->active) crtc_disable_count++; dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 7633af242919..e8f4e7b7af57 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -225,7 +225,7 @@ fill_dc_mst_payload_table_from_drm(struct dc_link *link, break; } } - ASSERT(i != copy_of_link_table.stream_count); + /* Payload absent from HW table when never allocated: nothing to remove. */ } /* Fill payload info*/ diff --git a/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c index ef75eb7d5adc..940de620e330 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c @@ -46,7 +46,7 @@ static int median3(int a, int b, int c) if (b > c) swap(b, c); if (a > b) - swap(b, c); + swap(a, b); return b; } diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c index d2a237fcf5b0..ccc7ce0db2e1 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c @@ -10921,6 +10921,8 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex calculate_tdlut_setting_params->cursor_buffer_size = mode_lib->ip.cursor_buffer_size; calculate_tdlut_setting_params->gpuvm_enable = display_cfg->gpuvm_enable; calculate_tdlut_setting_params->gpuvm_page_size_kbytes = display_cfg->plane_descriptors[k].overrides.gpuvm_min_page_size_kbytes; + calculate_tdlut_setting_params->tdlut_mpc_width_flag = display_cfg->plane_descriptors[k].tdlut.tdlut_mpc_width_flag; + calculate_tdlut_setting_params->is_gfx11 = dml_get_gfx_version(display_cfg->plane_descriptors[k].surface.tiling); // output calculate_tdlut_setting_params->tdlut_pte_bytes_per_frame = &s->tdlut_pte_bytes_per_frame[k]; diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index a71df052cf25..7103d8cfb479 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -1694,7 +1694,8 @@ bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps, return true; if (dc_caps != NULL && - dc_caps->dpp.dcn_arch == 1) { + dc_caps->dpp.dcn_arch == 1 && + !map_user_ramp) { if (input_tf->tf == TRANSFER_FUNCTION_PQ && dc_caps->dpp.dgam_rom_caps.pq == 1) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 2b0cdb2a2775..834ce6d1a40e 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -426,6 +426,8 @@ struct amd_pm_funcs { int (*print_clock_levels)(void *handle, enum pp_clock_type type, char *buf); int (*emit_clock_levels)(void *handle, enum pp_clock_type type, char *buf, int *offset); int (*force_performance_level)(void *handle, enum amd_dpm_forced_level level); + int (*reapply_performance_level)(void *handle, + enum amd_dpm_forced_level level); int (*get_sclk_od)(void *handle); int (*set_sclk_od)(void *handle, uint32_t value); int (*get_mclk_od)(void *handle); diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index d1c4d7f4accc..402354846c56 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -1085,6 +1085,91 @@ static void amdgpu_dpm_exit_umd_state(struct amdgpu_device *adev) AMD_PG_STATE_GATE); } +/** + * amdgpu_dpm_reapply_umd_profile - Restore the active UMD profile + * @adev: amdgpu device + * + * Resume and reset retain the selected DPM level in software, but the + * underlying GFX and PMFW state is lost. Reapply a retained UMD profile + * after the common resume path has restored its default CG and PG state. + */ +int amdgpu_dpm_reapply_umd_profile(struct amdgpu_device *adev) +{ + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + enum amd_dpm_forced_level level; + int ret, fallback_ret; + + if (!pp_funcs || !pp_funcs->reapply_performance_level || + !pp_funcs->force_performance_level) + return 0; + + /* Serialize the retained level with the GFX and PMFW reprogramming. */ + mutex_lock(&adev->pm.mutex); + if (adev->pm.dpm.thermal_active) { + dev_warn(adev->dev, + "Cannot restore UMD profile while thermal control is active\n"); + ret = 0; + goto unlock; + } + + if (pp_funcs->get_performance_level) + level = pp_funcs->get_performance_level(adev->powerplay.pp_handle); + else + level = adev->pm.dpm.forced_level; + + switch (level) { + case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: + case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: + break; + default: + ret = 0; + goto unlock; + } + + /* The active profile already owns the GFX PG reference. */ + ret = amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_GFX, + AMD_CG_STATE_UNGATE); + if (ret) + goto fallback_auto; + + ret = amdgpu_asic_update_umd_stable_pstate(adev, true); + if (ret) + goto fallback_auto; + + ret = pp_funcs->reapply_performance_level(adev->powerplay.pp_handle, + level); + if (ret) + goto fallback_auto; + +unlock: + mutex_unlock(&adev->pm.mutex); + + return ret; + +fallback_auto: + dev_warn(adev->dev, "Failed to restore UMD profile state: %d\n", ret); + + /* Restore normal CG before releasing the profile's PG reference. */ + amdgpu_asic_update_umd_stable_pstate(adev, false); + amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_GFX, + AMD_CG_STATE_GATE); + mutex_unlock(&adev->pm.mutex); + + mutex_lock(&adev->pm.stable_pstate_ctx_lock); + fallback_ret = amdgpu_dpm_force_performance_level(adev, + AMD_DPM_FORCED_LEVEL_AUTO); + if (fallback_ret) + dev_warn(adev->dev, "Failed to fall back to AUTO performance level: %d\n", + fallback_ret); + else + adev->pm.stable_pstate_ctx = NULL; + mutex_unlock(&adev->pm.stable_pstate_ctx_lock); + + return 0; +} + int amdgpu_dpm_force_performance_level(struct amdgpu_device *adev, enum amd_dpm_forced_level level) { diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h index 13a834575ed7..db78f44da050 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h @@ -482,6 +482,7 @@ void amdgpu_dpm_set_power_state(struct amdgpu_device *adev, enum amd_dpm_forced_level amdgpu_dpm_get_performance_level(struct amdgpu_device *adev); int amdgpu_dpm_force_performance_level(struct amdgpu_device *adev, enum amd_dpm_forced_level level); +int amdgpu_dpm_reapply_umd_profile(struct amdgpu_device *adev); int amdgpu_dpm_get_pp_num_states(struct amdgpu_device *adev, struct pp_states_info *states); int amdgpu_dpm_dispatch_task(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c index 05c5e7d19ca1..4edca695e73a 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c @@ -367,24 +367,46 @@ static void pp_dpm_en_umd_pstate(struct pp_hwmgr *hwmgr, } } -static int pp_dpm_force_performance_level(void *handle, - enum amd_dpm_forced_level level) +static int pp_dpm_apply_performance_level(struct pp_hwmgr *hwmgr, + enum amd_dpm_forced_level level, + bool reapply) { - struct pp_hwmgr *hwmgr = handle; + int ret; if (!hwmgr || !hwmgr->pm_en) return -EINVAL; - if (level == hwmgr->dpm_level) + if (!reapply && level == hwmgr->dpm_level) return 0; pp_dpm_en_umd_pstate(hwmgr, &level); hwmgr->request_dpm_level = level; - hwmgr_handle_task(hwmgr, AMD_PP_TASK_READJUST_POWER_STATE, NULL); + ret = hwmgr_handle_task(hwmgr, AMD_PP_TASK_READJUST_POWER_STATE, NULL); + if (ret) + return ret; + + ret = phm_force_dpm_levels(hwmgr, level); + if (ret) + return ret; + + hwmgr->dpm_level = level; return 0; } +static int pp_dpm_force_performance_level(void *handle, + enum amd_dpm_forced_level level) +{ + return pp_dpm_apply_performance_level(handle, level, false); +} + +static int +pp_dpm_reapply_performance_level(void *handle, + enum amd_dpm_forced_level level) +{ + return pp_dpm_apply_performance_level(handle, level, true); +} + static enum amd_dpm_forced_level pp_dpm_get_performance_level( void *handle) { @@ -1569,6 +1591,7 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .load_firmware = pp_dpm_load_fw, .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete, .force_performance_level = pp_dpm_force_performance_level, + .reapply_performance_level = pp_dpm_reapply_performance_level, .get_performance_level = pp_dpm_get_performance_level, .get_current_power_state = pp_dpm_get_current_power_state, .dispatch_tasks = pp_dpm_dispatch_tasks, diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index e0e208a0d9f9..0df4b36ec3a8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -2314,6 +2314,13 @@ static int smu_set_powergating_state(struct amdgpu_ip_block *ip_block, return 0; } +static void smu_enter_umd_pstate(struct smu_context *smu) +{ + smu_gpo_control(smu, false); + smu_gfx_ulv_control(smu, false); + smu_deep_sleep_control(smu, false); +} + static int smu_enable_umd_pstate(void *handle, enum amd_dpm_forced_level *level) { @@ -2332,9 +2339,7 @@ static int smu_enable_umd_pstate(void *handle, /* enter umd pstate, save current level, disable gfx cg*/ if (*level & profile_mode_mask) { smu_dpm_ctx->saved_dpm_level = smu_dpm_ctx->dpm_level; - smu_gpo_control(smu, false); - smu_gfx_ulv_control(smu, false); - smu_deep_sleep_control(smu, false); + smu_enter_umd_pstate(smu); amdgpu_asic_update_umd_stable_pstate(smu->adev, true); } } else { @@ -2393,7 +2398,8 @@ static void smu_power_profile_mode_put(struct smu_context *smu, static int smu_adjust_power_state_dynamic(struct smu_context *smu, enum amd_dpm_forced_level level, - bool skip_display_settings) + bool skip_display_settings, + bool force_performance_level) { int ret = 0; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); @@ -2420,7 +2426,7 @@ static int smu_adjust_power_state_dynamic(struct smu_context *smu, } } - if (smu_dpm_ctx->dpm_level != level) { + if (force_performance_level || smu_dpm_ctx->dpm_level != level) { ret = smu_asic_set_performance_level(smu, level); if (ret) { if (ret == -EOPNOTSUPP) @@ -2443,6 +2449,39 @@ static int smu_adjust_power_state_dynamic(struct smu_context *smu, return ret; } +static int +smu_reapply_power_state_dynamic(struct smu_context *smu, + enum amd_dpm_forced_level level) +{ + struct smu_dpm_context *smu_dpm_ctx = &smu->smu_dpm; + int ret; + + ret = smu_apply_clocks_adjust_rules(smu); + if (ret) { + dev_err(smu->adev->dev, "Failed to apply clocks adjust rules!"); + return ret; + } + + ret = smu_asic_set_performance_level(smu, level); + if (ret) { + if (ret == -EOPNOTSUPP) + dev_info(smu->adev->dev, "set performance level %d not supported", + level); + else + dev_err(smu->adev->dev, "Failed to set performance level %d", + level); + return ret; + } + + smu_dpm_ctx->dpm_level = level; + + if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL || + smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) + return 0; + + return smu_bump_power_profile_mode(smu, NULL, 0); +} + static int smu_handle_task(struct smu_context *smu, enum amd_dpm_forced_level level, enum amd_pp_task task_id) @@ -2457,13 +2496,13 @@ static int smu_handle_task(struct smu_context *smu, ret = smu_pre_display_config_changed(smu); if (ret) return ret; - ret = smu_adjust_power_state_dynamic(smu, level, false); + ret = smu_adjust_power_state_dynamic(smu, level, false, false); break; case AMD_PP_TASK_COMPLETE_INIT: - ret = smu_adjust_power_state_dynamic(smu, level, true); + ret = smu_adjust_power_state_dynamic(smu, level, true, false); break; case AMD_PP_TASK_READJUST_POWER_STATE: - ret = smu_adjust_power_state_dynamic(smu, level, true); + ret = smu_adjust_power_state_dynamic(smu, level, true, false); break; default: break; @@ -2592,6 +2631,37 @@ static int smu_force_performance_level(void *handle, return ret; } +static int +smu_reapply_performance_level(void *handle, + enum amd_dpm_forced_level level) +{ + struct smu_context *smu = handle; + struct smu_dpm_context *smu_dpm_ctx = &smu->smu_dpm; + + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; + + if (!smu->is_apu && !smu_dpm_ctx->dpm_context) + return -EINVAL; + + switch (level) { + case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: + case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: + break; + default: + return -EINVAL; + } + + if (smu_dpm_ctx->dpm_level != level) + return -EINVAL; + + smu_enter_umd_pstate(smu); + + return smu_reapply_power_state_dynamic(smu, level); +} + static int smu_set_display_count(void *handle, uint32_t count) { struct smu_context *smu = handle; @@ -3932,6 +4002,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .print_clock_levels = smu_print_ppclk_levels, .emit_clock_levels = smu_emit_ppclk_levels, .force_performance_level = smu_force_performance_level, + .reapply_performance_level = smu_reapply_performance_level, .read_sensor = smu_read_sensor, .get_apu_thermal_limit = smu_get_apu_thermal_limit, .set_apu_thermal_limit = smu_set_apu_thermal_limit, diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index d72c22dcf685..591f71577937 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -56,6 +56,7 @@ static void malidp_crtc_atomic_enable(struct drm_crtc *crtc, if (err < 0) { DRM_DEBUG_DRIVER("Failed to enable runtime power management: %d\n", err); + pm_runtime_put_noidle(crtc->dev->dev); return; } diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index efe534977d12..44761f7161f6 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1389,6 +1389,7 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp) { struct device_node *dp_node = dp->dev->of_node; struct video_info *video_info = &dp->video_info; + u32 val; switch (dp->plat_data->dev_type) { case RK3288_DP: @@ -1409,10 +1410,14 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp) * NOTE: those property parseing code is used for * providing backward compatibility for samsung platform. */ - of_property_read_u32(dp_node, "samsung,link-rate", - &video_info->max_link_rate); - of_property_read_u32(dp_node, "samsung,lane-count", - &video_info->max_lane_count); + if (of_property_read_u32(dp_node, "samsung,link-rate", &val)) + return dev_err_probe(dp->dev, -EINVAL, + "Failed to get samsung,link-rate\n"); + video_info->max_link_rate = val; + if (of_property_read_u32(dp_node, "samsung,lane-count", &val)) + return dev_err_probe(dp->dev, -EINVAL, + "Failed to get samsung,lane-count\n"); + video_info->max_lane_count = val; break; } diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c index d4b6ea42db0f..9c4ac2febc93 100644 --- a/drivers/gpu/drm/drm_panic.c +++ b/drivers/gpu/drm/drm_panic.c @@ -184,6 +184,8 @@ static void drm_panic_write_pixel24_xpage(void *vaddr, struct page *next_page, u8 *p = vaddr + offset; vaddr2 = kmap_local_page_try_from_panic(next_page); + if (!vaddr2) + return; *p++ = color & 0xff; color >>= 8; @@ -662,7 +664,8 @@ static int drm_panic_get_qr_code_url(u8 **qr_image) char *kmsg; int max_qr_data_size, url_len; - url_len = snprintf(url, sizeof(url), CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL "?a=%s&v=%s&z=", + url_len = snprintf(url, sizeof(url), "%s?a=%s&v=%s&z=", + CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL, utsname()->machine, utsname()->release); max_qr_data_size = drm_panic_qr_max_data_size(panic_qr_version, url_len); diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 4e93f8dd39d7..1827af24a3fa 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1254,6 +1254,8 @@ int dsi_tx_buf_alloc_6g(struct msm_dsi_host *msm_host, int size) if (IS_ERR(data)) { msm_host->tx_gem_obj = NULL; + drm_gpuvm_put(msm_host->vm); + msm_host->vm = NULL; return PTR_ERR(data); } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index 93a491a103e0..75dea34c43a8 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -13,14 +13,16 @@ #include "msm_kms.h" #include "hdmi.h" -static void msm_hdmi_power_on(struct drm_bridge *bridge) +static int msm_hdmi_power_on(struct drm_bridge *bridge) { struct drm_device *dev = bridge->dev; struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = hdmi_bridge->hdmi; int ret; - pm_runtime_resume_and_get(&hdmi->pdev->dev); + ret = pm_runtime_resume_and_get(&hdmi->pdev->dev); + if (ret) + return ret; if (hdmi->extp_clk) { DBG("pixclock: %lu", hdmi->pixclock); @@ -29,9 +31,14 @@ static void msm_hdmi_power_on(struct drm_bridge *bridge) DRM_DEV_ERROR(dev->dev, "failed to set extp clk rate: %d\n", ret); ret = clk_prepare_enable(hdmi->extp_clk); - if (ret) + if (ret) { DRM_DEV_ERROR(dev->dev, "failed to enable extp clk: %d\n", ret); + pm_runtime_put(&hdmi->pdev->dev); + return ret; + } } + + return 0; } static void power_off(struct drm_bridge *bridge) @@ -302,13 +309,18 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge, msm_hdmi_set_timings(hdmi, &crtc_state->adjusted_mode); - mutex_lock(&hdmi->state_mutex); - if (!hdmi->power_on) { - msm_hdmi_phy_resource_enable(phy); - msm_hdmi_power_on(bridge); - hdmi->power_on = true; + scoped_guard(mutex, &hdmi->state_mutex) { + if (!hdmi->power_on) { + if (msm_hdmi_phy_resource_enable(phy)) + return; + + if (msm_hdmi_power_on(bridge)) { + msm_hdmi_phy_resource_disable(phy); + return; + } + hdmi->power_on = true; + } } - mutex_unlock(&hdmi->state_mutex); if (connector->display_info.is_hdmi) msm_hdmi_audio_update(hdmi); @@ -342,10 +354,10 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge, msm_hdmi_phy_powerdown(phy); if (hdmi->power_on) { - power_off(bridge); hdmi->power_on = false; if (hdmi->connector->display_info.is_hdmi) msm_hdmi_audio_update(hdmi); + power_off(bridge); msm_hdmi_phy_resource_disable(phy); } mutex_unlock(&hdmi->state_mutex); diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c index 6777cba9255e..bc603a79c085 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c @@ -67,16 +67,28 @@ int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy) ret = regulator_bulk_enable(cfg->num_regs, phy->regs); if (ret) { DRM_DEV_ERROR(dev, "failed to enable regulators: (%d)\n", ret); - return ret; + goto err_pm_put; } for (i = 0; i < cfg->num_clks; i++) { ret = clk_prepare_enable(phy->clks[i]); - if (ret) + if (ret) { DRM_DEV_ERROR(dev, "failed to enable clock: %s (%d)\n", cfg->clk_names[i], ret); + goto err_clk_unprepare; + } } + return 0; + +err_clk_unprepare: + for (; i > 0; i--) + clk_disable_unprepare(phy->clks[i - 1]); + regulator_bulk_disable(cfg->num_regs, phy->regs); + +err_pm_put: + pm_runtime_put_sync(dev); + return ret; } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h index 112b674ed9c8..0172e0d200f8 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h @@ -46,6 +46,7 @@ int nv4c_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct n int g84_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pci **); int g92_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pci **); int g94_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pci **); +int mcp79_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pci **); int gf100_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pci **); int gf106_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pci **); int gk104_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pci **); diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index a3ba07fc48a0..a067c7244e7e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -631,6 +631,10 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) if (unlikely(device->info.family >= NV_DEVICE_INFO_V0_FERMI)) return nouveau_abi16_put(abi16, -EINVAL); + /* zero size yields a zero-length node, underflowing args.limit */ + if (unlikely(!info->size)) + return nouveau_abi16_put(abi16, -EINVAL); + chan = nouveau_abi16_chan(abi16, info->channel); if (!chan) return nouveau_abi16_put(abi16, -ENOENT); diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 7c6d91ee2722..f9662e067c56 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -397,6 +397,7 @@ nouveau_connector_destroy(struct drm_connector *connector) struct nouveau_connector *nv_connector = nouveau_connector(connector); nvif_event_dtor(&nv_connector->irq); nvif_event_dtor(&nv_connector->hpd); + cancel_work_sync(&nv_connector->irq_work); kfree(nv_connector->edid); drm_connector_unregister(connector); drm_connector_cleanup(connector); diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 55691ec44aba..738802358d85 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -486,7 +486,7 @@ nouveau_dp_irq(struct work_struct *work) container_of(work, typeof(*nv_connector), irq_work); struct drm_connector *connector = &nv_connector->base; struct nouveau_encoder *outp = find_encoder(connector, DCB_OUTPUT_DP); - struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev); + struct nouveau_drm *drm; struct nv50_mstm *mstm; u64 hpd = 0; int ret; @@ -494,6 +494,8 @@ nouveau_dp_irq(struct work_struct *work) if (!outp) return; + drm = nouveau_drm(outp->base.base.dev); + mstm = outp->dp.mstm; NV_DEBUG(drm, "service %s\n", connector->name); diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 4a193b7d6d9e..7acf241c4daf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -95,7 +95,7 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error) void nouveau_fence_context_del(struct nouveau_fence_chan *fctx) { - cancel_work_sync(&fctx->uevent_work); + disable_work_sync(&fctx->uevent_work); nouveau_fence_context_kill(fctx, 0); nvif_event_dtor(&fctx->event); fctx->dead = 1; diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c index 6fa387da0637..dc6c79f57a56 100644 --- a/drivers/gpu/drm/nouveau/nouveau_svm.c +++ b/drivers/gpu/drm/nouveau/nouveau_svm.c @@ -304,6 +304,19 @@ nouveau_svmm_fini(struct nouveau_svmm **psvmm) { struct nouveau_svmm *svmm = *psvmm; if (svmm) { + struct nouveau_svm *svm = svmm->vmm->cli->drm->svm; + + /* The fault handler caches svmm pointers under svm->mutex and + * dereferences them after dropping it, across blocking faults. + * The instance is already unlinked (nouveau_svmm_part), so drain + * the handler before the free to release any in-flight reference. + * + * On device teardown nouveau_svm_fini() ran first and freed + * drm->svm (NULL) after draining the buffer; nothing to flush. + */ + if (svm) + flush_work(&svm->buffer[0].work); + mutex_lock(&svmm->mutex); svmm->vmm = NULL; mutex_unlock(&svmm->mutex); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 3738c4664fb6..305b16d9bcc7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1237,7 +1237,7 @@ nvac_chipset = { .mc = { 0x00000001, g98_mc_new }, .mmu = { 0x00000001, mcp77_mmu_new }, .mxm = { 0x00000001, nv50_mxm_new }, - .pci = { 0x00000001, g94_pci_new }, + .pci = { 0x00000001, mcp79_pci_new }, .therm = { 0x00000001, g84_therm_new }, .timer = { 0x00000001, nv41_timer_new }, .volt = { 0x00000001, nv40_volt_new }, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild index a14ea0f7b1c8..90f03baeb22a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild @@ -9,6 +9,7 @@ nvkm-y += nvkm/subdev/pci/nv4c.o nvkm-y += nvkm/subdev/pci/g84.o nvkm-y += nvkm/subdev/pci/g92.o nvkm-y += nvkm/subdev/pci/g94.o +nvkm-y += nvkm/subdev/pci/mcp79.o nvkm-y += nvkm/subdev/pci/gf100.o nvkm-y += nvkm/subdev/pci/gf106.o nvkm-y += nvkm/subdev/pci/gk104.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/mcp79.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/mcp79.c new file mode 100644 index 000000000000..e2ae242f1aa7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/mcp79.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2026 Marek Czernohous + * + * MCP79/MCP7A (NVAC): like g94, but MSI re-arm goes through real PCI + * config space. The MMIO-mirror re-arm is unreliable on this IGP and a + * missed re-arm kills the interrupt line (see the nv46 comment; g92 + * already re-arms through config space for the same reason). + */ +#include "priv.h" + +static const struct nvkm_pci_func +mcp79_pci_func = { + .cfg = { .addr = 0x088000, .size = 0x1000 }, + + .init = g84_pci_init, + .msi_rearm = nv46_pci_msi_rearm, + + .pcie.init = g84_pcie_init, + .pcie.set_link = g84_pcie_set_link, + + .pcie.max_speed = g84_pcie_max_speed, + .pcie.cur_speed = g84_pcie_cur_speed, + + .pcie.set_version = g84_pcie_set_version, + .pcie.version = g84_pcie_version, + .pcie.version_supported = g92_pcie_version_supported, +}; + +int +mcp79_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&mcp79_pci_func, device, type, inst, ppci); +} diff --git a/drivers/gpu/drm/panel/panel-ebbg-ft8719.c b/drivers/gpu/drm/panel/panel-ebbg-ft8719.c index fb9f9f42be4f..1ab09c50a630 100644 --- a/drivers/gpu/drm/panel/panel-ebbg-ft8719.c +++ b/drivers/gpu/drm/panel/panel-ebbg-ft8719.c @@ -198,6 +198,8 @@ static int ebbg_ft8719_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_CLOCK_NON_CONTINUOUS; + ctx->panel.prepare_prev_first = true; + ret = drm_panel_of_backlight(&ctx->panel); if (ret) return dev_err_probe(dev, ret, "Failed to get backlight\n"); diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 7aa35899e33c..7c1edf8c5c2d 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -359,6 +359,10 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo, if (ret) return ret; + /* Imported sg tables only come with DMA addresses, no pages to map. */ + if (!ttm->pages) + return -EINVAL; + if (num_pages == 1 && ttm->caching == ttm_cached && !(man->use_tt && (ttm->page_flags & TTM_TT_FLAG_DECRYPTED))) { /* @@ -422,7 +426,7 @@ EXPORT_SYMBOL(ttm_bo_kmap_try_from_panic); * * Returns * -ENOMEM: Out of memory. - * -EINVAL: Invalid range. + * -EINVAL: Invalid range or the BO has no pages to map. */ int ttm_bo_kmap(struct ttm_buffer_object *bo, unsigned long start_page, unsigned long num_pages, @@ -496,7 +500,7 @@ EXPORT_SYMBOL(ttm_bo_kunmap); * * Returns * -ENOMEM: Out of memory. - * -EINVAL: Invalid range. + * -EINVAL: Invalid range or the BO has no pages to map. */ int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map) { @@ -543,6 +547,9 @@ int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map) if (ret) return ret; + if (!ttm->pages) + return -EINVAL; + /* * We need to use vmap to get the desired page protection * or to make the buffer object look contiguous. diff --git a/drivers/hte/hte-tegra194-test.c b/drivers/hte/hte-tegra194-test.c index 94e931f45305..4951049e00b0 100644 --- a/drivers/hte/hte-tegra194-test.c +++ b/drivers/hte/hte-tegra194-test.c @@ -218,10 +218,10 @@ static void tegra_hte_test_remove(struct platform_device *pdev) { (void)pdev; + timer_shutdown_sync(&hte.timer); free_irq(hte.gpio_in_irq, &hte); gpiod_put(hte.gpio_in); gpiod_put(hte.gpio_out); - timer_delete_sync(&hte.timer); } static struct platform_driver tegra_hte_test_driver = { diff --git a/drivers/hte/hte-tegra194.c b/drivers/hte/hte-tegra194.c index 690eb9be30fb..464467737002 100644 --- a/drivers/hte/hte-tegra194.c +++ b/drivers/hte/hte-tegra194.c @@ -787,17 +787,17 @@ static int tegra_hte_probe(struct platform_device *pdev) hte_dev->chip = gc; + for (i = 0; i < slices; i++) { + hte_dev->sl[i].flags = 0; + spin_lock_init(&hte_dev->sl[i].s_lock); + } + ret = devm_hte_register_chip(hte_dev->chip); if (ret) { dev_err(gc->dev, "hte chip register failed"); return ret; } - for (i = 0; i < slices; i++) { - hte_dev->sl[i].flags = 0; - spin_lock_init(&hte_dev->sl[i].s_lock); - } - val = HTE_TECTRL_ENABLE_ENABLE | (HTE_TECTRL_INTR_ENABLE << HTE_TECTRL_INTR_SHIFT) | (hte_dev->itr_thrshld << HTE_TECTRL_OCCU_SHIFT); diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index de408df0c4d7..667dffde3301 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,12 @@ #define POWER_METER_CAN_NOTIFY (1 << 3) #define POWER_METER_IS_BATTERY (1 << 8) #define UNKNOWN_HYSTERESIS 0xFFFFFFFF -#define UNKNOWN_POWER 0xFFFFFFFF +/* + * ACPI integers can either be 32-bit or 64-bit wide, so + * we have to check for both values. + */ +#define UNKNOWN_POWER_32 U32_MAX +#define UNKNOWN_POWER_64 U64_MAX #define METER_NOTIFY_CONFIG 0x80 #define METER_NOTIFY_TRIP 0x81 @@ -454,7 +460,7 @@ static int power_meter_read(struct device *dev, enum hwmon_sensor_types type, ret = update_meter(res); if (ret) return ret; - if (res->power == UNKNOWN_POWER) + if (res->power == UNKNOWN_POWER_32 || res->power == UNKNOWN_POWER_64) return -ENODATA; *val = res->power * 1000; break; diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index a84a32ada8bd..c9b7e435eda8 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -511,6 +511,11 @@ init_temp_data(struct platform_data *pdata, unsigned int cpu, int pkg_flag) tdata->cpu = cpu; tdata->cpu_core_id = topology_core_id(cpu); tdata->attr_size = MAX_CORE_ATTRS; + /* + * A zero timestamp does not look stale on 32-bit, where jiffies + * starts just short of wrapping. Backdate it instead. + */ + tdata->last_updated = jiffies - HZ - 1; mutex_init(&tdata->update_lock); return tdata; } @@ -554,9 +559,6 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu, u32 eax, edx; int err; - if (!housekeeping_cpu(cpu, HK_TYPE_MISC)) - return 0; - tdata = init_temp_data(pdata, cpu, pkg_flag); if (!tdata) return -ENOMEM; @@ -676,6 +678,14 @@ static int coretemp_cpu_online(unsigned int cpu) if (!cpu_has(c, X86_FEATURE_DTHERM)) return -ENODEV; + /* + * Keep isolated CPUs out of pdata->cpumask. Besides tracking the CPUs + * available to this driver, the mask is used to select the CPU on which + * to read the temperature MSRs. + */ + if (!housekeeping_cpu(cpu, HK_TYPE_MISC)) + return 0; + pdata = platform_get_drvdata(pdev); if (!pdata->hwmon_dev) { struct device *hwmon; @@ -705,8 +715,8 @@ static int coretemp_cpu_online(unsigned int cpu) } /* - * Check whether a thread sibling is already online. If not add the - * interface for this CPU core. + * Check whether a housekeeping thread sibling is already online. If + * not, add the interface for this CPU core. */ if (!cpumask_intersects(&pdata->cpumask, topology_sibling_cpumask(cpu))) coretemp_add_core(pdev, cpu, 0); @@ -736,9 +746,9 @@ static int coretemp_cpu_offline(unsigned int cpu) cpumask_clear_cpu(cpu, &pd->cpumask); /* - * If this is the last thread sibling, remove the CPU core - * interface, If there is still a sibling online, transfer the - * target cpu of that core interface to it. + * If this is the last housekeeping thread sibling, remove the CPU core + * interface. If there is still a housekeeping sibling online, transfer + * the target CPU of that core interface to it. */ target = cpumask_any_and(&pd->cpumask, topology_sibling_cpumask(cpu)); if (target >= nr_cpu_ids) { @@ -750,7 +760,8 @@ static int coretemp_cpu_offline(unsigned int cpu) } /* - * If all cores in this pkg are offline, remove the interface. + * If all housekeeping cores in this pkg are offline, remove the + * interface. */ tdata = get_temp_data(pd, -1); if (cpumask_empty(&pd->cpumask)) { @@ -763,7 +774,7 @@ static int coretemp_cpu_offline(unsigned int cpu) /* * Check whether this core is the target for the package - * interface. We need to assign it to some other cpu. + * interface. We need to assign it to some other housekeeping CPU. */ if (tdata && tdata->cpu == cpu) { target = cpumask_first(&pd->cpumask); diff --git a/drivers/hwmon/corsair-cpro.c b/drivers/hwmon/corsair-cpro.c index bf7775a731fb..17bb080eb9bb 100644 --- a/drivers/hwmon/corsair-cpro.c +++ b/drivers/hwmon/corsair-cpro.c @@ -135,9 +135,9 @@ static int send_usb_cmd(struct ccp_device *ccp, u8 command, u8 byte1, u8 byte2, * the raw event parsing and marked the ccp->wait_input_report * completion as done. */ - spin_lock_bh(&ccp->wait_input_report_lock); + spin_lock_irq(&ccp->wait_input_report_lock); reinit_completion(&ccp->wait_input_report); - spin_unlock_bh(&ccp->wait_input_report_lock); + spin_unlock_irq(&ccp->wait_input_report_lock); ret = hid_hw_output_report(ccp->hdev, ccp->cmd_buffer, OUT_BUFFER_SIZE); if (ret < 0) @@ -156,15 +156,16 @@ static int send_usb_cmd(struct ccp_device *ccp, u8 command, u8 byte1, u8 byte2, static int ccp_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { struct ccp_device *ccp = hid_get_drvdata(hdev); + unsigned long flags; /* only copy buffer when requested */ - spin_lock(&ccp->wait_input_report_lock); + spin_lock_irqsave(&ccp->wait_input_report_lock, flags); if (!completion_done(&ccp->wait_input_report)) { memcpy(ccp->buffer, data, min(IN_BUFFER_SIZE, size)); ccp->buffer_recv_size = size; complete_all(&ccp->wait_input_report); } - spin_unlock(&ccp->wait_input_report_lock); + spin_unlock_irqrestore(&ccp->wait_input_report_lock, flags); return 0; } diff --git a/drivers/hwmon/gigabyte_waterforce.c b/drivers/hwmon/gigabyte_waterforce.c index 4eea05f8b569..f4d0376dd68e 100644 --- a/drivers/hwmon/gigabyte_waterforce.c +++ b/drivers/hwmon/gigabyte_waterforce.c @@ -257,6 +257,9 @@ static int waterforce_raw_event(struct hid_device *hdev, struct hid_report *repo { struct waterforce_data *priv = hid_get_drvdata(hdev); + if (size <= FIRMWARE_VER_START_OFFSET_2) + return 0; + if (data[0] == get_firmware_ver_cmd[0] && data[1] == get_firmware_ver_cmd[1]) { /* Received a firmware version report */ priv->firmware_version = @@ -269,6 +272,8 @@ static int waterforce_raw_event(struct hid_device *hdev, struct hid_report *repo if (data[0] != get_status_cmd[0] || data[1] != get_status_cmd[1]) return 0; + if (size <= WATERFORCE_TEMP_SENSOR) + return 0; priv->temp_input[0] = data[WATERFORCE_TEMP_SENSOR] * 1000; priv->speed_input[0] = get_unaligned_le16(data + WATERFORCE_FAN_SPEED); diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index 3bdc30530847..9c977d2820f9 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -98,9 +98,9 @@ static int temp_from_reg_unsigned(u8 val_h, u8 val_l) static int temp_from_reg_signed(u8 val_h, u8 val_l) { - if (val_h & 0x80) - return (val_h - 0x100) * 1000; - return temp_from_reg_unsigned(val_h, val_l); + s16 val_hl = (val_h << 8) | val_l; + + return val_hl * 1000 / 256; } static int lm95245_read_conversion_rate(struct lm95245_data *data) diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c index 5d04013efb52..c3e68bde709d 100644 --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c @@ -543,7 +543,10 @@ static ssize_t heater_enable_store(struct device *dev, mutex_unlock(&data->i2c_lock); - return ret; + if (ret != SHT3X_CMD_LENGTH) + return ret < 0 ? ret : -EIO; + + return count; } static int update_interval_read(struct device *dev) diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c index 5a76361bb135..83dc3ca67046 100644 --- a/drivers/hwmon/sht4x.c +++ b/drivers/hwmon/sht4x.c @@ -67,7 +67,7 @@ DECLARE_CRC8_TABLE(sht4x_crc8_table); */ struct sht4x_data { struct i2c_client *client; - unsigned long heating_complete; /* in jiffies */ + u64 heating_complete; /* in jiffies */ bool data_pending; u32 heater_power; /* in milli-watts */ u32 heater_time; /* in milli-seconds */ @@ -92,14 +92,14 @@ static int sht4x_read_values(struct sht4x_data *data) u8 crc; u8 cmd[SHT4X_CMD_LEN] = {SHT4X_CMD_MEASURE_HPM}; u8 raw_data[SHT4X_RESPONSE_LENGTH]; - unsigned long curr_jiffies; + u64 curr_jiffies; - curr_jiffies = jiffies; - if (time_before(curr_jiffies, data->heating_complete)) + curr_jiffies = get_jiffies_64(); + if (time_before64(curr_jiffies, data->heating_complete)) msleep(jiffies_to_msecs(data->heating_complete - curr_jiffies)); if (data->data_pending && - time_before(jiffies, data->heating_complete + data->update_interval)) { + time_before64(get_jiffies_64(), data->heating_complete + data->update_interval)) { data->data_pending = false; } else { next_update = data->last_updated + @@ -237,7 +237,9 @@ static ssize_t heater_enable_show(struct device *dev, { struct sht4x_data *data = dev_get_drvdata(dev); - return sysfs_emit(buf, "%u\n", time_before(jiffies, data->heating_complete)); + guard(hwmon_lock)(dev); + + return sysfs_emit(buf, "%u\n", time_before64(get_jiffies_64(), data->heating_complete)); } static ssize_t heater_enable_store(struct device *dev, @@ -279,14 +281,16 @@ static ssize_t heater_enable_store(struct device *dev, guard(hwmon_lock)(dev); - if (time_before(jiffies, data->heating_complete)) + if (time_before64(get_jiffies_64(), data->heating_complete)) return -EBUSY; ret = i2c_master_send(data->client, &cmd, SHT4X_CMD_LEN); if (ret < 0) return ret; + if (ret != SHT4X_CMD_LEN) + return -EIO; - data->heating_complete = jiffies + msecs_to_jiffies(heating_time_bound); + data->heating_complete = get_jiffies_64() + msecs_to_jiffies(heating_time_bound); data->data_pending = true; return count; } @@ -410,7 +414,7 @@ static int sht4x_probe(struct i2c_client *client) data->client = client; data->heater_power = 200; data->heater_time = 1000; - data->heating_complete = jiffies; + data->heating_complete = get_jiffies_64(); crc8_populate_msb(sht4x_crc8_table, SHT4X_CRC8_POLYNOMIAL); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index c4bab532eed1..593ddec3c40e 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -515,6 +515,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) if (dev->rx_outstanding >= dev->rx_fifo_depth) break; + /* + * For block reads, queue only the length + * byte until i2c_dw_recv_len() runs. + */ + if ((flags & I2C_M_RECV_LEN) && + buf_len < msgs[dev->msg_write_idx].len) + break; + regmap_write(dev->map, DW_IC_DATA_CMD, cmd | 0x100); rx_limit--; diff --git a/drivers/i2c/busses/i2c-mt7621.c b/drivers/i2c/busses/i2c-mt7621.c index 0a288c998419..9ea5e3f9a763 100644 --- a/drivers/i2c/busses/i2c-mt7621.c +++ b/drivers/i2c/busses/i2c-mt7621.c @@ -144,7 +144,6 @@ static int mtk_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, u16 addr; int i, j, ret, len, page_len; u32 cmd; - u32 data[2]; i2c = i2c_get_adapdata(adap); @@ -186,6 +185,8 @@ static int mtk_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, /* transfer data */ for (len = pmsg->len, j = 0; len > 0; len -= 8, j += 8) { + u32 data[2] = { }; + page_len = (len >= 8) ? 8 : len; if (pmsg->flags & I2C_M_RD) { @@ -194,7 +195,8 @@ static int mtk_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } else { memcpy(data, &pmsg->buf[j], page_len); iowrite32(data[0], i2c->base + REG_SM0D0_REG); - iowrite32(data[1], i2c->base + REG_SM0D1_REG); + if (page_len > 4) + iowrite32(data[1], i2c->base + REG_SM0D1_REG); cmd = SM0CTL1_WRITE; } @@ -204,7 +206,8 @@ static int mtk_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, if (pmsg->flags & I2C_M_RD) { data[0] = ioread32(i2c->base + REG_SM0D0_REG); - data[1] = ioread32(i2c->base + REG_SM0D1_REG); + if (page_len > 4) + data[1] = ioread32(i2c->base + REG_SM0D1_REG); memcpy(&pmsg->buf[j], data, page_len); } else { if (!(pmsg->flags & I2C_M_IGNORE_NAK)) { diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 98ebbc973f21..8805fc454a4e 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -545,6 +545,7 @@ struct i2c_client *i2c_acpi_new_device_by_fwnode(struct fwnode_handle *fwnode, { struct i2c_acpi_lookup lookup; struct i2c_adapter *adapter; + struct i2c_client *client; struct acpi_device *adev; LIST_HEAD(resource_list); int ret; @@ -572,7 +573,10 @@ struct i2c_client *i2c_acpi_new_device_by_fwnode(struct fwnode_handle *fwnode, if (!adapter) return ERR_PTR(-EPROBE_DEFER); - return i2c_new_client_device(adapter, info); + client = i2c_new_client_device(adapter, info); + put_device(&adapter->dev); + + return client; } EXPORT_SYMBOL_GPL(i2c_acpi_new_device_by_fwnode); diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 038f7b2ec8c4..0dbcfb1a5204 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -1955,12 +1955,11 @@ struct i3c_dma *i3c_master_dma_map_single(struct device *dev, void *buf, if (force_bounce) { dma_xfer->map_len = ALIGN(len, cache_line_size()); - if (dir == DMA_FROM_DEVICE) - bounce = kzalloc(dma_xfer->map_len, GFP_KERNEL); - else - bounce = kmemdup(buf, dma_xfer->map_len, GFP_KERNEL); + bounce = kzalloc(dma_xfer->map_len, GFP_KERNEL); if (!bounce) return NULL; + if (dir != DMA_FROM_DEVICE) + memcpy(bounce, buf, len); dma_buf = bounce; } diff --git a/drivers/i3c/master/adi-i3c-master.c b/drivers/i3c/master/adi-i3c-master.c index 178029769bab..d6278d03012d 100644 --- a/drivers/i3c/master/adi-i3c-master.c +++ b/drivers/i3c/master/adi-i3c-master.c @@ -115,6 +115,7 @@ struct adi_i3c_master { spinlock_t lock; /* Protect transfer */ } xferqueue; void __iomem *regs; + int irq; struct clk *clk; unsigned long i3c_scl_lim; struct { @@ -957,6 +958,7 @@ static int adi_i3c_master_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; + master->irq = irq; version = readl(master->regs + ADI_AXI_REG_VERSION); if (ADI_AXI_PCORE_VER_MAJOR(version) != 1) @@ -1001,6 +1003,8 @@ static void adi_i3c_master_remove(struct platform_device *pdev) writel(0x00, master->regs + REG_IRQ_MASK); writel(0x01, master->regs + REG_ENABLE); + devm_free_irq(&pdev->dev, master->irq, master); + i3c_master_unregister(&master->base); } diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c index 37717e530a25..15a34429197b 100644 --- a/drivers/i3c/master/mipi-i3c-hci/dma.c +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c @@ -376,7 +376,7 @@ static void hci_dma_unmap_xfer(struct i3c_hci *hci, static struct i3c_dma *hci_dma_map_xfer(struct device *dev, struct hci_xfer *xfer) { enum dma_data_direction dir = xfer->rnw ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - bool need_bounce = device_iommu_mapped(dev) && xfer->rnw && (xfer->data_len & 3); + bool need_bounce = xfer->rnw && (xfer->data_len & 3); return i3c_master_dma_map_single(dev, xfer->data, xfer->data_len, need_bounce, dir); } diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c index 5127e58eebc7..f0cf3783bcd9 100644 --- a/drivers/iio/accel/adis16201.c +++ b/drivers/iio/accel/adis16201.c @@ -202,19 +202,19 @@ static int adis16201_write_raw(struct iio_dev *indio_dev, } static const struct iio_chan_spec adis16201_channels[] = { - ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT_REG, ADIS16201_SCAN_SUPPLY, 0, - 12), - ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT_REG, ADIS16201_SCAN_TEMP, 0, 12), ADIS_ACCEL_CHAN(X, ADIS16201_XACCL_OUT_REG, ADIS16201_SCAN_ACC_X, BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), ADIS_ACCEL_CHAN(Y, ADIS16201_YACCL_OUT_REG, ADIS16201_SCAN_ACC_Y, BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC_REG, ADIS16201_SCAN_AUX_ADC, 0, 12), ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT_REG, ADIS16201_SCAN_INCLI_X, BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 12), ADIS_INCLI_CHAN(Y, ADIS16201_YINCL_OUT_REG, ADIS16201_SCAN_INCLI_Y, BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 12), - IIO_CHAN_SOFT_TIMESTAMP(7) + ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT_REG, ADIS16201_SCAN_SUPPLY, 0, + 12), + ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC_REG, ADIS16201_SCAN_AUX_ADC, 0, 12), + ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT_REG, ADIS16201_SCAN_TEMP, 0, 12), + IIO_CHAN_SOFT_TIMESTAMP(7), }; static const struct iio_info adis16201_info = { diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c index dedb0885c277..b2287f4f4442 100644 --- a/drivers/iio/accel/adxl313_spi.c +++ b/drivers/iio/accel/adxl313_spi.c @@ -79,6 +79,8 @@ static int adxl313_spi_probe(struct spi_device *spi) return ret; chip_data = spi_get_device_match_data(spi); + if (!chip_data) + return -ENODATA; regmap = devm_regmap_init_spi(spi, &adxl31x_spi_regmap_config[chip_data->type]); diff --git a/drivers/iio/accel/adxl380_spi.c b/drivers/iio/accel/adxl380_spi.c index 6edd0d211ffa..b51edc021b26 100644 --- a/drivers/iio/accel/adxl380_spi.c +++ b/drivers/iio/accel/adxl380_spi.c @@ -26,6 +26,8 @@ static int adxl380_spi_probe(struct spi_device *spi) struct regmap *regmap; chip_data = spi_get_device_match_data(spi); + if (!chip_data) + return -ENODATA; regmap = devm_regmap_init_spi(spi, &adxl380_spi_regmap_config); if (IS_ERR(regmap)) diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 297853cd39e5..a8652bdd011a 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1548,6 +1548,7 @@ static void kxcjk1013_remove(struct i2c_client *client) iio_device_unregister(indio_dev); + pm_runtime_dont_use_autosuspend(&client->dev); pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index 02195deada49..28342a757c6c 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -503,6 +503,7 @@ static void mma9551_remove(struct i2c_client *client) iio_device_unregister(indio_dev); + pm_runtime_dont_use_autosuspend(&client->dev); pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index f85384a7908f..65533bc275ec 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1140,6 +1140,7 @@ static void mma9553_remove(struct i2c_client *client) iio_device_unregister(indio_dev); + pm_runtime_dont_use_autosuspend(&client->dev); pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c index f28e4ca37707..bec3f656406b 100644 --- a/drivers/iio/adc/ad7606_spi.c +++ b/drivers/iio/adc/ad7606_spi.c @@ -456,7 +456,11 @@ static const struct ad7606_bus_info ad7616_bus_info = { static int ad7606_spi_probe(struct spi_device *spi) { - const struct ad7606_bus_info *bus_info = spi_get_device_match_data(spi); + const struct ad7606_bus_info *bus_info; + + bus_info = spi_get_device_match_data(spi); + if (!bus_info) + return -ENODATA; return ad7606_probe(&spi->dev, spi->irq, NULL, bus_info->chip_info, bus_info->bops); diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index aa4ba3f5a506..8c16c5938601 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -2487,6 +2487,7 @@ static void at91_adc_remove(struct platform_device *pdev) pm_runtime_disable(st->dev); pm_runtime_set_suspended(st->dev); + pm_runtime_dont_use_autosuspend(st->dev); clk_disable_unprepare(st->per_clk); regulator_disable(st->vref); diff --git a/drivers/iio/adc/max11205.c b/drivers/iio/adc/max11205.c index 6c803df220b6..e8404973b01a 100644 --- a/drivers/iio/adc/max11205.c +++ b/drivers/iio/adc/max11205.c @@ -117,6 +117,8 @@ static int max11205_probe(struct spi_device *spi) ad_sd_init(&st->sd, indio_dev, spi, &max11205_sigma_delta_info); st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -ENODATA; indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index a6f21791c685..5bdfe5e26718 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -722,6 +722,8 @@ static int mcp3911_probe(struct spi_device *spi) adc = iio_priv(indio_dev); adc->spi = spi; adc->chip = spi_get_device_match_data(spi); + if (!adc->chip) + return -ENODATA; ret = devm_regulator_get_enable_read_voltage(dev, "vref"); if (ret < 0 && ret != -ENODEV) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index dae35ab929b6..ab4433210ad0 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -2743,7 +2743,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = { .set_ovs = stm32h7_adc_set_ovs, }; -static const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 }; +static const unsigned int stm32_adc_min_ts_mp1[] = { 100, 0, 0, 4300, 9800 }; static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp1) == STM32_ADC_INT_CH_NB); static const struct stm32_adc_cfg stm32mp1_adc_cfg = { @@ -2765,7 +2765,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { .set_ovs = stm32h7_adc_set_ovs, }; -static const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 }; +static const unsigned int stm32_adc_min_ts_mp13[] = { 1000, 1000, 1000, 4300, 9800 }; static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp13) == STM32_ADC_INT_CH_NB); static const struct stm32_adc_cfg stm32mp13_adc_cfg = { diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c index 4ae65793ad9b..19c30d60c504 100644 --- a/drivers/iio/adc/ti-adc128s052.c +++ b/drivers/iio/adc/ti-adc128s052.c @@ -196,12 +196,14 @@ static int adc128_probe(struct spi_device *spi) adc = iio_priv(indio_dev); adc->spi = spi; - indio_dev->name = spi_get_device_id(spi)->name; + config = spi_get_device_match_data(spi); + if (!config) + return -ENODATA; + + indio_dev->name = spi->modalias; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &adc128_info; - config = spi_get_device_match_data(spi); - indio_dev->channels = config->channels; indio_dev->num_channels = config->num_channels; diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c index aa8946063c7d..5c08bed48018 100644 --- a/drivers/iio/adc/ti-ads1100.c +++ b/drivers/iio/adc/ti-ads1100.c @@ -15,10 +15,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -43,6 +45,9 @@ static const int ads1100_data_rate[] = { 128, 32, 16, 8 }; static const int ads1100_data_rate_bits[] = { 12, 14, 15, 16 }; +/* Timeout based on the minimum sample rate of 8 SPS (7500ms) */ +#define ADS1100_MAX_DRDY_TIMEOUT_US (7500 * USEC_PER_MSEC) + struct ads1100_data { struct i2c_client *client; struct regulator *reg_vdd; @@ -123,10 +128,86 @@ static int ads1100_get_adc_result(struct ads1100_data *data, int chan, int *val) return 0; } +static int ads1100_conversion_busy(struct ads1100_data *data) +{ + u8 buffer[3]; + int ret; + + ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer)); + if (ret < 0) { + dev_err(&data->client->dev, "I2C read fail: %d\n", ret); + return ret; + } + + return FIELD_GET(ADS1100_CFG_ST_BSY, buffer[2]); +} + +static int ads1100_wait_single_conversion(struct ads1100_data *data) +{ + int data_rate_index = FIELD_GET(ADS1100_DR_MASK, data->config); + int data_rate_Hz = ads1100_data_rate[data_rate_index]; + unsigned long poll_us = DIV_ROUND_CLOSEST(USEC_PER_SEC, data_rate_Hz) / 4; + int busy; + int ret; + + ret = readx_poll_timeout(ads1100_conversion_busy, data, + busy, busy <= 0, + poll_us, ADS1100_MAX_DRDY_TIMEOUT_US); + if (busy < 0) + return busy; + + return ret; +} + +static int ads1100_start_single_conversion(struct ads1100_data *data) +{ + u8 config = data->config | ADS1100_CFG_SC; + int ret; + + ret = i2c_master_send(data->client, &config, sizeof(config)); + if (ret < 0) { + dev_err(&data->client->dev, "I2C write fail: %d\n", ret); + return ret; + } + /* Need to wait because of change from continuous to single mode */ + ret = ads1100_wait_single_conversion(data); + if (ret) + return ret; + + config |= ADS1100_CFG_ST_BSY; + + ret = i2c_master_send(data->client, &config, sizeof(config)); + if (ret < 0) { + dev_err(&data->client->dev, "I2C write fail: %d\n", ret); + return ret; + } + + /* No need to cache it, it's status bit */ + data->config = config & ~ADS1100_CFG_ST_BSY; + + return 0; +} + +static int ads1100_poll_data_ready(struct ads1100_data *data) +{ + int ret; + + ret = ads1100_start_single_conversion(data); + if (ret) + return ret; + + ret = ads1100_wait_single_conversion(data); + if (ret) + return ret; + + return ads1100_set_config_bits(data, ADS1100_CFG_SC, ADS1100_CONTINUOUS); +} + static int ads1100_set_scale(struct ads1100_data *data, int val, int val2) { int microvolts; int gain; + int ret; /* With Vdd between 2.7 and 5V, the scale is always below 1 */ if (val) @@ -135,6 +216,11 @@ static int ads1100_set_scale(struct ads1100_data *data, int val, int val2) if (!val2) return -EINVAL; + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(&data->client->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + microvolts = regulator_get_voltage(data->reg_vdd); /* * val2 is in 'micro' units, n = val2 / 1000000 @@ -149,22 +235,35 @@ static int ads1100_set_scale(struct ads1100_data *data, int val, int val2) ads1100_set_config_bits(data, ADS1100_PGA_MASK, ffs(gain) - 1); - return 0; + return ads1100_poll_data_ready(data); } static int ads1100_set_data_rate(struct ads1100_data *data, int chan, int rate) { unsigned int i; unsigned int size; + int ret; size = data->supports_data_rate ? ARRAY_SIZE(ads1100_data_rate) : 1; for (i = 0; i < size; i++) { if (ads1100_data_rate[i] == rate) - return ads1100_set_config_bits(data, ADS1100_DR_MASK, - FIELD_PREP(ADS1100_DR_MASK, i)); + break; } - return -EINVAL; + if (i == size) + return -EINVAL; + + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(&data->client->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + ret = ads1100_set_config_bits(data, ADS1100_DR_MASK, + FIELD_PREP(ADS1100_DR_MASK, i)); + if (ret) + return ret; + + return ads1100_poll_data_ready(data); } static int ads1100_get_vdd_millivolts(struct ads1100_data *data) diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index d0e5f35462b1..ce188c5a9ad1 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -819,6 +819,9 @@ static int ad5755_probe(struct spi_device *spi) spi_set_drvdata(spi, indio_dev); st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -ENODATA; + st->spi = spi; st->pwr_down = 0xf; diff --git a/drivers/iio/frequency/adf4377.c b/drivers/iio/frequency/adf4377.c index 48aa4b015a14..0548f626bb45 100644 --- a/drivers/iio/frequency/adf4377.c +++ b/drivers/iio/frequency/adf4377.c @@ -964,6 +964,9 @@ static int adf4377_probe(struct spi_device *spi) st->regmap = regmap; st->spi = spi; st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -ENODATA; + mutex_init(&st->lock); ret = adf4377_properties_parse(st); diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 7e85c1b8dc16..9f8721c196a9 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -1150,6 +1150,9 @@ static int adis16400_probe(struct spi_device *spi) /* setup the industrialio driver allocated elements */ st->variant = spi_get_device_match_data(spi); + if (!st->variant) + return -ENODATA; + indio_dev->name = spi_get_device_id(spi)->name; indio_dev->channels = st->variant->channels; indio_dev->num_channels = st->variant->num_channels; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index c8b48a5c5ed0..a44e4ea746a6 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -177,6 +177,7 @@ struct inv_icm42600_state { struct { s64 gyro; s64 accel; + bool accel_force_odr; } timestamp; struct inv_icm42600_apex apex; struct inv_icm42600_fifo fifo; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 96a6213770d4..d858acad3bfb 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -1225,14 +1225,16 @@ int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev) if (size <= 0) return size; - /* skip packet if no accel data or data is invalid */ - if (accel == NULL || !inv_icm42600_fifo_is_data_valid(accel)) - continue; - /* update odr */ - if (odr & INV_ICM42600_SENSOR_ACCEL) + if (odr & INV_ICM42600_SENSOR_ACCEL) { inv_sensors_timestamp_apply_odr(ts, st->fifo.period, st->fifo.nb.total, no); + st->timestamp.accel_force_odr = false; + } + + /* skip packet if no accel data or data is invalid */ + if (accel == NULL || !inv_icm42600_fifo_is_data_valid(accel)) + continue; memcpy(&buffer.accel, accel, sizeof(buffer.accel)); /* convert 8 bits FIFO temperature in high resolution format */ @@ -1241,5 +1243,10 @@ int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev) iio_push_to_buffers_with_timestamp(indio_dev, &buffer, ts_val); } + if (st->timestamp.accel_force_odr) { + inv_sensors_timestamp_apply_odr(ts, 0, 0, 0); + st->timestamp.accel_force_odr = false; + } + return 0; } diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c index 5c3840acf085..2c3e41a24b33 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c @@ -396,6 +396,8 @@ static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev) mutex_lock(&st->lock); inv_sensors_timestamp_apply_odr(ts, 0, 0, 0); + if (sensor == INV_ICM42600_SENSOR_ACCEL) + st->timestamp.accel_force_odr = false; ret = inv_icm42600_buffer_set_fifo_en(st, st->fifo.en & ~sensor); if (ret) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index 76eb22488e5f..e37b395dbd90 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -324,6 +324,15 @@ int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st, break; } + /* + * If we change mode from low-power to low-noise because of odr, + * we need to force odr change. + */ + if (oldconf->mode == INV_ICM42600_SENSOR_MODE_LOW_POWER && + conf->mode == INV_ICM42600_SENSOR_MODE_LOW_NOISE && + conf->odr != oldconf->odr) + st->timestamp.accel_force_odr = true; + /* set ACCEL_CONFIG0 register (accel fullscale & odr) */ if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) { val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->fs) | diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index a18dcac93929..194838d88284 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -806,15 +806,15 @@ int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev) if (size <= 0) return size; - /* skip packet if no gyro data or data is invalid */ - if (gyro == NULL || !inv_icm42600_fifo_is_data_valid(gyro)) - continue; - /* update odr */ if (odr & INV_ICM42600_SENSOR_GYRO) inv_sensors_timestamp_apply_odr(ts, st->fifo.period, st->fifo.nb.total, no); + /* skip packet if no gyro data or data is invalid */ + if (gyro == NULL || !inv_icm42600_fifo_is_data_valid(gyro)) + continue; + memcpy(&buffer.gyro, gyro, sizeof(buffer.gyro)); /* convert 8 bits FIFO temperature in high resolution format */ buffer.temp = temp ? (*temp * 64) : 0; diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c index 5ce01037ae55..fc07518faec7 100644 --- a/drivers/iio/light/apds9306.c +++ b/drivers/iio/light/apds9306.c @@ -61,7 +61,7 @@ #define APDS9306_NUM_REPEAT_RATES 7 #define APDS9306_INT_SRC_CLEAR 0 #define APDS9306_INT_SRC_ALS 1 -#define APDS9306_SAMP_FREQ_10HZ 0 +#define APDS9306_SAMP_FREQ_10HZ 2 /** * struct part_id_gts_multiplier - Part no. and corresponding gts multiplier diff --git a/drivers/iio/potentiometer/x9250.c b/drivers/iio/potentiometer/x9250.c index 735348492699..1c9e22459058 100644 --- a/drivers/iio/potentiometer/x9250.c +++ b/drivers/iio/potentiometer/x9250.c @@ -155,10 +155,15 @@ static const char *const x9250_regulator_names[] = { static int x9250_probe(struct spi_device *spi) { + const struct x9250_cfg *cfg; struct iio_dev *indio_dev; struct x9250 *x9250; int ret; + cfg = spi_get_device_match_data(spi); + if (!cfg) + return -ENODATA; + ret = devm_regulator_bulk_get_enable(&spi->dev, ARRAY_SIZE(x9250_regulator_names), x9250_regulator_names); if (ret) @@ -176,7 +181,7 @@ static int x9250_probe(struct spi_device *spi) x9250 = iio_priv(indio_dev); x9250->spi = spi; - x9250->cfg = spi_get_device_match_data(spi); + x9250->cfg = cfg; x9250->wp_gpio = devm_gpiod_get_optional(&spi->dev, "wp", GPIOD_OUT_LOW); if (IS_ERR(x9250->wp_gpio)) return dev_err_probe(&spi->dev, PTR_ERR(x9250->wp_gpio), diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c index 3b90384f17d7..e303923df675 100644 --- a/drivers/iio/pressure/bmp280-spi.c +++ b/drivers/iio/pressure/bmp280-spi.c @@ -83,6 +83,8 @@ static int bmp280_spi_probe(struct spi_device *spi) struct regmap *regmap; chip_info = spi_get_device_match_data(spi); + if (!chip_info) + return -ENODATA; if (chip_info->spi_read_extra_byte) bmp_regmap_bus = &bmp380_regmap_bus; diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 57c70384d210..648b31f37aa8 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -5576,7 +5576,7 @@ static int init_rcverr(struct hfi1_devdata *dd) static void free_rcverr(struct hfi1_devdata *dd) { if (dd->rcverr_timer.function) - timer_delete_sync(&dd->rcverr_timer); + timer_shutdown_sync(&dd->rcverr_timer); } static void handle_rxe_err(struct hfi1_devdata *dd, u32 unused, u64 reg) @@ -12308,7 +12308,7 @@ static void free_cntrs(struct hfi1_devdata *dd) int i; if (dd->synth_stats_timer.function) - timer_delete_sync(&dd->synth_stats_timer); + timer_shutdown_sync(&dd->synth_stats_timer); cancel_work_sync(&dd->update_cntr_work); ppd = (struct hfi1_pportdata *)(dd + 1); for (i = 0; i < dd->num_pports; i++, ppd++) { diff --git a/drivers/infiniband/hw/hfi1/fault.c b/drivers/infiniband/hw/hfi1/fault.c index a45cbffd52c7..b6acc0edb116 100644 --- a/drivers/infiniband/hw/hfi1/fault.c +++ b/drivers/infiniband/hw/hfi1/fault.c @@ -216,7 +216,6 @@ int hfi1_fault_init_debugfs(struct hfi1_ibdev *ibd) ibd->fault->attr.interval = 1; ibd->fault->attr.require_end = ULONG_MAX; ibd->fault->attr.stacktrace_depth = 32; - ibd->fault->attr.dname = NULL; ibd->fault->attr.verbose = 0; ibd->fault->enable = false; ibd->fault->opcode = false; diff --git a/drivers/input/input.c b/drivers/input/input.c index a500e1e276c2..9907dd9ec880 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -391,7 +391,7 @@ void input_handle_event(struct input_dev *dev, void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { - if (is_event_supported(type, dev->evbit, EV_MAX)) { + if (type == EV_SYN || is_event_supported(type, dev->evbit, EV_MAX)) { guard(spinlock_irqsave)(&dev->event_lock); input_handle_event(dev, type, code, value); } @@ -415,7 +415,7 @@ void input_inject_event(struct input_handle *handle, struct input_dev *dev = handle->dev; struct input_handle *grab; - if (is_event_supported(type, dev->evbit, EV_MAX)) { + if (type == EV_SYN || is_event_supported(type, dev->evbit, EV_MAX)) { guard(spinlock_irqsave)(&dev->event_lock); guard(rcu)(); diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 126f99cd0b29..716ab1c608f0 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -442,6 +442,7 @@ static const struct xpad_device { { 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 }, { 0x3537, 0x100f, "GameSir Nova 2 Lite", 0, XTYPE_XBOX360 }, { 0x3537, 0x1010, "GameSir G7 SE", 0, XTYPE_XBOXONE }, + { 0x3537, 0x1040, "GameSir Nova Lite", 0, XTYPE_XBOX360 }, { 0x3651, 0x1000, "CRKD SG", 0, XTYPE_XBOX360 }, { 0x366c, 0x0005, "ByoWave Proteus Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE, FLAG_DELAY_INIT }, { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX }, diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index e50a6fea9a60..4247772892ca 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -135,9 +135,6 @@ static void matrix_keypad_scan(struct work_struct *work) memset(new_state, 0, sizeof(new_state)); - for (row = 0; row < keypad->num_row_gpios; row++) - gpiod_direction_input(keypad->row_gpios[row]); - /* assert each column and read the row status out */ for (col = 0; col < keypad->num_col_gpios; col++) { diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index c07c3a01b978..16c26d75f46f 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -409,7 +409,13 @@ static void iommu_set_device_table(struct amd_iommu *iommu) BUG_ON(iommu->mmio_base == NULL); - if (is_kdump_kernel()) + /* + * A kdump kernel that reuses the previous kernel's device table must + * leave the base register alone. It already points at that table, and + * with SNP enabled the register is locked. If reuse failed, program + * the freshly allocated table like a normal boot. + */ + if (iommu->pci_seg->old_dev_tbl_cpy) return; entry = iommu_virt_to_phys(dev_table); @@ -642,8 +648,19 @@ static int __init find_last_devid_acpi(struct acpi_table_header *table, u16 pci_ /* Allocate per PCI segment device table */ static inline int __init alloc_dev_table(struct amd_iommu_pci_seg *pci_seg) { - pci_seg->dev_table = iommu_alloc_pages_sz(GFP_KERNEL | GFP_DMA32, - pci_seg->dev_table_size); + gfp_t gfp = GFP_KERNEL; + + /* + * Keep normal kernel device tables below 4G because a later kdump + * kernel only trusts and reuses old tables below that limit. A kdump + * kernel's new table is either discarded when reuse succeeds or + * programmed after the IOMMU is disabled, so the table does not + * need DMA32 memory (which the crashkernel may not have). + */ + if (!is_kdump_kernel()) + gfp |= GFP_DMA32; + + pci_seg->dev_table = iommu_alloc_pages_sz(gfp, pci_seg->dev_table_size); if (!pci_seg->dev_table) return -ENOMEM; diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 9da773ba550b..aa9ebf2bc96e 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -1453,6 +1453,11 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, sg_dma_len(s) = s_length; s->offset -= s_iova_off; s_length = iova_align(iovad, s_length + s_iova_off); + if (overflows_type(s_length, s->length)) { + ret = -EOVERFLOW; + + goto out_restore_sg; + } s->length = s_length; /* @@ -1469,7 +1474,20 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, * time through here (i.e. before it has a meaningful value). */ if (pad_len && pad_len < s_length - 1) { - prev->length += pad_len; + unsigned int new_prev_len; + + /* + * For large mappings spanning multiple GBs we + * may not be able to fit all needed padding into + * sg->length. + */ + if (check_add_overflow(prev->length, pad_len, &new_prev_len)) { + ret = -EOVERFLOW; + + goto out_restore_sg; + } + + prev->length = new_prev_len; iova_len += pad_len; } diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h index e696e019e969..33c9e06df63f 100644 --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -1183,12 +1183,20 @@ static inline void qi_desc_dev_iotlb_pasid(u16 sid, u16 pfsid, u32 pasid, unsigned int size_order, struct qi_desc *desc) { - unsigned long mask = 1UL << (VTD_PAGE_SHIFT + size_order - 1); - desc->qw0 = QI_DEV_EIOTLB_PASID(pasid) | QI_DEV_EIOTLB_SID(sid) | QI_DEV_EIOTLB_QDEP(qdep) | QI_DEIOTLB_TYPE | QI_DEV_IOTLB_PFSID(pfsid); + /* + * The widest range the descriptor can express is a full flush, encoded + * by making bit 63 the least significant zero bit of ADDR, that is + * @size_order == 64 - VTD_PAGE_SHIFT. Bound @size_order there so that + * a caller passing something larger cannot produce an out-of-range + * shift below. + */ + if (size_order > 64 - VTD_PAGE_SHIFT) + size_order = 64 - VTD_PAGE_SHIFT; + /* * If S bit is 0, we only flush a single page. If S bit is set, * The least significant zero bit indicates the invalidation address @@ -1198,7 +1206,8 @@ static inline void qi_desc_dev_iotlb_pasid(u16 sid, u16 pfsid, u32 pasid, * Max Invs Pending (MIP) is set to 0 for now until we have DIT in * ECAP. */ - if (!IS_ALIGNED(addr, VTD_PAGE_SIZE << size_order)) + if (size_order < 64 - VTD_PAGE_SHIFT && + !IS_ALIGNED(addr, BIT_ULL(VTD_PAGE_SHIFT + size_order))) pr_warn_ratelimited("Invalidate non-aligned address %llx, order %d\n", addr, size_order); @@ -1214,7 +1223,7 @@ static inline void qi_desc_dev_iotlb_pasid(u16 sid, u16 pfsid, u32 pasid, desc->qw1 |= GENMASK_ULL(size_order + VTD_PAGE_SHIFT - 1, VTD_PAGE_SHIFT); /* Clear size_order bit to indicate size */ - desc->qw1 &= ~mask; + desc->qw1 &= ~BIT_ULL(VTD_PAGE_SHIFT + size_order - 1); /* Set the S bit to indicate flushing more than 1 page */ desc->qw1 |= QI_DEV_EIOTLB_SIZE; } diff --git a/drivers/iommu/iommufd/io_pagetable.c b/drivers/iommu/iommufd/io_pagetable.c index a4d7a9d43560..77891d4d65fb 100644 --- a/drivers/iommu/iommufd/io_pagetable.c +++ b/drivers/iommu/iommufd/io_pagetable.c @@ -568,6 +568,9 @@ int iommufd_check_iova_range(struct io_pagetable *iopt, size_t iommu_pgsize = iopt->iova_alignment; u64 last_iova; + if (!bitmap->length) + return -EINVAL; + if (check_add_overflow(bitmap->iova, bitmap->length - 1, &last_iova)) return -EOVERFLOW; diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c index 1dcc52760eca..4a7935e75e4d 100644 --- a/drivers/irqchip/irq-atmel-aic.c +++ b/drivers/irqchip/irq-atmel-aic.c @@ -123,7 +123,7 @@ static void aic_pm_shutdown(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - guard(raw_spinlock)(&gc->lock); + guard(raw_spinlock_irqsave)(&gc->lock); irq_reg_writel(gc, 0xffffffff, AT91_AIC_IDCR); irq_reg_writel(gc, 0xffffffff, AT91_AIC_ICCR); } diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index 1f14b401f71d..07a317ed06ef 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -217,7 +217,7 @@ static void aic5_pm_shutdown(struct irq_data *d) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); int i; - guard(raw_spinlock)(&bgc->lock); + guard(raw_spinlock_irqsave)(&bgc->lock); for (i = 0; i < dgc->irqs_per_chip; i++) { irq_reg_writel(bgc, i + gc->irq_base, AT91_AIC5_SSR); irq_reg_writel(bgc, 1, AT91_AIC5_IDCR); diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 8607ed0d9884..4443bf46e390 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -3488,7 +3488,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, * Also honor the ITS's own EID limit. */ id_bits = FIELD_GET(GITS_TYPER_IDBITS, its->typer) + 1; - nvecs = min_t(unsigned int, nvecs, BIT(id_bits)); + nvecs = min_t(u64, nvecs, BIT_ULL(id_bits)); nr_ites = max(2, nvecs); sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1); sz = max(sz, ITS_ITT_ALIGN); diff --git a/drivers/irqchip/irq-imx-intmux.c b/drivers/irqchip/irq-imx-intmux.c index 5f9b204d350b..18e214e5b1b5 100644 --- a/drivers/irqchip/irq-imx-intmux.c +++ b/drivers/irqchip/irq-imx-intmux.c @@ -289,12 +289,16 @@ static int imx_intmux_probe(struct platform_device *pdev) static void imx_intmux_remove(struct platform_device *pdev) { struct intmux_data *data = platform_get_drvdata(pdev); - int i; + int i, ret; + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) + dev_warn(&pdev->dev, "failed to resume device: %d\n", ret); for (i = 0; i < data->channum; i++) { /* disable all interrupt sources of this channel */ - writel_relaxed(0, data->regs + CHANIER(i)); - + if (ret >= 0) + writel_relaxed(0, data->regs + CHANIER(i)); irq_set_chained_handler_and_data(data->irqchip_data[i].irq, NULL, NULL); @@ -302,6 +306,11 @@ static void imx_intmux_remove(struct platform_device *pdev) } pm_runtime_disable(&pdev->dev); + if (ret >= 0) { + pm_runtime_put_noidle(&pdev->dev); + clk_disable_unprepare(data->ipg_clk); + pm_runtime_set_suspended(&pdev->dev); + } } #ifdef CONFIG_PM diff --git a/drivers/irqchip/irq-mchp-eic.c b/drivers/irqchip/irq-mchp-eic.c index 31093a8ab67c..82cb0513bbb8 100644 --- a/drivers/irqchip/irq-mchp-eic.c +++ b/drivers/irqchip/irq-mchp-eic.c @@ -233,7 +233,7 @@ static int mchp_eic_probe(struct platform_device *pdev, struct device_node *pare ret = clk_prepare_enable(eic->clk); if (ret) - goto unmap; + goto clk_put; for (i = 0; i < MCHP_EIC_NIRQ; i++) { struct of_phandle_args irq; @@ -270,6 +270,8 @@ static int mchp_eic_probe(struct platform_device *pdev, struct device_node *pare clk_unprepare: clk_disable_unprepare(eic->clk); +clk_put: + clk_put(eic->clk); unmap: iounmap(eic->base); free: diff --git a/drivers/irqchip/irq-msi-lib.c b/drivers/irqchip/irq-msi-lib.c index d5eefc3d7215..8b8a64f63a71 100644 --- a/drivers/irqchip/irq-msi-lib.c +++ b/drivers/irqchip/irq-msi-lib.c @@ -72,6 +72,7 @@ bool msi_lib_init_dev_msi_info(struct device *dev, struct irq_domain *domain, info->flags = MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS; fallthrough; case DOMAIN_BUS_WIRED_TO_MSI: + info->flags |= MSI_FLAG_FREE_MSI_DESCS; /* Remove PCI specific flags */ required_flags &= ~MSI_FLAG_PCI_MSI_MASK_PARENT; break; diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c index 643c8e459611..52673ff9edf4 100644 --- a/drivers/irqchip/irq-riscv-imsic-platform.c +++ b/drivers/irqchip/irq-riscv-imsic-platform.c @@ -61,7 +61,7 @@ static int imsic_irq_retrigger(struct irq_data *d) local = per_cpu_ptr(imsic->global.local, vec->cpu); writel_relaxed(vec->local_id, local->msi_va); - return 0; + return 1; } static void imsic_irq_ack(struct irq_data *d) diff --git a/drivers/leds/flash/leds-ktd2692.c b/drivers/leds/flash/leds-ktd2692.c index 0f16eefcfe4c..04e2efdac3e6 100644 --- a/drivers/leds/flash/leds-ktd2692.c +++ b/drivers/leds/flash/leds-ktd2692.c @@ -69,6 +69,8 @@ const struct expresswire_timing ktd2692_timing = { }; struct ktd2692_context { + struct device *dev; + /* Common ExpressWire properties (ctrl GPIO and timing) */ struct expresswire_common_props props; @@ -196,13 +198,12 @@ static void ktd2692_setup(struct ktd2692_context *led) static void regulator_disable_action(void *_data) { - struct device *dev = _data; - struct ktd2692_context *led = dev_get_drvdata(dev); + struct ktd2692_context *led = _data; int ret; ret = regulator_disable(led->regulator); if (ret) - dev_err(dev, "Failed to disable supply: %d\n", ret); + dev_err(led->dev, "Failed to disable supply: %d\n", ret); } static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev, @@ -233,7 +234,7 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev, dev_err(dev, "Failed to enable supply: %d\n", ret); } else { ret = devm_add_action_or_reset(dev, - regulator_disable_action, dev); + regulator_disable_action, led); if (ret) return ret; } @@ -290,6 +291,7 @@ static int ktd2692_probe(struct platform_device *pdev) if (!led) return -ENOMEM; + led->dev = &pdev->dev; fled_cdev = &led->fled_cdev; led_cdev = &fled_cdev->led_cdev; led->props.timing = ktd2692_timing; diff --git a/drivers/mailbox/bcm74110-mailbox.c b/drivers/mailbox/bcm74110-mailbox.c index 2e7e86f3e6a4..0ae6c56b8786 100644 --- a/drivers/mailbox/bcm74110-mailbox.c +++ b/drivers/mailbox/bcm74110-mailbox.c @@ -97,6 +97,8 @@ struct bcm74110_mbox_chan { int type; }; +#define BCM74110_INIT_MSG_MAX 16 + struct bcm74110_mbox { struct platform_device *pdev; void __iomem *base; @@ -105,6 +107,7 @@ struct bcm74110_mbox { int rx_chan; int rx_irq; struct list_head rx_svc_init_list; + unsigned int rx_svc_init_count; spinlock_t rx_svc_list_lock; struct mbox_controller controller; @@ -148,7 +151,15 @@ static void bcm74110_rx_push_init_msg(struct bcm74110_mbox *mbox, u32 val) msg->msg = val; spin_lock(&mbox->rx_svc_list_lock); + if (mbox->rx_svc_init_count >= BCM74110_INIT_MSG_MAX) { + spin_unlock(&mbox->rx_svc_list_lock); + kfree(msg); + dev_warn_ratelimited(&mbox->pdev->dev, + "PMC INIT msg list full, dropping message\n"); + return; + } list_add_tail(&msg->list_entry, &mbox->rx_svc_init_list); + mbox->rx_svc_init_count++; spin_unlock(&mbox->rx_svc_list_lock); } @@ -225,6 +236,7 @@ static int bcm74110_rx_pop_init_msg(struct bcm74110_mbox *mbox, u32 func_type, list_entry) { if (BCM_MSG_GET_FIELD(msg->msg, FUNC) == func_type) { list_del(&msg->list_entry); + mbox->rx_svc_init_count--; found = true; break; } @@ -248,6 +260,7 @@ static void bcm74110_rx_flush_msg(struct bcm74110_mbox *mbox) spin_lock_irqsave(&mbox->rx_svc_list_lock, flags); list_splice_init(&mbox->rx_svc_init_list, &list_temp); + mbox->rx_svc_init_count = 0; spin_unlock_irqrestore(&mbox->rx_svc_list_lock, flags); list_for_each_entry_safe(msg, msg_tmp, &list_temp, list_entry) { diff --git a/drivers/mailbox/mailbox-altera.c b/drivers/mailbox/mailbox-altera.c index 17278c2571d3..7cb91413ef7f 100644 --- a/drivers/mailbox/mailbox-altera.c +++ b/drivers/mailbox/mailbox-altera.c @@ -270,7 +270,7 @@ static void altera_mbox_shutdown(struct mbox_chan *chan) writel_relaxed(~0, mbox->mbox_base + MAILBOX_INTMASK_REG); free_irq(mbox->irq, chan); } else if (!mbox->is_sender) { - timer_delete_sync(&mbox->rxpoll_timer); + timer_shutdown_sync(&mbox->rxpoll_timer); } } diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c index a1360b70b83f..6e915ec5deaa 100644 --- a/drivers/mailbox/mtk-cmdq-mailbox.c +++ b/drivers/mailbox/mtk-cmdq-mailbox.c @@ -506,8 +506,10 @@ static int cmdq_mbox_flush(struct mbox_chan *chan, unsigned long timeout) int ret; ret = pm_runtime_get_sync(cmdq->mbox.dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(cmdq->mbox.dev); return ret; + } spin_lock_irqsave(&thread->chan->lock, flags); if (list_empty(&thread->task_busy_list)) @@ -544,6 +546,9 @@ static int cmdq_mbox_flush(struct mbox_chan *chan, unsigned long timeout) dev_err(cmdq->mbox.dev, "Fail to wait GCE thread 0x%x done\n", (u32)(thread->base - cmdq->base)); + pm_runtime_mark_last_busy(cmdq->mbox.dev); + pm_runtime_put_autosuspend(cmdq->mbox.dev); + return -EFAULT; } pm_runtime_mark_last_busy(cmdq->mbox.dev); diff --git a/drivers/mailbox/qcom-ipcc.c b/drivers/mailbox/qcom-ipcc.c index dead907aa7a2..b0b4e40d9202 100644 --- a/drivers/mailbox/qcom-ipcc.c +++ b/drivers/mailbox/qcom-ipcc.c @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -151,6 +152,9 @@ static int qcom_ipcc_mbox_send_data(struct mbox_chan *chan, void *data) struct qcom_ipcc_chan_info *mchan = chan->con_priv; u32 hwirq; + if (!mchan) + return -EINVAL; + hwirq = qcom_ipcc_get_hwirq(mchan->client_id, mchan->signal_id); writel(hwirq, ipcc->base + IPCC_REG_SEND_ID); @@ -159,6 +163,8 @@ static int qcom_ipcc_mbox_send_data(struct mbox_chan *chan, void *data) static void qcom_ipcc_mbox_shutdown(struct mbox_chan *chan) { + guard(spinlock_irqsave)(&chan->lock); + chan->con_priv = NULL; } diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 59e5d8aa42b7..07e2f0fccefe 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -2402,8 +2402,10 @@ static void __scan(struct dm_bufio_client *c) for (l = 0; l < LIST_SIZE; l++) { while (true) { - if (count - freed <= retain_target) + if (count - freed <= retain_target) { atomic_long_set(&c->need_shrink, 0); + break; + } if (!atomic_long_read(&c->need_shrink)) break; @@ -2521,6 +2523,13 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign init_waitqueue_head(&c->free_buffer_wait); c->async_write_error = 0; + /* + * A client with no buffers yet is not holding the oldest buffer in + * the system; leaving this zeroed would claim exactly that and keep + * the client pinned at the front of dm_bufio_all_clients. + */ + c->oldest_buffer = jiffies; + c->dm_io = dm_io_client_create(); if (IS_ERR(c->dm_io)) { r = PTR_ERR(c->dm_io); @@ -2755,9 +2764,23 @@ static unsigned long __evict_a_few(unsigned long nr_buffers) dm_bufio_unlock(c); - if (count) + if (count) { c->oldest_buffer = oldest_buffer; - __insert_client(c); + __insert_client(c); + } else { + /* + * We evicted nothing, so 'oldest_buffer' tells us nothing new + * and the client keeps its old, possibly very stale, value. + * Requeue it at the back rather than by that value, otherwise + * __insert_client() would put it straight back at the front + * and every subsequent call would pop this same client again, + * never reaching any of the others. + * + * This leaves the list slightly out of order, which is fine - + * it is only ever an approximation. + */ + list_add_tail(&c->client_list, &dm_bufio_all_clients); + } return count; } @@ -2782,11 +2805,23 @@ static void evict_old(void) { unsigned long threshold = dm_bufio_cache_size - dm_bufio_cache_size / DM_BUFIO_LOW_WATERMARK_RATIO; + int unproductive = 0; mutex_lock(&dm_bufio_clients_lock); while (dm_bufio_current_allocated > threshold) { - if (!__evict_a_few(64)) - break; + if (__evict_a_few(64)) { + unproductive = 0; + } else { + /* + * This client had nothing to give. Try the others + * before giving up: one idle client, or one whose + * buffers are all held, must not stop us evicting + * from everybody else. Stop once a whole sweep of + * the client list has freed nothing. + */ + if (++unproductive >= dm_bufio_client_count) + break; + } cond_resched(); } mutex_unlock(&dm_bufio_clients_lock); diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index 0dc429eb2692..989f958c229b 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -325,8 +325,11 @@ static int read_header(struct pstore *ps, int *new_snapshot) } ps->io_client = dm_io_client_create(); - if (IS_ERR(ps->io_client)) - return PTR_ERR(ps->io_client); + if (IS_ERR(ps->io_client)) { + r = PTR_ERR(ps->io_client); + ps->io_client = NULL; + return r; + } r = alloc_area(ps); if (r) diff --git a/drivers/md/dm-vdo/indexer/chapter-index.c b/drivers/md/dm-vdo/indexer/chapter-index.c index fb1db41c794b..7a744b2da28f 100644 --- a/drivers/md/dm-vdo/indexer/chapter-index.c +++ b/drivers/md/dm-vdo/indexer/chapter-index.c @@ -284,10 +284,17 @@ int uds_search_chapter_index_page(struct delta_index_page *index_page, if (result != UDS_SUCCESS) return result; - if (was_entry_found(&entry, address)) - *record_page_ptr = uds_get_delta_entry_value(&entry); - else + if (!was_entry_found(&entry, address)) { *record_page_ptr = NO_CHAPTER_INDEX_ENTRY; + return UDS_SUCCESS; + } - return UDS_SUCCESS; + *record_page_ptr = uds_get_delta_entry_value(&entry); + result = VDO_ASSERT(*record_page_ptr < geometry->record_pages_per_chapter, + "0 <= %d < %u", *record_page_ptr, + geometry->record_pages_per_chapter); + if (result != VDO_SUCCESS) + *record_page_ptr = NO_CHAPTER_INDEX_ENTRY; + + return result; } diff --git a/drivers/md/dm-vdo/indexer/delta-index.c b/drivers/md/dm-vdo/indexer/delta-index.c index 0ac2443f0df3..a42de1af4b69 100644 --- a/drivers/md/dm-vdo/indexer/delta-index.c +++ b/drivers/md/dm-vdo/indexer/delta-index.c @@ -803,7 +803,7 @@ static void compute_new_list_offsets(struct delta_zone *delta_zone, u32 growing_ (delta_zone->size * BITS_PER_BYTE - delta_lists[tail_guard_index].size); } -static void rebalance_lists(struct delta_zone *delta_zone) +static int rebalance_lists(struct delta_zone *delta_zone) { struct delta_list *delta_lists; u32 i; @@ -814,9 +814,17 @@ static void rebalance_lists(struct delta_zone *delta_zone) for (i = 0; i <= delta_zone->list_count + 1; i++) used_space += get_delta_list_byte_size(&delta_lists[i]); + if (delta_zone->size < used_space) { + return vdo_log_warning_strerror(UDS_CORRUPT_DATA, + "delta zone lists overflow zone size %zu", + delta_zone->size); + } + compute_new_list_offsets(delta_zone, 0, 0, used_space); for (i = 1; i <= delta_zone->list_count + 1; i++) delta_lists[i].start = delta_zone->new_offsets[i]; + + return UDS_SUCCESS; } /* Start restoring a delta index from multiple input streams. */ @@ -944,8 +952,11 @@ int uds_start_restoring_delta_index(struct delta_index *delta_index, } /* Prepare each zone to start receiving the delta list data. */ - for (z = 0; z < delta_index->zone_count; z++) - rebalance_lists(&delta_index->delta_zones[z]); + for (z = 0; z < delta_index->zone_count; z++) { + result = rebalance_lists(&delta_index->delta_zones[z]); + if (result != UDS_SUCCESS) + return result; + } return UDS_SUCCESS; } diff --git a/drivers/md/dm-vdo/indexer/volume.c b/drivers/md/dm-vdo/indexer/volume.c index 425b3a74f4db..f7de78e0d0db 100644 --- a/drivers/md/dm-vdo/indexer/volume.c +++ b/drivers/md/dm-vdo/indexer/volume.c @@ -891,12 +891,6 @@ int uds_search_cached_record_page(struct volume *volume, struct uds_request *req if (record_page_number == NO_CHAPTER_INDEX_ENTRY) return UDS_SUCCESS; - result = VDO_ASSERT(record_page_number < geometry->record_pages_per_chapter, - "0 <= %d < %u", record_page_number, - geometry->record_pages_per_chapter); - if (result != VDO_SUCCESS) - return result; - page_number = geometry->index_pages_per_chapter + record_page_number; physical_page = map_to_physical_page(volume->geometry, chapter, page_number); diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c index 34148aa4df79..aa758d5ef601 100644 --- a/drivers/md/dm-writecache.c +++ b/drivers/md/dm-writecache.c @@ -194,6 +194,7 @@ struct dm_writecache { struct task_struct *endio_thread; struct task_struct *flush_thread; + spinlock_t flush_list_lock; struct bio_list flush_list; struct dm_kcopyd_client *dm_kcopyd; @@ -899,8 +900,6 @@ static void writecache_discard(struct dm_writecache *wc, sector_t start, sector_ } discarded_something = true; } - if (!writecache_entry_is_committed(wc, e)) - wc->uncommitted_blocks--; writecache_free_entry(wc, e); } @@ -1290,9 +1289,11 @@ static int writecache_flush_thread(void *data) struct bio *bio; wc_lock(wc); + spin_lock_irq(&wc->flush_list_lock); bio = bio_list_pop(&wc->flush_list); if (!bio) { set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irq(&wc->flush_list_lock); wc_unlock(wc); if (unlikely(kthread_should_stop())) { @@ -1303,6 +1304,7 @@ static int writecache_flush_thread(void *data) schedule(); continue; } + spin_unlock_irq(&wc->flush_list_lock); if (bio_op(bio) == REQ_OP_DISCARD) { writecache_discard(wc, bio->bi_iter.bi_sector, @@ -1324,9 +1326,12 @@ static int writecache_flush_thread(void *data) static void writecache_offload_bio(struct dm_writecache *wc, struct bio *bio) { + unsigned long flags; + spin_lock_irqsave(&wc->flush_list_lock, flags); if (bio_list_empty(&wc->flush_list)) wake_up_process(wc->flush_thread); bio_list_add(&wc->flush_list, bio); + spin_unlock_irqrestore(&wc->flush_list_lock, flags); } enum wc_map_op { @@ -1424,7 +1429,8 @@ static void writecache_bio_copy_ssd(struct dm_writecache *wc, struct bio *bio, dm_accept_partial_bio(bio, bio_size >> SECTOR_SHIFT); wc->stats.writes += bio->bi_iter.bi_size >> wc->block_size_bits; - wc->stats.writes_allocate += (bio->bi_iter.bi_size - wc->block_size) >> wc->block_size_bits; + if (!search_used) + wc->stats.writes_allocate += (bio->bi_iter.bi_size - wc->block_size) >> wc->block_size_bits; if (unlikely(wc->uncommitted_blocks >= wc->autocommit_blocks)) { wc->uncommitted_blocks = 0; @@ -1437,6 +1443,8 @@ static void writecache_bio_copy_ssd(struct dm_writecache *wc, struct bio *bio, static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio *bio) { struct wc_entry *e; + enum wc_map_op ret = WC_MAP_SUBMIT; + bool need_flush = false; do { bool found_entry = false; @@ -1473,7 +1481,8 @@ static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio writecache_map_remap_origin(wc, bio, e); wc->stats.writes_around += bio->bi_iter.bi_size >> wc->block_size_bits; wc->stats.writes += bio->bi_iter.bi_size >> wc->block_size_bits; - return WC_MAP_REMAP_ORIGIN; + ret = WC_MAP_REMAP_ORIGIN; + goto flush_pmem_and_ret; } wc->stats.writes_blocked_on_freelist++; writecache_wait_on_freelist(wc); @@ -1487,18 +1496,25 @@ static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio if (WC_MODE_PMEM(wc)) { bio_copy_block(wc, bio, memory_data(wc, e)); wc->stats.writes++; + need_flush = true; } else { writecache_bio_copy_ssd(wc, bio, e, search_used); return WC_MAP_REMAP; } } while (bio->bi_iter.bi_size); - if (unlikely(bio->bi_opf & REQ_FUA || wc->uncommitted_blocks >= wc->autocommit_blocks)) - writecache_flush(wc); - else - writecache_schedule_autocommit(wc); +flush_pmem_and_ret: + if (need_flush) { + if (unlikely(bio->bi_opf & REQ_FUA || wc->uncommitted_blocks >= wc->autocommit_blocks)) { + writecache_flush(wc); + if (writecache_has_error(wc)) + ret = WC_MAP_ERROR; + } else { + writecache_schedule_autocommit(wc); + } + } - return WC_MAP_SUBMIT; + return ret; } static enum wc_map_op writecache_map_flush(struct dm_writecache *wc, struct bio *bio) @@ -1588,7 +1604,10 @@ static int writecache_map(struct dm_target *ti, struct bio *bio) case WC_MAP_REMAP: /* make sure that writecache_end_io decrements bio_in_progress: */ - bio->bi_private = (void *)1; + if (unlikely(bio->bi_opf & REQ_FUA) && bio_op(bio) == REQ_OP_WRITE) + bio->bi_private = (void *)3; + else + bio->bi_private = (void *)1; atomic_inc(&wc->bio_in_progress[bio_data_dir(bio)]); wc_unlock(wc); return DM_MAPIO_REMAPPED; @@ -1618,12 +1637,19 @@ static int writecache_end_io(struct dm_target *ti, struct bio *bio, blk_status_t { struct dm_writecache *wc = ti->private; - if (bio->bi_private == (void *)1) { + if (bio->bi_private == (void *)1 || bio->bi_private == (void *)3) { int dir = bio_data_dir(bio); + bool fua = bio->bi_private == (void *)3; if (atomic_dec_and_test(&wc->bio_in_progress[dir])) if (unlikely(waitqueue_active(&wc->bio_in_progress_wait[dir]))) wake_up(&wc->bio_in_progress_wait[dir]); + + if (fua && likely(*status == BLK_STS_OK)) { + bio->bi_private = NULL; + writecache_offload_bio(wc, bio); + return DM_ENDIO_INCOMPLETE; + } } else if (bio->bi_private == (void *)2) { dm_iot_io_end(&wc->iot, 1); } @@ -2507,6 +2533,11 @@ static int writecache_ctr(struct dm_target *ti, unsigned int argc, char **argv) } if (WC_MODE_PMEM(wc)) { + if (!wc->ssd_dev->dax_dev) { + r = -EOPNOTSUPP; + ti->error = "Cache device is not a DAX device"; + goto bad; + } if (!dax_synchronous(wc->ssd_dev->dax_dev)) { r = -EOPNOTSUPP; ti->error = "Asynchronous persistent memory not supported as pmem cache"; @@ -2524,6 +2555,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned int argc, char **argv) wc->memory_map_size -= (uint64_t)wc->start_sector << SECTOR_SHIFT; + spin_lock_init(&wc->flush_list_lock); bio_list_init(&wc->flush_list); wc->flush_thread = kthread_run(writecache_flush_thread, wc, "dm_writecache_flush"); if (IS_ERR(wc->flush_thread)) { diff --git a/drivers/md/dm.c b/drivers/md/dm.c index f587b7229ce8..077bf8b16a0b 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1349,7 +1349,7 @@ void dm_accept_partial_bio(struct bio *bio, unsigned int n_sectors) * for accounting but it is being reduced so update accordingly. */ dm_io_set_flag(io, DM_IO_WAS_SPLIT); - io->sectors = n_sectors; + io->sectors = *tio->len_ptr; io->sector_offset = bio_sectors(io->orig_bio); } EXPORT_SYMBOL_GPL(dm_accept_partial_bio); diff --git a/drivers/md/md.c b/drivers/md/md.c index 44f44219ed7f..937a2f4da84b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1930,8 +1930,11 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_ if (!badblocks_set(&rdev->badblocks, sector, count, 1)) return -EINVAL; } - } else if (sb->bblog_offset != 0) + } else if (sb->bblog_offset != 0) { + if (le16_to_cpu(sb->bblog_size) > (PAGE_SIZE / 512)) + return -EINVAL; rdev->badblocks.shift = 0; + } if ((le32_to_cpu(sb->feature_map) & (MD_FEATURE_PPL | MD_FEATURE_MULTIPLE_PPLS))) { @@ -6255,12 +6258,22 @@ struct mddev *md_alloc(dev_t dev, char *name) disk->events |= DISK_EVENT_MEDIA_CHANGE; mddev->gendisk = disk; + + /* + * add_disk() makes the array openable before mddev->kobj exists. + * Hold reconfig_mutex until kobject_add() is done so that ioctls + * issued in between wait instead of using an uninitialised kobj. + */ + mddev_lock_nointr(mddev); error = add_disk(disk); - if (error) + if (error) { + mddev_unlock(mddev); goto out_put_disk; + } kobject_init(&mddev->kobj, &md_ktype); error = kobject_add(&mddev->kobj, &disk_to_dev(disk)->kobj, "%s", "md"); + mddev_unlock(mddev); if (error) { /* * The disk is already live at this point. Clear the hold flag diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c index 2518781cbdf6..1f7bf680234d 100644 --- a/drivers/md/raid5-cache.c +++ b/drivers/md/raid5-cache.c @@ -2001,27 +2001,36 @@ r5l_recovery_verify_data_checksum_for_mb(struct r5l_log *log, if (!page) return -ENOMEM; - while (mb_offset < le32_to_cpu(mb->meta_size)) { + while (mb_offset + sizeof(struct r5l_payload_header) <= le32_to_cpu(mb->meta_size)) { + u32 payload_size; sector_t payload_len; payload = (void *)mb + mb_offset; payload_flush = (void *)mb + mb_offset; if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_DATA) { + if (mb_offset + sizeof(struct r5l_payload_data_parity) + > le32_to_cpu(mb->meta_size)) + goto mismatch; + payload_size = le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9); payload_len = sizeof(struct r5l_payload_data_parity) + - (sector_t)sizeof(__le32) * - (le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9)); - if (mb_offset + payload_len > le32_to_cpu(mb->meta_size)) + (sector_t)sizeof(__le32) * payload_size; + if (mb_offset + payload_len > le32_to_cpu(mb->meta_size) || + payload_size < 1) goto mismatch; if (r5l_recovery_verify_data_checksum( log, ctx, page, log_offset, payload->checksum[0]) < 0) goto mismatch; } else if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_PARITY) { + if (mb_offset + sizeof(struct r5l_payload_data_parity) + > le32_to_cpu(mb->meta_size)) + goto mismatch; + payload_size = le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9); payload_len = sizeof(struct r5l_payload_data_parity) + - (sector_t)sizeof(__le32) * - (le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9)); - if (mb_offset + payload_len > le32_to_cpu(mb->meta_size)) + (sector_t)sizeof(__le32) * payload_size; + if (mb_offset + payload_len > le32_to_cpu(mb->meta_size) || + payload_size < conf->max_degraded) goto mismatch; if (r5l_recovery_verify_data_checksum( log, ctx, page, log_offset, @@ -2035,6 +2044,9 @@ r5l_recovery_verify_data_checksum_for_mb(struct r5l_log *log, payload->checksum[1]) < 0) goto mismatch; } else if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_FLUSH) { + if (mb_offset + sizeof(struct r5l_payload_flush) + > le32_to_cpu(mb->meta_size)) + goto mismatch; payload_len = sizeof(struct r5l_payload_flush) + (sector_t)le32_to_cpu(payload_flush->size); if (mb_offset + payload_len > le32_to_cpu(mb->meta_size)) @@ -2096,7 +2108,7 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log, mb_offset = sizeof(struct r5l_meta_block); log_offset = r5l_ring_add(log, ctx->pos, BLOCK_SECTORS); - while (mb_offset < le32_to_cpu(mb->meta_size)) { + while (mb_offset + sizeof(struct r5l_payload_header) < le32_to_cpu(mb->meta_size)) { sector_t payload_len; int dd; @@ -2106,6 +2118,9 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log, if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_FLUSH) { int i, count; + if (mb_offset + sizeof(struct r5l_payload_flush) > + le32_to_cpu(mb->meta_size)) + return -EINVAL; payload_len = sizeof(struct r5l_payload_flush) + (sector_t)le32_to_cpu(payload_flush->size); if (mb_offset + payload_len > @@ -2130,6 +2145,9 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log, } /* DATA or PARITY payload */ + if (mb_offset + sizeof(struct r5l_payload_data_parity) > + le32_to_cpu(mb->meta_size)) + return -EINVAL; payload_len = sizeof(struct r5l_payload_data_parity) + (sector_t)sizeof(__le32) * (le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9)); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 56d7e05e94ce..6dfefbacfe3c 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2627,6 +2627,7 @@ static int resize_stripes(struct r5conf *conf, int newsize) } else { kfree(conf->disks); conf->disks = ndisks; + conf->disks_cnt = newsize; } } else err = -ENOMEM; @@ -7391,7 +7392,8 @@ static void raid5_free_percpu(struct r5conf *conf) if (!conf->percpu) return; - cpuhp_state_remove_instance(CPUHP_MD_RAID5_PREPARE, &conf->node); + if (!hlist_unhashed_lockless(&conf->node)) + cpuhp_state_remove_instance(CPUHP_MD_RAID5_PREPARE, &conf->node); free_percpu(conf->percpu); } @@ -7405,7 +7407,7 @@ static void free_conf(struct r5conf *conf) free_thread_groups(conf); shrink_stripes(conf); raid5_free_percpu(conf); - for (i = 0; i < conf->pool_size; i++) + for (i = 0; i < conf->disks_cnt; i++) if (conf->disks[i].extra_page) put_page(conf->disks[i].extra_page); kfree(conf->disks); @@ -7588,7 +7590,7 @@ static struct r5conf *setup_conf(struct mddev *mddev) if (!conf->disks) goto abort; - + conf->disks_cnt = max_disks; for (i = 0; i < max_disks; i++) { conf->disks[i].extra_page = alloc_page(GFP_KERNEL); if (!conf->disks[i].extra_page) diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index eafc6e9ed6ee..fa9647a862ad 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -668,6 +668,7 @@ struct r5conf { unsigned long cache_state; struct shrinker *shrinker; int pool_size; /* number of disks in stripeheads in pool */ + int disks_cnt; /* number of entries in disks[] array */ spinlock_t device_lock; struct disk_info *disks; struct bio_set bio_split; diff --git a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c index 48410ce33490..638def4cb569 100644 --- a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c +++ b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c @@ -846,7 +846,9 @@ static irqreturn_t extron_interrupt(struct serio *serio, unsigned char data, return IRQ_HANDLED; memcpy(extron->data, extron->buf, extron->idx); extron->len = extron->idx; - extron->data[extron->len] = 0; + /* Keep fixed-offset response tests from using stale tail bytes. */ + memset(extron->data + extron->len, 0, + min_t(size_t, 10, sizeof(extron->data) - extron->len)); if (debug) dev_info(extron->dev, "received %s\n", extron->data); extron->idx = 0; diff --git a/drivers/media/common/saa7146/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c index 27c53eed8fe3..e908af0693d2 100644 --- a/drivers/media/common/saa7146/saa7146_core.c +++ b/drivers/media/common/saa7146/saa7146_core.c @@ -340,6 +340,8 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent goto out; } + spin_lock_init(&dev->int_slock); + /* create a nice device name */ sprintf(dev->name, "saa7146 (%d)", saa7146_num); @@ -425,7 +427,6 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent dev->ext = ext; mutex_init(&dev->v4l2_lock); - spin_lock_init(&dev->int_slock); spin_lock_init(&dev->slock); mutex_init(&dev->i2c_lock); diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c index e7b9b9b11d7d..ce228f2ef330 100644 --- a/drivers/media/dvb-frontends/stv0900_core.c +++ b/drivers/media/dvb-frontends/stv0900_core.c @@ -1775,6 +1775,8 @@ static int stv0900_recv_slave_reply(struct dvb_frontend *fe, if (stv0900_get_bits(intp, RX_END)) { reply->msg_len = stv0900_get_bits(intp, FIFO_BYTENBR); + if (reply->msg_len > sizeof(reply->msg)) + reply->msg_len = sizeof(reply->msg); for (i = 0; i < reply->msg_len; i++) reply->msg[i] = stv0900_read_reg(intp, DISRXDATA); diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c index f273efa330cf..b95b6b4a69c7 100644 --- a/drivers/media/dvb-frontends/stv090x.c +++ b/drivers/media/dvb-frontends/stv090x.c @@ -3902,6 +3902,8 @@ static int stv090x_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_s if (rx_end) { reply->msg_len = STV090x_GETFIELD_Px(reg, FIFO_BYTENBR_FIELD); + if (reply->msg_len > sizeof(reply->msg)) + reply->msg_len = sizeof(reply->msg); for (i = 0; i < reply->msg_len; i++) reply->msg[i] = STV090x_READ_DEMOD(state, DISRXDATA); } diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 5cbc973df684..6223911e324a 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1425,6 +1425,7 @@ static int adv7180_probe(struct i2c_client *client) if (state == NULL) return -ENOMEM; + mutex_init(&state->mutex); state->client = client; state->field = V4L2_FIELD_ALTERNATE; state->chip_info = i2c_get_match_data(client); @@ -1466,7 +1467,6 @@ static int adv7180_probe(struct i2c_client *client) } state->irq = client->irq; - mutex_init(&state->mutex); state->curr_norm = V4L2_STD_NTSC; state->input = 0; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 516553fb17e9..cfecfff4c3aa 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -2641,8 +2641,9 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) "(16-235)" : "(0-255)", (reg_io_0x02 & 0x08) ? "enabled" : "disabled"); } + ret = cp_read(sd, info->cp_csc) >> 4; v4l2_info(sd, "Color space conversion: %s\n", - csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]); + ret < 0 ? "" : csc_coeff_sel_rb[ret]); if (!is_digital_input(sd)) return 0; diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c index 3d399af01322..d08d01098a9a 100644 --- a/drivers/media/i2c/alvium-csi2.c +++ b/drivers/media/i2c/alvium-csi2.c @@ -2523,6 +2523,7 @@ static void alvium_remove(struct i2c_client *client) * make sure to turn power off manually. */ pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); if (!pm_runtime_status_suspended(dev)) alvium_set_power(alvium, false); pm_runtime_set_suspended(dev); diff --git a/drivers/media/i2c/ov2735.c b/drivers/media/i2c/ov2735.c index b96600204141..f248fdb352af 100644 --- a/drivers/media/i2c/ov2735.c +++ b/drivers/media/i2c/ov2735.c @@ -1081,6 +1081,7 @@ static void ov2735_remove(struct i2c_client *client) v4l2_subdev_cleanup(&ov2735->sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(ov2735->sd.ctrl_handler); + ov2735_power_off(ov2735->dev); } static DEFINE_RUNTIME_DEV_PM_OPS(ov2735_pm_ops, diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index dd01e1d515ff..27d7ca17d4d6 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -2071,9 +2071,6 @@ static int ov8856_power_on(struct device *dev) struct ov8856 *ov8856 = to_ov8856(sd); int ret; - if (is_acpi_node(dev_fwnode(dev))) - return 0; - ret = clk_prepare_enable(ov8856->xvclk); if (ret < 0) { dev_err(dev, "failed to enable xvclk\n"); @@ -2109,9 +2106,6 @@ static int ov8856_power_off(struct device *dev) struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov8856 *ov8856 = to_ov8856(sd); - if (is_acpi_node(dev_fwnode(dev))) - return 0; - gpiod_set_value_cansleep(ov8856->reset_gpio, 1); regulator_bulk_disable(ARRAY_SIZE(ov8856_supply_names), ov8856->supplies); @@ -2282,21 +2276,18 @@ static int ov8856_get_hwcfg(struct ov8856 *ov8856) dev_warn(dev, "external clock rate %u is unsupported", xvclk_rate); - if (!is_acpi_node(fwnode)) { - ov8856->reset_gpio = devm_gpiod_get_optional(dev, "reset", - GPIOD_OUT_LOW); - if (IS_ERR(ov8856->reset_gpio)) - return PTR_ERR(ov8856->reset_gpio); + ov8856->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(ov8856->reset_gpio)) + return PTR_ERR(ov8856->reset_gpio); - for (i = 0; i < ARRAY_SIZE(ov8856_supply_names); i++) - ov8856->supplies[i].supply = ov8856_supply_names[i]; + for (i = 0; i < ARRAY_SIZE(ov8856_supply_names); i++) + ov8856->supplies[i].supply = ov8856_supply_names[i]; - ret = devm_regulator_bulk_get(dev, - ARRAY_SIZE(ov8856_supply_names), - ov8856->supplies); - if (ret) - return ret; - } + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ov8856_supply_names), + ov8856->supplies); + if (ret) + return ret; ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) @@ -2316,7 +2307,8 @@ static int ov8856_get_hwcfg(struct ov8856 *ov8856) goto check_hwcfg_error; } - dev_dbg(dev, "Using %u data lanes\n", ov8856->cur_mode->data_lanes); + dev_dbg(dev, "Using %u data lanes\n", + bus_cfg.bus.mipi_csi2.num_data_lanes); if (bus_cfg.bus.mipi_csi2.num_data_lanes == 2) ov8856->priv_lane = &lane_cfg_2; diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index a0ca19359c43..aefc442b5737 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1373,7 +1373,8 @@ static int tc358743_log_status(struct v4l2_subdev *sd) static const char * const input_color_space[] = { "RGB", "YCbCr 601", "opRGB", "YCbCr 709", "NA (4)", "xvYCC 601", "NA(6)", "xvYCC 709", "NA(8)", "sYCC601", - "NA(10)", "NA(11)", "NA(12)", "opYCC 601"}; + "NA(10)", "NA(11)", "NA(12)", "opYCC 601", "NA(14)", + "NA(15)"}; v4l2_info(sd, "-----Chip status-----\n"); v4l2_info(sd, "Chip ID: 0x%02x\n", diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 74c59a94b2b0..d3bd31e38efa 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -806,12 +806,12 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, } if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) { CX18_ERR("No suitable DMA available, card %d\n", cx->instance); - return -EIO; + goto err_disable_device; } if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) { CX18_ERR("Cannot request encoder memory region, card %d\n", cx->instance); - return -EIO; + goto err_disable_device; } /* Enable bus mastering and memory mapped IO for the CX23418 */ @@ -835,6 +835,10 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, cx->pci_dev->irq, pci_latency, (u64)cx->base_addr); return 0; + +err_disable_device: + pci_disable_device(pci_dev); + return -EIO; } static void cx18_init_subdevs(struct cx18 *cx) @@ -1121,6 +1125,7 @@ static int cx18_probe(struct pci_dev *pci_dev, cx18_iounmap(cx); free_mem: release_mem_region(cx->base_addr, CX18_MEM_SIZE); + pci_disable_device(pci_dev); free_workqueues: destroy_workqueue(cx->in_work_queue); err: diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c index 08b7ce1043aa..27ce670197cc 100644 --- a/drivers/media/pci/tw68/tw68-core.c +++ b/drivers/media/pci/tw68/tw68-core.c @@ -228,7 +228,7 @@ static int tw68_initdev(struct pci_dev *pci_dev, /* pci init */ dev->pci = pci_dev; - if (pci_enable_device(pci_dev)) { + if (pcim_enable_device(pci_dev)) { err = -EIO; goto fail1; } diff --git a/drivers/media/pci/tw686x/tw686x-core.c b/drivers/media/pci/tw686x/tw686x-core.c index f39e0e34deb6..6dc8af345295 100644 --- a/drivers/media/pci/tw686x/tw686x-core.c +++ b/drivers/media/pci/tw686x/tw686x-core.c @@ -241,6 +241,7 @@ static int tw686x_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct tw686x_dev *dev; + unsigned long flags; int err; dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -352,6 +353,15 @@ static int tw686x_probe(struct pci_dev *pci_dev, pci_release_regions(pci_dev); disable_pci: pci_disable_device(pci_dev); + if (dev->v4l2_dev.dev) { + spin_lock_irqsave(&dev->lock, flags); + dev->pci_dev = NULL; + spin_unlock_irqrestore(&dev->lock, flags); + + v4l2_device_put(&dev->v4l2_dev); + return err; + } + free_audio: kfree(dev->audio_channels); free_video: diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c index da00f5fc0e5d..538ef56823b4 100644 --- a/drivers/media/platform/amphion/vpu_core.c +++ b/drivers/media/platform/amphion/vpu_core.c @@ -302,22 +302,23 @@ static void vpu_core_put_vpu(struct vpu_core *core) core->vpu->put_vpu(core->vpu); } +static void vpu_core_cancel_work(struct vpu_core *core); + static int vpu_core_unregister(struct device *dev, struct vpu_core *core) { list_del_init(&core->list); - vpu_core_put_vpu(core); - core->vpu = NULL; - vfree(core->msg_buffer); - core->msg_buffer = NULL; - if (core->workqueue) { - cancel_work_sync(&core->msg_work); - cancel_delayed_work_sync(&core->msg_delayed_work); + vpu_core_cancel_work(core); destroy_workqueue(core->workqueue); core->workqueue = NULL; } + vpu_core_put_vpu(core); + core->vpu = NULL; + vfree(core->msg_buffer); + core->msg_buffer = NULL; + return 0; } @@ -689,7 +690,6 @@ static int vpu_core_probe(struct platform_device *pdev) pm_runtime_enable(dev); ret = pm_runtime_resume_and_get(dev); if (ret) { - pm_runtime_put_noidle(dev); pm_runtime_set_suspended(dev); goto err_runtime_disable; } @@ -718,6 +718,8 @@ static void vpu_core_remove(struct platform_device *pdev) struct vpu_core *core = platform_get_drvdata(pdev); int ret; + WARN_ON(!list_empty(&core->instances)); + vpu_core_remove_dbgfs_file(core); ret = pm_runtime_resume_and_get(dev); WARN_ON(ret < 0); @@ -868,6 +870,7 @@ static struct platform_driver amphion_vpu_core_driver = { .remove = vpu_core_remove, .driver = { .name = "amphion-vpu-core", + .suppress_bind_attrs = true, .of_match_table = vpu_core_dt_match, .pm = &vpu_core_pm_ops, }, diff --git a/drivers/media/platform/amphion/vpu_drv.c b/drivers/media/platform/amphion/vpu_drv.c index efbfd2652721..67d48c338fd1 100644 --- a/drivers/media/platform/amphion/vpu_drv.c +++ b/drivers/media/platform/amphion/vpu_drv.c @@ -230,6 +230,7 @@ static struct platform_driver amphion_vpu_driver = { .remove = vpu_remove, .driver = { .name = "amphion-vpu", + .suppress_bind_attrs = true, .of_match_table = vpu_dt_match, .pm = &vpu_pm_ops, }, diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index a05a744cbb75..6a7e240c5b18 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -1121,10 +1121,13 @@ static void isi_graph_notify_unbind(struct v4l2_async_notifier *notifier, { struct atmel_isi *isi = notifier_to_isi(notifier); + if (!video_is_registered(isi->vdev)) + return; + dev_dbg(isi->dev, "Removing %s\n", video_device_node_name(isi->vdev)); - /* Checks internally if vdev have been init or not */ video_unregister_device(isi->vdev); + isi->vdev = NULL; } static int isi_graph_notify_bound(struct v4l2_async_notifier *notifier, @@ -1323,6 +1326,8 @@ static void atmel_isi_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); v4l2_async_nf_unregister(&isi->notifier); v4l2_async_nf_cleanup(&isi->notifier); + if (isi->vdev) + video_device_release(isi->vdev); v4l2_device_unregister(&isi->v4l2_dev); } 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 e1ad685a42e5..6f93fdf28ab3 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c @@ -1261,8 +1261,14 @@ static void wave5_vpu_dec_buf_queue_dst(struct vb2_buffer *vb) struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret; + + ret = pm_runtime_resume_and_get(inst->dev->dev); + if (ret < 0) { + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + return; + } - pm_runtime_resume_and_get(inst->dev->dev); vbuf->sequence = inst->queued_dst_buf_num++; if (inst->state == VPU_INST_STATE_PIC_RUN) { diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.c b/drivers/media/platform/chips-media/wave5/wave5-vpu.c index 3216b4997644..6fa2ff1cbf12 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.c @@ -340,6 +340,13 @@ static int wave5_vpu_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to get irq resource, falling back to polling\n"); sema_init(&dev->irq_sem, 1); dev->irq_thread = kthread_run(irq_thread, dev, "irq thread"); + if (IS_ERR(dev->irq_thread)) { + ret = PTR_ERR(dev->irq_thread); + dev_err(&pdev->dev, "failed to create irq thread\n"); + dev->irq_thread = NULL; + goto err_vdi_release; + } + hrtimer_setup(&dev->hrtimer, &wave5_vpu_timer_callback, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); dev->worker = kthread_run_worker(0, "vpu_irq_thread"); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c index e7ea2f6a99d5..c76d657cf863 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c @@ -729,7 +729,7 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res) ret = mutex_lock_interruptible(&vpu_dev->hw_lock); if (ret) { - pm_runtime_resume_and_get(inst->dev->dev); + pm_runtime_put_sync(inst->dev->dev); return ret; } @@ -737,16 +737,13 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res) ret = wave5_vpu_enc_finish_seq(inst, fail_res); if (ret < 0 && *fail_res != WAVE5_SYSERR_VPU_STILL_RUNNING) { dev_warn(inst->dev->dev, "enc_finish_seq timed out\n"); - pm_runtime_resume_and_get(inst->dev->dev); - mutex_unlock(&vpu_dev->hw_lock); - return ret; + goto unlock_and_return; } if (*fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING && retry++ >= MAX_FIRMWARE_CALL_RETRY) { - pm_runtime_resume_and_get(inst->dev->dev); - mutex_unlock(&vpu_dev->hw_lock); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto unlock_and_return; } } while (ret != 0); @@ -762,10 +759,12 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res) } wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_task); + +unlock_and_return: mutex_unlock(&vpu_dev->hw_lock); pm_runtime_put_sync(inst->dev->dev); - return 0; + return ret; } int wave5_vpu_enc_register_frame_buffer(struct vpu_instance *inst, unsigned int num, diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.c b/drivers/media/platform/imagination/e5010-jpeg-enc.c index c4e0097cb8b7..a36a2acc896c 100644 --- a/drivers/media/platform/imagination/e5010-jpeg-enc.c +++ b/drivers/media/platform/imagination/e5010-jpeg-enc.c @@ -175,12 +175,12 @@ static void calculate_qp_tables(struct e5010_context *ctx) long long delta = v4l2_jpeg_ref_table_chroma_qt[i] * contrast + luminosity; int val = (int)(v4l2_jpeg_ref_table_chroma_qt[i] + delta); - clamp(val, 1, 255); + val = clamp(val, 1, 255); ctx->chroma_qp[i] = quality == -50 ? 1 : val; delta = v4l2_jpeg_ref_table_luma_qt[i] * contrast + luminosity; val = (int)(v4l2_jpeg_ref_table_luma_qt[i] + delta); - clamp(val, 1, 255); + val = clamp(val, 1, 255); ctx->luma_qp[i] = quality == -50 ? 1 : val; } diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index e07e57d4206b..83d6c54f015d 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -829,7 +829,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, q_data[V4L2_M2M_DST].width = 640; q_data[V4L2_M2M_DST].height = 480; q_data[V4L2_M2M_DST].sizeimage = (640 * 480 * 3) / 2; - q_data[V4L2_M2M_SRC].field = V4L2_FIELD_INTERLACED_TB; + q_data[V4L2_M2M_DST].field = V4L2_FIELD_INTERLACED_TB; return vb2_queue_init(dst_vq); } diff --git a/drivers/media/platform/marvell/Kconfig b/drivers/media/platform/marvell/Kconfig index d31f4730f2a3..ab58175e433c 100644 --- a/drivers/media/platform/marvell/Kconfig +++ b/drivers/media/platform/marvell/Kconfig @@ -22,6 +22,7 @@ config VIDEO_MMP_CAMERA depends on V4L_PLATFORM_DRIVERS depends on I2C && VIDEO_DEV depends on ARCH_MMP || COMPILE_TEST + depends on GPIOLIB || COMPILE_TEST depends on COMMON_CLK select VIDEO_OV7670 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR select I2C_GPIO diff --git a/drivers/media/platform/marvell/mmp-driver.c b/drivers/media/platform/marvell/mmp-driver.c index d3da7ebb4a2b..4c31b62751a1 100644 --- a/drivers/media/platform/marvell/mmp-driver.c +++ b/drivers/media/platform/marvell/mmp-driver.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "mcam-core.h" @@ -269,8 +270,8 @@ static int mmpcam_probe(struct platform_device *pdev) /* * Add OF clock provider. */ - ret = of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, - mcam->mclk); + ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get, + &mcam->mclk_hw); if (ret) { dev_err(&pdev->dev, "can't add DT clock provider\n"); goto out; diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 5a9ba04d3d48..8e52b40e2423 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -1630,7 +1630,7 @@ static void mtk_jpegenc_worker(struct work_struct *work) v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); mtk_jpegenc_set_hw_param(ctx, hw_id, src_buf, dst_buf); - ret = pm_runtime_get_sync(comp_jpeg[hw_id]->dev); + ret = pm_runtime_resume_and_get(comp_jpeg[hw_id]->dev); if (ret < 0) { dev_err(jpeg->dev, "%s : %d, pm_runtime_get_sync fail !!!\n", __func__, __LINE__); @@ -1641,6 +1641,7 @@ static void mtk_jpegenc_worker(struct work_struct *work) if (ret) { dev_err(jpeg->dev, "%s : %d, jpegenc clk_prepare_enable fail\n", __func__, __LINE__); + pm_runtime_put(comp_jpeg[hw_id]->dev); goto enc_end; } @@ -1704,9 +1705,15 @@ static void mtk_jpegdec_worker(struct work_struct *work) ret = wait_event_interruptible_timeout(jpeg->hw_wq, atomic_read(&jpeg->hw_rdy) > 0, MTK_JPEG_HW_TIMEOUT_MSEC); - if (ret != 0 || (i++ > MTK_JPEG_MAX_RETRY_TIME)) { - dev_err(jpeg->dev, "%s : %d, all HW are busy\n", - __func__, __LINE__); + if (ret < 0) { + dev_err(jpeg->dev, "decoder HW wait interrupted: %d\n", + ret); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); + return; + } + + if (!ret && i++ > MTK_JPEG_MAX_RETRY_TIME) { + dev_err(jpeg->dev, "all decoder HW are busy\n"); v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); return; } @@ -1740,7 +1747,7 @@ static void mtk_jpegdec_worker(struct work_struct *work) jpeg_dst_buf->frame_num = ctx->total_frame_num; mtk_jpegdec_set_hw_param(ctx, hw_id, src_buf, dst_buf); - ret = pm_runtime_get_sync(comp_jpeg[hw_id]->dev); + ret = pm_runtime_resume_and_get(comp_jpeg[hw_id]->dev); if (ret < 0) { dev_err(jpeg->dev, "%s : %d, pm_runtime_get_sync fail !!!\n", __func__, __LINE__); diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c index 7fcb2fbdd64e..acb2758a7b42 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c @@ -1730,6 +1730,7 @@ static int mdp_comp_init(struct mdp_dev *mdp, struct device_node *node, struct device *dev = &mdp->pdev->dev; struct platform_device *pdev_c; int clk_ofst; + int ret; int i; s32 event; @@ -1756,8 +1757,10 @@ static int mdp_comp_init(struct mdp_dev *mdp, struct device_node *node, comp->clk_num = mdp->mdp_data->comp_data[id].info.clk_num; comp->clks = devm_kzalloc(dev, sizeof(struct clk *) * comp->clk_num, GFP_KERNEL); - if (!comp->clks) - return -ENOMEM; + if (!comp->clks) { + ret = -ENOMEM; + goto err_put_device; + } clk_ofst = mdp->mdp_data->comp_data[id].info.clk_ofst; @@ -1782,7 +1785,8 @@ static int mdp_comp_init(struct mdp_dev *mdp, struct device_node *node, if (of_property_read_u32_index(node, "mediatek,gce-events", MDP_GCE_EVENT_EOF, &event)) { dev_err(dev, "Component id %d has no EOF\n", id); - return -EINVAL; + ret = -EINVAL; + goto err_put_device; } } else { event = MDP_GCE_NO_EVENT; @@ -1791,6 +1795,10 @@ static int mdp_comp_init(struct mdp_dev *mdp, struct device_node *node, comp->gce_event[MDP_GCE_EVENT_EOF] = event; return 0; + +err_put_device: + put_device(&pdev_c->dev); + return ret; } static void mdp_comp_deinit(struct mdp_comp *comp) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c index 3b81fae9f913..7fec6b21684f 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c @@ -570,6 +570,8 @@ static void mtk_vcodec_dec_remove(struct platform_device *pdev) struct mtk_vcodec_dec_dev *dev = platform_get_drvdata(pdev); destroy_workqueue(dev->decode_workqueue); + if (IS_VDEC_LAT_ARCH(dev->vdec_pdata->hw_arch)) + destroy_workqueue(dev->core_workqueue); if (media_devnode_is_registered(dev->mdev_dec.devnode)) { media_device_unregister(&dev->mdev_dec); diff --git a/drivers/media/platform/mediatek/vpu/mtk_vpu.c b/drivers/media/platform/mediatek/vpu/mtk_vpu.c index 8d8319f0cd22..9dff1d971d37 100644 --- a/drivers/media/platform/mediatek/vpu/mtk_vpu.c +++ b/drivers/media/platform/mediatek/vpu/mtk_vpu.c @@ -962,10 +962,12 @@ static void mtk_vpu_remove(struct platform_device *pdev) #ifdef CONFIG_DEBUG_FS debugfs_remove(vpu_debugfs); #endif + devm_free_irq(&pdev->dev, vpu->reg.irq, vpu); if (vpu->wdt.wq) destroy_workqueue(vpu->wdt.wq); vpu_free_ext_mem(vpu, P_FW); vpu_free_ext_mem(vpu, D_FW); + of_reserved_mem_device_release(&pdev->dev); mutex_destroy(&vpu->vpu_mutex); clk_unprepare(vpu->clk); } diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c index 32bdeae04ad0..21d108eb93c7 100644 --- a/drivers/media/platform/microchip/microchip-isc-base.c +++ b/drivers/media/platform/microchip/microchip-isc-base.c @@ -289,6 +289,7 @@ static int isc_configure(struct isc_device *isc) struct regmap *regmap = isc->regmap; u32 pfe_cfg0, dcfg, mask, pipeline; struct isc_subdev_entity *subdev = isc->current_subdev; + int ret; pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps; pipeline = isc->config.bits_pipeline; @@ -321,7 +322,15 @@ static int isc_configure(struct isc_device *isc) isc_set_histogram(isc, false); /* Update profile */ - return isc_update_profile(isc); + ret = isc_update_profile(isc); + if (ret) { + /* flush the histogram work before the clocks are gated */ + isc_set_histogram(isc, false); + synchronize_irq(isc->irq); + cancel_work_sync(&isc->awb_work); + } + + return ret; } static int isc_prepare_streaming(struct vb2_queue *vq) @@ -425,6 +434,13 @@ static void isc_stop_streaming(struct vb2_queue *vq) /* Disable DMA interrupt */ regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE); + isc_set_histogram(isc, false); + + /* let a running IRQ handler finish before the clock is disabled */ + synchronize_irq(isc->irq); + + cancel_work_sync(&isc->awb_work); + pm_runtime_put_sync(isc->dev); /* Disable stream on the sub device */ @@ -1416,7 +1432,7 @@ static void isc_awb_work(struct work_struct *w) /* streaming is not active anymore */ if (isc->stop) { mutex_unlock(&isc->awb_mutex); - return; + goto out_pm_put; } isc_update_profile(isc); @@ -1427,6 +1443,7 @@ static void isc_awb_work(struct work_struct *w) if (ctrls->awb) regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); +out_pm_put: pm_runtime_put_sync(isc->dev); } @@ -1495,20 +1512,24 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl) if (ctrl->cluster[ISC_CTRL_GB_OFF]->is_new) ctrls->offset[ISC_HIS_CFG_MODE_GB] = isc->gb_off_ctrl->val; - isc_update_awb_ctrls(isc); - mutex_lock(&isc->awb_mutex); - if (vb2_is_streaming(&isc->vb2_vidq)) { + if (vb2_is_streaming(&isc->vb2_vidq) && !isc->stop) { + unsigned long flags; + /* - * If we are streaming, we can update profile to - * have the new settings in place. + * awb_lock keeps the DMA done IRQ from latching a + * partially written WB pipeline. */ + spin_lock_irqsave(&isc->awb_lock, flags); + isc_update_awb_ctrls(isc); + spin_unlock_irqrestore(&isc->awb_lock, flags); + isc_update_profile(isc); } else { /* - * The auto cluster will activate automatically this - * control. This has to be deactivated when not - * streaming. + * Not streaming: keep the cached values for the next + * stream start and deactivate the cluster-activated + * do_white_balance button. */ v4l2_ctrl_activate(isc->do_wb_ctrl, false); } @@ -1703,7 +1724,6 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier, { struct isc_device *isc = container_of(notifier->v4l2_dev, struct isc_device, v4l2_dev); - mutex_destroy(&isc->awb_mutex); cancel_work_sync(&isc->awb_work); video_unregister_device(&isc->video_dev); v4l2_ctrl_handler_free(&isc->ctrls.handler); @@ -1767,8 +1787,6 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) isc->current_subdev = container_of(notifier, struct isc_subdev_entity, notifier); - mutex_init(&isc->lock); - mutex_init(&isc->awb_mutex); init_completion(&isc->comp); @@ -1787,7 +1805,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) ret = vb2_queue_init(q); if (ret < 0) { dev_err(isc->dev, "vb2_queue_init() failed: %d\n", ret); - goto isc_async_complete_err; + return ret; } /* Init video dma queues */ @@ -1798,13 +1816,13 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) ret = isc_set_default_fmt(isc); if (ret) { dev_err(isc->dev, "Could not set default format\n"); - goto isc_async_complete_err; + return ret; } ret = isc_ctrl_init(isc); if (ret) { dev_err(isc->dev, "Init isc ctrols failed: %d\n", ret); - goto isc_async_complete_err; + return ret; } /* Register video device */ @@ -1824,7 +1842,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) { dev_err(isc->dev, "video_register_device failed: %d\n", ret); - goto isc_async_complete_err; + return ret; } ret = isc_scaler_link(isc); @@ -1839,10 +1857,6 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) isc_async_complete_unregister_device: video_unregister_device(vdev); - -isc_async_complete_err: - mutex_destroy(&isc->awb_mutex); - mutex_destroy(&isc->lock); return ret; } diff --git a/drivers/media/platform/microchip/microchip-isc-clk.c b/drivers/media/platform/microchip/microchip-isc-clk.c index 24358d804e75..66dc522a6190 100644 --- a/drivers/media/platform/microchip/microchip-isc-clk.c +++ b/drivers/media/platform/microchip/microchip-isc-clk.c @@ -98,15 +98,14 @@ static int isc_clk_is_enabled(struct clk_hw *hw) { struct isc_clk *isc_clk = to_isc_clk(hw); u32 status; - int ret; - ret = pm_runtime_resume_and_get(isc_clk->dev); - if (ret < 0) + /* Runs in atomic context, so must not sleep to resume the ISC. */ + if (pm_runtime_get_if_active(isc_clk->dev) <= 0) return 0; regmap_read(isc_clk->regmap, ISC_CLKSR, &status); - pm_runtime_put_sync(isc_clk->dev); + pm_runtime_put(isc_clk->dev); return status & ISC_CLK(isc_clk->id) ? 1 : 0; } diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h index ad4e98a1dd8f..f5e322c2e36b 100644 --- a/drivers/media/platform/microchip/microchip-isc.h +++ b/drivers/media/platform/microchip/microchip-isc.h @@ -287,6 +287,7 @@ struct isc_device { u32 dcfg; struct device *dev; + int irq; struct v4l2_device v4l2_dev; struct video_device video_dev; diff --git a/drivers/media/platform/microchip/microchip-sama5d2-isc.c b/drivers/media/platform/microchip/microchip-sama5d2-isc.c index 88e6d8e1c6c9..5bd109e93a8f 100644 --- a/drivers/media/platform/microchip/microchip-sama5d2-isc.c +++ b/drivers/media/platform/microchip/microchip-sama5d2-isc.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -424,6 +425,14 @@ static int microchip_isc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, isc); isc->dev = dev; + ret = devm_mutex_init(dev, &isc->lock); + if (ret) + return ret; + + ret = devm_mutex_init(dev, &isc->awb_mutex); + if (ret) + return ret; + io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(io_base)) return PTR_ERR(io_base); @@ -439,6 +448,8 @@ static int microchip_isc_probe(struct platform_device *pdev) if (irq < 0) return irq; + isc->irq = irq; + ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0, "microchip-sama5d2-isc", isc); if (ret < 0) { diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c index 77c6c183451b..d978ce448a4d 100644 --- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c +++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -413,6 +414,14 @@ static int microchip_xisc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, isc); isc->dev = dev; + ret = devm_mutex_init(dev, &isc->lock); + if (ret) + return ret; + + ret = devm_mutex_init(dev, &isc->awb_mutex); + if (ret) + return ret; + io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(io_base)) return PTR_ERR(io_base); @@ -428,6 +437,8 @@ static int microchip_xisc_probe(struct platform_device *pdev) if (irq < 0) return irq; + isc->irq = irq; + ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0, "microchip-sama7g5-xisc", isc); if (ret < 0) { diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c index c4c5c318f786..d10bda3757ef 100644 --- a/drivers/media/platform/nuvoton/npcm-video.c +++ b/drivers/media/platform/nuvoton/npcm-video.c @@ -120,6 +120,7 @@ struct npcm_video { struct list_head buffers; struct mutex buffer_lock; /* buffer list lock */ + int irq; unsigned long flags; unsigned int sequence; @@ -1486,6 +1487,7 @@ static int npcm_video_start_streaming(struct vb2_queue *q, unsigned int count) } set_bit(VIDEO_STREAMING, &video->flags); + enable_irq(video->irq); return 0; } @@ -1494,6 +1496,7 @@ static void npcm_video_stop_streaming(struct vb2_queue *q) struct npcm_video *video = vb2_get_drv_priv(q); struct regmap *vcd = video->vcd_regmap; + disable_irq(video->irq); clear_bit(VIDEO_STREAMING, &video->flags); regmap_write(vcd, VCD_INTE, 0); regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); @@ -1707,9 +1710,10 @@ static int npcm_video_init(struct npcm_video *video) dev_err(dev, "Failed to find VCD IRQ\n"); return -ENODEV; } + video->irq = irq; rc = devm_request_threaded_irq(dev, irq, NULL, npcm_video_irq, - IRQF_ONESHOT, DEVICE_NAME, video); + IRQF_ONESHOT | IRQF_NO_AUTOEN, DEVICE_NAME, video); if (rc < 0) { dev_err(dev, "Failed to request IRQ %d\n", irq); return rc; @@ -1807,8 +1811,7 @@ static void npcm_video_remove(struct platform_device *pdev) struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); struct npcm_video *video = to_npcm_video(v4l2_dev); - video_unregister_device(&video->vdev); - vb2_queue_release(&video->queue); + vb2_video_unregister_device(&video->vdev); v4l2_ctrl_handler_free(&video->ctrl_handler); v4l2_device_unregister(v4l2_dev); if (video->ece.enable) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 4ac4f576fdd1..9f0794dd5c54 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -1525,15 +1525,15 @@ static void mxc_jpeg_device_run(void *priv) dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); if (!src_buf || !dst_buf) { dev_err(dev, "Null src or dst buf\n"); - goto end; + goto job_finish; } q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); if (!q_data_cap) - goto end; + goto buf_finish; q_data_out = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); if (!q_data_out) - goto end; + goto buf_finish; src_buf->sequence = q_data_out->sequence++; dst_buf->sequence = q_data_cap->sequence++; @@ -1571,11 +1571,11 @@ static void mxc_jpeg_device_run(void *priv) ctx->slot = mxc_get_free_slot(&jpeg->slot_data); if (ctx->slot < 0) { dev_err(dev, "No more free slots\n"); - goto end; + goto buf_finish; } if (!mxc_jpeg_alloc_slot_data(jpeg)) { dev_err(dev, "Cannot allocate slot data\n"); - goto end; + goto buf_finish; } mxc_jpeg_enable_slot(reg, ctx->slot); @@ -1597,8 +1597,17 @@ static void mxc_jpeg_device_run(void *priv) mxc_jpeg_dec_mode_go(dev, reg); } schedule_delayed_work(&ctx->task_timer, msecs_to_jiffies(hw_timeout)); -end: + spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags); + return; +buf_finish: + v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); +job_finish: + spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); } static int mxc_jpeg_decoder_cmd(struct file *file, void *priv, diff --git a/drivers/media/platform/qcom/camss/camss-vfe-17x.c b/drivers/media/platform/qcom/camss/camss-vfe-17x.c index e5ee7e717b3b..62c2405359a0 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-17x.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-17x.c @@ -364,9 +364,8 @@ static irqreturn_t vfe_isr(int irq, void *dev) vfe->isr_ops.comp_done(vfe, i); for (wm = 0; wm < MSM_VFE_IMAGE_MASTERS_NUM; wm++) - if (status0 & BIT(9)) - if (vfe_bus_status[1] & STATUS1_WM_CLIENT_BUF_DONE(wm)) - vfe->isr_ops.wm_done(vfe, wm); + if (vfe_bus_status[1] & STATUS1_WM_CLIENT_BUF_DONE(wm)) + vfe->isr_ops.wm_done(vfe, wm); return IRQ_HANDLED; } @@ -383,45 +382,6 @@ static int vfe_halt(struct vfe_device *vfe) return 0; } -static int vfe_get_output(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - struct vfe_output *output; - unsigned long flags; - int wm_idx; - - spin_lock_irqsave(&vfe->output_lock, flags); - - output = &line->output; - if (output->state > VFE_OUTPUT_RESERVED) { - dev_err(vfe->camss->dev, "Output is running\n"); - goto error; - } - - output->wm_num = 1; - - wm_idx = vfe_reserve_wm(vfe, line->id); - if (wm_idx < 0) { - dev_err(vfe->camss->dev, "Can not reserve wm\n"); - goto error_get_wm; - } - output->wm_idx[0] = wm_idx; - - output->drop_update_idx = 0; - - spin_unlock_irqrestore(&vfe->output_lock, flags); - - return 0; - -error_get_wm: - vfe_release_wm(vfe, output->wm_idx[0]); - output->state = VFE_OUTPUT_OFF; -error: - spin_unlock_irqrestore(&vfe->output_lock, flags); - - return -EINVAL; -} - /* * vfe_enable - Enable streaming on VFE line * @line: VFE line @@ -442,7 +402,7 @@ static int vfe_enable(struct vfe_line *line) mutex_unlock(&vfe->stream_lock); - ret = vfe_get_output(line); + ret = vfe_get_output_v2(line); if (ret < 0) goto error_get_output; diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 20e0d6604fa9..bf76ac3fd4c5 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -804,7 +804,7 @@ int vfe_put_output(struct vfe_line *line) return 0; } -static int vfe_disable_output(struct vfe_line *line) +static void vfe_disable_output(struct vfe_line *line) { struct vfe_device *vfe = to_vfe(line); struct vfe_output *output = &line->output; @@ -816,8 +816,6 @@ static int vfe_disable_output(struct vfe_line *line) vfe->res->hw_ops->vfe_wm_stop(vfe, output->wm_idx[i]); output->gen2.active_num = 0; spin_unlock_irqrestore(&vfe->output_lock, flags); - - return vfe_reset(vfe); } /* @@ -829,21 +827,19 @@ static int vfe_disable_output(struct vfe_line *line) int vfe_disable(struct vfe_line *line) { struct vfe_device *vfe = to_vfe(line); - int ret; + int ret = 0; - ret = vfe_disable_output(line); - if (ret) - goto error; + vfe_disable_output(line); vfe_put_output(line); mutex_lock(&vfe->stream_lock); - vfe->stream_count--; + if (--vfe->stream_count == 0) + ret = vfe_reset(vfe); mutex_unlock(&vfe->stream_lock); -error: return ret; } diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index c1148f6ad6b2..0fb43cb6348d 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -2926,10 +2926,11 @@ static const struct camss_subdev_resources vfe_res_8775p[] = { /* VFE2 (lite) */ { .regulators = {}, - .clock = { "cpas_ahb", "cpas_vfe_lite", "vfe_lite_ahb", - "vfe_lite_csid", "vfe_lite_cphy_rx", + .clock = { "cpas_ahb", "gcc_axi_hf", "cpas_vfe_lite", + "vfe_lite_ahb", "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "camnoc_axi"}, .clock_rate = { + { 0 }, { 0 }, { 0 }, { 300000000, 400000000, 400000000, 400000000 }, @@ -2951,10 +2952,11 @@ static const struct camss_subdev_resources vfe_res_8775p[] = { /* VFE3 (lite) */ { .regulators = {}, - .clock = { "cpas_ahb", "cpas_vfe_lite", "vfe_lite_ahb", - "vfe_lite_csid", "vfe_lite_cphy_rx", + .clock = { "cpas_ahb", "gcc_axi_hf", "cpas_vfe_lite", + "vfe_lite_ahb", "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "camnoc_axi"}, .clock_rate = { + { 0 }, { 0 }, { 0 }, { 300000000, 400000000, 400000000, 400000000 }, @@ -2976,10 +2978,11 @@ static const struct camss_subdev_resources vfe_res_8775p[] = { /* VFE4 (lite) */ { .regulators = {}, - .clock = { "cpas_ahb", "cpas_vfe_lite", "vfe_lite_ahb", - "vfe_lite_csid", "vfe_lite_cphy_rx", + .clock = { "cpas_ahb", "gcc_axi_hf", "cpas_vfe_lite", + "vfe_lite_ahb", "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "camnoc_axi"}, .clock_rate = { + { 0 }, { 0 }, { 0 }, { 300000000, 400000000, 400000000, 400000000 }, @@ -3001,10 +3004,11 @@ static const struct camss_subdev_resources vfe_res_8775p[] = { /* VFE5 (lite) */ { .regulators = {}, - .clock = { "cpas_ahb", "cpas_vfe_lite", "vfe_lite_ahb", - "vfe_lite_csid", "vfe_lite_cphy_rx", + .clock = { "cpas_ahb", "gcc_axi_hf", "cpas_vfe_lite", + "vfe_lite_ahb", "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "camnoc_axi"}, .clock_rate = { + { 0 }, { 0 }, { 0 }, { 300000000, 400000000, 400000000, 400000000 }, @@ -3026,10 +3030,11 @@ static const struct camss_subdev_resources vfe_res_8775p[] = { /* VFE6 (lite) */ { .regulators = {}, - .clock = { "cpas_ahb", "cpas_vfe_lite", "vfe_lite_ahb", - "vfe_lite_csid", "vfe_lite_cphy_rx", + .clock = { "cpas_ahb", "gcc_axi_hf", "cpas_vfe_lite", + "vfe_lite_ahb", "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "camnoc_axi"}, .clock_rate = { + { 0 }, { 0 }, { 0 }, { 300000000, 400000000, 400000000, 400000000 }, diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index 83b2b0e59f03..b916e8c8a645 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -434,14 +434,14 @@ static int iris_enum_frameintervals(struct file *filp, void *fh, mbpf = NUM_MBS_PER_FRAME(fival->height, fival->width); fps = DIV_ROUND_UP(core->iris_platform_data->max_core_mbps, mbpf); - fival->type = V4L2_FRMIVAL_TYPE_STEPWISE; + fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; fival->stepwise.min.numerator = 1; fival->stepwise.min.denominator = min_t(u32, fps, MAXIMUM_FPS); fival->stepwise.max.numerator = 1; fival->stepwise.max.denominator = 1; fival->stepwise.step.numerator = 1; - fival->stepwise.step.denominator = MAXIMUM_FPS; + fival->stepwise.step.denominator = 1; return 0; } @@ -462,7 +462,7 @@ static int iris_querycap(struct file *filp, void *fh, struct v4l2_capability *ca info = "enc"; } snprintf(cap->bus_info, sizeof(cap->bus_info), - "plat:%s:%s", dev_name(core->dev), info); + "platform:%s:%s", dev_name(core->dev), info); return 0; } diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 66a750ed1609..236934a0022a 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -374,6 +374,57 @@ static int venus_add_dynamic_nodes(struct venus_core *core) static void venus_remove_dynamic_nodes(struct venus_core *core) {} #endif +static void venus_unreserve_iova_region(struct device *dev, struct dma_iova_state *state) +{ + unsigned int i; + + for (i = 0; dma_iova_size(&state[i]); i++) + dma_iova_free(dev, &state[i]); +} + +static int venus_reserve_iova_region(struct device *dev, struct dma_iova_state **iova_state, + unsigned long start, unsigned long size) +{ + unsigned long dma_limit = dev->bus_dma_limit; + unsigned long end, rem, chunk; + struct dma_iova_state *state; + unsigned int count = 0; + int ret = -ENOMEM; + + state = devm_kcalloc(dev, BITS_PER_TYPE(dma_addr_t) + 1, sizeof(*state), GFP_KERNEL); + if (!state) + return ret; + + end = start + size; + rem = end - max(start, PAGE_SIZE); + dev->bus_dma_limit = end - 1; + + while (rem) { + chunk = min(end & -end, (u64)1 << (fls64(rem) - 1)); + + if (!dma_iova_try_alloc(dev, &state[count], 0, chunk)) + goto err_free_iova; + + if (state[count].addr != end - chunk || state[count].__size != chunk) + goto err_free_iova; + + rem -= chunk; + end -= chunk; + count++; + } + + *iova_state = state; + dev->bus_dma_limit = dma_limit; + + return 0; + +err_free_iova: + venus_unreserve_iova_region(dev, state); + dev->bus_dma_limit = dma_limit; + + return ret; +} + static int venus_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -418,10 +469,15 @@ static int venus_probe(struct platform_device *pdev) return ret; } - ret = dma_set_mask_and_coherent(dev, core->res->dma_mask); + ret = venus_reserve_iova_region(dev, &core->iova_state, VENUS_NP_RESERVE_IOVA_START, + VENUS_NP_RESERVE_IOVA_SIZE); if (ret) goto err_core_put; + ret = dma_set_mask_and_coherent(dev, core->res->dma_mask); + if (ret) + goto err_unresv_iova_region; + dma_set_max_seg_size(dev, UINT_MAX); INIT_LIST_HEAD(&core->instances); @@ -431,13 +487,13 @@ static int venus_probe(struct platform_device *pdev) ret = hfi_create(core, &venus_core_ops); if (ret) - goto err_core_put; + goto err_unresv_iova_region; ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, venus_isr_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "venus", core); if (ret) - goto err_core_put; + goto err_unresv_iova_region; venus_assign_register_offsets(core); @@ -522,6 +578,8 @@ static int venus_probe(struct platform_device *pdev) v4l2_device_unregister(&core->v4l2_dev); err_hfi_destroy: hfi_destroy(core); +err_unresv_iova_region: + venus_unreserve_iova_region(dev, core->iova_state); err_core_put: if (core->pm_ops->core_put) core->pm_ops->core_put(core); @@ -559,6 +617,8 @@ static void venus_remove(struct platform_device *pdev) hfi_destroy(core); + venus_unreserve_iova_region(dev, core->iova_state); + mutex_destroy(&core->pm_lock); mutex_destroy(&core->lock); venus_dbgfs_deinit(core); diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 70e7b40affa9..497e8f50290f 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -8,6 +8,7 @@ #define __VENUS_CORE_H_ #include +#include #include #include #include @@ -30,6 +31,9 @@ #define VENUS_MAX_FPS 240 +#define VENUS_NP_RESERVE_IOVA_START 0x0 +#define VENUS_NP_RESERVE_IOVA_SIZE 0x25800000 + extern int venus_fw_debug; struct freq_tbl { @@ -183,6 +187,7 @@ struct venus_format { * @dump_core: a flag indicating that a core dump is required * @ocs: OF changeset pointer * @hwmode_dev: a flag indicating that HW_CTRL_TRIGGER is used in clock driver + * @iova_state: a pointer to an array of dma_iova_state entries reserved for restricted IOVA region */ struct venus_core { void __iomem *base; @@ -243,6 +248,7 @@ struct venus_core { unsigned long dump_core; struct of_changeset *ocs; bool hwmode_dev; + struct dma_iova_state *iova_state; }; struct vdec_controls { diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c index 0ce293b0718b..0862fd14d41e 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c @@ -1209,9 +1209,8 @@ static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on) spin_unlock_irqrestore(&fimc->slock, flags); } } else { - set_bit(ST_FLITE_OFF, &fimc->state); - spin_lock_irqsave(&fimc->slock, flags); + set_bit(ST_FLITE_OFF, &fimc->state); flite_hw_capture_stop(fimc); spin_unlock_irqrestore(&fimc->slock, flags); diff --git a/drivers/media/platform/st/sti/delta/delta-mjpeg-hdr.c b/drivers/media/platform/st/sti/delta/delta-mjpeg-hdr.c index 90e5b2f72c82..849a5e118aec 100644 --- a/drivers/media/platform/st/sti/delta/delta-mjpeg-hdr.c +++ b/drivers/media/platform/st/sti/delta/delta-mjpeg-hdr.c @@ -4,6 +4,7 @@ * Author: Hugues Fruchet for STMicroelectronics. */ +#include #include "delta.h" #include "delta-mjpeg.h" @@ -48,13 +49,13 @@ static int delta_mjpeg_read_sof(struct delta_ctx *pctx, goto err_no_more; memset(header, 0, sizeof(*header)); - header->length = be16_to_cpu(*(__be16 *)(data + offset)); + header->length = get_unaligned_be16(data + offset); offset += sizeof(u16); header->sample_precision = *(u8 *)(data + offset); offset += sizeof(u8); - header->frame_height = be16_to_cpu(*(__be16 *)(data + offset)); + header->frame_height = get_unaligned_be16(data + offset); offset += sizeof(u16); - header->frame_width = be16_to_cpu(*(__be16 *)(data + offset)); + header->frame_width = get_unaligned_be16(data + offset); offset += sizeof(u16); header->nb_of_components = *(u8 *)(data + offset); offset += sizeof(u8); diff --git a/drivers/media/platform/st/stm32/stm32-csi.c b/drivers/media/platform/st/stm32/stm32-csi.c index fd2b6dfbd44c..78c68cf90ffc 100644 --- a/drivers/media/platform/st/stm32/stm32-csi.c +++ b/drivers/media/platform/st/stm32/stm32-csi.c @@ -825,7 +825,7 @@ static int stm32_csi_async_bound(struct v4l2_async_notifier *notifier, int remote_pad; remote_pad = media_entity_get_fwnode_pad(&s_subdev->entity, - s_subdev->fwnode, + asd->match.fwnode, MEDIA_PAD_FL_SOURCE); if (remote_pad < 0) { dev_err(csidev->dev, "Couldn't find output pad for subdev %s\n", @@ -1059,6 +1059,7 @@ static int stm32_csi_probe(struct platform_device *pdev) return 0; err_cleanup: + v4l2_async_nf_unregister(&csidev->notifier); v4l2_async_nf_cleanup(&csidev->notifier); return ret; } @@ -1067,6 +1068,8 @@ static void stm32_csi_remove(struct platform_device *pdev) { struct stm32_csi_dev *csidev = platform_get_drvdata(pdev); + v4l2_async_nf_unregister(&csidev->notifier); + v4l2_async_nf_cleanup(&csidev->notifier); v4l2_async_unregister_subdev(&csidev->sd); pm_runtime_disable(&pdev->dev); diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c index 8e6f452f76c7..22a5e137f5b6 100644 --- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c +++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c @@ -154,7 +154,6 @@ struct snps_hdmirx_dev { int num_clks; u32 edid_blocks_written; u32 cur_fmt_fourcc; - u32 color_depth; spinlock_t rst_lock; /* to lock register access */ u8 edid[EDID_NUM_BLOCKS_MAX * EDID_BLOCK_SIZE]; }; @@ -378,6 +377,38 @@ static void hdmirx_toggle_polarity(struct snps_hdmirx_dev *hdmirx_dev) VPROC_HSYNC_POL_OVR_EN, 0); } +static u32 hdmirx_get_colordepth(struct snps_hdmirx_dev *hdmirx_dev) +{ + struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; + u32 val, color_depth_reg, color_depth; + + val = hdmirx_readl(hdmirx_dev, DMA_STATUS11); + color_depth_reg = (val & HDMIRX_COLOR_DEPTH_MASK) >> 3; + + switch (color_depth_reg) { + case 0x4: + color_depth = 24; + break; + case 0x5: + color_depth = 30; + break; + case 0x6: + color_depth = 36; + break; + case 0x7: + color_depth = 48; + break; + default: + color_depth = 24; + break; + } + + v4l2_dbg(1, debug, v4l2_dev, "%s: color_depth: %d, reg_val:%d\n", + __func__, color_depth, color_depth_reg); + + return color_depth; +} + /* * When querying DV timings during preview, if the DMA's timing is stable, * we retrieve the timings directly from the DMA. However, if the current @@ -391,7 +422,7 @@ static int hdmirx_get_detected_timings(struct snps_hdmirx_dev *hdmirx_dev, struct v4l2_bt_timings *bt = &timings->bt; u32 val, tmdsqpclk_freq, pix_clk; unsigned int num_retries = 0; - u32 field_type, deframer_st; + u32 field_type, deframer_st, color_depth; u64 tmp_data, tmds_clk; bool is_dvi_mode; int ret; @@ -412,10 +443,11 @@ static int hdmirx_get_detected_timings(struct snps_hdmirx_dev *hdmirx_dev, deframer_st = hdmirx_readl(hdmirx_dev, DEFRAMER_STATUS); is_dvi_mode = !(deframer_st & OPMODE_STS_MASK); + color_depth = hdmirx_get_colordepth(hdmirx_dev); tmdsqpclk_freq = hdmirx_readl(hdmirx_dev, CMU_TMDSQPCLK_FREQ); tmds_clk = tmdsqpclk_freq * 4 * 1000; tmp_data = tmds_clk * 24; - do_div(tmp_data, hdmirx_dev->color_depth); + do_div(tmp_data, color_depth); pix_clk = tmp_data; bt->pixelclock = pix_clk; @@ -427,7 +459,7 @@ static int hdmirx_get_detected_timings(struct snps_hdmirx_dev *hdmirx_dev, v4l2_dbg(2, debug, v4l2_dev, "tmds_clk:%llu, pix_clk:%d\n", tmds_clk, pix_clk); v4l2_dbg(1, debug, v4l2_dev, "interlace:%d, fmt:%d, color:%d, mode:%s\n", bt->interlaced, hdmirx_dev->pix_fmt, - hdmirx_dev->color_depth, + color_depth, is_dvi_mode ? "dvi" : "hdmi"); v4l2_dbg(2, debug, v4l2_dev, "deframer_st:%#x\n", deframer_st); @@ -947,36 +979,6 @@ static void hdmirx_controller_init(struct snps_hdmirx_dev *hdmirx_dev) VS_REMAPFILTER_EN_QST | VS_FILTER_ORDER_QST(0x3)); } -static void hdmirx_get_colordepth(struct snps_hdmirx_dev *hdmirx_dev) -{ - struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; - u32 val, color_depth_reg; - - val = hdmirx_readl(hdmirx_dev, DMA_STATUS11); - color_depth_reg = (val & HDMIRX_COLOR_DEPTH_MASK) >> 3; - - switch (color_depth_reg) { - case 0x4: - hdmirx_dev->color_depth = 24; - break; - case 0x5: - hdmirx_dev->color_depth = 30; - break; - case 0x6: - hdmirx_dev->color_depth = 36; - break; - case 0x7: - hdmirx_dev->color_depth = 48; - break; - default: - hdmirx_dev->color_depth = 24; - break; - } - - v4l2_dbg(1, debug, v4l2_dev, "%s: color_depth: %d, reg_val:%d\n", - __func__, hdmirx_dev->color_depth, color_depth_reg); -} - static void hdmirx_get_pix_fmt(struct snps_hdmirx_dev *hdmirx_dev) { struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; @@ -1087,7 +1089,6 @@ static void hdmirx_format_change(struct snps_hdmirx_dev *hdmirx_dev) }; hdmirx_get_pix_fmt(hdmirx_dev); - hdmirx_get_colordepth(hdmirx_dev); hdmirx_get_avi_infoframe(hdmirx_dev); v4l2_dbg(1, debug, v4l2_dev, "%s: queue res_chg_event\n", __func__); @@ -2532,10 +2533,11 @@ static int hdmirx_setup_irq(struct snps_hdmirx_dev *hdmirx_dev, irq_set_status_flags(irq, IRQ_NOAUTOEN); hdmirx_dev->det_irq = irq; - ret = devm_request_irq(dev, irq, hdmirx_5v_det_irq_handler, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "rk_hdmirx-5v", hdmirx_dev); - if (ret) { + ret = devm_request_any_context_irq(dev, irq, hdmirx_5v_det_irq_handler, + IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING, + "rk_hdmirx-5v", hdmirx_dev); + if (ret < 0) { dev_err_probe(dev, ret, "failed to request hdmirx-5v irq\n"); return ret; } diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c index 9fbef2402574..5158417fe603 100644 --- a/drivers/media/platform/ti/davinci/vpif_capture.c +++ b/drivers/media/platform/ti/davinci/vpif_capture.c @@ -1603,7 +1603,7 @@ vpif_capture_get_pdata(struct platform_device *pdev, static int vpif_probe(struct platform_device *pdev) { struct vpif_subdev_info *subdevdata; - struct i2c_adapter *i2c_adap; + struct i2c_adapter *i2c_adap = NULL; int subdev_count; int res_idx = 0; int i, err; @@ -1693,9 +1693,12 @@ static int vpif_probe(struct platform_device *pdev) } } + i2c_put_adapter(i2c_adap); + return 0; probe_subdev_out: + i2c_put_adapter(i2c_adap); v4l2_async_nf_cleanup(&vpif_obj.notifier); /* free sub devices memory */ kfree(vpif_obj.sd); diff --git a/drivers/media/platform/ti/davinci/vpif_display.c b/drivers/media/platform/ti/davinci/vpif_display.c index 1e7815e9f8e0..ba16370b70f9 100644 --- a/drivers/media/platform/ti/davinci/vpif_display.c +++ b/drivers/media/platform/ti/davinci/vpif_display.c @@ -1289,9 +1289,12 @@ static int vpif_probe(struct platform_device *pdev) if (err) goto probe_subdev_out; + i2c_put_adapter(i2c_adap); + return 0; probe_subdev_out: + i2c_put_adapter(i2c_adap); kfree(vpif_obj.sd); vpif_unregister: v4l2_device_unregister(&vpif_obj.v4l2_dev); diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 418cfe3a1414..a35f6392c6fa 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -1212,7 +1212,7 @@ static int hantro_probe(struct platform_device *pdev) ret = clk_bulk_prepare(vpu->variant->num_clocks, vpu->clocks); if (ret) { dev_err(&pdev->dev, "Failed to prepare clocks\n"); - goto err_rst_assert; + goto err_pm_disable_assert_reset; } ret = v4l2_device_register(&pdev->dev, &vpu->v4l2_dev); @@ -1266,8 +1266,11 @@ static int hantro_probe(struct platform_device *pdev) v4l2_device_unregister(&vpu->v4l2_dev); err_clk_unprepare: clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks); -err_rst_assert: +err_pm_disable_assert_reset: + pm_runtime_dont_use_autosuspend(vpu->dev); + pm_runtime_disable(vpu->dev); reset_control_assert(vpu->resets); + return ret; err_pm_disable: pm_runtime_dont_use_autosuspend(vpu->dev); pm_runtime_disable(vpu->dev); @@ -1287,9 +1290,9 @@ static void hantro_remove(struct platform_device *pdev) v4l2_m2m_put(vpu->m2m_dev); v4l2_device_unregister(&vpu->v4l2_dev); clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks); - reset_control_assert(vpu->resets); pm_runtime_dont_use_autosuspend(vpu->dev); pm_runtime_disable(vpu->dev); + reset_control_assert(vpu->resets); } #ifdef CONFIG_PM diff --git a/drivers/media/platform/verisilicon/hantro_g1_mpeg2_dec.c b/drivers/media/platform/verisilicon/hantro_g1_mpeg2_dec.c index e0d6bd0a6e44..6a942f4b8a2d 100644 --- a/drivers/media/platform/verisilicon/hantro_g1_mpeg2_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g1_mpeg2_dec.c @@ -161,8 +161,13 @@ int hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) seq = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_MPEG2_SEQUENCE); + if (WARN_ON(!seq)) + return -EINVAL; + pic = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_MPEG2_PICTURE); + if (WARN_ON(!pic)) + return -EINVAL; reg = G1_REG_DEC_AXI_RD_ID(0) | G1_REG_DEC_TIMEOUT_E(1) | diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c index 00aa566a4ccd..2a145433e6d1 100644 --- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c +++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c @@ -369,6 +369,7 @@ void rockchip_vpu981_av1_dec_exit(struct hantro_ctx *ctx) int rockchip_vpu981_av1_dec_init(struct hantro_ctx *ctx) { + int ret = 0; struct hantro_dev *vpu = ctx->dev; struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec; @@ -377,39 +378,54 @@ int rockchip_vpu981_av1_dec_init(struct hantro_ctx *ctx) av1_dec->global_model.cpu = dma_alloc_coherent(vpu->dev, GLOBAL_MODEL_SIZE, &av1_dec->global_model.dma, GFP_KERNEL); - if (!av1_dec->global_model.cpu) - return -ENOMEM; + if (!av1_dec->global_model.cpu) { + ret = -ENOMEM; + goto global_model_cpu_err; + } + av1_dec->global_model.size = GLOBAL_MODEL_SIZE; av1_dec->tile_info.cpu = dma_alloc_coherent(vpu->dev, AV1_TILE_INFO_SIZE, &av1_dec->tile_info.dma, GFP_KERNEL); - if (!av1_dec->tile_info.cpu) - return -ENOMEM; + if (!av1_dec->tile_info.cpu) { + ret = -ENOMEM; + goto tile_info_cpu_err; + } + av1_dec->tile_info.size = AV1_TILE_INFO_SIZE; av1_dec->film_grain.cpu = dma_alloc_coherent(vpu->dev, ALIGN(sizeof(struct rockchip_av1_film_grain), 2048), &av1_dec->film_grain.dma, GFP_KERNEL); - if (!av1_dec->film_grain.cpu) - return -ENOMEM; + if (!av1_dec->film_grain.cpu) { + ret = -ENOMEM; + goto film_grain_cpu_err; + } + av1_dec->film_grain.size = ALIGN(sizeof(struct rockchip_av1_film_grain), 2048); av1_dec->prob_tbl.cpu = dma_alloc_coherent(vpu->dev, ALIGN(sizeof(struct av1cdfs), 2048), &av1_dec->prob_tbl.dma, GFP_KERNEL); - if (!av1_dec->prob_tbl.cpu) - return -ENOMEM; + if (!av1_dec->prob_tbl.cpu) { + ret = -ENOMEM; + goto prob_tbl_cpu_err; + } + av1_dec->prob_tbl.size = ALIGN(sizeof(struct av1cdfs), 2048); av1_dec->prob_tbl_out.cpu = dma_alloc_coherent(vpu->dev, ALIGN(sizeof(struct av1cdfs), 2048), &av1_dec->prob_tbl_out.dma, GFP_KERNEL); - if (!av1_dec->prob_tbl_out.cpu) - return -ENOMEM; + if (!av1_dec->prob_tbl_out.cpu) { + ret = -ENOMEM; + goto prob_tbl_out_cpu_err; + } + av1_dec->prob_tbl_out.size = ALIGN(sizeof(struct av1cdfs), 2048); av1_dec->cdfs = &av1_dec->default_cdfs; av1_dec->cdfs_ndvc = &av1_dec->default_cdfs_ndvc; @@ -420,11 +436,37 @@ int rockchip_vpu981_av1_dec_init(struct hantro_ctx *ctx) AV1_TILE_SIZE, &av1_dec->tile_buf.dma, GFP_KERNEL); - if (!av1_dec->tile_buf.cpu) - return -ENOMEM; + if (!av1_dec->tile_buf.cpu) { + ret = -ENOMEM; + goto tile_buf_cpu_err; + } + av1_dec->tile_buf.size = AV1_TILE_SIZE; - return 0; + return ret; + +tile_buf_cpu_err: + dma_free_coherent(vpu->dev, av1_dec->prob_tbl_out.size, + av1_dec->prob_tbl_out.cpu, + av1_dec->prob_tbl_out.dma); +prob_tbl_out_cpu_err: + dma_free_coherent(vpu->dev, av1_dec->prob_tbl.size, + av1_dec->prob_tbl.cpu, + av1_dec->prob_tbl.dma); +prob_tbl_cpu_err: + dma_free_coherent(vpu->dev, av1_dec->film_grain.size, + av1_dec->film_grain.cpu, + av1_dec->film_grain.dma); +film_grain_cpu_err: + dma_free_coherent(vpu->dev, av1_dec->tile_info.size, + av1_dec->tile_info.cpu, + av1_dec->tile_info.dma); +tile_info_cpu_err: + dma_free_coherent(vpu->dev, av1_dec->global_model.size, + av1_dec->global_model.cpu, + av1_dec->global_model.dma); +global_model_cpu_err: + return ret; } static int rockchip_vpu981_av1_dec_prepare_run(struct hantro_ctx *ctx) diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 136fc4192265..7598b623e4e8 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1103,15 +1103,15 @@ static void ene_remove(struct pnp_dev *pnp_dev) unsigned long flags; rc_unregister_device(dev->rdev); - timer_delete_sync(&dev->tx_sim_timer); spin_lock_irqsave(&dev->hw_lock, flags); ene_rx_disable(dev); ene_rx_restore_hw_buffer(dev); spin_unlock_irqrestore(&dev->hw_lock, flags); - rc_free_device(dev->rdev); free_irq(dev->irq, dev); + timer_delete_sync(&dev->tx_sim_timer); release_region(dev->hw_io, ENE_IO_SIZE); + rc_free_device(dev->rdev); kfree(dev); } diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index bb0f95833df5..04982ffde68f 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -316,6 +316,9 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) if (ret < 0) goto clkerr; + priv->rdev = rdev; + priv->dev = dev; + if (devm_request_irq(dev, priv->irq, hix5hd2_ir_rx_interrupt, 0, pdev->name, priv) < 0) { dev_err(dev, "IRQ %d register failed\n", priv->irq); @@ -323,8 +326,6 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) goto regerr; } - priv->rdev = rdev; - priv->dev = dev; platform_set_drvdata(pdev, priv); return ret; diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c index e79de56997a4..ba6c04212707 100644 --- a/drivers/media/rc/ir_toy.c +++ b/drivers/media/rc/ir_toy.c @@ -373,7 +373,7 @@ static int irtoy_tx_carrier(struct rc_dev *rc, uint32_t carrier) u8 buf[3]; int err; - if (carrier < 11800) + if (carrier < 11800 || carrier > 3000000) return -EINVAL; buf[0] = 0x06; diff --git a/drivers/media/rc/meson-ir-tx.c b/drivers/media/rc/meson-ir-tx.c index fded2c256f2a..a0d07da09f67 100644 --- a/drivers/media/rc/meson-ir-tx.c +++ b/drivers/media/rc/meson-ir-tx.c @@ -219,6 +219,9 @@ static int meson_irtx_set_carrier(struct rc_dev *rc, u32 carrier) if (carrier == 0) return -EINVAL; + if (!DIV_ROUND_CLOSEST(USEC_PER_SEC, carrier)) + return -EINVAL; + ir->carrier = carrier; meson_irtx_set_mod(ir); @@ -288,11 +291,12 @@ static int meson_irtx_mod_clock_probe(struct meson_irtx *ir, if (!np) return -ENODEV; - clock = devm_clk_get(ir->dev, "xtal"); - if (IS_ERR(clock) || clk_prepare_enable(clock)) - return -ENODEV; - *clk_nr = IRB_MOD_XTAL3_CLK; + + clock = devm_clk_get_enabled(ir->dev, "xtal"); + if (IS_ERR(clock)) + return PTR_ERR(clock); + ir->clk_rate = clk_get_rate(clock) / 3; if (ir->clk_rate < IRB_MOD_1US_CLK_RATE) { @@ -324,7 +328,7 @@ static int meson_irtx_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) - return -ENODEV; + return irq; ir->dev = dev; ir->carrier = MIRTX_DEFAULT_CARRIER; @@ -345,7 +349,7 @@ static int meson_irtx_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "irq request failed\n"); - rc = rc_allocate_device(RC_DRIVER_IR_RAW_TX); + rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW_TX); if (!rc) return -ENOMEM; @@ -358,10 +362,8 @@ static int meson_irtx_probe(struct platform_device *pdev) rc->s_tx_duty_cycle = meson_irtx_set_duty_cycle; ret = devm_rc_register_device(dev, rc); - if (ret < 0) { - rc_free_device(rc); + if (ret < 0) return dev_err_probe(dev, ret, "rc_dev registration failed\n"); - } return 0; } diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 3170bd72a8e6..c9a5c030f772 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -358,8 +358,24 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) /* process each rr3 encoded byte into an int */ sig_size = be16_to_cpu(rr3->irdata.sig_size); + + /* + * Note we are not checking if we are reading beyond the end of the + * packet which was sent, and reading stale data. If the device + * sends a packet which is short then we get garbage IR, but no + * out of bounds read. + */ + if (sig_size > RR3_MAX_SIG_SIZE) { + dev_err(dev, "length %u is incorrect\n", sig_size); + return; + } + for (i = 0; i < sig_size; i++) { offset = rr3->irdata.sigdata[i]; + if (offset >= RR3_DRIVER_MAXLENS) { + dev_err(dev, "offset %u is incorrect\n", offset); + return; + } val = get_unaligned_be16(&rr3->irdata.lens[offset]); /* we should always get pulse/space/pulse/space samples */ @@ -1154,6 +1170,7 @@ static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message) usb_kill_urb(rr3->narrow_urb); usb_kill_urb(rr3->wide_urb); usb_kill_urb(rr3->flash_urb); + usb_kill_urb(rr3->learn_urb); return 0; } diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c index 992fff82b524..f6702b3df9a0 100644 --- a/drivers/media/rc/serial_ir.c +++ b/drivers/media/rc/serial_ir.c @@ -798,7 +798,7 @@ static int __init serial_ir_init_module(void) static void __exit serial_ir_exit_module(void) { - timer_delete_sync(&serial_ir.timeout_timer); + timer_shutdown_sync(&serial_ir.timeout_timer); serial_ir_exit(); } diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index 8c85b9f30a3a..e91cf2ffbc87 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -365,6 +365,7 @@ static int streamzap_probe(struct usb_interface *intf, return 0; rc_submit_fail: + rc_unregister_device(sz->rdev); rc_free_device(sz->rdev); usb_set_intfdata(intf, NULL); rc_dev_fail: diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index 28e840a7e5b8..af1ee08ffdbe 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -374,8 +374,8 @@ static void sunxi_ir_remove(struct platform_device *pdev) struct sunxi_ir *ir = platform_get_drvdata(pdev); rc_unregister_device(ir->rc); - rc_free_device(ir->rc); sunxi_ir_hw_exit(&pdev->dev); + rc_free_device(ir->rc); } static void sunxi_ir_shutdown(struct platform_device *pdev) diff --git a/drivers/media/test-drivers/vicodec/codec-fwht.h b/drivers/media/test-drivers/vicodec/codec-fwht.h index 0eab24020e9e..4b4d39031089 100644 --- a/drivers/media/test-drivers/vicodec/codec-fwht.h +++ b/drivers/media/test-drivers/vicodec/codec-fwht.h @@ -61,7 +61,7 @@ * both luma and chroma components resolutions are rounded up to * a multiple of 8 */ -#define vic_round_dim(dim, div) (round_up((dim) / (div), 8) * (div)) +#define vic_round_dim(dim, div) round_up(dim, 8 * (div)) struct fwht_cframe_hdr { u32 magic1; diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index 654da27b1140..3052d248a728 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -652,7 +652,7 @@ static int job_ready(void *priv) * if the header is invalid the device_run will just drop the frame * with an error */ - if (!is_header_valid(&ctx->state.header) && ctx->comp_has_frame) + if (!is_header_valid(&ctx->state.header)) return 1; flags = ntohl(ctx->state.header.flags); hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; @@ -893,6 +893,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct vicodec_ctx *ctx = file2ctx(file); + struct vicodec_q_data *q_data_out = + get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); struct v4l2_pix_format_mplane *pix_mp; struct v4l2_pix_format *pix; @@ -903,6 +905,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, pix = &f->fmt.pix; pix->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT : find_fmt(f->fmt.pix.pixelformat)->id; + if (ctx->is_enc) { + pix->width = q_data_out->coded_width; + pix->height = q_data_out->coded_height; + } pix->colorspace = ctx->state.colorspace; pix->xfer_func = ctx->state.xfer_func; pix->ycbcr_enc = ctx->state.ycbcr_enc; @@ -914,6 +920,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, pix_mp = &f->fmt.pix_mp; pix_mp->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT : find_fmt(pix_mp->pixelformat)->id; + if (ctx->is_enc) { + pix_mp->width = q_data_out->coded_width; + pix_mp->height = q_data_out->coded_height; + } pix_mp->colorspace = ctx->state.colorspace; pix_mp->xfer_func = ctx->state.xfer_func; pix_mp->ycbcr_enc = ctx->state.ycbcr_enc; @@ -1596,9 +1606,9 @@ static int vicodec_start_streaming(struct vb2_queue *q, } state->ref_stride = q_data->coded_width * info->luma_alpha_step; - state->ref_frame.buf = kvmalloc(total_planes_size, GFP_KERNEL); + state->ref_frame.buf = kvzalloc(total_planes_size, GFP_KERNEL); state->ref_frame.luma = state->ref_frame.buf; - new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL); + new_comp_frame = kvzalloc(ctx->comp_max_size, GFP_KERNEL); if (!state->ref_frame.luma || !new_comp_frame) { kvfree(state->ref_frame.luma); diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c index 8a8e097d2ac9..60310ece3530 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c +++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c @@ -474,6 +474,7 @@ static int vidtv_bridge_dvb_init(struct vidtv_dvb *dvb) fail_demod_probe: for (i = i - 1; i >= 0; --i) { dvb_unregister_frontend(dvb->fe[i]); + dvb_frontend_detach(dvb->fe[i]); fail_fe: dvb_module_release(dvb->i2c_client_tuner[i]); fail_tuner_probe: @@ -550,8 +551,11 @@ static void vidtv_bridge_remove(struct platform_device *pdev) mutex_destroy(&dvb->feed_lock); + vidtv_stop_streaming(dvb); + for (i = 0; i < NUM_FE; ++i) { dvb_unregister_frontend(dvb->fe[i]); + dvb_frontend_detach(dvb->fe[i]); dvb_module_release(dvb->i2c_client_tuner[i]); dvb_module_release(dvb->i2c_client_demod[i]); } diff --git a/drivers/media/test-drivers/vidtv/vidtv_demod.c b/drivers/media/test-drivers/vidtv/vidtv_demod.c index 505f96fccbf3..36bfeb33476b 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_demod.c +++ b/drivers/media/test-drivers/vidtv/vidtv_demod.c @@ -343,13 +343,6 @@ static int vidtv_diseqc_send_burst(struct dvb_frontend *fe, return 0; } -static void vidtv_demod_release(struct dvb_frontend *fe) -{ - struct vidtv_demod_state *state = fe->demodulator_priv; - - kfree(state); -} - static const struct dvb_frontend_ops vidtv_demod_ops = { .delsys = { SYS_DVBT, @@ -390,8 +383,6 @@ static const struct dvb_frontend_ops vidtv_demod_ops = { FE_CAN_HIERARCHY_AUTO, }, - .release = vidtv_demod_release, - .set_frontend = vidtv_demod_set_frontend, .get_frontend = vidtv_demod_get_frontend, diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c index 86c32699111a..5db440bf728e 100644 --- a/drivers/media/test-drivers/vim2m.c +++ b/drivers/media/test-drivers/vim2m.c @@ -205,6 +205,7 @@ struct vim2m_ctx { struct vim2m_dev *dev; struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *trans_num_bufs_ctrl; /* Processed buffers in this transaction */ u8 num_processed; @@ -1270,9 +1271,27 @@ static int vim2m_start_streaming(struct vb2_queue *q, unsigned int count) ctx->aborting = 0; q_data->sequence = 0; + v4l2_ctrl_grab(ctx->trans_num_bufs_ctrl, true); + return 0; } +static bool vim2m_other_queue_is_streaming(struct vim2m_ctx *ctx, + struct vb2_queue *q) +{ + struct vb2_queue *other_vq; + + if (!ctx->fh.m2m_ctx) + return false; + + if (V4L2_TYPE_IS_OUTPUT(q->type)) + other_vq = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx); + else + other_vq = v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx); + + return vb2_is_streaming(other_vq); +} + static void vim2m_stop_streaming(struct vb2_queue *q) { struct vim2m_ctx *ctx = vb2_get_drv_priv(q); @@ -1286,11 +1305,14 @@ static void vim2m_stop_streaming(struct vb2_queue *q) else vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); if (!vbuf) - return; + break; v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, &ctx->hdl); v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); } + + if (!vim2m_other_queue_is_streaming(ctx, q)) + v4l2_ctrl_grab(ctx->trans_num_bufs_ctrl, false); } static void vim2m_buf_request_complete(struct vb2_buffer *vb) @@ -1392,7 +1414,8 @@ static int vim2m_open(struct file *file) vim2m_ctrl_trans_time_msec.def = default_transtime; v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL); - v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_num_bufs, NULL); + ctx->trans_num_bufs_ctrl = + v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_num_bufs, NULL); if (hdl->error) { rc = hdl->error; v4l2_ctrl_handler_free(hdl); @@ -1447,10 +1470,10 @@ static int vim2m_release(struct file *file) v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); - v4l2_ctrl_handler_free(&ctx->hdl); mutex_lock(&dev->dev_mutex); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mutex_unlock(&dev->dev_mutex); + v4l2_ctrl_handler_free(&ctx->hdl); kfree(ctx); atomic_dec(&dev->num_inst); diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index f44930502bda..64a15a24a9c3 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -854,6 +854,7 @@ static void vivid_dev_release(struct v4l2_device *v4l2_dev) struct vivid_dev *dev = container_of(v4l2_dev, struct vivid_dev, v4l2_dev); cancel_work_sync(&dev->update_hdmi_ctrl_work); + cancel_work_sync(&dev->update_svid_ctrl_work); vivid_free_controls(dev); v4l2_device_unregister(&dev->v4l2_dev); #ifdef CONFIG_MEDIA_CONTROLLER diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c index d1c09bdb2f3b..cc2b704717f3 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c @@ -568,6 +568,7 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, const struct vivid_fmt *fmt; unsigned bytesperline, max_bpl; unsigned factor = 1; + unsigned int vdiv = 1; unsigned w, h; unsigned p; bool user_set_csc = !!(mp->flags & V4L2_PIX_FMT_FLAG_SET_CSC); @@ -620,6 +621,18 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, mp->height = r.height / factor; } + /* + * The chroma planes of vertically subsampled formats hold + * height / vdownsampling lines. If the height is not a multiple of + * the subsampling factor, then the buffer size calculations round + * that number down while the test pattern generator rounds it up, + * so the generator writes one line past the end of the buffer. + * Round the height down to keep both in sync. + */ + for (p = 0; p < fmt->planes; p++) + vdiv = max(vdiv, fmt->vdownsampling[p]); + mp->height = rounddown(mp->height, vdiv); + /* This driver supports custom bytesperline values */ mp->num_planes = fmt->buffers; diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 1e246b47766d..c7ff52044bd2 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -697,6 +697,10 @@ static int au0828_usb_probe(struct usb_interface *interface, retval = au0828_v4l2_device_register(interface, dev); if (retval) { au0828_usb_v4l2_media_release(dev); +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_delete(dev->media_dev, KBUILD_MODNAME, + THIS_MODULE); +#endif mutex_unlock(&dev->lock); kfree(dev); return retval; diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index 51752a922a74..4dc637746685 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -163,9 +163,6 @@ static int stop_urb_transfer(struct au0828_dev *dev) dprintk(2, "%s()\n", __func__); - if (!dev->urb_streaming) - return 0; - if (dev->bulk_timeout_running == 1) { dev->bulk_timeout_running = 0; timer_delete(&dev->bulk_timeout); @@ -179,6 +176,7 @@ static int stop_urb_transfer(struct au0828_dev *dev) kfree(dev->urbs[i]->transfer_buffer); usb_free_urb(dev->urbs[i]); + dev->urbs[i] = NULL; } } @@ -200,8 +198,10 @@ static int start_urb_transfer(struct au0828_dev *dev) for (i = 0; i < URB_COUNT; i++) { dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->urbs[i]) - return -ENOMEM; + if (!dev->urbs[i]) { + ret = -ENOMEM; + goto err; + } purb = dev->urbs[i]; @@ -217,7 +217,7 @@ static int start_urb_transfer(struct au0828_dev *dev) ret = -ENOMEM; pr_err("%s: failed big buffer allocation, err = %d\n", __func__, ret); - return ret; + goto err; } purb->status = -EINPROGRESS; @@ -235,10 +235,9 @@ static int start_urb_transfer(struct au0828_dev *dev) for (i = 0; i < URB_COUNT; i++) { ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC); if (ret != 0) { - stop_urb_transfer(dev); pr_err("%s: failed urb submission, err = %d\n", __func__, ret); - return ret; + goto err; } } @@ -249,6 +248,10 @@ static int start_urb_transfer(struct au0828_dev *dev) dev->bulk_timeout_running = 1; return 0; + +err: + stop_urb_transfer(dev); + return ret; } static void au0828_start_transport(struct au0828_dev *dev) diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index 9c71b32552df..1179cb0334f4 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c @@ -576,12 +576,19 @@ static int cx231xx_audio_init(struct cx231xx *dev) dev_dbg(dev->dev, "probing for cx231xx non standard usbaudio\n"); + /* + * Extension init errors are ignored by the cx231xx core, so fini() + * must be safe even if initialization fails part way through. + */ + spin_lock_init(&adev->slock); + INIT_WORK(&dev->wq_trigger, audio_trigger); + atomic_set(&dev->stream_started, 0); + err = snd_card_new(dev->dev, index[devnr], "Cx231xx Audio", THIS_MODULE, 0, &card); if (err < 0) return err; - spin_lock_init(&adev->slock); err = snd_pcm_new(card, "Cx231xx Audio", 0, 0, 1, &pcm); if (err < 0) goto err_free_card; @@ -596,8 +603,6 @@ static int cx231xx_audio_init(struct cx231xx *dev) strscpy(card->shortname, "Cx231xx Audio", sizeof(card->shortname)); strscpy(card->longname, "Conexant cx231xx Audio", sizeof(card->longname)); - INIT_WORK(&dev->wq_trigger, audio_trigger); - err = snd_card_register(card); if (err < 0) goto err_free_card; @@ -651,8 +656,10 @@ static int cx231xx_audio_init(struct cx231xx *dev) err_free_pkt_size: kfree(adev->alt_max_pkt_size); + adev->alt_max_pkt_size = NULL; err_free_card: snd_card_free(card); + adev->sndcard = NULL; return err; } @@ -669,6 +676,8 @@ static int cx231xx_audio_fini(struct cx231xx *dev) return 0; } + disable_work_sync(&dev->wq_trigger); + if (dev->adev.sndcard) { snd_card_free_when_closed(dev->adev.sndcard); kfree(dev->adev.alt_max_pkt_size); diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index d96b9ab276b7..1824e36e541f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -1828,7 +1828,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, retval = cx231xx_init_v4l2(dev, udev, interface, isoc_pipe); if (retval) - goto err_init; + goto err_video_alt; if (dev->current_pcb_config.ts1_source != 0xff) { /* compute alternate max packet sizes for TS1 */ diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 19f5036a78d7..f85d054fbb5c 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -463,7 +463,7 @@ struct cx231xx_i2c_xfer_data { u8 direction; /* 1 - IN, 0 - OUT */ u8 saddr_len; /* sub address len */ u16 saddr_dat; /* sub addr data */ - u8 buf_size; /* buffer size */ + u16 buf_size; /* buffer size */ u8 *p_buffer; /* pointer to the buffer */ }; diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 487c6ab784ab..d2957e4bf017 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -1391,8 +1391,16 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) "rtl2832_sdr", PLATFORM_DEVID_AUTO, &pdata, sizeof(pdata)); - if (IS_ERR(pdev) || pdev->dev.driver == NULL) + if (IS_ERR(pdev)) break; + if (!pdev->dev.driver) { + platform_device_unregister(pdev); + break; + } + if (!try_module_get(pdev->dev.driver->owner)) { + platform_device_unregister(pdev); + break; + } dev->platform_device_sdr = pdev; break; default: @@ -1426,8 +1434,10 @@ static int rtl28xxu_tuner_detach(struct dvb_usb_adapter *adap) /* remove platform SDR */ pdev = dev->platform_device_sdr; - if (pdev) + if (pdev) { + module_put(pdev->dev.driver->owner); platform_device_unregister(pdev); + } /* remove I2C tuner */ client = dev->i2c_client_tuner; diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 1012bfb18646..555281387513 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -949,9 +949,6 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, usb_bufs->buf[i] = kzalloc(sb_size, GFP_KERNEL); if (!usb_bufs->buf[i]) { - for (i--; i >= 0; i--) - kfree(usb_bufs->buf[i]); - em28xx_uninit_usb_xfer(dev, mode); return -ENOMEM; } diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c index 334cdde81a5c..ad9cc44660dd 100644 --- a/drivers/media/usb/go7007/go7007-usb.c +++ b/drivers/media/usb/go7007/go7007-usb.c @@ -1029,10 +1029,16 @@ static const struct i2c_algorithm go7007_usb_algo = { .functionality = go7007_usb_functionality, }; +static const struct i2c_adapter_quirks go7007_usb_quirks = { + .max_write_len = 12, + .max_read_len = 15, +}; + static struct i2c_adapter go7007_usb_adap_templ = { .owner = THIS_MODULE, .name = "WIS GO7007SB EZ-USB", .algo = &go7007_usb_algo, + .quirks = &go7007_usb_quirks, }; /********************* USB add/remove functions *********************/ @@ -1320,6 +1326,8 @@ static int go7007_usb_probe(struct usb_interface *intf, return 0; allocfail: + if (go->i2c_adapter_online) + i2c_del_adapter(&go->i2c_adapter); go7007_usb_release(go); kfree(go); return -ENOMEM; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c index 3077399901aa..dd6fcc6245af 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c @@ -633,6 +633,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp) if (ret) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "device_register failed"); + put_device(class_dev->parent); put_device(class_dev); return; } diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 2738ef74c737..7fd2e03f92e6 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -2010,7 +2010,7 @@ bool uvc_ctrl_status_event_async(struct urb *urb, struct uvc_video_chain *chain, struct uvc_device *dev = chain->dev; struct uvc_ctrl_work *w = &dev->async_ctrl; - if (list_empty(&ctrl->info.mappings)) + if (!ctrl->initialized || list_empty(&ctrl->info.mappings)) return false; w->data = data; diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 524c11e92aec..0ca98df9e60b 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -296,7 +296,7 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) { .format = V4L2_PIX_FMT_NV20, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 1 }, { .format = V4L2_PIX_FMT_NV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_P010, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_P010, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, { .format = V4L2_PIX_FMT_P012, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, { .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 4, .vdiv = 4 }, diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c index 02e2ae93d176..579787f0be35 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -2431,7 +2431,10 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls) int i; /* The first control is the master control and it must not be NULL */ - if (WARN_ON(ncontrols == 0 || controls[0] == NULL)) + if (WARN_ON(ncontrols == 0)) + return; + + if (!controls[0]) return; for (i = 0; i < ncontrols; i++) { @@ -2453,8 +2456,13 @@ void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls, u32 flag = 0; int i; + if (WARN_ON(ncontrols <= 1)) + return; + + if (!master) + return; + v4l2_ctrl_cluster(ncontrols, controls); - WARN_ON(ncontrols <= 1); WARN_ON(manual_val < master->minimum || manual_val > master->maximum); WARN_ON(set_volatile && !has_op(master, g_volatile_ctrl)); master->is_auto = true; diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c index 08d9e05b1b33..7b02c36c7fca 100644 --- a/drivers/memory/brcmstb_dpfe.c +++ b/drivers/memory/brcmstb_dpfe.c @@ -182,6 +182,8 @@ struct brcmstb_dpfe_priv { void __iomem *regs; void __iomem *dmem; void __iomem *imem; + resource_size_t regs_size; + resource_size_t dmem_size; struct device *dev; const struct dpfe_api *dpfe_api; struct mutex lock; @@ -401,9 +403,14 @@ static void __iomem *get_msg_ptr(struct brcmstb_dpfe_priv *priv, u32 response, */ switch (msg_type) { case 1: + if (DCPU_MSG_RAM_START + offset + DRAM_VENDOR_ERROR + + sizeof(u32) > priv->regs_size) + goto bad_offset; ptr = priv->regs + DCPU_MSG_RAM_START + offset; break; case 0: + if (offset + DRAM_VENDOR_ERROR + sizeof(u32) > priv->dmem_size) + goto bad_offset; ptr = priv->dmem + offset; break; default: @@ -415,6 +422,12 @@ static void __iomem *get_msg_ptr(struct brcmstb_dpfe_priv *priv, u32 response, } return ptr; + +bad_offset: + dev_err(priv->dev, "DCPU returned out-of-range offset %#x\n", offset); + if (buf && size) + *size = sprintf(buf, "ERROR: DCPU offset out of range\n"); + return NULL; } static void __finalize_command(struct brcmstb_dpfe_priv *priv) @@ -490,6 +503,8 @@ static int __send_command(struct brcmstb_dpfe_priv *priv, unsigned int cmd, for (i = 0; i < MSG_FIELD_MAX; i++) result[i] = readl_relaxed(regs + DCPU_MSG_RAM(i)); chksum_idx = result[MSG_ARG_COUNT] + MSG_ARG_COUNT + 1; + if (chksum_idx >= MSG_FIELD_MAX) + ret = -EINVAL; } /* Tell DCPU we are done */ @@ -858,6 +873,7 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct brcmstb_dpfe_priv *priv; + struct resource *res; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -869,17 +885,21 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev) mutex_init(&priv->lock); platform_set_drvdata(pdev, priv); - priv->regs = devm_platform_ioremap_resource_byname(pdev, "dpfe-cpu"); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dpfe-cpu"); + priv->regs = devm_ioremap_resource(dev, res); if (IS_ERR(priv->regs)) { dev_err(dev, "couldn't map DCPU registers\n"); return -ENODEV; } + priv->regs_size = resource_size(res); - priv->dmem = devm_platform_ioremap_resource_byname(pdev, "dpfe-dmem"); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dpfe-dmem"); + priv->dmem = devm_ioremap_resource(dev, res); if (IS_ERR(priv->dmem)) { dev_err(dev, "Couldn't map DCPU data memory\n"); return -ENOENT; } + priv->dmem_size = resource_size(res); priv->imem = devm_platform_ioremap_resource_byname(pdev, "dpfe-imem"); if (IS_ERR(priv->imem)) { diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 4a417b693080..7f75052b6ae3 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -34,6 +34,7 @@ static const struct regmap_access_table rpcif_volatile_table = { static const struct regmap_range xspi_volatile_ranges[] = { regmap_reg_range(XSPI_CDD0BUF0, XSPI_CDD0BUF0), + regmap_reg_range(XSPI_CDD1BUF0, XSPI_CDD1BUF0), }; static const struct regmap_access_table xspi_volatile_table = { diff --git a/drivers/memory/stm32_omm.c b/drivers/memory/stm32_omm.c index 2a1af229d244..faef90334249 100644 --- a/drivers/memory/stm32_omm.c +++ b/drivers/memory/stm32_omm.c @@ -275,6 +275,8 @@ static int stm32_omm_configure(struct device *dev) writel_relaxed(omm->cr, omm->io_base + OMM_CR); ret = stm32_omm_set_amcr(dev, true); + if (ret && (mux & CR_MUXEN)) + stm32_omm_toggle_child_clock(dev, false); error: pm_runtime_put_sync_suspend(dev); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 55a9fea95195..ae39cbf31710 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -989,6 +989,8 @@ config MFD_MAX77705 depends on I2C select MFD_CORE select MFD_SIMPLE_MFD_I2C + select REGMAP_I2C + select REGMAP_IRQ help Say yes here to add support for Maxim Integrated MAX77705 PMIC. This is a Power Management IC with Charger, safe LDOs, Flash, Haptic diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index e86b39de3303..e4ad48e1f139 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -421,6 +421,14 @@ static irqreturn_t da903x_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static void da903x_cancel_irq_work(void *data) +{ + struct da903x_chip *chip = data; + + disable_irq(chip->client->irq); + cancel_work_sync(&chip->irq_work); +} + static const struct da903x_chip_ops da903x_ops[] = { [0] = { .init_chip = da9030_init_chip, @@ -456,6 +464,13 @@ static int da903x_remove_subdevs(struct da903x_chip *chip) return device_for_each_child(chip->dev, NULL, __remove_subdev); } +static void da903x_remove_subdevs_action(void *data) +{ + struct da903x_chip *chip = data; + + da903x_remove_subdevs(chip); +} + static int da903x_add_subdevs(struct da903x_chip *chip, struct da903x_platform_data *pdata) { @@ -484,7 +499,6 @@ static int da903x_add_subdevs(struct da903x_chip *chip, return 0; failed: - da903x_remove_subdevs(chip); return ret; } @@ -520,6 +534,11 @@ static int da903x_probe(struct i2c_client *client) chip->ops->mask_events(chip, chip->events_mask); chip->ops->read_events(chip, &tmp); + ret = devm_add_action_or_reset(&client->dev, + da903x_remove_subdevs_action, chip); + if (ret) + return ret; + ret = devm_request_irq(&client->dev, client->irq, da903x_irq_handler, IRQF_TRIGGER_FALLING, "da903x", chip); @@ -529,14 +548,12 @@ static int da903x_probe(struct i2c_client *client) return ret; } - return da903x_add_subdevs(chip, pdata); -} - -static void da903x_remove(struct i2c_client *client) -{ - struct da903x_chip *chip = i2c_get_clientdata(client); + ret = devm_add_action_or_reset(&client->dev, da903x_cancel_irq_work, + chip); + if (ret) + return ret; - da903x_remove_subdevs(chip); + return da903x_add_subdevs(chip, pdata); } static struct i2c_driver da903x_driver = { @@ -544,7 +561,6 @@ static struct i2c_driver da903x_driver = { .name = "da903x", }, .probe = da903x_probe, - .remove = da903x_remove, .id_table = da903x_id_table, }; diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index c240fac0ede7..569c28c8b20f 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -146,6 +146,31 @@ static const struct irq_domain_ops tps65217_irq_domain_ops = { .map = tps65217_irq_map, }; +static void tps65217_irq_cleanup(void *data) +{ + struct tps65217 *tps = data; + unsigned int virq; + + if (!tps->irq_domain) + return; + + for (int i = 0; i < TPS65217_NUM_IRQ; i++) { + virq = irq_find_mapping(tps->irq_domain, i); + if (virq) + irq_dispose_mapping(virq); + } + + irq_domain_remove(tps->irq_domain); + tps->irq_domain = NULL; +} + +static void tps65217_irq_wake_disable(void *data) +{ + unsigned long irq = (unsigned long)data; + + disable_irq_wake(irq); +} + static int tps65217_irq_init(struct tps65217 *tps, int irq) { int ret; @@ -155,8 +180,12 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq) /* Mask all interrupt sources */ tps->irq_mask = TPS65217_INT_MASK; - tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK, - TPS65217_INT_MASK, TPS65217_PROTECT_NONE); + ret = tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK, + TPS65217_INT_MASK, TPS65217_PROTECT_NONE); + if (ret) { + dev_err(tps->dev, "Failed to mask interrupt sources: %d\n", ret); + return ret; + } tps->irq_domain = irq_domain_create_linear(dev_fwnode(tps->dev), TPS65217_NUM_IRQ, &tps65217_irq_domain_ops, tps); @@ -165,6 +194,10 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq) return -ENOMEM; } + ret = devm_add_action_or_reset(tps->dev, tps65217_irq_cleanup, tps); + if (ret) + return ret; + ret = devm_request_threaded_irq(tps->dev, irq, NULL, tps65217_irq_thread, IRQF_ONESHOT, "tps65217-irq", tps); @@ -174,7 +207,16 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq) return ret; } - enable_irq_wake(irq); + ret = enable_irq_wake(irq); + if (ret) { + dev_warn(tps->dev, "failed to enable IRQ wake: %d\n", ret); + return 0; + } + + ret = devm_add_action_or_reset(tps->dev, tps65217_irq_wake_disable, + (void *)(unsigned long)irq); + if (ret) + return ret; return 0; } @@ -333,7 +375,9 @@ static int tps65217_probe(struct i2c_client *client) } if (client->irq) { - tps65217_irq_init(tps, client->irq); + ret = tps65217_irq_init(tps, client->irq); + if (ret) + return ret; } else { int i; @@ -373,22 +417,6 @@ static int tps65217_probe(struct i2c_client *client) return 0; } -static void tps65217_remove(struct i2c_client *client) -{ - struct tps65217 *tps = i2c_get_clientdata(client); - unsigned int virq; - int i; - - for (i = 0; i < TPS65217_NUM_IRQ; i++) { - virq = irq_find_mapping(tps->irq_domain, i); - if (virq) - irq_dispose_mapping(virq); - } - - irq_domain_remove(tps->irq_domain); - tps->irq_domain = NULL; -} - static const struct i2c_device_id tps65217_id_table[] = { {"tps65217", TPS65217}, { /* sentinel */ } @@ -402,7 +430,6 @@ static struct i2c_driver tps65217_driver = { }, .id_table = tps65217_id_table, .probe = tps65217_probe, - .remove = tps65217_remove, }; static int __init tps65217_init(void) diff --git a/drivers/mfd/wcd934x.c b/drivers/mfd/wcd934x.c index 3c3080e8c8cf..d57796933d87 100644 --- a/drivers/mfd/wcd934x.c +++ b/drivers/mfd/wcd934x.c @@ -2,6 +2,7 @@ // Copyright (c) 2019, Linaro Limited #include +#include #include #include #include @@ -217,13 +218,18 @@ static int wcd934x_slim_probe(struct slim_device *sdev) struct gpio_desc *reset_gpio; int ret; + ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) + return dev_err_probe(dev, ret, + "Failed to set DMA mask\n"); + ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); if (!ddata) return -ENOMEM; ddata->irq = of_irq_get(np, 0); if (ddata->irq < 0) - return dev_err_probe(ddata->dev, ddata->irq, + return dev_err_probe(dev, ddata->irq, "Failed to get IRQ\n"); ddata->extclk = devm_clk_get(dev, "extclk"); diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c index 5ecf99883996..e70c07aa0d60 100644 --- a/drivers/misc/mei/vsc-tp.c +++ b/drivers/misc/mei/vsc-tp.c @@ -293,7 +293,7 @@ int vsc_tp_xfer(struct vsc_tp *tp, u8 cmd, const void *obuf, size_t olen, pkt->hdr.seq = cpu_to_le32(++tp->seq); memcpy(pkt->buf, obuf, olen); - crc = ~crc32(~0, (u8 *)pkt, sizeof(pkt) + olen); + crc = ~crc32(~0, (u8 *)pkt, sizeof(pkt->hdr) + olen); memcpy(pkt->buf + olen, &crc, sizeof(crc)); ret = vsc_tp_wakeup_request(tp); diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 7c91429a670b..c8a82b1592c9 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -283,6 +283,21 @@ static void fixup_use_write_buffers(struct mtd_info *mtd) pr_debug("Using buffer write method\n"); mtd->_write = cfi_amdstd_write_buffers; } + + /* + * The word count of the Write to Buffer command is a single bus + * word per device, so an x8 device can be told to program at most + * 256 bytes however large a buffer it advertises - including when + * several of them are interleaved on a wider bus, where CMD() + * replicates the count into each device's lane and it is truncated + * there. + */ + if (cfi->device_type == CFI_DEVICETYPE_X8 && + cfi->cfiq->MaxBufWriteSize > 8) { + cfi->cfiq->MaxBufWriteSize = 8; + mtd->writebufsize = cfi_interleave(cfi) << + cfi->cfiq->MaxBufWriteSize; + } } #endif /* !FORCE_WORD_WRITE */ diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 281fcbaa74e7..43411ec02ed5 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -152,6 +152,8 @@ static int amd76xrom_init_one(struct pci_dev *pdev, printk(KERN_ERR MOD_NAME " %s(): Unable to register resource %pR - kernel bug?\n", __func__, &window->rsrc); + pci_dev_put(window->pdev); + window->pdev = NULL; return -EBUSY; } diff --git a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c index 832b880d1aaf..1df5ea5fafca 100644 --- a/drivers/mtd/maps/l440gx.c +++ b/drivers/mtd/maps/l440gx.c @@ -110,8 +110,6 @@ static int __init init_l440gx(void) /* Allocate the resource region */ if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) { - pci_dev_put(dev); - pci_dev_put(pm_dev); printk(KERN_WARNING "Could not allocate pm iobase resource\n"); iounmap(l440gx_map.virt); return -ENXIO; diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index ca00d211e73e..c6bbce6aed41 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c @@ -256,7 +256,7 @@ static int mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) struct mtd_info *mtd = NULL; int err; - err = pci_enable_device(dev); + err = pcim_enable_device(dev); if (err) goto out; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 51c8ed489348..f84e4213b678 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -562,7 +562,7 @@ int mtd_pairing_info_to_wunit(struct mtd_info *mtd, return -EINVAL; if (master->pairing && master->pairing->get_wunit) - return mtd->pairing->get_wunit(master, info); + return master->pairing->get_wunit(master, info); return info->pair; } diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index b7e3763c47f0..22ddeaa7d522 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -31,8 +31,10 @@ static int mtd_get_sb(struct fs_context *fc, int ret; sb = sget_dev(fc, MKDEV(MTD_BLOCK_MAJOR, mtd->index)); - if (IS_ERR(sb)) + if (IS_ERR(sb)) { + put_mtd_device(mtd); return PTR_ERR(sb); + } if (sb->s_root) { /* new mountpoint for an already mounted superblock */ diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 83ba4ebd02d4..b954e70b4c6b 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -2086,7 +2086,7 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc, if (!np) { dev_err(dev, "Missing or invalid atmel,smc property\n"); ret = -EINVAL; - goto out_release_dma; + goto out_put_mck; } nc->smc = syscon_node_to_regmap(np); @@ -2094,11 +2094,13 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc, if (IS_ERR(nc->smc)) { ret = PTR_ERR(nc->smc); dev_err(dev, "Could not get SMC regmap (err = %d)\n", ret); - goto out_release_dma; + goto out_put_mck; } return 0; +out_put_mck: + clk_put(nc->mck); out_release_dma: if (nc->dmac) dma_release_channel(nc->dmac); diff --git a/drivers/mtd/nand/raw/nuvoton-ma35d1-nand-controller.c b/drivers/mtd/nand/raw/nuvoton-ma35d1-nand-controller.c index 1a285cd8fad6..f659d3a6b9ef 100644 --- a/drivers/mtd/nand/raw/nuvoton-ma35d1-nand-controller.c +++ b/drivers/mtd/nand/raw/nuvoton-ma35d1-nand-controller.c @@ -993,7 +993,6 @@ static int ma35_nand_probe(struct platform_device *pdev) ret = ma35_nand_chips_init(&pdev->dev, nand); if (ret) { dev_err(&pdev->dev, "failed to init NAND chips\n"); - clk_disable(nand->clk); return ret; } diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 4dd6f1a4e797..b469c01aacf9 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -328,14 +328,16 @@ config_nand_cw_read(struct nand_chip *chip, bool use_ecc, int cw) { struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; - __le32 *reg = &nandc->regs->read_location0; + int reg_base = NAND_READ_LOCATION_0; - if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw)) + if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw)) { reg = &nandc->regs->read_location_last0; + reg_base = NAND_READ_LOCATION_LAST_CW_0; + } if (nandc->props->supports_bam) - qcom_write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, reg, reg_base, 4, NAND_BAM_NEXT_SGL); qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 75db1713e617..f9b72671c525 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -1631,6 +1631,9 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand, if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH) { int bytes; + if (mtd->writesize < 1024) + return -EINVAL; + ecc->size = 1024; nsectors = mtd->writesize / ecc->size; diff --git a/drivers/mtd/parsers/qcomsmempart.c b/drivers/mtd/parsers/qcomsmempart.c index 4311b89d8df0..b12d87c3b023 100644 --- a/drivers/mtd/parsers/qcomsmempart.c +++ b/drivers/mtd/parsers/qcomsmempart.c @@ -143,9 +143,9 @@ static int parse_qcomsmem_part(struct mtd_info *mtd, *c = tolower(*c); parts[j].name = name; - parts[j].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; + parts[j].offset = (u64)le32_to_cpu(pentry->offset) * mtd->erasesize; parts[j].mask_flags = pentry->attr; - parts[j].size = le32_to_cpu(pentry->length) * mtd->erasesize; + parts[j].size = (u64)le32_to_cpu(pentry->length) * mtd->erasesize; pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", i, pentry->name, le32_to_cpu(pentry->offset), le32_to_cpu(pentry->length), pentry->attr); diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 037407fc2e11..512d0e4e3b1f 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1281,6 +1281,9 @@ int spi_nor_prep_and_lock(struct spi_nor *nor) ret = wait_event_killable(nor->rww.wait, spi_nor_rww_start_exclusive(nor)); + if (ret) + spi_nor_unprep(nor); + return ret; } @@ -1352,6 +1355,9 @@ static int spi_nor_prep_and_lock_pe(struct spi_nor *nor, loff_t start, size_t le ret = wait_event_killable(nor->rww.wait, spi_nor_rww_start_pe(nor, start, len)); + if (ret) + spi_nor_unprep(nor); + return ret; } @@ -1425,6 +1431,9 @@ static int spi_nor_prep_and_lock_rd(struct spi_nor *nor, loff_t start, size_t le ret = wait_event_killable(nor->rww.wait, spi_nor_rww_start_rd(nor, start, len)); + if (ret) + spi_nor_unprep(nor); + return ret; } diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index a8324c2da0ac..a9668c83ac5e 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -1175,6 +1175,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor, #define PROFILE1_DWORD5_DUMMY_166MHZ GENMASK(31, 27) #define PROFILE1_DWORD5_DUMMY_133MHZ GENMASK(21, 17) #define PROFILE1_DWORD5_DUMMY_100MHZ GENMASK(11, 7) +#define SFDP_PROFILE1_DWORD_MIN 5 /** * spi_nor_parse_profile1() - parse the xSPI Profile 1.0 table @@ -1192,6 +1193,9 @@ static int spi_nor_parse_profile1(struct spi_nor *nor, int ret; u8 dummy, opcode; + if (profile1_header->length < SFDP_PROFILE1_DWORD_MIN) + return -EINVAL; + len = profile1_header->length * sizeof(*dwords); dwords = kmalloc(len, GFP_KERNEL); if (!dwords) @@ -1262,6 +1266,7 @@ static int spi_nor_parse_profile1(struct spi_nor *nor, } #define SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE BIT(31) +#define SFDP_SCCR_DWORD_MIN 22 /** * spi_nor_parse_sccr() - Parse the Status, Control and Configuration Register @@ -1280,6 +1285,9 @@ static int spi_nor_parse_sccr(struct spi_nor *nor, size_t len; int ret; + if (sccr_header->length < SFDP_SCCR_DWORD_MIN) + return -EINVAL; + len = sccr_header->length * sizeof(*dwords); dwords = kmalloc(len, GFP_KERNEL); if (!dwords) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index baafc13603d3..2e9e1b4d74da 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -6270,7 +6270,7 @@ static int __init bond_check_params(struct bond_params *params) } for (arp_ip_count = 0, i = 0; - (arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[i]; i++) { + (i < BOND_MAX_ARP_TARGETS) && arp_ip_target[i]; i++) { __be32 ip; /* not a complete check, but good enough to catch mistakes */ diff --git a/drivers/net/ethernet/google/gve/gve_flow_rule.c b/drivers/net/ethernet/google/gve/gve_flow_rule.c index 0bb8cd1876a3..426a264af8b2 100644 --- a/drivers/net/ethernet/google/gve/gve_flow_rule.c +++ b/drivers/net/ethernet/google/gve/gve_flow_rule.c @@ -206,6 +206,7 @@ int gve_get_flow_rule_entry(struct gve_priv *priv, struct ethtool_rxnfc *cmd) return -EOPNOTSUPP; if (!priv->flow_rules_cache.rules_cache_synced || + !*cache_num || fsp->location < be32_to_cpu(rules_cache[0].location) || fsp->location > be32_to_cpu(rules_cache[*cache_num - 1].location)) { err = gve_adminq_query_flow_rules(priv, GVE_FLOW_RULE_QUERY_RULES, fsp->location); diff --git a/drivers/net/ethernet/hisilicon/hisi_femac.c b/drivers/net/ethernet/hisilicon/hisi_femac.c index d244a40df430..fba68035c969 100644 --- a/drivers/net/ethernet/hisilicon/hisi_femac.c +++ b/drivers/net/ethernet/hisilicon/hisi_femac.c @@ -491,6 +491,7 @@ static int hisi_femac_net_close(struct net_device *dev) netif_stop_queue(dev); napi_disable(&priv->napi); + hisi_femac_port_reset(priv); hisi_femac_free_skb_rings(priv); return 0; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index f950570909ab..75ba78a84c86 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -9426,23 +9426,6 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, } protocol = vlan_get_protocol(skb); - if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && - adapter->ptp_clock) { - if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON && - !test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS, - &adapter->state)) { - skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - tx_flags |= IXGBE_TX_FLAGS_TSTAMP; - - /* schedule check for Tx timestamp */ - adapter->ptp_tx_skb = skb_get(skb); - adapter->ptp_tx_start = jiffies; - schedule_work(&adapter->ptp_tx_work); - } else { - adapter->tx_hwtstamp_skipped++; - } - } - #ifdef CONFIG_PCI_IOV /* * Use the l2switch_enable flag - would be false if the DMA @@ -9507,6 +9490,29 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, #ifdef IXGBE_FCOE xmit_fcoe: #endif /* IXGBE_FCOE */ + /* Reserve the Tx timestamp only after all skb preparation: + * skb_get() makes the skb shared, and pskb_expand_head() + * (reached from skb_cow_head() or skb_checksum_help()) + * refuses shared skbs. + */ + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && + adapter->ptp_clock) { + if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON && + !test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS, + &adapter->state)) { + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + tx_flags |= IXGBE_TX_FLAGS_TSTAMP; + first->tx_flags |= IXGBE_TX_FLAGS_TSTAMP; + + /* schedule check for Tx timestamp */ + adapter->ptp_tx_skb = skb_get(skb); + adapter->ptp_tx_start = jiffies; + schedule_work(&adapter->ptp_tx_work); + } else { + adapter->tx_hwtstamp_skipped++; + } + } + if (ixgbe_tx_map(tx_ring, first, hdr_len)) goto cleanup_tx_timestamp; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 7151ae883136..c38989009c76 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1630,7 +1630,8 @@ static int macvlan_changelink(struct net_device *dev, if (data && data[IFLA_MACVLAN_FLAGS]) { __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC; - if (macvlan_passthru(vlan->port) && promisc) { + if (macvlan_passthru(vlan->port) && promisc && + netif_running(dev)) { int err; if (flags & MACVLAN_FLAG_NOPROMISC) diff --git a/drivers/net/netdevsim/bpf.c b/drivers/net/netdevsim/bpf.c index 5f17f68f3c08..319f75e42f7c 100644 --- a/drivers/net/netdevsim/bpf.c +++ b/drivers/net/netdevsim/bpf.c @@ -150,6 +150,17 @@ int nsim_bpf_setup_tc_block_cb(enum tc_setup_type type, return -EOPNOTSUPP; } + /* A dev-bound program can be replayed here when a netdev joins + * a shared block, after the core attach-time check has run; + * enforce the device match as nfp does. + */ + if (prog && bpf_prog_is_dev_bound(prog->aux) && + !bpf_offload_dev_match(prog, ns->netdev)) { + NSIM_EA(cls_bpf->common.extack, + "program bound to a different device"); + return -EINVAL; + } + if (cls_bpf->command != TC_CLSBPF_OFFLOAD) return -EOPNOTSUPP; diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 14fa87a8e083..61c240d846ee 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -3204,6 +3204,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) len = CCP_LENGTH(dp); if (!pskb_may_pull(skb, len + 2)) return; /* too short */ + dp = skb->data + 2; dp += CCP_HDRLEN; len -= CCP_HDRLEN; if (len < CCP_OPT_MINLEN || len < CCP_OPT_LENGTH(dp)) diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index f5a26a0bc679..69445a94ee6f 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -523,11 +523,17 @@ static void read_bulk_callback(struct urb *urb) } /* - * If the packet is unreasonably long, quietly drop it rather than - * kernel panicing by calling skb_put. + * Drop frames shorter than an Ethernet header, because + * eth_type_trans() reads the header whatever the length, and frames + * longer than what was actually received. Passing either up would + * expose stale buffer contents, and skb_put() could panic on the + * latter. count is at most PEGASUS_MTU. */ - if (pkt_len > PEGASUS_MTU - rx_offset) + if (pkt_len < ETH_HLEN || pkt_len + rx_offset > count) { + net->stats.rx_errors++; + net->stats.rx_length_errors++; goto goon; + } /* * at this point we are sure pegasus->rx_skb != NULL diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 8cf4e81f8f88..7b9923b6480e 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -6785,11 +6785,8 @@ static void set_carrier(struct r8152 *tp) { struct net_device *netdev = tp->netdev; struct napi_struct *napi = &tp->napi; - u16 speed; - - speed = rtl8152_get_speed(tp); - if (speed & LINK_STATUS) { + if (r8152_mdio_read(tp, MII_BMSR) & BMSR_LSTATUS) { if (!netif_carrier_ok(netdev)) { tp->rtl_ops.enable(tp); netif_stop_queue(netdev); @@ -6815,6 +6812,11 @@ static void set_carrier(struct r8152 *tp) tasklet_enable(&tp->tx_tl); netif_info(tp, link, netdev, "carrier off\n"); } + + if (rtl8152_get_speed(tp) & LINK_STATUS) { + set_bit(RTL8152_LINK_CHG, &tp->flags); + schedule_delayed_work(&tp->schedule, 0); + } } } diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 148114ab85ac..25cdbba5dfa9 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -1621,10 +1621,9 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog, } } - if (!old_prog) { + if (!old_prog) peer->hw_features &= ~NETIF_F_GSO_SOFTWARE; - peer->max_mtu = max_mtu; - } + peer->max_mtu = max_mtu; xdp_features_set_redirect_target(peer, true); } diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index b7ab57f4e277..34390befdf8a 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -458,9 +458,6 @@ struct virtnet_info { /* Work struct for setting rx mode */ struct work_struct rx_mode_work; - /* OK to queue work setting RX mode? */ - bool rx_mode_work_enabled; - /* Does the affinity hint is set for virtqueues? */ bool affinity_hint_set; @@ -740,16 +737,13 @@ static void disable_delayed_refill(struct virtnet_info *vi) static void enable_rx_mode_work(struct virtnet_info *vi) { - rtnl_lock(); - vi->rx_mode_work_enabled = true; - rtnl_unlock(); + if (enable_work(&vi->rx_mode_work) && netif_running(vi->dev)) + schedule_work(&vi->rx_mode_work); } static void disable_rx_mode_work(struct virtnet_info *vi) { - rtnl_lock(); - vi->rx_mode_work_enabled = false; - rtnl_unlock(); + disable_work_sync(&vi->rx_mode_work); } static void virtqueue_napi_schedule(struct napi_struct *napi, @@ -3996,8 +3990,7 @@ static void virtnet_set_rx_mode(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); - if (vi->rx_mode_work_enabled) - schedule_work(&vi->rx_mode_work); + schedule_work(&vi->rx_mode_work); } static int virtnet_vlan_rx_add_vid(struct net_device *dev, @@ -5813,7 +5806,6 @@ static void virtnet_freeze_down(struct virtio_device *vdev) /* Make sure no work handler is accessing the device */ flush_work(&vi->config_work); disable_rx_mode_work(vi); - flush_work(&vi->rx_mode_work); if (netif_running(vi->dev)) { rtnl_lock(); @@ -5840,7 +5832,6 @@ static int virtnet_restore_up(struct virtio_device *vdev) virtio_device_ready(vdev); enable_delayed_refill(vi); - enable_rx_mode_work(vi); if (netif_running(vi->dev)) { rtnl_lock(); @@ -5853,6 +5844,8 @@ static int virtnet_restore_up(struct virtio_device *vdev) netif_tx_lock_bh(vi->dev); netif_device_attach(vi->dev); netif_tx_unlock_bh(vi->dev); + + enable_rx_mode_work(vi); return err; } @@ -6952,6 +6945,7 @@ static int virtnet_probe(struct virtio_device *vdev) INIT_WORK(&vi->config_work, virtnet_config_changed_work); INIT_WORK(&vi->rx_mode_work, virtnet_rx_mode_work); + disable_work(&vi->rx_mode_work); spin_lock_init(&vi->refill_lock); if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) { @@ -7103,8 +7097,6 @@ static int virtnet_probe(struct virtio_device *vdev) if (vi->has_rss || vi->has_rss_hash_report) virtnet_init_default_rss(vi); - enable_rx_mode_work(vi); - /* serialize netdev register + virtio_device_ready() with ndo_open() */ rtnl_lock(); @@ -7204,6 +7196,8 @@ static int virtnet_probe(struct virtio_device *vdev) goto free_unregister_netdev; } + enable_rx_mode_work(vi); + pr_debug("virtnet: registered device %s with %d RX and TX vq's\n", dev->name, max_queue_pairs); @@ -7255,7 +7249,6 @@ static void virtnet_remove(struct virtio_device *vdev) /* Make sure no work handler is accessing the device. */ flush_work(&vi->config_work); disable_rx_mode_work(vi); - flush_work(&vi->rx_mode_work); virtnet_free_irq_moder(vi); diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 68c7ef190780..5e67f088962e 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -316,6 +316,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, case HAL_RXDMA_DIR_BUF: break; default: + ath11k_dp_srng_cleanup(ab, ring); ath11k_warn(ab, "Not a valid ring type in dp :%d\n", type); return -EINVAL; } @@ -327,6 +328,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, ret = ath11k_hal_srng_setup(ab, type, ring_num, mac_id, ¶ms); if (ret < 0) { + ath11k_dp_srng_cleanup(ab, ring); ath11k_warn(ab, "failed to setup srng: %d ring_id %d\n", ret, ring_num); return ret; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 91f293ab7013..67c9174a30aa 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -4814,6 +4814,7 @@ static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab, u16 tag, u16 len, const void *ptr, void *data) { + struct ath12k_svc_ext_info *svc_ext_info = &ab->wmi_ab.svc_ext_info; struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0]; struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data; int ret; @@ -4858,6 +4859,22 @@ static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab, return ret; } + if (svc_rdy_ext->tot_phy_id > + ARRAY_SIZE(svc_ext_info->mac_phy_info)) { + ath12k_warn(ab, "too many PHY entries %u (max %zu)\n", + svc_rdy_ext->tot_phy_id, + ARRAY_SIZE(svc_ext_info->mac_phy_info)); + return -EINVAL; + } + + if (svc_rdy_ext->n_mac_phy_caps < svc_rdy_ext->tot_phy_id) { + ath12k_warn(ab, + "not enough MAC/PHY caps %u, expected %u\n", + svc_rdy_ext->n_mac_phy_caps, + svc_rdy_ext->tot_phy_id); + return -EINVAL; + } + ath12k_wmi_save_all_mac_phy_info(ab, svc_rdy_ext); svc_rdy_ext->mac_phy_done = true; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c index b03d5a1f1a93..7fd3e018affe 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c @@ -221,7 +221,7 @@ static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_5GHz[] = { }; static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_2GHz[] = { - {0, 0, 0, 0, 0, 128}, + {0, 0, 0, 0, 0, -128}, {0, 0, 0, 0, 0, 70}, {0, 0, 0, 0, 0, 20}, {0, 0, 0, 3, 0, 20}, diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 6ce8e4af18fe..281b2c3e9e7c 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -224,12 +224,14 @@ mt76_find_power_limits_node(struct mt76_dev *dev) struct property *regd = of_find_property(cur, "regdomain", NULL); if (!country && !regd) { - fallback = cur; + of_node_put(fallback); + fallback = of_node_get(cur); continue; } if (mt76_string_prop_find(country, dev->alpha2) || mt76_string_prop_find(regd, region_name)) { + of_node_put(fallback); of_node_put(np); return cur; } @@ -356,7 +358,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, s8 target_power) { struct mt76_dev *dev = phy->dev; - struct device_node *np; + struct device_node *np, *band_np; const s8 *val; char name[16]; u32 mcs_rates = dev->drv->mcs_rates; @@ -389,15 +391,18 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, band = '6'; break; default: + of_node_put(np); return target_power; } snprintf(name, sizeof(name), "txpower-%cg", band); - np = of_get_child_by_name(np, name); - if (!np) + band_np = of_get_child_by_name(np, name); + of_node_put(np); + if (!band_np) return target_power; - np = mt76_find_channel_node(np, chan); + np = mt76_find_channel_node(band_np, chan); + of_node_put(band_np); if (!np) return target_power; @@ -422,6 +427,8 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, ARRAY_SIZE(dest->ru), val, len, target_power, txs_delta, &max_power); + of_node_put(np); + return max_power; } EXPORT_SYMBOL_GPL(mt76_get_rate_power_limits); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index c4f5f6ee916a..4b41462413bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -541,8 +541,10 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) mt7615_cap_dbdc_enable(dev); mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops, MT_BAND1); - if (!mphy) - return -ENOMEM; + if (!mphy) { + ret = -ENOMEM; + goto error; + } phy = mphy->priv; phy->dev = dev; @@ -572,7 +574,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) ret = mt76_eeprom_override(mphy); if (ret) - return ret; + goto error_free_hw; /* second phy can only handle 5 GHz */ mphy->cap.has_5ghz = true; @@ -590,7 +592,14 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) ret = mt76_register_phy(mphy, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) - ieee80211_free_hw(mphy->hw); + goto error_free_hw; + + return 0; + +error_free_hw: + ieee80211_free_hw(mphy->hw); +error: + mt7615_cap_dbdc_disable(dev); return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 25936fb309fb..a6667e3a66d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -254,8 +254,10 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, mt7615_mutex_acquire(dev); - mt7615_mcu_add_bss_info(phy, vif, NULL, false); - mt7615_mcu_sta_add(phy, vif, NULL, false); + if (vif->type != NL80211_IFTYPE_MONITOR) { + mt7615_mcu_add_bss_info(phy, vif, NULL, false); + mt7615_mcu_sta_add(phy, vif, NULL, false); + } mt76_testmode_reset(phy->mt76, true); if (vif == phy->monitor_vif) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c index f607eee3fb47..5e09f43926e0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c @@ -116,6 +116,7 @@ void mt7615_unregister_device(struct mt7615_dev *dev) mcu_running = mt7615_wait_for_mcu_init(dev); mt7615_unregister_ext_phy(dev); + cancel_work_sync(&dev->reset_work); mt76_unregister_device(&dev->mt76); if (mcu_running) mt7615_mcu_exit(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 17c978291531..eef131c05f76 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -302,10 +302,14 @@ mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; fallthrough; case MT_PHY_TYPE_HT: + if (idx > 31) + return -EINVAL; txrate->flags |= IEEE80211_TX_RC_MCS; txrate->idx = idx; break; case MT_PHY_TYPE_VHT: + if ((idx & 0xf) > 9) + return -EINVAL; txrate->flags |= IEEE80211_TX_RC_VHT_MCS; txrate->idx = idx; break; @@ -493,18 +497,21 @@ mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, struct mt76x02_sta *msta, first_rate = st->rate & ~MT_PKTID_RATE; first_rate |= st->pktid & MT_PKTID_RATE; - mt76x02_mac_process_tx_rate(&rate[0], first_rate, - dev->mphy.chandef.chan->band); + if (mt76x02_mac_process_tx_rate(&rate[0], first_rate, + dev->mphy.chandef.chan->band)) + return; } else if (rate[0].idx < 0) { if (!msta) return; - mt76x02_mac_process_tx_rate(&rate[0], msta->wcid.tx_info, - dev->mphy.chandef.chan->band); + if (mt76x02_mac_process_tx_rate(&rate[0], msta->wcid.tx_info, + dev->mphy.chandef.chan->band)) + return; } - mt76x02_mac_process_tx_rate(&last_rate, st->rate, - dev->mphy.chandef.chan->band); + if (mt76x02_mac_process_tx_rate(&last_rate, st->rate, + dev->mphy.chandef.chan->band)) + return; for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) { retry--; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index b2cc44914294..d06cc5ee07b2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -90,7 +90,7 @@ __mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, MT_MCU_MSG_TYPE_CMD; ret = mt76x02u_skb_dma_info(skb, CPU_TX_PORT, info); if (ret) - return ret; + goto out; ret = mt76u_bulk_msg(dev, skb->data, skb->len, NULL, 500, MT_EP_OUT_INBAND_CMD); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c index 95047ee48a42..0ad86526dddc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c @@ -132,6 +132,15 @@ static int mt7925u_mac_reset(struct mt792x_dev *dev) return err; } +static void mt7925u_stop(struct ieee80211_hw *hw, bool suspend) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + cancel_delayed_work_sync(&dev->mlo_pm_work); + + mt792xu_stop(hw, suspend); +} + static int mt7925u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { @@ -178,7 +187,7 @@ static int mt7925u_probe(struct usb_interface *usb_intf, if (!ops) return -ENOMEM; - ops->stop = mt792xu_stop; + ops->stop = mt7925u_stop; mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops); if (!mdev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index 3f49bbbba3b9..1d9102b5e556 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -63,12 +63,18 @@ static void mt7996_put_hif2(struct mt7996_hif *hif) static struct mt7996_hif *mt7996_pci_init_hif2(struct pci_dev *pdev) { + struct pci_dev *tmp_pdev; + hif_idx++; - if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7996_DEVICE_ID_2, NULL) && - !pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7992_DEVICE_ID_2, NULL) && - !pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7990_DEVICE_ID_2, NULL)) + tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7996_DEVICE_ID_2, NULL); + if (!tmp_pdev) + tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7992_DEVICE_ID_2, NULL); + if (!tmp_pdev) + tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7990_DEVICE_ID_2, NULL); + if (!tmp_pdev) return NULL; + pci_dev_put(tmp_pdev); writel(hif_idx | MT_PCIE_RECOG_ID_SEM, pcim_iomap_table(pdev)[0] + MT_PCIE_RECOG_ID); diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 93275bb692fa..3fef2ad45dee 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -885,7 +885,7 @@ int mt76_skb_adjust_pad(struct sk_buff *skb, int pad) } } - if (skb_pad(last, pad)) + if (__skb_pad(last, pad, false)) return -ENOMEM; __skb_put(last, pad); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index f9e67b8c3b3c..b39dbf22dfc1 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -854,6 +854,9 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, enum mt76_txq_id qid, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta) { + struct ieee80211_tx_status status = { + .sta = sta, + }; struct mt76_tx_info tx_info = { .skb = skb, }; @@ -861,17 +864,27 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, u16 idx = q->head; int err; - if (q->queued == q->ndesc) - return -ENOSPC; + if (q->queued == q->ndesc) { + err = -ENOSPC; + goto err_free_skb; + } skb->prev = skb->next = NULL; err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info); if (err < 0) - return err; + goto err_free_skb; err = mt76u_tx_setup_buffers(dev, tx_info.skb, q->entry[idx].urb); - if (err < 0) - return err; + if (err < 0) { + /* + * mt76_tx_status_skb_get() walks the idr and dereferences + * a freed skb. This SKB is not counted in non-AQL counter + * due to error return, so using 0xffff as wcid to keep + * balanced. + */ + mt76_tx_complete_skb(dev, 0xffff, tx_info.skb); + goto err_ret; + } mt76u_fill_bulk_urb(dev, USB_DIR_OUT, q->ep, q->entry[idx].urb, mt76u_complete_tx, &q->entry[idx]); @@ -882,6 +895,14 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, q->queued++; return idx; + +err_free_skb: + status.skb = tx_info.skb; + spin_lock_bh(&dev->rx_lock); + ieee80211_tx_status_ext(dev->hw, &status); + spin_unlock_bh(&dev->rx_lock); +err_ret: + return err; } static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q) diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 766f22d31079..3b6302f14de0 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -597,7 +597,7 @@ static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, hw_key_idx = key->keyidx; } - if (hw_key_idx > sec->total_cam_num) { + if (hw_key_idx >= sec->total_cam_num) { ret = -ENOSPC; goto out; } diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 299526220380..c4fb9c226fae 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -156,8 +156,24 @@ static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 le if (!info) return -EINVAL; + if (len < sizeof(*fw_hdr)) { + rtw89_err(rtwdev, "[ERR]fw header truncated\n"); + return -EINVAL; + } + info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_W6_SEC_NUM); + if (!info->section_num || info->section_num > FWDL_SECTION_MAX_NUM) { + rtw89_err(rtwdev, "[ERR]invalid fw section num %u\n", + info->section_num); + return -EINVAL; + } + base_hdr_len = struct_size(fw_hdr, sections, info->section_num); + if (base_hdr_len > len) { + rtw89_err(rtwdev, "[ERR]fw header truncated\n"); + return -EINVAL; + } + info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_W7_DYN_HDR); info->idmem_share_mode = le32_get_bits(fw_hdr->w7, FW_HDR_W7_IDMEM_SHARE_MODE); @@ -449,9 +465,25 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le int ret; u32 i; + if (len < sizeof(*fw_hdr)) { + rtw89_err(rtwdev, "[ERR]fw header truncated\n"); + return -EINVAL; + } + info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_V1_W6_SEC_NUM); + if (!info->section_num || info->section_num > FWDL_SECTION_MAX_NUM) { + rtw89_err(rtwdev, "[ERR]invalid fw section num %u\n", + info->section_num); + return -EINVAL; + } + info->dsp_checksum = le32_get_bits(fw_hdr->w6, FW_HDR_V1_W6_DSP_CHKSUM); base_hdr_len = struct_size(fw_hdr, sections, info->section_num); + if (base_hdr_len > len) { + rtw89_err(rtwdev, "[ERR]fw header truncated\n"); + return -EINVAL; + } + info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_V1_W7_DYN_HDR); info->idmem_share_mode = le32_get_bits(fw_hdr->w7, FW_HDR_V1_W7_IDMEM_SHARE_MODE); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index 84c46d2f4d85..6d2382cb5cd8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -1895,8 +1895,8 @@ static void _dpk_information(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u8 kidx = dpk->cur_idx[path]; dpk->bp[path][kidx].band = chan->band_type; - dpk->bp[path][kidx].ch = chan->band_width; - dpk->bp[path][kidx].bw = chan->channel; + dpk->bp[path][kidx].ch = chan->channel; + dpk->bp[path][kidx].bw = chan->band_width; rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d[%d] (PHY%d): TSSI %s/ DBCC %s/ %s/ CH%d/ %s\n", diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 90046d6f620e..144c4c2801bd 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -16,10 +16,14 @@ void __rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + size_t hdr_len = offsetof(struct ieee80211_mgmt, u.assoc_req.variable); const u8 *rsn, *ies = mgmt->u.assoc_req.variable; struct rtw89_rsn_ie *rsn_ie; - rsn = cfg80211_find_ie(WLAN_EID_RSN, ies, skb->len); + if (skb->len < hdr_len) + return; + + rsn = cfg80211_find_ie(WLAN_EID_RSN, ies, skb->len - hdr_len); if (!rsn) return; diff --git a/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c b/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c index 4627847c6daa..455b3b6f0991 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c +++ b/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c @@ -14,6 +14,11 @@ ipc_protocol_free_msg_get(struct iosm_protocol *ipc_protocol, int *index) u32 new_head = (head + 1) % IPC_MEM_MSG_ENTRIES; union ipc_mem_msg_entry *msg; + if (head >= IPC_MEM_MSG_ENTRIES) { + dev_err(ipc_protocol->dev, "invalid message head %u", head); + return NULL; + } + if (new_head == le32_to_cpu(ipc_protocol->p_ap_shm->msg_tail)) { dev_err(ipc_protocol->dev, "message ring is full"); return NULL; diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index c759ebc56457..e3f126897cfc 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1530,12 +1530,17 @@ static inline bool tx_dealloc_work_todo(struct xenvif_queue *queue) void xenvif_unmap_frontend_data_rings(struct xenvif_queue *queue) { - if (queue->tx.sring) + if (queue->tx.sring) { xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(queue->vif), queue->tx.sring); - if (queue->rx.sring) + queue->tx.sring = NULL; + } + + if (queue->rx.sring) { xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(queue->vif), queue->rx.sring); + queue->rx.sring = NULL; + } } int xenvif_map_frontend_data_rings(struct xenvif_queue *queue, diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index aca25db2503b..e4405a6c6e70 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -731,6 +731,7 @@ static void connect(struct backend_info *be) unsigned int queue_index; unsigned int requested_num_queues; struct xenvif_queue *queue; + unsigned int num_queues; /* Check whether the frontend requested multiple queues * and read the number requested. @@ -837,14 +838,15 @@ static void connect(struct backend_info *be) return; err: - if (be->vif->num_queues > 0) + num_queues = be->vif->num_queues; + if (num_queues > 0) xenvif_disconnect_data(be->vif); /* Clean up existing queues */ + be->vif->num_queues = 0; synchronize_net(); - for (queue_index = 0; queue_index < be->vif->num_queues; ++queue_index) + for (queue_index = 0; queue_index < num_queues; ++queue_index) xenvif_deinit_queue(&be->vif->queues[queue_index]); vfree(be->vif->queues); be->vif->queues = NULL; - be->vif->num_queues = 0; xenvif_disconnect_ctrl(be->vif); return; } diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c index 9d73713d6f82..38506314248f 100644 --- a/drivers/nvme/host/auth.c +++ b/drivers/nvme/host/auth.c @@ -378,8 +378,21 @@ static int nvme_auth_process_dhchap_success1(struct nvme_ctrl *ctrl, nvme_auth_hmac_name(chap->hash_id), nvme_auth_dhgroup_name(chap->dhgroup_id)); - if (!data->rvalid) + if (!data->rvalid) { + /* + * The controller did not return a response. If we asked it to + * authenticate itself the session must not be used, otherwise + * mutual authentication would silently degrade to one-way. + */ + if (chap->bi_directional) { + dev_warn(ctrl->device, + "qid %d: controller did not authenticate\n", + chap->qid); + chap->status = NVME_AUTH_DHCHAP_FAILURE_FAILED; + return -ECONNREFUSED; + } return 0; + } /* Validate controller response */ if (crypto_memneq(chap->response, data->rval, data->hl)) { diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index ad725e346c94..99a8e2953b02 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2210,13 +2210,18 @@ static int nvme_query_fdp_granularity(struct nvme_ctrl *ctrl, } size = le32_to_cpu(hdr.sze); + if (size < sizeof(*h) + sizeof(*desc)) { + dev_warn(ctrl->device, "FDP config size too small:%zu\n", + size); + return 0; + } if (size > PAGE_SIZE * MAX_ORDER_NR_PAGES) { dev_warn(ctrl->device, "FDP config size too large:%zu\n", size); return 0; } - h = kvmalloc(size, GFP_KERNEL); + h = kvzalloc(size, GFP_KERNEL); if (!h) return -ENOMEM; @@ -2242,9 +2247,9 @@ static int nvme_query_fdp_granularity(struct nvme_ctrl *ctrl, desc = log; end = log + size - sizeof(*h); for (i = 0; i < fdp_idx; i++) { - u16 dsze = le16_to_cpu(desc->dsze); + u16 dsze = get_unaligned_le16(&desc->dsze); - if (!dsze || log + dsze > end) { + if (dsze < sizeof(*desc) || log + dsze + sizeof(*desc) > end) { dev_warn(ctrl->device, "FDP invalid config descriptor at index %d\n", i); ret = 0; @@ -2254,13 +2259,13 @@ static int nvme_query_fdp_granularity(struct nvme_ctrl *ctrl, desc = log; } - if (le32_to_cpu(desc->nrg) > 1) { + if (get_unaligned_le32(&desc->nrg) > 1) { dev_warn(ctrl->device, "FDP NRG > 1 not supported\n"); ret = 0; goto out; } - info->runs = le64_to_cpu(desc->runs); + info->runs = get_unaligned_le64(&desc->runs); out: kvfree(h); return ret; diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 19a9dd7caed8..dbaf503b7de9 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -1713,6 +1713,7 @@ static void nvme_rdma_process_nvme_rsp(struct nvme_rdma_queue *queue, "Bogus remote invalidation for rkey %#x\n", req->mr ? req->mr->rkey : 0); nvme_rdma_error_recovery(queue->ctrl); + return; } } else if (req->mr) { int ret; diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c index 12478e029735..2b6085359a95 100644 --- a/drivers/nvme/host/sysfs.c +++ b/drivers/nvme/host/sysfs.c @@ -626,7 +626,7 @@ static ssize_t quirks_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RO(quirks); #ifdef CONFIG_NVME_HOST_AUTH -static ssize_t nvme_ctrl_dhchap_secret_show(struct device *dev, +static ssize_t dhchap_secret_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nvme_ctrl *ctrl = dev_get_drvdata(dev); @@ -637,7 +637,7 @@ static ssize_t nvme_ctrl_dhchap_secret_show(struct device *dev, return sysfs_emit(buf, "%s\n", opts->dhchap_secret); } -static ssize_t nvme_ctrl_dhchap_secret_store(struct device *dev, +static ssize_t dhchap_secret_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nvme_ctrl *ctrl = dev_get_drvdata(dev); @@ -681,10 +681,9 @@ static ssize_t nvme_ctrl_dhchap_secret_store(struct device *dev, return count; } -static DEVICE_ATTR(dhchap_secret, S_IRUGO | S_IWUSR, - nvme_ctrl_dhchap_secret_show, nvme_ctrl_dhchap_secret_store); +static DEVICE_ATTR_ADMIN_RW(dhchap_secret); -static ssize_t nvme_ctrl_dhchap_ctrl_secret_show(struct device *dev, +static ssize_t dhchap_ctrl_secret_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nvme_ctrl *ctrl = dev_get_drvdata(dev); @@ -695,7 +694,7 @@ static ssize_t nvme_ctrl_dhchap_ctrl_secret_show(struct device *dev, return sysfs_emit(buf, "%s\n", opts->dhchap_ctrl_secret); } -static ssize_t nvme_ctrl_dhchap_ctrl_secret_store(struct device *dev, +static ssize_t dhchap_ctrl_secret_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nvme_ctrl *ctrl = dev_get_drvdata(dev); @@ -739,8 +738,7 @@ static ssize_t nvme_ctrl_dhchap_ctrl_secret_store(struct device *dev, return count; } -static DEVICE_ATTR(dhchap_ctrl_secret, S_IRUGO | S_IWUSR, - nvme_ctrl_dhchap_ctrl_secret_show, nvme_ctrl_dhchap_ctrl_secret_store); +static DEVICE_ATTR_ADMIN_RW(dhchap_ctrl_secret); #endif static struct attribute *nvme_dev_attrs[] = { diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index b7e4624f1dcd..94495b022871 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -1425,6 +1425,19 @@ static int nvme_tcp_try_recv(struct nvme_tcp_queue *queue) lock_sock(sk); queue->nr_cqe = 0; consumed = sock->ops->read_sock(sk, &rd_desc, nvme_tcp_recv_skb); + /* + * nvme_tcp_recv_skb() handles its own errors, so a queue that is + * still enabled failed inside read_sock(). Handle it before + * release_sock() processes the backlog. + */ + if (unlikely(consumed < 0 && consumed != -EAGAIN && + queue->rd_enabled)) { + dev_err(queue->ctrl->ctrl.device, + "queue %d: receive failed: %d\n", + nvme_tcp_queue_id(queue), consumed); + queue->rd_enabled = false; + nvme_tcp_error_recovery(&queue->ctrl->ctrl); + } release_sock(sk); return consumed == -EAGAIN ? 0 : consumed; } @@ -1437,9 +1450,11 @@ static void nvme_tcp_io_work(struct work_struct *w) do { bool pending = false; + bool got_send_mutex = false; int result; if (mutex_trylock(&queue->send_mutex)) { + got_send_mutex = true; result = nvme_tcp_try_send(queue); mutex_unlock(&queue->send_mutex); if (result > 0) @@ -1454,8 +1469,13 @@ static void nvme_tcp_io_work(struct work_struct *w) else if (unlikely(result < 0)) return; - /* did we get some space after spending time in recv? */ - if (nvme_tcp_queue_has_pending(queue) && + /* + * did we get some space after spending time in recv? + * Only check this if we could take send_mutex. Otherwise + * the task holding it sends the requests and queues io_work + * again after it releases the mutex. + */ + if (got_send_mutex && nvme_tcp_queue_has_pending(queue) && sk_stream_is_writeable(queue->sock->sk)) pending = true; diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index fa9920787a8f..623b5303de2a 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -1606,7 +1606,7 @@ void nvmet_execute_keep_alive(struct nvmet_req *req) pr_debug("ctrl %d update keep-alive timer for %d secs\n", ctrl->cntlid, ctrl->kato); - mod_delayed_work(system_wq, &ctrl->ka_work, ctrl->kato * HZ); + mod_delayed_work(system_percpu_wq, &ctrl->ka_work, ctrl->kato * HZ); out: nvmet_req_complete(req, status); } diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c index 8230a0563616..eb2b6c7a8083 100644 --- a/drivers/nvme/target/auth.c +++ b/drivers/nvme/target/auth.c @@ -238,6 +238,7 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, bool reset) void nvmet_auth_sq_free(struct nvmet_sq *sq) { + sq->auth_expiry_active = false; cancel_delayed_work(&sq->auth_expired_work); #ifdef CONFIG_NVME_TARGET_TCP_TLS sq->tls_key = NULL; @@ -248,6 +249,7 @@ void nvmet_auth_sq_free(struct nvmet_sq *sq) sq->dhchap_c2 = NULL; kfree(sq->dhchap_skey); sq->dhchap_skey = NULL; + sq->dhchap_skey_len = 0; } void nvmet_auth_sq_destroy(struct nvmet_sq *sq) diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index f6ac42eaac0e..e2032b58191c 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -1662,8 +1662,10 @@ static ssize_t nvmet_subsys_attr_qid_max_store(struct config_item *item, subsys->max_qid = qid_max; /* Force reconnect */ + mutex_lock(&subsys->lock); list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) ctrl->ops->delete_ctrl(ctrl); + mutex_unlock(&subsys->lock); up_write(&nvmet_config_sem); return cnt; diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c index 5b010318286e..61a36fb54e87 100644 --- a/drivers/nvme/target/fabrics-cmd-auth.c +++ b/drivers/nvme/target/fabrics-cmd-auth.c @@ -6,6 +6,7 @@ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -18,16 +19,27 @@ static void nvmet_auth_expired_work(struct work_struct *work) struct nvmet_sq *sq = container_of(to_delayed_work(work), struct nvmet_sq, auth_expired_work); + mutex_lock(&sq->auth_lock); + /* A command may have cancelled or rearmed this timeout. */ + if (!sq->auth_expiry_active || + delayed_work_pending(&sq->auth_expired_work)) + goto out_unlock; + sq->auth_expiry_active = false; + pr_debug("%s: ctrl %d qid %d transaction %u expired, resetting\n", __func__, sq->ctrl->cntlid, sq->qid, sq->dhchap_tid); sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE; sq->dhchap_tid = -1; +out_unlock: + mutex_unlock(&sq->auth_lock); } void nvmet_auth_sq_init(struct nvmet_sq *sq) { /* Initialize in-band authentication */ + mutex_init(&sq->auth_lock); INIT_DELAYED_WORK(&sq->auth_expired_work, nvmet_auth_expired_work); + sq->auth_expiry_active = false; sq->authenticated = false; sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE; } @@ -258,6 +270,8 @@ void nvmet_execute_auth_send(struct nvmet_req *req) u16 status = 0; u8 dhchap_status; + mutex_lock(&req->sq->auth_lock); + if (req->cmd->auth_send.secp != NVME_AUTH_DHCHAP_PROTOCOL_IDENTIFIER) { status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; req->error_loc = @@ -283,8 +297,10 @@ void nvmet_execute_auth_send(struct nvmet_req *req) offsetof(struct nvmf_auth_send_command, tl); goto done; } - if (!nvmet_check_transfer_len(req, tl)) { + if (unlikely(tl != req->transfer_len)) { pr_debug("%s: transfer length mismatch (%u)\n", __func__, tl); + mutex_unlock(&req->sq->auth_lock); + nvmet_check_transfer_len(req, tl); return; } @@ -310,6 +326,7 @@ void nvmet_execute_auth_send(struct nvmet_req *req) /* Restart negotiation */ pr_debug("%s: ctrl %d qid %d reset negotiation\n", __func__, ctrl->cntlid, req->sq->qid); + nvmet_auth_sq_free(req->sq); if (!req->sq->qid) { dhchap_status = nvmet_setup_auth(ctrl, req->sq, true); @@ -408,10 +425,12 @@ void nvmet_execute_auth_send(struct nvmet_req *req) status, req->error_loc); if (req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2 && req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) { - unsigned long auth_expire_secs = ctrl->kato ? ctrl->kato : 120; + unsigned long auth_expire = min_t(u64, MAX_JIFFY_OFFSET, + (u64)(ctrl->kato ? ctrl->kato : 120) * HZ); - mod_delayed_work(system_wq, &req->sq->auth_expired_work, - auth_expire_secs * HZ); + req->sq->auth_expiry_active = true; + mod_delayed_work(system_percpu_wq, &req->sq->auth_expired_work, + auth_expire); goto complete; } /* Final states, clear up variables */ @@ -420,6 +439,7 @@ void nvmet_execute_auth_send(struct nvmet_req *req) nvmet_ctrl_fatal_error(ctrl); complete: + mutex_unlock(&req->sq->auth_lock); nvmet_req_complete(req, status); } @@ -538,6 +558,8 @@ void nvmet_execute_auth_receive(struct nvmet_req *req) u32 al; u16 status = 0; + mutex_lock(&req->sq->auth_lock); + if (req->cmd->auth_receive.secp != NVME_AUTH_DHCHAP_PROTOCOL_IDENTIFIER) { status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; req->error_loc = @@ -563,8 +585,10 @@ void nvmet_execute_auth_receive(struct nvmet_req *req) offsetof(struct nvmf_auth_receive_command, al); goto done; } - if (!nvmet_check_transfer_len(req, al)) { + if (unlikely(al != req->transfer_len)) { pr_debug("%s: transfer length mismatch (%u)\n", __func__, al); + mutex_unlock(&req->sq->auth_lock); + nvmet_check_transfer_len(req, al); return; } @@ -578,10 +602,11 @@ void nvmet_execute_auth_receive(struct nvmet_req *req) switch (req->sq->dhchap_step) { case NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE: if (nvmet_auth_challenge(req, d, al) < 0) { - pr_warn("ctrl %d qid %d: challenge error (%d)\n", - ctrl->cntlid, req->sq->qid, status); + pr_warn("ctrl %d qid %d: challenge error\n", + ctrl->cntlid, req->sq->qid); status = NVME_SC_INTERNAL; - break; + kfree(d); + goto done; } req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_REPLY; break; @@ -623,5 +648,6 @@ void nvmet_execute_auth_receive(struct nvmet_req *req) nvmet_auth_sq_free(req->sq); nvmet_ctrl_fatal_error(ctrl); } + mutex_unlock(&req->sq->auth_lock); nvmet_req_complete(req, status); } diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c index bc837fbfada1..9aedab2603bd 100644 --- a/drivers/nvme/target/fabrics-cmd.c +++ b/drivers/nvme/target/fabrics-cmd.c @@ -14,6 +14,10 @@ static void nvmet_execute_prop_set(struct nvmet_req *req) if (!nvmet_check_transfer_len(req, 0)) return; + if (!nvmet_check_auth_status(req)) { + status = NVME_SC_AUTH_REQUIRED | NVME_STATUS_DNR; + goto out; + } if (req->cmd->prop_set.attrib & 1) { req->error_loc = diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c index 1880fc780432..89edffeb1062 100644 --- a/drivers/nvme/target/fc.c +++ b/drivers/nvme/target/fc.c @@ -1710,7 +1710,7 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, be16_to_cpu(rqst->assoc_cmd.sqsize)); if (!queue) { ret = VERR_QUEUE_ALLOC_FAIL; - nvmet_fc_tgt_a_put(iod->assoc); + nvmet_fc_schedule_delete_assoc(iod->assoc); } } } @@ -2493,11 +2493,11 @@ __nvmet_fc_fcp_nvme_cmd_done(struct nvmet_fc_tgtport *tgtport, } else { /* - * try to push the data even if the SQE status is non-zero. - * There may be a status where data still was intended to - * be moved + * A failed command may not have filled its read buffer, so + * only push data for success, as the tcp and rdma targets do. */ - if ((fod->io_dir == NVMET_FCP_READ) && (fod->data_sg_cnt)) { + if (fod->io_dir == NVMET_FCP_READ && fod->data_sg_cnt && + !cqe->status) { /* push the data over before sending rsp */ nvmet_fc_transfer_fcp_data(tgtport, fod, NVMET_FCOP_READDATA); diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c index 0103815542d4..160364cc8c98 100644 --- a/drivers/nvme/target/io-cmd-bdev.c +++ b/drivers/nvme/target/io-cmd-bdev.c @@ -305,7 +305,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) &prot_miter); if (unlikely(rc)) { bio_io_error(bio); - return; + goto out_plug; } } @@ -325,11 +325,12 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) rc = nvmet_bdev_alloc_bip(req, bio, &prot_miter); if (unlikely(rc)) { bio_io_error(bio); - return; + goto out_plug; } } submit_bio(bio); +out_plug: blk_finish_plug(&plug); } diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c index 2d068439b129..6e1470016472 100644 --- a/drivers/nvme/target/io-cmd-file.c +++ b/drivers/nvme/target/io-cmd-file.c @@ -133,8 +133,8 @@ static bool nvmet_file_execute_io(struct nvmet_req *req, int ki_flags) pos = le64_to_cpu(req->cmd->rw.slba) << req->ns->blksize_shift; if (unlikely(pos + req->transfer_len > req->ns->size)) { - nvmet_req_complete(req, errno_to_nvme_status(req, -ENOSPC)); - return true; + ret = -ENOSPC; + goto complete; } memset(&req->f.iocb, 0, sizeof(struct kiocb)); diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index 87e2fdbd1865..45fc188412d2 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -156,8 +156,10 @@ struct nvmet_sq { u32 sqhd; bool sqhd_disabled; #ifdef CONFIG_NVME_TARGET_AUTH + struct mutex auth_lock; bool authenticated; struct delayed_work auth_expired_work; + bool auth_expiry_active; u16 dhchap_tid; u8 sc_c; u8 dhchap_status; diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c index e3815be98ee6..dcc6cae6f3c5 100644 --- a/drivers/nvme/target/pci-epf.c +++ b/drivers/nvme/target/pci-epf.c @@ -1095,10 +1095,22 @@ static int nvmet_pci_epf_iod_parse_sgl_segments(struct nvmet_pci_epf_ctrl *ctrl, return 0; } +static u64 nvmet_pci_epf_iod_data_segs_len(struct nvmet_pci_epf_iod *iod) +{ + u64 len = 0; + int i; + + for (i = 0; i < iod->nr_data_segs; i++) + len += iod->data_segs[i].length; + + return len; +} + static int nvmet_pci_epf_iod_parse_sgls(struct nvmet_pci_epf_iod *iod) { struct nvmet_pci_epf_ctrl *ctrl = iod->ctrl; struct nvme_sgl_desc *sgl = &iod->cmd.common.dptr.sgl; + int ret; if (sgl->type == (NVME_SGL_FMT_DATA_DESC << 4)) { /* Single data descriptor case. */ @@ -1106,10 +1118,23 @@ static int nvmet_pci_epf_iod_parse_sgls(struct nvmet_pci_epf_iod *iod) iod->data_segs = &iod->data_seg; iod->data_seg.pci_addr = le64_to_cpu(sgl->addr); iod->data_seg.length = le32_to_cpu(sgl->length); - return 0; + } else { + ret = nvmet_pci_epf_iod_parse_sgl_segments(ctrl, iod); + if (ret) + return ret; } - return nvmet_pci_epf_iod_parse_sgl_segments(ctrl, iod); + /* + * The command executes on data_len bytes, but each segment is + * allocated and transferred in full, so they must describe exactly + * data_len bytes. + */ + if (nvmet_pci_epf_iod_data_segs_len(iod) != iod->data_len) { + iod->status = NVME_SC_SGL_INVALID_DATA | NVME_STATUS_DNR; + return -EINVAL; + } + + return 0; } static int nvmet_pci_epf_alloc_iod_data_buf(struct nvmet_pci_epf_iod *iod) @@ -1174,7 +1199,6 @@ static void nvmet_pci_epf_complete_iod(struct nvmet_pci_epf_iod *iod) unsigned long flags; /* Print an error message for failed commands, except AENs. */ - iod->status = le16_to_cpu(iod->cqe.status) >> 1; if (iod->status && iod->cmd.common.opcode != nvme_admin_async_event) dev_err(iod->ctrl->dev, "CQ[%d]: Command %s (0x%x) status 0x%0x\n", diff --git a/drivers/nvme/target/pr.c b/drivers/nvme/target/pr.c index 9ab50f821ad6..0f696840b168 100644 --- a/drivers/nvme/target/pr.c +++ b/drivers/nvme/target/pr.c @@ -589,7 +589,7 @@ static u16 nvmet_pr_preempt(struct nvmet_req *req, &ctrl->hostid, abort); } - if (holder == reg) { + if (holder == reg && prkey == holder->rkey) { status = nvmet_pr_update_reg_attr(pr, holder, nvmet_pr_update_holder_rtype, &rtype); if (!status && original_rtype != rtype) diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index 2b03bce27a88..a0ba6641c7ff 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -1410,7 +1410,7 @@ nvmet_rdma_parse_cm_connect_req(struct rdma_conn_param *conn, struct nvme_rdma_cm_req *req; req = (struct nvme_rdma_cm_req *)conn->private_data; - if (!req || conn->private_data_len == 0) + if (!req || conn->private_data_len < sizeof(*req)) return NVME_RDMA_CM_INVALID_LEN; if (le16_to_cpu(req->recfmt) != NVME_RDMA_CM_FMT_1_0) diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c index 95af4b67108c..00f694ac3986 100644 --- a/drivers/nvme/target/zns.c +++ b/drivers/nvme/target/zns.c @@ -286,6 +286,11 @@ static void nvmet_bdev_zone_zmgmt_recv_work(struct work_struct *w) if (status) goto out; + /* Only the zone count and matching descriptors are written below. */ + status = nvmet_zero_sgl(req, 0, out_bufsize); + if (status) + goto out; + if (!req_slba_nr_zones) { status = NVME_SC_SUCCESS; goto out; @@ -314,6 +319,11 @@ static void nvmet_bdev_zone_zmgmt_recv_work(struct work_struct *w) void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req) { + u32 out_bufsize = (le32_to_cpu(req->cmd->zmr.numd) + 1) << 2; + + if (!nvmet_check_transfer_len(req, out_bufsize)) + return; + INIT_WORK(&req->z.zmgmt_work, nvmet_bdev_zone_zmgmt_recv_work); queue_work(zbd_wq, &req->z.zmgmt_work); } diff --git a/drivers/parisc/eisa_enumerator.c b/drivers/parisc/eisa_enumerator.c index f0cb31198a8f..aa41d3abc6c2 100644 --- a/drivers/parisc/eisa_enumerator.c +++ b/drivers/parisc/eisa_enumerator.c @@ -311,6 +311,7 @@ static int configure_function(const unsigned char *buf, int *more) static int parse_slot_config(int slot, const unsigned char *buf, + unsigned int buflen, struct eeprom_eisa_slot_info *es, struct resource *io_parent, struct resource *mem_parent) @@ -333,8 +334,8 @@ static int parse_slot_config(int slot, printk(KERN_INFO "EISA slot %d: %s %s ", slot, board, es->flags&HPEE_FLAG_BOARD_IS_ISA ? "ISA" : "EISA"); - maxlen = es->config_data_length < HPEE_MAX_LENGTH ? - es->config_data_length : HPEE_MAX_LENGTH; + /* never parse beyond the data that is actually in the buffer */ + maxlen = min_t(unsigned int, es->config_data_length, buflen); while ((pos < maxlen) && (num_func <= es->num_functions)) { pos+=configure_function(buf+pos, &function_len); @@ -491,6 +492,13 @@ int eisa_enumerator(unsigned long eeprom_addr, printk(KERN_INFO "Enumerating EISA bus\n"); eh = (struct eeprom_header*)(eeprom_buf); + /* + * The EEPROM contents are not to be trusted: clamp the number of + * slots so that all slot records fit into eeprom_buf. + */ + eh->num_slots = min_t(u8, eh->num_slots, + (HPEE_MAX_LENGTH - sizeof(*eh)) / + sizeof(struct eeprom_eisa_slot_info)); for (i=0;inum_slots;i++) { struct eeprom_eisa_slot_info *es; @@ -503,7 +511,8 @@ int eisa_enumerator(unsigned long eeprom_addr, if (es->config_data_offset < HPEE_MAX_LENGTH) { if (parse_slot_config(i+1, &eeprom_buf[es->config_data_offset], - es, io_parent, mem_parent)) { + HPEE_MAX_LENGTH - es->config_data_offset, + es, io_parent, mem_parent)) { return -1; } } else { diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index f1bc0ac81a92..72bb2a2dd238 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -920,6 +920,8 @@ static void qcom_pcie_ep_remove(struct platform_device *pdev) if (pcie_ep->link_status == QCOM_PCIE_EP_LINK_DISABLED) return; + pci_epc_deinit_notify(pcie_ep->pci.ep.epc); + dw_pcie_ep_deinit(&pcie_ep->pci.ep); qcom_pcie_disable_resources(pcie_ep); } diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index 799461335762..9ebc227a1ef8 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -553,19 +553,6 @@ static void rockchip_pcie_ep_link_training(struct work_struct *work) if (ret) goto again; - /* - * Check the current speed: if gen2 speed was requested and we are not - * at gen2 speed yet, retrain again for gen2. - */ - val = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL); - if (!PCIE_LINK_IS_GEN2(val) && rockchip->link_gen == 2) { - /* Enable retrain for gen2 */ - rockchip_pcie_ep_retrain_link(rockchip); - readl_poll_timeout(rockchip->apb_base + PCIE_CORE_CTRL, - val, PCIE_LINK_IS_GEN2(val), 50, - LINK_TRAIN_TIMEOUT); - } - /* Check again that the link is up */ if (!rockchip_pcie_ep_link_up(rockchip)) goto again; diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c index d203c4876d30..0b52f2e370f4 100644 --- a/drivers/pci/controller/pcie-rockchip-host.c +++ b/drivers/pci/controller/pcie-rockchip-host.c @@ -328,26 +328,6 @@ static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip) goto err_power_off_phy; } - if (rockchip->link_gen == 2) { - /* - * Enable retrain for gen2. This should be configured only after - * gen1 finished. - */ - status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL2); - status &= ~PCI_EXP_LNKCTL2_TLS; - status |= PCI_EXP_LNKCTL2_TLS_5_0GT; - rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL2); - status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL); - status |= PCI_EXP_LNKCTL_RL; - rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL); - - err = readl_poll_timeout(rockchip->apb_base + PCIE_CORE_CTRL, - status, PCIE_LINK_IS_GEN2(status), 20, - 500 * USEC_PER_MSEC); - if (err) - dev_dbg(dev, "PCIe link training gen2 timeout, fall back to gen1!\n"); - } - /* Check the final link width from negotiated lane counter from MGMT */ status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL); status = 0x1 << ((status & PCIE_CORE_PL_CONF_LANE_MASK) >> diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c index 0f88da378805..456dcfd676ed 100644 --- a/drivers/pci/controller/pcie-rockchip.c +++ b/drivers/pci/controller/pcie-rockchip.c @@ -66,8 +66,10 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip) } rockchip->link_gen = of_pci_get_max_link_speed(node); - if (rockchip->link_gen < 0 || rockchip->link_gen > 2) - rockchip->link_gen = 2; + if (rockchip->link_gen < 0 || rockchip->link_gen >= 2) { + rockchip->link_gen = 1; + dev_warn(dev, "invalid max-link-speed, limited to 2.5 GT/s\n"); + } for (i = 0; i < ROCKCHIP_NUM_PM_RSTS; i++) rockchip->pm_rsts[i].id = rockchip_pci_pm_rsts[i]; @@ -147,12 +149,8 @@ int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) goto err_exit_phy; } - if (rockchip->link_gen == 2) - rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2, - PCIE_CLIENT_CONFIG); - else - rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1, - PCIE_CLIENT_CONFIG); + rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1, + PCIE_CLIENT_CONFIG); regs = PCIE_CLIENT_ARI_ENABLE | PCIE_CLIENT_CONF_LANE_NUM(rockchip->lanes); diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h index 3e82a69b9c00..b5da15601b58 100644 --- a/drivers/pci/controller/pcie-rockchip.h +++ b/drivers/pci/controller/pcie-rockchip.h @@ -42,7 +42,6 @@ #define PCIE_CLIENT_MODE_RC HWORD_SET_BIT(0x0040) #define PCIE_CLIENT_MODE_EP HWORD_CLR_BIT(0x0040) #define PCIE_CLIENT_GEN_SEL_1 HWORD_CLR_BIT(0x0080) -#define PCIE_CLIENT_GEN_SEL_2 HWORD_SET_BIT(0x0080) #define PCIE_CLIENT_LEGACY_INT_CTRL (PCIE_CLIENT_BASE + 0x0c) #define PCIE_CLIENT_INT_IN_ASSERT HWORD_SET_BIT(0x0002) #define PCIE_CLIENT_INT_IN_DEASSERT HWORD_CLR_BIT(0x0002) @@ -197,8 +196,6 @@ (((x) & PCIE_CORE_PL_CONF_LS_MASK) == PCIE_CORE_PL_CONF_LS_READY) #define PCIE_LINK_UP(x) \ (((x) & PCIE_CLIENT_LINK_STATUS_MASK) == PCIE_CLIENT_LINK_STATUS_UP) -#define PCIE_LINK_IS_GEN2(x) \ - (((x) & PCIE_CORE_PL_CONF_SPEED_MASK) == PCIE_CORE_PL_CONF_SPEED_5G) #define RC_REGION_0_ADDR_TRANS_H 0x00000000 #define RC_REGION_0_ADDR_TRANS_L 0x00000000 diff --git a/drivers/pci/controller/pcie-xilinx-dma-pl.c b/drivers/pci/controller/pcie-xilinx-dma-pl.c index b037c8f315e4..e18eeecdc8a9 100644 --- a/drivers/pci/controller/pcie-xilinx-dma-pl.c +++ b/drivers/pci/controller/pcie-xilinx-dma-pl.c @@ -581,7 +581,7 @@ static int xilinx_pl_dma_pcie_init_irq_domain(struct pl_dma_pcie *port) port->pldma_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), 32, &event_domain_ops, port); if (!port->pldma_domain) - return -ENOMEM; + goto err_put_node; irq_domain_update_bus_token(port->pldma_domain, DOMAIN_BUS_NEXUS); @@ -589,7 +589,7 @@ static int xilinx_pl_dma_pcie_init_irq_domain(struct pl_dma_pcie *port) &intx_domain_ops, port); if (!port->intx_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); - return -ENOMEM; + goto err_put_node; } irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED); @@ -597,13 +597,17 @@ static int xilinx_pl_dma_pcie_init_irq_domain(struct pl_dma_pcie *port) ret = xilinx_pl_dma_pcie_init_msi_irq_domain(port); if (ret != 0) { irq_domain_remove(port->intx_domain); - return -ENOMEM; + goto err_put_node; } of_node_put(pcie_intc_node); raw_spin_lock_init(&port->lock); return 0; + +err_put_node: + of_node_put(pcie_intc_node); + return -ENOMEM; } static int xilinx_pl_dma_pcie_setup_irq(struct pl_dma_pcie *port) diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c index aae9a8a00406..3b0cc6db4402 100644 --- a/drivers/pci/doe.c +++ b/drivers/pci/doe.c @@ -210,8 +210,9 @@ static int pci_doe_sysfs_feature_populate(struct pci_dev *pdev, pci_warn(pdev, "Failed adding %s to sysfs group\n", attrs[i].attr.name); goto fail; - } else - kfree(attrs[i].attr.name); + } + kfree(attrs[i].attr.name); + attrs[i].attr.name = NULL; } } diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index f59baa912970..785b7d5e7c09 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -38,7 +38,7 @@ int pciehp_poll_time; * not really modular, but the easiest way to keep compat with existing * bootargs behaviour is to continue using module_param here. */ -module_param(pciehp_poll_mode, bool, 0644); +module_param(pciehp_poll_mode, bool, 0444); module_param(pciehp_poll_time, int, 0644); MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index 0c6446519640..c224619b9a26 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -144,7 +144,7 @@ static int dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf) int len; len = utf16s_to_utf8s((const wchar_t *)obj->buffer.pointer, - obj->buffer.length, + obj->buffer.length / sizeof(wchar_t), UTF16_LITTLE_ENDIAN, buf, PAGE_SIZE - 1); buf[len++] = '\n'; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index bab3213bafbd..25720f28518a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3242,7 +3242,15 @@ void pci_pm_init(struct pci_dev *dev) } poweron: - pci_pm_power_up_and_verify_state(dev); + pci_update_current_state(dev, PCI_UNKNOWN); + if (dev->current_state == PCI_D0) { + /* No need for full power-up, just sync-up platform state */ + platform_pci_set_power_state(dev, PCI_D0); + } else { + /* Power up the device and restore BARs if necessary */ + pci_set_full_power_state(dev, false); + } + pci_update_current_state(dev, PCI_D0); pm_runtime_forbid(&dev->dev); /* @@ -5892,18 +5900,31 @@ static enum pci_bus_speed to_pcie_link_speed(u16 lnksta) return pcie_link_speed[FIELD_GET(PCI_EXP_LNKSTA_CLS, lnksta)]; } -int pcie_link_speed_mbps(struct pci_dev *pdev) +/** + * pcie_link_bandwidth_mbps - get the current bandwidth of a single PCIe link + * @pdev: PCI device to query + * + * The bandwidth includes all negotiated lanes and does not account for + * encoding overhead. A negotiated width of zero gives zero bandwidth. + * + * Return: Bandwidth in Mb/s, or a negative errno on failure. + */ +int pcie_link_bandwidth_mbps(struct pci_dev *pdev) { u16 lnksta; - int err; + int speed, err; err = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnksta); if (err) - return err; + return pcibios_err_to_errno(err); + + speed = pcie_dev_speed_mbps(to_pcie_link_speed(lnksta)); + if (speed < 0) + return speed; - return pcie_dev_speed_mbps(to_pcie_link_speed(lnksta)); + return speed * FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta); } -EXPORT_SYMBOL(pcie_link_speed_mbps); +EXPORT_SYMBOL(pcie_link_bandwidth_mbps); /** * pcie_bandwidth_available - determine minimum link settings of a PCIe diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 9f90abe3e88e..ad3fea4b56f8 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -1379,11 +1379,14 @@ void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, }; if (kfifo_in_spinlocked(&aer_recover_ring, &entry, 1, - &aer_recover_ring_lock)) + &aer_recover_ring_lock)) { schedule_work(&aer_recover_work); - else + } else { pr_err("buffer overflow in recovery for %04x:%02x:%02x.%x\n", domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + ghes_estatus_pool_region_free((unsigned long)aer_regs, + sizeof(struct aer_capability_regs)); + } } EXPORT_SYMBOL_GPL(aer_recover_queue); #endif diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 4e4e38e62691..082c51ce8893 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1661,6 +1661,8 @@ void set_pcie_port_type(struct pci_dev *pdev) pdev->aspm_l1_support = 1; #endif + pdev->supported_speeds = pcie_get_supported_speeds(pdev); + parent = pci_upstream_bridge(pdev); if (!parent) return; @@ -2046,9 +2048,6 @@ int pci_setup_device(struct pci_dev *dev) set_pcie_untrusted(dev); - if (pci_is_pcie(dev)) - dev->supported_speeds = pcie_get_supported_speeds(dev); - /* "Unknown power state" */ dev->current_state = PCI_UNKNOWN; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e03a3831bcc0..812b01d24fc4 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -103,7 +103,11 @@ int pcie_failed_link_retrain(struct pci_dev *dev) pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta); pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &oldlnkctl2); - if (!(lnksta & PCI_EXP_LNKSTA_DLLLA) && pcie_lbms_seen(dev, lnksta)) { + if (lnksta & PCI_EXP_LNKSTA_DLLLA) { + ; + } else if (PCIE_LNKCTL2_TLS2SPEED(oldlnkctl2) == PCIE_SPEED_2_5GT) { + return ret; + } else if (pcie_lbms_seen(dev, lnksta)) { pci_info(dev, "broken device, retraining non-functional downstream link at 2.5GT/s\n"); ret = pcie_set_target_speed(dev, PCIE_SPEED_2_5GT, false); if (ret) @@ -1940,6 +1944,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4388, quirk_no_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4389, quirk_no_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x438a, quirk_no_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x438b, quirk_no_msi); +/* ULi M1575 EHCI (10b9:5239): MSI stalls the async schedule */ +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x5239, quirk_no_msi); static void quirk_pcie_mch(struct pci_dev *pdev) { @@ -2380,6 +2386,24 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, DECLARE_PCI_FIXUP_HEADER(0x1402, 0x2000, quirk_plx_pci9050); DECLARE_PCI_FIXUP_HEADER(0x1402, 0x2600, quirk_plx_pci9050); +/* + * An idle downstream port of a PLX/Broadcom PEX 8532/8533/8548 switch + * autosuspends into D3hot, and that takes the whole switch down with + * it -- any device behind another port of the same switch then sees a + * fatal, non-recoverable bus fault on its next access. Keep these + * ports out of D3 entirely. + */ +static void quirk_plx_pex_no_d3(struct pci_dev *dev) +{ + if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) { + dev->dev_flags |= PCI_DEV_FLAGS_NO_D3; + pci_info(dev, "avoiding D3 on this downstream port\n"); + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_PLX, 0x8532, quirk_plx_pex_no_d3); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_PLX, 0x8533, quirk_plx_pex_no_d3); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_PLX, 0x8548, quirk_plx_pex_no_d3); + static void quirk_netmos(struct pci_dev *dev) { unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4; diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 11636634ae51..451476ce10ae 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -599,11 +599,16 @@ static pci_ers_result_t pcifront_common_process(int cmd, case XEN_PCI_OP_aer_detected: return pdrv->err_handler->error_detected(pcidev, state); case XEN_PCI_OP_aer_mmio: - return pdrv->err_handler->mmio_enabled(pcidev); + if (pdrv->err_handler->mmio_enabled) + return pdrv->err_handler->mmio_enabled(pcidev); + return PCI_ERS_RESULT_RECOVERED; case XEN_PCI_OP_aer_slotreset: - return pdrv->err_handler->slot_reset(pcidev); + if (pdrv->err_handler->slot_reset) + return pdrv->err_handler->slot_reset(pcidev); + return PCI_ERS_RESULT_RECOVERED; case XEN_PCI_OP_aer_resume: - pdrv->err_handler->resume(pcidev); + if (pdrv->err_handler->resume) + pdrv->err_handler->resume(pcidev); return PCI_ERS_RESULT_NONE; default: dev_err(&pdev->xdev->dev, diff --git a/drivers/peci/controller/peci-aspeed.c b/drivers/peci/controller/peci-aspeed.c index ad3a7d71ed4c..57e1a7138607 100644 --- a/drivers/peci/controller/peci-aspeed.c +++ b/drivers/peci/controller/peci-aspeed.c @@ -527,14 +527,14 @@ static int aspeed_peci_probe(struct platform_device *pdev) if (priv->irq < 0) return priv->irq; + init_completion(&priv->xfer_complete); + spin_lock_init(&priv->lock); + ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler, 0, "peci-aspeed", priv); if (ret) return ret; - init_completion(&priv->xfer_complete); - spin_lock_init(&priv->lock); - priv->rst = devm_reset_control_get(&pdev->dev, NULL); if (IS_ERR(priv->rst)) return dev_err_probe(priv->dev, PTR_ERR(priv->rst), diff --git a/drivers/peci/controller/peci-npcm.c b/drivers/peci/controller/peci-npcm.c index 931868991241..3cc4e959aff3 100644 --- a/drivers/peci/controller/peci-npcm.c +++ b/drivers/peci/controller/peci-npcm.c @@ -253,14 +253,14 @@ static int npcm_peci_probe(struct platform_device *pdev) if (priv->irq < 0) return priv->irq; + init_completion(&priv->xfer_complete); + spin_lock_init(&priv->lock); + ret = devm_request_irq(&pdev->dev, priv->irq, npcm_peci_irq_handler, 0, "peci-npcm-irq", priv); if (ret) return ret; - init_completion(&priv->xfer_complete); - spin_lock_init(&priv->lock); - ret = npcm_peci_init_ctrl(priv); if (ret) return ret; diff --git a/drivers/perf/xgene_pmu.c b/drivers/perf/xgene_pmu.c index 33b5497bdc06..ecbcd2d39f9e 100644 --- a/drivers/perf/xgene_pmu.c +++ b/drivers/perf/xgene_pmu.c @@ -1873,6 +1873,8 @@ static int xgene_pmu_probe(struct platform_device *pdev) if (irq < 0) return -EINVAL; + raw_spin_lock_init(&xgene_pmu->lock); + rc = devm_request_irq(&pdev->dev, irq, xgene_pmu_isr, IRQF_NOBALANCING | IRQF_NO_THREAD, dev_name(&pdev->dev), xgene_pmu); @@ -1883,8 +1885,6 @@ static int xgene_pmu_probe(struct platform_device *pdev) xgene_pmu->irq = irq; - raw_spin_lock_init(&xgene_pmu->lock); - /* Check for active MCBs and MCUs */ rc = xgene_pmu_probe_active_mcb_mcu_l3c(xgene_pmu, pdev); if (rc) { diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c index e73feb8ac90d..f64dbb29a99d 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -1452,8 +1452,12 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, struct fwnode /* get the last defined gpio line (offset + nb of pins) */ npins = args.args[0] + args.args[2]; - while (!fwnode_property_get_reference_args(fwnode, "gpio-ranges", NULL, 3, ++i, &args)) + fwnode_handle_put(args.fwnode); + + while (!fwnode_property_get_reference_args(fwnode, "gpio-ranges", NULL, 3, ++i, &args)) { npins = max(npins, (int)(args.args[0] + args.args[2])); + fwnode_handle_put(args.fwnode); + } } else { bank_nr = pctl->nbanks; bank->gpio_chip.base = bank_nr * STM32_GPIO_PINS_PER_BANK; diff --git a/drivers/platform/x86/amd/hfi/hfi.c b/drivers/platform/x86/amd/hfi/hfi.c index ac6ef0b5b95b..1d12a3b8f32f 100644 --- a/drivers/platform/x86/amd/hfi/hfi.c +++ b/drivers/platform/x86/amd/hfi/hfi.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -169,6 +170,21 @@ static int amd_hfi_fill_metadata(struct amd_hfi_data *amd_hfi_data) return -EINVAL; } + /* + * The bitmaps enumerating the APIC IDs occupy the first n_bitmaps + * words of table_data. Reject a firmware-provided count that would + * push those reads past the end of the shared memory region. + */ + if (struct_size(amd_hfi_data->shmem, table_data, amd_hfi_data->shmem->n_bitmaps) > + pcct_ext->length) { + dev_err(amd_hfi_data->dev, "invalid number of bitmaps: %u\n", + amd_hfi_data->shmem->n_bitmaps); + return -EINVAL; + } + + /* The ranking data for each processor follows the bitmaps */ + u32 *table = amd_hfi_data->shmem->table_data + amd_hfi_data->shmem->n_bitmaps; + for (unsigned int i = 0; i < amd_hfi_data->shmem->n_bitmaps; i++) { u32 bitmap = amd_hfi_data->shmem->table_data[i]; @@ -193,10 +209,6 @@ static int amd_hfi_fill_metadata(struct amd_hfi_data *amd_hfi_data) info = per_cpu_ptr(&amd_hfi_cpuinfo, cpu_index); apic_index = apic_start * info->nr_class * 2; for (unsigned int k = 0; k < info->nr_class; k++) { - u32 *table = amd_hfi_data->shmem->table_data + - amd_hfi_data->shmem->n_bitmaps + - i * info->nr_class; - info->amd_hfi_classes[k].eff = table[apic_index + 2 * k]; info->amd_hfi_classes[k].perf = table[apic_index + 2 * k + 1]; } diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c index 000f876e27eb..8abb80e1803f 100644 --- a/drivers/platform/x86/amd/pmc/pmc.c +++ b/drivers/platform/x86/amd/pmc/pmc.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -554,7 +555,6 @@ static int amd_pmc_wa_irq1(struct amd_pmc_dev *pdev) static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg) { - struct rtc_device *rtc_device; time64_t then, now, duration; struct rtc_wkalrm alarm; struct rtc_time tm; @@ -570,7 +570,8 @@ static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg) if (pdev->major < 64 || (pdev->major == 64 && pdev->minor < 53)) return 0; - rtc_device = rtc_class_open("rtc0"); + struct rtc_device *rtc_device __free(rtc_class_close) = + rtc_class_open("rtc0"); if (!rtc_device) return 0; rc = rtc_read_alarm(rtc_device, &alarm); @@ -604,19 +605,6 @@ static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg) return rc; } -static bool amd_pmc_intermediate_wakeup_need_delay(struct amd_pmc_dev *pdev) -{ - /* - * Starting a new HW sleep cycle right after waking from one - * can cause electrical problems triggering the over voltage protection. - * That is avoided by delaying the next suspend a bit, see also - * https://lore.kernel.org/all/20250414162446.3853194-1-superm1@kernel.org/ - */ - struct smu_metrics table; - - return get_metrics_table(pdev, &table) == 0 && table.s0i3_last_entry_status; -} - static bool amd_pmc_want_suspend_delay(struct amd_pmc_dev *pdev) { /* @@ -709,7 +697,7 @@ static void amd_pmc_s2idle_check(void) struct amd_pmc_dev *pdev = &pmc; int rc; - if (amd_pmc_intermediate_wakeup_need_delay(pdev) || + if (!pdev->is_first_check_after_suspend || amd_pmc_want_suspend_delay(pdev)) msleep(2500); diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c index 85192c7536b8..cbe4eef5b8bb 100644 --- a/drivers/platform/x86/amd/pmf/spc.c +++ b/drivers/platform/x86/amd/pmf/spc.c @@ -244,13 +244,11 @@ static int amd_pmf_get_battery_prop(enum power_supply_property prop) continue; ret = power_supply_get_property(psy, prop, &value); - if (ret) { - power_supply_put(psy); - return ret; - } + power_supply_put(psy); + return ret ? ret : value.intval; } - return value.intval; + return -ENODEV; } static int amd_pmf_get_battery_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) diff --git a/drivers/platform/x86/amd/pmf/sps.c b/drivers/platform/x86/amd/pmf/sps.c index c28f3c5744c2..bf101e527b11 100644 --- a/drivers/platform/x86/amd/pmf/sps.c +++ b/drivers/platform/x86/amd/pmf/sps.c @@ -248,20 +248,24 @@ static int amd_pmf_update_sps_power_limits_v2(struct amd_pmf_dev *pdev, int pwr_ switch (pwr_mode) { case POWER_MODE_PERFORMANCE: index = config_store_v2.sps_idx.power_states[src][POWER_MODE_BEST_PERFORMANCE]; - amd_pmf_update_slider_v2(pdev, index); break; case POWER_MODE_BALANCED_POWER: index = config_store_v2.sps_idx.power_states[src][POWER_MODE_BALANCED]; - amd_pmf_update_slider_v2(pdev, index); break; case POWER_MODE_POWER_SAVER: index = config_store_v2.sps_idx.power_states[src][POWER_MODE_BEST_POWER_EFFICIENCY]; - amd_pmf_update_slider_v2(pdev, index); break; default: return -EINVAL; } + if (index >= APTS_MAX_STATES) { + dev_err(pdev->dev, "Invalid APTS index: %d\n", index); + return -EINVAL; + } + + amd_pmf_update_slider_v2(pdev, index); + return 0; } diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 9f0f79030b5b..c8cc47df9294 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -998,10 +998,10 @@ static ssize_t kbd_rgb_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - u32 flags, cmd, boot, awake, sleep, keyboard; + u32 flags, cmd, boot, awake, sleep, shutdown; int err; - if (sscanf(buf, "%d %d %d %d %d", &cmd, &boot, &awake, &sleep, &keyboard) != 5) + if (sscanf(buf, "%d %d %d %d %d", &cmd, &boot, &awake, &sleep, &shutdown) != 5) return -EINVAL; if (cmd) @@ -1014,7 +1014,7 @@ static ssize_t kbd_rgb_state_store(struct device *dev, flags |= BIT(3); if (sleep) flags |= BIT(5); - if (keyboard) + if (shutdown) flags |= BIT(7); /* 0xbd is the required default arg0 for the method. Nothing happens otherwise */ @@ -1028,7 +1028,7 @@ static ssize_t kbd_rgb_state_store(struct device *dev, static DEVICE_ATTR_WO(kbd_rgb_state); static DEVICE_STRING_ATTR_RO(kbd_rgb_state_index, 0444, - "cmd boot awake sleep keyboard"); + "cmd boot awake sleep shutdown"); static struct attribute *kbd_rgb_state_attrs[] = { &dev_attr_kbd_rgb_state.attr, @@ -4122,13 +4122,20 @@ static int is_display_toggle(int code) static int read_screenpad_backlight_power(struct asus_wmi *asus) { - int ret; + int ret, retval; - ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); + ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_POWER, &retval); if (ret < 0) return ret; - /* 1 == powered */ - return ret ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF; + + /* + * The firmware reports the panel power in the low byte of the + * devstate as a raw EC status byte that is non-zero when the + * panel is powered; other models report it through + * ASUS_WMI_DSTS_STATUS_BIT, which lies inside the same mask. + */ + return (retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK) ? + BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF; } static int read_screenpad_brightness(struct backlight_device *bd) @@ -4156,7 +4163,8 @@ static int update_screenpad_bl_status(struct backlight_device *bd) u32 ctrl_param = bd->props.brightness; int err = 0; - if (bd->props.power) { + switch (bd->props.power) { + case BACKLIGHT_POWER_ON: err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 1, NULL); if (err < 0) return err; @@ -4164,12 +4172,17 @@ static int update_screenpad_bl_status(struct backlight_device *bd) err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL); if (err < 0) return err; - } + break; - if (!bd->props.power) { + case BACKLIGHT_POWER_OFF: err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL); if (err < 0) return err; + break; + + default: + pr_warn("Invalid screenpad backlight power state: %d\n", bd->props.power); + return -EINVAL; } return err; @@ -4186,16 +4199,17 @@ static int asus_screenpad_init(struct asus_wmi *asus) struct backlight_device *bd; struct backlight_properties props; int err, power; - int brightness = 0; + u32 brightness = 0; - power = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); + power = read_screenpad_backlight_power(asus); if (power < 0) return power; - if (power) { + if (power == BACKLIGHT_POWER_ON) { err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness); if (err < 0) return err; + brightness &= ASUS_WMI_DSTS_BRIGHTNESS_MASK; } memset(&props, 0, sizeof(struct backlight_properties)); diff --git a/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c b/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c index 274bdecce685..0dac3a853dfe 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c +++ b/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include "bioscfg.h" #include "../../firmware_attributes_class.h" @@ -53,74 +53,44 @@ int hp_get_integer_from_buffer(u8 **buffer, u32 *buffer_size, u32 *integer) int hp_get_string_from_buffer(u8 **buffer, u32 *buffer_size, char *dst, u32 dst_size) { + char utf8_buf[MAX_BUFF_SIZE]; u16 *src = (u16 *)*buffer; + int escaped_len; + u16 orig_size; u16 src_size; - - u16 size; - int i; - int conv_dst_size; + int utf8_len; if (*buffer_size < sizeof(u16)) return -EINVAL; - src_size = *(src++); - /* size value in u16 chars */ - size = src_size / sizeof(u16); + src_size = *src; - /* Ensure there is enough space remaining to read and convert - * the string + /* + * Ensure there is enough space remaining for the length prefix + * just read plus the string data it describes. */ - if (*buffer_size < src_size) + if (*buffer_size < sizeof(u16) + src_size) return -EINVAL; - for (i = 0; i < size; i++) - if (src[i] == '\\' || - src[i] == '\r' || - src[i] == '\n' || - src[i] == '\t') - size++; - - /* - * Conversion is limited to destination string max number of - * bytes. - */ - conv_dst_size = size; - if (size >= dst_size) - conv_dst_size = dst_size - 1; + src++; + /* size value in u16 chars */ + orig_size = src_size / sizeof(u16); - /* - * convert from UTF-16 unicode to ASCII - */ - utf16s_to_utf8s(src, src_size, UTF16_HOST_ENDIAN, dst, conv_dst_size); - dst[conv_dst_size] = 0; - - for (i = 0; i < conv_dst_size; i++) { - if (*src == '\\' || - *src == '\r' || - *src == '\n' || - *src == '\t') { - dst[i++] = '\\'; - if (i == conv_dst_size) - break; - } + utf8_len = utf16s_to_utf8s(src, orig_size, UTF16_HOST_ENDIAN, + utf8_buf, sizeof(utf8_buf)); - if (*src == '\r') - dst[i] = 'r'; - else if (*src == '\n') - dst[i] = 'n'; - else if (*src == '\t') - dst[i] = 't'; - else if (*src == '"') - dst[i] = '\''; - else - dst[i] = *src; - src++; - } + escaped_len = string_escape_mem(utf8_buf, utf8_len, dst, dst_size - 1, + ESCAPE_SPACE | ESCAPE_SPECIAL, + "\\\r\n\t"); + if (escaped_len > dst_size - 1) + escaped_len = dst_size - 1; + dst[escaped_len] = '\0'; + strreplace(dst, '"', '\''); - *buffer = (u8 *)src; - *buffer_size -= size * sizeof(u16); + *buffer += sizeof(u16) + src_size; + *buffer_size -= sizeof(u16) + src_size; - return size; + return escaped_len; } int hp_get_common_data_from_buffer(u8 **buffer_ptr, u32 *buffer_size, @@ -442,7 +412,7 @@ int hp_convert_hexstr_to_str(const char *input, u32 input_len, char **str, int * *len = 0; *str = NULL; - new_str = kmalloc(input_len, GFP_KERNEL); + new_str = kmalloc(2 * DIV_ROUND_UP(input_len, 5) + 1, GFP_KERNEL); if (!new_str) return -ENOMEM; diff --git a/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c index 6b94f90bea07..97990191b71f 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c @@ -60,7 +60,8 @@ int hp_get_password_instance_for_type(const char *name) return -EINVAL; } -static int validate_password_input(int instance_id, const char *buf) +static int validate_password_input(int instance_id, const char *buf, + bool is_current) { int length; struct password_data *password_data = &bioscfg_drv.password_data[instance_id]; @@ -69,13 +70,18 @@ static int validate_password_input(int instance_id, const char *buf) if (length > 0 && buf[length - 1] == '\n') length--; + /* An empty current_password clears the session password */ + if (is_current && !length) + return 0; + if (length > MAX_PASSWD_SIZE) - return INVALID_BIOS_AUTH; + return -E2BIG; if (password_data->min_password_length > length || password_data->max_password_length < length) - return INVALID_BIOS_AUTH; - return SUCCESS; + return -E2BIG; + + return 0; } ATTRIBUTE_N_PROPERTY_SHOW(is_enabled, password); @@ -96,7 +102,7 @@ static int store_password_instance(struct kobject *kobj, const char *buf, id = get_password_instance_id(kobj); if (id >= 0) - ret = validate_password_input(id, buf_cp); + ret = validate_password_input(id, buf_cp, is_current); } if (!ret) { diff --git a/drivers/platform/x86/hp/hp-bioscfg/spmobj-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/spmobj-attributes.c index 4d94e48c1a4c..040964ed50ce 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/spmobj-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/spmobj-attributes.c @@ -47,9 +47,6 @@ size_t hp_calculate_security_buffer(const char *authentication) return sizeof(u16) * 2; authlen = strlen(authentication); - if (!authlen) - return sizeof(u16) * 2; - size = sizeof(u16) + authlen * sizeof(u16); if (!strstarts(authentication, BEAM_PREFIX)) size += strlen(UTF_PREFIX) * sizeof(u16); @@ -310,7 +307,7 @@ static ssize_t auth_token_store(struct kobject *kobj, length--; /* allocate space and copy current auth token */ - bioscfg_drv.spm_data.auth_token = kmemdup(buf, length, GFP_KERNEL); + bioscfg_drv.spm_data.auth_token = kstrndup(buf, length, GFP_KERNEL); if (!bioscfg_drv.spm_data.auth_token) { ret = -ENOMEM; goto exit_token; diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c index 5eb2aade44cc..f92bb3dca2e3 100644 --- a/drivers/platform/x86/hp/hp-wmi.c +++ b/drivers/platform/x86/hp/hp-wmi.c @@ -491,8 +491,9 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command, goto out_free; } - if (obj->type != ACPI_TYPE_BUFFER) { - pr_warn("query 0x%x returned an invalid object 0x%x\n", query, ret); + if (obj->type != ACPI_TYPE_BUFFER || + obj->buffer.length < sizeof(*bios_return)) { + pr_warn("query 0x%x returned wrong type or too small buffer\n", query); ret = -EINVAL; goto out_free; } @@ -511,7 +512,7 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command, if (!outsize) goto out_free; - actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return))); + actual_outsize = min_t(u32, outsize, obj->buffer.length - sizeof(*bios_return)); memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize); memset(buffer + actual_outsize, 0, outsize - actual_outsize); diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index 1505fc3ef7a8..96c33ba80002 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -280,7 +280,6 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, unsigned long gpio_flags; union acpi_object *obj; struct gpio_desc *gpio; - const char *err_msg; const char *con_id; int ret; @@ -326,7 +325,8 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, 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"; + dev_err_probe(int3472->dev, ret, + "Failed to map GPIO pin to sensor\n"); break; case INT3472_GPIO_TYPE_CLK_ENABLE: @@ -336,7 +336,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, con_id, gpio_flags); if (IS_ERR(gpio)) { ret = PTR_ERR(gpio); - err_msg = "Failed to get GPIO\n"; + dev_err_probe(int3472->dev, ret, "Failed to get GPIO\n"); break; } @@ -344,13 +344,15 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, case INT3472_GPIO_TYPE_CLK_ENABLE: ret = skl_int3472_register_gpio_clock(int3472, gpio); if (ret) - err_msg = "Failed to register clock\n"; + dev_err_probe(int3472->dev, ret, + "Failed to register clock\n"); break; case INT3472_GPIO_TYPE_PRIVACY_LED: ret = skl_int3472_register_pled(int3472, gpio); if (ret) - err_msg = "Failed to register LED\n"; + dev_err_probe(int3472->dev, ret, + "Failed to register LED\n"); break; case INT3472_GPIO_TYPE_POWER_ENABLE: @@ -360,7 +362,8 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, ret = skl_int3472_register_regulator(int3472, gpio, enable_time_us, con_id, second_sensor); if (ret) - err_msg = "Failed to register regulator\n"; + dev_err_probe(int3472->dev, ret, + "Failed to register regulator\n"); break; default: /* Never reached */ @@ -383,11 +386,11 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, int3472->ngpios++; ACPI_FREE(obj); - if (ret < 0) - return dev_err_probe(int3472->dev, ret, err_msg); - - /* Tell acpi_dev_get_resources() to not make a copy of the resource */ - return 1; + /* + * Either return an error or tell acpi_dev_get_resources() to not make a + * copy of the resource. + */ + return ret < 0 ? ret : 1; } int int3472_discrete_parse_crs(struct int3472_discrete_device *int3472) diff --git a/drivers/platform/x86/intel/pmt/class.c b/drivers/platform/x86/intel/pmt/class.c index 8077274726b5..9ec843617e3c 100644 --- a/drivers/platform/x86/intel/pmt/class.c +++ b/drivers/platform/x86/intel/pmt/class.c @@ -339,7 +339,14 @@ static int intel_pmt_dev_register(struct intel_pmt_entry *entry, sysfs_bin_attr_init(&entry->pmt_bin_attr); entry->pmt_bin_attr.attr.name = ns->name; entry->pmt_bin_attr.attr.mode = 0440; - entry->pmt_bin_attr.mmap = intel_pmt_mmap; + + /* + * The read_telem callback controls access to the memory area. Block + * usage if the read_telem callback is present. + */ + if (!(entry->cb && entry->cb->read_telem)) + entry->pmt_bin_attr.mmap = intel_pmt_mmap; + entry->pmt_bin_attr.read = intel_pmt_read; entry->pmt_bin_attr.size = entry->size; diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c index 0dfc552b2802..3836d76943f5 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c @@ -211,7 +211,7 @@ static int uncore_pm_notify(struct notifier_block *nb, unsigned long mode, struct uncore_data *data = &uncore_instances[i]; if (!data || !data->valid || !data->stored_uncore_data) - return 0; + continue; wrmsrq_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, data->stored_uncore_data); diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index 1e292eaeb209..814e418bea82 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -617,7 +617,7 @@ static bool intel_vsec_get_features(struct pci_dev *pdev, found = true; if (info && (info->quirks & VSEC_QUIRK_NO_DVSEC) && - intel_vsec_walk_header(&pdev->dev, info)) + !intel_vsec_walk_header(&pdev->dev, info)) found = true; return found; diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c index a30845ba3796..4fc931029634 100644 --- a/drivers/platform/x86/oxpec.c +++ b/drivers/platform/x86/oxpec.c @@ -60,6 +60,7 @@ enum oxp_board { oxp_x1, oxp_g1_i, oxp_g1_a, + oxp_apex, }; static enum oxp_board board; @@ -103,11 +104,14 @@ static struct device *oxp_dev; #define OXP_X1_CHARGE_LIMIT_REG 0xA3 /* X1 charge limit (%) */ #define OXP_X1_CHARGE_INHIBIT_REG 0xA4 /* X1 bypass charging */ -#define OXP_X1_CHARGE_INHIBIT_MASK_AWAKE 0x01 +#define OXP_APEX_CHARGE_LIMIT_REG 0xE5 /* Apex charge limit (%) */ +#define OXP_APEX_CHARGE_INHIBIT_REG 0xE6 /* Apex bypass charging */ + +#define OXP_CHARGE_INHIBIT_MASK_AWAKE 0x01 /* X1 Mask is 0x0A, F1Pro is 0x02 but the extra bit on the X1 does nothing. */ -#define OXP_X1_CHARGE_INHIBIT_MASK_OFF 0x02 -#define OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS (OXP_X1_CHARGE_INHIBIT_MASK_AWAKE | \ - OXP_X1_CHARGE_INHIBIT_MASK_OFF) +#define OXP_CHARGE_INHIBIT_MASK_OFF 0x02 +#define OXP_CHARGE_INHIBIT_MASK_ALWAYS (OXP_CHARGE_INHIBIT_MASK_AWAKE | \ + OXP_CHARGE_INHIBIT_MASK_OFF) static const struct dmi_system_id dmi_table[] = { { @@ -220,7 +224,7 @@ static const struct dmi_system_id dmi_table[] = { DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER APEX"), }, - .driver_data = (void *)oxp_fly, + .driver_data = (void *)oxp_apex, }, { .matches = { @@ -404,6 +408,7 @@ static umode_t tt_toggle_is_visible(struct kobject *kobj, case oxp_x1: case oxp_g1_i: case oxp_g1_a: + case oxp_apex: return attr->mode; default: break; @@ -433,6 +438,7 @@ static ssize_t tt_toggle_store(struct device *dev, case oxp_fly: case oxp_mini_amd_pro: case oxp_g1_a: + case oxp_apex: reg = OXP_TURBO_SWITCH_REG; mask = OXP_TURBO_TAKE_VAL; break; @@ -479,6 +485,7 @@ static ssize_t tt_toggle_show(struct device *dev, case oxp_fly: case oxp_mini_amd_pro: case oxp_g1_a: + case oxp_apex: reg = OXP_TURBO_SWITCH_REG; mask = OXP_TURBO_TAKE_VAL; break; @@ -576,6 +583,7 @@ static bool oxp_psy_ext_supported(void) case oxp_g1_i: case oxp_g1_a: case oxp_fly: + case oxp_apex: return true; default: break; @@ -589,12 +597,24 @@ static int oxp_psy_ext_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { + u8 limit_reg, inhibit_reg; long raw_val; int ret; + switch (board) { + case oxp_apex: + limit_reg = OXP_APEX_CHARGE_LIMIT_REG; + inhibit_reg = OXP_APEX_CHARGE_INHIBIT_REG; + break; + default: + limit_reg = OXP_X1_CHARGE_LIMIT_REG; + inhibit_reg = OXP_X1_CHARGE_INHIBIT_REG; + break; + } + switch (psp) { case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: - ret = read_from_ec(OXP_X1_CHARGE_LIMIT_REG, 1, &raw_val); + ret = read_from_ec(limit_reg, 1, &raw_val); if (ret) return ret; if (raw_val < 0 || raw_val > 100) @@ -602,14 +622,14 @@ static int oxp_psy_ext_get_prop(struct power_supply *psy, val->intval = raw_val; return 0; case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: - ret = read_from_ec(OXP_X1_CHARGE_INHIBIT_REG, 1, &raw_val); + ret = read_from_ec(inhibit_reg, 1, &raw_val); if (ret) return ret; - if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS) == - OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS) + if ((raw_val & OXP_CHARGE_INHIBIT_MASK_ALWAYS) == + OXP_CHARGE_INHIBIT_MASK_ALWAYS) val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; - else if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_AWAKE) == - OXP_X1_CHARGE_INHIBIT_MASK_AWAKE) + else if ((raw_val & OXP_CHARGE_INHIBIT_MASK_AWAKE) == + OXP_CHARGE_INHIBIT_MASK_AWAKE) val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE; else val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; @@ -625,29 +645,41 @@ static int oxp_psy_ext_set_prop(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val) { + u8 limit_reg, inhibit_reg; long raw_val; + switch (board) { + case oxp_apex: + limit_reg = OXP_APEX_CHARGE_LIMIT_REG; + inhibit_reg = OXP_APEX_CHARGE_INHIBIT_REG; + break; + default: + limit_reg = OXP_X1_CHARGE_LIMIT_REG; + inhibit_reg = OXP_X1_CHARGE_INHIBIT_REG; + break; + } + switch (psp) { case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: if (val->intval < 0 || val->intval > 100) return -EINVAL; - return write_to_ec(OXP_X1_CHARGE_LIMIT_REG, val->intval); + return write_to_ec(limit_reg, val->intval); case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: switch (val->intval) { case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO: raw_val = 0; break; case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE: - raw_val = OXP_X1_CHARGE_INHIBIT_MASK_AWAKE; + raw_val = OXP_CHARGE_INHIBIT_MASK_AWAKE; break; case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE: - raw_val = OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS; + raw_val = OXP_CHARGE_INHIBIT_MASK_ALWAYS; break; default: return -EINVAL; } - return write_to_ec(OXP_X1_CHARGE_INHIBIT_REG, raw_val); + return write_to_ec(inhibit_reg, raw_val); default: return -EINVAL; } @@ -715,6 +747,7 @@ static int oxp_pwm_enable(void) case oxp_x1: case oxp_g1_i: case oxp_g1_a: + case oxp_apex: return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL); default: return -EINVAL; @@ -743,6 +776,7 @@ static int oxp_pwm_disable(void) case oxp_x1: case oxp_g1_i: case oxp_g1_a: + case oxp_apex: return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO); default: return -EINVAL; @@ -771,6 +805,7 @@ static int oxp_pwm_read(long *val) case oxp_x1: case oxp_g1_i: case oxp_g1_a: + case oxp_apex: return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val); default: return -EOPNOTSUPP; @@ -815,6 +850,7 @@ static int oxp_pwm_fan_speed(long *val) case oxp_mini_amd_a07: case oxp_mini_amd_pro: case oxp_g1_a: + case oxp_apex: return read_from_ec(OXP_SENSOR_FAN_REG, 2, val); default: return -EOPNOTSUPP; @@ -855,6 +891,7 @@ static int oxp_pwm_input_write(long val) case oxp_fly: case oxp_mini_amd_pro: case oxp_g1_a: + case oxp_apex: return write_to_ec(OXP_SENSOR_PWM_REG, val); default: return -EOPNOTSUPP; @@ -902,6 +939,7 @@ static int oxp_pwm_input_read(long *val) case oxp_fly: case oxp_mini_amd_pro: case oxp_g1_a: + case oxp_apex: default: ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); if (ret) diff --git a/drivers/platform/x86/siemens/simatic-ipc.c b/drivers/platform/x86/siemens/simatic-ipc.c index 7039874d8f11..4a4509fc9263 100644 --- a/drivers/platform/x86/siemens/simatic-ipc.c +++ b/drivers/platform/x86/siemens/simatic-ipc.c @@ -92,6 +92,7 @@ static int register_platform_devices(u32 station_id) u8 wdtmode = SIMATIC_IPC_DEVICE_NONE; u8 battmode = SIMATIC_IPC_DEVICE_NONE; char *pdevname; + int ret; int i; for (i = 0; i < ARRAY_SIZE(device_modes); i++) { @@ -139,8 +140,10 @@ static int register_platform_devices(u32 station_id) pdevname, PLATFORM_DEVID_NONE, &platform_data, sizeof(struct simatic_ipc_platform)); - if (IS_ERR(ipc_led_platform_device)) - return PTR_ERR(ipc_led_platform_device); + if (IS_ERR(ipc_led_platform_device)) { + ret = PTR_ERR(ipc_led_platform_device); + goto err_unregister_batt; + } pr_debug("device=%s created\n", ipc_led_platform_device->name); @@ -153,8 +156,10 @@ static int register_platform_devices(u32 station_id) KBUILD_MODNAME "_wdt", PLATFORM_DEVID_NONE, &platform_data, sizeof(struct simatic_ipc_platform)); - if (IS_ERR(ipc_wdt_platform_device)) - return PTR_ERR(ipc_wdt_platform_device); + if (IS_ERR(ipc_wdt_platform_device)) { + ret = PTR_ERR(ipc_wdt_platform_device); + goto err_unregister_led; + } pr_debug("device=%s created\n", ipc_wdt_platform_device->name); @@ -169,6 +174,14 @@ static int register_platform_devices(u32 station_id) } return 0; + +err_unregister_led: + if (ledmode != SIMATIC_IPC_DEVICE_NONE) + platform_device_unregister(ipc_led_platform_device); +err_unregister_batt: + if (battmode != SIMATIC_IPC_DEVICE_NONE) + platform_device_unregister(ipc_batt_platform_device); + return ret; } static void request_additional_modules(u32 station_id) diff --git a/drivers/platform/x86/tuxedo/nb04/wmi_ab.c b/drivers/platform/x86/tuxedo/nb04/wmi_ab.c index 32d7756022c2..38a719381fdc 100644 --- a/drivers/platform/x86/tuxedo/nb04/wmi_ab.c +++ b/drivers/platform/x86/tuxedo/nb04/wmi_ab.c @@ -232,8 +232,8 @@ static const struct tux_kbl_map_entry_t sirius_16_ansii_kbl_map[] = { { 0x2e, { 246000, 67500, 5250 } }, { 0x2a, { 269500, 67500, 5250 } }, { 0x53, { 294500, 67500, 5250 } }, - { 0x55, { 311200, 67500, 5250 } }, - { 0x54, { 327900, 67500, 5250 } }, + { 0x54, { 311200, 67500, 5250 } }, + { 0x55, { 327900, 67500, 5250 } }, { 0x56, { 344600, 67500, 5250 } }, { 0x2b, { 31000, 85500, 5500 } }, { 0x14, { 51500, 85500, 5500 } }, @@ -337,8 +337,8 @@ static const struct tux_kbl_map_entry_t sirius_16_iso_kbl_map[] = { { 0x2e, { 246000, 67500, 5250 } }, { 0x2a, { 269500, 67500, 5250 } }, { 0x53, { 294500, 67500, 5250 } }, - { 0x55, { 311200, 67500, 5250 } }, - { 0x54, { 327900, 67500, 5250 } }, + { 0x54, { 311200, 67500, 5250 } }, + { 0x55, { 327900, 67500, 5250 } }, { 0x56, { 344600, 67500, 5250 } }, { 0x2b, { 31000, 85500, 5500 } }, { 0x14, { 51500, 85500, 5500 } }, diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 969a75f4c016..3b0a5bdd352b 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -1387,6 +1387,13 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init) } } + /* Keep the charge properties current between percentage changes. */ + if (di->bat_cap.prev_percent == percent && + di->bat_cap.prev_mah != di->bat_cap.mah) { + di->bat_cap.prev_mah = di->bat_cap.mah; + changed = true; + } + if (changed) { if (di->bm->capacity_scaling) { di->bat_cap.cap_scale.scaled_cap = @@ -2205,42 +2212,36 @@ static int ab8500_fg_get_ext_psy_data(struct power_supply *ext, void *data) switch (prop) { case POWER_SUPPLY_PROP_STATUS: - switch (ext->desc->type) { - case POWER_SUPPLY_TYPE_BATTERY: - switch (ret.intval) { - case POWER_SUPPLY_STATUS_UNKNOWN: - case POWER_SUPPLY_STATUS_DISCHARGING: - case POWER_SUPPLY_STATUS_NOT_CHARGING: - if (!di->flags.charging) - break; - di->flags.charging = false; - di->flags.fully_charged = false; - if (di->bm->capacity_scaling) - ab8500_fg_update_cap_scalers(di); - queue_work(di->fg_wq, &di->fg_work); + switch (ret.intval) { + case POWER_SUPPLY_STATUS_UNKNOWN: + case POWER_SUPPLY_STATUS_DISCHARGING: + case POWER_SUPPLY_STATUS_NOT_CHARGING: + if (!di->flags.charging) break; - case POWER_SUPPLY_STATUS_FULL: - if (di->flags.fully_charged) - break; - di->flags.fully_charged = true; - di->flags.force_full = true; - /* Save current capacity as maximum */ - di->bat_cap.max_mah = di->bat_cap.mah; - queue_work(di->fg_wq, &di->fg_work); - break; - case POWER_SUPPLY_STATUS_CHARGING: - if (di->flags.charging && - !di->flags.fully_charged) - break; - di->flags.charging = true; - di->flags.fully_charged = false; - if (di->bm->capacity_scaling) - ab8500_fg_update_cap_scalers(di); - queue_work(di->fg_wq, &di->fg_work); + di->flags.charging = false; + di->flags.fully_charged = false; + if (di->bm->capacity_scaling) + ab8500_fg_update_cap_scalers(di); + queue_work(di->fg_wq, &di->fg_work); + break; + case POWER_SUPPLY_STATUS_FULL: + if (di->flags.fully_charged) break; - } + di->flags.fully_charged = true; + di->flags.force_full = true; + /* Save current capacity as maximum */ + di->bat_cap.max_mah = di->bat_cap.mah; + queue_work(di->fg_wq, &di->fg_work); break; - default: + case POWER_SUPPLY_STATUS_CHARGING: + if (di->flags.charging && + !di->flags.fully_charged) + break; + di->flags.charging = true; + di->flags.fully_charged = false; + if (di->bm->capacity_scaling) + ab8500_fg_update_cap_scalers(di); + queue_work(di->fg_wq, &di->fg_work); break; } break; diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 01c9ec1116fa..cd30993b8a89 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -43,6 +43,7 @@ */ #include +#include #include #include #include @@ -2234,7 +2235,6 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) }; int ret; - INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll); ret = devm_mutex_init(di->dev, &di->lock); if (ret) return ret; @@ -2255,6 +2255,12 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) psy_desc->get_property = bq27xxx_battery_get_property; psy_desc->external_power_changed = bq27xxx_external_power_changed; + /* Cancel the poll work after the power_supply is unregistered. */ + ret = devm_delayed_work_autocancel(di->dev, &di->work, + bq27xxx_battery_poll); + if (ret) + return ret; + di->bat = devm_power_supply_register(di->dev, psy_desc, &psy_cfg); if (IS_ERR(di->bat)) return dev_err_probe(di->dev, PTR_ERR(di->bat), @@ -2281,8 +2287,6 @@ void bq27xxx_battery_teardown(struct bq27xxx_device_info *di) mutex_lock(&di->lock); di->removed = true; mutex_unlock(&di->lock); - - cancel_delayed_work_sync(&di->work); } EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown); @@ -2291,7 +2295,7 @@ static int bq27xxx_battery_suspend(struct device *dev) { struct bq27xxx_device_info *di = dev_get_drvdata(dev); - cancel_delayed_work(&di->work); + cancel_delayed_work_sync(&di->work); return 0; } diff --git a/drivers/power/supply/cros_charge-control.c b/drivers/power/supply/cros_charge-control.c index 53e6a77e03fc..6a6022f377b7 100644 --- a/drivers/power/supply/cros_charge-control.c +++ b/drivers/power/supply/cros_charge-control.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #define EC_CHARGE_CONTROL_BEHAVIOURS (BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | \ @@ -294,6 +295,7 @@ static int cros_chctl_probe(struct platform_device *pdev) priv->dev = dev; priv->cros_ec = cros_ec; + dev_set_drvdata(dev, priv); if (priv->cmd_version == 1) priv->psy_ext = &cros_chctl_psy_ext_v1; @@ -319,13 +321,38 @@ static int cros_chctl_probe(struct platform_device *pdev) return devm_battery_hook_register(dev, &priv->battery_hook); } +static int cros_chctl_resume(struct device *dev) +{ + struct cros_chctl_priv *priv = dev_get_drvdata(dev); + int ret; + + /* + * The EC resets its charge control state when the AP powers off, so the + * configuration is lost across hibernation, while the values exposed to + * userspace still describe it. The cached state is the only remaining + * record of that configuration: reprogram the EC from it rather than + * re-reading the EC, which would adopt the reset defaults instead. + */ + guard(mutex)(&priv->lock); + ret = cros_chctl_configure_ec(priv); + if (ret) + dev_err(dev, "failed to restore charge control state: %d\n", ret); + + return ret; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(cros_chctl_pm_ops, NULL, cros_chctl_resume); + static const struct platform_device_id cros_chctl_id[] = { { "cros-charge-control", 0 }, {} }; static struct platform_driver cros_chctl_driver = { - .driver.name = "cros-charge-control", + .driver = { + .name = "cros-charge-control", + .pm = pm_sleep_ptr(&cros_chctl_pm_ops), + }, .probe = cros_chctl_probe, .id_table = cros_chctl_id, }; diff --git a/drivers/power/supply/generic-adc-battery.c b/drivers/power/supply/generic-adc-battery.c index c69c9b9fa0eb..df5f91bc1d0f 100644 --- a/drivers/power/supply/generic-adc-battery.c +++ b/drivers/power/supply/generic-adc-battery.c @@ -135,7 +135,7 @@ static void gab_work(struct work_struct *work) adc_bat = container_of(delayed_work, struct gab, bat_work); status = adc_bat->status; - if (!power_supply_am_i_supplied(adc_bat->psy)) + if (power_supply_am_i_supplied(adc_bat->psy) <= 0) adc_bat->status = POWER_SUPPLY_STATUS_DISCHARGING; else if (gab_charge_finished(adc_bat)) adc_bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING; diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 615dc27089a3..7edca0694eb7 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -190,7 +190,35 @@ static void power_supply_deferred_register_work(struct work_struct *work) device_unlock(psy->dev.parent); } -#ifdef CONFIG_OF +static int power_supply_check_supplies_by_name(struct power_supply *psy) +{ + struct device *parent = psy->dev.parent; + int nval, ret; + + if (!parent) + return 0; + + nval = device_property_string_array_count(parent, "supplied-from"); + if (nval <= 0) + return 0; + + psy->supplied_from = devm_kmalloc_array(&psy->dev, nval, + sizeof(*psy->supplied_from), + GFP_KERNEL); + if (!psy->supplied_from) + return -ENOMEM; + + ret = device_property_read_string_array(parent, "supplied-from", + (const char **)psy->supplied_from, + nval); + if (ret < 0) + return ret; + + psy->num_supplies = nval; + + return 0; +} + static int __power_supply_populate_supplied_from(struct power_supply *epsy, void *data) { @@ -262,22 +290,21 @@ static int power_supply_find_supply_from_fwnode(struct fwnode_handle *supply_nod static int power_supply_check_supplies(struct power_supply *psy) { struct fwnode_handle *np; - int cnt = 0; + int cnt, ret; /* If there is already a list honor it */ if (psy->supplied_from && psy->num_supplies > 0) return 0; - /* No device node found, nothing to do */ - if (!psy->dev.fwnode) - return 0; - - do { - int ret; + for (cnt = 0; psy->dev.fwnode; cnt++) { + np = fwnode_find_reference(psy->dev.fwnode, "power-supplies", cnt); + if (IS_ERR(np)) { + ret = PTR_ERR(np); + if (ret != -ENOENT) + return ret; - np = fwnode_find_reference(psy->dev.fwnode, "power-supplies", cnt++); - if (IS_ERR(np)) break; + } ret = power_supply_find_supply_from_fwnode(np); fwnode_handle_put(np); @@ -286,48 +313,21 @@ static int power_supply_check_supplies(struct power_supply *psy) dev_dbg(&psy->dev, "Failed to find supply!\n"); return ret; } - } while (!IS_ERR(np)); + } - /* Missing valid "power-supplies" entries */ - if (cnt == 1) - return 0; + /* Fall back to the name-based property if no references were specified. */ + if (!cnt) + return power_supply_check_supplies_by_name(psy); /* All supplies found, allocate char * array for filling */ psy->supplied_from = devm_kcalloc(&psy->dev, - cnt - 1, sizeof(*psy->supplied_from), + cnt, sizeof(*psy->supplied_from), GFP_KERNEL); if (!psy->supplied_from) return -ENOMEM; return power_supply_populate_supplied_from(psy); } -#else -static int power_supply_check_supplies(struct power_supply *psy) -{ - int nval, ret; - - if (!psy->dev.parent) - return 0; - - nval = device_property_string_array_count(psy->dev.parent, "supplied-from"); - if (nval <= 0) - return 0; - - psy->supplied_from = devm_kmalloc_array(&psy->dev, nval, - sizeof(char *), GFP_KERNEL); - if (!psy->supplied_from) - return -ENOMEM; - - ret = device_property_read_string_array(psy->dev.parent, - "supplied-from", (const char **)psy->supplied_from, nval); - if (ret < 0) - return ret; - - psy->num_supplies = nval; - - return 0; -} -#endif struct psy_am_i_supplied_data { struct power_supply *psy; diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c index 7454ec0e9963..03ffaad3b53d 100644 --- a/drivers/power/supply/qcom_battmgr.c +++ b/drivers/power/supply/qcom_battmgr.c @@ -1258,6 +1258,23 @@ static unsigned int qcom_battmgr_sc8280xp_convert_temp(unsigned int temperature) return DIV_ROUND_CLOSEST(temperature, 10); } +/* + * The charger supplies' online state comes from the battery status response, + * and the firmware sends no notification of its own when it changes, so + * announce the change here. A supply that is not registered yet announces its + * state when it is. + */ +static void qcom_battmgr_sc8280xp_set_online(struct power_supply *psy, + bool *online, bool value) +{ + if (*online == value) + return; + + *online = value; + if (psy) + power_supply_changed(psy); +} + static void qcom_battmgr_sc8280xp_callback(struct qcom_battmgr *battmgr, const struct qcom_battmgr_message *resp, size_t len) @@ -1327,9 +1344,12 @@ static void qcom_battmgr_sc8280xp_callback(struct qcom_battmgr *battmgr, battmgr->status.temperature = qcom_battmgr_sc8280xp_convert_temp(le32_to_cpu(resp->status.temperature)); source = le32_to_cpu(resp->status.charging_source); - battmgr->ac.online = source == BATTMGR_CHARGING_SOURCE_AC; - battmgr->usb.online = source == BATTMGR_CHARGING_SOURCE_USB; - battmgr->wireless.online = source == BATTMGR_CHARGING_SOURCE_WIRELESS; + qcom_battmgr_sc8280xp_set_online(battmgr->ac_psy, &battmgr->ac.online, + source == BATTMGR_CHARGING_SOURCE_AC); + qcom_battmgr_sc8280xp_set_online(battmgr->usb_psy, &battmgr->usb.online, + source == BATTMGR_CHARGING_SOURCE_USB); + qcom_battmgr_sc8280xp_set_online(battmgr->wls_psy, &battmgr->wireless.online, + source == BATTMGR_CHARGING_SOURCE_WIRELESS); if (battmgr->info.last_full_capacity != 0) { /* * 100 * battmgr->status.capacity can overflow a 32bit diff --git a/drivers/power/supply/qcom_smbx.c b/drivers/power/supply/qcom_smbx.c index b1cb925581ec..ad2cf516e2de 100644 --- a/drivers/power/supply/qcom_smbx.c +++ b/drivers/power/supply/qcom_smbx.c @@ -349,6 +349,9 @@ /* pmi8998 registers represent current in increments of 1/40th of an amp */ #define CURRENT_SCALE_FACTOR 25000 +#define SMB2_FLOAT_VOLTAGE_MIN_UV 3487500 +#define SMB2_FLOAT_VOLTAGE_MAX_UV 4920000 +#define SMB2_FLOAT_VOLTAGE_STEP_UV 7500 /* clang-format on */ enum charger_status { @@ -375,6 +378,7 @@ struct smb_init_register { * @base: Base address for smb registers * @regmap: Register map * @batt_info: Battery data from DT + * @initial_charge_enable: Charging enable state before hardware setup * @status_change_work: Worker to handle plug/unplug events * @cable_irq: USB plugin IRQ * @wakeup_enabled: If the cable IRQ will cause a wakeup @@ -388,6 +392,7 @@ struct smb_chip { unsigned int base; struct regmap *regmap; struct power_supply_battery_info *batt_info; + u8 initial_charge_enable; struct delayed_work status_change_work; int cable_irq; @@ -629,26 +634,20 @@ static int smb_get_prop_health(struct smb_chip *chip, int *val) return rc; } - switch (stat) { - case CHARGER_ERROR_STATUS_BAT_OV_BIT: + if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE; - return 0; - case BAT_TEMP_STATUS_TOO_COLD_BIT: + else if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT) *val = POWER_SUPPLY_HEALTH_COLD; - return 0; - case BAT_TEMP_STATUS_TOO_HOT_BIT: + else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT) *val = POWER_SUPPLY_HEALTH_OVERHEAT; - return 0; - case BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT: + else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT) *val = POWER_SUPPLY_HEALTH_COOL; - return 0; - case BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT: + else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT) *val = POWER_SUPPLY_HEALTH_WARM; - return 0; - default: + else *val = POWER_SUPPLY_HEALTH_GOOD; - return 0; - } + + return 0; } static int smb_get_property(struct power_supply *psy, @@ -716,16 +715,22 @@ static irqreturn_t smb_handle_batt_overvoltage(int irq, void *data) { struct smb_chip *chip = data; unsigned int status; + int rc; - regmap_read(chip->regmap, chip->base + BATTERY_CHARGER_STATUS_2, - &status); + rc = regmap_read(chip->regmap, + chip->base + BATTERY_CHARGER_STATUS_2, &status); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read charger status: %d\n", rc); + return IRQ_HANDLED; + } if (status & CHARGER_ERROR_STATUS_BAT_OV_BIT) { /* The hardware stops charging automatically */ dev_err(chip->dev, "battery overvoltage detected\n"); - power_supply_changed(chip->chg_psy); } + power_supply_changed(chip->chg_psy); + return IRQ_HANDLED; } @@ -757,7 +762,7 @@ static irqreturn_t smb_handle_wdog_bark(int irq, void *data) power_supply_changed(chip->chg_psy); - rc = regmap_write(chip->regmap, BARK_BITE_WDOG_PET, + rc = regmap_write(chip->regmap, chip->base + BARK_BITE_WDOG_PET, BARK_BITE_WDOG_PET_BIT); if (rc < 0) dev_err(chip->dev, "Couldn't pet the dog rc=%d\n", rc); @@ -807,11 +812,7 @@ static const struct smb_init_register smb_init_seq[] = { .mask = SOC_LT_CHG_RECHARGE_THRESH_SEL_BIT | VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT, .val = VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT }, - /* Enable charging */ { .addr = USBIN_OPTIONS_1_CFG, .mask = HVDCP_EN_BIT, .val = 0 }, - { .addr = CHARGING_ENABLE_CMD, - .mask = CHARGING_ENABLE_CMD_BIT, - .val = CHARGING_ENABLE_CMD_BIT }, /* * Match downstream defaults * CHG_EN_SRC_BIT - charger enable is controlled by software @@ -832,6 +833,13 @@ static const struct smb_init_register smb_init_seq[] = { AUTO_RECHG_BIT | EN_ANALOG_DROP_IN_VBATT_BIT | CHARGER_INHIBIT_BIT, .val = CHARGER_INHIBIT_BIT }, + /* + * Set the enable command only once CHGR_CFG2 has selected software + * control, or a charger its watchdog has disabled stays disabled. + */ + { .addr = CHARGING_ENABLE_CMD, + .mask = CHARGING_ENABLE_CMD_BIT, + .val = CHARGING_ENABLE_CMD_BIT }, /* STAT pin software override, match downstream. Parallel charging? */ { .addr = STAT_CFG, .mask = STAT_SW_OVERRIDE_CFG_BIT, @@ -902,6 +910,19 @@ static int smb_init_hw(struct smb_chip *chip) return 0; } +static void smb_restore_charge_enable(void *data) +{ + struct smb_chip *chip = data; + int rc; + + rc = regmap_update_bits(chip->regmap, + chip->base + CHARGING_ENABLE_CMD, + CHARGING_ENABLE_CMD_BIT, + chip->initial_charge_enable); + if (rc < 0) + dev_err(chip->dev, "Couldn't restore charging state: %d\n", rc); +} + static int smb_init_irq(struct smb_chip *chip, int *irq, const char *name, irqreturn_t (*handler)(int irq, void *data)) { @@ -929,6 +950,9 @@ static int smb_probe(struct platform_device *pdev) struct power_supply_config supply_config = {}; struct power_supply_desc *desc; struct smb_chip *chip; + unsigned int charge_enable; + unsigned int float_voltage_sel; + int float_voltage_uv; int rc, irq; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); @@ -959,6 +983,18 @@ static int smb_probe(struct platform_device *pdev) "Couldn't get usbin_i IIO channel\n"); } + rc = regmap_read(chip->regmap, chip->base + CHARGING_ENABLE_CMD, + &charge_enable); + if (rc < 0) + return dev_err_probe(chip->dev, rc, + "Couldn't read charging state\n"); + + chip->initial_charge_enable = charge_enable & CHARGING_ENABLE_CMD_BIT; + rc = devm_add_action_or_reset(chip->dev, smb_restore_charge_enable, chip); + if (rc) + return dev_err_probe(chip->dev, rc, + "Couldn't register charging state rollback\n"); + rc = smb_init_hw(chip); if (rc < 0) return rc; @@ -993,12 +1029,35 @@ static int smb_probe(struct platform_device *pdev) return dev_err_probe(chip->dev, rc, "Failed to init status change work\n"); - rc = (chip->batt_info->voltage_max_design_uv - 3487500) / 7500 + 1; + if (power_supply_battery_info_has_prop(chip->batt_info, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX)) { + float_voltage_uv = + chip->batt_info->constant_charge_voltage_max_uv; + } else if (power_supply_battery_info_has_prop(chip->batt_info, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN)) { + float_voltage_uv = chip->batt_info->voltage_max_design_uv; + } else { + dev_warn(chip->dev, "No battery float voltage; preserving hardware setting\n"); + goto skip_float_voltage; + } + + if (float_voltage_uv < SMB2_FLOAT_VOLTAGE_MIN_UV || + float_voltage_uv > SMB2_FLOAT_VOLTAGE_MAX_UV) + return dev_err_probe(chip->dev, -EINVAL, + "float voltage %d uV outside %d-%d uV\n", + float_voltage_uv, + SMB2_FLOAT_VOLTAGE_MIN_UV, + SMB2_FLOAT_VOLTAGE_MAX_UV); + + float_voltage_sel = + (float_voltage_uv - SMB2_FLOAT_VOLTAGE_MIN_UV) / + SMB2_FLOAT_VOLTAGE_STEP_UV; rc = regmap_update_bits(chip->regmap, chip->base + FLOAT_VOLTAGE_CFG, - FLOAT_VOLTAGE_SETTING_MASK, rc); + FLOAT_VOLTAGE_SETTING_MASK, float_voltage_sel); if (rc < 0) return dev_err_probe(chip->dev, rc, "Couldn't set vbat max\n"); +skip_float_voltage: rc = smb_init_irq(chip, &irq, "bat-ov", smb_handle_batt_overvoltage); if (rc < 0) return rc; @@ -1022,6 +1081,8 @@ static int smb_probe(struct platform_device *pdev) if (rc < 0) return dev_err_probe(chip->dev, rc, "Couldn't set wake irq\n"); + devm_remove_action(chip->dev, smb_restore_charge_enable, chip); + platform_set_drvdata(pdev, chip); /* Initialise charger state */ diff --git a/drivers/pps/generators/pps_gen.c b/drivers/pps/generators/pps_gen.c index 69a470fa164d..eda7fd933bec 100644 --- a/drivers/pps/generators/pps_gen.c +++ b/drivers/pps/generators/pps_gen.c @@ -69,17 +69,28 @@ static long pps_gen_cdev_ioctl(struct file *file, if (ret) return -EFAULT; - ret = pps_gen->info->enable(pps_gen, status); - if (ret) - return ret; - pps_gen->enabled = status; + scoped_guard(mutex, &pps_gen->info_lock) { + if (!pps_gen->info) + return -ENODEV; + + ret = pps_gen->info->enable(pps_gen, status); + if (ret) + return ret; + pps_gen->enabled = status; + } break; case PPS_GEN_USESYSTEMCLOCK: dev_dbg(&pps_gen->dev, "PPS_GEN_USESYSTEMCLOCK\n"); - ret = put_user(pps_gen->info->use_system_clock, uiuarg); + scoped_guard(mutex, &pps_gen->info_lock) { + if (!pps_gen->info) + return -ENODEV; + status = pps_gen->info->use_system_clock; + } + + ret = put_user(status, uiuarg); if (ret) return -EFAULT; @@ -212,6 +223,24 @@ static void pps_gen_unregister_cdev(struct pps_gen_device *pps_gen) { pr_debug("unregistering pps-gen%d\n", pps_gen->id); cdev_device_del(&pps_gen->cdev, &pps_gen->dev); + + /* + * An open file keeps pps_gen around, but the driver may free info as + * soon as we return. The sysfs files are gone now, so wait for the + * ioctls using info and make later ones fail. + * + * The driver may have stopped the generator before calling us, but + * userspace could have enabled it again since. Nothing can enable it + * after this point, so stop it here for good. + */ + scoped_guard(mutex, &pps_gen->info_lock) { + if (pps_gen->enabled) { + pps_gen->info->enable(pps_gen, false); + pps_gen->enabled = false; + } + pps_gen->info = NULL; + } + put_device(&pps_gen->dev); } @@ -243,6 +272,7 @@ struct pps_gen_device *pps_gen_register_source(const struct pps_gen_source_info pps_gen->info = info; pps_gen->enabled = false; + mutex_init(&pps_gen->info_lock); init_waitqueue_head(&pps_gen->queue); spin_lock_init(&pps_gen->lock); diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 2533c95b0ba9..c02f69de44dc 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -358,6 +358,9 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) /* Disable clock on PWM disable */ pm_runtime_put_sync(pwmchip_parent(chip)); + + /* A disabled channel must not constrain the sibling's period */ + pc->period_cycles[pwm->hwpwm] = 0; } static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index eae756c82c26..bb0b7268b2b5 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2110,6 +2110,7 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) if (r == rdev) { dev_err(dev, "Supply for %s (%s) resolved to itself\n", rdev->desc->name, rdev->supply_name); + put_device(&rdev->dev); if (!have_full_constraints()) { ret = -EINVAL; goto out; @@ -5659,6 +5660,7 @@ static void regulator_resolve_coupling(struct regulator_dev *rdev) if (c_rdev->coupling_desc.coupler != coupler) { rdev_err(rdev, "coupler mismatch with %s\n", rdev_get_name(c_rdev)); + put_device(&c_rdev->dev); return; } @@ -5705,6 +5707,8 @@ static void regulator_remove_coupling(struct regulator_dev *rdev) c_desc->coupled_rdevs[i] = NULL; c_desc->n_resolved--; + + put_device(&c_rdev->dev); } if (coupler && coupler->detach_regulator) { diff --git a/drivers/regulator/rt6190-regulator.c b/drivers/regulator/rt6190-regulator.c index 3883440295ed..bf99e18f6d5b 100644 --- a/drivers/regulator/rt6190-regulator.c +++ b/drivers/regulator/rt6190-regulator.c @@ -109,19 +109,27 @@ static int rt6190_out_enable(struct regulator_dev *rdev) ret = regmap_raw_read(regmap, RT6190_REG_OUTV, out_cfg, sizeof(out_cfg)); if (ret) - return ret; + goto err_pm_put; ret = regulator_enable_regmap(rdev); if (ret) - return ret; + goto err_pm_put; ret = regmap_raw_write(regmap, RT6190_REG_OUTV, out_cfg, sizeof(out_cfg)); if (ret) - return ret; + goto err_pm_put; + + ret = regmap_update_bits(regmap, RT6190_REG_SET5, RT6190_ENGCP_MASK, + RT6190_ENGCP_MASK); + if (ret) + goto err_pm_put; + + return 0; - return regmap_update_bits(regmap, RT6190_REG_SET5, RT6190_ENGCP_MASK, - RT6190_ENGCP_MASK); +err_pm_put: + pm_runtime_put(data->dev); + return ret; } static int rt6190_out_disable(struct regulator_dev *rdev) diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c index 94177e416047..da3cddbe7d4c 100644 --- a/drivers/remoteproc/remoteproc_elf_loader.c +++ b/drivers/remoteproc/remoteproc_elf_loader.c @@ -46,8 +46,9 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw) struct elf32_hdr *ehdr; u32 elf_shdr_get_size; u64 phoff, shoff; + size_t shend; char class; - u16 phnum; + u16 phnum, shnum, shstrndx; if (!fw) { dev_err(dev, "failed to load %s\n", name); @@ -90,9 +91,27 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw) phoff = elf_hdr_get_e_phoff(class, fw->data); shoff = elf_hdr_get_e_shoff(class, fw->data); phnum = elf_hdr_get_e_phnum(class, fw->data); + shnum = elf_hdr_get_e_shnum(class, fw->data); + shstrndx = elf_hdr_get_e_shstrndx(class, fw->data); elf_shdr_get_size = elf_size_of_shdr(class); - if (fw->size < shoff + elf_shdr_get_size) { + /* keeps shoff in size_t range for the two bounds below */ + if (shoff > fw->size) { + dev_err(dev, "Section header table is out of bounds\n"); + return -EINVAL; + } + + if (shnum) { + shend = size_add(size_mul(elf_shdr_get_size, shnum), shoff); + if (shend > fw->size) { + dev_err(dev, "Section headers are out of bounds\n"); + return -EINVAL; + } + } + + /* find_table() reads the header at shstrndx even with no sections */ + shend = size_add(size_mul(elf_shdr_get_size, (size_t)shstrndx + 1), shoff); + if (shend > fw->size) { dev_err(dev, "Image is too small\n"); return -EINVAL; } diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index b537f40654b7..9dfa1f4ef7ff 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -753,7 +753,9 @@ static u32 rtc_handler(void *context) unsigned char rtc_intr; unsigned long flags; - + /* Quiesce this event before rtc->irqwork can arm the next one. */ + acpi_clear_event(ACPI_EVENT_RTC); + acpi_disable_event(ACPI_EVENT_RTC, 0); /* * Always update rtc irq when ACPI is used as RTC Alarm. * Or else, ACPI SCI is enabled during suspend/resume only, @@ -776,8 +778,6 @@ static u32 rtc_handler(void *context) } pm_wakeup_hard_event(dev); - acpi_clear_event(ACPI_EVENT_RTC); - acpi_disable_event(ACPI_EVENT_RTC, 0); return ACPI_INTERRUPT_HANDLED; } diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 7083d927820f..c23f04bdd95f 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -531,7 +531,7 @@ static int pcf8563_probe(struct i2c_client *client) err = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf8563_irq, IRQF_SHARED | IRQF_ONESHOT | irqflags, - pcf8563_driver.driver.name, client); + pcf8563_driver.driver.name, pcf8563); if (err) { dev_err(&client->dev, "unable to request IRQ %d\n", client->irq); diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index d35f93451ee9..3c9e736d45e7 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -601,7 +601,8 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) data_length, session->max_burst); data_offset = be32_to_cpu(rhdr->data_offset); - if (data_offset + data_length > task->sc->sdb.length) { + if (data_offset > task->sc->sdb.length || + data_length > task->sc->sdb.length - data_offset) { iscsi_conn_printk(KERN_ERR, conn, "invalid R2T with data len %u at offset %u " "and total length %d\n", data_length, diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 3dde703b7766..137a7a94d9cb 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -277,9 +277,6 @@ int __init register_intc_controller(struct intc_desc *desc) k += save_reg(d, k, hw->prio_regs[i].set_reg, smp); k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp); } - - sort(d->prio, hw->nr_prio_regs, sizeof(*d->prio), - intc_handle_int_cmp, NULL); } if (hw->sense_regs) { @@ -290,9 +287,6 @@ int __init register_intc_controller(struct intc_desc *desc) for (i = 0; i < hw->nr_sense_regs; i++) k += save_reg(d, k, hw->sense_regs[i].reg, 0); - - sort(d->sense, hw->nr_sense_regs, sizeof(*d->sense), - intc_handle_int_cmp, NULL); } if (hw->subgroups) @@ -360,6 +354,11 @@ int __init register_intc_controller(struct intc_desc *desc) } } + sort(d->prio, d->nr_prio, sizeof(*d->prio), + intc_handle_int_cmp, NULL); + sort(d->sense, d->nr_sense, sizeof(*d->sense), + intc_handle_int_cmp, NULL); + intc_subgroup_init(desc, d); /* enable bits matching force_enable after registering irqs */ diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c index 6dc0549f7900..3d3302c900ca 100644 --- a/drivers/sh/maple/maple.c +++ b/drivers/sh/maple/maple.c @@ -863,10 +863,10 @@ static int __init maple_bus_init(void) kmem_cache_destroy(maple_queue_cache); cleanup_bothirqs: - free_irq(HW_EVENT_VSYNC, 0); + free_irq(HW_EVENT_VSYNC, &maple_unsupported_device); cleanup_irq: - free_irq(HW_EVENT_MAPLE_DMA, 0); + free_irq(HW_EVENT_MAPLE_DMA, &maple_unsupported_device); cleanup_dma: free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES); diff --git a/drivers/slimbus/messaging.c b/drivers/slimbus/messaging.c index e2dbe4a66b70..ee127ef42046 100644 --- a/drivers/slimbus/messaging.c +++ b/drivers/slimbus/messaging.c @@ -139,7 +139,7 @@ int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn) if (need_tid) { ret = slim_alloc_txn_tid(ctrl, txn); if (ret) - return ret; + goto slim_xfer_err; if (!txn->msg->comp) txn->comp = &done; diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index 9e3fddd8f5a9..2962e66e2e41 100644 --- a/drivers/soc/fsl/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -88,6 +88,7 @@ static void unregister_dpio_irq_handlers(struct fsl_mc_device *dpio_dev) /* clear the affinity hint */ irq_set_affinity_hint(irq->virq, NULL); + devm_free_irq(&dpio_dev->dev, irq->virq, &dpio_dev->dev); } static int register_dpio_irq_handlers(struct fsl_mc_device *dpio_dev, int cpu) @@ -248,9 +249,9 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) return 0; -err_dpaa2_io_create: - unregister_dpio_irq_handlers(dpio_dev); err_register_dpio_irq: + dpaa2_io_down(priv->io); +err_dpaa2_io_create: fsl_mc_free_irqs(dpio_dev); err_allocate_irqs: dpio_disable(dpio_dev->mc_io, 0, dpio_dev->mc_handle); @@ -280,10 +281,10 @@ static void dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev) priv = dev_get_drvdata(dev); cpu = dpaa2_io_get_cpu(priv->io); - dpaa2_io_down(priv->io); - dpio_teardown_irqs(dpio_dev); + dpaa2_io_down(priv->io); + cpumask_set_cpu(cpu, cpus_unused_mask); err = dpio_open(dpio_dev->mc_io, 0, dpio_dev->obj_desc.id, diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 4a88e54d25b9..502e2ffe8689 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -865,12 +865,12 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) clk_put(tsa->tdm[i].l1rclk_clk); } if (tsa->tdm[i].l1tsync_clk) { - clk_disable_unprepare(tsa->tdm[i].l1rsync_clk); - clk_put(tsa->tdm[i].l1rsync_clk); + clk_disable_unprepare(tsa->tdm[i].l1tsync_clk); + clk_put(tsa->tdm[i].l1tsync_clk); } if (tsa->tdm[i].l1tclk_clk) { - clk_disable_unprepare(tsa->tdm[i].l1rclk_clk); - clk_put(tsa->tdm[i].l1rclk_clk); + clk_disable_unprepare(tsa->tdm[i].l1tclk_clk); + clk_put(tsa->tdm[i].l1tclk_clk); } } return ret; @@ -1039,12 +1039,12 @@ static void tsa_remove(struct platform_device *pdev) clk_put(tsa->tdm[i].l1rclk_clk); } if (tsa->tdm[i].l1tsync_clk) { - clk_disable_unprepare(tsa->tdm[i].l1rsync_clk); - clk_put(tsa->tdm[i].l1rsync_clk); + clk_disable_unprepare(tsa->tdm[i].l1tsync_clk); + clk_put(tsa->tdm[i].l1tsync_clk); } if (tsa->tdm[i].l1tclk_clk) { - clk_disable_unprepare(tsa->tdm[i].l1rclk_clk); - clk_put(tsa->tdm[i].l1rclk_clk); + clk_disable_unprepare(tsa->tdm[i].l1tclk_clk); + clk_put(tsa->tdm[i].l1tclk_clk); } } } diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 2fa6a45904e9..f85cac34c726 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -991,25 +991,28 @@ EXPORT_SYMBOL_GPL(geni_icc_disable); * @se: Pointer to the serial engine structure. * @fw: Pointer to the firmware image. * @protocol: Expected serial engine protocol type. + * @fw_size_out: Non-NULL output parameter; receives the rounded, validated + * firmware word count on success. * * Identifies the appropriate firmware image or configuration required for a * specific communication protocol instance running on a Qualcomm GENI * controller. Validates the firmware size against the hardware PROG_RAM_DEPTH * read from SE_HW_PARAM_2. * - * Return: pointer to a valid 'struct se_fw_hdr' if found, or NULL otherwise. + * Return: pointer to a valid 'const struct se_fw_hdr' if found, or NULL otherwise. */ -static struct se_fw_hdr *geni_find_protocol_fw(struct geni_se *se, const struct firmware *fw, - enum geni_se_protocol_type protocol) +static const struct se_fw_hdr *geni_find_protocol_fw(struct geni_se *se, const struct firmware *fw, + enum geni_se_protocol_type protocol, + u32 *fw_size_out) { struct device *dev = se->dev; const struct elf32_hdr *ehdr; const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; - struct se_fw_hdr *sefw; + const struct se_fw_hdr *sefw; u32 fw_end, cfg_idx_end, cfg_val_end; u32 prog_ram_depth; - u16 fw_size; + u32 fw_size; int i; if (!fw || fw->size < sizeof(struct elf32_hdr)) @@ -1048,24 +1051,23 @@ static struct se_fw_hdr *geni_find_protocol_fw(struct geni_se *se, const struct if (phdr->p_filesz < sizeof(struct se_fw_hdr)) continue; - sefw = (struct se_fw_hdr *)(fw->data + phdr->p_offset); + sefw = (const struct se_fw_hdr *)(fw->data + phdr->p_offset); fw_size = le16_to_cpu(sefw->fw_size_in_items); - fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32); - cfg_idx_end = le16_to_cpu(sefw->cfg_idx_offset) + - le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u8); - cfg_val_end = le16_to_cpu(sefw->cfg_val_offset) + - le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u32); if (le32_to_cpu(sefw->magic) != SE_MAGIC_NUM || le32_to_cpu(sefw->version) != 1) continue; - if (le32_to_cpu(sefw->serial_protocol) != protocol) + if (le16_to_cpu(sefw->serial_protocol) != protocol) continue; - if (fw_size % 2 != 0) { + if (fw_size % 2 != 0) fw_size++; - sefw->fw_size_in_items = cpu_to_le16(fw_size); - } + + fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32); + cfg_idx_end = le16_to_cpu(sefw->cfg_idx_offset) + + le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u8); + cfg_val_end = le16_to_cpu(sefw->cfg_val_offset) + + le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u32); prog_ram_depth = FIELD_GET(PROG_RAM_DEPTH_MSK, readl_relaxed(se->base + SE_HW_PARAM_2)); @@ -1081,6 +1083,7 @@ static struct se_fw_hdr *geni_find_protocol_fw(struct geni_se *se, const struct continue; } + *fw_size_out = fw_size; return sefw; } @@ -1191,17 +1194,17 @@ static int geni_load_se_fw(struct geni_se *se, const struct firmware *fw, { const u32 *fw_data, *cfg_val_arr; const u8 *cfg_idx_arr; - u32 i, reg_value; + u32 i, reg_value, fw_size_in_items; int ret; - struct se_fw_hdr *hdr; + const struct se_fw_hdr *hdr; - hdr = geni_find_protocol_fw(se, fw, protocol); + hdr = geni_find_protocol_fw(se, fw, protocol, &fw_size_in_items); if (!hdr) return -EINVAL; - fw_data = (const u32 *)((u8 *)hdr + le16_to_cpu(hdr->fw_offset)); + fw_data = (const u32 *)((const u8 *)hdr + le16_to_cpu(hdr->fw_offset)); cfg_idx_arr = (const u8 *)hdr + le16_to_cpu(hdr->cfg_idx_offset); - cfg_val_arr = (const u32 *)((u8 *)hdr + le16_to_cpu(hdr->cfg_val_offset)); + cfg_val_arr = (const u32 *)((const u8 *)hdr + le16_to_cpu(hdr->cfg_val_offset)); ret = geni_icc_set_bw(se); if (ret) @@ -1272,7 +1275,7 @@ static int geni_load_se_fw(struct geni_se *se, const struct firmware *fw, /* Program RAM address space. */ memcpy_toio(se->base + SE_GENI_CFG_RAMN, fw_data, - le16_to_cpu(hdr->fw_size_in_items) * sizeof(u32)); + fw_size_in_items * sizeof(u32)); /* Put default values on GENI's output pads. */ writel_relaxed(0x1, se->base + GENI_FORCE_DEFAULT_REG); diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c index 0fcbc08633f6..748be7ff2aff 100644 --- a/drivers/soc/samsung/exynos-pmu.c +++ b/drivers/soc/samsung/exynos-pmu.c @@ -47,6 +47,8 @@ struct exynos_pmu_context { unsigned long *in_cpuhp; bool sys_insuspend; bool sys_inreboot; + int cpuhp_prepare_state; + int cpuhp_online_state; }; void __iomem *pmu_base_addr; @@ -589,16 +591,55 @@ static int setup_cpuhp_and_cpuidle(struct device *dev) gs101_cpuhp_pmu_online(cpu); /* register CPU hotplug callbacks */ - cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "soc/exynos-pmu:prepare", - gs101_cpuhp_pmu_online, NULL); + pmu_context->cpuhp_prepare_state = CPUHP_INVALID; + pmu_context->cpuhp_online_state = CPUHP_INVALID; - cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/exynos-pmu:online", - NULL, gs101_cpuhp_pmu_offline); + ret = cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "soc/exynos-pmu:prepare", + gs101_cpuhp_pmu_online, NULL); + if (ret < 0) + return ret; + + pmu_context->cpuhp_prepare_state = ret; + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/exynos-pmu:online", + NULL, gs101_cpuhp_pmu_offline); + if (ret < 0) + goto clean_cpuhp_state_prepare; + + pmu_context->cpuhp_online_state = ret; /* register CPU PM notifiers for cpuidle */ - cpu_pm_register_notifier(&gs101_cpu_pm_notifier); - register_reboot_notifier(&exynos_cpupm_reboot_nb); - return 0; + ret = cpu_pm_register_notifier(&gs101_cpu_pm_notifier); + if (ret) + goto clean_cpuhp_states; + + ret = register_reboot_notifier(&exynos_cpupm_reboot_nb); + if (!ret) + /* Success */ + return ret; + + cpu_pm_unregister_notifier(&gs101_cpu_pm_notifier); + +clean_cpuhp_states: + cpuhp_remove_state(pmu_context->cpuhp_online_state); + pmu_context->cpuhp_online_state = CPUHP_INVALID; + +clean_cpuhp_state_prepare: + cpuhp_remove_state(pmu_context->cpuhp_prepare_state); + pmu_context->cpuhp_prepare_state = CPUHP_INVALID; + + return ret; +} + +static void destroy_cpuhp_and_cpuidle(void) +{ + cpu_pm_unregister_notifier(&gs101_cpu_pm_notifier); + unregister_reboot_notifier(&exynos_cpupm_reboot_nb); + + if (pmu_context->cpuhp_prepare_state != CPUHP_INVALID) + cpuhp_remove_state(pmu_context->cpuhp_prepare_state); + if (pmu_context->cpuhp_online_state != CPUHP_INVALID) + cpuhp_remove_state(pmu_context->cpuhp_online_state); } static int exynos_pmu_probe(struct platform_device *pdev) @@ -669,8 +710,12 @@ static int exynos_pmu_probe(struct platform_device *pdev) ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, exynos_pmu_devs, ARRAY_SIZE(exynos_pmu_devs), NULL, 0, NULL); - if (ret) + if (ret) { + if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_cpuhp) + destroy_cpuhp_and_cpuidle(); + return ret; + } if (devm_of_platform_populate(dev)) dev_err(dev, "Error populating children, reboot and poweroff might not work properly\n"); diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 71a6e5c475b0..d3953de255be 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -322,6 +322,10 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi, list_for_each_entry(xfer, &message->transfers, transfer_list) { + /* Skip zero-length transfers to avoid len underflow below */ + if (!xfer->len) + continue; + if (xfer->speed_hz) amd_set_spi_freq(amd_spi, xfer->speed_hz); else @@ -335,6 +339,10 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi, xfer->len--; } tx_len += xfer->len; + if (tx_len + rx_len > AMD_SPI_FIFO_SIZE) { + message->status = -EMSGSIZE; + goto fin_msg; + } /* Write data into the FIFO. */ for (i = 0; i < xfer->len; i++) @@ -344,8 +352,13 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi, } /* Store no. of bytes to be received from FIFO */ - if (xfer->rx_buf) + if (xfer->rx_buf) { rx_len += xfer->len; + if (tx_len + rx_len > AMD_SPI_FIFO_SIZE) { + message->status = -EMSGSIZE; + goto fin_msg; + } + } } if (!buf) { diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index ae5545be0a45..de333a4a3200 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -1197,8 +1197,9 @@ static int bcm_qspi_exec_mem_op(struct spi_mem *mem, u32 addr = 0, len; u_char *buf; + /* cmd[] holds 1 opcode + 4 address + 1 dummy byte at most */ if (!op->data.nbytes || !op->addr.nbytes || op->addr.nbytes > 4 || - op->data.dir != SPI_MEM_DATA_IN) + op->dummy.nbytes > 1 || op->data.dir != SPI_MEM_DATA_IN) return -EOPNOTSUPP; buf = op->data.buf.in; diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 192cc5ef65fb..61f70da3959e 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -1297,7 +1297,9 @@ static int bcm2835_spi_setup(struct spi_device *spi) } for (i = 0; i < ARRAY_SIZE(pinctrl_compats); i++) { - if (of_find_compatible_node(NULL, NULL, pinctrl_compats[i])) + struct device_node *np __free(device_node) = + of_find_compatible_node(NULL, NULL, pinctrl_compats[i]); + if (np) break; } diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 6dcba0e0ddaa..c3676b21e816 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -268,6 +268,7 @@ #define MRVL_XFER_FUNC_START BIT(0) #define MRVL_XFER_QWORD_COUNT 32 #define MRVL_XFER_QWORD_BYTECOUNT 8 +#define MRVL_XFER_MAX_LEN (MRVL_XFER_QWORD_COUNT * MRVL_XFER_QWORD_BYTECOUNT) #define MRVL_XSPI_POLL_TIMEOUT_US 1000 #define MRVL_XSPI_POLL_DELAY_US 10 @@ -1047,7 +1048,7 @@ static int cdns_xspi_transfer_one_message_b0(struct spi_controller *controller, struct spi_device *spi = m->spi; struct spi_transfer *t = NULL; - const unsigned int max_len = MRVL_XFER_QWORD_BYTECOUNT * MRVL_XFER_QWORD_COUNT; + const unsigned int max_len = MRVL_XFER_MAX_LEN; int current_transfer_len; int cs = spi_get_chipselect(spi, 0); int cs_change = 0; @@ -1070,13 +1071,16 @@ static int cdns_xspi_transfer_one_message_b0(struct spi_controller *controller, list_for_each_entry(t, &m->transfers, transfer_list) { u8 *txd = (u8 *) t->tx_buf; u8 *rxd = (u8 *) t->rx_buf; - u8 data[10]; + u8 data[MRVL_XFER_MAX_LEN] = {0}; u32 cmd_regs[6]; if (!txd) txd = data; - cdns_xspi->in_buffer = txd + 1; + if (rxd) + cdns_xspi->in_buffer = rxd; + else + cdns_xspi->in_buffer = data; cdns_xspi->out_buffer = txd + 1; while (t->len) { @@ -1101,8 +1105,10 @@ static int cdns_xspi_transfer_one_message_b0(struct spi_controller *controller, if (!cdns_xspi_is_stig_ready(cdns_xspi, true)) return -EIO; - cdns_xspi->in_buffer += current_transfer_len; - cdns_xspi->out_buffer += current_transfer_len; + if (rxd) + cdns_xspi->in_buffer += current_transfer_len; + if (t->tx_buf) + cdns_xspi->out_buffer += current_transfer_len; } if (rxd) { diff --git a/drivers/spi/spi-ch341.c b/drivers/spi/spi-ch341.c index 3eaa8f176f63..170240a0dde8 100644 --- a/drivers/spi/spi-ch341.c +++ b/drivers/spi/spi-ch341.c @@ -189,6 +189,12 @@ static int ch341_probe(struct usb_interface *intf, ctrl->transfer_one = ch341_transfer_one; ctrl->set_cs = ch341_set_cs; ctrl->auto_runtime_pm = false; + /* + * The CH341A SPI_STREAM command clocks data in both directions on + * every transfer, so the driver always needs a TX and an RX buffer; + * let the SPI core supply dummy buffers for half-duplex transfers. + */ + ctrl->flags = SPI_CONTROLLER_MUST_TX | SPI_CONTROLLER_MUST_RX; usb_set_intfdata(intf, ch341); diff --git a/drivers/spi/spi-jcore.c b/drivers/spi/spi-jcore.c index e37ca22e04ba..2bde899eb2b4 100644 --- a/drivers/spi/spi-jcore.c +++ b/drivers/spi/spi-jcore.c @@ -84,6 +84,8 @@ static void jcore_spi_baudrate(struct jcore_spi *hw, int speed) { if (speed == hw->speed_hz) return; + if (speed <= 0) + speed = 1; hw->speed_hz = speed; if (speed >= hw->clock_freq / 2) hw->speed_reg = 0; diff --git a/drivers/spi/spi-ljca.c b/drivers/spi/spi-ljca.c index 3f412cf8f1cd..0bc858993311 100644 --- a/drivers/spi/spi-ljca.c +++ b/drivers/spi/spi-ljca.c @@ -105,7 +105,13 @@ static int ljca_spi_read_write(struct ljca_spi_dev *ljca_spi, const u8 *w_data, (u8 *)r_packet, LJCA_SPI_BUF_SIZE); if (ret < 0) return ret; - else if (ret < sizeof(*r_packet) || r_packet->len <= 0) + + if (ret < sizeof(*r_packet)) + return -EIO; + + /* write acks carry no payload */ + if (!r_packet->len || r_packet->len > len || + (r_data && ret < sizeof(*r_packet) + r_packet->len)) return -EIO; if (r_data) diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c index cccd17f24775..79328ae89fbb 100644 --- a/drivers/spi/spi-npcm-fiu.c +++ b/drivers/spi/spi-npcm-fiu.c @@ -343,6 +343,10 @@ static int npcm_fiu_uma_read(struct spi_mem *mem, u32 val; u32 i; + /* data_reg holds at most 16 bytes */ + if (data_size > sizeof(data_reg)) + return -EOPNOTSUPP; + regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS, NPCM_FIU_UMA_CTS_DEV_NUM, (spi_get_chipselect(mem->spi, 0) << @@ -398,6 +402,10 @@ static int npcm_fiu_uma_write(struct spi_mem *mem, u32 val; u32 i; + /* data_reg holds at most 16 bytes */ + if (data_size > sizeof(data_reg)) + return -EOPNOTSUPP; + regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS, NPCM_FIU_UMA_CTS_DEV_NUM, (spi_get_chipselect(mem->spi, 0) << diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 919e847c061d..567485785ec9 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -391,6 +391,8 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) dev_dbg(snandc->dev, "ECC strength: %u bits per %u bytes\n", ecc_cfg->strength, ecc_cfg->step_size); + snandc->qspi->ecc = ecc_cfg; + return 0; err_free_ecc_cfg: @@ -407,6 +409,7 @@ static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand) kfree(snandc->qspi->oob_buf); snandc->qspi->oob_buf = NULL; + snandc->qspi->ecc = NULL; kfree(ecc_cfg); } diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 7a6ee93be9bd..e5d483a9d38b 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -2454,6 +2454,7 @@ static int stm32_spi_probe(struct platform_device *pdev) gen_pool_free(spi->sram_pool, (unsigned long)spi->sram_rx_buf, spi->sram_rx_buf_size); + spi->sram_rx_buf = NULL; dev_warn(&pdev->dev, "failed to request rx mdma channel, DMA only\n"); } @@ -2491,7 +2492,7 @@ static int stm32_spi_probe(struct platform_device *pdev) if (spi->mdma_rx) dma_release_channel(spi->mdma_rx); err_pool_free: - if (spi->sram_pool) + if (spi->sram_rx_buf) gen_pool_free(spi->sram_pool, (unsigned long)spi->sram_rx_buf, spi->sram_rx_buf_size); err_dma_release: diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index 406fd9d5337e..c9588fd1d123 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -229,11 +229,10 @@ static bool zynq_qspi_supports_op(struct spi_mem *mem, return false; /* - * The number of address bytes should be equal to or less than 3 bytes. + * The number of address bytes should be equal to or less than 4 bytes. */ - if (op->addr.nbytes > 3) + if (op->addr.nbytes > 4) return false; - return true; } @@ -526,6 +525,7 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) { struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->controller); + u8 opaddr[4] __aligned(4); int err = 0, i; u8 *tmpbuf; @@ -547,12 +547,13 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem, } if (op->addr.nbytes) { - for (i = 0; i < op->addr.nbytes; i++) { - xqspi->txbuf[i] = op->addr.val >> + for (i = 0; i < op->addr.nbytes; i++) + opaddr[i] = op->addr.val >> (8 * (op->addr.nbytes - i - 1)); - } reinit_completion(&xqspi->data_completion); + xqspi->txbuf = opaddr; + xqspi->rxbuf = NULL; xqspi->tx_bytes = op->addr.nbytes; xqspi->rx_bytes = op->addr.nbytes; diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c index 78bf8c4031e9..7d2844d9bcd9 100644 --- a/drivers/staging/greybus/uart.c +++ b/drivers/staging/greybus/uart.c @@ -53,7 +53,6 @@ struct gb_tty { spinlock_t read_lock; spinlock_t write_lock; struct async_icount iocount; - struct async_icount oldcount; wait_queue_head_t wioctl; struct mutex mutex; u8 ctrlin; /* input control lines */ @@ -643,11 +642,16 @@ static int wait_serial_change(struct gb_tty *gb_tty, unsigned long arg) if (!(arg & (TIOCM_DSR | TIOCM_RI | TIOCM_CD))) return -EINVAL; - do { + spin_lock_irq(&gb_tty->read_lock); + old = gb_tty->iocount; + spin_unlock_irq(&gb_tty->read_lock); + + add_wait_queue(&gb_tty->wioctl, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irq(&gb_tty->read_lock); - old = gb_tty->oldcount; new = gb_tty->iocount; - gb_tty->oldcount = new; spin_unlock_irq(&gb_tty->read_lock); if ((arg & TIOCM_DSR) && (old.dsr != new.dsr)) @@ -657,18 +661,20 @@ static int wait_serial_change(struct gb_tty *gb_tty, unsigned long arg) if ((arg & TIOCM_RI) && (old.rng != new.rng)) break; - add_wait_queue(&gb_tty->wioctl, &wait); - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - remove_wait_queue(&gb_tty->wioctl, &wait); if (gb_tty->disconnected) { - if (arg & TIOCM_CD) - break; retval = -ENODEV; - } else if (signal_pending(current)) { + break; + } + + schedule(); + + if (signal_pending(current)) { retval = -ERESTARTSYS; + break; } - } while (!retval); + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&gb_tty->wioctl, &wait); return retval; } diff --git a/drivers/staging/media/av7110/sp8870.c b/drivers/staging/media/av7110/sp8870.c index 0c813860f5b2..b5b49f1ef5e7 100644 --- a/drivers/staging/media/av7110/sp8870.c +++ b/drivers/staging/media/av7110/sp8870.c @@ -315,7 +315,6 @@ static int sp8870_init(struct dvb_frontend *fe) sp8870_wake_up(state); if (state->initialised) return 0; - state->initialised = 1; dprintk("initialising frontend...\n"); @@ -353,6 +352,8 @@ static int sp8870_init(struct dvb_frontend *fe) sp8870_writereg(state, 0x0D00, 0x010); sp8870_writereg(state, 0x0D01, 0x000); + state->initialised = 1; + return 0; } @@ -401,7 +402,7 @@ static int sp8870_read_ber(struct dvb_frontend *fe, u32 *ber) if (ret < 0) return -EIO; - tmp = ret << 6; + tmp |= ret << 6; if (tmp >= 0x3FFF0) tmp = ~0; diff --git a/drivers/staging/media/imx/imx-media-csc-scaler.c b/drivers/staging/media/imx/imx-media-csc-scaler.c index 1869c5792ecb..085f4f8eb8bd 100644 --- a/drivers/staging/media/imx/imx-media-csc-scaler.c +++ b/drivers/staging/media/imx/imx-media-csc-scaler.c @@ -147,6 +147,7 @@ static void device_run(void *_ctx) v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); v4l2_m2m_job_finish(priv->m2m_dev, ctx->fh.m2m_ctx); + kfree(run); } /* diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c index ccb71de22b0a..49df5c6398b5 100644 --- a/drivers/staging/media/meson/vdec/vdec.c +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -34,7 +34,7 @@ struct dummy_buf { static u32 get_output_size(u32 width, u32 height) { - return ALIGN(width * height, SZ_64K); + return ALIGN(ALIGN(width, 32) * ALIGN(height, 32), SZ_64K); } u32 amvdec_get_output_size(struct amvdec_session *sess) diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index 4727f94df435..f8ade0bea1da 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -316,7 +316,7 @@ static void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup) } else { cur_time = jiffies; - if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ) { + if (cur_time - psecuritypriv->last_mic_err_time < 60 * HZ) { psecuritypriv->btkip_countermeasure = true; psecuritypriv->last_mic_err_time = 0; psecuritypriv->btkip_countermeasure_time = cur_time; @@ -384,13 +384,13 @@ static signed int recvframe_chkmic(struct adapter *adapter, union recv_frame *p mickey = &stainfo->dot11tkiprxmickey.skey[0]; } - datalen = precvframe->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len-prxattrib->icv_len-8;/* icv_len included the mic code */ + datalen = precvframe->u.hdr.len - prxattrib->hdrlen - prxattrib->iv_len - prxattrib->icv_len - 8;/* icv_len included the mic code */ pframe = precvframe->u.hdr.rx_data; - payload = pframe+prxattrib->hdrlen+prxattrib->iv_len; + payload = pframe + prxattrib->hdrlen + prxattrib->iv_len; rtw_seccalctkipmic(mickey, pframe, payload, datalen, &miccode[0], (unsigned char)prxattrib->priority); /* care the length of the data */ - pframemic = payload+datalen; + pframemic = payload + datalen; bmic_err = false; @@ -437,9 +437,22 @@ static union recv_frame *decryptor(struct adapter *padapter, union recv_frame *p u32 res = _SUCCESS; if (prxattrib->encrypt > 0) { - u8 *iv = precv_frame->u.hdr.rx_data+prxattrib->hdrlen; + u8 *iv; + u32 min_len = prxattrib->hdrlen + prxattrib->iv_len + prxattrib->icv_len; - prxattrib->key_index = (((iv[3])>>6)&0x3); + /* TKIP appends an 8-byte Michael MIC that icv_len doesn't account for */ + if (prxattrib->encrypt == _TKIP_) + min_len += 8; + + /* a protected frame must be long enough to hold the IV and ICV/MIC */ + if (precv_frame->u.hdr.len < min_len) { + rtw_free_recvframe(precv_frame, + &padapter->recvpriv.free_recv_queue); + return NULL; + } + + iv = precv_frame->u.hdr.rx_data + prxattrib->hdrlen; + prxattrib->key_index = (((iv[3]) >> 6) & 0x3); if (prxattrib->key_index > WEP_KEYS) { switch (prxattrib->encrypt) { @@ -561,7 +574,7 @@ static signed int recv_decache(union recv_frame *precv_frame, u8 bretry, struct { signed int tid = precv_frame->u.hdr.attrib.priority; - u16 seq_ctrl = ((precv_frame->u.hdr.attrib.seq_num&0xffff) << 4) | + u16 seq_ctrl = ((precv_frame->u.hdr.attrib.seq_num & 0xffff) << 4) | (precv_frame->u.hdr.attrib.frag_num & 0xf); if (tid > 15) @@ -625,29 +638,29 @@ static void process_wmmps_data(struct adapter *padapter, union recv_frame *precv if (!psta->qos_option) return; - if (!(psta->qos_info&0xf)) + if (!(psta->qos_info & 0xf)) return; - if (psta->state&WIFI_SLEEP_STATE) { + if (psta->state & WIFI_SLEEP_STATE) { u8 wmmps_ac = 0; switch (pattrib->priority) { case 1: case 2: - wmmps_ac = psta->uapsd_bk&BIT(1); + wmmps_ac = psta->uapsd_bk & BIT(1); break; case 4: case 5: - wmmps_ac = psta->uapsd_vi&BIT(1); + wmmps_ac = psta->uapsd_vi & BIT(1); break; case 6: case 7: - wmmps_ac = psta->uapsd_vo&BIT(1); + wmmps_ac = psta->uapsd_vo & BIT(1); break; case 0: case 3: default: - wmmps_ac = psta->uapsd_be&BIT(1); + wmmps_ac = psta->uapsd_be & BIT(1); break; } @@ -967,20 +980,20 @@ static signed int validate_recv_ctrl_frame(struct adapter *padapter, union recv_ switch (pattrib->priority) { case 1: case 2: - wmmps_ac = psta->uapsd_bk&BIT(0); + wmmps_ac = psta->uapsd_bk & BIT(0); break; case 4: case 5: - wmmps_ac = psta->uapsd_vi&BIT(0); + wmmps_ac = psta->uapsd_vi & BIT(0); break; case 6: case 7: - wmmps_ac = psta->uapsd_vo&BIT(0); + wmmps_ac = psta->uapsd_vo & BIT(0); break; case 0: case 3: default: - wmmps_ac = psta->uapsd_be&BIT(0); + wmmps_ac = psta->uapsd_be & BIT(0); break; } @@ -992,7 +1005,7 @@ static signed int validate_recv_ctrl_frame(struct adapter *padapter, union recv_ psta->state ^= WIFI_STA_ALIVE_CHK_STATE; } - if ((psta->state&WIFI_SLEEP_STATE) && (pstapriv->sta_dz_bitmap&BIT(psta->aid))) { + if ((psta->state & WIFI_SLEEP_STATE) && (pstapriv->sta_dz_bitmap & BIT(psta->aid))) { struct list_head *xmitframe_plist, *xmitframe_phead; struct xmit_frame *pxmitframe = NULL; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; @@ -1036,7 +1049,7 @@ static signed int validate_recv_ctrl_frame(struct adapter *padapter, union recv_ /* spin_unlock_bh(&psta->sleep_q.lock); */ spin_unlock_bh(&pxmitpriv->lock); - if (pstapriv->tim_bitmap&BIT(psta->aid)) { + if (pstapriv->tim_bitmap & BIT(psta->aid)) { if (psta->sleepq_len == 0) { /* issue nulldata with More data bit = 0 to indicate we have no buffered packets */ issue_nulldata_in_interrupt(padapter, psta->hwaddr); @@ -1411,15 +1424,17 @@ static signed int validate_80211w_mgmt(struct adapter *adapter, union recv_frame if (!mgmt_DATA) goto validate_80211w_fail; precv_frame = decryptor(adapter, precv_frame); + if (!precv_frame) { + kfree(mgmt_DATA); + goto validate_80211w_fail; + } /* save actual management data frame body */ - memcpy(mgmt_DATA, ptr+pattrib->hdrlen+pattrib->iv_len, data_len); + memcpy(mgmt_DATA, ptr + pattrib->hdrlen + pattrib->iv_len, data_len); /* overwrite the iv field */ - memcpy(ptr+pattrib->hdrlen, mgmt_DATA, data_len); + memcpy(ptr + pattrib->hdrlen, mgmt_DATA, data_len); /* remove the iv and icv length */ pattrib->pkt_len = pattrib->pkt_len - pattrib->iv_len - pattrib->icv_len; kfree(mgmt_DATA); - if (!precv_frame) - goto validate_80211w_fail; } else if (is_multicast_ether_addr(GetAddr1Ptr(ptr)) && (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC)) { signed int BIP_ret = _SUCCESS; @@ -1470,7 +1485,7 @@ static signed int validate_recv_frame(struct adapter *adapter, union recv_frame struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; u8 *ptr = precv_frame->u.hdr.rx_data; - u8 ver = (unsigned char) (*ptr)&0x3; + u8 ver = (unsigned char) (*ptr) & 0x3; /* add version chk */ if (ver != 0) { @@ -1508,7 +1523,7 @@ static signed int validate_recv_frame(struct adapter *adapter, union recv_frame retval = _FAIL; /* only data frame return _SUCCESS */ break; case WIFI_DATA_TYPE: /* data */ - pattrib->qos = (subtype & BIT(7)) ? 1:0; + pattrib->qos = (subtype & BIT(7)) ? 1 : 0; retval = validate_recv_data_frame(adapter, precv_frame); if (retval == _FAIL) { struct recv_priv *precvpriv = &adapter->recvpriv; @@ -1553,8 +1568,8 @@ static signed int wlanhdr_to_ethhdr(union recv_frame *precvframe) if (pattrib->encrypt) recvframe_pull_tail(precvframe, pattrib->icv_len); - psnap = (struct ieee80211_snap_hdr *)(ptr+pattrib->hdrlen + pattrib->iv_len); - psnap_type = ptr+pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE; + psnap = (struct ieee80211_snap_hdr *)(ptr + pattrib->hdrlen + pattrib->iv_len); + psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE; /* convert hdr + possible LLC headers into Ethernet header */ /* eth_type = (psnap_type[0] << 8) | psnap_type[1]; */ if ((!memcmp(psnap, rfc1042_header, SNAP_SIZE) && @@ -1568,37 +1583,37 @@ static signed int wlanhdr_to_ethhdr(union recv_frame *precvframe) /* Leave Ethernet header part of hdr and full payload */ bsnaphdr = false; - rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr?SNAP_SIZE:0); + rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0); len = precvframe->u.hdr.len - rmv_len; - memcpy(&be_tmp, ptr+rmv_len, 2); + memcpy(&be_tmp, ptr + rmv_len, 2); eth_type = ntohs(be_tmp); /* pattrib->ether_type */ pattrib->eth_type = eth_type; if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)) { ptr += rmv_len; *ptr = 0x87; - *(ptr+1) = 0x12; + *(ptr + 1) = 0x12; eth_type = 0x8712; /* append rx status for mp test packets */ - ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr)+2)-24); + ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + 2) - 24); if (!ptr) return _FAIL; memcpy(ptr, get_rxmem(precvframe), 24); ptr += 24; } else { - ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr) + (bsnaphdr?2:0))); + ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0))); if (!ptr) return _FAIL; } memcpy(ptr, pattrib->dst, ETH_ALEN); - memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN); + memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN); if (!bsnaphdr) { be_tmp = htons(len); - memcpy(ptr+12, &be_tmp, 2); + memcpy(ptr + 12, &be_tmp, 2); } return _SUCCESS; @@ -1736,7 +1751,7 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe) pdata += nSubframe_Length; a_len -= nSubframe_Length; if (a_len != 0) { - padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & (4-1)); + padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & (4 - 1)); if (padding_len == 4) padding_len = 0; @@ -2002,7 +2017,7 @@ static int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame * rtw_recv_indicatepkt(padapter, prframe); - preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096; + preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) % 4096; return _SUCCESS; } @@ -2012,7 +2027,7 @@ static int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame * retval = amsdu_to_msdu(padapter, prframe); - preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096; + preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) % 4096; if (retval != _SUCCESS) { } @@ -2201,7 +2216,7 @@ static int recv_func(struct adapter *padapter, union recv_frame *rframe) !psecuritypriv->busetkipkey) { rtw_enqueue_recvframe(rframe, &padapter->recvpriv.uc_swdec_pending_queue); - if (recvpriv->free_recvframe_cnt < NR_RECVFRAME/4) { + if (recvpriv->free_recvframe_cnt < NR_RECVFRAME / 4) { /* to prevent from recvframe starvation, get recvframe from uc_swdec_pending_queue to free_recvframe_cnt */ rframe = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue); if (rframe) @@ -2289,19 +2304,19 @@ static void rtw_signal_stat_timer_hdl(struct timer_list *t) } /* update value of signal_strength, rssi, signal_qual */ - tmp_s = (avg_signal_strength+(_alpha-1)*recvpriv->signal_strength); + tmp_s = (avg_signal_strength + (_alpha - 1) * recvpriv->signal_strength); if (tmp_s % _alpha) - tmp_s = tmp_s/_alpha + 1; + tmp_s = tmp_s / _alpha + 1; else - tmp_s = tmp_s/_alpha; + tmp_s = tmp_s / _alpha; if (tmp_s > 100) tmp_s = 100; - tmp_q = (avg_signal_qual+(_alpha-1)*recvpriv->signal_qual); + tmp_q = (avg_signal_qual + (_alpha - 1) * recvpriv->signal_qual); if (tmp_q % _alpha) - tmp_q = tmp_q/_alpha + 1; + tmp_q = tmp_q / _alpha + 1; else - tmp_q = tmp_q/_alpha; + tmp_q = tmp_q / _alpha; if (tmp_q > 100) tmp_q = 100; diff --git a/drivers/staging/rtl8723bs/hal/sdio_ops.c b/drivers/staging/rtl8723bs/hal/sdio_ops.c index 54228c41579e..811720775eb8 100644 --- a/drivers/staging/rtl8723bs/hal/sdio_ops.c +++ b/drivers/staging/rtl8723bs/hal/sdio_ops.c @@ -791,6 +791,13 @@ static struct recv_buf *sd_recv_rxfifo(struct adapter *adapter, u32 size) struct recv_priv *recv_priv; struct recv_buf *recvbuf; + /* RX0_REQ_LEN is device-reported; the skb buffer is only + * MAX_RECVBUF_SZ bytes, reject bogus lengths instead of + * overflowing past it. + */ + if (size > MAX_RECVBUF_SZ) + return NULL; + /* Patch for some SDIO Host 4 bytes issue */ /* ex. RK3188 */ readsize = round_up(size, 4); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index 48e7849d4816..dc9c82e8650e 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -178,17 +178,21 @@ static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone, { int cpu; int curr_temp, ret; - - *temp = 0; + bool temp_valid = false; for_each_online_cpu(cpu) { ret = intel_tcc_get_temp(cpu, &curr_temp, false); if (ret < 0) return ret; - if (!*temp || curr_temp > *temp) + if (!temp_valid || curr_temp > *temp) { *temp = curr_temp; + temp_valid = true; + } } + if (!temp_valid) + return -ENODATA; + *temp *= 1000; return 0; diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c index 9a4cec000910..61665f945b4c 100644 --- a/drivers/thermal/intel/intel_powerclamp.c +++ b/drivers/thermal/intel/intel_powerclamp.c @@ -290,9 +290,10 @@ static int window_size_set(const char *arg, const struct kernel_param *kp) pr_err("Out of recommended window size %lu, between 2-10\n", new_window_size); ret = -EINVAL; + goto exit_win; } - window_size = clamp(new_window_size, 2ul, 10ul); + window_size = new_window_size; smp_mb(); exit_win: diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index b9cc0b786ca6..f9f9c10246e1 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -231,8 +231,9 @@ struct exar8250_platform { int (*rs485_config)(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485); const struct serial_rs485 *rs485_supported; - int (*register_gpio)(struct pci_dev *pcidev, struct uart_8250_port *port); - void (*unregister_gpio)(struct uart_8250_port *port); + int (*register_gpio)(struct exar8250 *priv, struct pci_dev *pcidev, + struct uart_8250_port *port); + void (*unregister_gpio)(struct exar8250 *priv); }; /** @@ -256,6 +257,7 @@ struct exar8250 { struct exar8250_board *board; struct eeprom_93cx6 eeprom; void __iomem *virt; + struct platform_device *gpio; int line[]; }; @@ -1174,22 +1176,21 @@ static const struct software_node exar_gpio_node = { .properties = exar_gpio_properties, }; -static int xr17v35x_register_gpio(struct pci_dev *pcidev, struct uart_8250_port *port) +static int xr17v35x_register_gpio(struct exar8250 *priv, struct pci_dev *pcidev, + struct uart_8250_port *port) { if (pcidev->vendor == PCI_VENDOR_ID_EXAR) - port->port.private_data = - __xr17v35x_register_gpio(pcidev, &exar_gpio_node); + priv->gpio = __xr17v35x_register_gpio(pcidev, &exar_gpio_node); return 0; } -static void xr17v35x_unregister_gpio(struct uart_8250_port *port) +static void xr17v35x_unregister_gpio(struct exar8250 *priv) { - if (!port->port.private_data) - return; - - __xr17v35x_unregister_gpio(port->port.private_data); - port->port.private_data = NULL; + if (priv->gpio) { + __xr17v35x_unregister_gpio(priv->gpio); + priv->gpio = NULL; + } } static int sealevel_rs485_config(struct uart_port *port, struct ktermios *termios, @@ -1286,8 +1287,9 @@ static const struct software_node iot2040_gpio_node = { .properties = iot2040_gpio_properties, }; -static int iot2040_register_gpio(struct pci_dev *pcidev, - struct uart_8250_port *port) +static int iot2040_register_gpio(struct exar8250 *priv, + struct pci_dev *pcidev, + struct uart_8250_port *port) { u8 __iomem *p = port->port.membase; @@ -1296,8 +1298,7 @@ static int iot2040_register_gpio(struct pci_dev *pcidev, writeb(IOT2040_UARTS_ENABLE, p + UART_EXAR_MPIOLVL_15_8); writeb(IOT2040_UARTS_GPIO_HI_MODE, p + UART_EXAR_MPIOSEL_15_8); - port->port.private_data = - __xr17v35x_register_gpio(pcidev, &iot2040_gpio_node); + priv->gpio = __xr17v35x_register_gpio(pcidev, &iot2040_gpio_node); return 0; } @@ -1374,7 +1375,7 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, /* Setup Multipurpose Input/Output pins. */ setup_gpio(pcidev, p); - ret = platform->register_gpio(pcidev, port); + ret = platform->register_gpio(priv, pcidev, port); } return ret; @@ -1384,9 +1385,8 @@ static void pci_xr17v35x_exit(struct pci_dev *pcidev) { const struct exar8250_platform *platform = exar_get_platform(); struct exar8250 *priv = pci_get_drvdata(pcidev); - struct uart_8250_port *port = serial8250_get_port(priv->line[0]); - platform->unregister_gpio(port); + platform->unregister_gpio(priv); } static inline void exar_misc_clear(struct exar8250 *priv) diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 776ec1ef29d6..325e587ae2c4 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -183,9 +183,8 @@ static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port) static void ehl_serial_exit(struct lpss8250 *lpss) { - struct uart_8250_port *up = serial8250_get_port(lpss->data.line); - - up->dma = NULL; + if (lpss->data.line >= 0) + serial8250_get_port(lpss->data.line)->dma = NULL; } #ifdef CONFIG_SERIAL_8250_DMA @@ -329,6 +328,8 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) return ret; lpss->board = (struct lpss8250_board *)id->driver_data; + /* for tests in lpss->board->exit() */ + lpss->data.line = -1; memset(&uart, 0, sizeof(struct uart_8250_port)); diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index c0ffee251614..8c48e0a26b3c 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -727,6 +727,9 @@ static int omap_8250_startup(struct uart_port *port) struct uart_8250_dma *dma = &priv->omap8250_dma; int ret; + /* ISR and runtime PM need the line; probe sets it only after registration */ + priv->line = port->line; + #ifdef CONFIG_PM up->capabilities |= UART_CAP_RPM; #endif diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 4b213d0c6133..20d2a8612cbc 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1355,10 +1355,6 @@ static void pl011_rs485_tx_start(struct uart_amba_port *uap) struct uart_port *port = &uap->port; u32 cr; - if (uap->rs485_tx_state == WAIT_AFTER_RTS) { - uap->rs485_tx_state = SEND; - return; - } if (uap->rs485_tx_state == WAIT_AFTER_SEND || uap->rs485_tx_state == WAIT_AFTER_SEND_DELAY) { hrtimer_try_to_cancel(&uap->trigger_stop_tx); @@ -1397,6 +1393,10 @@ static void pl011_start_tx(struct uart_port *port) if ((uap->port.rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_state != SEND) { + /* trigger_start_tx starts TX once delay_rts_before_send passed */ + if (uap->rs485_tx_state == WAIT_AFTER_RTS) + return; + pl011_rs485_tx_start(uap); if (uap->rs485_tx_state == WAIT_AFTER_RTS) return; @@ -1413,8 +1413,10 @@ static enum hrtimer_restart pl011_trigger_start_tx(struct hrtimer *t) unsigned long flags; uart_port_lock_irqsave(&uap->port, &flags); - if (uap->rs485_tx_state == WAIT_AFTER_RTS) + if (uap->rs485_tx_state == WAIT_AFTER_RTS) { + uap->rs485_tx_state = SEND; pl011_start_tx(&uap->port); + } uart_port_unlock_irqrestore(&uap->port, flags); return HRTIMER_NORESTART; @@ -2306,8 +2308,31 @@ static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios, struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - if (port->rs485.flags & SER_RS485_ENABLED) + if ((port->rs485.flags & SER_RS485_ENABLED) && + !(rs485->flags & SER_RS485_ENABLED)) { + bool tx_pending = uap->rs485_tx_state == WAIT_AFTER_RTS; + u32 cr = pl011_read(uap, REG_CR); + + /* + * Leaving RS485 mode, which only enables the transmitter while + * sending. Don't stop it, as that stalls a DMA transfer still + * in flight. Drop pending deferred starts and stops and keep + * it enabled. + */ + hrtimer_try_to_cancel(&uap->trigger_start_tx); + hrtimer_try_to_cancel(&uap->trigger_stop_tx); + uap->rs485_tx_state = OFF; + + cr |= UART011_CR_TXE | UART011_CR_RXE; + pl011_write(cr, uap, REG_CR); + + /* Start TX that was still waiting for delay_rts_before_send */ + if (tx_pending && !uart_tx_stopped(port) && + !pl011_dma_tx_start(uap)) + pl011_start_tx_pio(uap); + } else if (port->rs485.flags & SER_RS485_ENABLED) { pl011_rs485_tx_stop(uap); + } /* Make sure auto RTS is disabled */ if (rs485->flags & SER_RS485_ENABLED) { diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index e3a919328695..f49d6052d11b 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -444,7 +444,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) skip_a: uart_port_unlock(&uap_a->port); if (push) - tty_flip_buffer_push(&uap->port.state->port); + tty_flip_buffer_push(&uap_a->port.state->port); if (!uap_b) goto out; @@ -469,7 +469,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) skip_b: uart_port_unlock(&uap_b->port); if (push) - tty_flip_buffer_push(&uap->port.state->port); + tty_flip_buffer_push(&uap_b->port.state->port); out: return rc; diff --git a/drivers/ufs/core/ufs_bsg.c b/drivers/ufs/core/ufs_bsg.c index bb6ff8ca5c7a..0e0b08a3821c 100644 --- a/drivers/ufs/core/ufs_bsg.c +++ b/drivers/ufs/core/ufs_bsg.c @@ -142,7 +142,7 @@ static int ufs_bsg_request(struct bsg_job *job) int ret; bool rpmb = false; - bsg_reply->reply_payload_rcv_len = 0; + memset(job->reply, 0, job->reply_len); ufshcd_rpm_get_sync(hba); @@ -194,14 +194,12 @@ static int ufs_bsg_request(struct bsg_job *job) ufshcd_rpm_put_sync(hba); kfree(buff); bsg_reply->result = ret; - /* complete the job here only if no error */ - if (ret == 0) { + if (ret == 0) job->reply_len = rpmb ? sizeof(struct ufs_rpmb_reply) : sizeof(struct ufs_bsg_reply); - bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len); - } + bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len); - return ret; + return 0; } /** diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 52df1df6333a..97f86b6905b5 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -4219,9 +4219,12 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, do { /* for peer attributes we retry upon failure */ ret = ufshcd_send_uic_cmd(hba, &uic_cmd); - if (ret) + if (ret) { dev_dbg(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n", set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret); + uic_cmd.argument2 &= ~MASK_UIC_COMMAND_RESULT; + uic_cmd.argument3 = mib_val; + } } while (ret && peer && --retries); if (ret) @@ -4285,9 +4288,11 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, do { /* for peer attributes we retry upon failure */ ret = ufshcd_send_uic_cmd(hba, &uic_cmd); - if (ret) + if (ret) { dev_dbg(hba->dev, "%s: attr-id 0x%x error code %d\n", get, UIC_GET_ATTR_ID(attr_sel), ret); + uic_cmd.argument2 &= ~MASK_UIC_COMMAND_RESULT; + } } while (ret && peer && --retries); if (ret) @@ -5709,9 +5714,6 @@ static int ufshcd_poll(struct Scsi_Host *shost, unsigned int queue_num) spin_lock_irqsave(&hba->outstanding_lock, flags); tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); completed_reqs = ~tr_doorbell & hba->outstanding_reqs; - WARN_ONCE(completed_reqs & ~hba->outstanding_reqs, - "completed: %#lx; outstanding: %#lx\n", completed_reqs, - hba->outstanding_reqs); if (queue_num == UFSHCD_POLL_FROM_INTERRUPT_CONTEXT) { /* Do not complete polled requests from interrupt context. */ ufshcd_clear_polled(hba, &completed_reqs); @@ -7775,15 +7777,6 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) } hba->req_abort_count++; - if (!hba->mcq_enabled && !(reg & (1 << tag))) { - /* only execute this code in single doorbell mode */ - dev_err(hba->dev, - "%s: cmd was completed, but without a notifying intr, tag = %d", - __func__, tag); - __ufshcd_transfer_req_compl(hba, 1UL << tag); - goto release; - } - /* * Task abort to the device W-LUN is illegal. When this command * will fail, due to spec violation, scsi err handling next step diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index b980cb08d675..990482982a28 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -782,6 +782,7 @@ static void acm_port_shutdown(struct tty_port *port) urb = usb_get_from_anchor(&acm->delayed); if (!urb) break; + usb_put_urb(urb); wb = urb->context; wb->use = false; usb_autopm_put_interface_async(acm->control); @@ -1710,7 +1711,7 @@ static int acm_resume(struct usb_interface *intf) urb = usb_get_from_anchor(&acm->delayed); if (!urb) break; - + usb_put_urb(urb); acm_start_wb(acm, urb->context); } @@ -1818,6 +1819,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x11ca, 0x0201), /* VeriFone Mx870 Gadget Serial */ .driver_info = SINGLE_RX_URB, }, + { USB_DEVICE(0x11ca, 0x0219), /* VeriFone Vx820 Gadget Serial */ + .driver_info = SINGLE_RX_URB, + }, { USB_DEVICE(0x1901, 0x0006), /* GE Healthcare Patient Monitor UI Controller */ .driver_info = DISABLE_ECHO, /* DISABLE ECHO in termios flag */ }, diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 0f804a52ab76..a8e5016fee98 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -613,6 +613,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* ezcap401 - BOS descriptor fetch hangs at SuperSpeed Plus */ { USB_DEVICE(0x32ed, 0x0401), .driver_info = USB_QUIRK_NO_BOS }, + /* GameSir G7 SE */ + { USB_DEVICE(0x3537, 0x10a0), .driver_info = USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE }, + /* DELL USB GEN2 */ { USB_DEVICE(0x413c, 0xb062), .driver_info = USB_QUIRK_NO_LPM | USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/fotg210/fotg210-udc.c b/drivers/usb/fotg210/fotg210-udc.c index 0bae12e34f9a..26f29dba58f2 100644 --- a/drivers/usb/fotg210/fotg210-udc.c +++ b/drivers/usb/fotg210/fotg210-udc.c @@ -661,7 +661,7 @@ static void fotg210_set_feature(struct fotg210_udc *fotg210, case USB_RECIP_ENDPOINT: { u8 epnum; epnum = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; - if (epnum) + if (epnum && epnum < FOTG210_MAX_NUM_EP) fotg210_set_epnstall(fotg210->ep[epnum]); else fotg210_set_cxstall(fotg210); @@ -677,8 +677,8 @@ static void fotg210_set_feature(struct fotg210_udc *fotg210, static void fotg210_clear_feature(struct fotg210_udc *fotg210, struct usb_ctrlrequest *ctrl) { - struct fotg210_ep *ep = - fotg210->ep[ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK]; + u8 epnum = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; + struct fotg210_ep *ep; switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: @@ -688,7 +688,12 @@ static void fotg210_clear_feature(struct fotg210_udc *fotg210, fotg210_set_cxdone(fotg210); break; case USB_RECIP_ENDPOINT: - if (ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK) { + if (epnum >= FOTG210_MAX_NUM_EP) { + fotg210_request_error(fotg210); + break; + } + if (epnum) { + ep = fotg210->ep[epnum]; if (ep->wedged) { fotg210_set_cxdone(fotg210); break; @@ -744,8 +749,8 @@ static void fotg210_get_status(struct fotg210_udc *fotg210, fotg210->ep0_data = cpu_to_le16(0); break; case USB_RECIP_ENDPOINT: - epnum = ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK; - if (epnum) + epnum = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; + if (epnum && epnum < FOTG210_MAX_NUM_EP) fotg210->ep0_data = cpu_to_le16(fotg210_is_epnstall(fotg210->ep[epnum]) << USB_ENDPOINT_HALT); diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 677cd236f079..c14e8e250037 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -615,7 +615,7 @@ ep_read_iter(struct kiocb *iocb, struct iov_iter *to) return -EBADMSG; } - buf = kmalloc(len, GFP_KERNEL); + buf = kmalloc(len, GFP_KERNEL | __GFP_NOWARN); if (unlikely(!buf)) { mutex_unlock(&epdata->lock); return -ENOMEM; @@ -677,7 +677,7 @@ ep_write_iter(struct kiocb *iocb, struct iov_iter *from) return -EBADMSG; } - buf = kmalloc(len, GFP_KERNEL); + buf = kmalloc(len, GFP_KERNEL | __GFP_NOWARN); if (unlikely(!buf)) { mutex_unlock(&epdata->lock); return -ENOMEM; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index dc18da8385a2..071a0310d610 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3600,15 +3600,13 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred, static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len, - u32 *trb_buff_len, struct xhci_segment *seg) + u32 *trb_buff_len, struct xhci_segment *seg, u32 max_pkt) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; unsigned int unalign; - unsigned int max_pkt; u32 new_buff_len; size_t len; - max_pkt = xhci_usb_endpoint_maxp(urb->dev, urb->ep); unalign = (enqd_len + *trb_buff_len) % max_pkt; /* we got lucky, last normal TRB data on segment is packet aligned */ @@ -3753,9 +3751,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (enqd_len + trb_buff_len < full_len) { field |= TRB_CHAIN; if (trb_is_link(ring->enqueue + 1)) { - if (xhci_align_td(xhci, urb, enqd_len, - &trb_buff_len, - ring->enq_seg)) { + if (xhci_align_td(xhci, urb, enqd_len, &trb_buff_len, + ring->enq_seg, ring->bounce_buf_len)) { send_addr = ring->enq_seg->bounce_dma; /* TD bounced at least, and last on this seg */ td->bounce_seg = ring->enq_seg; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index a4fab82da76b..b894ba988a3d 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4435,10 +4435,13 @@ 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_and_free_slot(xhci, udev->slot_id); - if (!ret) { - if (xhci_alloc_dev(hcd, udev) == 1) - xhci_setup_addressable_virt_dev(xhci, udev); + + if (!virt_dev->sideband) { + 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); + } } kfree(command->completion); kfree(command); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 0f9a7a4c1f66..2f83e7b866f6 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -2444,6 +2444,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x30) }, /* Compal EXM-G1x */ { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x60) }, + { USB_DEVICE_INTERFACE_CLASS(0x1286, 0x4e3c, 0xff) }, /* ASR modem */ { USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 (IOT version) */ .driver_info = RSVD(4) | RSVD(5) | RSVD(6) }, { USB_DEVICE(0x1782, 0x4d10) }, /* Fibocom L610 (AT mode) */ @@ -2511,6 +2512,10 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(5) }, { USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff), /* Rolling RW135R-GL (laptop MBIM) */ .driver_info = RSVD(5) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x33f8, 0x9300, 0xff, 0xff, 0x30) }, /* Rolling RN947R */ + { USB_DEVICE_AND_INTERFACE_INFO(0x33f8, 0x9300, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x33f8, 0x9300, 0xff, 0xff, 0x10), + .driver_info = ZLP }, { USB_DEVICE_INTERFACE_CLASS(0x3466, 0x3301, 0xff) }, /* TDTECH MT5710-CN */ { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WWD for Global */ { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0x00, 0x40) }, diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 741e68e46139..bac926cfee28 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -972,12 +972,13 @@ static int sierra_submit_delayed_urbs(struct usb_serial_port *port) intfdata->in_flight--; usb_unanchor_urb(urb); kfree(urb->transfer_buffer); - usb_free_urb(urb); spin_lock(&portdata->lock); portdata->outstanding_urbs--; spin_unlock(&portdata->lock); } + + usb_put_urb(urb); } if (ec) diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 0017f6e969e1..67e1820bbbaf 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -402,6 +402,7 @@ void usb_wwan_close(struct usb_serial_port *port) urb = usb_get_from_anchor(&portdata->delayed); if (!urb) break; + usb_put_urb(urb); unbusy_queued_urb(urb, portdata); usb_autopm_put_interface_async(serial->interface); } @@ -579,6 +580,8 @@ static int usb_wwan_submit_delayed_urbs(struct usb_serial_port *port) if (!urb) break; + usb_put_urb(urb); + err = usb_submit_urb(urb, GFP_ATOMIC); if (err) { dev_err(&port->dev, "%s: submit urb failed: %d\n", diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 6c1f62c78ac2..55dbe7508ea7 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -134,6 +134,8 @@ struct version_format { #define NVIDIA_FTB_DP_OFFSET (2) #define NVIDIA_FTB_DBG_OFFSET (3) +#define CCG_READ_MAX_RETRIES 4 + struct version_info { struct version_format base; struct version_format app; @@ -254,6 +256,7 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) }; u32 rlen, rem_len = len, max_read_len = len; int status; + int retry_count; /* check any max_read_len limitation on i2c adapter */ if (quirks && quirks->max_read_len) @@ -265,7 +268,17 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) rlen = min_t(u16, rem_len, max_read_len); msgs[1].len = rlen; put_unaligned_le16(rab, buf); - status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + + for (retry_count = 0; retry_count < CCG_READ_MAX_RETRIES; retry_count++) { + status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + + /* Only retry on -EREMOTEIO, and not after the last attempt */ + if (status != -EREMOTEIO || retry_count == CCG_READ_MAX_RETRIES - 1) + break; + + fsleep(1000); + } + if (status < 0) { dev_err(uc->dev, "i2c_transfer failed %d\n", status); pm_runtime_put_sync(uc->dev); @@ -383,14 +396,28 @@ static int ucsi_ccg_init(struct ucsi_ccg *uc) return -ETIMEDOUT; } -static void ucsi_ccg_update_get_current_cam_cmd(struct ucsi_ccg *uc, u8 *data) +static int ucsi_ccg_update_get_current_cam_cmd(struct ucsi_ccg *uc, u8 *data) { u8 cam, new_cam; cam = data[0]; + if (cam >= UCSI_MAX_ALTMODES) { + dev_err(uc->dev, "PPM returned invalid alternate mode index %u\n", + cam); + return -EPROTO; + } + new_cam = uc->orig[cam].linked_idx; + if (new_cam >= UCSI_MAX_ALTMODES) { + dev_err(uc->dev, "invalid linked alternate mode index %u for %u\n", + new_cam, cam); + return -EPROTO; + } + uc->updated[new_cam].active_idx = cam; data[0] = new_cam; + + return 0; } static bool ucsi_ccg_update_altmodes(struct ucsi *ucsi, @@ -633,8 +660,10 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci, switch (UCSI_COMMAND(command)) { case UCSI_GET_CURRENT_CAM: - if (uc->has_multiple_dp) - ucsi_ccg_update_get_current_cam_cmd(uc, (u8 *)data); + if (!ret && uc->has_multiple_dp && + (*cci & UCSI_CCI_COMMAND_COMPLETE) && + !(*cci & UCSI_CCI_ERROR)) + ret = ucsi_ccg_update_get_current_cam_cmd(uc, (u8 *)data); break; case UCSI_GET_ALTERNATE_MODES: if (UCSI_ALTMODE_RECIPIENT(command) == UCSI_RECIPIENT_SOP) { diff --git a/drivers/vfio/pci/mlx5/cmd.c b/drivers/vfio/pci/mlx5/cmd.c index a92b095b90f6..a870ea1c0e9d 100644 --- a/drivers/vfio/pci/mlx5/cmd.c +++ b/drivers/vfio/pci/mlx5/cmd.c @@ -1627,7 +1627,7 @@ set_report_output(u32 size, int index, struct mlx5_vhca_qp *qp, int i; buf_offset = index * qp->max_msg_size; - if (WARN_ON(buf_offset + size >= qp->recv_buf.npages * PAGE_SIZE || + if (WARN_ON(buf_offset + size > qp->recv_buf.npages * PAGE_SIZE || (nent > qp->max_msg_size / entry_size))) return; diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index 35862e83f7af..2b602ad004dd 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -1009,7 +1009,9 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo) if (ret < 0) goto put_display_node; - fb_add_videomode(&fb_vm, &info->modelist); + ret = fb_add_videomode(&fb_vm, &info->modelist); + if (ret < 0) + goto put_display_node; put_display_node: of_node_put(display_np); @@ -1077,8 +1079,13 @@ static int atmel_lcdfb_probe(struct platform_device *pdev) } atmel_lcdfb_start_clock(sinfo); - modelist = list_first_entry(&info->modelist, - struct fb_modelist, list); + modelist = list_first_entry_or_null(&info->modelist, + struct fb_modelist, list); + if (!modelist) { + dev_err(dev, "no video mode available\n"); + ret = -EINVAL; + goto stop_clk; + } fb_videomode_to_var(&info->var, &modelist->mode); atmel_lcdfb_check_var(&info->var, info); diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c index 8f6a2d1736d3..86ae7a7252d2 100644 --- a/drivers/video/fbdev/core/bitblit.c +++ b/drivers/video/fbdev/core/bitblit.c @@ -18,6 +18,7 @@ #include #include #include "fbcon.h" +#include "fbcon_rotate.h" /* * Accelerated handlers. @@ -151,7 +152,9 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, const unsigned short *s, int count, int yy, int xx, int fg, int bg) { + struct fbcon_par *par = info->fbcon_par; struct fb_image image; + u32 vyres = GETVYRES(par->p, info); u32 width = DIV_ROUND_UP(vc->vc_font.width, 8); u32 cellsize = width * vc->vc_font.height; u32 maxcnt = info->pixmap.size/cellsize; @@ -168,10 +171,10 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, image.height = vc->vc_font.height; image.depth = 1; - if (image.dy >= info->var.yres) + if (image.dy >= vyres) return; - image.height = min(image.height, info->var.yres - image.dy); + image.height = min(image.height, vyres - image.dy); if (attribute) { buf = kmalloc(cellsize, GFP_ATOMIC); diff --git a/drivers/video/fbdev/kyro/fbdev.c b/drivers/video/fbdev/kyro/fbdev.c index c44d6809859e..fc350edb41a8 100644 --- a/drivers/video/fbdev/kyro/fbdev.c +++ b/drivers/video/fbdev/kyro/fbdev.c @@ -766,7 +766,7 @@ static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) fb_memset_io(info->screen_base, 0, size); if (register_framebuffer(info) < 0) - goto out_free_fb; + goto out_free_wc; fb_info(info, "%s frame buffer device, at %dx%d@%d using %ldk/%ldk of VRAM\n", info->fix.id, @@ -777,6 +777,8 @@ static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; +out_free_wc: + arch_phys_wc_del(currentpar->wc_cookie); out_free_fb: framebuffer_release(info); diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c index 6038f217ab42..c6da5a62f8c5 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c @@ -1042,7 +1042,11 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; ch->defio.delay = msecs_to_jiffies(tmp); ch->info->fbdefio = &ch->defio; - fb_deferred_io_init(ch->info); + ret = fb_deferred_io_init(ch->info); + if (ret) { + ch->info->fbdefio = NULL; + return ret; + } } sh_mobile_lcdc_display_on(ch); diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index 891ce7b76d63..30a94d85fc8c 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -1041,10 +1041,13 @@ static int ufx_ops_open(struct fb_info *info, int user) if (fbdefio) { fbdefio->delay = UFX_DEFIO_WRITE_DELAY; fbdefio->deferred_io = ufx_dpy_deferred_io; - } - info->fbdefio = fbdefio; - fb_deferred_io_init(info); + info->fbdefio = fbdefio; + if (fb_deferred_io_init(info)) { + kfree(fbdefio); + info->fbdefio = NULL; + } + } } pr_debug("open /dev/fb%d user=%d fb_info=%p count=%d", diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index 0df3ac694f4e..e4559312a926 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -763,7 +763,11 @@ static int ssd1307fb_probe(struct i2c_client *client) info->fix.smem_start = __pa(vmem); info->fix.smem_len = vmem_size; - fb_deferred_io_init(info); + ret = fb_deferred_io_init(info); + if (ret) { + dev_err(dev, "failed to init fb deferred io: %d\n", ret); + goto fb_defio_error; + } i2c_set_clientdata(client, info); diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index f6da680c29ea..abaac2ed22a9 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -947,10 +947,13 @@ static int dlfb_ops_open(struct fb_info *info, int user) fbdefio->delay = DL_DEFIO_WRITE_DELAY; fbdefio->sort_pagereflist = true; fbdefio->deferred_io = dlfb_dpy_deferred_io; - } - info->fbdefio = fbdefio; - fb_deferred_io_init(info); + info->fbdefio = fbdefio; + if (fb_deferred_io_init(info)) { + kfree(fbdefio); + info->fbdefio = NULL; + } + } } dev_dbg(info->dev, "open, user=%d fb_info=%p count=%d\n", diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c index d8f3bfb2dd6c..22aaafd2c11f 100644 --- a/drivers/video/fbdev/xen-fbfront.c +++ b/drivers/video/fbdev/xen-fbfront.c @@ -443,7 +443,11 @@ static int xenfb_probe(struct xenbus_device *dev, } fb_info->fbdefio = &xenfb_defio; - fb_deferred_io_init(fb_info); + ret = fb_deferred_io_init(fb_info); + if (ret < 0) { + xenbus_dev_fatal(dev, ret, "fb_deferred_io_init"); + goto error_cmap; + } xenfb_init_shared_page(info, fb_info); @@ -465,6 +469,7 @@ static int xenfb_probe(struct xenbus_device *dev, error_fb: fb_deferred_io_cleanup(fb_info); +error_cmap: fb_dealloc_cmap(&fb_info->cmap); framebuffer_release(fb_info); error_nomem: diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 1e21b75114e5..02ebbdba8610 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -1072,6 +1072,13 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) return -EINVAL; + /* + * Private mappings of foreign grant pages must never become + * writable: they would take the COW path on granted pages. + */ + if (!(vma->vm_flags & VM_SHARED)) + vm_flags_clear(vma, VM_MAYWRITE); + pr_debug("map %d+%d at %lx (pgoff %lx)\n", index, count, vma->vm_start, vma->vm_pgoff); diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index f37d8d212c06..fc21473672d4 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -1168,51 +1168,40 @@ static irqreturn_t ioeventfd_interrupt(int irq, void *dev_id) struct privcmd_kernel_ioreq *kioreq = port->kioreq; struct ioreq *ioreq = &kioreq->ioreq[port->vcpu]; struct privcmd_kernel_ioeventfd *kioeventfd; - unsigned int state = STATE_IOREQ_READY; + bool matched = false; - if (ioreq->state != STATE_IOREQ_READY || - ioreq->type != IOREQ_TYPE_COPY || ioreq->dir != IOREQ_WRITE) + if (ioreq->state != STATE_IOREQ_READY) return IRQ_NONE; - /* - * We need a barrier, smp_mb(), here to ensure reads are finished before - * `state` is updated. Since the lock implementation ensures that - * appropriate barrier will be added anyway, we can avoid adding - * explicit barrier here. - * - * Ideally we don't need to update `state` within the locks, but we do - * that here to avoid adding explicit barrier. - */ + /* Xen publishes the request before changing its state to READY. */ + virt_rmb(); - spin_lock(&kioreq->lock); - ioreq->state = STATE_IOREQ_INPROCESS; + if (ioreq->type != IOREQ_TYPE_COPY || ioreq->dir != IOREQ_WRITE) + return IRQ_NONE; + spin_lock(&kioreq->lock); list_for_each_entry(kioeventfd, &kioreq->ioeventfds, list) { if (ioreq->addr == kioeventfd->addr + VIRTIO_MMIO_QUEUE_NOTIFY && ioreq->size == kioeventfd->addr_len && (ioreq->data & QUEUE_NOTIFY_VQ_MASK) == kioeventfd->vq) { + /* Finish reading the request before claiming it. */ + virt_mb(); + ioreq->state = STATE_IOREQ_INPROCESS; eventfd_signal(kioeventfd->eventfd); - state = STATE_IORESP_READY; + matched = true; break; } } spin_unlock(&kioreq->lock); - /* - * We need a barrier, smp_mb(), here to ensure writes are finished - * before `state` is updated. Since the lock implementation ensures that - * appropriate barrier will be added anyway, we can avoid adding - * explicit barrier here. - */ - - ioreq->state = state; - - if (state == STATE_IORESP_READY) { - notify_remote_via_evtchn(port->port); - return IRQ_HANDLED; - } + if (!matched) + return IRQ_NONE; - return IRQ_NONE; + /* Publish the response only after signaling the eventfd. */ + virt_wmb(); + ioreq->state = STATE_IORESP_READY; + notify_remote_via_evtchn(port->port); + return IRQ_HANDLED; } static void ioreq_free(struct privcmd_kernel_ioreq *kioreq) diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index 7de2fa67743c..b128ceeee21b 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c @@ -234,13 +234,16 @@ static int pcistub_get_gsi_from_sbdf(unsigned int sbdf) int bus = PCI_BUS_NUM(sbdf); int slot = PCI_SLOT(sbdf); int func = PCI_FUNC(sbdf); + int gsi; psdev = pcistub_device_find(domain, bus, slot, func); - if (!psdev) return -ENODEV; - return psdev->gsi; + gsi = psdev->gsi; + pcistub_device_put(psdev); + + return gsi; } #endif diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c index 5ba9ef2742f6..f400b28eea28 100644 --- a/fs/affs/bitmap.c +++ b/fs/affs/bitmap.c @@ -46,7 +46,7 @@ affs_free_block(struct super_block *sb, u32 block) pr_debug("%s(%u)\n", __func__, block); - if (block > sbi->s_partition_size) + if (!affs_validblock(sb, block)) goto err_range; blk = block - sbi->s_reserved; diff --git a/fs/aio.c b/fs/aio.c index 5bc133386407..e06fa57b05ca 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -474,7 +474,18 @@ static int aio_migrate_folio(struct address_space *mapping, struct folio *dst, #define aio_migrate_folio NULL #endif +/* + * filemap_fault() reads a folio that it did not find in the page cache. All + * folios of a live ring are there, so the ring was truncated under the fault. + */ +static int aio_read_folio(struct file *file, struct folio *folio) +{ + folio_unlock(folio); + return -EIO; +} + static const struct address_space_operations aio_ctx_aops = { + .read_folio = aio_read_folio, .dirty_folio = noop_dirty_folio, .migrate_folio = aio_migrate_folio, }; @@ -1816,7 +1827,12 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync, list_del_init(&req->wait.entry); list_del(&iocb->ki_list); iocb->ki_res.res = mangle_poll(mask); - if (iocb->ki_eventfd && !eventfd_signal_allowed()) { + /* + * We hold an arbitrary provider waitqueue lock here. Signaling a + * result eventfd can feed back through epoll and try to take the same + * lock again. Defer all eventfd-backed poll completions. + */ + if (iocb->ki_eventfd) { iocb = NULL; INIT_WORK(&req->work, aio_poll_put_work); schedule_work(&req->work); diff --git a/fs/backing-file.c b/fs/backing-file.c index 6f16e23f7046..bf526fa2e29d 100644 --- a/fs/backing-file.c +++ b/fs/backing-file.c @@ -35,13 +35,36 @@ struct file *backing_file_open(const struct file *user_file, int flags, const struct cred *cred) { const struct path *user_path = file_user_path(user_file); + struct inode *real_inode = d_inode(real_path->dentry); struct file *f; int error; + /* + * may_open() checked the inode of the user file, which need not carry + * S_APPEND and S_IMMUTABLE of the backing inode. + */ + if ((flags & O_ACCMODE) != O_RDONLY) { + if (IS_IMMUTABLE(real_inode)) + return ERR_PTR(-EPERM); + if (IS_APPEND(real_inode) && !(flags & O_APPEND)) + return ERR_PTR(-EPERM); + } + f = alloc_empty_backing_file(flags, cred, user_file); if (IS_ERR(f)) return f; + /* + * A user file that must not generate fsnotify events (e.g. the fd + * that fanotify creates for a permission event with + * dentry_open_nonotify()) must not generate them through its backing + * file either. Otherwise a listener watching the backing filesystem + * gets a nested permission event from its own read(2), which only + * another reader of the same group can answer. + */ + if (FMODE_FSNOTIFY_NONE(user_file->f_mode)) + file_set_fsnotify_mode(f, FMODE_NONOTIFY); + path_get(user_path); backing_file_set_user_path(f, user_path); error = vfs_open(real_path, f); @@ -222,6 +245,14 @@ ssize_t backing_file_write_iter(struct file *file, struct iov_iter *iter, if (!iov_iter_count(iter)) return 0; + /* + * F_SETFL and RWF_NOAPPEND can take append mode away from the user + * file. They checked its inode, not the backing one. + */ + if ((file->f_flags & O_APPEND) && !(flags & IOCB_APPEND) && + IS_APPEND(file_inode(file))) + return -EPERM; + ret = file_remove_privs(iocb->ki_filp); if (ret) return ret; @@ -309,6 +340,10 @@ ssize_t backing_file_splice_write(struct pipe_inode_info *pipe, if (!out->f_op->splice_write) return -EINVAL; + /* splice refuses a user file in append mode, so F_SETFL cleared it */ + if ((out->f_flags & O_APPEND) && IS_APPEND(file_inode(out))) + return -EPERM; + ret = file_remove_privs(iocb->ki_filp); if (ret) return ret; @@ -339,6 +374,10 @@ int backing_file_mmap(struct file *file, struct vm_area_struct *vma, if (!can_mmap_file(file)) return -ENODEV; + /* do_mmap() checked the inode of the user file */ + if ((vma->vm_flags & VM_SHARED) && IS_APPEND(file_inode(file))) + return -EACCES; + vma_set_file(vma, file); old_cred = override_creds(ctx->cred); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 62858d8d66bd..6287e15bce11 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8143,7 +8143,6 @@ static int btrfs_getattr(struct mnt_idmap *idmap, struct inode *inode = d_inode(path->dentry); u32 blocksize = btrfs_sb(inode->i_sb)->sectorsize; u32 bi_flags = BTRFS_I(inode)->flags; - u32 bi_ro_flags = BTRFS_I(inode)->ro_flags; stat->result_mask |= STATX_BTIME; stat->btime.tv_sec = BTRFS_I(inode)->i_otime_sec; @@ -8156,8 +8155,6 @@ static int btrfs_getattr(struct mnt_idmap *idmap, stat->attributes |= STATX_ATTR_IMMUTABLE; if (bi_flags & BTRFS_INODE_NODUMP) stat->attributes |= STATX_ATTR_NODUMP; - if (bi_ro_flags & BTRFS_INODE_RO_VERITY) - stat->attributes |= STATX_ATTR_VERITY; stat->attributes_mask |= (STATX_ATTR_APPEND | STATX_ATTR_COMPRESSED | diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 6cc4fe2ccd8a..61a0575fd162 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2284,6 +2284,9 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd, case BTRFS_IOC_GET_SUPPORTED_FEATURES: ret = btrfs_ioctl_get_supported_features((void __user*)arg); break; + default: + ret = -ENOTTY; + break; } out: diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 200b4e4a0799..a07b5a4d6e4d 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -8302,6 +8302,7 @@ static int relocating_repair_kthread(void *data) bool btrfs_repair_one_zone(struct btrfs_fs_info *fs_info, u64 logical) { struct btrfs_block_group *cache; + struct task_struct *task; if (!btrfs_is_zoned(fs_info)) return false; @@ -8319,8 +8320,9 @@ bool btrfs_repair_one_zone(struct btrfs_fs_info *fs_info, u64 logical) return true; } - kthread_run(relocating_repair_kthread, cache, - "btrfs-relocating-repair"); + task = kthread_run(relocating_repair_kthread, cache, "btrfs-relocating-repair"); + if (IS_ERR(task)) + btrfs_put_block_group(cache); return true; } diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index cfbd88412f04..51aeae341f56 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -314,6 +314,12 @@ static bool ceph_netfs_issue_op_inline(struct netfs_io_subrequest *subreq) return false; } + if (subreq->start >= iinfo->inline_len) { + ceph_mdsc_put_request(req); + err = -ENODATA; + goto out; + } + len = min_t(size_t, iinfo->inline_len - subreq->start, subreq->len); err = copy_to_iter(iinfo->inline_data + subreq->start, len, &subreq->io_iter); if (err == 0) { @@ -356,7 +362,7 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq) struct ceph_client *cl = fsc->client; struct ceph_osd_request *req = NULL; struct ceph_vino vino = ceph_vino(inode); - int err; + int err = 0; u64 len; bool sparse = IS_ENCRYPTED(inode) || ceph_test_mount_opt(fsc, SPARSEREAD); u64 off = subreq->start; @@ -1883,7 +1889,12 @@ static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned r = wait_event_killable(ci->i_cap_wq, context_is_writeable_or_written(inode, snapc)); ceph_put_snap_context(snapc); - return r == 0 ? -EAGAIN : r; + /* + * *foliop is cleared, so a return of 0 makes + * netfs_write_begin() grab the folio again and call us again + * to recheck it. Any error (fatal signal) fails the write. + */ + return r; } return 0; } diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 91cb305815cb..3dfd230412cc 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1561,6 +1561,8 @@ static void __send_cap(struct cap_msg_args *arg, struct ceph_inode_info *ci) spin_lock(&ci->i_ceph_lock); __cap_delay_requeue(arg->session->s_mdsc, ci); spin_unlock(&ci->i_ceph_lock); + ceph_buffer_put(arg->old_xattr_buf); + ceph_buffer_put(arg->xattr_buf); return; } @@ -2878,6 +2880,10 @@ static int try_get_cap_refs(struct inode *inode, int need, int want, } /* finish pending truncate */ + if (ci->i_truncate_pending && (flags & NON_BLOCKING)) { + ret = -EAGAIN; + goto out_unlock; + } while (ci->i_truncate_pending) { spin_unlock(&ci->i_ceph_lock); if (snap_rwsem_locked) { diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c index a236035f3a7a..f23ba5c14878 100644 --- a/fs/ceph/crypto.c +++ b/fs/ceph/crypto.c @@ -83,6 +83,9 @@ static int ceph_crypt_get_context(struct inode *inode, void *ctx, size_t len) return -ENOBUFS; ctxlen = le32_to_cpu(cfa->cfa_blob_len); + if (ctxlen > ci->fscrypt_auth_len - + offsetof(struct ceph_fscrypt_auth, cfa_blob)) + return -ENOBUFS; if (len < ctxlen) return -ERANGE; diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 342d8778b69c..0220daac0fba 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "super.h" #include "mds_client.h" @@ -104,6 +105,7 @@ static int parse_reply_info_in(void **p, void *end, u64 features) { int err = 0; + size_t splits_len; u8 struct_v = 0; if (features == (u64)-1) { @@ -122,9 +124,11 @@ static int parse_reply_info_in(void **p, void *end, ceph_decode_need(p, end, sizeof(struct ceph_mds_reply_inode), bad); info->in = *p; - *p += sizeof(struct ceph_mds_reply_inode) + - sizeof(*info->in->fragtree.splits) * - le32_to_cpu(info->in->fragtree.nsplits); + splits_len = size_mul(sizeof(*info->in->fragtree.splits), + le32_to_cpu(info->in->fragtree.nsplits)); + *p += sizeof(struct ceph_mds_reply_inode); + ceph_decode_need(p, end, splits_len, bad); + *p += splits_len; ceph_decode_32_safe(p, end, info->symlink_len, bad); ceph_decode_need(p, end, info->symlink_len, bad); @@ -338,6 +342,8 @@ static int parse_reply_info_lease(void **p, void *end, lend = *p + struct_len; ceph_decode_need(p, end, struct_len, bad); + if (struct_len < sizeof(**lease)) + goto bad; *lease = *p; *p += sizeof(**lease); @@ -434,10 +440,8 @@ static int parse_reply_info_readdir(void **p, void *end, goto done; BUG_ON(!info->dir_entries); - if ((unsigned long)(info->dir_entries + num) > - (unsigned long)info->dir_entries + info->dir_buf_size) { + if (num > info->dir_buf_size / sizeof(*info->dir_entries)) { pr_err_client(cl, "dir contents are larger than expected\n"); - WARN_ON(1); goto bad; } @@ -1756,8 +1760,10 @@ __open_export_target_session(struct ceph_mds_client *mdsc, int target) if (session->s_state == CEPH_MDS_SESSION_NEW || session->s_state == CEPH_MDS_SESSION_CLOSING) { ret = __open_session(mdsc, session); - if (ret) + if (ret) { + ceph_put_mds_session(session); return ERR_PTR(ret); + } } return session; @@ -3812,6 +3818,14 @@ int ceph_mdsc_wait_request(struct ceph_mds_client *mdsc, /* only abort if we didn't race with a real reply */ if (test_bit(CEPH_MDS_R_GOT_RESULT, &req->r_req_flags)) { err = le32_to_cpu(req->r_reply_info.head->result); + if (err > 0 || err < -MAX_ERRNO) { + /* + * The result is server-controlled. Values outside + * the errno range are turned into bogus pointers by + * the ERR_PTR() users among the callers. + */ + err = -EIO; + } } else if (err < 0) { doutc(cl, "aborted request %lld with %d\n", req->r_tid, err); diff --git a/fs/ceph/mdsmap.c b/fs/ceph/mdsmap.c index c91c0e2e118b..d377d13f854d 100644 --- a/fs/ceph/mdsmap.c +++ b/fs/ceph/mdsmap.c @@ -170,6 +170,10 @@ struct ceph_mdsmap *ceph_mdsmap_decode(struct ceph_mds_client *mdsc, void **p, * and the mds rank >= m_num_active_mds. */ m->possible_max_rank = max(m->m_num_active_mds, m->m_max_mds); + if (m->possible_max_rank > CEPH_MAX_MDS) { + err = -EIO; + goto corrupt; + } m->m_info = kcalloc(m->possible_max_rank, sizeof(*m->m_info), GFP_NOFS); if (!m->m_info) @@ -205,7 +209,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(struct ceph_mds_client *mdsc, void **p, ceph_decode_need(p, end, sizeof(u64) + sizeof(u32), bad); *p += sizeof(u64); namelen = ceph_decode_32(p); /* skip mds name */ - *p += namelen; + ceph_decode_skip_n(p, end, namelen, bad); ceph_decode_32_safe(p, end, mds, bad); ceph_decode_32_safe(p, end, inc, bad); @@ -223,7 +227,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(struct ceph_mds_client *mdsc, void **p, laggy = laggy_since.tv_sec != 0 || laggy_since.tv_nsec != 0; *p += sizeof(u32); ceph_decode_32_safe(p, end, namelen, bad); - *p += namelen; + ceph_decode_skip_n(p, end, namelen, bad); if (info_v >= 2) { ceph_decode_32_safe(p, end, num_export_targets, bad); export_targets_len = size_mul(num_export_targets, @@ -316,6 +320,10 @@ struct ceph_mdsmap *ceph_mdsmap_decode(struct ceph_mds_client *mdsc, void **p, { int num_laggy = 0; ceph_decode_32_safe(p, end, n, bad_ext); + if (n > CEPH_MAX_MDS) { + err = -EIO; + goto corrupt; + } ceph_decode_need(p, end, sizeof(u32) * n, bad_ext); for (i = 0; i < n; i++) { diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index c65f2b202b2b..00cfcef5fbb2 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -788,6 +788,7 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc, struct ceph_snap_realm *first_realm = NULL; struct ceph_snap_realm *realm_to_rebuild = NULL; struct ceph_client *client = mdsc->fsc->client; + size_t snaps_len; int rebuild_snapcs; int err = -ENOMEM; int ret; @@ -802,8 +803,10 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc, ceph_decode_need(&p, e, sizeof(*ri), bad); ri = p; p += sizeof(*ri); - ceph_decode_need(&p, e, sizeof(u64)*(le32_to_cpu(ri->num_snaps) + - le32_to_cpu(ri->num_prior_parent_snaps)), bad); + snaps_len = size_mul(size_add(le32_to_cpu(ri->num_snaps), + le32_to_cpu(ri->num_prior_parent_snaps)), + sizeof(u64)); + ceph_decode_need(&p, e, snaps_len, bad); snaps = p; p += sizeof(u64) * le32_to_cpu(ri->num_snaps); prior_parent_snaps = p; diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index cc73b0874ce4..90a9e7de8fea 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -11,6 +11,7 @@ #include #include #include +#include #define XATTR_CEPH_PREFIX "ceph." #define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1) @@ -845,14 +846,23 @@ static int __build_xattrs(struct inode *inode) } err = -EIO; while (numattr--) { + int names_size, vals_size; + ceph_decode_32_safe(&p, end, len, bad); namelen = len; name = p; + ceph_decode_need(&p, end, namelen, bad); p += len; ceph_decode_32_safe(&p, end, len, bad); ceph_decode_need(&p, end, len, bad); val = p; p += len; + if (namelen > INT_MAX || len > INT_MAX || + check_add_overflow(ci->i_xattrs.names_size, + (int)namelen, &names_size) || + check_add_overflow(ci->i_xattrs.vals_size, + (int)len, &vals_size)) + goto bad; err = __set_xattr(ci, name, namelen, val, len, 0, 0, &xattrs[numattr]); diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index f27997ef9a08..707552228ed6 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -207,8 +207,14 @@ fscrypt_find_mode_key(struct fscrypt_master_key *mk, u8 hkdf_context, if (node->hkdf_context == hkdf_context && node->mode_num == mode_num && node->data_unit_bits == ci->ci_data_unit_bits && - fscrypt_is_key_prepared(&node->key, ci)) + fscrypt_is_key_prepared(&node->key, ci)) { + /* + * Upgrade the RCU dereference to a full ACQUIRE, so + * that blk-crypto global state is seen as initialized. + */ + smp_acquire__after_ctrl_dep(); return &node->key; + } } return NULL; } diff --git a/fs/dax.c b/fs/dax.c index 69ac2562cec3..30d0c7e4b30c 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -2168,6 +2168,7 @@ static int dax_range_compare_iter(struct iomap_iter *it_src, loff_t pos1 = it_src->pos, pos2 = it_dest->pos; u64 dest_len; void *saddr, *daddr; + size_t size1, size2; int id, ret; len = min(len, min(smap->length, dmap->length)); @@ -2183,17 +2184,18 @@ static int dax_range_compare_iter(struct iomap_iter *it_src, } id = dax_read_lock(); - ret = dax_iomap_direct_access(smap, pos1, ALIGN(pos1 + len, PAGE_SIZE), - &saddr, NULL); + size1 = ALIGN(len + offset_in_page(pos1), PAGE_SIZE); + ret = dax_iomap_direct_access(smap, pos1, size1, &saddr, NULL); if (ret < 0) goto out_unlock; - ret = dax_iomap_direct_access(dmap, pos2, ALIGN(pos2 + len, PAGE_SIZE), - &daddr, NULL); + size2 = ALIGN(len + offset_in_page(pos2), PAGE_SIZE); + ret = dax_iomap_direct_access(dmap, pos2, size2, &daddr, NULL); if (ret < 0) goto out_unlock; - *same = !memcmp(saddr, daddr, len); + *same = !memcmp(saddr + offset_in_page(pos1), + daddr + offset_in_page(pos2), len); if (!*same) len = 0; dax_read_unlock(id); @@ -2233,7 +2235,7 @@ int dax_dedupe_file_range_compare(struct inode *src, loff_t srcoff, status = dax_range_compare_iter(&src_iter, &dst_iter, min(src_iter.len, dst_iter.len), same); if (status < 0) - return ret; + return status; src_iter.status = dst_iter.status = status; } return ret; diff --git a/fs/dcache.c b/fs/dcache.c index 5ee1c3d592c8..3ad74a3abf9a 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -442,6 +442,16 @@ static void dentry_free(struct dentry *dentry) call_rcu(&dentry->d_u.d_rcu, __d_free); } +/* + * When inode is unlinked and doesn't have any aliases (i.e., all fds pointing + * to it are closed) we report FS_DELETE_SELF to fsnotify and cleanup all inode + * marks. + */ +static bool inode_notify_dead(struct inode *inode) +{ + return !inode->i_nlink && hlist_empty(&inode->i_dentry); +} + /* * Release the dentry's inode, using the filesystem * d_iput() operation if defined. @@ -451,14 +461,16 @@ static void dentry_unlink_inode(struct dentry * dentry) __releases(dentry->d_inode->i_lock) { struct inode *inode = dentry->d_inode; + bool notify_dead; raw_write_seqcount_begin(&dentry->d_seq); __d_clear_type_and_inode(dentry); hlist_del_init(&dentry->d_u.d_alias); raw_write_seqcount_end(&dentry->d_seq); + notify_dead = inode_notify_dead(inode); spin_unlock(&dentry->d_lock); spin_unlock(&inode->i_lock); - if (!inode->i_nlink) + if (notify_dead) fsnotify_inoderemove(inode); if (dentry->d_op && dentry->d_op->d_iput) dentry->d_op->d_iput(dentry, inode); @@ -673,7 +685,7 @@ static struct dentry *__dentry_kill(struct dentry *dentry) if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); - cond_resched(); + cond_resched_tasks_rcu_qs(); /* now that it's negative, ->d_parent is stable */ if (!IS_ROOT(dentry)) { parent = dentry->d_parent; diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 9a0b6c2b6b01..dd68198f34dd 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -520,10 +520,8 @@ static void lowcomms_write_space(struct sock *sk) clear_bit(SOCK_NOSPACE, &con->sock->flags); spin_lock_bh(&con->writequeue_lock); - if (test_and_clear_bit(CF_APP_LIMITED, &con->flags)) { + if (test_and_clear_bit(CF_APP_LIMITED, &con->flags)) con->sock->sk->sk_write_pending--; - clear_bit(SOCKWQ_ASYNC_NOSPACE, &con->sock->flags); - } lowcomms_queue_swork(con); spin_unlock_bh(&con->writequeue_lock); @@ -1389,7 +1387,7 @@ static int send_to_sock(struct connection *con) if (ret == -EAGAIN || ret == 0) { lock_sock(con->sock->sk); spin_lock_bh(&con->writequeue_lock); - if (test_bit(SOCKWQ_ASYNC_NOSPACE, &con->sock->flags) && + if (test_bit(SOCK_NOSPACE, &con->sock->flags) && !test_and_set_bit(CF_APP_LIMITED, &con->flags)) { /* Notify TCP that we're limited by the * application window size. diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c index 48a0c84cec75..858fe65ba84d 100644 --- a/fs/erofs/decompressor.c +++ b/fs/erofs/decompressor.c @@ -23,7 +23,7 @@ static int z_erofs_load_lz4_config(struct super_block *sb, if (!sbi->lz4.max_pclusterblks) { sbi->lz4.max_pclusterblks = 1; /* reserved case */ } else if (sbi->lz4.max_pclusterblks > - erofs_blknr(sb, Z_EROFS_PCLUSTER_MAX_SIZE)) { + Z_EROFS_PCLUSTER_MAX_SIZE >> sbi->blkszbits) { erofs_err(sb, "too large lz4 pclusterblks %u", sbi->lz4.max_pclusterblks); return -EINVAL; diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index d3e55de4a2a2..ab470783e798 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -336,7 +336,11 @@ static int get_name(const struct path *path, char *name, struct dentry *child) } out_close: - fput(file); + /* + * @file is the read-only directory opened above, so __fput() + * cannot block on anything the caller holds. + */ + __fput_sync(file); out: return error; } diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 08556dd45760..b7d59eec7b3f 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -329,7 +329,7 @@ struct ext4_group_info *ext4_get_group_info(struct super_block *sb, struct ext4_group_info **grp_info; long indexv, indexh; - if (unlikely(group >= EXT4_SB(sb)->s_groups_count)) + if (unlikely(group >= ext4_get_groups_count(sb))) return NULL; if (unlikely(!EXT4_SB(sb)->s_group_info)) return NULL; diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index ed546c52ebc3..9c67a2c28faf 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -3809,6 +3809,9 @@ extern void ext4_ext_tree_init(handle_t *handle, struct inode *inode); extern int ext4_ext_index_trans_blocks(struct inode *inode, int extents); extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, struct ext4_map_blocks *map, int flags); +ext4_lblk_t ext4_determine_insert_hole(struct inode *inode, ext4_lblk_t lblk, + ext4_lblk_t hole_start, + ext4_lblk_t hole_len); extern int ext4_ext_truncate(handle_t *, struct inode *); extern int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, ext4_lblk_t end); diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 21fba12520a8..80d41be51564 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4160,21 +4160,19 @@ static int get_implied_cluster_alloc(struct super_block *sb, } /* - * Determine hole length around the given logical block, first try to - * locate and expand the hole from the given @path, and then adjust it - * if it's partially or completely converted to delayed extents, insert - * it into the extent cache tree if it's indeed a hole, finally return - * the length of the determined extent. + * Adjust the hole [@hole_start, @hole_start + @hole_len) the caller found + * around the queried block @lblk if it's partially or completely converted + * to delayed extents, insert it into the extent cache tree if it's indeed a + * hole, finally return the length of the determined extent starting at + * @lblk. @hole_start must not be behind @lblk. */ -static ext4_lblk_t ext4_ext_determine_insert_hole(struct inode *inode, - struct ext4_ext_path *path, - ext4_lblk_t lblk) +ext4_lblk_t ext4_determine_insert_hole(struct inode *inode, ext4_lblk_t lblk, + ext4_lblk_t hole_start, + ext4_lblk_t hole_len) { - ext4_lblk_t hole_start, len; + ext4_lblk_t len = hole_len; struct extent_status es; - hole_start = lblk; - len = ext4_ext_find_hole(inode, path, &hole_start); again: ext4_es_find_extent_range(inode, &ext4_es_is_delayed, hole_start, hole_start + len - 1, &es); @@ -4342,9 +4340,11 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, * we couldn't try to create block if flags doesn't contain EXT4_GET_BLOCKS_CREATE */ if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { - ext4_lblk_t len; + ext4_lblk_t hole_start = map->m_lblk, len; - len = ext4_ext_determine_insert_hole(inode, path, map->m_lblk); + len = ext4_ext_find_hole(inode, path, &hole_start); + len = ext4_determine_insert_hole(inode, map->m_lblk, + hole_start, len); map->m_pblk = 0; map->m_len = min_t(unsigned int, map->m_len, len); diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index da76353b3a57..50c567123b42 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c @@ -586,6 +586,23 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, for (i = partial - chain + 1; i < depth; i++) count = count * epb + (epb - offsets[i] - 1); count++; + + /* + * The count knows nothing about delayed allocation, so let + * the common helper reconcile it with the extent status + * tree. Only when the lookup really did find a hole: + * ext4_get_branch() also returns a non-NULL partial when it + * failed, and caching a hole for a range it could not read + * would answer every later read from that cache instead of + * retrying. Clamp the count first, a subtree can be bigger + * than the logical block space when the block size is large. + */ + if (!err) { + count = umin(count, EXT_MAX_BLOCKS - map->m_lblk); + count = ext4_determine_insert_hole(inode, map->m_lblk, + map->m_lblk, count); + } + /* Fill in size of a hole we found */ map->m_pblk = 0; map->m_len = umin(map->m_len, count); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index c3fb5f16f6e3..47ce682ae17f 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -6216,15 +6216,12 @@ int ext4_getattr(struct mnt_idmap *idmap, const struct path *path, stat->attributes |= STATX_ATTR_IMMUTABLE; if (flags & EXT4_NODUMP_FL) stat->attributes |= STATX_ATTR_NODUMP; - if (flags & EXT4_VERITY_FL) - stat->attributes |= STATX_ATTR_VERITY; stat->attributes_mask |= (STATX_ATTR_APPEND | STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED | STATX_ATTR_IMMUTABLE | - STATX_ATTR_NODUMP | - STATX_ATTR_VERITY); + STATX_ATTR_NODUMP); generic_fillattr(idmap, request_mask, inode, stat); return 0; @@ -6482,8 +6479,14 @@ static int ext4_try_to_expand_extra_isize(struct inode *inode, * When !SB_ACTIVE, iput triggers write_inode_now() which acquires * s_writepages_rwsem, causing a deadlock with the caller's active * jbd2 handle (lock order: s_writepages_rwsem -> jbd2_handle). + * + * Skip it while unmounting as well. shrink_dcache_for_umount() + * clears s_root before generic_shutdown_super() clears SB_ACTIVE, and + * the last iput() of a lazytime inode in that window redirties it and + * lands here. Moving xattrs out to a block then needs a new EA inode, + * which ext4_xattr_inode_create() refuses without s_root. */ - if (unlikely(!(inode->i_sb->s_flags & SB_ACTIVE))) + if (unlikely(!(inode->i_sb->s_flags & SB_ACTIVE) || !inode->i_sb->s_root)) return -EBUSY; /* diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 9aec4ee780a7..cc85786be270 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -1360,7 +1360,8 @@ static void ext4_sb_setparams(struct ext4_sb_info *sbi, es->s_encoding = cpu_to_le16(params->encoding); if (params->set_flags & EXT4_TUNE_FL_ENCODING_FLAGS) es->s_encoding_flags = cpu_to_le16(params->encoding_flags); - strscpy_pad(es->s_mount_opts, params->mount_opts); + if (params->set_flags & EXT4_TUNE_FL_MOUNT_OPTS) + strscpy_pad(es->s_mount_opts, params->mount_opts); if (params->set_flags & EXT4_TUNE_FL_EDIT_FEATURES) { es->s_feature_compat |= cpu_to_le32(params->set_feature_compat_mask); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 2c661155158f..49bd70aab225 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -3204,19 +3204,20 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry) ext4_fc_track_unlink(handle, dentry); retval = ext4_mark_inode_dirty(handle, dir); +end_rmdir: + brelse(bh); + if (handle) + ext4_journal_stop(handle); + /* VFS negative dentries are incompatible with Encoding and * Case-insensitiveness. Eventually we'll want avoid * invalidating the dentries here, alongside with returning the * negative dentries at ext4_lookup(), when it is better * supported by the VFS for the CI case. */ - if (IS_ENABLED(CONFIG_UNICODE) && IS_CASEFOLDED(dir)) + if (!retval && IS_ENABLED(CONFIG_UNICODE) && IS_CASEFOLDED(dir)) d_invalidate(dentry); -end_rmdir: - brelse(bh); - if (handle) - ext4_journal_stop(handle); return retval; } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index b4ff7e692986..613b04b64b14 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2783,6 +2783,14 @@ static int ext4_check_opt_consistency(struct fs_context *fc, } if (is_remount) { + if (test_opt(sb, DELALLOC) && + (ctx->mask_s_mount_opt & EXT4_MOUNT_DELALLOC) && + !ctx_test_mount_opt(ctx, EXT4_MOUNT_DELALLOC)) { + ext4_msg(sb, KERN_ERR, + "can't disable delalloc during remount"); + return -EINVAL; + } + if (!sbi->s_journal && ctx_test_mount_opt(ctx, EXT4_MOUNT_DATA_ERR_ABORT)) { ext4_msg(NULL, KERN_WARNING, @@ -6016,6 +6024,7 @@ static int ext4_load_journal(struct super_block *sb, int err = 0; int really_read_only; int journal_dev_ro; + bool enable_write = false; if (WARN_ON_ONCE(!ext4_has_feature_journal(sb))) return -EFSCORRUPTED; @@ -6072,6 +6081,7 @@ static int ext4_load_journal(struct super_block *sb, } ext4_msg(sb, KERN_INFO, "write access will " "be enabled during recovery"); + enable_write = true; } } @@ -6088,7 +6098,19 @@ static int ext4_load_journal(struct super_block *sb, if (save) memcpy(save, ((char *) es) + EXT4_S_ERR_START, EXT4_S_ERR_LEN); + /* + * Fast commit replay performs regular ext4 metadata updates + * (see ext4_fc_replay()) which refuse to run on a read-only + * superblock. We promised write access above, so make that + * true for the duration of the recovery, the same way + * ext4_orphan_cleanup() does. The superblock is not published + * yet, so nothing can observe the transient state. + */ + if (enable_write) + sb->s_flags &= ~SB_RDONLY; err = jbd2_journal_load(journal); + if (enable_write) + sb->s_flags |= SB_RDONLY; if (save && memcmp(((char *) es) + EXT4_S_ERR_START, save, EXT4_S_ERR_LEN)) { memcpy(((char *) es) + EXT4_S_ERR_START, @@ -6581,13 +6603,6 @@ static int __ext4_remount(struct fs_context *fc, struct super_block *sb) goto restore_opts; } - if ((old_opts.s_mount_opt & EXT4_MOUNT_DELALLOC) && - !test_opt(sb, DELALLOC)) { - ext4_msg(sb, KERN_ERR, "can't disable delalloc during remount"); - err = -EINVAL; - goto restore_opts; - } - sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | (test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0); diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index 0399db98fccf..8fea48dc50ba 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -1219,6 +1219,7 @@ int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock) int i; int err; +repeat: err = f2fs_is_compressed_cluster(inode, start_idx); if (err < 0) return err; @@ -1230,12 +1231,11 @@ int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock) /* truncate compressed cluster */ err = f2fs_prepare_compress_overwrite(inode, &pagep, start_idx, &fsdata); - - /* should not be a normal cluster */ - f2fs_bug_on(F2FS_I_SB(inode), err == 0); - - if (err <= 0) + if (err < 0) return err; + else if (err == 0) + /* the cluster became non-compressed one due to race case */ + goto repeat; rpages = fsdata; diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 3455565b8245..eba1e025b9d6 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -2186,7 +2186,6 @@ static int f2fs_read_single_page(struct inode *inode, struct folio *folio, got_it: if ((map->m_flags & F2FS_MAP_MAPPED)) { block_nr = map->m_pblk + block_in_file - map->m_lblk; - folio_set_mappedtodisk(folio); if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), block_nr, DATA_GENERIC_ENHANCE_READ)) { @@ -2675,10 +2674,12 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio) return true; if (f2fs_used_in_atomic_write(inode)) return true; - /* rewrite low ratio compress data w/ OPU mode to avoid fragmentation */ - if (f2fs_compressed_file(inode) && - F2FS_OPTION(sbi).compress_mode == COMPR_MODE_USER && - is_inode_flag_set(inode, FI_ENABLE_COMPRESS)) + /* + * rewrite low ratio compress data w/ OPU mode to avoid fragmentation. + * If IO comes from compressed write path and fallback to raw write, + * force out‑place to prevent metadata‑data inconsistency. + */ + if (fio && f2fs_compressed_file(inode)) return true; /* swap file is migrating in aligned write mode */ diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 791f1cf198c1..8211ee75fb8f 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -123,6 +123,7 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct dnode_of_data dn; bool need_alloc = !f2fs_is_pinned_file(inode); + loff_t isize; int err = 0; vm_fault_t ret; @@ -176,9 +177,26 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) file_update_time(vmf->vma->vm_file); filemap_invalidate_lock_shared(inode->i_mapping); + /* + * mmap stores bypass the COW inode and would break atomicity. Check + * under invalidate_lock: f2fs_ioc_start_atomic_write() holds it while + * flushing dirty folios and setting FI_ATOMIC_FILE, so either it sees + * our dirty folio and writes it back, or we see the flag. + */ + if (unlikely(f2fs_is_atomic_file(inode))) { + err = -EOPNOTSUPP; + goto out_sem; + } + folio_lock(folio); + /* + * A concurrent buffered write can extend isize, so we store isize in a + * local variable to let the zeroing offset match the EOF check below. + */ + isize = i_size_read(inode); + if (unlikely(folio->mapping != inode->i_mapping || - folio_pos(folio) > i_size_read(inode) || + folio_pos(folio) > isize || !folio_test_uptodate(folio))) { folio_unlock(folio); err = -EFAULT; @@ -207,18 +225,11 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) /* wait for GCed page writeback via META_MAPPING */ f2fs_wait_on_block_writeback(inode, dn.data_blkaddr); - /* - * check to see if the page is mapped already (no holes) - */ - if (folio_test_mappedtodisk(folio)) - goto out_sem; - /* page is wholly or partially inside EOF */ - if (((loff_t)(folio->index + 1) << PAGE_SHIFT) > - i_size_read(inode)) { + if (((loff_t)(folio->index + 1) << PAGE_SHIFT) > isize) { loff_t offset; - offset = i_size_read(inode) & ~PAGE_MASK; + offset = isize & ~PAGE_MASK; folio_zero_segment(folio, offset, folio_size(folio)); } folio_mark_dirty(folio); @@ -1058,15 +1069,12 @@ int f2fs_getattr(struct mnt_idmap *idmap, const struct path *path, stat->attributes |= STATX_ATTR_IMMUTABLE; if (flags & F2FS_NODUMP_FL) stat->attributes |= STATX_ATTR_NODUMP; - if (IS_VERITY(inode)) - stat->attributes |= STATX_ATTR_VERITY; stat->attributes_mask |= (STATX_ATTR_COMPRESSED | STATX_ATTR_APPEND | STATX_ATTR_ENCRYPTED | STATX_ATTR_IMMUTABLE | - STATX_ATTR_NODUMP | - STATX_ATTR_VERITY); + STATX_ATTR_NODUMP); generic_fillattr(idmap, request_mask, inode, stat); @@ -2084,9 +2092,11 @@ static long f2fs_fallocate(struct file *file, int mode, /* * Pinned file should not support partial truncation since the block - * can be used by applications. + * can be used by applications. Atomic files should not either, since + * these modify the original inode directly and break atomicity. */ - if ((f2fs_compressed_file(inode) || f2fs_is_pinned_file(inode)) && + if ((f2fs_compressed_file(inode) || f2fs_is_pinned_file(inode) || + f2fs_is_atomic_file(inode)) && (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE))) { ret = -EOPNOTSUPP; @@ -2371,6 +2381,8 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate) f2fs_down_write(&fi->i_gc_rwsem[WRITE]); f2fs_down_write(&fi->i_gc_rwsem[READ]); + /* serialize with f2fs_vm_page_mkwrite(), see the comment there */ + filemap_invalidate_lock(inode->i_mapping); /* * Should wait end_io to count F2FS_WB_CP_DATA correctly by @@ -2426,6 +2438,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate) f2fs_i_size_write(fi->cow_inode, isize); out_unlock: + filemap_invalidate_unlock(inode->i_mapping); f2fs_up_write(&fi->i_gc_rwsem[READ]); f2fs_up_write(&fi->i_gc_rwsem[WRITE]); if (ret) @@ -2991,8 +3004,8 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, /* writeback all dirty pages in the range */ err = filemap_write_and_wait_range(inode->i_mapping, - pg_start << PAGE_SHIFT, - (pg_end << PAGE_SHIFT) - 1); + (loff_t)pg_start << PAGE_SHIFT, + ((loff_t)pg_end << PAGE_SHIFT) - 1); if (err) goto out; diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 510d073f8ec5..46f14f891843 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -4087,6 +4087,7 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio) else err = f2fs_submit_page_bio(fio); if (!err) { + fio->submitted = 1; f2fs_update_device_state(fio->sbi, fio->ino, fio->new_blkaddr, 1); f2fs_update_iostat(fio->sbi, fio_inode(fio), @@ -4687,7 +4688,7 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) down_write(&sit_i->sentry_lock); - if (!sit_i->dirty_sentries) + if (!sit_i->dirty_sentries && to_journal) goto out; /* diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 74b12c1ef821..69d36e1a301b 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -3171,15 +3171,42 @@ static qsize_t *f2fs_get_reserved_space(struct inode *inode) return &F2FS_I(inode)->i_reserved_quota; } +/* + * Quota files only grow and there are at most MAXQUOTAS of them, so there is + * no point in keeping them inline. Writeback of quota files does not handle + * inline data and would drop what was written to them. + */ +static int f2fs_quota_convert_inline(struct inode *inode) +{ + int err; + + if (!f2fs_has_inline_data(inode)) + return 0; + + inode_lock(inode); + err = f2fs_convert_inline_inode(inode); + inode_unlock(inode); + return err; +} + static int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type) { + int err; + if (is_set_ckpt_flags(sbi, CP_QUOTA_NEED_FSCK_FLAG)) { f2fs_err(sbi, "quota sysfile may be corrupted, skip loading it"); return 0; } - return dquot_quota_on_mount(sbi->sb, F2FS_OPTION(sbi).s_qf_names[type], + err = dquot_quota_on_mount(sbi->sb, F2FS_OPTION(sbi).s_qf_names[type], F2FS_OPTION(sbi).s_jquota_fmt, type); + if (err) + return err; + + err = f2fs_quota_convert_inline(sb_dqopt(sbi->sb)->files[type]); + if (err) + dquot_quota_off(sbi->sb, type); + return err; } int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly) @@ -3391,6 +3418,10 @@ static int f2fs_quota_on(struct super_block *sb, int type, int format_id, inode = d_inode(path->dentry); + err = f2fs_quota_convert_inline(inode); + if (err) + goto out; + err = filemap_fdatawrite(inode->i_mapping); if (err) goto out; @@ -3889,6 +3920,12 @@ static inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi, /* fix in-memory information all the time */ raw_super->segment_count = cpu_to_le32((main_end_blkaddr - segment0_blkaddr) >> log_blocks_per_seg); + if (__F2FS_HAS_FEATURE(raw_super, F2FS_FEATURE_SB_CHKSUM)) { + __u32 crc = f2fs_crc32(raw_super, + offsetof(struct f2fs_super_block, crc)); + + raw_super->crc = cpu_to_le32(crc); + } if (f2fs_readonly(sb) || f2fs_hw_is_readonly(sbi)) { set_sbi_flag(sbi, SBI_NEED_SB_WRITE); @@ -4149,7 +4186,7 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) return 1; if (f2fs_sb_has_readonly(sbi)) - goto check_data; + continue; for (j = i + 1; j < NR_CURSEG_NODE_TYPE; j++) { if (le32_to_cpu(ckpt->cur_node_segno[i]) == @@ -4161,14 +4198,14 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) } } } -check_data: + for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) { if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs || le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg) return 1; if (f2fs_sb_has_readonly(sbi)) - goto skip_cross; + continue; for (j = i + 1; j < NR_CURSEG_DATA_TYPE; j++) { if (le32_to_cpu(ckpt->cur_data_segno[i]) == @@ -4180,6 +4217,9 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) } } } + if (f2fs_sb_has_readonly(sbi)) + goto skip_cross; + for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { for (j = 0; j < NR_CURSEG_DATA_TYPE; j++) { if (le32_to_cpu(ckpt->cur_node_segno[i]) == diff --git a/fs/fat/fat.h b/fs/fat/fat.h index d3e426de5f01..6748dea6cd21 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -389,7 +389,7 @@ extern void fat_ent_access_init(struct super_block *sb); extern int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry); extern int fat_ent_write(struct inode *inode, struct fat_entry *fatent, - int new, int wait); + int new, int old, int wait); extern int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster); extern int fat_free_clusters(struct inode *inode, int cluster); diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index a7061c2ad8e4..515bc0cfc64f 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -408,7 +408,7 @@ static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs, } int fat_ent_write(struct inode *inode, struct fat_entry *fatent, - int new, int wait) + int new, int old, int wait) { struct super_block *sb = inode->i_sb; const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; @@ -417,10 +417,25 @@ int fat_ent_write(struct inode *inode, struct fat_entry *fatent, ops->ent_put(fatent, new); if (wait) { err = fat_sync_bhs(fatent->bhs, fatent->nr_bhs); - if (err) + if (err) { + /* + * bhs are not uptodate after I/O error. So we + * can't simply re-dirty to revert. And it + * would not have value to write again on I/O + * error. + */ return err; + } } - return fat_mirror_bhs(sb, fatent->bhs, fatent->nr_bhs); + + err = fat_mirror_bhs(sb, fatent->bhs, fatent->nr_bhs); + if (err) { + /* Try to revert if got the error on mirror FAT */ + ops->ent_put(fatent, old); + if (wait) + fat_sync_bhs(fatent->bhs, fatent->nr_bhs); + } + return err; } static inline int fat_ent_next(struct msdos_sb_info *sbi, diff --git a/fs/fat/file.c b/fs/fat/file.c index 4fc49a614fb8..ca2f9db34da5 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -360,7 +360,8 @@ static int fat_free(struct inode *inode, int skip) __func__, MSDOS_I(inode)->i_pos); ret = -EIO; } else if (ret > 0) { - err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait); + err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, ret, + wait); if (err) ret = err; } diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 5c45603bf77e..c0bc4356eded 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -133,11 +133,9 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster) ret = fat_ent_read(inode, &fatent, last); if (ret >= 0) { int wait = inode_needs_sync(inode); - int old = ret; - ret = fat_ent_write(inode, &fatent, new_dclus, wait); - if (ret < 0) - fat_ent_write(inode, &fatent, old, wait); + ret = fat_ent_write(inode, &fatent, new_dclus, ret, + wait); fatent_brelse(&fatent); } if (ret < 0) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 094d2872881d..3025fc7ddfe8 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -454,12 +454,12 @@ static bool inode_do_switch_wbs(struct inode *inode, if (inode->i_state & I_DIRTY_ALL) { /* * We need to keep b_dirty list sorted by - * dirtied_time_when. However properly sorting the + * dirtied_when. However properly sorting the * inode in the list gets too expensive when switching * many inodes. So just attach inode at the end of the - * dirty list and clobber the dirtied_time_when. + * dirty list and clobber the dirtied_when. */ - inode->dirtied_time_when = jiffies; + inode->dirtied_when = jiffies; inode_io_list_move_locked(inode, new_wb, &new_wb->b_dirty); } else { @@ -534,6 +534,7 @@ static void process_inode_switch_wbs(struct bdi_writeback *new_wb, } } + wb_io_lists_depopulated(old_wb); spin_unlock(&new_wb->list_lock); spin_unlock(&old_wb->list_lock); diff --git a/fs/fs_pin.c b/fs/fs_pin.c index 47ef3c71ce90..1a508f2167e0 100644 --- a/fs/fs_pin.c +++ b/fs/fs_pin.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include #include #include "internal.h" @@ -22,8 +23,8 @@ void pin_remove(struct fs_pin *pin) void pin_insert(struct fs_pin *pin, struct vfsmount *m) { spin_lock(&pin_lock); - hlist_add_head(&pin->s_list, &m->mnt_sb->s_pins); - hlist_add_head(&pin->m_list, &real_mount(m)->mnt_pins); + hlist_add_head_rcu(&pin->s_list, &m->mnt_sb->s_pins); + hlist_add_head_rcu(&pin->m_list, &real_mount(m)->mnt_pins); spin_unlock(&pin_lock); } @@ -73,7 +74,7 @@ void mnt_pin_kill(struct mount *m) while (1) { struct hlist_node *p; rcu_read_lock(); - p = READ_ONCE(m->mnt_pins.first); + p = rcu_dereference(hlist_first_rcu(&m->mnt_pins)); if (!p) { rcu_read_unlock(); break; @@ -87,7 +88,7 @@ void group_pin_kill(struct hlist_head *p) while (1) { struct hlist_node *q; rcu_read_lock(); - q = READ_ONCE(p->first); + q = rcu_dereference(hlist_first_rcu(p)); if (!q) { rcu_read_unlock(); break; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index a7a3ac5b34f4..f72d74e3c5f0 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2271,6 +2271,9 @@ static int fuse_launder_folio(struct folio *folio) .wb_ctx = &data, }; + if (fuse_is_bad(wpc.inode)) + return -EIO; + if (folio_clear_dirty_for_io(folio)) { err = iomap_writeback_folio(&wpc, folio); err = fuse_iomap_writeback_submit(&wpc, err); @@ -3075,7 +3078,7 @@ static ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in, } err = fuse_simple_request(fm, &args); if (err == -ENOSYS) { - if (fc->no_copy_file_range_64) { + if (args.opcode == FUSE_COPY_FILE_RANGE) { fc->no_copy_file_range = 1; err = -EOPNOTSUPP; } else { @@ -3086,7 +3089,7 @@ static ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in, if (err) goto out; - bytes_copied = fc->no_copy_file_range_64 ? + bytes_copied = args.opcode == FUSE_COPY_FILE_RANGE ? outarg.size : outarg_64.bytes_copied; if (bytes_copied > len) { @@ -3094,9 +3097,11 @@ static ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in, goto out; } - truncate_inode_pages_range(inode_out->i_mapping, - ALIGN_DOWN(pos_out, PAGE_SIZE), - ALIGN(pos_out + bytes_copied, PAGE_SIZE) - 1); + if (bytes_copied) + truncate_inode_pages_range(inode_out->i_mapping, + ALIGN_DOWN(pos_out, PAGE_SIZE), + ALIGN(pos_out + bytes_copied, + PAGE_SIZE) - 1); file_update_time(file_out); fuse_write_update_attr(inode_out, pos_out + bytes_copied, bytes_copied); diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index 2b3daa93e299..e475f7f9e83d 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -454,26 +454,23 @@ static int virtio_fs_add_instance(struct virtio_device *vdev, return ret; } -/* Return the virtio_fs with a given tag, or NULL */ +/* Return the virtio_fs with a given tag, or NULL. + * Callers hold virtio_fs_mutex, which also keeps the virtqueues alive. + */ static struct virtio_fs *virtio_fs_find_instance(const char *tag) { struct virtio_fs *fs; - mutex_lock(&virtio_fs_mutex); + lockdep_assert_held(&virtio_fs_mutex); list_for_each_entry(fs, &virtio_fs_instances, list) { if (strcmp(fs->tag, tag) == 0) { kobject_get(&fs->kobj); - goto found; + return fs; } } - fs = NULL; /* not found */ - -found: - mutex_unlock(&virtio_fs_mutex); - - return fs; + return NULL; /* not found */ } static void virtio_fs_free_devs(struct virtio_fs *fs) @@ -1675,13 +1672,17 @@ static int virtio_fs_get_tree(struct fs_context *fsc) * in fc->iq->priv. Once fuse_conn is going away, it calls ->put() * to drop the reference to this object. */ + mutex_lock(&virtio_fs_mutex); fs = virtio_fs_find_instance(fsc->source); + if (fs) + virtqueue_size = virtqueue_get_vring_size(fs->vqs[VQ_REQUEST].vq); + mutex_unlock(&virtio_fs_mutex); + if (!fs) { pr_info("virtio-fs: tag <%s> not found\n", fsc->source); return -EINVAL; } - virtqueue_size = virtqueue_get_vring_size(fs->vqs[VQ_REQUEST].vq); if (WARN_ON(virtqueue_size <= FUSE_HEADER_OVERHEAD)) goto out_err; diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 0ed81a685fcd..59e3d295a2a1 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -690,7 +690,9 @@ static void gfs2_before_commit(struct gfs2_sbd *sdp, unsigned int limit, page = mempool_alloc(gfs2_page_pool, GFP_NOIO); p = page_address(page); - memcpy_from_page(p, page, bh_offset(bd2->bd_bh), bd2->bd_bh->b_size); + memcpy_from_folio(p, bd2->bd_bh->b_folio, + bh_offset(bd2->bd_bh), + bd2->bd_bh->b_size); *(__be32 *)p = 0; clear_buffer_escaped(bd2->bd_bh); unlock_buffer(bd2->bd_bh); diff --git a/fs/iomap/fiemap.c b/fs/iomap/fiemap.c index d11dadff8286..54b824b7edb5 100644 --- a/fs/iomap/fiemap.c +++ b/fs/iomap/fiemap.c @@ -76,15 +76,15 @@ int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi, while ((ret = iomap_iter(&iter, ops)) > 0) iter.status = iomap_fiemap_iter(&iter, fi, &prev); + /* inode with no (attribute) mapping will give ENOENT */ + if (ret < 0 && ret != -ENOENT) + return ret; + if (prev.type != IOMAP_HOLE) { ret = iomap_to_fiemap(fi, &prev, FIEMAP_EXTENT_LAST); if (ret < 0) return ret; } - - /* inode with no (attribute) mapping will give ENOENT */ - if (ret < 0 && ret != -ENOENT) - return ret; return 0; } EXPORT_SYMBOL_GPL(iomap_fiemap); diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 3433fa14cd01..8a0da54f391d 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -821,6 +821,8 @@ static int isofs_fill_super(struct super_block *s, struct fs_context *fc) if (!sb_set_blocksize(s, orig_zonesize)) goto out_freesbi; + sbi->s_session_start = (sector_t)vol_desc_start << + (ISOFS_BLOCK_BITS - s->s_blocksize_bits); sbi->s_nls_iocharset = NULL; #ifdef CONFIG_JOLIET diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h index 506555837533..a36a63479743 100644 --- a/fs/isofs/isofs.h +++ b/fs/isofs/isofs.h @@ -35,6 +35,8 @@ struct isofs_sb_info { unsigned long s_firstdatazone; unsigned long s_log_zone_size; unsigned long s_max_size; + /* Session start in filesystem block units. */ + sector_t s_session_start; int s_rock_offset; /* offset of SUSP fields within SU area */ s32 s_sbsector; diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 869b331eff4f..a4a337301b6f 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -9,6 +9,7 @@ #include #include +#include #include "isofs.h" #include "rock.h" @@ -84,6 +85,10 @@ static void init_rock_state(struct rock_state *rs, struct inode *inode) */ static int rock_continue(struct rock_state *rs) { + struct super_block *sb = rs->inode->i_sb; + struct isofs_sb_info *sbi = ISOFS_SB(sb); + sector_t session_end = sbi->s_session_start + + ((sector_t)sbi->s_nzones << (ISOFS_BLOCK_BITS - sb->s_blocksize_bits)); int ret = 1; int blocksize = 1 << rs->inode->i_blkbits; const int min_de_size = offsetof(struct rock_ridge, u); @@ -101,11 +106,13 @@ static int rock_continue(struct rock_state *rs) goto out; } - if ((unsigned)rs->cont_extent >= ISOFS_SB(rs->inode->i_sb)->s_nzones) { + if (rs->cont_extent && + (rs->cont_extent < sbi->s_session_start || + rs->cont_extent >= session_end)) { printk(KERN_NOTICE "rock: corrupted directory entry. " "extent=%u out of volume (nzones=%lu)\n", (unsigned)rs->cont_extent, - ISOFS_SB(rs->inode->i_sb)->s_nzones); + sbi->s_nzones); ret = -EIO; goto out; } diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index fa0fb738db0c..1184dbad43e5 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -844,7 +844,6 @@ int jbd2_fc_get_buf(journal_t *journal, struct buffer_head **bh_out) fc_off = journal->j_fc_off; blocknr = journal->j_fc_first + fc_off; - journal->j_fc_off++; ret = jbd2_journal_bmap(journal, blocknr, &pblock); if (ret) return ret; @@ -854,6 +853,7 @@ int jbd2_fc_get_buf(journal_t *journal, struct buffer_head **bh_out) return -ENOMEM; journal->j_fc_wbuf[fc_off] = bh; + journal->j_fc_off++; *bh_out = bh; diff --git a/fs/namespace.c b/fs/namespace.c index ab050a939cb5..34e0d14c454b 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -5817,7 +5817,8 @@ static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq, ks->bufsize = bufsize; if (ks->mask & STATMOUNT_STRING_REQ) { - if (bufsize == sizeof(ks->sm)) + /* Even the reserved empty string needs room past the fixed part. */ + if (bufsize <= sizeof(ks->sm)) return -EOVERFLOW; ks->seq.buf = kvmalloc(seq_size, GFP_KERNEL_ACCOUNT); @@ -5997,6 +5998,8 @@ static ssize_t do_listmount(struct klistmount *kls, bool reverse) } else { if (reverse) first = mnt_find_id_at_reverse(ns, last_mnt_id - 1); + else if (last_mnt_id == U64_MAX) + first = NULL; /* nothing comes after the largest id */ else first = mnt_find_id_at(ns, last_mnt_id + 1); } @@ -6373,7 +6376,7 @@ static int mntns_install(struct nsset *nsset, struct ns_common *ns) if (is_anon_ns(mnt_ns)) return -EINVAL; - if (fs->users != 1) + if (current->fs->users != 1) return -EINVAL; get_mnt_ns(mnt_ns); diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c index 6ca3d74be1e1..3e137c9ca138 100644 --- a/fs/nilfs2/dir.c +++ b/fs/nilfs2/dir.c @@ -231,11 +231,27 @@ static struct nilfs_dir_entry *nilfs_next_entry(struct nilfs_dir_entry *p) nilfs_rec_len_from_disk(p->rec_len)); } +static inline unsigned int +nilfs_validate_entry(char *base, unsigned int offset, unsigned int mask) +{ + struct nilfs_dir_entry *de = (struct nilfs_dir_entry *)(base + offset); + struct nilfs_dir_entry *p = + (struct nilfs_dir_entry *)(base + (offset & mask)); + + while ((char *)p < (char *)de) { + if (p->rec_len == 0) + break; + p = nilfs_next_entry(p); + } + return (char *)p - base; +} + static int nilfs_readdir(struct file *file, struct dir_context *ctx) { loff_t pos = ctx->pos; struct inode *inode = file_inode(file); struct super_block *sb = inode->i_sb; + unsigned int chunk_size = nilfs_chunk_size(inode); unsigned int offset = pos & ~PAGE_MASK; unsigned long n = pos >> PAGE_SHIFT; unsigned long npages = dir_pages(inode); @@ -254,6 +270,24 @@ static int nilfs_readdir(struct file *file, struct dir_context *ctx) ctx->pos += PAGE_SIZE - offset; return -EIO; } + /* + * ctx->pos comes from userspace via llseek and may point + * into the middle of an entry -- or at unvalidated bytes + * of a crafted image. offset is only nonzero here on the + * very first iteration (subsequent pages always start at + * offset 0, which -- like any chunk boundary -- is always + * a legitimate entry start, since no rec_len chain crosses + * a chunk boundary). Snap a non-chunk-aligned offset onto + * a real entry boundary by walking the chain from the + * enclosing chunk's start, as ext2 does; otherwise + * dir_emit() copies name_len bytes from a fake entry, + * reading past the end of the folio. + */ + if (offset & (chunk_size - 1)) { + offset = nilfs_validate_entry(kaddr, offset, + ~(chunk_size - 1)); + ctx->pos = ((loff_t)n << PAGE_SHIFT) + offset; + } de = (struct nilfs_dir_entry *)(kaddr + offset); limit = kaddr + nilfs_last_byte(inode, n) - NILFS_DIR_REC_LEN(1); diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 87ddde159f0c..16e3745ce6e9 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -163,7 +163,7 @@ static int nilfs_writepages(struct address_space *mapping, int err = 0; if (sb_rdonly(inode->i_sb)) { - nilfs_clear_dirty_pages(mapping); + nilfs_clear_dirty_pages(mapping, false); return -EROFS; } @@ -897,13 +897,7 @@ void nilfs_evict_inode(struct inode *inode) nilfs_clear_inode(inode); - if (IS_SYNC(inode)) - nilfs_set_transaction_flag(NILFS_TI_SYNC); nilfs_transaction_commit(sb); - /* - * May construct a logical segment and may fail in sync mode. - * But delete_inode has no return value. - */ } int nilfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 913e1a472c8f..bcb68f92f05e 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -972,10 +972,10 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, * Return: 0 on success, or one of the following negative error codes on * failure: * * %-EFAULT - Failure during execution of requested operation. + * * %-EINTR - Interrupted. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient memory available. * * %-ENOSPC - No space left on device (only in a panic state). - * * %-ERESTARTSYS - Interrupted. * * %-EROFS - Read only filesystem. */ static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 946b0d3534a5..79e662e2bf33 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -407,7 +407,7 @@ static int nilfs_mdt_write_folio(struct folio *folio, * have dirty folios that try to be flushed in background. * So, here we simply discard this dirty folio. */ - nilfs_clear_folio_dirty(folio); + nilfs_clear_folio_dirty(folio, false); folio_unlock(folio); return -EROFS; } @@ -650,10 +650,10 @@ void nilfs_mdt_restore_from_shadow_map(struct inode *inode) if (mi->mi_palloc_cache) nilfs_palloc_clear_cache(inode); - nilfs_clear_dirty_pages(inode->i_mapping); + nilfs_clear_dirty_pages(inode->i_mapping, true); nilfs_copy_back_pages(inode->i_mapping, shadow->inode->i_mapping); - nilfs_clear_dirty_pages(ii->i_assoc_inode->i_mapping); + nilfs_clear_dirty_pages(ii->i_assoc_inode->i_mapping, true); nilfs_copy_back_pages(ii->i_assoc_inode->i_mapping, NILFS_I(shadow->inode)->i_assoc_inode->i_mapping); diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index 89180e2f59fe..969e96ce0b84 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c @@ -370,8 +370,9 @@ void nilfs_copy_back_pages(struct address_space *dmap, /** * nilfs_clear_dirty_pages - discard dirty pages in address space * @mapping: address space with dirty pages for discarding + * @force: whether to clear the dirty state regardless of busy buffer heads */ -void nilfs_clear_dirty_pages(struct address_space *mapping) +void nilfs_clear_dirty_pages(struct address_space *mapping, bool force) { struct folio_batch fbatch; unsigned int i; @@ -392,7 +393,7 @@ void nilfs_clear_dirty_pages(struct address_space *mapping) * was acquired. Skip processing in that case. */ if (likely(folio->mapping == mapping)) - nilfs_clear_folio_dirty(folio); + nilfs_clear_folio_dirty(folio, force); folio_unlock(folio); } @@ -404,13 +405,16 @@ void nilfs_clear_dirty_pages(struct address_space *mapping) /** * nilfs_clear_folio_dirty - discard dirty folio * @folio: dirty folio that will be discarded + * @force: whether to clear the states regardless of busy buffer heads * * nilfs_clear_folio_dirty() clears working states including dirty state for - * the folio and its buffers. If the folio has buffers, clear only if it is - * confirmed that none of the buffer heads are busy (none have valid - * references and none are locked). + * the folio and its buffers. If the folio has buffers and force is false, + * clear only if it is confirmed that none of the buffer heads are busy (none + * have valid references and none are locked). If force is true, the states + * are cleared unconditionally, the caller should guarantee that the folio is + * not being modified concurrently. */ -void nilfs_clear_folio_dirty(struct folio *folio) +void nilfs_clear_folio_dirty(struct folio *folio, bool force) { struct buffer_head *bh, *head; @@ -423,24 +427,28 @@ void nilfs_clear_folio_dirty(struct folio *folio) BIT(BH_Async_Write) | BIT(BH_NILFS_Volatile) | BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected) | BIT(BH_Delay)); - bool busy, invalidated = false; + + if (!force) { + bool busy, invalidated = false; recheck_buffers: - busy = false; - bh = head; - do { - if (atomic_read(&bh->b_count) | buffer_locked(bh)) { - busy = true; - break; + busy = false; + bh = head; + do { + if (atomic_read(&bh->b_count) | + buffer_locked(bh)) { + busy = true; + break; + } + } while (bh = bh->b_this_page, bh != head); + + if (busy) { + if (invalidated) + return; + invalidate_bh_lrus(); + invalidated = true; + goto recheck_buffers; } - } while (bh = bh->b_this_page, bh != head); - - if (busy) { - if (invalidated) - return; - invalidate_bh_lrus(); - invalidated = true; - goto recheck_buffers; } bh = head; diff --git a/fs/nilfs2/page.h b/fs/nilfs2/page.h index 136cd1c143c9..c3ba3468af5c 100644 --- a/fs/nilfs2/page.h +++ b/fs/nilfs2/page.h @@ -41,8 +41,8 @@ void nilfs_folio_bug(struct folio *); int nilfs_copy_dirty_pages(struct address_space *, struct address_space *); void nilfs_copy_back_pages(struct address_space *, struct address_space *); -void nilfs_clear_folio_dirty(struct folio *folio); -void nilfs_clear_dirty_pages(struct address_space *mapping); +void nilfs_clear_folio_dirty(struct folio *folio, bool force); +void nilfs_clear_dirty_pages(struct address_space *mapping, bool force); unsigned int nilfs_page_count_clean_buffers(struct folio *folio, unsigned int from, unsigned int to); unsigned long nilfs_find_uncommitted_extent(struct inode *inode, diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index a9c61d0492cb..dfff3bc84bcd 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c @@ -785,11 +785,11 @@ static void nilfs_abort_roll_forward(struct the_nilfs *nilfs) * * Return: 0 on success, or one of the following negative error codes on * failure: + * * %-EINTR - Interrupted. * * %-EINVAL - Inconsistent filesystem state. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient memory available. * * %-ENOSPC - No space left on device (only in a panic state). - * * %-ERESTARTSYS - Interrupted. */ int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs, struct super_block *sb, diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index c20340f4e0dc..e967d16b2f13 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -1825,6 +1825,7 @@ static void nilfs_abort_logs(struct list_head *logs, int err) list_for_each_entry(segbuf, logs, sb_list) { list_for_each_entry(bh, &segbuf->sb_segsum_buffers, b_assoc_buffers) { + clear_buffer_dirty(bh); clear_buffer_uptodate(bh); if (bh->b_folio != bd_folio) { if (bd_folio) @@ -1836,6 +1837,7 @@ static void nilfs_abort_logs(struct list_head *logs, int err) list_for_each_entry(bh, &segbuf->sb_payload_buffers, b_assoc_buffers) { if (bh == segbuf->sb_super_root) { + clear_buffer_dirty(bh); clear_buffer_uptodate(bh); if (bh->b_folio != bd_folio) { folio_end_writeback(bd_folio); @@ -2253,7 +2255,7 @@ static int nilfs_segctor_sync(struct nilfs_sc_info *sci) wake_up(&sci->sc_wait_daemon); for (;;) { - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_KILLABLE); /* * Synchronize only while the log writer thread is alive. @@ -2267,11 +2269,11 @@ static int nilfs_segctor_sync(struct nilfs_sc_info *sci) err = wait_req.err; break; } - if (!signal_pending(current)) { + if (!fatal_signal_pending(current)) { schedule(); continue; } - err = -ERESTARTSYS; + err = -EINTR; break; } finish_wait(&sci->sc_wait_request, &wait_req.wq); @@ -2305,10 +2307,10 @@ static void nilfs_segctor_wakeup(struct nilfs_sc_info *sci, int err, bool force) * * Return: 0 on success, or one of the following negative error codes on * failure: + * * %-EINTR - Interrupted. * * %-EIO - I/O error (including metadata corruption). * * %-ENOMEM - Insufficient memory available. * * %-ENOSPC - No space left on device (only in a panic state). - * * %-ERESTARTSYS - Interrupted. * * %-EROFS - Read only filesystem. */ int nilfs_construct_segment(struct super_block *sb) @@ -2335,10 +2337,10 @@ int nilfs_construct_segment(struct super_block *sb) * * Return: 0 on success, or one of the following negative error codes on * failure: + * * %-EINTR - Interrupted. * * %-EIO - I/O error (including metadata corruption). * * %-ENOMEM - Insufficient memory available. * * %-ENOSPC - No space left on device (only in a panic state). - * * %-ERESTARTSYS - Interrupted. * * %-EROFS - Read only filesystem. */ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode, diff --git a/fs/nilfs2/sysfs.c b/fs/nilfs2/sysfs.c index bc52afbfc5c7..5bb74a45ad1e 100644 --- a/fs/nilfs2/sysfs.c +++ b/fs/nilfs2/sysfs.c @@ -195,8 +195,10 @@ int nilfs_sysfs_create_snapshot_group(struct nilfs_root *root) "%llu", root->cno); } - if (err) + if (err) { kobject_put(&root->snapshot_kobj); + wait_for_completion(&root->snapshot_kobj_unregister); + } return err; } @@ -204,6 +206,7 @@ int nilfs_sysfs_create_snapshot_group(struct nilfs_root *root) void nilfs_sysfs_delete_snapshot_group(struct nilfs_root *root) { kobject_put(&root->snapshot_kobj); + wait_for_completion(&root->snapshot_kobj_unregister); } /************************************************************************ diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 9911a484398a..b453229db3af 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -887,6 +887,26 @@ nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno) if (!new) return NULL; + new->cno = cno; + new->ifile = NULL; + new->nilfs = nilfs; + refcount_set(&new->count, 1); + atomic64_set(&new->inodes_count, 0); + atomic64_set(&new->blocks_count, 0); + + /* + * Register the sysfs group before publishing the root in the + * checkpoint tree. nilfs_sysfs_create_snapshot_group() can sleep, + * so it must run outside ns_cptree_lock; creating it first also + * ensures a concurrent nilfs_lookup_root() can never observe a root + * whose sysfs registration later fails and gets freed. + */ + err = nilfs_sysfs_create_snapshot_group(new); + if (err) { + kfree(new); + return NULL; + } + spin_lock(&nilfs->ns_cptree_lock); p = &nilfs->ns_cptree.rb_node; @@ -903,29 +923,17 @@ nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno) } else { refcount_inc(&root->count); spin_unlock(&nilfs->ns_cptree_lock); + nilfs_sysfs_delete_snapshot_group(new); kfree(new); return root; } } - new->cno = cno; - new->ifile = NULL; - new->nilfs = nilfs; - refcount_set(&new->count, 1); - atomic64_set(&new->inodes_count, 0); - atomic64_set(&new->blocks_count, 0); - rb_link_node(&new->rb_node, parent, p); rb_insert_color(&new->rb_node, &nilfs->ns_cptree); spin_unlock(&nilfs->ns_cptree_lock); - err = nilfs_sysfs_create_snapshot_group(new); - if (err) { - kfree(new); - new = NULL; - } - return new; } diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index cdb69c23e2e6..bb12baebd0c9 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -650,6 +650,9 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir, unsigned long name2_len = name2 ? name2->len : 0; unsigned int len, size; + if (WARN_ON_ONCE(name_len >= PATH_MAX || name2_len >= PATH_MAX)) + return NULL; + /* Reserve terminating null byte even for empty name */ size = sizeof(*fne) + name_len + name2_len + 2; if (dir_fh_len) @@ -658,7 +661,7 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir, size += FANOTIFY_FH_HDR_LEN + dir2_fh_len; if (child_fh_len) size += FANOTIFY_FH_HDR_LEN + child_fh_len; - fne = kmalloc(size, gfp); + fne = kvmalloc(size, gfp); if (!fne) return NULL; @@ -1048,7 +1051,7 @@ static void fanotify_free_fid_event(struct fanotify_event *event) static void fanotify_free_name_event(struct fanotify_event *event) { - kfree(FANOTIFY_NE(event)); + kvfree(FANOTIFY_NE(event)); } static void fanotify_free_error_event(struct fsnotify_group *group, diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index eb2ba71d5c81..775f55080dd4 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h @@ -42,9 +42,16 @@ struct fanotify_info { u8 dir_fh_totlen; u8 dir2_fh_totlen; u8 file_fh_totlen; - u8 name_len; - u8 name2_len; - u8 pad[3]; + u8 pad; + /* + * Deliberately not limited to NAME_MAX: some filesystems return longer + * names (vfat up to 255 UTF-16 characters, as Windows allows, which is + * up to 765 bytes of UTF-8; FUSE up to PATH_MAX - 1), and readdir() and + * inotify report them in full. Only names of PATH_MAX bytes or more, + * which no path can refer to, are dropped. + */ + u16 name_len; + u16 name2_len; unsigned char buf[]; /* * (struct fanotify_fh) dir_fh starts at buf[0] @@ -167,7 +174,7 @@ static inline char *fanotify_info_name2(struct fanotify_info *info) static inline void fanotify_info_init(struct fanotify_info *info) { BUILD_BUG_ON(FANOTIFY_FH_HDR_LEN + MAX_HANDLE_SZ > U8_MAX); - BUILD_BUG_ON(NAME_MAX > U8_MAX); + BUILD_BUG_ON(PATH_MAX > U16_MAX); info->dir_fh_totlen = 0; info->dir2_fh_totlen = 0; @@ -213,8 +220,7 @@ static inline void fanotify_info_set_file_fh(struct fanotify_info *info, static inline void fanotify_info_copy_name(struct fanotify_info *info, const struct qstr *name) { - if (WARN_ON_ONCE(name->len > NAME_MAX) || - WARN_ON_ONCE(info->name2_len > 0)) + if (WARN_ON_ONCE(info->name2_len > 0)) return; info->name_len = name->len; @@ -224,9 +230,6 @@ static inline void fanotify_info_copy_name(struct fanotify_info *info, static inline void fanotify_info_copy_name2(struct fanotify_info *info, const struct qstr *name) { - if (WARN_ON_ONCE(name->len > NAME_MAX)) - return; - info->name2_len = name->len; strcpy(fanotify_info_name2(info), name->name); } diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c index ae15c2fc4864..4753fcab4d81 100644 --- a/fs/ntfs3/fslog.c +++ b/fs/ntfs3/fslog.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -2455,7 +2456,8 @@ static int find_log_rec(struct ntfs_log *log, u64 lsn, struct lcb *lcb) * Check that the length field isn't greater than the total * available space the log file. */ - rec_len = len + log->record_header_len; + if (check_add_overflow(len, log->record_header_len, &rec_len)) + return -EINVAL; if (rec_len >= log->total_avail) return -EINVAL; @@ -3300,10 +3302,15 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe, asize = le32_to_cpu(attr2->size); used = le32_to_cpu(rec->used); + /* + * attr2->size is taken from the log record and is bounded only + * by the log record length, not by the MFT record. Refuse an + * attribute that does not fit, as mi_insert_attr() does. + */ if (!check_if_attr(rec, lrh) || dlen < SIZEOF_RESIDENT || !IS_ALIGNED(asize, 8) || Add2Ptr(attr2, asize) > Add2Ptr(lrh, rec_len) || - dlen > record_size - used) { + dlen > record_size - used || asize > record_size - used) { goto dirty_vol; } @@ -3333,10 +3340,21 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe, break; case DeleteAttribute: - asize = le32_to_cpu(attr->size); used = le32_to_cpu(rec->used); - if (!check_if_attr(rec, lrh)) + /* + * check_if_attr() accepts a record_off that points at the + * ATTR_END marker, which is how CreateAttribute appends. The + * bytes there are not an attribute and check_attr() never + * validated them, so refuse an offset that cannot hold a + * resident header before reading attr->size, and then bound it + * as mi_remove_attr() does. + */ + if (!check_if_attr(rec, lrh) || roff + SIZEOF_RESIDENT > used) + goto dirty_vol; + + asize = le32_to_cpu(attr->size); + if (asize > used - roff) goto dirty_vol; rec->used = cpu_to_le32(used - asize); @@ -3418,7 +3436,8 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe, if (!check_if_attr(rec, lrh) || !attr->non_res || aoff < le16_to_cpu(attr->nres.run_off) || aoff > asize || - (nsize > asize && nsize - asize > record_size - used)) { + (nsize > asize && + ALIGN(nsize, 8) - asize > record_size - used)) { goto dirty_vol; } diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index 03ae5a817c1b..97cbe176a83e 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -596,6 +596,8 @@ static const struct NTFS_DE *hdr_insert_head(struct INDEX_HDR *hdr, if (!e) return NULL; + if (size_add(used, ins_bytes) > le32_to_cpu(hdr->total)) + return NULL; /* Now we just make room for the inserted entries and jam it in. */ to_move = used - le32_to_cpu(hdr->de_off); @@ -1800,7 +1802,10 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni, } /* Copy root entries into new buffer. */ - hdr_insert_head(hdr, re, to_move); + if (!hdr_insert_head(hdr, re, to_move)) { + err = -EINVAL; + goto out_put_n; + } /* Update bitmap attribute. */ indx_mark_used(indx, ni, new_vbn >> indx->idx2vbn_bits); @@ -1952,7 +1957,11 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, /* Copy all the entries <= sp into the new buffer. */ de_t = hdr_first_de(hdr1); to_copy = PtrOffset(de_t, sp); - hdr_insert_head(hdr2, de_t, to_copy); + if (!hdr_insert_head(hdr2, de_t, to_copy)) { + err = -EINVAL; + put_indx_node(n2); + goto out; + } /* Remove all entries (sp including) from hdr1. */ used = used1 - to_copy - sp_size; diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 61e5eb0090d3..0888c44f677c 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -2124,6 +2124,18 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g } reg->hr_node_num = O2NM_MAX_NODES; + INIT_LIST_HEAD(®->hr_all_item); + mutex_init(®->hr_arming_mutex); + reg->hr_stopping = true; + INIT_DELAYED_WORK(®->hr_write_timeout_work, o2hb_write_timeout); + INIT_DELAYED_WORK(®->hr_nego_timeout_work, o2hb_nego_timeout); + INIT_LIST_HEAD(®->hr_handler_list); + config_item_init_type_name(®->hr_item, name, &o2hb_region_type); + if (!config_item_name(®->hr_item)) { + ret = -ENOMEM; + goto put_item; + } + spin_lock(&o2hb_live_lock); reg->hr_region_num = 0; if (o2hb_global_heartbeat_active()) { @@ -2132,26 +2144,19 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g if (reg->hr_region_num >= O2NM_MAX_REGIONS) { spin_unlock(&o2hb_live_lock); ret = -EFBIG; - goto free; + goto put_item; } set_bit(reg->hr_region_num, o2hb_region_bitmap); } list_add_tail(®->hr_all_item, &o2hb_all_regions); spin_unlock(&o2hb_live_lock); - config_item_init_type_name(®->hr_item, name, &o2hb_region_type); - /* this is the same way to generate msg key as dlm, for local heartbeat, * name is also the same, so make initial crc value different to avoid * message key conflict. */ reg->hr_key = crc32_le(reg->hr_region_num + O2NM_MAX_REGIONS, name, strlen(name)); - mutex_init(®->hr_arming_mutex); - reg->hr_stopping = true; - INIT_DELAYED_WORK(®->hr_write_timeout_work, o2hb_write_timeout); - INIT_DELAYED_WORK(®->hr_nego_timeout_work, o2hb_nego_timeout); - INIT_LIST_HEAD(®->hr_handler_list); ret = o2net_register_handler(O2HB_NEGO_TIMEOUT_MSG, reg->hr_key, sizeof(struct o2hb_nego_msg), o2hb_nego_timeout_handler, @@ -2174,10 +2179,13 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g o2net_unregister_and_flush_handler_list(®->hr_handler_list); remove_item: spin_lock(&o2hb_live_lock); - list_del(®->hr_all_item); + list_del_init(®->hr_all_item); if (o2hb_global_heartbeat_active()) clear_bit(reg->hr_region_num, o2hb_region_bitmap); spin_unlock(&o2hb_live_lock); +put_item: + config_item_put(®->hr_item); + return ERR_PTR(ret); free: kfree(reg); return ERR_PTR(ret); diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c index 87aeb1a7a90a..bfc7c0fb2be0 100644 --- a/fs/ocfs2/cluster/nodemanager.c +++ b/fs/ocfs2/cluster/nodemanager.c @@ -626,8 +626,11 @@ static void o2nm_node_group_drop_item(struct config_group *group, write_lock(&cluster->cl_nodes_lock); - /* XXX sloppy */ - if (node->nd_ipv4_address) + /* + * 0.0.0.0 is a valid configured address, so nd_ipv4_address does + * not tell us whether nd_ip_node was published in the IP tree. + */ + if (test_bit(O2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes)) rb_erase(&node->nd_ip_node, &cluster->cl_node_ip_tree); /* nd_num might be 0 if the node number hasn't been set.. */ diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index fbfce8cd131a..1dee6b8eaf2d 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -221,7 +221,8 @@ static void TEA_transform(__u32 buf[4], __u32 const in[]) buf[1] += b1; } -static void str2hashbuf(const char *msg, int len, __u32 *buf, int num) +static void str2hashbuf(const char *msg, int len, __u32 *buf, int num, + bool legacy_signed) { __u32 pad, val; int i; @@ -235,7 +236,10 @@ static void str2hashbuf(const char *msg, int len, __u32 *buf, int num) for (i = 0; i < len; i++) { if ((i % 4) == 0) val = pad; - val = msg[i] + (val << 8); + if (legacy_signed) + val = (signed char)msg[i] + (val << 8); + else + val = (unsigned char)msg[i] + (val << 8); if ((i % 4) == 3) { *buf++ = val; val = pad; @@ -248,8 +252,9 @@ static void str2hashbuf(const char *msg, int len, __u32 *buf, int num) *buf++ = pad; } -static void ocfs2_dx_dir_name_hash(struct inode *dir, const char *name, int len, - struct ocfs2_dx_hinfo *hinfo) +static void __ocfs2_dx_dir_name_hash(struct inode *dir, const char *name, + int len, struct ocfs2_dx_hinfo *hinfo, + bool legacy_signed) { struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); const char *p; @@ -279,7 +284,7 @@ static void ocfs2_dx_dir_name_hash(struct inode *dir, const char *name, int len, p = name; while (len > 0) { - str2hashbuf(p, len, in, 4); + str2hashbuf(p, len, in, 4, legacy_signed); TEA_transform(buf, in); len -= 16; p += 16; @@ -290,6 +295,19 @@ static void ocfs2_dx_dir_name_hash(struct inode *dir, const char *name, int len, hinfo->minor_hash = buf[1]; } +static void ocfs2_dx_dir_name_hash(struct inode *dir, const char *name, int len, + struct ocfs2_dx_hinfo *hinfo) +{ + __ocfs2_dx_dir_name_hash(dir, name, len, hinfo, false); +} + +static void ocfs2_dx_dir_name_hash_signed(struct inode *dir, const char *name, + int len, + struct ocfs2_dx_hinfo *hinfo) +{ + __ocfs2_dx_dir_name_hash(dir, name, len, hinfo, true); +} + /* * bh passed here can be an inode block or a dir data block, depending * on the inode inline data flag. @@ -961,10 +979,10 @@ static int ocfs2_dx_dir_lookup(struct inode *inode, return ret; } -static int ocfs2_dx_dir_search(const char *name, int namelen, - struct inode *dir, - struct ocfs2_dx_root_block *dx_root, - struct ocfs2_dir_lookup_result *res) +static int __ocfs2_dx_dir_search(const char *name, int namelen, + struct inode *dir, + struct ocfs2_dx_root_block *dx_root, + struct ocfs2_dir_lookup_result *res) { int ret, i, found; u64 phys; @@ -977,8 +995,6 @@ static int ocfs2_dx_dir_search(const char *name, int namelen, struct ocfs2_extent_list *dr_el; struct ocfs2_dx_entry_list *entry_list; - ocfs2_dx_dir_name_hash(dir, name, namelen, &res->dl_hinfo); - if (ocfs2_dx_root_inline(dx_root)) { entry_list = &dx_root->dr_entries; goto search; @@ -1075,6 +1091,44 @@ static int ocfs2_dx_dir_search(const char *name, int namelen, return ret; } +static int ocfs2_dx_dir_search(const char *name, int namelen, + struct inode *dir, + struct ocfs2_dx_root_block *dx_root, + struct ocfs2_dir_lookup_result *res) +{ + struct ocfs2_dx_hinfo legacy; + int ret; + + ocfs2_dx_dir_name_hash(dir, name, namelen, &res->dl_hinfo); + + ret = __ocfs2_dx_dir_search(name, namelen, dir, dx_root, res); + if (ret != -ENOENT) + return ret; + + /* + * Nothing under the current hash. The entry may have been indexed by + * an older kernel, which sign-extended the name bytes when hashing. + * New entries are always indexed under the unsigned hash, so only fall + * back to the legacy signed one when it can actually differ: an ASCII + * name hashes the same either way, and a genuine miss on one should + * not have to walk the index twice. + */ + ocfs2_dx_dir_name_hash_signed(dir, name, namelen, &legacy); + if (legacy.major_hash == res->dl_hinfo.major_hash && + legacy.minor_hash == res->dl_hinfo.minor_hash) + return ret; + + res->dl_hinfo = legacy; + + ret = __ocfs2_dx_dir_search(name, namelen, dir, dx_root, res); + if (ret) + return ret; + + pr_warn_once("ocfs2: directory index with signed name hash\n"); + + return 0; +} + static int ocfs2_find_entry_dx(const char *name, int namelen, struct inode *dir, struct ocfs2_dir_lookup_result *lookup) diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index b4055ced93d9..90d23dd7d4c8 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -3527,6 +3527,10 @@ void ocfs2_mark_lockres_freeing(struct ocfs2_super *osb, struct ocfs2_mask_waiter mw; unsigned long flags, flags2; + /* We didn't get anywhere near actually using this lockres. */ + if (!(lockres->l_flags & OCFS2_LOCK_INITIALIZED)) + return; + ocfs2_init_mask_waiter(&mw); spin_lock_irqsave(&lockres->l_lock, flags); diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index a0df92a23498..f4c36ce1678d 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -140,18 +140,26 @@ static int ocfs2_file_open(struct inode *inode, struct file *file) static int ocfs2_file_release(struct inode *inode, struct file *file) { struct ocfs2_inode_info *oi = OCFS2_I(inode); + struct dentry *dentry = file->f_path.dentry; + struct name_snapshot name; + bool trace_enabled = trace_ocfs2_file_release_enabled(); + + if (trace_enabled) + take_dentry_name_snapshot(&name, dentry); spin_lock(&oi->ip_lock); if (!--oi->ip_open_count) oi->ip_flags &= ~OCFS2_INODE_OPEN_DIRECT; - trace_ocfs2_file_release(inode, file, file->f_path.dentry, - oi->ip_blkno, - file->f_path.dentry->d_name.len, - file->f_path.dentry->d_name.name, - oi->ip_open_count); + if (trace_enabled) + trace_ocfs2_file_release(inode, file, dentry, + oi->ip_blkno, name.name.len, + name.name.name, oi->ip_open_count); spin_unlock(&oi->ip_lock); + if (trace_enabled) + release_dentry_name_snapshot(&name); + ocfs2_free_file_private(inode, file); return 0; diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 835c00b90b7c..c1ac673ca456 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -637,14 +637,18 @@ static int ocfs2_read_locked_inode(struct inode *inode, fe = (struct ocfs2_dinode *) bh->b_data; /* - * This is a code bug. Right now the caller needs to - * understand whether it is asking for a system file inode or - * not so the proper lock names can be built. + * The caller must know whether it is asking for a system file inode + * or not so the proper lock names can be built. Since i_flags comes + * from disk, a mismatch is filesystem corruption instead of a code + * bug, so handle it with ocfs2_error() rather than BUG_ON(). */ - mlog_bug_on_msg(!!(fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL)) != - !!(args->fi_flags & OCFS2_FI_FLAG_SYSFILE), - "Inode %llu: system file state is ambiguous\n", - (unsigned long long)args->fi_blkno); + if (!!(fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL)) != + !!(args->fi_flags & OCFS2_FI_FLAG_SYSFILE)) { + status = ocfs2_error(osb->sb, + "Inode %llu: system file state is ambiguous\n", + (unsigned long long)args->fi_blkno); + goto bail; + } if (S_ISCHR(le16_to_cpu(fe->i_mode)) || S_ISBLK(le16_to_cpu(fe->i_mode))) @@ -1530,8 +1534,23 @@ int ocfs2_validate_inode_block(struct super_block *sb, goto bail; } - if (le16_to_cpu(di->i_suballoc_slot) != (u16)OCFS2_INVALID_SLOT && - (u32)le16_to_cpu(di->i_suballoc_slot) > OCFS2_SB(sb)->max_slots - 1) { + /* + * Only system inodes created by mkfs.ocfs2 are allocated from the + * global allocator and thus legitimately carry OCFS2_INVALID_SLOT. + * Regular inodes are always allocated from a per-slot suballocator. + * If a regular inode with OCFS2_INVALID_SLOT was accepted here, + * deleting it would pass the slot to get_local_system_inode() via + * ocfs2_remove_inode() and trigger BUG_ON(slot == OCFS2_INVALID_SLOT). + */ + if (le16_to_cpu(di->i_suballoc_slot) == (u16)OCFS2_INVALID_SLOT) { + if (!(le32_to_cpu(di->i_flags) & OCFS2_SYSTEM_FL)) { + rc = ocfs2_error(sb, + "Invalid dinode %llu: suballoc slot %u for non-system inode\n", + (unsigned long long)bh->b_blocknr, + le16_to_cpu(di->i_suballoc_slot)); + goto bail; + } + } else if ((u32)le16_to_cpu(di->i_suballoc_slot) > OCFS2_SB(sb)->max_slots - 1) { rc = ocfs2_error(sb, "Invalid dinode %llu: suballoc slot %u\n", (unsigned long long)bh->b_blocknr, le16_to_cpu(di->i_suballoc_slot)); diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 8c07610692d0..2b8b57e914f0 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -158,7 +158,7 @@ static void ocfs2_queue_replay_slots(struct ocfs2_super *osb, replay_map->rm_state = REPLAY_DONE; } -void ocfs2_free_replay_slots(struct ocfs2_super *osb) +static void ocfs2_free_replay_slots(struct ocfs2_super *osb) { struct ocfs2_replay_map *replay_map = osb->replay_map; @@ -246,6 +246,7 @@ void ocfs2_recovery_exit(struct ocfs2_super *osb) /* XXX: Should we bug if there are dirty entries? */ kfree(rm); + ocfs2_free_replay_slots(osb); } static int __ocfs2_recovery_map_test(struct ocfs2_super *osb, diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index f8b3b2a3d630..19fc920d26b1 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h @@ -151,7 +151,6 @@ void ocfs2_recovery_exit(struct ocfs2_super *osb); void ocfs2_recovery_disable_quota(struct ocfs2_super *osb); int ocfs2_compute_replay_slots(struct ocfs2_super *osb); -void ocfs2_free_replay_slots(struct ocfs2_super *osb); /* * Journal Control: * Initialize, Load, Shutdown, Wipe a journal. diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index dc252b53c7dc..fe4ab1659e0d 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1163,15 +1163,23 @@ static int ocfs2_fill_super(struct super_block *sb, struct fs_context *fc) out_dismount: atomic_set(&osb->vol_state, VOLUME_DISABLED); wake_up(&osb->osb_mount_event); - ocfs2_free_replay_slots(osb); ocfs2_dismount_volume(sb, 1); goto out; out_debugfs: debugfs_remove_recursive(osb->osb_debug_root); out_super: + /* + * A recovery thread launched by a node failure event may still be + * waiting for the volume to be mounted. Set VOLUME_DISABLED and + * wake it up, then wait for it to exit before osb is freed, + * otherwise the kthread would leak and stay blocked on the wait + * queue embedded in the freed osb. + */ + atomic_set(&osb->vol_state, VOLUME_DISABLED); + wake_up(&osb->osb_mount_event); ocfs2_release_system_inodes(osb); - kfree(osb->recovery_map); + ocfs2_recovery_exit(osb); ocfs2_delete_osb(osb); kfree(osb); out: @@ -1769,14 +1777,12 @@ static int ocfs2_mount_volume(struct super_block *sb) status = ocfs2_truncate_log_init(osb); if (status < 0) { mlog_errno(status); - goto out_check_volume; + goto out_system_inodes; } ocfs2_super_unlock(osb, 1); return 0; -out_check_volume: - ocfs2_free_replay_slots(osb); out_system_inodes: if (osb->local_alloc_state == OCFS2_LA_ENABLED) ocfs2_shutdown_local_alloc(osb); diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index b5029c4e3784..734801de8e89 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -533,9 +533,10 @@ static inline const char *ocfs2_xattr_prefix(int name_index) return handler ? xattr_prefix(handler) : NULL; } -static u32 ocfs2_xattr_name_hash(struct inode *inode, - const char *name, - int name_len) +static u32 __ocfs2_xattr_name_hash(struct inode *inode, + const char *name, + int name_len, + bool legacy_signed) { /* Get hash value of uuid from super block */ u32 hash = OCFS2_SB(inode->i_sb)->uuid_hash; @@ -544,13 +545,30 @@ static u32 ocfs2_xattr_name_hash(struct inode *inode, /* hash extended attribute name */ for (i = 0; i < name_len; i++) { hash = (hash << OCFS2_HASH_SHIFT) ^ - (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^ - *name++; + (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)); + if (legacy_signed) + hash ^= (signed char)name[i]; + else + hash ^= (unsigned char)name[i]; } return hash; } +static u32 ocfs2_xattr_name_hash(struct inode *inode, + const char *name, + int name_len) +{ + return __ocfs2_xattr_name_hash(inode, name, name_len, false); +} + +static u32 ocfs2_xattr_name_hash_signed(struct inode *inode, + const char *name, + int name_len) +{ + return __ocfs2_xattr_name_hash(inode, name, name_len, true); +} + static int ocfs2_xattr_entry_real_size(int name_len, size_t value_len) { return namevalue_size(name_len, value_len) + @@ -3143,6 +3161,14 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode, credits += ocfs2_calc_extend_credits( inode->i_sb, &def_xv.xv.xr_list); + /* + * A value too big to stay inline is only charged as + * OCFS2_XATTR_ROOT_SIZE above, so it can still need a + * value tree of its own. No xattr block is allocated + * on this path, so the tree is all we reserve for. + */ + if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) + meta_add += ocfs2_extend_meta_needed(&def_xv.xv.xr_list); goto out; } } @@ -3243,7 +3269,13 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode, credits += OCFS2_XATTR_BLOCK_CREATE_CREDITS; if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) { struct ocfs2_extent_list *el = &def_xv.xv.xr_list; - meta_add += ocfs2_extend_meta_needed(el); + /* + * One block for the xattr block we may have to + * allocate, the rest for growing the value tree it + * would hold. If ocfs2_xattr_ibody_set() succeeds + * instead, that first block goes unused. + */ + meta_add += 1 + ocfs2_extend_meta_needed(el); credits += ocfs2_calc_extend_credits(inode->i_sb, el); } else { @@ -3935,11 +3967,12 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, return ret; } -static int ocfs2_xattr_index_block_find(struct inode *inode, - struct buffer_head *root_bh, - int name_index, - const char *name, - struct ocfs2_xattr_search *xs) +static int __ocfs2_xattr_index_block_find(struct inode *inode, + struct buffer_head *root_bh, + int name_index, + const char *name, + u32 name_hash, + struct ocfs2_xattr_search *xs) { int ret; struct ocfs2_xattr_block *xb = @@ -3948,7 +3981,6 @@ static int ocfs2_xattr_index_block_find(struct inode *inode, struct ocfs2_extent_list *el = &xb_root->xt_list; u64 p_blkno = 0; u32 first_hash, num_clusters = 0; - u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name)); if (le16_to_cpu(el->l_next_free_rec) == 0) return -ENODATA; @@ -3979,6 +4011,59 @@ static int ocfs2_xattr_index_block_find(struct inode *inode, return ret; } +static int ocfs2_xattr_index_block_find(struct inode *inode, + struct buffer_head *root_bh, + int name_index, + const char *name, + struct ocfs2_xattr_search *xs) +{ + u32 name_hash, legacy_hash; + int name_len = strlen(name); + int ret; + + name_hash = ocfs2_xattr_name_hash(inode, name, name_len); + + ret = __ocfs2_xattr_index_block_find(inode, root_bh, name_index, name, + name_hash, xs); + if (ret != -ENODATA) + return ret; + + /* + * Nothing under the current hash. The entry may have been stored by + * an older kernel, which sign-extended the name bytes when hashing. + * Skip the retry when the two hashes are equal, so that a name made + * only of ASCII does not have to walk the tree twice. + */ + legacy_hash = ocfs2_xattr_name_hash_signed(inode, name, name_len); + if (legacy_hash == name_hash) + return ret; + + /* + * A miss still leaves xs->bucket holding the bucket a new entry would + * be inserted into, so drop it before searching again. + */ + ocfs2_xattr_bucket_relse(xs->bucket); + + ret = __ocfs2_xattr_index_block_find(inode, root_bh, name_index, name, + legacy_hash, xs); + if (!ret) { + pr_warn_once("ocfs2: xattr tree with signed name hash\n"); + return ret; + } + if (ret != -ENODATA) + return ret; + + /* + * Not under either hash. Restore the unsigned placement, since that + * is where a new entry is stored: leaving the bucket where the legacy + * hash put it would break the ordering the search relies on. + */ + ocfs2_xattr_bucket_relse(xs->bucket); + + return __ocfs2_xattr_index_block_find(inode, root_bh, name_index, name, + name_hash, xs); +} + static int ocfs2_iterate_xattr_buckets(struct inode *inode, u64 blkno, u32 clusters, @@ -5517,16 +5602,14 @@ static int ocfs2_rm_xattr_cluster(struct inode *inode, /* * check whether the xattr bucket is filled up with the same hash value. - * If we want to insert the xattr with the same hash, return -ENOSPC. - * If we want to insert a xattr with different hash value, go ahead - * and ocfs2_divide_xattr_bucket will handle this. + * If the entry being set carries that same hash, return -ENOSPC, since + * ocfs2_divide_xattr_bucket() has no divide position to work with. + * Otherwise go ahead and ocfs2_divide_xattr_bucket() will handle this. */ -static int ocfs2_check_xattr_bucket_collision(struct inode *inode, - struct ocfs2_xattr_bucket *bucket, - const char *name) +static int ocfs2_check_xattr_bucket_collision(struct ocfs2_xattr_bucket *bucket, + u32 name_hash) { struct ocfs2_xattr_header *xh = bucket_xh(bucket); - u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name)); if (name_hash != le32_to_cpu(xh->xh_entries[0].xe_name_hash)) return 0; @@ -5595,10 +5678,27 @@ static int ocfs2_xattr_set_entry_index_block(struct inode *inode, struct ocfs2_xattr_search *xs, struct ocfs2_xattr_set_ctxt *ctxt) { + u32 name_hash; int ret; trace_ocfs2_xattr_set_entry_index_block(xi->xi_name); + /* + * An existing entry keeps the hash it was stored under, and that is + * the hash a split has to work with. A new entry is stored under the + * unsigned one, which is what ocfs2_xa_add_entry() will write. + * + * Read it before the set below. Filling the bucket may defragment it, + * and ocfs2_defrag_xattr_bucket() re-sorts the entry array, so + * afterwards xs->here only denotes whichever entry the sort left in + * that slot. + */ + if (xs->not_found) + name_hash = ocfs2_xattr_name_hash(inode, xi->xi_name, + xi->xi_name_len); + else + name_hash = le32_to_cpu(xs->here->xe_name_hash); + ret = ocfs2_xattr_set_entry_bucket(inode, xi, xs, ctxt); if (!ret) goto out; @@ -5615,9 +5715,7 @@ static int ocfs2_xattr_set_entry_index_block(struct inode *inode, * one bucket's worth, so check it here whether we need to * add a new bucket for the insert. */ - ret = ocfs2_check_xattr_bucket_collision(inode, - xs->bucket, - xi->xi_name); + ret = ocfs2_check_xattr_bucket_collision(xs->bucket, name_hash); if (ret) { mlog_errno(ret); goto out; diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 12b817f4ffcf..b63f612d5ebf 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -256,9 +256,10 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry, inode = proc_get_inode(dir->i_sb, de); if (!inode) return ERR_PTR(-ENOMEM); + /* never reused and so never a mountpoint for long */ if (de->flags & PROC_ENTRY_FORCE_LOOKUP) - return d_splice_alias_ops(inode, dentry, - &proc_net_dentry_ops); + return proc_splice_unmountable(inode, dentry, + &proc_net_dentry_ops); return d_splice_alias_ops(inode, dentry, &proc_misc_dentry_ops); } diff --git a/fs/read_write.c b/fs/read_write.c index 833bae068770..011fe55c94cd 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -1530,9 +1530,11 @@ static int generic_copy_file_checks(struct file *file_in, loff_t pos_in, else count = min(count, size_in - (uint64_t)pos_in); - ret = generic_write_check_limits(file_out, pos_out, &count); - if (ret) - return ret; + if (count) { + ret = generic_write_check_limits(file_out, pos_out, &count); + if (ret) + return ret; + } /* Don't allow overlapped copying within the same file. */ if (inode_in == inode_out && diff --git a/fs/signalfd.c b/fs/signalfd.c index d469782f97f4..0aa1657bbedf 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -48,17 +48,30 @@ static int signalfd_release(struct inode *inode, struct file *file) return 0; } +static void refine_sigmask(struct signalfd_ctx *ctx, sigset_t *sigmask) +{ + struct k_sigaction *k = current->sighand->action; + int n; + + *sigmask = ctx->sigmask; + for (n = 1; n <= _NSIG; ++n, ++k) { + if (k->sa.sa_flags & SA_IMMUTABLE) + sigaddset(sigmask, n); + } +} + static __poll_t signalfd_poll(struct file *file, poll_table *wait) { struct signalfd_ctx *ctx = file->private_data; __poll_t events = 0; + sigset_t sigmask; poll_wait(file, ¤t->sighand->signalfd_wqh, wait); spin_lock_irq(¤t->sighand->siglock); - if (next_signal(¤t->pending, &ctx->sigmask) || - next_signal(¤t->signal->shared_pending, - &ctx->sigmask)) + refine_sigmask(ctx, &sigmask); + if (next_signal(¤t->pending, &sigmask) || + next_signal(¤t->signal->shared_pending, &sigmask)) events |= EPOLLIN; spin_unlock_irq(¤t->sighand->siglock); @@ -155,11 +168,13 @@ static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info int nonblock) { enum pid_type type; - ssize_t ret; DECLARE_WAITQUEUE(wait, current); + sigset_t sigmask; + ssize_t ret; spin_lock_irq(¤t->sighand->siglock); - ret = dequeue_signal(&ctx->sigmask, info, &type); + refine_sigmask(ctx, &sigmask); + ret = dequeue_signal(&sigmask, info, &type); switch (ret) { case 0: if (!nonblock) @@ -174,7 +189,7 @@ static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info add_wait_queue(¤t->sighand->signalfd_wqh, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); - ret = dequeue_signal(&ctx->sigmask, info, &type); + ret = dequeue_signal(&sigmask, info, &type); if (ret != 0) break; if (signal_pending(current)) { @@ -184,6 +199,7 @@ static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info spin_unlock_irq(¤t->sighand->siglock); schedule(); spin_lock_irq(¤t->sighand->siglock); + refine_sigmask(ctx, &sigmask); } spin_unlock_irq(¤t->sighand->siglock); diff --git a/fs/splice.c b/fs/splice.c index f5094b6d00a0..8ac45441e219 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1351,10 +1351,10 @@ ssize_t do_splice(struct file *in, loff_t *off_in, struct file *out, ret = do_splice_from(ipipe, out, &offset, len, flags); file_end_write(out); - if (!off_out) - out->f_pos = offset; - else + if (off_out) *off_out = offset; + else if (ret >= 0) + out->f_pos = offset; } else if (opipe) { if (off_out) return -ESPIPE; @@ -1375,10 +1375,10 @@ ssize_t do_splice(struct file *in, loff_t *off_in, struct file *out, ret = splice_file_to_pipe(in, opipe, &offset, len, flags); - if (!off_in) - in->f_pos = offset; - else + if (off_in) *off_in = offset; + else if (ret >= 0) + in->f_pos = offset; } else { ret = -EINVAL; } diff --git a/fs/stat.c b/fs/stat.c index 8c110555b3d7..3bc049f0bc3d 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -203,8 +203,12 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat, if (IS_DAX(inode)) stat->attributes |= STATX_ATTR_DAX; + if (IS_VERITY(inode)) + stat->attributes |= STATX_ATTR_VERITY; + stat->attributes_mask |= (STATX_ATTR_AUTOMOUNT | - STATX_ATTR_DAX); + STATX_ATTR_DAX | + STATX_ATTR_VERITY); idmap = mnt_idmap(path->mnt); if (inode->i_op->getattr) { diff --git a/fs/udf/super.c b/fs/udf/super.c index f91b231b7d7b..556540f2797a 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1611,7 +1611,10 @@ static bool udf_lvid_valid(struct super_block *sb, parts = le32_to_cpu(lvid->numOfPartitions); impuselen = le32_to_cpu(lvid->lengthOfImpUse); - if (parts >= sb->s_blocksize || impuselen >= sb->s_blocksize || + if (sizeof(struct logicalVolIntegrityDescImpUse) > impuselen || + impuselen >= sb->s_blocksize) + return false; + if (parts >= sb->s_blocksize || sizeof(struct logicalVolIntegrityDesc) + impuselen + 2 * parts * sizeof(u32) > sb->s_blocksize) return false; diff --git a/fs/verity/open.c b/fs/verity/open.c index 2aa5eae5a540..02e2c14ab3ff 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -273,12 +273,6 @@ static bool validate_fsverity_descriptor(struct inode *inode, const struct fsverity_descriptor *desc, size_t desc_size) { - if (desc_size < sizeof(*desc)) { - fsverity_err(inode, "Unrecognized descriptor size: %zu bytes", - desc_size); - return false; - } - if (desc->version != 1) { fsverity_err(inode, "Unrecognized descriptor version: %u", desc->version); @@ -317,31 +311,37 @@ static bool validate_fsverity_descriptor(struct inode *inode, int fsverity_get_descriptor(struct inode *inode, struct fsverity_descriptor **desc_ret) { - int res; + int size, res; struct fsverity_descriptor *desc; - res = inode->i_sb->s_vop->get_verity_descriptor(inode, NULL, 0); - if (res < 0) { - fsverity_err(inode, - "Error %d getting verity descriptor size", res); - return res; + size = inode->i_sb->s_vop->get_verity_descriptor(inode, NULL, 0); + if (size < 0) { + fsverity_err(inode, "Error %d getting verity descriptor size", + size); + return size; } - if (res > FS_VERITY_MAX_DESCRIPTOR_SIZE) { - fsverity_err(inode, "Verity descriptor is too large (%d bytes)", - res); + if (size < sizeof(*desc) || size > FS_VERITY_MAX_DESCRIPTOR_SIZE) { + fsverity_err(inode, + "Verity descriptor has invalid size (%d bytes)", + size); return -EMSGSIZE; } - desc = kmalloc(res, GFP_KERNEL); + desc = kmalloc(size, GFP_KERNEL); if (!desc) return -ENOMEM; - res = inode->i_sb->s_vop->get_verity_descriptor(inode, desc, res); + res = inode->i_sb->s_vop->get_verity_descriptor(inode, desc, size); if (res < 0) { fsverity_err(inode, "Error %d reading verity descriptor", res); kfree(desc); return res; } - - if (!validate_fsverity_descriptor(inode, desc, res)) { + if (res != size) { + fsverity_err(inode, "Verity descriptor size changed (%d => %d)", + size, res); + kfree(desc); + return -EINVAL; + } + if (!validate_fsverity_descriptor(inode, desc, size)) { kfree(desc); return -EINVAL; } diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h index 8c829d28dcf3..f55b51f33346 100644 --- a/include/linux/fault-inject.h +++ b/include/linux/fault-inject.h @@ -14,6 +14,13 @@ struct kmem_cache; #include #include +/* + * Length of the debugfs directory name embedded in struct fault_attr. + * Chosen to accommodate every in-tree caller of fault_create_debugfs_attr() + * (the longest is "fail_dma_array_full", 19 chars) with generous headroom. + */ +#define FAULT_ATTR_DNAME_LEN 64 + /* * For explanation of the elements of this struct, see * Documentation/fault-injection/fault-injection.rst @@ -33,7 +40,7 @@ struct fault_attr { unsigned long count; struct ratelimit_state ratelimit_state; - struct dentry *dname; + char dname[FAULT_ATTR_DNAME_LEN]; }; enum fault_flags { @@ -47,7 +54,6 @@ enum fault_flags { .stacktrace_depth = 32, \ .ratelimit_state = RATELIMIT_STATE_INIT_DISABLED, \ .verbose = 2, \ - .dname = NULL, \ } #define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER diff --git a/include/linux/fs.h b/include/linux/fs.h index 55ecd9d26b4f..349b7fc57db3 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -847,7 +847,9 @@ struct inode { /* 32-bit hole */ struct rw_semaphore i_rwsem; - unsigned long dirtied_when; /* jiffies of first dirtying */ + /* Timestamp for writeback list ordering and age checks (jiffies). */ + unsigned long dirtied_when; + /* Start time for deciding when lazytime updates need writeback (jiffies). */ unsigned long dirtied_time_when; struct hlist_node i_hash; diff --git a/include/linux/libata.h b/include/linux/libata.h index 868af0a08f52..a92908f07e22 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1136,6 +1136,7 @@ extern struct ata_host *ata_host_alloc_pinfo(struct device *dev, extern void ata_host_get(struct ata_host *host); extern void ata_host_put(struct ata_host *host); extern int ata_host_start(struct ata_host *host); +void ata_host_undo_start(struct ata_host *host); extern int ata_host_register(struct ata_host *host, const struct scsi_host_template *sht); extern int ata_host_activate(struct ata_host *host, int irq, diff --git a/include/linux/pci.h b/include/linux/pci.h index 95c77e2a1d1f..72d1ca12aaa8 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1413,7 +1413,7 @@ int pcie_set_mps(struct pci_dev *dev, int mps); u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev, enum pci_bus_speed *speed, enum pcie_link_width *width); -int pcie_link_speed_mbps(struct pci_dev *pdev); +int pcie_link_bandwidth_mbps(struct pci_dev *pdev); void pcie_print_link_status(struct pci_dev *dev); int pcie_reset_flr(struct pci_dev *dev, bool probe); int pcie_flr(struct pci_dev *dev); diff --git a/include/linux/pps_gen_kernel.h b/include/linux/pps_gen_kernel.h index f26f6aac000d..c4d22b1af118 100644 --- a/include/linux/pps_gen_kernel.h +++ b/include/linux/pps_gen_kernel.h @@ -11,6 +11,7 @@ #include #include #include +#include /* * Global defines @@ -44,6 +45,7 @@ struct pps_gen_source_info { /* The main struct */ struct pps_gen_device { const struct pps_gen_source_info *info; /* PSS generator info */ + struct mutex info_lock; /* protects info */ bool enabled; /* PSS generator status */ unsigned int event; diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 95da051fb155..116ac3cd5d54 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -13,6 +13,7 @@ #define _LINUX_RTC_H_ +#include #include #include #include @@ -199,6 +200,7 @@ extern void rtc_update_irq(struct rtc_device *rtc, extern struct rtc_device *rtc_class_open(const char *name); extern void rtc_class_close(struct rtc_device *rtc); +DEFINE_FREE(rtc_class_close, struct rtc_device *, if (_T) rtc_class_close(_T)); extern int rtc_irq_set_state(struct rtc_device *rtc, int enabled); extern int rtc_irq_set_freq(struct rtc_device *rtc, int freq); diff --git a/include/math-emu/op-common.h b/include/math-emu/op-common.h index 8ce066c035cf..1d1ce5c08efc 100644 --- a/include/math-emu/op-common.h +++ b/include/math-emu/op-common.h @@ -135,6 +135,24 @@ do { \ else \ { \ /* we've got a denormalized number */ \ + int _FP_PACK_CANONICAL_is_tiny = 1; \ + if (_FP_TININESS_AFTER_ROUNDING && X##_e == 0) \ + { \ + /* Architectures that detect tininess after rounding \ + only signal underflow if the result is still \ + subnormal once rounded as if the exponent range \ + were unbounded. Round a copy to find out. */ \ + FP_DECL_##fs(_FP_PACK_CANONICAL_T); \ + /* The class field is not used by the rounding below, \ + and is unused entirely where this block is dead. */ \ + (void)_FP_PACK_CANONICAL_T##_c; \ + _FP_FRAC_COPY_##wc(_FP_PACK_CANONICAL_T, X); \ + _FP_PACK_CANONICAL_T##_s = X##_s; \ + _FP_PACK_CANONICAL_T##_e = X##_e; \ + _FP_ROUND(wc, _FP_PACK_CANONICAL_T); \ + if (_FP_FRAC_OVERP_##wc(fs, _FP_PACK_CANONICAL_T)) \ + _FP_PACK_CANONICAL_is_tiny = 0; \ + } \ X##_e = -X##_e + 1; \ if (X##_e <= _FP_WFRACBITS_##fs) \ { \ @@ -161,8 +179,9 @@ do { \ _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ } \ } \ - if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) || \ - (FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW)) \ + if (_FP_PACK_CANONICAL_is_tiny \ + && ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) || \ + (FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW))) \ FP_SET_EXCEPTION(FP_EX_UNDERFLOW); \ } \ else \ diff --git a/include/math-emu/soft-fp.h b/include/math-emu/soft-fp.h index 5650c1628383..02ada0a9fca1 100644 --- a/include/math-emu/soft-fp.h +++ b/include/math-emu/soft-fp.h @@ -31,6 +31,14 @@ #include #endif +/* Whether the architecture determines tininess of a floating-point + result after rounding rather than before it. IEEE 754 permits either + but requires the same choice for every operation, so this has to agree + with what the hardware does for the results it produces itself. */ +#ifndef _FP_TININESS_AFTER_ROUNDING +#define _FP_TININESS_AFTER_ROUNDING 0 +#endif + #define _FP_WORKBITS 3 #define _FP_WORK_LSB ((_FP_W_TYPE)1 << 3) #define _FP_WORK_ROUND ((_FP_W_TYPE)1 << 2) diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 31fc1bee3797..b900734ee9c1 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -834,6 +834,9 @@ bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl); * * @ncontrols: The number of controls in this cluster. * @controls: The cluster control array of size @ncontrols. + * + * If controls[0] is NULL, then this function does nothing and just + * returns. */ void v4l2_ctrl_cluster(unsigned int ncontrols, struct v4l2_ctrl **controls); @@ -845,6 +848,9 @@ void v4l2_ctrl_cluster(unsigned int ncontrols, struct v4l2_ctrl **controls); * @ncontrols: The number of controls in this cluster. * @controls: The cluster control array of size @ncontrols. The first control * must be the 'auto' control (e.g. autogain, autoexposure, etc.) + * + * If controls[0] is NULL, then this function does nothing and just + * returns. * @manual_val: The value for the first control in the cluster that equals the * manual setting. * @set_volatile: If true, then all controls except the first auto control will diff --git a/include/net/addrconf.h b/include/net/addrconf.h index b353dea9aedc..03d6543a5189 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -80,6 +80,9 @@ struct ifa6_config { u8 ifa_proto; const struct in6_addr *peer_pfx; + struct inet6_ifaddr *ifpub; + unsigned long cstamp; + unsigned long tstamp; u32 rt_priority; u32 ifa_flags; diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index d50e0afc3193..39ccb785dd4c 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -297,14 +297,6 @@ static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk) bool inet_csk_reqsk_queue_drop(struct sock *sk, struct request_sock *req); void inet_csk_reqsk_queue_drop_and_put(struct sock *sk, struct request_sock *req); -static inline unsigned long -reqsk_timeout(struct request_sock *req, unsigned long max_timeout) -{ - u64 timeout = (u64)req->timeout << req->num_timeout; - - return (unsigned long)min_t(u64, timeout, max_timeout); -} - void inet_csk_destroy_sock(struct sock *sk); void inet_csk_prepare_for_destroy_sock(struct sock *sk); void inet_csk_prepare_forced_close(struct sock *sk); diff --git a/include/net/ip.h b/include/net/ip.h index 5041202ccce2..86e555fb6897 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -513,31 +513,6 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst, return res; } -/* Configured/administrative MTU of a route, for advertising the TCP MSS. - * - * Unlike ip_dst_mtu_maybe_forward(), this deliberately ignores the - * ICMP-learned path MTU (rt->rt_pmtu). The advertised MSS bounds what the - * peer may send to us and must reflect our receive capability (the device or - * route-configured MTU), not a path MTU learned on the reverse (send) - * direction, which may not apply to the peer->us path and outlives the fnhe - * for the whole connection. See RFC 2923 section 2.3 and the comment above - * tcp_advertise_mss(). - */ -static inline unsigned int ip_dst_mtu_configured(const struct dst_entry *dst) -{ - unsigned int mtu, res; - - rcu_read_lock(); - mtu = dst_metric_raw(dst, RTAX_MTU); - if (!mtu) - mtu = READ_ONCE(dst_dev_rcu(dst)->mtu); - mtu = min_t(unsigned int, mtu, IP_MAX_MTU); - res = mtu - lwtunnel_headroom(dst->lwtstate, mtu); - rcu_read_unlock(); - - return res; -} - static inline unsigned int ip_skb_dst_mtu(struct sock *sk, const struct sk_buff *skb) { diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 4137bdf05baa..956ebbebd53c 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -354,43 +354,6 @@ static inline unsigned int ip6_dst_mtu_maybe_forward(const struct dst_entry *dst return mtu - lwtunnel_headroom(dst->lwtstate, mtu); } -/* Configured/administrative MTU of a route, for advertising the TCP MSS. - * - * Unlike ip6_dst_mtu_maybe_forward(), this ignores any ICMPv6-learned path - * MTU (which is kept on the RTF_CACHE exception route) and returns the MTU of - * the underlying route (fib6_pmtu) or the egress device. The advertised MSS - * bounds what the peer may send to us and must reflect our receive - * capability, not a path MTU learned on the reverse (send) direction. See - * RFC 2923 section 2.3 and the comment above tcp_advertise_mss(). - */ -static inline unsigned int ip6_dst_mtu_configured(const struct dst_entry *dst) -{ - const struct rt6_info *rt = dst_rt6_info(dst); - const struct fib6_info *from; - struct inet6_dev *idev; - unsigned int mtu = 0; - - rcu_read_lock(); - /* IPv6 keeps the learned PMTU and the configured MTU in the same - * RTAX_MTU slot: the learned value sits on this (possibly RTF_CACHE) - * dst, the configured one on the underlying route. Reach the latter - * via ->from (fib6_pmtu), populated by ip6_route_info_create(). - */ - from = rcu_dereference(rt->from); - if (from) - mtu = from->fib6_pmtu; - if (!mtu) { - mtu = IPV6_MIN_MTU; - idev = __in6_dev_get(dst_dev_rcu(dst)); - if (idev) - mtu = max_t(unsigned int, mtu, READ_ONCE(idev->cnf.mtu6)); - } - rcu_read_unlock(); - - mtu = min_t(unsigned int, mtu, IP6_MAX_MTU); - return mtu - lwtunnel_headroom(dst->lwtstate, mtu); -} - u32 ip6_mtu_from_fib6(const struct fib6_result *res, const struct in6_addr *daddr, const struct in6_addr *saddr); diff --git a/include/net/mptcp.h b/include/net/mptcp.h index f7263fe2a2e4..a296f711e92f 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -219,6 +219,9 @@ int mptcp_subflow_init_cookie_req(struct request_sock *req, struct request_sock *mptcp_subflow_reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk_listener, bool attach_listener); +/* Caller must hold an RCU read-side lock. */ +void mptcp_subflow_reqsk_clone(struct request_sock *req, + struct request_sock *new_req); __be32 mptcp_get_reset_option(const struct sk_buff *skb); @@ -314,6 +317,12 @@ static inline struct request_sock *mptcp_subflow_reqsk_alloc(const struct reques return NULL; } +/* Caller must hold an RCU read-side lock. */ +static inline void mptcp_subflow_reqsk_clone(struct request_sock *req, + struct request_sock *new_req) +{ +} + static inline __be32 mptcp_reset_option(const struct sk_buff *skb) { return htonl(0u); } static inline void mptcp_active_detect_blackhole(struct sock *sk, bool expired) { } diff --git a/include/net/tcp.h b/include/net/tcp.h index e40bad560648..f9bcfa8773a3 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -838,6 +838,13 @@ static inline u32 __tcp_set_rto(const struct tcp_sock *tp) return usecs_to_jiffies((tp->srtt_us >> 3) + tp->rttvar_us); } +static inline unsigned long tcp_reqsk_timeout(struct request_sock *req) +{ + u64 timeout = (u64)req->timeout << req->num_timeout; + + return (unsigned long)min_t(u64, timeout, TCP_RTO_MAX); +} + u32 tcp_delack_max(const struct sock *sk); /* Compute the actual rto_min value */ diff --git a/include/trace/events/huge_memory.h b/include/trace/events/huge_memory.h index 2276614691df..1464d45c90ab 100644 --- a/include/trace/events/huge_memory.h +++ b/include/trace/events/huge_memory.h @@ -167,10 +167,10 @@ TRACE_EVENT(mm_collapse_huge_page_swapin, TRACE_EVENT(mm_khugepaged_scan_file, - TP_PROTO(struct mm_struct *mm, struct folio *folio, struct file *file, + TP_PROTO(struct mm_struct *mm, unsigned long pfn, struct file *file, int present, int swap, int result), - TP_ARGS(mm, folio, file, present, swap, result), + TP_ARGS(mm, pfn, file, present, swap, result), TP_STRUCT__entry( __field(struct mm_struct *, mm) @@ -183,7 +183,7 @@ TRACE_EVENT(mm_khugepaged_scan_file, TP_fast_assign( __entry->mm = mm; - __entry->pfn = folio ? folio_pfn(folio) : -1; + __entry->pfn = pfn; __assign_str(filename); __entry->present = present; __entry->swap = swap; diff --git a/init/main.c b/init/main.c index 269b30038b9f..2097f4bbc0d8 100644 --- a/init/main.c +++ b/init/main.c @@ -910,12 +910,12 @@ void start_kernel(void) __stop___param - __start___param, -1, -1, NULL, &unknown_bootoption); print_unknown_bootoptions(); - if (!IS_ERR_OR_NULL(after_dashes)) - parse_args("Setting init args", after_dashes, NULL, 0, -1, -1, - NULL, set_init_arg); if (extra_init_args) parse_args("Setting extra init args", extra_init_args, NULL, 0, -1, -1, NULL, set_init_arg); + if (!IS_ERR_OR_NULL(after_dashes)) + parse_args("Setting init args", after_dashes, NULL, 0, -1, -1, + NULL, set_init_arg); /* Architectural and non-timekeeping rng init, before allocator init */ random_init_early(command_line); diff --git a/init/version.c b/init/version.c index 94c96f6fbfe6..0bd5c45aabc4 100644 --- a/init/version.c +++ b/init/version.c @@ -23,6 +23,9 @@ static int __init early_hostname(char *arg) size_t maxlen = bufsize - 1; ssize_t arglen; + if (!arg) + return -EINVAL; + arglen = strscpy(init_uts_ns.name.nodename, arg, bufsize); if (arglen < 0) { pr_warn("hostname parameter exceeds %zd characters and will be truncated", diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 093551fe66a7..11eaf5df3645 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -529,6 +529,13 @@ static void mqueue_evict_inode(struct inode *inode) list_add_tail(&msg->m_list, &tmp_msg); kfree(info->node_cache); spin_unlock(&info->lock); + /* + * A shared file table can let the notification owner exit without + * running ->flush(). No users of the inode remain during eviction, so + * tear down any stale notification after dropping info->lock because + * netlink_sendskb() may release the final socket reference. + */ + remove_notification(info); list_for_each_entry_safe(msg, nmsg, &tmp_msg, m_list) { list_del(&msg->m_list); diff --git a/ipc/msgutil.c b/ipc/msgutil.c index 7a03f6d03de3..2b93abb808e7 100644 --- a/ipc/msgutil.c +++ b/ipc/msgutil.c @@ -63,7 +63,8 @@ static struct msg_msg *alloc_msg(size_t len) size_t alen; alen = min(len, DATALEN_MSG); - msg = kmem_buckets_alloc(msg_buckets, sizeof(*msg) + alen, GFP_KERNEL); + msg = kmem_buckets_alloc(msg_buckets, sizeof(*msg) + alen, + GFP_KERNEL_ACCOUNT); if (msg == NULL) return NULL; diff --git a/ipc/shm.c b/ipc/shm.c index c77a6c8683ce..2f5cee0c78c7 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -936,26 +936,11 @@ static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminf static void shm_add_rss_swap(struct shmid_kernel *shp, unsigned long *rss_add, unsigned long *swp_add) { - struct inode *inode; + struct inode *inode = file_inode(shp->shm_file); - inode = file_inode(shp->shm_file); - - if (is_file_hugepages(shp->shm_file)) { - struct address_space *mapping = inode->i_mapping; - struct hstate *h = hstate_file(shp->shm_file); - *rss_add += pages_per_huge_page(h) * mapping->nrpages; - } else { -#ifdef CONFIG_SHMEM - struct shmem_inode_info *info = SHMEM_I(inode); - - spin_lock_irq(&info->lock); - *rss_add += inode->i_mapping->nrpages; - *swp_add += info->swapped; - spin_unlock_irq(&info->lock); -#else - *rss_add += inode->i_mapping->nrpages; -#endif - } + *rss_add += READ_ONCE(inode->i_mapping->nrpages); + if (IS_ENABLED(CONFIG_SHMEM) && !is_file_hugepages(shp->shm_file)) + *swp_add += READ_ONCE(SHMEM_I(inode)->swapped); } /* diff --git a/kernel/bpf/queue_stack_maps.c b/kernel/bpf/queue_stack_maps.c index c1c9dee4dcdd..b5628e414981 100644 --- a/kernel/bpf/queue_stack_maps.c +++ b/kernel/bpf/queue_stack_maps.c @@ -59,6 +59,9 @@ static int queue_stack_map_alloc_check(union bpf_attr *attr) */ return -E2BIG; + if (attr->max_entries >= U32_MAX / attr->value_size) + return -E2BIG; + return 0; } diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 07e1e2922819..aa629b7d76e5 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -4219,7 +4219,7 @@ static void __cgroup_kill(struct cgroup *cgrp) cgrp->kill_seq++; spin_unlock_irq(&css_set_lock); - css_task_iter_start(&cgrp->self, CSS_TASK_ITER_PROCS | CSS_TASK_ITER_THREADED, &it); + css_task_iter_start(&cgrp->self, CSS_TASK_ITER_THREADED, &it); while ((task = css_task_iter_next(&it))) { /* Ignore kernel threads here. */ if (task->flags & PF_KTHREAD) diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c index 7481fbb947d3..a2a598ad6e6d 100644 --- a/kernel/cpu_pm.c +++ b/kernel/cpu_pm.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -76,7 +77,8 @@ EXPORT_SYMBOL_GPL(cpu_pm_register_notifier); * * Remove a driver from the CPU PM notifier list. * - * This function has the same return conditions as raw_notifier_chain_unregister. + * This function may sleep, and has the same return conditions as + * raw_notifier_chain_unregister. */ int cpu_pm_unregister_notifier(struct notifier_block *nb) { @@ -86,6 +88,11 @@ int cpu_pm_unregister_notifier(struct notifier_block *nb) raw_spin_lock_irqsave(&cpu_pm_notifier.lock, flags); ret = raw_notifier_chain_unregister(&cpu_pm_notifier.chain, nb); raw_spin_unlock_irqrestore(&cpu_pm_notifier.lock, flags); + + /* Wait for the rcu_read_lock() walkers in cpu_pm_notify(). */ + if (!ret) + synchronize_rcu(); + return ret; } EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier); diff --git a/kernel/debug/gdbstub.c b/kernel/debug/gdbstub.c index 22fe969c5d2e..1a917c5bdd1e 100644 --- a/kernel/debug/gdbstub.c +++ b/kernel/debug/gdbstub.c @@ -42,6 +42,8 @@ /* Our I/O buffers. */ static char remcom_in_buffer[BUFMAX]; static char remcom_out_buffer[BUFMAX]; +/* Payload bytes get_packet() stored in remcom_in_buffer, excluding the NUL. */ +static int remcom_in_len; static int gdbstub_use_prev_in_buf; static int gdbstub_prev_in_buf_pos; @@ -86,7 +88,7 @@ static int gdbstub_read_wait(void) } #endif /* scan for the sequence $# */ -static void get_packet(char *buffer) +static int get_packet(char *buffer) { unsigned char checksum; unsigned char xmitcsum; @@ -134,6 +136,8 @@ static void get_packet(char *buffer) } buffer[count] = 0; } while (checksum != xmitcsum); + + return count; } /* @@ -320,16 +324,26 @@ int kgdb_hex2long(char **ptr, unsigned long *long_val) * Copy the binary array pointed to by buf into mem. Fix $, #, and * 0x7d escaped with 0x7d. Return -EFAULT on failure or 0 on success. * The input buf is overwritten with the result to write to mem. + * + * buf_end points one past the last byte received for this packet. Each + * 0x7d escape consumes a second input byte, so decoding count bytes can + * read up to 2 * count input bytes; stop at buf_end rather than running + * off the end of remcom_in_buffer. */ -static int kgdb_ebin2mem(char *buf, char *mem, int count) +static int kgdb_ebin2mem(char *buf, char *mem, int count, char *buf_end) { int size = 0; char *c = buf; while (count-- > 0) { + if (buf >= buf_end) + return -EINVAL; c[size] = *buf++; - if (c[size] == 0x7d) + if (c[size] == 0x7d) { + if (buf >= buf_end) + return -EINVAL; c[size] = *buf++ ^ 0x20; + } size++; } @@ -366,16 +380,33 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) static int write_mem_msg(int binary) { char *ptr = &remcom_in_buffer[1]; + char *buf_end = &remcom_in_buffer[remcom_in_len]; unsigned long addr; unsigned long length; int err; if (kgdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ',' && kgdb_hex2long(&ptr, &length) > 0 && *(ptr++) == ':') { - if (binary) - err = kgdb_ebin2mem(ptr, (char *)addr, length); - else + /* + * Trust only the bytes actually received, not length: the + * client can claim more payload than it sent. 'M' decodes two + * hex chars per byte in place, so it needs 2 * length bytes at + * ptr; 'X' decodes one byte per byte, and kgdb_ebin2mem() bounds + * its extra 0x7d-escape reads against buf_end itself. + */ + if (ptr >= buf_end) + return -EINVAL; + + if (binary) { + if (length > (unsigned long)(buf_end - ptr)) + return -EINVAL; + err = kgdb_ebin2mem(ptr, (char *)addr, length, buf_end); + } else { + if (length > (unsigned long)(buf_end - ptr) / 2) + return -EINVAL; err = kgdb_hex2mem(ptr, (char *)addr, length); + } + if (err) return err; if (CACHE_FLUSH_IS_SAFE) @@ -562,6 +593,14 @@ static void gdb_cmd_memread(struct kgdb_state *ks) if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && kgdb_hex2long(&ptr, &length) > 0) { + /* + * The hex-encoded reply needs 2 * length + 1 bytes + * in remcom_out_buffer[BUFMAX]. + */ + if (length > (BUFMAX - 1) / 2) { + error_packet(remcom_out_buffer, -EINVAL); + return; + } err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length); if (!err) error_packet(remcom_out_buffer, -EINVAL); @@ -777,9 +816,9 @@ static void gdb_cmd_query(struct kgdb_state *ks) strscpy(remcom_out_buffer, "E01"); break; } + len = len / 2; kgdb_hex2mem(remcom_in_buffer + 6, remcom_out_buffer, len); - len = len / 2; remcom_out_buffer[len++] = 0; kdb_common_init_state(ks); @@ -984,7 +1023,7 @@ int gdb_serial_stub(struct kgdb_state *ks) /* Clear the out buffer. */ memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); - get_packet(remcom_in_buffer); + remcom_in_len = get_packet(remcom_in_buffer); switch (remcom_in_buffer[0]) { case '?': /* gdbserial status */ diff --git a/kernel/fork.c b/kernel/fork.c index b7543a93f269..bc6078b910a6 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -810,7 +810,8 @@ void __init fork_init(void) #ifndef ARCH_MIN_TASKALIGN #define ARCH_MIN_TASKALIGN 0 #endif - int align = max_t(int, L1_CACHE_BYTES, ARCH_MIN_TASKALIGN); + int align = max3(L1_CACHE_BYTES, ARCH_MIN_TASKALIGN, + __alignof__(struct task_struct)); unsigned long useroffset, usersize; /* create a slab on which task_structs can be allocated */ diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index d197854a93c8..97e50ade3bb9 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -78,6 +78,7 @@ enum { #include "settings.h" extern int __irq_set_trigger(struct irq_desc *desc, unsigned long flags); +extern int __irq_set_irqchip_state(struct irq_desc *desc, enum irqchip_irq_state which, bool val); extern void __disable_irq(struct irq_desc *desc); extern void __enable_irq(struct irq_desc *desc); diff --git a/kernel/irq/kexec.c b/kernel/irq/kexec.c index 1a3deffe6b5b..f245b9876422 100644 --- a/kernel/irq/kexec.c +++ b/kernel/irq/kexec.c @@ -25,7 +25,7 @@ void machine_kexec_mask_interrupts(void) * First try to remove the active state from an interrupt which is forwarded * to a VM. If the interrupt is not forwarded, try to EOI the interrupt. */ - check_eoi = irq_set_irqchip_state(i, IRQCHIP_STATE_ACTIVE, false); + check_eoi = __irq_set_irqchip_state(desc, IRQCHIP_STATE_ACTIVE, false); } if (check_eoi && chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data)) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index a0b79bcc0e08..19eda7aa9feb 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -2702,6 +2702,28 @@ int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, bool * } EXPORT_SYMBOL_GPL(irq_get_irqchip_state); +int __irq_set_irqchip_state(struct irq_desc *desc, enum irqchip_irq_state which, bool val) +{ + struct irq_data *data = irq_desc_get_irq_data(desc); + struct irq_chip *chip; + + do { + chip = irq_data_get_irq_chip(data); + + if (WARN_ON_ONCE(!chip)) + return -ENODEV; + + if (chip->irq_set_irqchip_state) + break; + + data = irqd_get_parent_data(data); + } while (data); + + if (data) + return chip->irq_set_irqchip_state(data, which, val); + return -EINVAL; +} + /** * irq_set_irqchip_state - set the state of a forwarded interrupt. * @irq: Interrupt line that is forwarded to a VM @@ -2716,25 +2738,8 @@ EXPORT_SYMBOL_GPL(irq_get_irqchip_state); */ int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, bool val) { - scoped_irqdesc_get_and_buslock(irq, 0) { - struct irq_data *data = irq_desc_get_irq_data(scoped_irqdesc); - struct irq_chip *chip; - - do { - chip = irq_data_get_irq_chip(data); - - if (WARN_ON_ONCE(!chip)) - return -ENODEV; - - if (chip->irq_set_irqchip_state) - break; - - data = irqd_get_parent_data(data); - } while (data); - - if (data) - return chip->irq_set_irqchip_state(data, which, val); - } + scoped_irqdesc_get_and_buslock(irq, 0) + return __irq_set_irqchip_state(scoped_irqdesc, which, val); return -EINVAL; } EXPORT_SYMBOL_GPL(irq_set_irqchip_state); diff --git a/kernel/panic.c b/kernel/panic.c index b13f040680ac..7f8725f2154b 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -364,7 +364,8 @@ void nmi_panic(struct pt_regs *regs, const char *msg) { if (panic_try_start()) panic("%s", msg); - else if (panic_on_other_cpu()) + + if (panic_on_other_cpu()) nmi_panic_self_stop(regs); } EXPORT_SYMBOL(nmi_panic); diff --git a/kernel/resource.c b/kernel/resource.c index fe1327753a13..139fb5e19cbe 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -1300,8 +1300,8 @@ static int __request_region_locked(struct resource *res, struct resource *parent } if (conflict->flags & flags & IORESOURCE_MUXED) { add_wait_queue(&muxed_resource_wait, &wait); - write_unlock(&resource_lock); set_current_state(TASK_UNINTERRUPTIBLE); + write_unlock(&resource_lock); schedule(); remove_wait_queue(&muxed_resource_wait, &wait); write_lock(&resource_lock); diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index 22a1fbccb929..9b5db92744ae 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -72,6 +72,18 @@ static void sugov_update_rate_limit_us(struct sugov_policy *sg_policy) (s64)sg_policy->tunables->rate_limit_us * NSEC_PER_USEC; } +static void sugov_update_rate_limit_us_sync(struct sugov_policy *sg_policy) +{ + /* + * Serialize with rate_limit_us_store() to prevent this path from using + * a stale rate limit tunable value to set the limit for the given + * policy. + */ + guard(mutex)(&sg_policy->tunables->attr_set.update_lock); + + sugov_update_rate_limit_us(sg_policy); +} + static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time) { s64 delta_ns; @@ -859,7 +871,7 @@ static int sugov_start(struct cpufreq_policy *policy) void (*uu)(struct update_util_data *data, u64 time, unsigned int flags); unsigned int cpu; - sugov_update_rate_limit_us(sg_policy); + sugov_update_rate_limit_us_sync(sg_policy); sg_policy->last_freq_update_time = 0; sg_policy->next_freq = 0; sg_policy->work_in_progress = false; diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 67e8c2065d82..fbc277c6963c 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -2794,7 +2794,7 @@ static void update_task_scan_period(struct task_struct *p, p->mm->numa_next_scan = jiffies + msecs_to_jiffies(p->numa_scan_period); - return; + goto out; } /* @@ -2838,7 +2838,10 @@ static void update_task_scan_period(struct task_struct *p, p->numa_scan_period = clamp(p->numa_scan_period + diff, task_scan_min(p), task_scan_max(p)); - memset(p->numa_faults_locality, 0, sizeof(p->numa_faults_locality)); + +out: + memset(p->numa_faults_locality, 0, + sizeof(p->numa_faults_locality)); } /* diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 25f62867a16d..7fc3b3b13875 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -1810,10 +1810,13 @@ static long seccomp_notify_addfd(struct seccomp_filter *filter, * We need to check again if the addfd request has been handled, * and if not, we will remove it from the queue. */ - if (list_empty(&kaddfd.list)) + if (list_empty(&kaddfd.list)) { ret = kaddfd.ret; - else + } else { list_del(&kaddfd.list); + if (addfd.flags & SECCOMP_ADDFD_FLAG_SEND) + knotif->state = SECCOMP_NOTIFY_SENT; + } out_unlock: mutex_unlock(&filter->notify_lock); diff --git a/kernel/sys.c b/kernel/sys.c index c8376d7a0741..bc89bd133111 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1077,6 +1077,9 @@ SYSCALL_DEFINE1(times, struct tms __user *, tbuf) #ifdef CONFIG_COMPAT static compat_clock_t clock_t_to_compat_clock_t(clock_t x) { + if (USER_HZ == COMPAT_USER_HZ) + return x; + return compat_jiffies_to_clock_t(clock_t_to_jiffies(x)); } diff --git a/kernel/time/itimer.c b/kernel/time/itimer.c index 03a32dffc56c..f7de39769095 100644 --- a/kernel/time/itimer.c +++ b/kernel/time/itimer.c @@ -60,7 +60,7 @@ static void get_cpu_itimer(struct task_struct *tsk, unsigned int clock_id, thread_group_sample_cputime(tsk, samples); t = samples[clock_id]; - if (val < t) + if (val <= t) /* about to fire */ val = TICK_NSEC; else diff --git a/kernel/time/namespace.c b/kernel/time/namespace.c index 99dcdb3315db..632f33157284 100644 --- a/kernel/time/namespace.c +++ b/kernel/time/namespace.c @@ -51,7 +51,7 @@ ktime_t do_timens_ktime_to_host(clockid_t clockid, ktime_t tim, tim = 0; } else { tim = ktime_sub(tim, offset); - if (unlikely(tim > KTIME_MAX)) + if (unlikely(tim < 0)) tim = KTIME_MAX; } diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index b3d4bae9ee3e..fcb98cbb1219 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -1597,8 +1597,8 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, */ expires = cpu_timer_getexpires(&timer.it.cpu); error = posix_cpu_timer_set(&timer, 0, &zero_it, &it); - if (!error) { - /* Timer is now unarmed, deletion can not fail. */ + if (error != TIMER_RETRY) { + /* Unarmed or target gone (-ESRCH), deletion can not fail. */ posix_cpu_timer_del(&timer); } else { while (error == TIMER_RETRY) { diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 377e29ca5a52..32f59de2ba4c 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -2569,6 +2569,7 @@ ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real, ktime_t *offs_boot, ktime_t *offs_tai) { struct timekeeper *tk = &tk_core.timekeeper; + u32 cwsseq_orig = *cwsseq; unsigned int seq; ktime_t base; u64 nsecs; @@ -2580,7 +2581,7 @@ ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real, nsecs = timekeeping_get_ns(&tk->tkr_mono); base = ktime_add_ns(base, nsecs); - if (*cwsseq != tk->clock_was_set_seq) { + if (cwsseq_orig != tk->clock_was_set_seq) { *cwsseq = tk->clock_was_set_seq; *offs_real = tk->offs_real; *offs_boot = tk->offs_boot; diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index f74acc78866d..dcb762664ce7 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -7004,6 +7004,8 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order) if (psize > RB_WRITE_MASK + 1) return -EINVAL; + guard(cpus_read_lock)(); + /* prevent another thread from changing buffer sizes */ guard(mutex)(&buffer->mutex); diff --git a/kernel/ucount.c b/kernel/ucount.c index fc4a8f2d3096..5cbf1553658e 100644 --- a/kernel/ucount.c +++ b/kernel/ucount.c @@ -302,23 +302,26 @@ long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum rlimit_type type, for (iter = ucounts; iter; iter = iter->ns->ucounts) { long new = atomic_long_add_return(1, &iter->rlimit[type]); - if (new < 0 || new > max) + /* + * Take the extra reference on the 0 -> 1 transition before the + * limit check: a rejected walk must not leave a concurrent one + * holding the surviving increment with no reference. + */ + if (new == 1 && !get_ucounts(iter)) goto dec_unwind; + if (new < 0 || new > max) { + /* undo iter too, releasing the reference taken above */ + do_dec_rlimit_put_ucounts(ucounts, iter->ns->ucounts, type); + return 0; + } if (iter == ucounts) ret = new; if (!override_rlimit) max = get_userns_rlimit_max(iter->ns, type); - /* - * Grab an extra ucount reference for the caller when - * the rlimit count was previously 0. - */ - if (new != 1) - continue; - if (!get_ucounts(iter)) - goto dec_unwind; } return ret; dec_unwind: + /* get_ucounts() failed for iter: undo iter without a put */ dec = atomic_long_sub_return(1, &iter->rlimit[type]); WARN_ON_ONCE(dec < 0); do_dec_rlimit_put_ucounts(ucounts, iter, type); diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 03cb63883d04..702f934e69a9 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -45,8 +45,11 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns) { /* Start with the same capabilities as init but useless for doing * anything as the capabilities are bound to the new user namespace. + * The exec securebits grant nothing, they are restrictions the task + * placed on itself. Keep them and their locks. */ - cred->securebits = SECUREBITS_DEFAULT; + cred->securebits = SECUREBITS_DEFAULT | + (cred->securebits & (SECURE_ALL_UNPRIVILEGED | SECURE_ALL_UNPRIVILEGED << 1)); cred->cap_inheritable = CAP_EMPTY_SET; cred->cap_permitted = CAP_FULL_SET; cred->cap_effective = CAP_FULL_SET; diff --git a/lib/842/842_decompress.c b/lib/842/842_decompress.c index 582085ef8b49..45a9815abd63 100644 --- a/lib/842/842_decompress.c +++ b/lib/842/842_decompress.c @@ -165,6 +165,9 @@ static int __do_index(struct sw842_param *p, u8 size, u8 bits, u64 fsize) u64 index, offset, total = round_down(p->out - p->ostart, 8); int ret; + if (size > p->olen) + return -ENOSPC; + ret = next_bits(p, &index, bits); if (ret) return ret; @@ -306,7 +309,7 @@ int sw842_decompress(const u8 *in, unsigned int ilen, if (ret) return ret; - if (p.out == out) /* no previous bytes */ + if (p.out - p.ostart < 8) /* no complete previous block */ return -EINVAL; /* copy rep + 1 */ @@ -344,6 +347,8 @@ int sw842_decompress(const u8 *in, unsigned int ilen, if (!bytes || bytes > SHORT_DATA_BITS_MAX) return -EINVAL; + if (bytes > p.olen) + return -ENOSPC; while (bytes-- > 0) { ret = next_bits(&p, &tmp, 8); diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c index 7c6d3a086fdc..fbe9e6c99521 100644 --- a/lib/alloc_tag.c +++ b/lib/alloc_tag.c @@ -276,7 +276,7 @@ void __init alloc_tag_sec_init(void) kernel_tags.count = last_codetag - kernel_tags.first_tag; /* Check if kernel tags fit into page flags */ - if (kernel_tags.count > (1UL << NR_UNUSED_PAGEFLAG_BITS)) { + if (CODETAG_ID_FIRST + kernel_tags.count > (1UL << NR_UNUSED_PAGEFLAG_BITS)) { shutdown_mem_profiling(false); /* allocinfo file does not exist yet */ pr_err("%lu allocation tags cannot be references using %d available page flag bits. Memory allocation profiling is disabled!\n", kernel_tags.count, NR_UNUSED_PAGEFLAG_BITS); diff --git a/lib/buildid.c b/lib/buildid.c index ef112a7084ef..015a1f9d2b48 100644 --- a/lib/buildid.c +++ b/lib/buildid.c @@ -66,6 +66,10 @@ static int freader_get_folio(struct freader *r, loff_t file_off) freader_put_folio(r); + /* the page index must fit in pgoff_t */ + if (file_off < 0 || file_off > MAX_LFS_FILESIZE) + return -EFAULT; + /* only use page cache lookup - fail if not already cached */ r->folio = filemap_get_folio(r->file->f_mapping, file_off >> PAGE_SHIFT); diff --git a/lib/decompress_bunzip2.c b/lib/decompress_bunzip2.c index ca736166f100..b8fb40ed06d2 100644 --- a/lib/decompress_bunzip2.c +++ b/lib/decompress_bunzip2.c @@ -428,6 +428,10 @@ static int INIT get_next_block(struct bunzip_data *bd) t += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */ + /* Bound the run so t and runPos cannot overflow. */ + if (t >= dbufSize) + return RETVAL_DATA_ERROR; + runPos <<= 1; continue; } @@ -439,7 +443,7 @@ static int INIT get_next_block(struct bunzip_data *bd) array.) */ if (runPos) { runPos = 0; - if (dbufCount+t >= dbufSize) + if (dbufCount+t > dbufSize) return RETVAL_DATA_ERROR; uc = symToByte[mtfSymbol[0]]; diff --git a/lib/fault-inject.c b/lib/fault-inject.c index 999053fa133e..02916ef2761c 100644 --- a/lib/fault-inject.c +++ b/lib/fault-inject.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -64,7 +65,7 @@ static void fail_dump(struct fault_attr *attr) { if (attr->verbose > 0 && __ratelimit(&attr->ratelimit_state)) { printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure.\n" - "name %pd, interval %lu, probability %lu, " + "name %s, interval %lu, probability %lu, " "space %d, times %d\n", attr->dname, attr->interval, attr->probability, atomic_read(&attr->space), @@ -261,7 +262,9 @@ struct dentry *fault_create_debugfs_attr(const char *name, debugfs_create_xul("reject-end", mode, dir, &attr->reject_end); #endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */ - attr->dname = dget(dir); + if (strscpy(attr->dname, name, sizeof(attr->dname)) == -E2BIG) + pr_warn("FAULT_INJECTION: name '%s' truncated to '%s'\n", + name, attr->dname); return dir; } EXPORT_SYMBOL_GPL(fault_create_debugfs_attr); diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 4bc7c1933755..b2eb629497a9 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -836,6 +836,10 @@ unsigned long iov_iter_alignment(const struct iov_iter *i) return 0; } + /* An empty iterator may have no segment array at all. */ + if (!i->count) + return 0; + /* iovec and kvec have identical layouts */ if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i))) return iov_iter_alignment_iovec(i); diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 5a2480467ab9..bdc2720b7aac 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -83,7 +83,7 @@ static int kobject_action_type(const char *buf, size_t count, for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) { if (strncmp(kobject_actions[action], buf, count_first) != 0) continue; - if (kobject_actions[action][count_first] != '\0') + if (strlen(kobject_actions[action]) != count_first) continue; if (args) *args = args_start; diff --git a/lib/plist.c b/lib/plist.c index 330febb4bd7d..1e9cb0e35af7 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -174,8 +174,15 @@ void plist_requeue(struct plist_node *node, struct plist_head *head) /* * After plist_del(), iter is the replacement of the node. If the node * was on prio_list, take shortcut to find node_next instead of looping. + * + * prio_list is a headless ring, so from the LAST bucket ->next wraps + * round to the first one; in that case node_next is the list head. */ if (!list_empty(&iter->prio_list)) { + struct plist_node *first = plist_first(head); + + if (iter->prio_list.next == &first->prio_list) + goto queue; iter = list_entry(iter->prio_list.next, struct plist_node, prio_list); node_next = &iter->node_list; diff --git a/lib/stackdepot.c b/lib/stackdepot.c index de0b0025af2b..b20f4db5c83f 100644 --- a/lib/stackdepot.c +++ b/lib/stackdepot.c @@ -322,7 +322,7 @@ static bool depot_init_pool(void **prealloc) * NULL; do not reset to NULL if we have reached the maximum number of * pools. */ - if (pools_num < stack_max_pools) + if (pools_num + 1 < stack_max_pools) WRITE_ONCE(new_pool, NULL); else WRITE_ONCE(new_pool, STACK_DEPOT_POISON); diff --git a/mm/damon/core.c b/mm/damon/core.c index 8fa788b0d709..56f2343ffefa 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -2004,6 +2004,7 @@ static void damos_apply_scheme(struct damon_ctx *c, struct damon_target *t, } if (damos_filter_out(c, t, r, s)) return; + sz = damon_sz_region(r); ktime_get_coarse_ts64(&begin); trace_damos_before_apply(cidx, sidx, tidx, r, damon_nr_regions(t), do_trace); @@ -2145,6 +2146,13 @@ static __kernel_ulong_t damos_get_node_mem_bp( } si_meminfo_node(&i, goal->nid); + if (!i.totalram || i.totalram < i.freeram) { + if (goal->metric == DAMOS_QUOTA_NODE_MEM_USED_BP) + return 10000; + else /* DAMOS_QUOTA_NODE_MEM_FREE_BP */ + return 0; + } + if (goal->metric == DAMOS_QUOTA_NODE_MEM_USED_BP) numerator = i.totalram - i.freeram; else /* DAMOS_QUOTA_NODE_MEM_FREE_BP */ diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c index 1854b4bb6bd2..ddd26a78a9bc 100644 --- a/mm/damon/paddr.c +++ b/mm/damon/paddr.c @@ -183,7 +183,7 @@ static unsigned long damon_pa_pageout(struct damon_region *r, else list_add(&folio->lru, &folio_list); put_folio: - addr += folio_size(folio); + addr = PFN_PHYS(folio_pfn(folio)) + folio_size(folio); folio_put(folio); } if (install_young_filter) @@ -221,7 +221,7 @@ static inline unsigned long damon_pa_mark_accessed_or_deactivate( folio_deactivate(folio); applied += folio_nr_pages(folio); put_folio: - addr += folio_size(folio); + addr = PFN_PHYS(folio_pfn(folio)) + folio_size(folio); folio_put(folio); } s->last_applied = folio; @@ -271,7 +271,7 @@ static unsigned long damon_pa_migrate(struct damon_region *r, folio_is_file_lru(folio)); list_add(&folio->lru, &folio_list); put_folio: - addr += folio_size(folio); + addr = PFN_PHYS(folio_pfn(folio)) + folio_size(folio); folio_put(folio); } applied = damon_migrate_pages(&folio_list, s->target_nid); @@ -300,7 +300,7 @@ static unsigned long damon_pa_stat(struct damon_region *r, if (!damos_pa_filter_out(s, folio)) *sz_filter_passed += folio_size(folio) / addr_unit; - addr += folio_size(folio); + addr = PFN_PHYS(folio_pfn(folio)) + folio_size(folio); folio_put(folio); } s->last_applied = folio; diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c index 37e0a8bef4b1..e95cddca0a10 100644 --- a/mm/damon/sysfs-schemes.c +++ b/mm/damon/sysfs-schemes.c @@ -2484,12 +2484,12 @@ static int damon_sysfs_add_scheme_filters(struct damos *scheme, return err; } } else if (filter->type == DAMOS_FILTER_TYPE_ADDR) { - if (sysfs_filter->addr_range.end < - sysfs_filter->addr_range.start) { + filter->addr_range = sysfs_filter->addr_range; + if (filter->addr_range.end < + filter->addr_range.start) { damos_destroy_filter(filter); return -EINVAL; } - filter->addr_range = sysfs_filter->addr_range; } else if (filter->type == DAMOS_FILTER_TYPE_TARGET) { filter->target_idx = sysfs_filter->target_idx; } else if (filter->type == DAMOS_FILTER_TYPE_HUGEPAGE_SIZE) { diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c index 3a79d8c89b5b..1ae026d099a2 100644 --- a/mm/damon/sysfs.c +++ b/mm/damon/sysfs.c @@ -1199,6 +1199,7 @@ struct damon_sysfs_kdamond { struct damon_sysfs_contexts *contexts; struct damon_ctx *damon_ctx; unsigned int refresh_ms; + unsigned long next_refresh_jiffies; }; static struct damon_sysfs_kdamond *damon_sysfs_kdamond_alloc(void) @@ -1567,17 +1568,15 @@ static struct damon_ctx *damon_sysfs_build_ctx( return ctx; } -static unsigned long damon_sysfs_next_update_jiffies; - static int damon_sysfs_repeat_call_fn(void *data) { struct damon_sysfs_kdamond *sysfs_kdamond = data; if (!sysfs_kdamond->refresh_ms) return 0; - if (time_before(jiffies, damon_sysfs_next_update_jiffies)) + if (time_before(jiffies, sysfs_kdamond->next_refresh_jiffies)) return 0; - damon_sysfs_next_update_jiffies = jiffies + + sysfs_kdamond->next_refresh_jiffies = jiffies + msecs_to_jiffies(sysfs_kdamond->refresh_ms); if (!mutex_trylock(&damon_sysfs_lock)) @@ -1645,8 +1644,8 @@ static int damon_sysfs_turn_damon_on(struct damon_sysfs_kdamond *kdamond) } kdamond->damon_ctx = ctx; - damon_sysfs_next_update_jiffies = - jiffies + msecs_to_jiffies(kdamond->refresh_ms); + kdamond->next_refresh_jiffies = jiffies + + msecs_to_jiffies(kdamond->refresh_ms); repeat_call_control->fn = damon_sysfs_repeat_call_fn; repeat_call_control->data = kdamond; diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c index cfa7849041ad..7d4d7565e8ee 100644 --- a/mm/damon/vaddr.c +++ b/mm/damon/vaddr.c @@ -925,6 +925,8 @@ static int damos_va_stat_pmd_entry(pmd_t *pmd, unsigned long addr, return 0; for (; addr < next; pte += nr, addr += nr * PAGE_SIZE) { + unsigned long page_idx; + nr = 1; ptent = ptep_get(pte); @@ -938,7 +940,8 @@ static int damos_va_stat_pmd_entry(pmd_t *pmd, unsigned long addr, if (!damos_va_filter_out(s, folio, vma, addr, pte, NULL)) *sz_filter_passed += folio_size(folio); - nr = folio_nr_pages(folio); + page_idx = folio_page_idx(folio, pte_page(ptent)); + nr = folio_nr_pages(folio) - page_idx; s->last_applied = folio; } pte_unmap_unlock(start_pte, ptl); diff --git a/mm/execmem.c b/mm/execmem.c index 084a207e4278..9560441e57ab 100644 --- a/mm/execmem.c +++ b/mm/execmem.c @@ -164,9 +164,11 @@ static void execmem_cache_clean(struct work_struct *work) mutex_lock(mutex); mas_for_each(&mas, area, ULONG_MAX) { + struct vm_struct *vm = find_vm_area(area); size_t size = mas_range_len(&mas); - if (IS_ALIGNED(size, PMD_SIZE) && + if (vm && get_vm_area_size(vm) == size && + IS_ALIGNED(size, PMD_SIZE) && IS_ALIGNED(mas.index, PMD_SIZE)) { struct vm_struct *vm = find_vm_area(area); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index ebc78406335b..42aace6e3ca1 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -2353,6 +2353,11 @@ struct folio *alloc_hugetlb_folio_reserve(struct hstate *h, int preferred_nid, h->resv_huge_pages--; spin_unlock_irq(&hugetlb_lock); + + if (folio) + lruvec_stat_mod_folio(folio, NR_HUGETLB, + folio_nr_pages(folio)); + return folio; } @@ -2360,24 +2365,30 @@ struct folio *alloc_hugetlb_folio_reserve(struct hstate *h, int preferred_nid, struct folio *alloc_hugetlb_folio_nodemask(struct hstate *h, int preferred_nid, nodemask_t *nmask, gfp_t gfp_mask, bool allow_alloc_fallback) { - spin_lock_irq(&hugetlb_lock); - if (available_huge_pages(h)) { - struct folio *folio; + struct folio *folio = NULL; + spin_lock_irq(&hugetlb_lock); + if (available_huge_pages(h)) folio = dequeue_hugetlb_folio_nodemask(h, gfp_mask, preferred_nid, nmask); - if (folio) { - spin_unlock_irq(&hugetlb_lock); - return folio; - } - } spin_unlock_irq(&hugetlb_lock); - /* We cannot fallback to other nodes, as we could break the per-node pool. */ - if (!allow_alloc_fallback) - gfp_mask |= __GFP_THISNODE; + if (!folio) { + /* + * We cannot fallback to other nodes, as we could break the + * per-node pool. + */ + if (!allow_alloc_fallback) + gfp_mask |= __GFP_THISNODE; - return alloc_migrate_hugetlb_folio(h, gfp_mask, preferred_nid, nmask); + folio = alloc_migrate_hugetlb_folio(h, gfp_mask, preferred_nid, + nmask); + } + + if (folio) + lruvec_stat_mod_folio(folio, NR_HUGETLB, folio_nr_pages(folio)); + + return folio; } static nodemask_t *policy_mbind_nodemask(gfp_t gfp) @@ -7427,15 +7438,6 @@ long hugetlb_reserve_pages(struct inode *inode, out_put_pages: spool_resv = chg - gbl_reserve; - if (spool_resv) { - /* put sub pool's reservation back, chg - gbl_reserve */ - gbl_resv = hugepage_subpool_put_pages(spool, spool_resv); - /* - * subpool's reserved pages can not be put back due to race, - * return to hstate. - */ - hugetlb_acct_memory(h, -gbl_resv); - } /* Restore used_hpages for pages that failed global reservation */ if (gbl_reserve && spool) { unsigned long flags; @@ -7445,6 +7447,15 @@ long hugetlb_reserve_pages(struct inode *inode, spool->used_hpages -= gbl_reserve; unlock_or_release_subpool(spool, flags); } + if (spool_resv) { + /* put sub pool's reservation back, chg - gbl_reserve */ + gbl_resv = hugepage_subpool_put_pages(spool, spool_resv); + /* + * subpool's reserved pages can not be put back due to race, + * return to hstate. + */ + hugetlb_acct_memory(h, -gbl_resv); + } out_uncharge_cgroup: hugetlb_cgroup_uncharge_cgroup_rsvd(hstate_index(h), chg * pages_per_huge_page(h), h_cg); @@ -8054,6 +8065,15 @@ void hugetlb_unshare_all_pmds(struct vm_area_struct *vma) */ void fixup_hugetlb_reservations(struct vm_area_struct *vma) { - if (is_vm_hugetlb_page(vma)) - clear_vma_resv_huge_pages(vma); + if (!is_vm_hugetlb_page(vma)) + return; + + /* + * Rmap walks might still find this VMA and take the lock + * inside the reservation map for __vma_private_lock(). Don't clear + * the reservation map while that is possible. + */ + i_mmap_lock_write(vma->vm_file->f_mapping); + clear_vma_resv_huge_pages(vma); + i_mmap_unlock_write(vma->vm_file->f_mapping); } diff --git a/mm/hugetlb_cgroup.c b/mm/hugetlb_cgroup.c index b6537a3e4f62..7c59c20d6857 100644 --- a/mm/hugetlb_cgroup.c +++ b/mm/hugetlb_cgroup.c @@ -187,6 +187,34 @@ static void hugetlb_cgroup_css_free(struct cgroup_subsys_state *css) hugetlb_cgroup_free(hugetlb_cgroup_from_css(css)); } +static void hugetlb_cgroup_move_usage(struct hugetlb_cgroup *from, + struct hugetlb_cgroup *to, + struct folio *from_folio, + struct folio *to_folio) +{ + int idx = hstate_index(folio_hstate(from_folio)); + unsigned long nr_pages = folio_nr_pages(from_folio); + int from_nid = folio_nid(from_folio); + int to_nid = folio_nid(to_folio); + unsigned long usage; + + lockdep_assert_held(&hugetlb_lock); + + if (!from || !to) + return; + + if (from == to && from_nid == to_nid) + return; + + usage = from->nodeinfo[from_nid]->usage[idx]; + if (WARN_ON_ONCE(usage < nr_pages)) + return; + WRITE_ONCE(from->nodeinfo[from_nid]->usage[idx], usage - nr_pages); + + usage = to->nodeinfo[to_nid]->usage[idx]; + WRITE_ONCE(to->nodeinfo[to_nid]->usage[idx], usage + nr_pages); +} + /* * Should be called with hugetlb_lock held. * Since we are holding hugetlb_lock, pages cannot get moved from @@ -221,6 +249,8 @@ static void hugetlb_cgroup_move_parent(int idx, struct hugetlb_cgroup *h_cg, /* Take the pages off the local counter */ page_counter_cancel(counter, nr_pages); + hugetlb_cgroup_move_usage(h_cg, parent, folio, folio); + set_hugetlb_cgroup(folio, parent); out: return; @@ -914,6 +944,9 @@ void hugetlb_cgroup_migrate(struct folio *old_folio, struct folio *new_folio) /* move the h_cg details to new cgroup */ set_hugetlb_cgroup(new_folio, h_cg); set_hugetlb_cgroup_rsvd(new_folio, h_cg_rsvd); + + hugetlb_cgroup_move_usage(h_cg, h_cg, old_folio, new_folio); + list_move(&new_folio->lru, &h->hugepage_activelist); spin_unlock_irq(&hugetlb_lock); } diff --git a/mm/khugepaged.c b/mm/khugepaged.c index e2ac26c05064..cc3a09a0c259 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -2308,6 +2308,7 @@ static int hpage_collapse_scan_file(struct mm_struct *mm, unsigned long addr, int present, swap; int node = NUMA_NO_NODE; int result = SCAN_SUCCEED; + unsigned long failed_pfn = -1; present = 0; swap = 0; @@ -2344,6 +2345,7 @@ static int hpage_collapse_scan_file(struct mm_struct *mm, unsigned long addr, folio->index == start) { /* Maybe PMD-mapped */ result = SCAN_PTE_MAPPED_HUGEPAGE; + failed_pfn = folio_pfn(folio); /* * For SCAN_PTE_MAPPED_HUGEPAGE, further processing * by the caller won't touch the page cache, and so @@ -2357,6 +2359,7 @@ static int hpage_collapse_scan_file(struct mm_struct *mm, unsigned long addr, node = folio_nid(folio); if (hpage_collapse_scan_abort(node, cc)) { result = SCAN_SCAN_ABORT; + failed_pfn = folio_pfn(folio); folio_put(folio); break; } @@ -2364,12 +2367,14 @@ static int hpage_collapse_scan_file(struct mm_struct *mm, unsigned long addr, if (!folio_test_lru(folio)) { result = SCAN_PAGE_LRU; + failed_pfn = folio_pfn(folio); folio_put(folio); break; } if (folio_expected_ref_count(folio) + 1 != folio_ref_count(folio)) { result = SCAN_PAGE_COUNT; + failed_pfn = folio_pfn(folio); folio_put(folio); break; } @@ -2401,7 +2406,7 @@ static int hpage_collapse_scan_file(struct mm_struct *mm, unsigned long addr, } } - trace_mm_khugepaged_scan_file(mm, folio, file, present, swap, result); + trace_mm_khugepaged_scan_file(mm, failed_pfn, file, present, swap, result); return result; } diff --git a/mm/ksm.c b/mm/ksm.c index 4f672f4f2140..80274ace8155 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -1065,7 +1065,8 @@ static inline void folio_set_stable_node(struct folio *folio, struct ksm_stable_node *stable_node) { VM_WARN_ON_FOLIO(folio_test_anon(folio) && PageAnonExclusive(&folio->page), folio); - folio->mapping = (void *)((unsigned long)stable_node | FOLIO_MAPPING_KSM); + WRITE_ONCE(folio->mapping, + (void *)((unsigned long)stable_node | FOLIO_MAPPING_KSM)); } #ifdef CONFIG_SYSFS @@ -3248,7 +3249,7 @@ void folio_migrate_ksm(struct folio *newfolio, struct folio *folio) stable_node = folio_stable_node(folio); if (stable_node) { VM_BUG_ON_FOLIO(stable_node->kpfn != folio_pfn(folio), folio); - stable_node->kpfn = folio_pfn(newfolio); + WRITE_ONCE(stable_node->kpfn, folio_pfn(newfolio)); /* * newfolio->mapping was set in advance; now we need smp_wmb() * to make sure that the new stable_node->kpfn is visible diff --git a/mm/madvise.c b/mm/madvise.c index b8c25fea4fab..729d8f2f07fd 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -415,9 +415,10 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd, if (next - addr != HPAGE_PMD_SIZE) { int err; + if (!folio_trylock(folio)) + goto huge_unlock; folio_get(folio); spin_unlock(ptl); - folio_lock(folio); err = split_folio(folio); folio_unlock(folio); folio_put(folio); @@ -427,10 +428,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd, } if (!pageout && pmd_young(orig_pmd)) { - pmdp_invalidate(vma, addr, pmd); - orig_pmd = pmd_mkold(orig_pmd); - - set_pmd_at(mm, addr, pmd, orig_pmd); + pmdp_test_and_clear_young(vma, addr, pmd); tlb_remove_pmd_tlb_entry(tlb, pmd, addr); } @@ -451,6 +449,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd, spin_unlock(ptl); if (pageout) reclaim_pages(&folio_list); + cond_resched(); return 0; } @@ -460,7 +459,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd, restart: start_pte = pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); if (!start_pte) - return 0; + goto out; flush_tlb_batched_pending(mm); arch_enter_lazy_mmu_mode(); for (; addr < end; pte += nr, addr += nr * PAGE_SIZE) { @@ -564,6 +563,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd, folio_deactivate(folio); } +out: if (start_pte) { arch_leave_lazy_mmu_mode(); pte_unmap_unlock(start_pte, ptl); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 82ad23d689c7..2aa741316b49 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2311,10 +2311,11 @@ static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask, bool raised_max_event = false; unsigned long pflags; bool allow_spinning = gfpflags_allow_spinning(gfp_mask); + int ret = 0; retry: if (consume_stock(memcg, nr_pages)) - return 0; + return ret; if (!allow_spinning) /* Avoid the refill and flush of the older stock */ @@ -2424,16 +2425,11 @@ static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask, * put the burden of reclaim on regular allocation requests * and let these go through as privileged allocations. */ - if (!(gfp_mask & (__GFP_NOFAIL | __GFP_HIGH))) - return -ENOMEM; + if (!(gfp_mask & (__GFP_NOFAIL | __GFP_HIGH))) { + ret = -ENOMEM; + goto out; + } force: - /* - * If the allocation has to be enforced, don't forget to raise - * a MEMCG_MAX event. - */ - if (!raised_max_event) - __memcg_memory_event(mem_over_limit, MEMCG_MAX, allow_spinning); - /* * The allocation either can't fail or will lead to more memory * being freed very soon. Allow memory usage go over the limit @@ -2443,7 +2439,15 @@ static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask, if (do_memsw_account()) page_counter_charge(&memcg->memsw, nr_pages); - return 0; +out: + /* + * Don't forget to raise a MEMCG_MAX event for forced or rejected + * requests. + */ + if (!raised_max_event) + __memcg_memory_event(mem_over_limit, MEMCG_MAX, allow_spinning); + + return ret; done_restock: if (batch > nr_pages) @@ -2502,7 +2506,7 @@ static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask, !(current->flags & PF_MEMALLOC) && gfpflags_allow_blocking(gfp_mask)) __mem_cgroup_handle_over_high(gfp_mask); - return 0; + return ret; } static inline int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask, diff --git a/mm/memory.c b/mm/memory.c index 72793ec63107..01d14ca0e74d 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -6808,14 +6808,34 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, resource_size_t phys_addr; pgprot_t prot = __pgprot(0); void __iomem *maddr; + struct page *page; int offset = offset_in_page(addr); int ret = -EINVAL; bool writable; struct follow_pfnmap_args args = { .vma = vma, .address = addr }; + /* + * Limit access to one page at a time, as that's what follow_pfnmap_start() + * guarantees; expect the caller to retry to read larger ranges. + */ + len = min_t(int, len, PAGE_SIZE - offset); + retry: if (follow_pfnmap_start(&args)) return -EINVAL; + + /* + * Reject anything that looks like ordinary RAM, including anonymous + * folios in CoW mappings or allocated kernel memory. Note that we + * cannot distinguish memblock allocations from non-RAM reliably, so + * we cannot easily reject them here. + */ + page = pfn_to_online_page(args.pfn); + if (page && !PageReserved(page)) { + follow_pfnmap_end(&args); + return -EINVAL; + } + prot = args.pgprot; phys_addr = (resource_size_t)args.pfn << PAGE_SHIFT; writable = args.writable; @@ -6824,7 +6844,7 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, if ((write & FOLL_WRITE) && !writable) return -EINVAL; - maddr = ioremap_prot(phys_addr, PAGE_ALIGN(len + offset), prot); + maddr = ioremap_prot(phys_addr, PAGE_SIZE, prot); if (!maddr) return -ENOMEM; @@ -6832,7 +6852,7 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, goto out_unmap; if ((pgprot_val(prot) != pgprot_val(args.pgprot)) || - (phys_addr != (args.pfn << PAGE_SHIFT)) || + (phys_addr != ((resource_size_t)args.pfn << PAGE_SHIFT)) || (writable != args.writable)) { follow_pfnmap_end(&args); iounmap(maddr); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 2a84cecf5435..919a505cabae 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2206,7 +2206,7 @@ static nodemask_t *policy_nodemask(gfp_t gfp, struct mempolicy *pol, break; case MPOL_BIND: /* Restrict to nodemask (but not on lower zones) */ - if (apply_policy_zone(pol, gfp_zone(gfp)) && + if (apply_policy_zone(pol, gfp_zone(current_gfp_context(gfp))) && cpuset_nodemask_valid_mems_allowed(&pol->nodes)) nodemask = &pol->nodes; if (pol->home_node != NUMA_NO_NODE) @@ -2519,6 +2519,7 @@ static unsigned long alloc_pages_bulk_interleave(gfp_t gfp, struct mempolicy *pol, unsigned long nr_pages, struct page **page_array) { + unsigned int cpuset_mems_cookie; int nodes; unsigned long nr_pages_per_node; int delta; @@ -2526,7 +2527,16 @@ static unsigned long alloc_pages_bulk_interleave(gfp_t gfp, unsigned long nr_allocated; unsigned long total_allocated = 0; - nodes = nodes_weight(pol->nodes); + /* count the nodes, retry if a rebind happened during the read */ + do { + cpuset_mems_cookie = read_mems_allowed_begin(); + nodes = nodes_weight(pol->nodes); + } while (read_mems_allowed_retry(cpuset_mems_cookie)); + + /* if the nodemask has become invalid, we cannot do anything */ + if (!nodes) + return 0; + nr_pages_per_node = nr_pages / nodes; delta = nr_pages - nodes * nr_pages_per_node; diff --git a/mm/mlock.c b/mm/mlock.c index 31045f17766a..20061dd28150 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -468,7 +468,7 @@ static int mlock_fixup(struct vma_iterator *vmi, struct vm_area_struct *vma, unsigned long end, vm_flags_t newflags) { struct mm_struct *mm = vma->vm_mm; - int nr_pages; + long nr_pages; int ret = 0; vm_flags_t oldflags = vma->vm_flags; diff --git a/mm/mremap.c b/mm/mremap.c index f0e63d3b3c14..8ed7c50e499b 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -874,12 +874,6 @@ unsigned long move_page_tables(struct pagetable_move_control *pmc) return pmc_progress(pmc); } -/* Set vrm->delta to the difference in VMA size specified by user. */ -static void vrm_set_delta(struct vma_remap_struct *vrm) -{ - vrm->delta = abs_diff(vrm->old_len, vrm->new_len); -} - /* Determine what kind of remap this is - shrink, expand or no resize at all. */ static enum mremap_type vrm_remap_type(struct vma_remap_struct *vrm) { @@ -892,6 +886,13 @@ static enum mremap_type vrm_remap_type(struct vma_remap_struct *vrm) return MREMAP_EXPAND; } +/* Populate calculated fields. */ +static void vrm_populate_calculated(struct vma_remap_struct *vrm) +{ + vrm->delta = abs_diff(vrm->old_len, vrm->new_len); + vrm->remap_type = vrm_remap_type(vrm); +} + /* * When moving a VMA to vrm->new_adr, does this result in the new and old VMAs * overlapping? @@ -1238,6 +1239,20 @@ static int copy_vma_and_data(struct vma_remap_struct *vrm, pmc_revert.need_rmap_locks = true; move_page_tables(&pmc_revert); + /* + * When copy_vma_and_data() returns, the new VMA will be + * unmapped rather than the old one. + * + * When an accountable move is being performed, this unmapping + * will not uncharge any expansion, so do that now. + * + * A move is accountable if the VMA is accountable and + * MREMAP_DONTUNMAP is not specified, so only do so if the + * latter is true. + */ + if (!(vrm->flags & MREMAP_DONTUNMAP)) + vrm_uncharge(vrm); + vrm->vma = new_vma; vrm->old_len = vrm->new_len; vrm->addr = vrm->new_addr; @@ -1245,7 +1260,7 @@ static int copy_vma_and_data(struct vma_remap_struct *vrm, mremap_userfaultfd_prep(new_vma, vrm->uf); } - fixup_hugetlb_reservations(vma); + fixup_hugetlb_reservations(vrm->vma); *new_vma_ptr = new_vma; return err; @@ -1422,6 +1437,7 @@ static unsigned long mremap_to(struct vma_remap_struct *vrm) /* Set up for the move now shrink has been executed. */ vrm->old_len = vrm->new_len; + vrm_populate_calculated(vrm); } /* MREMAP_DONTUNMAP expands by old_len since old_len == new_len */ @@ -1694,8 +1710,7 @@ static int check_prep_vma(struct vma_remap_struct *vrm) if (is_vm_hugetlb_page(vma) && !align_hugetlb(vrm)) return -EINVAL; - vrm_set_delta(vrm); - vrm->remap_type = vrm_remap_type(vrm); + vrm_populate_calculated(vrm); /* For convenience, we set new_addr even if VMA won't move. */ if (!vrm_implies_new_addr(vrm)) vrm->new_addr = addr; diff --git a/mm/nommu.c b/mm/nommu.c index c3a23b082adb..d609ecdcf022 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1644,6 +1644,9 @@ static int __access_remote_vm(struct mm_struct *mm, unsigned long addr, struct vm_area_struct *vma; int write = gup_flags & FOLL_WRITE; + if (addr + len < addr) + return 0; + if (mmap_read_lock_killable(mm)) return 0; @@ -1697,9 +1700,6 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in { struct mm_struct *mm; - if (addr + len < addr) - return 0; - mm = get_task_mm(tsk); if (!mm) return 0; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ff863a87f2b8..8bdc35efad26 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -1026,10 +1027,12 @@ static inline void __free_one_page(struct page *page, * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page, * merge with it and move up one order. */ - if (page_is_guard(buddy)) + if (page_is_guard(buddy)) { clear_page_guard(zone, buddy, order); - else + account_freepages(zone, 1 << order, migratetype); + } else { __del_page_from_free_list(buddy, zone, order, buddy_mt); + } if (unlikely(buddy_mt != migratetype)) { /* @@ -2206,10 +2209,17 @@ static inline bool boost_watermark(struct zone *zone) if (!watermark_boost_factor) return false; + + /* + * A kdump capture kernel exits before a boost can pay off, while + * the raised watermark can exceed the memory left for the dump. + */ + if (is_kdump_kernel()) + return false; + /* * Don't bother in zones that are unlikely to produce results. - * On small machines, including kdump capture kernels running - * in a small area, boosting the watermark can cause an out of + * On small machines, boosting the watermark can cause an out of * memory situation immediately. */ if ((pageblock_nr_pages * 4) > zone_managed_pages(zone)) diff --git a/mm/page_isolation.c b/mm/page_isolation.c index f72b6cd38b95..2e366e7bd5e9 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c @@ -380,13 +380,19 @@ static int isolate_single_pageblock(unsigned long boundary_pfn, } if (PageBuddy(page)) { - int order = buddy_order(page); + unsigned int order = buddy_order_unsafe(page); - /* pageblock_isolate_and_move_free_pages() handled this */ - VM_WARN_ON_ONCE(pfn + (1 << order) > boundary_pfn); - - pfn += 1UL << order; - continue; + /* buddy_order_unsafe() is racy. Validate the order before shifting. */ + if (order <= MAX_PAGE_ORDER && + /* + * pageblock_isolate_and_move_free_pages() splits + * cross-boundary PageBuddy, verify it. + */ + pfn + (1UL << order) <= boundary_pfn) { + pfn += 1UL << order; + continue; + } + goto failed; } /* @@ -405,10 +411,28 @@ static int isolate_single_pageblock(unsigned long boundary_pfn, if (PageCompound(page)) { struct page *head = compound_head(page); unsigned long head_pfn = page_to_pfn(head); - unsigned long nr_pages = compound_nr(head); + unsigned int order = compound_order(head); + unsigned long nr_pages; + + /* compound_order() is racy. Cap it at MAX_FOLIO_ORDER. */ + if (order > MAX_FOLIO_ORDER) + goto failed; + + nr_pages = 1UL << order; + + /* + * compound_head() is also racy, so the derived head_pfn + * needs additional checks to make sure it is valid. + * Otherwise, just fail the check. pfn comes from + * __first_valid_page() as a legitimate PFN, so use it to + * check head_pfn. + */ + if (head_pfn > pfn || !IS_ALIGNED(head_pfn, nr_pages) || + pfn - head_pfn >= nr_pages) + goto failed; if (head_pfn + nr_pages <= boundary_pfn || - PageHuge(page)) { + PageHuge(head)) { pfn = head_pfn + nr_pages; continue; } diff --git a/mm/page_table_check.c b/mm/page_table_check.c index 91c4dacc41fb..fa2c12e76a9e 100644 --- a/mm/page_table_check.c +++ b/mm/page_table_check.c @@ -67,7 +67,7 @@ static void page_table_check_clear(unsigned long pfn, unsigned long pgcnt) struct page *page; bool anon; - if (!pfn_valid(pfn)) + if (!pfn_valid(pfn) || is_zero_pfn(pfn) || is_huge_zero_pfn(pfn)) return; page = pfn_to_page(pfn); @@ -102,7 +102,7 @@ static void page_table_check_set(unsigned long pfn, unsigned long pgcnt, struct page *page; bool anon; - if (!pfn_valid(pfn)) + if (!pfn_valid(pfn) || is_zero_pfn(pfn) || is_huge_zero_pfn(pfn)) return; page = pfn_to_page(pfn); diff --git a/mm/percpu.c b/mm/percpu.c index 81462ce5866e..32519523845b 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -1692,14 +1692,15 @@ static void pcpu_alloc_tag_alloc_hook(struct pcpu_chunk *chunk, int off, { if (mem_alloc_profiling_enabled() && likely(chunk->obj_exts)) { alloc_tag_add(&chunk->obj_exts[off >> PCPU_MIN_ALLOC_SHIFT].tag, - current->alloc_tag, size); + current->alloc_tag, pcpu_obj_full_size(size)); } } static void pcpu_alloc_tag_free_hook(struct pcpu_chunk *chunk, int off, size_t size) { if (mem_alloc_profiling_enabled() && likely(chunk->obj_exts)) - alloc_tag_sub(&chunk->obj_exts[off >> PCPU_MIN_ALLOC_SHIFT].tag, size); + alloc_tag_sub(&chunk->obj_exts[off >> PCPU_MIN_ALLOC_SHIFT].tag, + pcpu_obj_full_size(size)); } #else static void pcpu_alloc_tag_alloc_hook(struct pcpu_chunk *chunk, int off, diff --git a/mm/shmem.c b/mm/shmem.c index 0100110f77b8..68a3a0734e3d 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1129,7 +1129,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend, } folio_batch_remove_exceptionals(&fbatch); folio_batch_release(&fbatch); - cond_resched(); + cond_resched_tasks_rcu_qs(); } /* @@ -1170,7 +1170,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend, index = start; while (index < end) { - cond_resched(); + cond_resched_tasks_rcu_qs(); if (!find_get_entries(mapping, &index, end - 1, &fbatch, indices)) { @@ -4595,6 +4595,9 @@ static int shmem_parse_opt_casefold(struct fs_context *fc, struct fs_parameter * struct unicode_map *encoding; char *version_str = param->string + 5; + if (ctx->encoding) + return invalfc(fc, "casefold parameter cannot be specified twice\n"); + if (!latest_version) { if (strncmp(param->string, "utf8-", 5)) return invalfc(fc, "Only UTF-8 encodings are supported " @@ -5081,6 +5084,7 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc) if (ctx->encoding) { sb->s_encoding = ctx->encoding; + ctx->encoding = NULL; set_default_d_op(sb, &shmem_ci_dentry_ops); if (ctx->strict_encoding) sb->s_encoding_flags = SB_ENC_STRICT_MODE_FL; @@ -5177,6 +5181,9 @@ static void shmem_free_fc(struct fs_context *fc) struct shmem_options *ctx = fc->fs_private; if (ctx) { +#if IS_ENABLED(CONFIG_UNICODE) + utf8_unload(ctx->encoding); +#endif mpol_put(ctx->mpol); kfree(ctx); } diff --git a/mm/swap_state.c b/mm/swap_state.c index b8d7744b4436..57cae6f6eac1 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -86,17 +86,27 @@ void show_swap_cache_info(void) */ struct folio *swap_cache_get_folio(swp_entry_t entry) { + struct swap_cluster_info *ci = __swap_entry_to_cluster(entry); + unsigned int ci_off = swp_cluster_offset(entry); unsigned long swp_tb; struct folio *folio; for (;;) { - swp_tb = swap_table_get(__swap_entry_to_cluster(entry), - swp_cluster_offset(entry)); + swp_tb = swap_table_get(ci, ci_off); if (!swp_tb_is_folio(swp_tb)) return NULL; folio = swp_tb_to_folio(swp_tb); - if (likely(folio_try_get(folio))) + if (!folio_try_get(folio)) + continue; + /* + * The folio may have been freed and its memory reused before + * we got the reference. Make sure it is still in the slot. + */ + swp_tb = swap_table_get(ci, ci_off); + if (likely(swp_tb_is_folio(swp_tb) && + swp_tb_to_folio(swp_tb) == folio)) return folio; + folio_put(folio); } return NULL; diff --git a/mm/truncate.c b/mm/truncate.c index 4bf64fd610c9..3534bc320a9c 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -259,30 +259,32 @@ bool truncate_inode_partial_folio(struct folio *folio, loff_t start, loff_t end) * for shmem truncate */ struct folio *folio2; + pgoff_t end_idx; if (offset + length == size) goto no_split; - split_at2 = folio_page(folio, - PAGE_ALIGN_DOWN(offset + length) / PAGE_SIZE); - folio2 = page_folio(split_at2); - - if (!folio_try_get(folio2)) + /* + * After the first split at the start edge, the folio at the + * end edge may be freed and reused concurrently. + * __filemap_get_folio() looks up the straddler at end_idx + * and returns it locked and ref'd with the mapping + * validated. + */ + end_idx = (pos + offset + length) >> PAGE_SHIFT; + folio2 = __filemap_get_folio(folio->mapping, end_idx, + FGP_LOCK | FGP_NOWAIT, 0); + if (IS_ERR(folio2)) goto no_split; + /* make sure folio2 is large */ if (!folio_test_large(folio2)) goto out; - if (!folio_trylock(folio2)) - goto out; - - /* make sure folio2 is large and does not change its mapping */ - if (folio_test_large(folio2) && - folio2->mapping == folio->mapping) - try_folio_split_or_unmap(folio2, split_at2, min_order); - - folio_unlock(folio2); + split_at2 = folio_page(folio2, (end_idx - folio2->index)); + try_folio_split_or_unmap(folio2, split_at2, min_order); out: + folio_unlock(folio2); folio_put(folio2); no_split: return true; @@ -878,8 +880,7 @@ void pagecache_isize_extended(struct inode *inode, loff_t from, loff_t to) unsigned int offset, end; offset = from - folio_pos(folio); - end = min_t(unsigned int, to - folio_pos(folio), - folio_size(folio)); + end = min_t(loff_t, to - folio_pos(folio), folio_size(folio)); folio_zero_segment(folio, offset, end); } diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index 34798ce783e6..579445bddf56 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c @@ -1414,8 +1414,12 @@ static long move_pages_ptes(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd pte_unmap(dst_pte); src_pte = dst_pte = NULL; ret = split_folio(src_folio); - if (ret) + if (ret) { + /* do not retry, extra refs may be held forever */ + if (ret == -EAGAIN) + ret = -EBUSY; goto out; + } /* have to reacquire the folio after it got split */ folio_unlock(src_folio); folio_put(src_folio); diff --git a/mm/vmscan.c b/mm/vmscan.c index c983815bde5b..e72d50bab730 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -5082,7 +5082,7 @@ static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control * sc->nr_reclaimed = 0; if (mem_cgroup_disabled()) - shrink_one(&pgdat->__lruvec, sc); + shrink_one(mem_cgroup_lruvec(NULL, pgdat), sc); else shrink_many(pgdat, sc); @@ -7642,7 +7642,8 @@ static unsigned long __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, sc->gfp_mask); cond_resched(); - psi_memstall_enter(&pflags); + if (!sc->proactive) + psi_memstall_enter(&pflags); delayacct_freepages_start(); fs_reclaim_acquire(sc->gfp_mask); /* @@ -7666,7 +7667,8 @@ static unsigned long __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, memalloc_noreclaim_restore(noreclaim_flag); fs_reclaim_release(sc->gfp_mask); delayacct_freepages_end(); - psi_memstall_leave(&pflags); + if (!sc->proactive) + psi_memstall_leave(&pflags); trace_mm_vmscan_node_reclaim_end(sc->nr_reclaimed); @@ -7823,7 +7825,7 @@ int user_proactive_reclaim(char *buf, } else { struct scan_control sc = { .gfp_mask = current_gfp_context(gfp_mask), - .reclaim_idx = gfp_zone(gfp_mask), + .reclaim_idx = MAX_NR_ZONES - 1, .proactive_swappiness = swappiness == -1 ? NULL : &swappiness, .priority = DEF_PRIORITY, .may_writepage = !laptop_mode, diff --git a/mm/zswap.c b/mm/zswap.c index 18249dd96ef8..d2e5f0cff71d 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -288,6 +288,8 @@ static struct zswap_pool *zswap_pool_create(char *compressor) zswap_pool_debug("created", pool); + static_branch_enable(&zswap_ever_enabled); + return pool; ref_fail: @@ -1818,9 +1820,8 @@ static int zswap_setup(void) pool = __zswap_pool_create_fallback(); if (pool) { pr_info("loaded using pool %s\n", pool->tfm_name); - list_add(&pool->list, &zswap_pools); + list_add_rcu(&pool->list, &zswap_pools); zswap_has_pool = true; - static_branch_enable(&zswap_ever_enabled); } else { pr_err("pool creation failed\n"); zswap_enabled = false; diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 3733f408d2e4..0660d306cf4f 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -1207,6 +1207,7 @@ static int lowpan_control_open(struct inode *inode, struct file *file) } static const struct file_operations lowpan_control_fops = { + .owner = THIS_MODULE, .open = lowpan_control_open, .read = seq_read, .write = lowpan_control_write, diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c index 9ae6d9224c3b..807c9e0e212c 100644 --- a/net/bluetooth/hci_debugfs.c +++ b/net/bluetooth/hci_debugfs.c @@ -68,6 +68,7 @@ static ssize_t __name ## _write(struct file *file, \ } \ \ static const struct file_operations __name ## _fops = { \ + .owner = THIS_MODULE, \ .open = simple_open, \ .read = __name ## _read, \ .write = __name ## _write, \ @@ -286,6 +287,7 @@ static ssize_t use_debug_keys_read(struct file *file, char __user *user_buf, } static const struct file_operations use_debug_keys_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = use_debug_keys_read, .llseek = default_llseek, @@ -304,6 +306,7 @@ static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf, } static const struct file_operations sc_only_mode_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = sc_only_mode_read, .llseek = default_llseek, @@ -440,6 +443,7 @@ static ssize_t ssp_debug_mode_read(struct file *file, char __user *user_buf, } static const struct file_operations ssp_debug_mode_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = ssp_debug_mode_read, .llseek = default_llseek, @@ -532,6 +536,7 @@ static ssize_t force_bredr_smp_write(struct file *file, } static const struct file_operations force_bredr_smp_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = force_bredr_smp_read, .write = force_bredr_smp_write, @@ -781,6 +786,7 @@ static ssize_t force_static_address_write(struct file *file, } static const struct file_operations force_static_address_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = force_static_address_read, .write = force_static_address_write, @@ -1184,6 +1190,7 @@ static ssize_t force_no_mitm_write(struct file *file, } static const struct file_operations force_no_mitm_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = force_no_mitm_read, .write = force_no_mitm_write, @@ -1322,6 +1329,7 @@ static ssize_t dut_mode_write(struct file *file, const char __user *user_buf, } static const struct file_operations dut_mode_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = dut_mode_read, .write = dut_mode_write, @@ -1378,6 +1386,7 @@ static ssize_t vendor_diag_write(struct file *file, const char __user *user_buf, } static const struct file_operations vendor_diag_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = vendor_diag_read, .write = vendor_diag_write, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 462667a6e6ac..0ba7b1ea435c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -323,6 +323,10 @@ static int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size) { size_t alloc_size, i; + /* roundup_pow_of_two(0) is undefined */ + if (!size) + return -EINVAL; + /* Allocated size is a power of 2 to map sequence numbers * (which may be up to 14 bits) in to a smaller array that is * sized for the negotiated ERTM transmit windows. @@ -3648,18 +3652,33 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data break; case L2CAP_MODE_ERTM: - if (!test_bit(CONF_EWS_RECV, &chan->conf_state)) - chan->remote_tx_win = rfc.txwin_size; - else - rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; - - chan->remote_max_tx = rfc.max_transmit; - size = min_t(u16, le16_to_cpu(rfc.max_pdu_size), chan->conn->mtu - L2CAP_EXT_HDR_SIZE - L2CAP_SDULEN_SIZE - L2CAP_FCS_SIZE); rfc.max_pdu_size = cpu_to_le16(size); - chan->remote_mps = size; + + /* The TxWindow must be within 1 to 63, otherwise + * propose the default one and keep the parameters of + * an earlier request. This overrides a PENDING result + * from the EFS check above, so the request is no + * longer pending, nor done if an earlier one was. + */ + if (!rfc.txwin_size || + rfc.txwin_size > L2CAP_DEFAULT_TX_WINDOW) { + result = L2CAP_CONF_UNACCEPT; + clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state); + clear_bit(CONF_OUTPUT_DONE, &chan->conf_state); + rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; + remote_efs = 0; + } else { + if (!test_bit(CONF_EWS_RECV, &chan->conf_state)) + chan->remote_tx_win = rfc.txwin_size; + else + rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; + + chan->remote_max_tx = rfc.max_transmit; + chan->remote_mps = size; + } __l2cap_set_ertm_timeouts(chan, &rfc); @@ -3801,7 +3820,11 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, } } - if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode) + /* A connected channel cannot change its mode, as the new mode would + * not be initialized. + */ + if (chan->mode != rfc.mode && + (chan->mode == L2CAP_MODE_BASIC || chan->state == BT_CONNECTED)) return -ECONNREFUSED; chan->mode = rfc.mode; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index bb383ee188bb..b85c6a11334e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -805,6 +805,10 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, break; } + /* A zero TxWindow is invalid, use the default instead */ + if (!opts.txwin_size) + opts.txwin_size = L2CAP_DEFAULT_TX_WINDOW; + if (!l2cap_valid_mtu(chan, opts.imtu)) { err = -EINVAL; break; diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 614d2bba9fd6..a406fff75ba0 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -1141,6 +1141,9 @@ static int build_initial_monmap(struct ceph_mon_client *monc) int num_mon = opt->num_mon; int i; + if (num_mon < 1 || num_mon > CEPH_MAX_MON) + return -EINVAL; + /* build initial monmap */ monc->monmap = kzalloc(struct_size(monc->monmap, mon_inst, num_mon), GFP_KERNEL); diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 46b2c2ae7778..0b37fb3c6264 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -1108,7 +1108,9 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, req->r_base_oloc.pool = layout->pool_id; req->r_base_oloc.pool_ns = ceph_try_get_string(layout->pool_ns); ceph_oid_printf(&req->r_base_oid, "%llx.%08llx", vino.ino, objnum); - req->r_flags = flags | osdc->client->options->read_from_replica; + req->r_flags = flags; + if (flags & CEPH_OSD_FLAG_READ) + req->r_flags |= osdc->client->options->read_from_replica; req->r_snapid = vino.snap; if (flags & CEPH_OSD_FLAG_WRITE) @@ -3568,6 +3570,7 @@ static int ceph_oloc_decode(void **p, void *end, ceph_decode_need(p, end, len, e_inval); struct_end = *p + len; + ceph_decode_need(p, end, 8 + 4 + 4, e_inval); oloc->pool = ceph_decode_64(p); *p += 4; /* skip preferred */ @@ -3580,7 +3583,7 @@ static int ceph_oloc_decode(void **p, void *end, if (struct_v >= 5) { bool changed = false; - len = ceph_decode_32(p); + ceph_decode_32_safe(p, end, len, e_inval); if (len > 0) { ceph_decode_need(p, end, len, e_inval); if (!oloc->pool_ns || @@ -3599,7 +3602,9 @@ static int ceph_oloc_decode(void **p, void *end, } if (struct_v >= 6) { - s64 hash = ceph_decode_64(p); + s64 hash; + + ceph_decode_64_safe(p, end, hash, e_inval); if (hash != -1) { pr_warn("ceph_object_locator::hash is set\n"); goto e_inval; @@ -3640,7 +3645,7 @@ static int ceph_redirect_decode(void **p, void *end, if (ret) goto out; - len = ceph_decode_32(p); + ceph_decode_32_safe(p, end, len, e_inval); if (len > 0) { pr_warn("ceph_request_redirect::object_name is set\n"); goto e_inval; diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index 68bd45852fc3..803514a1bc7c 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -378,21 +378,33 @@ static int decode_choose_args(void **p, void *end, struct crush_map *c) ceph_decode_32_safe(p, end, num_buckets, e_inval); while (num_buckets--) { struct crush_choose_arg *arg; + struct crush_bucket *bucket; u32 bucket_index; + u32 i; ceph_decode_32_safe(p, end, bucket_index, e_inval); if (bucket_index >= arg_map->size) goto e_inval; arg = &arg_map->args[bucket_index]; + if (arg->ids || arg->weight_set) + goto e_inval; ret = decode_choose_arg(p, end, arg); if (ret) goto fail; + bucket = c->buckets[bucket_index]; if (arg->ids_size && - (!c->buckets[bucket_index] || - arg->ids_size != c->buckets[bucket_index]->size)) + (!bucket || arg->ids_size != bucket->size)) + goto e_inval; + + if (arg->weight_set_size && !bucket) goto e_inval; + + for (i = 0; i < arg->weight_set_size; i++) { + if (arg->weight_set[i].size != bucket->size) + goto e_inval; + } } if (!__insert_choose_arg_map(&c->choose_args, arg_map)) { diff --git a/net/core/dev.c b/net/core/dev.c index 0bfd5e9940df..673223065b95 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6074,6 +6074,8 @@ static int __netif_receive_skb_core(struct sk_buff **pskb, bool pfmemalloc, } if (unlikely(skb_vlan_tag_present(skb)) && !netdev_uses_dsa(skb->dev)) { + unsigned int priority_tag_depth = 1; + check_vlan_id: if (skb_vlan_tag_get_id(skb)) { /* Vlan id is non 0 and vlan_do_receive() above couldn't @@ -6085,6 +6087,12 @@ static int __netif_receive_skb_core(struct sk_buff **pskb, bool pfmemalloc, * 802.1Q or 802.1AD and vlan_do_receive() above could * not find vlan dev for vlan id 0. */ + if (unlikely(priority_tag_depth >= VLAN_MAX_DEPTH)) { + drop_reason = SKB_DROP_REASON_RECURSION_LIMIT; + goto drop; + } + + priority_tag_depth++; __vlan_hwaccel_clear_tag(skb); skb = skb_vlan_untag(skb); if (unlikely(!skb)) diff --git a/net/core/gro.c b/net/core/gro.c index 252d7851d1ae..f96e5024758e 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -192,6 +192,10 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) } merge: + /* skb_segment() cannot split the linear part of a frag_list member. */ + if (unlikely(headlen > offset + skb_shinfo(p)->gso_size)) + return -E2BIG; + /* sk ownership - if any - completely transferred to the aggregated packet */ skb->destructor = NULL; skb->sk = NULL; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 1808bed195af..227c889fba57 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3899,7 +3899,18 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) else csstart = skb_headlen(skb); - BUG_ON(csstart > skb_headlen(skb)); + if (unlikely(csstart < 0 || csstart > skb_headlen(skb) || + (skb->ip_summed == CHECKSUM_PARTIAL && + csstart + skb->csum_offset + sizeof(__sum16) > + skb->len))) { + DEBUG_NET_WARN_ON_ONCE(1); + /* Send the frame without the checksum filled in, or send + * zeroes if we can't even copy it. + */ + if (skb_copy_bits(skb, 0, to, skb->len)) + memset(to, 0, skb->len); + return; + } skb_copy_from_linear_data(skb, to, csstart); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 6b36652d6bb9..dd14944ad3ed 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -982,6 +984,9 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req, rcu_assign_pointer(tcp_sk(nreq->sk)->fastopen_rsk, nreq); } + if (rsk_is_mptcp(req)) + mptcp_subflow_reqsk_clone(req, nreq); + return nreq; } @@ -1126,9 +1131,11 @@ static void reqsk_timer_handler(struct timer_list *t) (!resend || !tcp_rtx_synack(sk_listener, req) || inet_rsk(req)->acked)) { + if (req->num_retrans > 1 && tcp_rsk(req)->accecn_ok) + tcp_rsk(req)->accecn_fail_mode |= TCP_ACCECN_ACE_FAIL_SEND; if (req->num_timeout++ == 0) atomic_dec(&queue->young); - mod_timer(&req->rsk_timer, jiffies + reqsk_timeout(req, TCP_RTO_MAX)); + mod_timer(&req->rsk_timer, jiffies + tcp_reqsk_timeout(req)); if (!nreq) return; @@ -1154,10 +1161,14 @@ static void reqsk_timer_handler(struct timer_list *t) */ if (nreq) { __NET_INC_STATS(net, LINUX_MIB_TCPMIGRATEREQFAILURE); + /* The timer was not armed, drop its reference here. */ + reqsk_put(nreq); no_ownership: reqsk_migrate_reset(nreq); reqsk_queue_removed(queue, nreq); - __reqsk_free(nreq); + /* Drop the temporary reference and the one reserved for ehash. */ + reqsk_put(nreq); + reqsk_put(nreq); } drop: @@ -1460,7 +1471,7 @@ struct sock *inet_csk_complete_hashdance(struct sock *sk, struct sock *child, __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMIGRATEREQFAILURE); reqsk_migrate_reset(nreq); - __reqsk_free(nreq); + reqsk_put(nreq); } else if (inet_csk_reqsk_queue_add(sk, req, child)) { return child; } @@ -1515,7 +1526,7 @@ void inet_csk_listen_stop(struct sock *sk) __NET_INC_STATS(sock_net(nsk), LINUX_MIB_TCPMIGRATEREQFAILURE); reqsk_migrate_reset(nreq); - __reqsk_free(nreq); + reqsk_put(nreq); } rcu_read_unlock(); diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index a57e33ff92d7..49c70d752a89 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -549,8 +549,9 @@ struct sock *__inet_lookup_established(const struct net *net, if (likely(inet_match(net, sk, acookie, ports, dif, sdif))) { if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt))) goto out; - if (unlikely(!inet_match(net, sk, acookie, - ports, dif, sdif))) { + if (unlikely(hlist_nulls_unhashed_lockless(&sk->sk_nulls_node) || + !inet_match(net, sk, acookie, ports, dif, + sdif))) { sock_gen_put(sk); goto begin; } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index b1282c01a77e..66a7f25f236b 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -2474,6 +2474,7 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb, skb_push(skb2, sizeof(struct iphdr)); skb_reset_network_header(skb2); iph = ip_hdr(skb2); + memset(iph, 0, sizeof(*iph)); iph->ihl = sizeof(struct iphdr) >> 2; iph->saddr = saddr; iph->daddr = daddr; diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c index 59ec465a9df9..7cb33af671e2 100644 --- a/net/ipv4/netfilter/nf_reject_ipv4.c +++ b/net/ipv4/netfilter/nf_reject_ipv4.c @@ -357,6 +357,11 @@ void nf_send_unreach(struct sk_buff *skb_in, int code, int hook) if (!skb_valid_dst(skb_in) && nf_reject_fill_skb_dst(skb_in) < 0) return; + if (hook == NF_INET_INGRESS) { + memset(IPCB(skb_in), 0, sizeof(*IPCB(skb_in))); + IPCB(skb_in)->iif = skb_in->skb_iif; + } + if (skb_csum_unnecessary(skb_in) || !nf_reject_verify_csum(skb_in, dataoff, proto)) { icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 6e51d8f5365d..e6276896f3ad 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1362,8 +1362,8 @@ static unsigned int ipv4_default_advmss(const struct dst_entry *dst) rcu_read_lock(); net = dst_dev_net_rcu(dst); - advmss = max_t(unsigned int, ip_dst_mtu_configured(dst) - header_size, - net->ipv4.ip_rt_min_advmss); + advmss = max_t(unsigned int, ipv4_mtu(dst) - header_size, + net->ipv4.ip_rt_min_advmss); rcu_read_unlock(); return min(advmss, IPV4_MAX_PMTU - header_size); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index b5f0a65c6786..8b3d4e8ee455 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -218,6 +218,8 @@ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, bh_unlock_sock(child); sock_put(child); + reqsk_put(req); + return NULL; } __reqsk_free(req); diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 34a8a932402d..bc3e5d6b8662 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -26,6 +26,7 @@ static int ip_local_port_range_max[] = { 65535, 65535 }; static int tcp_adv_win_scale_min = -31; static int tcp_adv_win_scale_max = 31; static int tcp_app_win_max = 31; +static int tcp_tso_rtt_log_max = 31; static int tcp_min_snd_mss_min = TCP_MIN_SND_MSS; static int tcp_min_snd_mss_max = 65535; static int tcp_rto_max_max = TCP_RTO_MAX_SEC * MSEC_PER_SEC; @@ -1379,6 +1380,7 @@ static struct ctl_table ipv4_net_table[] = { .maxlen = sizeof(u8), .mode = 0644, .proc_handler = proc_dou8vec_minmax, + .extra2 = &tcp_tso_rtt_log_max, }, { .procname = "tcp_min_rtt_wlen", diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 8e83ef81fc18..e3f462f161dd 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -288,12 +288,12 @@ int tcp_set_default_congestion_control(struct net *net, const char *name) ca = tcp_ca_find_autoload(name); if (!ca) { ret = -ENOENT; - } else if (!bpf_try_module_get(ca, ca->owner)) { - ret = -EBUSY; } else if (!net_eq(net, &init_net) && !(ca->flags & TCP_CONG_NON_RESTRICTED)) { /* Only init netns can set default to a restricted algorithm */ ret = -EPERM; + } else if (!bpf_try_module_get(ca, ca->owner)) { + ret = -EBUSY; } else { prev = xchg(&net->ipv4.tcp_congestion_control, ca); if (prev) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e1785140bf9b..28db1353445b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -6236,6 +6236,8 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, if (th->syn) { if (tcp_ecn_mode_accecn(tp)) { accecn_reflector = true; + tp->syn_ect_rcv = TCP_SKB_CB(skb)->ip_dsfield & + INET_ECN_MASK; if (tp->rx_opt.accecn && tp->saw_accecn_opt < TCP_ACCECN_OPT_COUNTER_SEEN) { u8 saw_opt = tcp_accecn_option_init(skb, tp->rx_opt.accecn); @@ -7561,7 +7563,9 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, if (!inet_csk_reqsk_queue_add(sk, req, fastopen_sk)) { bh_unlock_sock(fastopen_sk); sock_put(fastopen_sk); - goto drop_and_free; + /* tcp_disconnect() already dropped one reqsk ref. */ + reqsk_put(req); + goto drop; } READ_ONCE(sk->sk_data_ready)(sk); bh_unlock_sock(fastopen_sk); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index d05009f985af..ebcd78ad13ef 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -484,6 +484,10 @@ static void tcp_ecn_openreq_child(struct sock *sk, tp->syn_ect_snt = treq->syn_ect_snt; tcp_accecn_third_ack(sk, skb, treq->syn_ect_snt); tp->saw_accecn_opt = treq->saw_accecn_opt; + if (treq->accecn_fail_mode & TCP_ACCECN_ACE_FAIL_SEND) + tcp_accecn_fail_mode_set(tp, TCP_ACCECN_ACE_FAIL_SEND); + if (treq->accecn_fail_mode & TCP_ACCECN_ACE_FAIL_RECV) + tcp_accecn_fail_mode_set(tp, TCP_ACCECN_ACE_FAIL_RECV); tp->prev_ecnfield = treq->syn_ect_rcv; tp->accecn_opt_demand = 1; tcp_ecn_received_counters_payload(sk, skb); @@ -717,7 +721,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, * it can be estimated (approximately) * from another data. */ - tmp_opt.ts_recent_stamp = ktime_get_seconds() - reqsk_timeout(req, TCP_RTO_MAX) / HZ; + tmp_opt.ts_recent_stamp = ktime_get_seconds() - + tcp_reqsk_timeout(req) / HZ; paws_reject = tcp_paws_reject(&tmp_opt, th->rst); } } @@ -751,16 +756,28 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, */ if (!tcp_oow_rate_limited(sock_net(sk), skb, LINUX_MIB_TCPACKSKIPPEDSYNRECV, - &tcp_rsk(req)->last_oow_ack_time) && - - !tcp_rtx_synack(sk, req)) { - unsigned long expires = jiffies; - - expires += reqsk_timeout(req, TCP_RTO_MAX); - if (!fastopen) - mod_timer_pending(&req->rsk_timer, expires); - else - req->rsk_timer.expires = expires; + &tcp_rsk(req)->last_oow_ack_time)) { + if (tcp_rsk(req)->accecn_ok) { + u8 ect_rcv = TCP_SKB_CB(skb)->ip_dsfield & + INET_ECN_MASK; + + tcp_rsk(req)->syn_ect_rcv = ect_rcv; + if (tcp_accecn_ace(tcp_hdr(skb)) == 0x0) + tcp_rsk(req)->accecn_fail_mode |= TCP_ACCECN_ACE_FAIL_RECV; + } + if (!tcp_rtx_synack(sk, req)) { + unsigned long expires = jiffies; + + if (req->num_retrans > 1 && tcp_rsk(req)->accecn_ok) + tcp_rsk(req)->accecn_fail_mode |= TCP_ACCECN_ACE_FAIL_SEND; + + expires += tcp_reqsk_timeout(req); + if (!fastopen) + mod_timer_pending(&req->rsk_timer, + expires); + else + req->rsk_timer.expires = expires; + } } return NULL; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index ddcc7e53f2e3..b39ab081e3a6 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -333,8 +333,11 @@ static void tcp_ecn_send(struct sock *sk, struct sk_buff *skb, return; if (tcp_ecn_mode_accecn(tp)) { - if (!tcp_accecn_ace_fail_recv(tp)) + if (!tcp_accecn_ace_fail_recv(tp) && + !tcp_accecn_ace_fail_send(tp)) INET_ECN_xmit(sk); + else + INET_ECN_dontxmit(sk); tcp_accecn_set_ace(tp, skb, th); skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ACCECN; } else { @@ -2628,7 +2631,7 @@ static int tcp_mtu_probe(struct sock *sk) mss_now = tcp_current_mss(sk); probe_size = tcp_mtu_to_mss(sk, (icsk->icsk_mtup.search_high + icsk->icsk_mtup.search_low) >> 1); - size_needed = probe_size + (tp->reordering + 1) * (u64)tp->mss_cache; + size_needed = probe_size + ((u64)tp->reordering + 1) * tp->mss_cache; interval = icsk->icsk_mtup.search_high - icsk->icsk_mtup.search_low; /* When misfortune happens, we are reprobing actively, * and then reprobe timer has expired. We stick with current diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index eb549fea8fdd..017a52022a1a 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -22,6 +22,7 @@ #include #include #include +#include #include static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk) @@ -482,6 +483,8 @@ static void tcp_fastopen_synack_timer(struct sock *sk, struct request_sock *req) * it's not good to give up too easily. */ tcp_rtx_synack(sk, req); + if (req->num_retrans > 1 && tcp_rsk(req)->accecn_ok) + tcp_rsk(req)->accecn_fail_mode |= TCP_ACCECN_ACE_FAIL_SEND; req->num_timeout++; tcp_update_rto_stats(sk); if (!tp->retrans_stamp) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 81f5bda2a89f..527ae9fc1c41 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1155,10 +1155,19 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg, ifa->flags |= IFA_F_TENTATIVE; ifa->valid_lft = cfg->valid_lft; ifa->prefered_lft = cfg->preferred_lft; - ifa->cstamp = ifa->tstamp = jiffies; ifa->tokenized = false; ifa->rt = f6i; + ifa->ifpub = cfg->ifpub; + if (cfg->ifpub) { + ifa->cstamp = cfg->cstamp; + ifa->tstamp = cfg->tstamp; + } else { + unsigned long now = jiffies; + + ifa->cstamp = now; + ifa->tstamp = now; + } ifa->idev = idev; in6_dev_hold(idev); @@ -1168,14 +1177,18 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg, rcu_read_lock(); - err = ipv6_add_addr_hash(idev->dev, ifa); + write_lock_bh(&idev->lock); + + if (idev->dead) + err = -ENODEV; + else + err = ipv6_add_addr_hash(idev->dev, ifa); if (err < 0) { + write_unlock_bh(&idev->lock); rcu_read_unlock(); goto out; } - write_lock_bh(&idev->lock); - /* Add to inet6_dev unicast addr list. */ ipv6_link_dev_addr(idev, ifa); @@ -1487,6 +1500,9 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block) cfg.pfx = &addr; cfg.scope = ipv6_addr_scope(cfg.pfx); + cfg.ifpub = ifp; + cfg.cstamp = now; + cfg.tstamp = tmp_tstamp; ift = ipv6_add_addr(idev, &cfg, block, NULL); if (IS_ERR(ift)) { @@ -1497,12 +1513,6 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block) goto retry; } - spin_lock_bh(&ift->lock); - ift->ifpub = ifp; - ift->cstamp = now; - ift->tstamp = tmp_tstamp; - spin_unlock_bh(&ift->lock); - addrconf_dad_start(ift); in6_ifa_put(ift); in6_dev_put(idev); @@ -2188,6 +2198,7 @@ void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp) ifp->idev->dev->name, &ifp->addr, eth_hdr(skb)->h_source); if (ifp->flags & IFA_F_STABLE_PRIVACY) { + bool start_dad = false; struct in6_addr new_addr; struct inet6_ifaddr *ifp2; int retries = ifp->stable_privacy_retry + 1; @@ -2226,11 +2237,14 @@ void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp) goto lock_errdad; spin_lock_bh(&ifp2->lock); - ifp2->stable_privacy_retry = retries; - ifp2->state = INET6_IFADDR_STATE_PREDAD; + if (ifp2->state != INET6_IFADDR_STATE_DEAD) { + ifp2->stable_privacy_retry = retries; + start_dad = true; + } spin_unlock_bh(&ifp2->lock); - addrconf_mod_dad_work(ifp2, net->ipv6.sysctl.idgen_delay); + if (start_dad) + addrconf_mod_dad_work(ifp2, net->ipv6.sysctl.idgen_delay); in6_ifa_put(ifp2); lock_errdad: spin_lock_bh(&ifp->lock); @@ -3884,7 +3898,9 @@ static int addrconf_ifdown(struct net_device *dev, bool unregister) * Do not dev_put! */ if (unregister) { + write_lock_bh(&idev->lock); WRITE_ONCE(idev->dead, 1); + write_unlock_bh(&idev->lock); /* protected by rtnl_lock */ RCU_INIT_POINTER(dev->ip6_ptr, NULL); @@ -4006,6 +4022,10 @@ static int addrconf_ifdown(struct net_device *dev, bool unregister) } if (!keep) { + spin_lock_bh(&net->ipv6.addrconf_hash_lock); + hlist_del_init_rcu(&ifa->addr_lst); + spin_unlock_bh(&net->ipv6.addrconf_hash_lock); + write_lock_bh(&idev->lock); list_del_rcu(&ifa->if_list); write_unlock_bh(&idev->lock); diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 182d38e6d6d8..f4f39a20e951 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -73,7 +73,9 @@ struct sock *__inet6_lookup_established(const struct net *net, if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt))) goto out; - if (unlikely(!inet6_match(net, sk, saddr, daddr, ports, dif, sdif))) { + if (unlikely(hlist_nulls_unhashed_lockless(&sk->sk_nulls_node) || + !inet6_match(net, sk, saddr, daddr, ports, dif, + sdif))) { sock_gen_put(sk); goto begin; } diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c index 07cdaa10da0d..5e08d8529cc8 100644 --- a/net/ipv6/netfilter/nf_reject_ipv6.c +++ b/net/ipv6/netfilter/nf_reject_ipv6.c @@ -444,6 +444,11 @@ 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_INGRESS) { + memset(IP6CB(skb_in), 0, sizeof(*IP6CB(skb_in))); + IP6CB(skb_in)->iif = skb_in->skb_iif; + } + if (!skb_valid_dst(skb_in) && nf_reject6_fill_skb_dst(skb_in) < 0) return; diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 25ec8001898d..c10a8a9d607e 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -227,6 +227,7 @@ static int ip6_frag_queue(struct net *net, } skb_dst_drop(skb); + skb_orphan(skb); return -EINPROGRESS; insert_error: diff --git a/net/ipv6/route.c b/net/ipv6/route.c index ce60fe53b822..c3a837bdd0cb 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -3264,7 +3264,7 @@ EXPORT_SYMBOL_GPL(ip6_sk_redirect); static unsigned int ip6_default_advmss(const struct dst_entry *dst) { - unsigned int mtu = ip6_dst_mtu_configured(dst); + unsigned int mtu = dst6_mtu(dst); struct net *net; mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index e14a49180eef..df09dcfd15ce 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3921,9 +3921,16 @@ static int mptcp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) * subflow_finish_connect() */ if (unlikely(err)) { - /* avoid leaving a dangling token in an unconnected socket */ mptcp_token_destroy(msk); mptcp_set_state(sk, TCP_CLOSE); + + spin_lock_bh(&msk->fallback_lock); + msk->allow_subflows = true; + msk->allow_infinite_fallback = true; + clear_bit(MPTCP_FALLBACK_DONE, &msk->flags); + spin_unlock_bh(&msk->fallback_lock); + + mptcp_subflow_ctx_reset(mptcp_subflow_ctx(ssk)); return err; } diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index dc8920a6a90c..184831b5b624 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -543,14 +543,16 @@ struct mptcp_subflow_context { closing : 1, /* must not pass rx data to msk anymore */ valid_csum_seen : 1, /* at least one csum validated */ is_mptfo : 1, /* subflow is doing TFO */ - close_event_done : 1, /* has done the post-closed part */ mpc_drop : 1, /* the MPC option has been dropped in a rtx */ resetting : 1, /* subflow is resetting */ - __unused : 8; + __unused : 9; bool data_avail; bool scheduled; bool pm_listener; /* a listener managed by the kernel PM? */ bool fully_established; /* path validated */ + bool close_event_done; /* has done the post-closed part, + * protected by msk socket lock + */ u32 lent_mem_frag; u32 remote_nonce; u64 thmac; diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 1932fcf9f925..e020960f093e 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -47,6 +47,39 @@ static void subflow_req_destructor(struct request_sock *req) mptcp_token_destroy_request(req); } +void mptcp_subflow_reqsk_clone(struct request_sock *req, + struct request_sock *new_req) +{ + struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req); + struct mptcp_subflow_request_sock *new_subflow_req; + struct mptcp_sock *msk; + + new_subflow_req = mptcp_subflow_rsk(new_req); + RCU_LOCKDEP_WARN(!rcu_read_lock_any_held(), + "MPTCP reqsk clone called without RCU"); + + /* A non-NULL ->msk means the request owns one reference. The clone + * copied only the pointer, while the original request can concurrently + * transfer its reference to the child. Acquire a reference for the + * clone, then verify that the original request still owns the same msk. + * MPTCP sockets use SLAB_TYPESAFE_BY_RCU and all clone callers run in + * an RCU read-side critical section, keeping the memory stable here. + */ + msk = READ_ONCE(subflow_req->msk); + if (msk) { + struct sock *sk = (struct sock *)msk; + + if (!refcount_inc_not_zero_acquire(&sk->sk_refcnt)) { + msk = NULL; + } else if (READ_ONCE(subflow_req->msk) != msk) { + sock_put(sk); + msk = NULL; + } + } + + new_subflow_req->msk = msk; +} + static void subflow_generate_hmac(u64 key1, u64 key2, u32 nonce1, u32 nonce2, void *hmac) { @@ -925,7 +958,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, } /* move the msk reference ownership to the subflow */ - subflow_req->msk = NULL; + WRITE_ONCE(subflow_req->msk, NULL); ctx->conn = (struct sock *)owner; if (subflow_use_different_sport(owner, sk)) { diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 6ccb23a640d8..0ff9da922c39 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1098,13 +1098,13 @@ static int ctnetlink_filter_match_tuple(struct nf_conntrack_tuple *filter_tuple, break; case NFPROTO_IPV6: if ((flags & CTA_FILTER_FLAG(CTA_IP_SRC)) && - !ipv6_addr_cmp(&filter_tuple->src.u3.in6, - &ct_tuple->src.u3.in6)) + !ipv6_addr_equal(&filter_tuple->src.u3.in6, + &ct_tuple->src.u3.in6)) return 0; if ((flags & CTA_FILTER_FLAG(CTA_IP_DST)) && - !ipv6_addr_cmp(&filter_tuple->dst.u3.in6, - &ct_tuple->dst.u3.in6)) + !ipv6_addr_equal(&filter_tuple->dst.u3.in6, + &ct_tuple->dst.u3.in6)) return 0; break; } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 4516e5452522..7b8ba1690d54 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2646,6 +2646,12 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, } offset = offset_in_page(data); + if (unlikely(to_write > MAX_SKB_FRAGS * PAGE_SIZE - offset)) { + net_warn_ratelimited("Packet exceed the number of skb frags(%u)\n", + (unsigned int)MAX_SKB_FRAGS); + return -EFAULT; + } + len_max = PAGE_SIZE - offset; len = ((to_write > len_max) ? len_max : to_write); @@ -2657,12 +2663,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, while (likely(to_write)) { nr_frags = skb_shinfo(skb)->nr_frags; - if (unlikely(nr_frags >= MAX_SKB_FRAGS)) { - pr_err("Packet exceed the number of skb frags(%u)\n", - (unsigned int)MAX_SKB_FRAGS); - return -EFAULT; - } - page = pgv_to_page(data); data += len; flush_dcache_page(page); diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 1c6e3b3f39d0..c8771aa7df53 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -1271,6 +1271,7 @@ void rds_ib_conn_free(void *arg) { struct rds_ib_connection *ic = arg; spinlock_t *lock_ptr; + unsigned long flags; rdsdebug("ic %p\n", ic); @@ -1281,9 +1282,10 @@ void rds_ib_conn_free(void *arg) */ lock_ptr = ic->rds_ibdev ? &ic->rds_ibdev->spinlock : &ib_nodev_conns_lock; - spin_lock_irq(lock_ptr); + /* May be called with IRQs already disabled (see __rds_conn_create()) */ + spin_lock_irqsave(lock_ptr, flags); list_del(&ic->ib_node); - spin_unlock_irq(lock_ptr); + spin_unlock_irqrestore(lock_ptr, flags); rds_ib_recv_free_caches(ic); diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index 0b52e060988d..ad4ff441bc98 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -949,6 +949,12 @@ static void rds_ib_process_recv(struct rds_connection *conn, } } + if (data_len < min_t(u32, ic->i_recv_data_rem, RDS_FRAG_SIZE)) { + rds_ib_conn_error(conn, + "fragment shorter than header-declared length; forcing reconnect\n"); + goto done; + } + list_add_tail(&recv->r_frag->f_item, &ibinc->ii_frags); recv->r_frag = NULL; @@ -1004,7 +1010,12 @@ void rds_ib_recv_cqe_handler(struct rds_ib_connection *ic, * event is processed. */ if (wc->status == IB_WC_SUCCESS) { - rds_ib_process_recv(conn, recv, wc->byte_len, state); + if (wc->opcode != IB_WC_RECV) + rds_ib_conn_error(conn, + "recv completion had unexpected opcode %u, disconnecting and reconnecting\n", + wc->opcode); + else + rds_ib_process_recv(conn, recv, wc->byte_len, state); } else { /* We expect errors as the qp is drained during shutdown */ if (rds_conn_up(conn) || rds_conn_connecting(conn)) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 03588ac5c382..8c9970352952 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -75,7 +75,8 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, struct sctp_transport *transport, long *timeo_p, size_t msg_len); static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p); -static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); +static int sctp_wait_for_connect(struct sctp_association *, + struct sctp_transport *, long *timeo_p); static int sctp_wait_for_accept(struct sock *sk, long timeo); static void sctp_wait_for_close(struct sock *sk, long timeo); static void sctp_destruct_sock(struct sock *sk); @@ -1244,7 +1245,7 @@ static int __sctp_connect(struct sock *sk, struct sockaddr *kaddrs, *assoc_id = asoc->assoc_id; timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); - return sctp_wait_for_connect(asoc, &timeo); + return sctp_wait_for_connect(asoc, NULL, &timeo); out_free: pr_debug("%s: took out_free path with asoc:%p kaddrs:%p err:%d\n", @@ -1846,7 +1847,7 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc, if (asoc->ep->intl_enable) { timeo = sock_sndtimeo(sk, 0); - err = sctp_wait_for_connect(asoc, &timeo); + err = sctp_wait_for_connect(asoc, transport, &timeo); if (err || sk->sk_shutdown & RCV_SHUTDOWN) { err = -ESRCH; goto err; @@ -1889,7 +1890,7 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc, if (unlikely(wait_connect)) { timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); - sctp_wait_for_connect(asoc, &timeo); + sctp_wait_for_connect(asoc, NULL, &timeo); } err = msg_len; @@ -9337,7 +9338,9 @@ static bool sctp_writeable(const struct sock *sk) /* Wait for an association to go into ESTABLISHED state. If timeout is 0, * returns immediately with EINPROGRESS. */ -static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) +static int sctp_wait_for_connect(struct sctp_association *asoc, + struct sctp_transport *transport, + long *timeo_p) { struct sock *sk = asoc->base.sk; int err = 0; @@ -9346,12 +9349,16 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) pr_debug("%s: asoc:%p, timeo:%ld\n", __func__, asoc, *timeo_p); - /* Increment the association's refcnt. */ + /* Hold references while the socket lock is dropped. */ + if (transport) + sctp_transport_hold(transport); sctp_association_hold(asoc); for (;;) { prepare_to_wait_exclusive(&asoc->wait, &wait, TASK_INTERRUPTIBLE); + if (transport && transport->dead) + goto do_transport_dead; if (!*timeo_p) goto do_nonblock; if (sk->sk_shutdown & RCV_SHUTDOWN) @@ -9380,7 +9387,8 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) out: finish_wait(&asoc->wait, &wait); - /* Release the association's refcnt. */ + if (transport) + sctp_transport_put(transport); sctp_association_put(asoc); return err; @@ -9399,6 +9407,10 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) do_nonblock: err = -EINPROGRESS; goto out; + +do_transport_dead: + err = -EAGAIN; + goto out; } static int sctp_wait_for_accept(struct sock *sk, long timeo) diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c index 3144b4b1fe29..495fb1354728 100644 --- a/net/smc/smc_tx.c +++ b/net/smc/smc_tx.c @@ -249,6 +249,13 @@ int smc_tx_sendmsg(struct smc_sock *smc, struct msghdr *msg, size_t len) rc = memcpy_from_msg(sndbuf_base + chunk_off, msg, chunk_len); if (rc) { + if (chunk) { + /* send_done counts the first chunk: + * queue it and retry the rest + */ + copylen -= chunk_len; + break; + } smc_sndbuf_sync_sg_for_device(conn); if (send_done) return send_done; diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index e2694fb03ba1..091b8cb415ec 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@ -1033,12 +1033,16 @@ void rpcrdma_reset_cwnd(struct rpcrdma_xprt *r_xprt) * @rqst: controlling RPC request * @srcp: points to RPC message payload in receive buffer * @copy_len: remaining length of receive buffer content - * @pad: Write chunk pad bytes needed (zero for pure inline) + * @writelist: bytes conveyed by the Write chunk (zero for pure inline) * * The upper layer has set the maximum number of bytes it can * receive in each component of rq_rcv_buf. These values are set in * the head.iov_len, page_len, tail.iov_len, and buflen fields. * + * For READ replies with a Write chunk, the payload is already in + * the page list. An overestimated head length and buflen can be + * reduced without moving reply data. + * * Unlike the TCP equivalent (xdr_partial_copy_from_skb), in * many cases this function simply updates iov_base pointers in * rq_rcv_buf to point directly to the received reply data, to @@ -1047,13 +1051,16 @@ void rpcrdma_reset_cwnd(struct rpcrdma_xprt *r_xprt) * Returns the count of bytes which had to be memcopied. */ static unsigned long -rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) +rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, + u32 writelist) { unsigned long fixup_copy_count; int i, npages, curlen; char *destp; struct page **ppages; int page_base; + int pad = writelist & 3; + unsigned int delta; /* The head iovec is redirected to the RPC reply message * in the receive buffer, to avoid a memcopy. @@ -1065,8 +1072,20 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) * head.iov_len bytes are copied into the page list. */ curlen = rqst->rq_rcv_buf.head[0].iov_len; - if (curlen > copy_len) + if (curlen > copy_len) { + /* These READ replies have no inline fields after the payload. + * Trim the head without moving the directly-placed data. + */ + if (writelist) { + delta = curlen - copy_len; + + rqst->rq_rcv_buf.head[0].iov_len = copy_len; + rqst->rq_private_buf.head[0].iov_len = copy_len; + rqst->rq_rcv_buf.buflen -= delta; + rqst->rq_private_buf.buflen -= delta; + } curlen = copy_len; + } srcp += curlen; copy_len -= curlen; @@ -1294,7 +1313,7 @@ rpcrdma_decode_msg(struct rpcrdma_xprt *r_xprt, struct rpcrdma_rep *rep, base = (char *)xdr_inline_decode(xdr, 0); rpclen = xdr_stream_remaining(xdr); r_xprt->rx_stats.fixup_copy_count += - rpcrdma_inline_fixup(rqst, base, rpclen, writelist & 3); + rpcrdma_inline_fixup(rqst, base, rpclen, writelist); r_xprt->rx_stats.total_rdma_reply += writelist; return rpclen + xdr_align_size(writelist); diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 4afa662430ca..d9bc86fa09bc 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -469,7 +469,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) newxprt->sc_max_requests = svcrdma_max_requests; newxprt->sc_max_bc_requests = svcrdma_max_bc_requests; newxprt->sc_recv_batch = RPCRDMA_MAX_RECV_BATCH; - newxprt->sc_fc_credits = cpu_to_be32(newxprt->sc_max_requests); /* Qualify the transport's resource defaults with the * capabilities of this particular device. @@ -490,6 +489,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) newxprt->sc_max_bc_requests = 2; } + newxprt->sc_fc_credits = cpu_to_be32(newxprt->sc_max_requests); + /* Estimate the needed number of rdma_rw contexts. The maximum * Read and Write chunks have one segment each. Each request * can involve one Read chunk and either a Write chunk or Reply diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 8449107b2a09..111c415f1aed 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -114,9 +114,9 @@ static void rpcrdma_xprt_drain(struct rpcrdma_xprt *r_xprt) rpcrdma_ep_put(ep); } -/* Ensure xprt_force_disconnect() is invoked exactly once when a - * connection is closed or lost. (The important thing is it needs - * to be invoked "at least" once). +/* Ensure xprt_force_disconnect() is invoked at most once for an + * unexpected endpoint failure. Local endpoint teardown closes this + * gate before it can generate CM events and flushed completions. */ void rpcrdma_force_disconnect(struct rpcrdma_ep *ep) { @@ -587,6 +587,9 @@ void rpcrdma_xprt_disconnect(struct rpcrdma_xprt *r_xprt) if (!ep) return; + /* Prevent teardown-generated events from requesting another close. */ + atomic_xchg(&ep->re_force_disconnect, 1); + id = ep->re_id; rc = rdma_disconnect(id); trace_xprtrdma_disconnect(r_xprt, rc); diff --git a/net/tipc/group.c b/net/tipc/group.c index 0da7b2713394..a9ce1c7018b6 100644 --- a/net/tipc/group.c +++ b/net/tipc/group.c @@ -74,7 +74,7 @@ struct tipc_member { u16 window; u16 bc_rcv_nxt; u16 bc_syncpt; - u16 bc_acked; + bool bc_pending; }; struct tipc_group { @@ -316,7 +316,6 @@ static struct tipc_member *tipc_group_create_member(struct tipc_group *grp, m->node = node; m->port = port; m->instance = instance; - m->bc_acked = grp->bc_snd_nxt - 1; ret = tipc_group_add_to_tree(grp, m); if (ret < 0) { kfree(m); @@ -340,9 +339,12 @@ static void tipc_group_delete_member(struct tipc_group *grp, rb_erase(&m->tree_node, &grp->members); grp->member_cnt--; - /* Check if we were waiting for replicast ack from this member */ - if (grp->bc_ackers && less(m->bc_acked, grp->bc_snd_nxt - 1)) - grp->bc_ackers--; + /* If this member owed an ack for the current replicast and it + * was the last one, restore the open state so blocked broadcast + * senders can proceed. + */ + if (grp->bc_ackers && m->bc_pending && !--grp->bc_ackers) + *grp->open = true; list_del_init(&m->list); list_del_init(&m->small_win); @@ -394,7 +396,6 @@ void tipc_group_update_member(struct tipc_member *m, int len) void tipc_group_update_bc_members(struct tipc_group *grp, int len, bool ack) { - u16 prev = grp->bc_snd_nxt - 1; struct tipc_member *m; struct rb_node *n; u16 ackers = 0; @@ -403,8 +404,8 @@ void tipc_group_update_bc_members(struct tipc_group *grp, int len, bool ack) m = container_of(n, struct tipc_member, tree_node); if (tipc_group_is_receiver(m)) { tipc_group_update_member(m, len); - m->bc_acked = prev; ackers++; + m->bc_pending = ack; } } @@ -800,9 +801,9 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup, if (!m || !grp->bc_ackers) return; acked = msg_grp_bc_acked(hdr); - if (acked != grp->bc_snd_nxt || m->bc_acked == acked) + if (acked != grp->bc_snd_nxt || !m->bc_pending) return; - m->bc_acked = acked; + m->bc_pending = false; if (--grp->bc_ackers) return; list_del_init(&m->small_win); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index af14b50933f5..4780264a8a49 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2355,8 +2355,18 @@ static void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb, if (unlikely(!msg_isdata(hdr))) tipc_sk_proto_rcv(sk, &inputq, xmitq); - if (unlikely(grp)) + if (unlikely(grp)) { + bool was_open = tsk->group_is_open; + tipc_group_filter_msg(grp, &inputq, xmitq); + /* A departing member may have held the last outstanding + * replicast ack, which can restore the open state inside + * tipc_group_filter_msg(); wake up senders blocked in + * poll()/write() if the group just became writable. + */ + if (!was_open && tsk->group_is_open) + sk->sk_write_space(sk); + } if (unlikely(!grp) && mtyp == TIPC_MCAST_MSG) tipc_mcast_filter_msg(net, &tsk->mc_method.deferredq, &inputq); diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c index e02ed6e3955c..bb93cf3aa6fe 100644 --- a/net/unix/sysctl_net_unix.c +++ b/net/unix/sysctl_net_unix.c @@ -19,7 +19,9 @@ static struct ctl_table unix_table[] = { .data = &init_net.unx.sysctl_max_dgram_qlen, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_INT_MAX, }, }; diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c index 5ee0edaf075c..9dc1ff31867a 100644 --- a/net/xdp/xsk_buff_pool.c +++ b/net/xdp/xsk_buff_pool.c @@ -175,6 +175,7 @@ int xp_assign_dev(struct xsk_buff_pool *pool, { u32 needed = netdev->mtu + ETH_PAD_LEN; u32 segs = netdev->xdp_zc_max_segs; + u8 umem_flags = pool->umem->flags; bool mbuf = flags & XDP_USE_SG; bool force_zc, force_copy; struct netdev_bpf bpf; @@ -270,6 +271,7 @@ int xp_assign_dev(struct xsk_buff_pool *pool, if (!force_zc) err = 0; /* fallback to copy mode */ if (err) { + pool->umem->flags = umem_flags; xsk_clear_pool_at_qid(netdev, queue_id); dev_put(netdev); } diff --git a/rust/Makefile b/rust/Makefile index d4618f646b05..d6429e68949f 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -367,7 +367,10 @@ quiet_cmd_bindgen = BINDGEN $@ $(obj)/bindings/bindings_generated.rs: private bindgen_target_flags = \ $(shell grep -Ev '^#|^$$' $(src)/bindgen_parameters) $(obj)/bindings/bindings_generated.rs: private bindgen_target_extra = ; \ - sed -Ei 's/pub const RUST_CONST_HELPER_([a-zA-Z0-9_]*)/pub const \1/g' $@ + sed -Ei 's/pub const RUST_CONST_HELPER_([a-zA-Z0-9_]*)/pub const \1/g' $@; \ + sed -Ei 's/^pub struct dma_data_direction\(/#[cfi_encoding="18dma_data_direction"]\n&/' $@; \ + sed -Ei 's/^pub struct hrtimer_restart\(/#[cfi_encoding="15hrtimer_restart"]\n&/' $@; \ + sed -Ei 's/^pub struct irqreturn\(/#[cfi_encoding="9irqreturn"]\n&/' $@ $(obj)/bindings/bindings_generated.rs: $(src)/bindings/bindings_helper.h \ $(src)/bindgen_parameters FORCE $(call if_changed_dep,bindgen) diff --git a/rust/bindgen_parameters b/rust/bindgen_parameters index e13c6f9dd17b..a5d547dc8e8e 100644 --- a/rust/bindgen_parameters +++ b/rust/bindgen_parameters @@ -23,6 +23,11 @@ # warning. We don't need to peek into it anyway. --opaque-type spinlock +# enums that appear in indirect function calls should specify a cfi type +--newtype-enum dma_data_direction +--newtype-enum hrtimer_restart +--newtype-enum irqreturn + # `seccomp`'s comment gets understood as a doctest --no-doc-comments diff --git a/rust/bindings/lib.rs b/rust/bindings/lib.rs index 8305adbdf8cb..37f584727eba 100644 --- a/rust/bindings/lib.rs +++ b/rust/bindings/lib.rs @@ -23,6 +23,7 @@ unreachable_pub, unsafe_op_in_unsafe_fn )] +#![feature(cfi_encoding)] #[allow(dead_code)] #[allow(clippy::as_underscore)] diff --git a/rust/kernel/bitmap.rs b/rust/kernel/bitmap.rs index 0e5e825aefb6..a00988bc8191 100644 --- a/rust/kernel/bitmap.rs +++ b/rust/kernel/bitmap.rs @@ -19,7 +19,7 @@ /// Must reference a `[c_ulong]` long enough to fit `data.len()` bits. /// Must not be longer than [`i32::MAX`] bits, so offsets and lengths used with /// [`Bitmap`] functions fit in the `int` and `unsigned int` arguments of the C bitmap API. -/// This also matches [`BitmapVec::MAX_LEN`]. +/// This also matches the maximum length accepted by [`BitmapVec::new`]. #[cfg_attr(CONFIG_64BIT, repr(align(8)))] #[cfg_attr(not(CONFIG_64BIT), repr(align(4)))] pub struct Bitmap { diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 4ce9e5d7f3dd..b6c73db358ce 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -267,25 +267,25 @@ pub enum DataDirection { /// /// This is used when the buffer can be both read from and written to by the device. /// The cache for the corresponding memory region is both flushed and invalidated. - Bidirectional = Self::const_cast(bindings::dma_data_direction_DMA_BIDIRECTIONAL), + Bidirectional = Self::const_cast(bindings::dma_data_direction::DMA_BIDIRECTIONAL), /// The DMA mapping is for data transfer from memory to the device (write). /// /// The CPU has prepared data in the buffer, and the device will read it. /// The cache for the corresponding memory region is flushed before device access. - ToDevice = Self::const_cast(bindings::dma_data_direction_DMA_TO_DEVICE), + ToDevice = Self::const_cast(bindings::dma_data_direction::DMA_TO_DEVICE), /// The DMA mapping is for data transfer from the device to memory (read). /// /// The device will write data into the buffer for the CPU to read. /// The cache for the corresponding memory region is invalidated before CPU access. - FromDevice = Self::const_cast(bindings::dma_data_direction_DMA_FROM_DEVICE), + FromDevice = Self::const_cast(bindings::dma_data_direction::DMA_FROM_DEVICE), /// The DMA mapping is not for data transfer. /// /// This is primarily for debugging purposes. With this direction, the DMA mapping API /// will not perform any cache coherency operations. - None = Self::const_cast(bindings::dma_data_direction_DMA_NONE), + None = Self::const_cast(bindings::dma_data_direction::DMA_NONE), } impl DataDirection { @@ -297,7 +297,7 @@ const fn const_cast(val: bindings::dma_data_direction) -> u32 { // CAST: The C standard allows compilers to choose different integer types for enums. // To safely check the value, we cast it to a wide signed integer type (`i128`) // which can hold any standard C integer enum type without truncation. - let wide_val = val as i128; + let wide_val = val.0 as i128; // Check if the value is outside the valid range for the target type `u32`. // CAST: `u32::MAX` is cast to `i128` to match the type of `wide_val` for the comparison. @@ -315,11 +315,12 @@ const fn const_cast(val: bindings::dma_data_direction) -> u32 { impl From for bindings::dma_data_direction { /// Returns the raw representation of [`enum dma_data_direction`]. fn from(direction: DataDirection) -> Self { - // CAST: `direction as u32` gets the underlying representation of our `#[repr(u32)]` enum. - // The subsequent cast to `Self` (the bindgen type) assumes the C enum is compatible - // with the enum variants of `DataDirection`, which is a valid assumption given our - // compile-time checks. - direction as u32 as Self + match direction { + DataDirection::Bidirectional => Self::DMA_BIDIRECTIONAL, + DataDirection::ToDevice => Self::DMA_TO_DEVICE, + DataDirection::FromDevice => Self::DMA_FROM_DEVICE, + DataDirection::None => Self::DMA_NONE, + } } } diff --git a/rust/kernel/irq/request.rs b/rust/kernel/irq/request.rs index 70700f43ddd3..4f2b315856b9 100644 --- a/rust/kernel/irq/request.rs +++ b/rust/kernel/irq/request.rs @@ -20,10 +20,10 @@ #[repr(u32)] pub enum IrqReturn { /// The interrupt was not from this device or was not handled. - None = bindings::irqreturn_IRQ_NONE, + None = bindings::irqreturn::IRQ_NONE.0, /// The interrupt was handled by this device. - Handled = bindings::irqreturn_IRQ_HANDLED, + Handled = bindings::irqreturn::IRQ_HANDLED.0, } /// Callbacks for an IRQ handler. @@ -275,7 +275,7 @@ pub fn synchronize(&self, dev: &Device) -> Result { unsafe extern "C" fn handle_irq_callback( _irq: i32, ptr: *mut c_void, -) -> c_uint { +) -> bindings::irqreturn_t { // SAFETY: `ptr` is a pointer to `RegistrationInner` set in `Registration::new` let inner = unsafe { &*(ptr as *const RegistrationInner) }; // SAFETY: `inner.handler` is a pointer to `T` set in `Registration::new` @@ -284,20 +284,20 @@ pub fn synchronize(&self, dev: &Device) -> Result { // callback is running implies that the device has not yet been unbound. let device = unsafe { inner.dev.as_bound() }; - T::handle(handler, device) as c_uint + bindings::irqreturn_t(T::handle(handler, device) as c_uint) } /// The value that can be returned from [`ThreadedHandler::handle`]. #[repr(u32)] pub enum ThreadedIrqReturn { /// The interrupt was not from this device or was not handled. - None = bindings::irqreturn_IRQ_NONE, + None = bindings::irqreturn::IRQ_NONE.0, /// The interrupt was handled by this device. - Handled = bindings::irqreturn_IRQ_HANDLED, + Handled = bindings::irqreturn::IRQ_HANDLED.0, /// The handler wants the handler thread to wake up. - WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD, + WakeThread = bindings::irqreturn::IRQ_WAKE_THREAD.0, } /// Callbacks for a threaded IRQ handler. @@ -501,7 +501,7 @@ pub fn synchronize(&self, dev: &Device) -> Result { unsafe extern "C" fn handle_threaded_irq_callback( _irq: i32, ptr: *mut c_void, -) -> c_uint { +) -> bindings::irqreturn_t { // SAFETY: `ptr` is a pointer to `RegistrationInner` set in `ThreadedRegistration::new` let inner = unsafe { &*(ptr as *const RegistrationInner) }; // SAFETY: `inner.handler` is a pointer to `T` set in `ThreadedRegistration::new` @@ -510,7 +510,7 @@ pub fn synchronize(&self, dev: &Device) -> Result { // callback is running implies that the device has not yet been unbound. let device = unsafe { inner.dev.as_bound() }; - T::handle(handler, device) as c_uint + bindings::irqreturn_t(T::handle(handler, device) as c_uint) } /// # Safety @@ -519,7 +519,7 @@ pub fn synchronize(&self, dev: &Device) -> Result { unsafe extern "C" fn thread_fn_callback( _irq: i32, ptr: *mut c_void, -) -> c_uint { +) -> bindings::irqreturn_t { // SAFETY: `ptr` is a pointer to `RegistrationInner` set in `ThreadedRegistration::new` let inner = unsafe { &*(ptr as *const RegistrationInner) }; // SAFETY: `inner.handler` is a pointer to `T` set in `ThreadedRegistration::new` @@ -528,5 +528,5 @@ pub fn synchronize(&self, dev: &Device) -> Result { // callback is running implies that the device has not yet been unbound. let device = unsafe { inner.dev.as_bound() }; - T::handle_threaded(handler, device) as c_uint + bindings::irqreturn_t(T::handle_threaded(handler, device) as c_uint) } diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index 856d2d929a00..35ff2ef7d944 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -498,14 +498,14 @@ unsafe fn start(this: *const Self, expires: ::Ex #[repr(u32)] pub enum HrTimerRestart { /// Timer should not be restarted. - NoRestart = bindings::hrtimer_restart_HRTIMER_NORESTART, + NoRestart = bindings::hrtimer_restart::HRTIMER_NORESTART.0, /// Timer should be restarted. - Restart = bindings::hrtimer_restart_HRTIMER_RESTART, + Restart = bindings::hrtimer_restart::HRTIMER_RESTART.0, } impl HrTimerRestart { fn into_c(self) -> bindings::hrtimer_restart { - self as bindings::hrtimer_restart + bindings::hrtimer_restart(self as c_uint) } } diff --git a/scripts/Makefile.autofdo b/scripts/Makefile.autofdo index 1caf2457e585..0b14a05726ad 100644 --- a/scripts/Makefile.autofdo +++ b/scripts/Makefile.autofdo @@ -18,7 +18,7 @@ ifdef CONFIG_LTO_CLANG_THIN KBUILD_LDFLAGS += --lto-sample-profile=$(CLANG_AUTOFDO_PROFILE) endif KBUILD_LDFLAGS += --mllvm=-enable-fs-discriminator=true --mllvm=-improved-fs-discriminator=true -plugin-opt=thinlto - KBUILD_LDFLAGS += -plugin-opt=-split-machine-functions + KBUILD_LDFLAGS += $(call ld-option,-plugin-opt=-function-splitting=all,-plugin-opt=-split-machine-functions) endif export CFLAGS_AUTOFDO_CLANG diff --git a/security/apparmor/af_unix.c b/security/apparmor/af_unix.c index 834a3b1c2f0a..aa2b31d5598c 100644 --- a/security/apparmor/af_unix.c +++ b/security/apparmor/af_unix.c @@ -676,7 +676,7 @@ static void update_sk_ctx(struct sock *sk, struct aa_label *label, if (old == plabel) { rcu_assign_pointer(ctx->peer_lastupdate, aa_get_label(plabel)); - } else if (aa_label_is_subset(plabel, old)) { + } else if (!old || aa_label_is_subset(plabel, old)) { rcu_assign_pointer(ctx->peer_lastupdate, aa_get_label(plabel)); rcu_assign_pointer(ctx->peer, aa_get_label(plabel)); @@ -694,13 +694,17 @@ static void update_peer_ctx(struct sock *sk, struct aa_sk_ctx *ctx, spin_lock(&unix_sk(sk)->lock); old = rcu_dereference_protected(ctx->peer, lockdep_is_held(&unix_sk(sk)->lock)); - l = aa_label_merge(old, label, GFP_ATOMIC); - if (l) { - if (l != old) { - rcu_assign_pointer(ctx->peer, l); - aa_put_label(old); - } else - aa_put_label(l); + if (!old) { + rcu_assign_pointer(ctx->peer, aa_get_label(label)); + } else { + l = aa_label_merge(old, label, GFP_ATOMIC); + if (l) { + if (l != old) { + rcu_assign_pointer(ctx->peer, l); + aa_put_label(old); + } else + aa_put_label(l); + } } spin_unlock(&unix_sk(sk)->lock); } diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 534a93520c56..f8f9320e266a 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -691,49 +691,50 @@ static void revalidate_tty(const struct cred *subj_cred, struct aa_label *label) no_tty(); } -struct cred_label { - const struct cred *cred; - struct aa_label *label; -}; - -static int match_file(const void *p, struct file *file, unsigned int fd) +/* + * iterate_fd() callback, called with files->file_lock held: grab a ref + * on the next file so it can be revalidated without the lock held. + */ +static int get_next_file(const void *p, struct file *file, unsigned int fd) { - struct cred_label *cl = (struct cred_label *)p; + *(struct file **)p = get_file(file); - if (aa_file_perm(OP_INHERIT, cl->cred, cl->label, file, - aa_map_file_to_perms(file), IN_ATOMIC)) - return fd + 1; - return 0; + return fd + 1; } - /* based on selinux's flush_unauthorized_files */ void aa_inherit_files(const struct cred *cred, struct files_struct *files) { struct aa_label *label = aa_get_newest_cred_label(cred); - struct cred_label cl = { - .cred = cred, - .label = label, - }; - struct file *devnull = NULL; - unsigned int n; + struct file *devnull = NULL, *file = NULL; + bool devnull_tried = false; + unsigned int n = 0; revalidate_tty(cred, label); - /* Revalidate access to inherited open files. */ - n = iterate_fd(files, 0, match_file, &cl); - if (!n) /* none found? */ - goto out; - - devnull = dentry_open(&aa_null, O_RDWR, cred); - if (IS_ERR(devnull)) - devnull = NULL; - /* replace all the matching ones with this */ - do { + /* + * Revalidate access to inherited open files. Each file is + * revalidated holding only a reference to it, with no locks + * held, as revalidation may sleep (e.g. unix socket mediation + * dropping path refs, or allocating path buffers). + */ + while ((n = iterate_fd(files, n, get_next_file, &file)) != 0) { + int error = aa_file_perm(OP_INHERIT, cred, label, file, + aa_map_file_to_perms(file), false); + + fput(file); + if (!error) + continue; + if (!devnull_tried) { + devnull_tried = true; + devnull = dentry_open(&aa_null, O_RDWR, cred); + if (IS_ERR(devnull)) + devnull = NULL; + } + /* replace the denied fd (n - 1) with devnull, or close it */ replace_fd(n - 1, devnull, 0); - } while ((n = iterate_fd(files, n, match_file, &cl)) != 0); + } if (devnull) fput(devnull); -out: aa_put_label(label); } diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h index 574be681f83e..75c49e713a74 100644 --- a/security/apparmor/include/label.h +++ b/security/apparmor/include/label.h @@ -162,7 +162,11 @@ do { \ #define labels_ns(X) (vec_ns(&((X)->vec[0]), (X)->size)) #define labels_set(X) (&labels_ns(X)->labels) #define labels_view(X) labels_ns(X) -#define labels_profile(X) ((X)->vec[(X)->size - 1]) + +static inline struct aa_profile *labels_profile(const struct aa_label *label) +{ + return label->vec[label->size - 1]; +} int aa_label_next_confined(struct aa_label *l, int i); diff --git a/security/apparmor/label.c b/security/apparmor/label.c index 5c42cd01ea47..667f20363ebf 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -386,7 +386,6 @@ void aa_label_kref(struct kref *kref) label_free_switch(label); return; } - /* TODO: update labels_profile macro so it works here */ AA_BUG(label_isprofile(label) && on_list_rcu(&label->vec[0]->base.profiles)); AA_BUG(label_isprofile(label) && diff --git a/security/apparmor/match.c b/security/apparmor/match.c index b2a4bee4e393..e4ef1057e2c0 100644 --- a/security/apparmor/match.c +++ b/security/apparmor/match.c @@ -397,7 +397,6 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags) /* check for duplicate table entry */ if (dfa->tables[table->td_id]) goto fail; - dfa->tables[table->td_id] = table; data += table_size(table->td_lolen, table->td_flags); size -= table_size(table->td_lolen, table->td_flags); @@ -414,9 +413,9 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags) if (!table) goto fail; } - dfa->tables[table->td_id] = table; break; } + dfa->tables[table->td_id] = table; table = NULL; } error = verify_table_headers(dfa->tables, flags); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 70d6315a059a..230d8428b4d3 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -1163,6 +1163,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, struct aa_loaddata *rawdata_ent; const char *op; ssize_t count, error; + bool rawdata_created = false; LIST_HEAD(lh); op = mask & AA_MAY_REPLACE_POLICY ? OP_PROF_REPL : OP_PROF_LOAD; @@ -1302,6 +1303,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, ent = NULL; goto fail_lock; } + rawdata_created = true; } list_for_each_entry(ent, &lh, list) { if (!ent->old) { @@ -1397,6 +1399,20 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, return udata_sz; fail_lock: + /* + * Remove fs entries created by this load. Nothing else references + * them yet, and leaving them behind would leak the new profiles + * (their dents pin the proxy) and make the next load at the same, + * unbumped ns revision fail with -EEXIST on its raw_data dir. + * ensure children (which are at the end of the list are removed + * before their parent + */ + list_for_each_entry_reverse(tmp, &lh, list) { + if (!tmp->old) + __aafs_profile_rmdir(tmp->new); + } + if (rawdata_created) + __aa_fs_remove_rawdata(udata); mutex_unlock(&ns->lock); /* audit cause of failure */ diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 1e1792d3ff5a..391665c27ede 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -1244,6 +1244,15 @@ static bool verify_dfa_accept_index(struct aa_dfa *dfa, int table_size) for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) { if (ACCEPT_TABLE(dfa)[i] >= table_size) return false; + /* + * Accept indexes for owner-conditional permissions come in + * pairs, so the non-owner entry at index + 1 must also be + * in bounds. + */ + if (dfa->tables[YYTD_ID_ACCEPT2] && + (ACCEPT_TABLE2(dfa)[i] & ACCEPT_FLAG_OWNER) && + ACCEPT_TABLE(dfa)[i] + 1 >= table_size) + return false; } return true; } diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 065cdfaef1ea..e1b2da84f778 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -656,13 +656,30 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg) if (retval) return retval; - retval = snd_compr_allocate_buffer(stream, params); - if (retval) - return -ENOMEM; + if (stream->next_track) { + /* + * total_bytes_available/transferred still refer to the + * current buffer; its geometry must not change. + */ + if (params->buffer.fragment_size != stream->runtime->fragment_size || + params->buffer.fragments != stream->runtime->fragments) + return -EINVAL; + } else { + retval = snd_compr_allocate_buffer(stream, params); + if (retval) + return retval; + } retval = stream->ops->set_params(stream, params); - if (retval) + if (retval) { + /* the stream stays OPEN: drop the buffer of the rejected setup */ + if (stream->runtime->state == SNDRV_PCM_STATE_OPEN && + !stream->runtime->dma_buffer_p) { + kfree(stream->runtime->buffer); + stream->runtime->buffer = NULL; + } return retval; + } if (stream->next_track) return retval; @@ -731,6 +748,9 @@ snd_compr_set_metadata(struct snd_compr_stream *stream, unsigned long arg) * we should allow parameter change only when stream has been * opened not in other cases */ + if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) + return -EBADFD; + if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata))) return -EFAULT; @@ -1122,7 +1142,9 @@ static int snd_compr_task_start_prepare(struct snd_compr_task_runtime *task, { if (task == NULL) return -EINVAL; - if (task->state >= SND_COMPRESS_TASK_STATE_FINISHED) + /* only an unqueued or already finished task may be (re)started */ + if (task->state != SND_COMPRESS_TASK_STATE_IDLE && + task->state != SND_COMPRESS_TASK_STATE_FINISHED) return -EBUSY; if (utask->input_size > task->input->size) return -EINVAL; diff --git a/sound/core/init.c b/sound/core/init.c index 3a45fa6fc515..2bf98de846f6 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -1141,12 +1141,12 @@ EXPORT_SYMBOL(snd_card_file_remove); int snd_power_ref_and_wait(struct snd_card *card) { snd_power_ref(card); - if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0) - return 0; - wait_event_cmd(card->power_sleep, - card->shutdown || - snd_power_get_state(card) == SNDRV_CTL_POWER_D0, - snd_power_unref(card), snd_power_ref(card)); + if (snd_power_get_state(card) != SNDRV_CTL_POWER_D0) { + wait_event_cmd(card->power_sleep, + card->shutdown || + snd_power_get_state(card) == SNDRV_CTL_POWER_D0, + snd_power_unref(card), snd_power_ref(card)); + } if (card->shutdown) { snd_power_unref(card); return -ENODEV; diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h index 935cf3df0b30..571186db4fa5 100644 --- a/sound/core/seq/oss/seq_oss_device.h +++ b/sound/core/seq/oss/seq_oss_device.h @@ -72,6 +72,7 @@ struct seq_oss_devinfo { int cseq; /* sequencer client number */ int port; /* sequencer port number */ int queue; /* sequencer queue number */ + bool initialized; struct snd_seq_addr addr; /* address of this device */ diff --git a/sound/core/seq/oss/seq_oss_event.c b/sound/core/seq/oss/seq_oss_event.c index 122735862044..20f4c5ce763c 100644 --- a/sound/core/seq/oss/seq_oss_event.c +++ b/sound/core/seq/oss/seq_oss_event.c @@ -425,6 +425,9 @@ snd_seq_oss_event_input(struct snd_seq_event *ev, int direct, void *private_data struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data; union evrec *rec; + if (!dp || !smp_load_acquire(&dp->initialized)) + return 0; /* ignored */ + if (ev->type != SNDRV_SEQ_EVENT_ECHO) return snd_seq_oss_midi_input(ev, direct, private_data); diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index 973f057eb731..102c9358ce48 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -258,6 +258,7 @@ snd_seq_oss_open(struct file *file, int level) client_table[dp->index] = dp; num_clients++; + smp_store_release(&dp->initialized, true); return 0; @@ -403,6 +404,7 @@ snd_seq_oss_release(struct seq_oss_devinfo *dp) client_table[dp->index] = NULL; num_clients--; + smp_store_release(&dp->initialized, false); snd_seq_oss_reset(dp); diff --git a/sound/core/ump_convert.c b/sound/core/ump_convert.c index 85cc67de6330..0a7972d91ec5 100644 --- a/sound/core/ump_convert.c +++ b/sound/core/ump_convert.c @@ -323,7 +323,7 @@ static int fill_rpn(struct ump_cvt_to_ump_bank *cc, cc->cc_data_lsb); reset_rpn(cc); - return 1; + return 8; } /* convert to a MIDI 1.0 Channel Voice message */ diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index d08027681c37..fd8d6b474e46 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -365,11 +365,14 @@ static int loopback_check_format(struct loopback_cable *cable, int stream) runtime->channels != cruntime->channels || is_access_interleaved(runtime->access) != is_access_interleaved(cruntime->access); - if (!check) - return 0; - if (stream == SNDRV_PCM_STREAM_CAPTURE) + /* + * Matching params also go on to the update below, so that + * the setup controls follow a playback that joins an open + * capture. + */ + if (check && stream == SNDRV_PCM_STREAM_CAPTURE) return -EIO; - else if (cruntime->state == SNDRV_PCM_STATE_RUNNING) { + else if (check && cruntime->state == SNDRV_PCM_STATE_RUNNING) { /* close must not free the peer runtime below */ atomic_inc(&cable->stop_count); stop_capture = true; @@ -988,6 +991,18 @@ static unsigned int get_cable_index(struct snd_pcm_substream *substream) return !substream->stream; } +/* + * In notify mode the playback side may change format, rate, channels and, + * with a sound timer, the period size. A running capture that no longer + * matches is stopped by loopback_check_format(). + * call in loopback->cable_lock + */ +static bool loopback_playback_unconstrained(struct loopback_pcm *dpcm) +{ + return dpcm->substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + get_notify(dpcm); +} + static int rule_format(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { @@ -997,6 +1012,8 @@ static int rule_format(struct snd_pcm_hw_params *params, snd_mask_none(&m); scoped_guard(mutex, &dpcm->loopback->cable_lock) { + if (loopback_playback_unconstrained(dpcm)) + return 0; m.bits[0] = (u_int32_t)cable->hw.formats; m.bits[1] = (u_int32_t)(cable->hw.formats >> 32); } @@ -1011,6 +1028,8 @@ static int rule_rate(struct snd_pcm_hw_params *params, struct snd_interval t; scoped_guard(mutex, &dpcm->loopback->cable_lock) { + if (loopback_playback_unconstrained(dpcm)) + return 0; t.min = cable->hw.rate_min; t.max = cable->hw.rate_max; } @@ -1027,6 +1046,8 @@ static int rule_channels(struct snd_pcm_hw_params *params, struct snd_interval t; scoped_guard(mutex, &dpcm->loopback->cable_lock) { + if (loopback_playback_unconstrained(dpcm)) + return 0; t.min = cable->hw.channels_min; t.max = cable->hw.channels_max; } @@ -1043,6 +1064,8 @@ static int rule_period_bytes(struct snd_pcm_hw_params *params, struct snd_interval t; scoped_guard(mutex, &dpcm->loopback->cable_lock) { + if (loopback_playback_unconstrained(dpcm)) + return 0; t.min = cable->hw.period_bytes_min; t.max = cable->hw.period_bytes_max; } diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index 4af89822bf32..94213c1ff170 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -155,20 +155,20 @@ static void snd_mpu401_uart_timer(struct timer_list *t) scoped_guard(spinlock_irqsave, &mpu->timer_lock) { /*mpu->mode |= MPU401_MODE_TIMER;*/ - mod_timer(&mpu->timer, 1 + jiffies); + if (mpu->timer_invoked) + mod_timer(&mpu->timer, 1 + jiffies); } if (mpu->rmidi) _snd_mpu401_uart_interrupt(mpu); } /* - * initialize the timer callback if not programmed yet + * arm the timer if it is not already active */ static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input) { 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 : @@ -474,6 +474,7 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi) struct snd_mpu401 *mpu = rmidi->private_data; if (mpu->irq >= 0) free_irq(mpu->irq, (void *) mpu); + timer_shutdown_sync(&mpu->timer); release_and_free_resource(mpu->res); kfree(mpu); } @@ -528,6 +529,7 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, spin_lock_init(&mpu->input_lock); spin_lock_init(&mpu->output_lock); spin_lock_init(&mpu->timer_lock); + timer_setup(&mpu->timer, snd_mpu401_uart_timer, 0); mpu->hardware = hardware; mpu->irq = -1; mpu->rmidi = rmidi; diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index 1ed6d4f0cb62..288a873a27e6 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -443,7 +443,7 @@ static void snd_mtpav_output_trigger(struct snd_rawmidi_substream *substream, in scoped_guard(spinlock_irqsave, &mtp_card->spinlock) { if (up) { - if ((portp->mode & MTPAV_MODE_OUTPUT_TRIGGERED)) { + 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; diff --git a/sound/hda/codecs/hdmi/eld.c b/sound/hda/codecs/hdmi/eld.c index 1464fd1c675b..fc6fe1b0873c 100644 --- a/sound/hda/codecs/hdmi/eld.c +++ b/sound/hda/codecs/hdmi/eld.c @@ -155,9 +155,11 @@ void snd_hdmi_write_eld_info(struct hdmi_eld *eld, e->aud_synch_delay = val; else if (!strcmp(name, "speakers")) e->spk_alloc = val; - else if (!strcmp(name, "sad_count")) + else if (!strcmp(name, "sad_count")) { + if (val > ELD_MAX_SAD) + continue; e->sad_count = val; - else if (!strncmp(name, "sad", 3)) { + } else if (!strncmp(name, "sad", 3)) { sname = name + 4; n = name[3] - '0'; if (name[4] >= '0' && name[4] <= '9') { diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c index 480d1c5f129f..a30072139f35 100644 --- a/sound/hda/codecs/hdmi/hdmi.c +++ b/sound/hda/codecs/hdmi/hdmi.c @@ -983,7 +983,8 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) snd_hda_set_dev_select(codec, pin_nid, dev_id); if (spec->intel_hsw_fixup) { - conns = spec->num_cvts; + /* spec->cvt_nids[] only has ARRAY_SIZE(spec->cvt_nids) slots */ + conns = min_t(int, spec->num_cvts, ARRAY_SIZE(spec->cvt_nids)); memcpy(per_pin->mux_nids, spec->cvt_nids, sizeof(hda_nid_t) * conns); } else { diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index 03265550c0ee..404a93f552cb 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -7222,7 +7222,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1664, "ASUS ExpertBook PM3406CHA", ALC256_FIXUP_ASUS_PM3406CHA), SND_PCI_QUIRK(0x1043, 0x1683, "ASUS UM3402YAR", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402VA", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402VA", ALC294_FIXUP_ASUS_SPI_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x16d3, "ASUS UX5304VA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), @@ -7723,6 +7723,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x2782, 0x1701, "Infinix Y4 Max", ALC269VC_FIXUP_INFINIX_Y4_MAX), SND_PCI_QUIRK(0x2782, 0x1705, "MEDION E15433", ALC269VC_FIXUP_INFINIX_Y4_MAX), SND_PCI_QUIRK(0x2782, 0x1707, "Vaio VJFE-ADL", ALC298_FIXUP_SPK_VOLUME), + SND_PCI_QUIRK(0x2782, 0x1718, "Acer Aspire AL16-31P", ALC269VC_FIXUP_INFINIX_Y4_MAX), SND_PCI_QUIRK(0x2782, 0x4900, "MEDION E15443", ALC233_FIXUP_MEDION_MTL_SPK), SND_PCI_QUIRK(0x2782, 0xa128, "Positivo N15RPE-S", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x2782, 0xa212, "Lunnen Ground 14", ALC269VC_FIXUP_LUNNEN_GROUND_14), diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index ebfc08b5fb28..6eb9e4b8ba2e 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -375,6 +375,11 @@ static int tas2563_save_calibration(struct tas2781_hda *h) i, j, status); return -EINVAL; } + if (*(uint32_t *)&data[offset] == 0) { + dev_warn(p->dev, + "Dev %d: Caldat[%d] is zero\n", i, j); + return -EINVAL; + } bedata = cpu_to_be32(*(uint32_t *)&data[offset]); memcpy(&data[offset], &bedata, sizeof(bedata)); offset += TAS2563_CAL_DATA_SIZE; diff --git a/sound/hda/codecs/via.c b/sound/hda/codecs/via.c index 6becea9bb810..b35eb727cf2a 100644 --- a/sound/hda/codecs/via.c +++ b/sound/hda/codecs/via.c @@ -933,6 +933,7 @@ static const struct hda_fixup via_fixups[] = { static const struct hda_quirk vt2002p_fixups[] = { SND_PCI_QUIRK(0x1043, 0x13f7, "Asus B23E", VIA_FIXUP_POWER_SAVE), SND_PCI_QUIRK(0x1043, 0x1487, "Asus G75", VIA_FIXUP_ASUS_G75), + SND_PCI_QUIRK(0x1043, 0x1c33, "Asus X55A", VIA_FIXUP_POWER_SAVE), SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", VIA_FIXUP_POWER_SAVE), {} diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c index 7869f673894f..e6548e03a32c 100644 --- a/sound/hda/common/codec.c +++ b/sound/hda/common/codec.c @@ -1806,6 +1806,12 @@ int snd_hda_codec_reset(struct hda_codec *codec) { struct hda_bus *bus = codec->bus; + /* ASoC: driver unbind frees the card, incl. the hwdep issuing the reset */ + if (bus->core.ext_ops) { + codec_err(codec, "Codec reset is not supported with ASoC\n"); + return -EOPNOTSUPP; + } + if (snd_hda_lock_devices(bus) < 0) return -EBUSY; diff --git a/sound/hda/common/sysfs.c b/sound/hda/common/sysfs.c index f8c8483fd5e5..121a54ea3150 100644 --- a/sound/hda/common/sysfs.c +++ b/sound/hda/common/sysfs.c @@ -117,6 +117,8 @@ static int clear_codec(struct hda_codec *codec) int err; err = snd_hda_codec_reset(codec); + if (err == -EOPNOTSUPP) + return err; if (err < 0) { codec_err(codec, "The codec is being used, can't free.\n"); return err; @@ -132,6 +134,8 @@ static int reconfig_codec(struct hda_codec *codec) CLASS(snd_hda_power, pm)(codec); codec_info(codec, "hda-codec: reconfiguring\n"); err = snd_hda_codec_reset(codec); + if (err == -EOPNOTSUPP) + return err; if (err < 0) { codec_err(codec, "The codec is being used, can't reconfigure.\n"); diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index 077fdf2181c1..e3480f23f7f3 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -742,7 +742,8 @@ static struct { /* ALSA driver */ -static int snd_sgio2audio_free(struct snd_sgio2audio *chip) +static int snd_sgio2audio_free(struct snd_sgio2audio *chip, + unsigned int irq_count) { int i; @@ -752,7 +753,7 @@ static int snd_sgio2audio_free(struct snd_sgio2audio *chip) writeq(0, &mace->perif.audio.control); /* release IRQ's */ - for (i = 0; i < ARRAY_SIZE(snd_sgio2_isr_table); i++) + for (i = 0; i < irq_count; i++) free_irq(snd_sgio2_isr_table[i].irq, &chip->channel[snd_sgio2_isr_table[i].idx]); @@ -768,7 +769,7 @@ static int snd_sgio2audio_dev_free(struct snd_device *device) { struct snd_sgio2audio *chip = device->device_data; - return snd_sgio2audio_free(chip); + return snd_sgio2audio_free(chip, ARRAY_SIZE(snd_sgio2_isr_table)); } static const struct snd_device_ops ops = { @@ -819,7 +820,7 @@ static int snd_sgio2audio_create(struct snd_card *card, 0, snd_sgio2_isr_table[i].desc, &chip->channel[snd_sgio2_isr_table[i].idx])) { - snd_sgio2audio_free(chip); + snd_sgio2audio_free(chip, i); printk(KERN_ERR "sgio2audio: cannot allocate irq %d\n", snd_sgio2_isr_table[i].irq); return -EBUSY; @@ -843,13 +844,13 @@ static int snd_sgio2audio_create(struct snd_card *card, /* initialize the AD1843 codec */ err = ad1843_init(&chip->ad1843); if (err < 0) { - snd_sgio2audio_free(chip); + snd_sgio2audio_free(chip, ARRAY_SIZE(snd_sgio2_isr_table)); return err; } err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { - snd_sgio2audio_free(chip); + snd_sgio2audio_free(chip, ARRAY_SIZE(snd_sgio2_isr_table)); return err; } *rchip = chip; diff --git a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c index e25a78dd1bf2..339311e5d807 100644 --- a/sound/oss/dmasound/dmasound_q40.c +++ b/sound/oss/dmasound/dmasound_q40.c @@ -49,9 +49,8 @@ static int Q40SetFormat(int format); static int Q40SetVolume(int volume); static void Q40PlayNextFrame(int index); static void Q40Play(void); -static irqreturn_t Q40StereoInterrupt(int irq, void *dummy); -static irqreturn_t Q40MonoInterrupt(int irq, void *dummy); -static void Q40Interrupt(void); +static irqreturn_t q40_audio_interrupt(int irq, void *dummy); +static void q40_frame_done(void); /*** Mid level stuff *********************************************************/ @@ -372,8 +371,8 @@ static void Q40Free(void *ptr, unsigned int size) static int __init Q40IrqInit(void) { /* Register interrupt handler. */ - if (request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0, - "DMA sound", Q40Interrupt)) + if (request_irq(Q40_IRQ_SAMPLE, q40_audio_interrupt, 0, + "DMA sound", q40_frame_done)) return 0; return(1); @@ -384,7 +383,7 @@ static int __init Q40IrqInit(void) static void Q40IrqCleanUp(void) { master_outb(0,SAMPLE_ENABLE_REG); - free_irq(Q40_IRQ_SAMPLE, Q40Interrupt); + free_irq(Q40_IRQ_SAMPLE, q40_frame_done); } #endif /* MODULE */ @@ -403,7 +402,6 @@ static void Q40PlayNextFrame(int index) u_char *start; u_long size; u_char speed; - int error; /* used by Q40Play() if all doubts whether there really is something * to be played are already wiped out. @@ -420,15 +418,6 @@ static void Q40PlayNextFrame(int index) speed=(dmasound.hard.speed==10000 ? 0 : 1); master_outb( 0,SAMPLE_ENABLE_REG); - free_irq(Q40_IRQ_SAMPLE, Q40Interrupt); - if (dmasound.soft.stereo) - error = request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0, - "Q40 sound", Q40Interrupt); - else - error = request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0, - "Q40 sound", Q40Interrupt); - if (error && printk_ratelimit()) - pr_err("Couldn't register sound interrupt\n"); master_outb( speed, SAMPLE_RATE_REG); master_outb( 1,SAMPLE_CLEAR_REG); @@ -456,31 +445,35 @@ static void Q40Play(void) spin_unlock_irqrestore(&dmasound.lock, flags); } -static irqreturn_t Q40StereoInterrupt(int irq, void *dummy) -{ - spin_lock(&dmasound.lock); - if (q40_sc>1){ - *DAC_LEFT=*q40_pp++; - *DAC_RIGHT=*q40_pp++; - q40_sc -=2; - master_outb(1,SAMPLE_CLEAR_REG); - }else Q40Interrupt(); - spin_unlock(&dmasound.lock); - return IRQ_HANDLED; -} -static irqreturn_t Q40MonoInterrupt(int irq, void *dummy) +static irqreturn_t q40_audio_interrupt(int irq, void *dummy) { + bool frame_done = false; + spin_lock(&dmasound.lock); - if (q40_sc>0){ - *DAC_LEFT=*q40_pp; - *DAC_RIGHT=*q40_pp++; - q40_sc --; - master_outb(1,SAMPLE_CLEAR_REG); - }else Q40Interrupt(); + if (dmasound.hard.stereo) { + if (q40_sc > 1) { + *DAC_LEFT = *q40_pp++; + *DAC_RIGHT = *q40_pp++; + q40_sc -= 2; + master_outb(1, SAMPLE_CLEAR_REG); + } else { + frame_done = true; + } + } else if (q40_sc > 0) { + *DAC_LEFT = *q40_pp; + *DAC_RIGHT = *q40_pp++; + q40_sc--; + master_outb(1, SAMPLE_CLEAR_REG); + } else { + frame_done = true; + } spin_unlock(&dmasound.lock); + if (frame_done) + q40_frame_done(); return IRQ_HANDLED; } -static void Q40Interrupt(void) + +static void q40_frame_done(void) { if (!write_sq.active) { /* playing was interrupted and sq_reset() has already cleared diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 3d34575a0e8f..ba290f3a50e4 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -395,7 +395,7 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m dev_dbg(chip->card->dev, "dsp_spos: module got no code segment\n"); } else { - if (ins->code.offset + code->size > DSP_CODE_BYTE_SIZE) { + if ((u64)ins->code.offset + code->size > DSP_CODE_BYTE_SIZE / 4) { dev_err(chip->card->dev, "dsp_spos: no space available in DSP\n"); return -ENOMEM; diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c index 6b55610ad535..b17c4539f4e4 100644 --- a/sound/soc/codecs/arizona-jack.c +++ b/sound/soc/codecs/arizona-jack.c @@ -713,6 +713,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_priv *info) snd_soc_jack_report(info->jack, SND_JACK_HEADPHONE, SND_JACK_LINEOUT | SND_JACK_HEADPHONE); + pm_runtime_put_autosuspend(arizona->dev); info->hpdet_active = false; } diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index b4d93b9404bb..ac28b3cadb69 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -517,6 +517,9 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) snd_hdac_display_power(hdev->bus, HDA_CODEC_IDX_CONTROLLER, false); + /* The codec is in D0, the status is RPM_SUSPENDED after a previous unbind */ + pm_runtime_set_active(&hdev->dev); + /* match for forbid call in snd_hda_codec_device_new() */ pm_runtime_allow(&hdev->dev); @@ -557,6 +560,13 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component) return; } + /* + * Resume the codec to have its link reference (dropped below) and + * codec_powered bit in the same state as after the probe. + */ + pm_runtime_get_sync(&hdev->dev); + + /* prevent runtime PM callbacks while the link and the codec are torn down */ pm_runtime_disable(&hdev->dev); snd_hdac_ext_bus_link_put(hdev->bus, hlink); @@ -564,6 +574,12 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component) driver->ops->remove(codec); snd_hda_codec_cleanup_for_unbind(codec); + + /* Balances the disable above, cleanup_for_unbind keeps runtime PM disabled */ + pm_runtime_enable(&hdev->dev); + pm_runtime_put_noidle(&hdev->dev); + /* The codec is cleaned up, system suspend must skip it from now on */ + pm_runtime_set_suspended(&hdev->dev); } static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = { diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 8350b02b575f..f094225ba40a 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -1129,27 +1129,35 @@ static const struct regmap_config wsa_regmap_config = { int wsa_macro_set_spkr_mode(struct snd_soc_component *component, int mode) { struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + unsigned int comp1_ctl3, comp1_ctl7; + u8 comp_val, boost_val; wsa->spkr_mode = mode; - switch (mode) { - case WSA_MACRO_SPKR_MODE_1: - snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL3, 0x80, 0x00); - snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL3, 0x80, 0x00); - snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL7, 0x01, 0x00); - snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL7, 0x01, 0x00); - snd_soc_component_update_bits(component, CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x44); - snd_soc_component_update_bits(component, CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x44); - break; - default: - snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL3, 0x80, 0x80); - snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL3, 0x80, 0x80); - snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL7, 0x01, 0x01); - snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL7, 0x01, 0x01); - snd_soc_component_update_bits(component, CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x58); - snd_soc_component_update_bits(component, CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x58); - break; + /* Compander1 CTL3/CTL7 moved on v2.5+ silicon. */ + if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5) { + comp1_ctl3 = CDC_2_5_WSA_COMPANDER1_CTL3; + comp1_ctl7 = CDC_2_5_WSA_COMPANDER1_CTL7; + } else { + comp1_ctl3 = CDC_WSA_COMPANDER1_CTL3; + comp1_ctl7 = CDC_WSA_COMPANDER1_CTL7; } + + if (mode == WSA_MACRO_SPKR_MODE_1) { + comp_val = 0x00; + boost_val = 0x44; + } else { + comp_val = 0x80; + boost_val = 0x58; + } + + snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL3, 0x80, comp_val); + snd_soc_component_update_bits(component, comp1_ctl3, 0x80, comp_val); + snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL7, 0x01, comp_val ? 0x01 : 0x00); + snd_soc_component_update_bits(component, comp1_ctl7, 0x01, comp_val ? 0x01 : 0x00); + snd_soc_component_update_bits(component, CDC_WSA_BOOST0_BOOST_CTL, 0x7C, boost_val); + snd_soc_component_update_bits(component, CDC_WSA_BOOST1_BOOST_CTL, 0x7C, boost_val); + return 0; } EXPORT_SYMBOL(wsa_macro_set_spkr_mode); diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c index 08cc52b374a9..0275fb420ef2 100644 --- a/sound/soc/codecs/pcm6240.c +++ b/sound/soc/codecs/pcm6240.c @@ -2034,8 +2034,6 @@ static const struct regmap_config pcmdevice_i2c_regmap = { static void pcmdevice_remove(struct pcmdevice_priv *pcm_dev) { - if (pcm_dev->irq) - free_irq(pcm_dev->irq, pcm_dev); mutex_destroy(&pcm_dev->codec_lock); } diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index 1d80a4b862e2..1147b332c83a 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -3300,8 +3300,8 @@ static void rt5682s_i2c_shutdown(struct i2c_client *client) struct rt5682s_priv *rt5682s = i2c_get_clientdata(client); disable_irq(client->irq); - cancel_delayed_work_sync(&rt5682s->jack_detect_work); - cancel_delayed_work_sync(&rt5682s->jd_check_work); + disable_delayed_work_sync(&rt5682s->jack_detect_work); + disable_delayed_work_sync(&rt5682s->jd_check_work); rt5682s_reset(rt5682s); } diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index bc5b872f1e42..bbbea9af73cd 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.c +++ b/sound/soc/codecs/rt712-sdca-dmic.c @@ -247,7 +247,7 @@ static int rt712_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + struct rt712_sdca_dmic_priv *rt712 = snd_soc_component_get_drvdata(component); struct rt712_sdca_dmic_kctrl_priv *p = (struct rt712_sdca_dmic_kctrl_priv *)kcontrol->private_value; unsigned int regvalue, ctl, i; @@ -278,7 +278,7 @@ static int rt712_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt712_sdca_dmic_kctrl_priv *p = (struct rt712_sdca_dmic_kctrl_priv *)kcontrol->private_value; - struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + struct rt712_sdca_dmic_priv *rt712 = snd_soc_component_get_drvdata(component); unsigned int gain_val[4]; unsigned int i, adc_vol_flag = 0, changed = 0; unsigned int regvalue[4]; diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c index 5c0a76a4a106..1a815de90909 100644 --- a/sound/soc/codecs/tlv320aic32x4-clk.c +++ b/sound/soc/codecs/tlv320aic32x4-clk.c @@ -320,6 +320,9 @@ static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_aic32x4 *div = to_clk_aic32x4(hw); u8 divisor; + if (!rate) + return -EINVAL; + divisor = DIV_ROUND_UP(parent_rate, rate); if (divisor > AIC32X4_DIV_MAX) return -EINVAL; @@ -333,8 +336,11 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw, { unsigned long divisor; + if (!req->rate) + return -EINVAL; + divisor = DIV_ROUND_UP(req->best_parent_rate, req->rate); - if (divisor > AIC32X4_DIV_MAX) + if (!divisor || divisor > AIC32X4_DIV_MAX) return -EINVAL; req->rate = DIV_ROUND_UP(req->best_parent_rate, divisor); diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 1c050b8c19de..d607400b3976 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -5092,6 +5092,13 @@ static int wcd9335_slim_probe(struct slim_device *slim) return 0; } +static void wcd9335_put_device_action(void *data) +{ + struct device *dev = data; + + put_device(dev); +} + static int wcd9335_slim_status(struct slim_device *sdev, enum slim_device_status status) { @@ -5116,28 +5123,40 @@ static int wcd9335_slim_status(struct slim_device *sdev, return -EINVAL; } + ret = devm_add_action_or_reset(dev, wcd9335_put_device_action, + &wcd->slim_ifc_dev->dev); + if (ret) + return ret; + slim_get_logical_addr(wcd->slim_ifc_dev); wcd->regmap = regmap_init_slimbus(sdev, &wcd9335_regmap_config); - if (IS_ERR(wcd->regmap)) + if (IS_ERR(wcd->regmap)) { + put_device(&wcd->slim_ifc_dev->dev); return dev_err_probe(dev, PTR_ERR(wcd->regmap), "Failed to allocate slim register map\n"); + } wcd->if_regmap = regmap_init_slimbus(wcd->slim_ifc_dev, &wcd9335_ifc_regmap_config); - if (IS_ERR(wcd->if_regmap)) + if (IS_ERR(wcd->if_regmap)) { + put_device(&wcd->slim_ifc_dev->dev); return dev_err_probe(dev, PTR_ERR(wcd->if_regmap), "Failed to allocate ifc register map\n"); + } ret = wcd9335_bring_up(wcd); if (ret) { dev_err(dev, "Failed to bringup WCD9335\n"); + put_device(&wcd->slim_ifc_dev->dev); return ret; } ret = wcd9335_irq_init(wcd); - if (ret) + if (ret) { + put_device(&wcd->slim_ifc_dev->dev); return ret; + } wcd9335_probe(wcd); diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 128c3a59beac..80b1bb7e1774 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3533,6 +3533,7 @@ int wm8994_mic_detect(struct snd_soc_component *component, struct snd_soc_jack * break; default: dev_warn(component->dev, "Invalid MICBIAS %d\n", micbias); + pm_runtime_put(component->dev); return -EINVAL; } @@ -4352,6 +4353,7 @@ static int wm8994_component_probe(struct snd_soc_component *component) ret = regmap_read(control->regmap, WM8994_GPIO_1, ®); if (ret < 0) { dev_err(component->dev, "Failed to read GPIO1 state: %d\n", ret); + pm_runtime_put(component->dev); goto err_irq; } if ((reg & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) { @@ -4364,6 +4366,7 @@ static int wm8994_component_probe(struct snd_soc_component *component) ret = regmap_read(control->regmap, WM8994_GPIO_6, ®); if (ret < 0) { dev_err(component->dev, "Failed to read GPIO6 state: %d\n", ret); + pm_runtime_put(component->dev); goto err_irq; } if ((reg & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) { diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index 5f2ced650dcc..6fb50b6e5e18 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -455,10 +455,11 @@ /* * Device will report senseless data in many cases, so discard any measurements - * outside of valid range. + * outside of the two-point trim range. Do not narrow this to ambient: a + * speaker that has been playing easily runs well above 45 degC. */ -#define WSA883X_LOW_TEMP_THRESHOLD 5 -#define WSA883X_HIGH_TEMP_THRESHOLD 45 +#define WSA883X_LOW_TEMP_THRESHOLD WSA883X_T1_TEMP +#define WSA883X_HIGH_TEMP_THRESHOLD WSA883X_T2_TEMP struct wsa883x_priv { struct regmap *regmap; @@ -1430,7 +1431,7 @@ static int wsa883x_get_temp(struct wsa883x_priv *wsa883x, long *temp) unsigned int dmeas_msb = 0, dmeas_lsb = 0; int d1, d2, dmeas; unsigned int mask; - int ret, range; + int ret; long val; guard(mutex)(&wsa883x->sp_lock); @@ -1493,8 +1494,8 @@ static int wsa883x_get_temp(struct wsa883x_priv *wsa883x, long *temp) } val = WSA883X_T1_TEMP + (((dmeas - d1) * (WSA883X_T2_TEMP - WSA883X_T1_TEMP)) / (d2 - d1)); - range = WSA883X_HIGH_TEMP_THRESHOLD - WSA883X_LOW_TEMP_THRESHOLD; - if (in_range(val, WSA883X_LOW_TEMP_THRESHOLD, range)) { + if (val >= WSA883X_LOW_TEMP_THRESHOLD && + val <= WSA883X_HIGH_TEMP_THRESHOLD) { wsa883x->temperature = val; *temp = val * 1000; ret = 0; diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index 5ecd7962d77a..d941e9826ba0 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -720,10 +720,11 @@ /* * Device will report senseless data in many cases, so discard any measurements - * outside of valid range. + * outside of the two-point trim range. Do not narrow this to ambient: a + * speaker that has been playing easily runs well above 45 degC. */ -#define WSA884X_LOW_TEMP_THRESHOLD 5 -#define WSA884X_HIGH_TEMP_THRESHOLD 45 +#define WSA884X_LOW_TEMP_THRESHOLD WSA884X_T1_TEMP +#define WSA884X_HIGH_TEMP_THRESHOLD WSA884X_T2_TEMP struct wsa884x_priv { struct regmap *regmap; @@ -1931,8 +1932,8 @@ static int wsa884x_get_temp(struct wsa884x_priv *wsa884x, long *temp) dev_dbg(wsa884x->dev, "Measured temp %ld (dmeas=%d, d1=%d, d2=%d)\n", val, dmeas, d1, d2); - if ((val > WSA884X_LOW_TEMP_THRESHOLD) && - (val < WSA884X_HIGH_TEMP_THRESHOLD)) { + if (val >= WSA884X_LOW_TEMP_THRESHOLD && + val <= WSA884X_HIGH_TEMP_THRESHOLD) { wsa884x->temperature = val; *temp = val * 1000; ret = 0; diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index d7a823384c08..08683f989cee 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -57,6 +58,7 @@ struct fsl_xcvr { struct snd_aes_iec958 tx_iec958; u8 cap_ds[FSL_XCVR_CAPDS_SIZE]; struct work_struct work_rst; + int irq; spinlock_t lock; /* Protect hw_reset and trigger */ struct snd_pcm_hw_constraint_list spdif_constr_rates; u32 spdif_constr_rates_list[SPDIF_NUM_RATES]; @@ -1555,7 +1557,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev) struct fsl_xcvr *xcvr; struct resource *rx_res, *tx_res; void __iomem *regs; - int ret, irq; + int ret; xcvr = devm_kzalloc(dev, sizeof(*xcvr), GFP_KERNEL); if (!xcvr) @@ -1643,12 +1645,22 @@ static int fsl_xcvr_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(xcvr->reset), "failed to get XCVR reset control\n"); + /* + * irq0_isr() schedules work_rst. Prepare the work and its lock + * before the IRQ, and register the cancel action first so a failed + * probe frees the IRQ and then cancels any queued work. + */ + spin_lock_init(&xcvr->lock); + ret = devm_work_autocancel(dev, &xcvr->work_rst, reset_rx_work); + if (ret) + return ret; + /* get IRQs */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + xcvr->irq = platform_get_irq(pdev, 0); + if (xcvr->irq < 0) + return xcvr->irq; - ret = devm_request_irq(dev, irq, irq0_isr, 0, pdev->name, xcvr); + ret = devm_request_irq(dev, xcvr->irq, irq0_isr, 0, pdev->name, xcvr); if (ret) return dev_err_probe(dev, ret, "failed to claim IRQ0\n"); @@ -1689,8 +1701,6 @@ static int fsl_xcvr_probe(struct platform_device *pdev) fsl_xcvr_comp.name); } - INIT_WORK(&xcvr->work_rst, reset_rx_work); - spin_lock_init(&xcvr->lock); return ret; } @@ -1698,6 +1708,8 @@ static void fsl_xcvr_remove(struct platform_device *pdev) { struct fsl_xcvr *xcvr = dev_get_drvdata(&pdev->dev); + /* Free the IRQ first so irq0_isr() cannot requeue work_rst. */ + devm_free_irq(&pdev->dev, xcvr->irq, xcvr); cancel_work_sync(&xcvr->work_rst); pm_runtime_disable(&pdev->dev); } diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 257180630475..92a68dbd841e 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -253,6 +253,11 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) return 0; } +static void sst_unregister_platform_device(void *data) +{ + platform_device_unregister(data); +} + static int sst_acpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -341,7 +346,10 @@ static int sst_acpi_probe(struct platform_device *pdev) pdata->platform); return PTR_ERR(plat_dev); } - + ret = devm_add_action_or_reset(dev, sst_unregister_platform_device, + plat_dev); + if (ret) + return ret; /* * Create platform device for sst machine driver, * pass machine info as pdata @@ -354,6 +362,10 @@ static int sst_acpi_probe(struct platform_device *pdev) return PTR_ERR(mdev); } + ret = devm_add_action_or_reset(dev, sst_unregister_platform_device, + mdev); + if (ret) + return ret; /* Fill sst platform data */ ctx->pdata = pdata; strcpy(ctx->firmware_name, mach->fw_filename); diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index 7b59d514b432..d2cb0ccd3456 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -377,6 +377,7 @@ struct q6afe { struct q6core_svc_api_info ainfo; struct mutex lock; struct aprv2_ibasic_rsp_result_t result; + uint32_t vote_result; wait_queue_head_t wait; struct list_head port_list; spinlock_t port_list_lock; @@ -966,13 +967,14 @@ static int q6afe_callback(struct apr_device *adev, struct apr_resp_pkt *data) struct aprv2_ibasic_rsp_result_t *res; struct apr_hdr *hdr = &data->hdr; struct q6afe_port *port; + uint32_t *vote_res; if (!data->payload_size) return 0; - res = data->payload; switch (hdr->opcode) { case APR_BASIC_RSP_RESULT: { + res = data->payload; if (res->status) { dev_err(afe->dev, "cmd = 0x%x returned error = 0x%x\n", res->opcode, res->status); @@ -999,8 +1001,10 @@ static int q6afe_callback(struct apr_device *adev, struct apr_resp_pkt *data) } break; case AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST: + vote_res = data->payload; afe->result.opcode = hdr->opcode; - afe->result.status = res->status; + afe->result.status = 0; + afe->vote_result = *vote_res; wake_up(&afe->wait); break; default: @@ -1910,6 +1914,8 @@ int q6afe_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id, AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST); if (ret) dev_err(afe->dev, "AFE failed to vote (%d)\n", hw_block_id); + else + *client_handle = afe->vote_result; kfree(pkt); diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index 9122876e00a2..50d5d2143daa 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -223,6 +223,7 @@ int q6apm_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, phys_a mutex_lock(&graph->lock); data->dsp_buf = 0; + atomic_set(&data->hw_ptr, 0); if (data->buf) { mutex_unlock(&graph->lock); diff --git a/sound/soc/sdw_utils/soc_sdw_rt711.c b/sound/soc/sdw_utils/soc_sdw_rt711.c index 4aa93fdefef6..1d020d44d474 100644 --- a/sound/soc/sdw_utils/soc_sdw_rt711.c +++ b/sound/soc/sdw_utils/soc_sdw_rt711.c @@ -123,6 +123,7 @@ int asoc_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_ device_remove_software_node(ctx->headset_codec_dev); put_device(ctx->headset_codec_dev); + ctx->headset_codec_dev = NULL; return 0; } diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 621a9d5f9377..23a68ac3a3e3 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -647,6 +647,7 @@ static int __davinci_mcasp_set_clkdiv(struct davinci_mcasp *mcasp, int div_id, break; default: + pm_runtime_put(mcasp->dev); return -EINVAL; } diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index 01444fc960d0..863d35aff196 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c @@ -71,7 +71,12 @@ static int sf_sample_free(void *private_data, struct snd_sf_sample *sp, static void sf_sample_reset(void *private_data) { struct snd_emux *emu = private_data; - emu->ops.sample_reset(emu); + + /* stop all voices that might refer to zones and samples to be freed */ + if (emu->ops.sample_reset) + emu->ops.sample_reset(emu); + else + snd_emux_terminate_all(emu); } int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, char *name) @@ -96,8 +101,7 @@ int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, ch sf_cb.private_data = emu; sf_cb.sample_new = sf_sample_new; sf_cb.sample_free = sf_sample_free; - if (emu->ops.sample_reset) - sf_cb.sample_reset = sf_sample_reset; + sf_cb.sample_reset = sf_sample_reset; emu->sflist = snd_sf_new(&sf_cb, emu->memhdr); if (emu->sflist == NULL) return -ENOMEM; diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c index 30793a131746..2f8ba39d4a6f 100644 --- a/sound/synth/emux/soundfont.c +++ b/sound/synth/emux/soundfont.c @@ -443,6 +443,15 @@ remove_info(struct snd_sf_list *sflist, struct snd_soundfont *sf, struct snd_sf_zone *prev, *next, *p; int removed = 0; + /* stop voices before freeing the zones they might refer to */ + for (p = sf->zones; p; p = p->next) { + if (!p->mapped && p->bank == bank && p->instr == instr) { + if (sflist->callback.sample_reset) + sflist->callback.sample_reset(sflist->callback.private_data); + break; + } + } + prev = NULL; for (p = sf->zones; p; p = next) { next = p->next; diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 9ef4faa006a0..46acd2f44c44 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -125,24 +125,21 @@ void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) line6pcm->in.pos_done -= runtime->buffer_size; } -void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) +/* update the capture position and check whether we need period_elapsed call */ +bool line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) { - struct snd_pcm_substream *substream = - get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); - line6pcm->in.bytes += length; if (line6pcm->in.bytes >= line6pcm->in.period) { line6pcm->in.bytes %= line6pcm->in.period; - spin_unlock(&line6pcm->in.lock); - snd_pcm_period_elapsed(substream); - spin_lock(&line6pcm->in.lock); + return true; } + return false; } /* * Callback for completed capture URB. */ -static void audio_in_callback(struct urb *urb) +static bool handle_audio_in(struct urb *urb) { int i, index, length = 0, shutdown = 0; struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; @@ -207,8 +204,18 @@ static void audio_in_callback(struct urb *urb) if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) && test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) - line6_capture_check_period(line6pcm, length); + return line6_capture_check_period(line6pcm, length); } + + return false; +} + +static void audio_in_callback(struct urb *urb) +{ + struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; + + if (handle_audio_in(urb)) + snd_pcm_period_elapsed(get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE)); } /* open capture callback */ diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h index 90572dae134e..628315389efc 100644 --- a/sound/usb/line6/capture.h +++ b/sound/usb/line6/capture.h @@ -17,7 +17,7 @@ extern const struct snd_pcm_ops snd_line6_capture_ops; extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize); -extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm, +extern bool line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length); extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm); extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm); diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 2e70ca5456c5..495a983a0c51 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -136,6 +136,8 @@ static void add_monitor_signal(struct urb *urb_out, unsigned char *signal, /* Find a free URB, prepare audio data, and submit URB. must be called in line6pcm->out.lock context + Returns 1 if snd_pcm_period_elapsed() needs to be called for the + capture stream after releasing the lock, 0 if not, or a negative error */ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) { @@ -151,6 +153,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) line6pcm->properties->rates.rats[0].den * (line6pcm->line6->intervals_per_second / LINE6_ISO_INTERVAL); struct urb *urb_out; + bool capture_period_elapsed = false; index = find_first_zero_bit(&line6pcm->out.active_urbs, line6pcm->line6->iso_buffers); @@ -260,8 +263,9 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) urb_out->transfer_buffer, urb_out-> transfer_buffer_length); - line6_capture_check_period(line6pcm, - urb_out->transfer_buffer_length); + capture_period_elapsed = + line6_capture_check_period(line6pcm, + urb_out->transfer_buffer_length); } } else { if (!(line6pcm->line6->properties->capabilities & LINE6_CAP_HWMON) @@ -283,24 +287,26 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) dev_err(line6pcm->line6->ifcdev, "URB out #%d submission failed (%d)\n", index, ret); - return 0; + return capture_period_elapsed; } /* Submit all currently available playback URBs. must be called in line6pcm->out.lock context + The capture period notification is skipped here since we can't call + snd_pcm_period_elapsed() in the lock; it'll be caught up at the next one. */ int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) { - int ret = 0, i; + int ret, i; for (i = 0; i < line6pcm->line6->iso_buffers; ++i) { ret = submit_audio_out_urb(line6pcm); if (ret < 0) - break; + return ret; } - return ret; + return 0; } /* @@ -316,6 +322,8 @@ static void audio_out_callback(struct urb *urb) const int bytes_per_frame = line6pcm->properties->bytes_per_channel * line6pcm->properties->playback_hw.channels_max; + bool capture_period_elapsed = false; + bool playback_period_elapsed = false; #if USE_CLEAR_BUFFER_WORKAROUND memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); @@ -358,19 +366,22 @@ static void audio_out_callback(struct urb *urb) shutdown = 1; if (!shutdown) { - submit_audio_out_urb(line6pcm); + capture_period_elapsed = submit_audio_out_urb(line6pcm) > 0; if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) { line6pcm->out.bytes += length; if (line6pcm->out.bytes >= line6pcm->out.period) { line6pcm->out.bytes %= line6pcm->out.period; - spin_unlock(&line6pcm->out.lock); - snd_pcm_period_elapsed(substream); - spin_lock(&line6pcm->out.lock); + playback_period_elapsed = true; } } } spin_unlock_irqrestore(&line6pcm->out.lock, flags); + + if (capture_period_elapsed) + snd_pcm_period_elapsed(get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE)); + if (playback_period_elapsed) + snd_pcm_period_elapsed(substream); } /* open playback callback */ diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 682b6c1fe76b..c2f7b08607ac 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1343,6 +1343,18 @@ static void retire_capture_urb(struct snd_usb_substream *subs, bytes -= adj; subs->stream_offset_adj -= adj; } + /* + * A packet can be as large as the endpoint's maxpacksize, which + * the device chooses, while the ring buffer can be as small as + * two 64-byte periods. The hwptr_done wrap below handles one + * wrap only, so never take more than one buffer from a packet. + */ + if (unlikely(bytes > subs->buffer_bytes)) { + dev_warn_ratelimited(&subs->dev->dev, + "%u-byte packet exceeds %u-byte buffer, truncating\n", + bytes, subs->buffer_bytes); + bytes = subs->buffer_bytes; + } frames = bytes / stride; if (!subs->txfr_quirk) bytes = frames * stride; @@ -1553,8 +1565,14 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, for (i = 0; i < ctx->packets; i++) { counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, avail); + /* + * Bound by the ring buffer as well as by the URB: + * copy_to_urb() wraps hwptr_done once, so one URB must + * never carry more than the whole buffer. + */ if (counts < 0 || - (frames + counts) * stride > ctx->buffer_size) + (frames + counts) * stride > ctx->buffer_size || + (frames + counts) * stride > subs->buffer_bytes) break; /* set up descriptor */ urb->iso_frame_desc[i].offset = frames * stride; diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index be80d9d14e0a..01a5564eda7a 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -2161,6 +2161,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_DISABLE_AUTOSUSPEND), DEVICE_FLG(0x045e, 0x070f, /* MS LifeChat LX-3000 Headset */ QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), + DEVICE_FLG(0x046d, 0x0802, /* Logitech Webcam C200 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), DEVICE_FLG(0x046d, 0x0807, /* Logitech Webcam C500 */ QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), DEVICE_FLG(0x046d, 0x0808, /* Logitech Webcam C600 */ diff --git a/tools/perf/arch/loongarch/util/header.c b/tools/perf/arch/loongarch/util/header.c index 0c6d823334a2..46f53a74f71e 100644 --- a/tools/perf/arch/loongarch/util/header.c +++ b/tools/perf/arch/loongarch/util/header.c @@ -26,7 +26,7 @@ static char *_get_field(const char *line) { - char *line2, *nl; + const char *line2, *nl; line2 = strrchr(line, ' '); if (!line2) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index cb138d1bdd7b..8452d776d994 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -2743,7 +2743,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, if (chain) chain_nr = chain->nr; - if (evsel__has_branch_callstack(evsel)) { + if (chain && evsel__has_branch_callstack(evsel)) { struct perf_env *env = evsel__env(evsel); err = resolve_lbr_callchain_sample(thread, cursor, sample, parent, diff --git a/tools/perf/util/powerpc-vpadtl.c b/tools/perf/util/powerpc-vpadtl.c index 55b9b6e07074..eacc845ebda2 100644 --- a/tools/perf/util/powerpc-vpadtl.c +++ b/tools/perf/util/powerpc-vpadtl.c @@ -681,7 +681,7 @@ int powerpc_vpadtl_process_auxtrace_info(union perf_event *event, struct perf_session *session) { struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; - size_t min_sz = sizeof(u64) * POWERPC_VPADTL_TYPE; + size_t min_sz = sizeof(u64) * (POWERPC_VPADTL_TYPE + 1); struct powerpc_vpadtl *vpa; int err; diff --git a/tools/testing/selftests/core/unshare_test.c b/tools/testing/selftests/core/unshare_test.c index 7fec9dfb1b0e..6716e0f74d7d 100644 --- a/tools/testing/selftests/core/unshare_test.c +++ b/tools/testing/selftests/core/unshare_test.c @@ -40,6 +40,14 @@ TEST(unshare_EMFILE) ASSERT_EQ(sscanf(buf, "%d", &nr_open), 1); + /* + * Cap nr_open for the duration of the test to avoid ENOMEM from a + * huge fd table allocation; buf/n keep the real original value so + * fs.nr_open can be restored to it once the test is done. + */ + if (nr_open > 1024 * 1024) + nr_open = 1024 * 1024; + ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit)); /* bump fs.nr_open */ @@ -73,10 +81,13 @@ TEST(unshare_EMFILE) if (pid == 0) { int err; + char buf3[32]; + ssize_t n3; - /* restore fs.nr_open */ + /* restore fs.nr_open to the (possibly capped) test baseline */ + n3 = sprintf(buf3, "%d\n", nr_open); lseek(fd, 0, SEEK_SET); - write(fd, buf, n); + write(fd, buf3, n3); /* ... and now unshare(CLONE_FILES) must fail with EMFILE */ err = unshare(CLONE_FILES); EXPECT_EQ(err, -1) @@ -89,6 +100,10 @@ TEST(unshare_EMFILE) EXPECT_EQ(waitpid(pid, &status, 0), pid); EXPECT_EQ(true, WIFEXITED(status)); EXPECT_EQ(0, WEXITSTATUS(status)); + + /* restore the real fs.nr_open value */ + lseek(fd, 0, SEEK_SET); + write(fd, buf, n); } TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 19c9afa0be71..a0c22cd7a9c0 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -4362,6 +4362,185 @@ TEST(user_notification_addfd_rlimit) close(memfd); } +/* Just take a signal and do nothing else. */ +static void empty_handler(int signo) +{ +} + +/* + * Verify that when SECCOMP_IOCTL_NOTIF_ADDFD with SECCOMP_ADDFD_FLAG_SEND is + * interrupted by a signal before the tracee dequeues the addfd request, + * knotif->state is restored from SECCOMP_NOTIFY_REPLIED back to + * SECCOMP_NOTIFY_SENT so that: + * 1. The woken tracee sees knotif->state == SECCOMP_NOTIFY_SENT in + * do_user_notif() and goes back to sleep instead of prematurely + * returning 0 from the trapped syscall without the FD installed. + * 2. The supervisor can retry SECCOMP_IOCTL_NOTIF_ADDFD (or + * SECCOMP_IOCTL_NOTIF_SEND) instead of failing with -EINPROGRESS. + * + * To deterministically hit the race window where the supervisor sleeps in + * wait_for_completion_interruptible(&kaddfd.completion) after waking the + * tracee (complete(&knotif->ready)) but before the tracee runs + * seccomp_handle_addfd(), pin all processes to a single CPU and enforce a + * strict 3-tier scheduling priority hierarchy on that CPU: + * - Supervisor: SCHED_FIFO priority 99 (highest) + * - Signal helper (sig_pid): SCHED_FIFO priority 50 (middle) + * - Tracee (pid): SCHED_IDLE (lowest) + */ +TEST(user_notification_addfd_send_interrupted) +{ + /* + * Save parent_pid before user_notif_syscall(__NR_getppid, ...) installs + * the seccomp filter on the calling process; children inherit that + * filter, so sig_pid must not call getppid(). + */ + pid_t tracee_pid, sig_pid, parent_pid = getpid(); + long ret; + int status, listener, memfd, err; + struct seccomp_notif_addfd addfd = {}; + struct seccomp_notif req = {}; + struct sigaction sa = {}; + struct sched_param sp_zero = { .sched_priority = 0 }; + struct sched_param sp_fifo_high = { .sched_priority = 99 }; + struct sched_param sp_fifo_mid = { .sched_priority = 50 }; + struct timespec delay = { .tv_nsec = 15000000 }; + cpu_set_t cpuset; + int cpu; + + /* Pin the supervisor (and its future child processes) to one CPU. */ + cpu = sched_getcpu(); + if (cpu >= 0) { + CPU_ZERO(&cpuset); + CPU_SET(cpu, &cpuset); + sched_setaffinity(0, sizeof(cpuset), &cpuset); + } + + sa.sa_handler = empty_handler; + ASSERT_EQ(sigaction(SIGUSR1, &sa, NULL), 0); + + memfd = memfd_create("test", 0); + ASSERT_GE(memfd, 0); + + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); + ASSERT_EQ(0, ret) { + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); + } + + /* + * Follow the convention of other user_notification_* tests in this + * file by trapping __NR_getppid: because the filter is installed on + * the supervisor before fork(), the trapped syscall must be a + * side-effect-free syscall that the supervisor itself never invokes. + * Even though getppid() does not normally return an FD, + * SECCOMP_ADDFD_FLAG_SEND replaces the trapped syscall's return value + * with the newly installed FD number (42). + */ + listener = user_notif_syscall(__NR_getppid, + SECCOMP_FILTER_FLAG_NEW_LISTENER); + ASSERT_GE(listener, 0); + + tracee_pid = fork(); + ASSERT_GE(tracee_pid, 0); + + if (tracee_pid == 0) { + /* + * Tracee: invoke __NR_getppid as a dummy trigger syscall to + * trap into do_user_notif(). Verify that the syscall returns + * the injected FD number (42) and that FD 42 is open. + */ + ret = syscall(__NR_getppid); + exit(ret != 42 || fcntl(42, F_GETFD) < 0); + } + + /* Wait for the tracee to trap in do_user_notif(). */ + ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0); + + /* + * Demote the tracee to SCHED_IDLE and promote the supervisor to + * SCHED_FIFO(99) on the same CPU. + */ + ASSERT_EQ(sched_setscheduler(tracee_pid, SCHED_IDLE, &sp_zero), 0); + if (sched_setscheduler(0, SCHED_FIFO, &sp_fifo_high) != 0) { + kill(tracee_pid, SIGKILL); + waitpid(tracee_pid, NULL, 0); + SKIP(return, "SCHED_FIFO requires CAP_SYS_NICE"); + } + + addfd.srcfd = memfd; + addfd.newfd_flags = O_CLOEXEC; + addfd.newfd = 42; + addfd.id = req.id; + addfd.flags = SECCOMP_ADDFD_FLAG_SETFD | SECCOMP_ADDFD_FLAG_SEND; + + /* + * Fork a signal helper on the same CPU and set it to SCHED_FIFO(50). + * Because the supervisor is currently running at SCHED_FIFO(99) on + * this CPU, sig_pid is queued on the runqueue but cannot run until the + * supervisor blocks inside the kernel. + * + * When the supervisor invokes ioctl(SECCOMP_IOCTL_NOTIF_ADDFD) below: + * 1. seccomp_notify_addfd() sets knotif->state = SECCOMP_NOTIFY_REPLIED, + * wakes the tracee (SCHED_IDLE), and blocks in + * wait_for_completion_interruptible(&kaddfd.completion). + * 2. The CPU scheduler immediately runs sig_pid (SCHED_FIFO 50) + * ahead of the woken tracee (SCHED_IDLE). + * 3. sig_pid sends SIGUSR1 to parent_pid, waking the supervisor + * (SCHED_FIFO 99), which immediately preempts sig_pid, aborts the + * wait with -ERESTARTSYS (-EINTR), removes kaddfd from + * knotif->addfd, and restores knotif->state = SECCOMP_NOTIFY_SENT + * before the tracee has executed a single instruction. + */ + sig_pid = fork(); + if (sig_pid < 0) { + sched_setscheduler(0, SCHED_OTHER, &sp_zero); + kill(tracee_pid, SIGKILL); + waitpid(tracee_pid, NULL, 0); + } + ASSERT_GE(sig_pid, 0); + if (sig_pid == 0) { + if (sched_setscheduler(0, SCHED_FIFO, &sp_fifo_mid) != 0) + _exit(1); + kill(parent_pid, SIGUSR1); + _exit(0); + } + + ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd); + err = errno; + + /* + * Restore normal scheduling ASAP so the supervisor does not remain + * SCHED_FIFO on a single-CPU machine/VM/CI, then sleep briefly so the + * woken tracee runs in do_user_notif(). With knotif->state restored to + * SECCOMP_NOTIFY_SENT, the tracee must loop back to sleep waiting for + * the notification reply rather than returning 0 from __NR_getppid. + */ + ASSERT_EQ(sched_setscheduler(0, SCHED_OTHER, &sp_zero), 0); + ASSERT_EQ(sched_setscheduler(tracee_pid, SCHED_OTHER, &sp_zero), 0); + + EXPECT_EQ(ret, -1); + EXPECT_EQ(err, EINTR); + EXPECT_EQ(waitpid(sig_pid, &status, 0), sig_pid); + EXPECT_EQ(true, WIFEXITED(status)); + EXPECT_EQ(0, WEXITSTATUS(status)); + + nanosleep(&delay, NULL); + + /* + * Retry SECCOMP_IOCTL_NOTIF_ADDFD. Because knotif->state is + * SECCOMP_NOTIFY_SENT, the retry succeeds (returns 42) instead of + * failing with -EINPROGRESS, installs FD 42 into the tracee, and wakes + * the tracee to complete the syscall with return value 42. + */ + EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), 42); + + EXPECT_EQ(waitpid(tracee_pid, &status, 0), tracee_pid); + EXPECT_EQ(true, WIFEXITED(status)); + EXPECT_EQ(0, WEXITSTATUS(status)); + + close(listener); + close(memfd); +} + #ifndef SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP #define SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP (1UL << 0) #define SECCOMP_IOCTL_NOTIF_SET_FLAGS SECCOMP_IOW(4, __u64) diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c index a59a4446b846..2ab7bb46a371 100644 --- a/virt/kvm/guest_memfd.c +++ b/virt/kvm/guest_memfd.c @@ -576,6 +576,9 @@ int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot, BUILD_BUG_ON(sizeof(gpa_t) != sizeof(offset)); BUILD_BUG_ON(sizeof(gfn_t) != sizeof(slot->gmem.pgoff)); + if (WARN_ON_ONCE(slot->flags & KVM_MEMSLOT_GMEM_ONLY)) + return -EINVAL; + file = fget(fd); if (!file) return -EBADF; @@ -613,7 +616,13 @@ int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot, if (kvm_gmem_supports_mmap(inode)) slot->flags |= KVM_MEMSLOT_GMEM_ONLY; - xa_store_range(&gmem->bindings, start, end - 1, slot, GFP_KERNEL); + r = xa_err(xa_store_range(&gmem->bindings, start, end - 1, slot, GFP_KERNEL)); + if (r) { + xa_store_range(&gmem->bindings, start, end - 1, NULL, GFP_KERNEL); + slot->gmem.file = NULL; + slot->gmem.pgoff = 0; + slot->flags &= ~KVM_MEMSLOT_GMEM_ONLY; + } filemap_invalidate_unlock(inode->i_mapping); /* @@ -621,7 +630,6 @@ int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot, * not the other way 'round. Active bindings are invalidated if the * file is closed before memslots are destroyed. */ - r = 0; err: fput(file); return r;