From 7d1ab81f7a17ca319427e879592e0b9a231067a8 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 19 Oct 2016 19:28:12 +0100 Subject: [PATCH 001/855] UPSTREAM: thread_info: factor out restart_block Since commit f56141e3e2d9aabf ("all arches, signal: move restart_block to struct task_struct"), thread_info and restart_block have been logically distinct, yet struct restart_block is still defined in . At least one architecture (erroneously) uses restart_block as part of its thread_info, and thus the definition of restart_block must come before the include of . Subsequent patches in this series need to shuffle the order of includes and definitions in , and will make this ordering fragile. This patch moves the definition of restart_block out to its own header. This serves as generic cleanup, logically separating thread_info and restart_block, and also makes it easier to avoid fragility. Signed-off-by: Mark Rutland Reviewed-by: Andy Lutomirski Cc: Andrew Morton Cc: Heiko Carstens Cc: Kees Cook Signed-off-by: Catalin Marinas (cherry picked from commit 53d74d056a4e306a72b8883d325b5d853c0618e6) Change-Id: I887fc29c4d669ce0b44e2e8dfe8349def52640b3 Signed-off-by: Greg Hackmann --- include/linux/restart_block.h | 51 +++++++++++++++++++++++++++++++++++ include/linux/thread_info.h | 41 +--------------------------- 2 files changed, 52 insertions(+), 40 deletions(-) create mode 100644 include/linux/restart_block.h diff --git a/include/linux/restart_block.h b/include/linux/restart_block.h new file mode 100644 index 000000000000..0d905d8ec553 --- /dev/null +++ b/include/linux/restart_block.h @@ -0,0 +1,51 @@ +/* + * Common syscall restarting data + */ +#ifndef __LINUX_RESTART_BLOCK_H +#define __LINUX_RESTART_BLOCK_H + +#include +#include + +struct timespec; +struct compat_timespec; +struct pollfd; + +/* + * System call restart block. + */ +struct restart_block { + long (*fn)(struct restart_block *); + union { + /* For futex_wait and futex_wait_requeue_pi */ + struct { + u32 __user *uaddr; + u32 val; + u32 flags; + u32 bitset; + u64 time; + u32 __user *uaddr2; + } futex; + /* For nanosleep */ + struct { + clockid_t clockid; + struct timespec __user *rmtp; +#ifdef CONFIG_COMPAT + struct compat_timespec __user *compat_rmtp; +#endif + u64 expires; + } nanosleep; + /* For poll */ + struct { + struct pollfd __user *ufds; + int nfds; + int has_timeout; + unsigned long tv_sec; + unsigned long tv_nsec; + } poll; + }; +}; + +extern long do_no_restart_syscall(struct restart_block *parm); + +#endif /* __LINUX_RESTART_BLOCK_H */ diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index 2873baf5372a..c75c6ab364ca 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -9,51 +9,12 @@ #include #include - -struct timespec; -struct compat_timespec; +#include #ifdef CONFIG_THREAD_INFO_IN_TASK #define current_thread_info() ((struct thread_info *)current) #endif -/* - * System call restart block. - */ -struct restart_block { - long (*fn)(struct restart_block *); - union { - /* For futex_wait and futex_wait_requeue_pi */ - struct { - u32 __user *uaddr; - u32 val; - u32 flags; - u32 bitset; - u64 time; - u32 __user *uaddr2; - } futex; - /* For nanosleep */ - struct { - clockid_t clockid; - struct timespec __user *rmtp; -#ifdef CONFIG_COMPAT - struct compat_timespec __user *compat_rmtp; -#endif - u64 expires; - } nanosleep; - /* For poll */ - struct { - struct pollfd __user *ufds; - int nfds; - int has_timeout; - unsigned long tv_sec; - unsigned long tv_nsec; - } poll; - }; -}; - -extern long do_no_restart_syscall(struct restart_block *parm); - #include #include -- GitLab From be8c7b643033be34f78c8cfd8e43ed141b35d676 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 19 Oct 2016 19:28:13 +0100 Subject: [PATCH 002/855] UPSTREAM: thread_info: include for THREAD_INFO_IN_TASK When CONFIG_THREAD_INFO_IN_TASK is selected, the current_thread_info() macro relies on current having been defined prior to its use. However, not all users of current_thread_info() include , and thus current is not guaranteed to be defined. When CONFIG_THREAD_INFO_IN_TASK is not selected, it's possible that get_current() / current are based upon current_thread_info(), and includes . Thus always including would result in circular dependences on some platforms. To ensure both cases work, this patch includes , but only when CONFIG_THREAD_INFO_IN_TASK is selected. Signed-off-by: Mark Rutland Acked-by: Heiko Carstens Reviewed-by: Andy Lutomirski Cc: Andrew Morton Cc: Kees Cook Signed-off-by: Catalin Marinas (cherry picked from commit dc3d2a679cd8631b8a570fc8ca5f4712d7d25698) Change-Id: If6e47e03c9bef27ff7f4429ed15367e8ff185bed Signed-off-by: Greg Hackmann --- include/linux/thread_info.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index c75c6ab364ca..58373875e8ee 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -12,6 +12,12 @@ #include #ifdef CONFIG_THREAD_INFO_IN_TASK +/* + * For CONFIG_THREAD_INFO_IN_TASK kernels we need for the + * definition of current, but for !CONFIG_THREAD_INFO_IN_TASK kernels, + * including can cause a circular dependency on some platforms. + */ +#include #define current_thread_info() ((struct thread_info *)current) #endif -- GitLab From 85852eab3c519f0bbfbd47dfe7c65be3c2877bdb Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Wed, 18 Apr 2018 15:00:51 -0700 Subject: [PATCH 003/855] ANDROID: arm64: temporarily mark ARM64_SW_TTBR0_PAN as BROKEN The backport of ARM64 THREAD_INFO_IN_TASK is about to take away init_thread_info. This will break the build for kernels with CONFIG_ARM64_SW_TTBR0_PAN=y. Make this option depend on BROKEN until we repair the damage later in the patchstack. Change-Id: I383f1a0529f8b893c5f70dbb471fe25b1db1414e Signed-off-by: Greg Hackmann --- arch/arm64/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 8108f56b59fe..481840bee376 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -832,6 +832,7 @@ endif config ARM64_SW_TTBR0_PAN bool "Emulate Privileged Access Never using TTBR0_EL1 switching" + depends on BROKEN help Enabling this option prevents the kernel from accessing user-space memory directly by pointing TTBR0_EL1 to a reserved -- GitLab From ed97c7b462ebb67f2a3d4262c7ad0ef52e97a45c Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 3 Nov 2016 20:23:03 +0000 Subject: [PATCH 004/855] UPSTREAM: arm64: thread_info remove stale items We have a comment claiming __switch_to() cares about where cpu_context is located relative to cpu_domain in thread_info. However arm64 has never had a thread_info::cpu_domain field, and neither __switch_to nor cpu_switch_to care where the cpu_context field is relative to others. Additionally, the init_thread_info alias is never used anywhere in the kernel, and will shortly become problematic when thread_info is moved into task_struct. This patch removes both. Signed-off-by: Mark Rutland Tested-by: Laura Abbott Cc: James Morse Cc: Will Deacon Signed-off-by: Catalin Marinas (cherry picked from commit dcbe02855f048fdf1e13ebc697e83c8d297f9f5a) Change-Id: I7204c0ea6c90751d5b6f88fc1ae5cd51514e5591 Signed-off-by: Greg Hackmann --- arch/arm64/include/asm/thread_info.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index 3e34cc65b9bd..e6960fde32f1 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -42,7 +42,6 @@ typedef unsigned long mm_segment_t; /* * low level task data that entry.S needs immediate access to. - * __switch_to() assumes cpu_context follows immediately after cpu_domain. */ struct thread_info { unsigned long flags; /* low level flags */ @@ -63,7 +62,6 @@ struct thread_info { .addr_limit = KERNEL_DS, \ } -#define init_thread_info (init_thread_union.thread_info) #define init_stack (init_thread_union.stack) /* -- GitLab From eb1ac3bbf423860eb72fef2ef2f33e11aa871d7a Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 3 Nov 2016 20:23:04 +0000 Subject: [PATCH 005/855] BACKPORT: arm64: asm-offsets: remove unused definitions Subsequent patches will move the thread_info::{task,cpu} fields, and the current TI_{TASK,CPU} offset definitions are not used anywhere. This patch removes the redundant definitions. Signed-off-by: Mark Rutland Tested-by: Laura Abbott Cc: James Morse Cc: Will Deacon Signed-off-by: Catalin Marinas (cherry picked from commit 3fe12da4c7fa6491e0fb7c5371716ac7f8ea80a5) Change-Id: I1753d6ba7db05c1395315b6956af500a32c9e426 [ghackmann@google.com: fix trivial merge conflicts with SW PAN emulation backport] Signed-off-by: Greg Hackmann --- arch/arm64/kernel/asm-offsets.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index b6c9389c160a..1ea3168cc429 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -40,8 +40,6 @@ int main(void) DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit)); - DEFINE(TI_TASK, offsetof(struct thread_info, task)); - DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); #ifdef CONFIG_ARM64_SW_TTBR0_PAN DEFINE(TSK_TI_TTBR0, offsetof(struct thread_info, ttbr0)); #endif -- GitLab From ab96e216b6dba981fcb4f3b48c9530961cbc47c1 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 3 Nov 2016 20:23:05 +0000 Subject: [PATCH 006/855] UPSTREAM: arm64: factor out current_stack_pointer We define current_stack_pointer in , though other files and header relying upon it do not have this necessary include, and are thus fragile to changes in the header soup. Subsequent patches will affect the header soup such that directly including may result in a circular header include in some of these cases, so we can't simply include . Instead, factor current_thread_info into its own header, and have all existing users include this explicitly. Signed-off-by: Mark Rutland Tested-by: Laura Abbott Cc: Will Deacon Signed-off-by: Catalin Marinas (cherry picked from commit a9ea0017ebe8889dfa136cac2aa7ae0ee6915e1f) Change-Id: I3b509f998c13da8f614ecd39052ed803009ab8a1 Signed-off-by: Greg Hackmann --- arch/arm64/include/asm/percpu.h | 2 ++ arch/arm64/include/asm/perf_event.h | 2 ++ arch/arm64/include/asm/stack_pointer.h | 9 +++++++++ arch/arm64/include/asm/thread_info.h | 6 +----- arch/arm64/kernel/return_address.c | 1 + arch/arm64/kernel/stacktrace.c | 1 + arch/arm64/kernel/traps.c | 1 + 7 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 arch/arm64/include/asm/stack_pointer.h diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h index 5394c8405e66..d7a3c6294224 100644 --- a/arch/arm64/include/asm/percpu.h +++ b/arch/arm64/include/asm/percpu.h @@ -16,6 +16,8 @@ #ifndef __ASM_PERCPU_H #define __ASM_PERCPU_H +#include + static inline void set_my_cpu_offset(unsigned long off) { asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory"); diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h index 38b6a2b49d68..8d5cbec17d80 100644 --- a/arch/arm64/include/asm/perf_event.h +++ b/arch/arm64/include/asm/perf_event.h @@ -17,6 +17,8 @@ #ifndef __ASM_PERF_EVENT_H #define __ASM_PERF_EVENT_H +#include + #define ARMV8_PMU_MAX_COUNTERS 32 #define ARMV8_PMU_COUNTER_MASK (ARMV8_PMU_MAX_COUNTERS - 1) diff --git a/arch/arm64/include/asm/stack_pointer.h b/arch/arm64/include/asm/stack_pointer.h new file mode 100644 index 000000000000..ffcdf742cddf --- /dev/null +++ b/arch/arm64/include/asm/stack_pointer.h @@ -0,0 +1,9 @@ +#ifndef __ASM_STACK_POINTER_H +#define __ASM_STACK_POINTER_H + +/* + * how to get the current stack pointer from C + */ +register unsigned long current_stack_pointer asm ("sp"); + +#endif /* __ASM_STACK_POINTER_H */ diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index e6960fde32f1..aec20c7c62a5 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -36,6 +36,7 @@ struct task_struct; +#include #include typedef unsigned long mm_segment_t; @@ -64,11 +65,6 @@ struct thread_info { #define init_stack (init_thread_union.stack) -/* - * how to get the current stack pointer from C - */ -register unsigned long current_stack_pointer asm ("sp"); - /* * how to get the thread information struct from C */ diff --git a/arch/arm64/kernel/return_address.c b/arch/arm64/kernel/return_address.c index 1718706fde83..12a87f2600f2 100644 --- a/arch/arm64/kernel/return_address.c +++ b/arch/arm64/kernel/return_address.c @@ -12,6 +12,7 @@ #include #include +#include #include struct return_address_data { diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index c2efddfca18c..5b8006819cde 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -22,6 +22,7 @@ #include #include +#include #include /* diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index d210bbfcd09c..6c0c02cb2983 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include -- GitLab From 34e59ca8fa0dcec31226fc364600cfe5056dd5d9 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 3 Nov 2016 20:23:06 +0000 Subject: [PATCH 007/855] UPSTREAM: arm64: traps: simplify die() and __die() In arm64's die and __die routines we pass around a thread_info, and subsequently use this to determine the relevant task_struct, and the end of the thread's stack. Subsequent patches will decouple thread_info from the stack, and this approach will no longer work. To figure out the end of the stack, we can use the new generic end_of_stack() helper. As we only call __die() from die(), and die() always deals with the current task, we can remove the parameter and have both acquire current directly, which also makes it clear that __die can't be called for arbitrary tasks. Signed-off-by: Mark Rutland Tested-by: Laura Abbott Cc: Will Deacon Signed-off-by: Catalin Marinas (cherry picked from commit 876e7a38e8788773aac768091aaa3b42e470c03b) Change-Id: If29e80223165e96bfe5b24aba766587165509a62 Signed-off-by: Greg Hackmann --- arch/arm64/kernel/traps.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 6c0c02cb2983..5bd77f37f297 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -229,10 +229,9 @@ void show_stack(struct task_struct *tsk, unsigned long *sp) #endif #define S_SMP " SMP" -static int __die(const char *str, int err, struct thread_info *thread, - struct pt_regs *regs) +static int __die(const char *str, int err, struct pt_regs *regs) { - struct task_struct *tsk = thread->task; + struct task_struct *tsk = current; static int die_counter; int ret; @@ -247,7 +246,8 @@ static int __die(const char *str, int err, struct thread_info *thread, print_modules(); __show_regs(regs); pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n", - TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1); + TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), + end_of_stack(tsk)); if (!user_mode(regs)) { dump_mem(KERN_EMERG, "Stack: ", regs->sp, @@ -266,7 +266,6 @@ static DEFINE_RAW_SPINLOCK(die_lock); */ void die(const char *str, struct pt_regs *regs, int err) { - struct thread_info *thread = current_thread_info(); int ret; oops_enter(); @@ -274,9 +273,9 @@ void die(const char *str, struct pt_regs *regs, int err) raw_spin_lock_irq(&die_lock); console_verbose(); bust_spinlocks(1); - ret = __die(str, err, thread, regs); + ret = __die(str, err, regs); - if (regs && kexec_should_crash(thread->task)) + if (regs && kexec_should_crash(current)) crash_kexec(regs); bust_spinlocks(0); -- GitLab From abcc8cc3e49d8aa809a341a8b417f6f98e5242a8 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 3 Nov 2016 20:23:07 +0000 Subject: [PATCH 008/855] UPSTREAM: arm64: unexport walk_stackframe The walk_stackframe functions is architecture-specific, with a varying prototype, and common code should not use it directly. None of its current users can be built as modules. With THREAD_INFO_IN_TASK, users will also need to hold a stack reference before calling it. There's no reason for it to be exported, and it's very easy to misuse, so unexport it for now. Signed-off-by: Mark Rutland Cc: Will Deacon Signed-off-by: Catalin Marinas (cherry picked from commit 2020a5ae7c8c2c8504565004915017507b135c63) Change-Id: If09c303ccd98dcc030e20a16a2eab5bf7bb54e4a Signed-off-by: Greg Hackmann --- arch/arm64/kernel/stacktrace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 5b8006819cde..d53f99d4c223 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -129,7 +129,6 @@ void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame, break; } } -EXPORT_SYMBOL(walk_stackframe); #ifdef CONFIG_STACKTRACE struct stack_trace_data { -- GitLab From 0c7aad65028f70c0b6f1a69c9e86ba26824b221e Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 3 Nov 2016 20:23:08 +0000 Subject: [PATCH 009/855] UPSTREAM: arm64: prep stack walkers for THREAD_INFO_IN_TASK When CONFIG_THREAD_INFO_IN_TASK is selected, task stacks may be freed before a task is destroyed. To account for this, the stacks are refcounted, and when manipulating the stack of another task, it is necessary to get/put the stack to ensure it isn't freed and/or re-used while we do so. This patch reworks the arm64 stack walking code to account for this. When CONFIG_THREAD_INFO_IN_TASK is not selected these perform no refcounting, and this should only be a structural change that does not affect behaviour. Signed-off-by: Mark Rutland Tested-by: Laura Abbott Cc: AKASHI Takahiro Cc: Andy Lutomirski Cc: James Morse Cc: Will Deacon Signed-off-by: Catalin Marinas (cherry picked from commit 9bbd4c56b0b642f04396da378296e68096d5afca) Change-Id: I3ca86d1284456eeabe862bec8271570cc7e4a720 Signed-off-by: Greg Hackmann --- arch/arm64/kernel/process.c | 20 ++++++++++++++------ arch/arm64/kernel/stacktrace.c | 5 +++++ arch/arm64/kernel/traps.c | 5 +++++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 20a6d909f324..5d6c9dad7689 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -425,27 +425,35 @@ struct task_struct *__switch_to(struct task_struct *prev, unsigned long get_wchan(struct task_struct *p) { struct stackframe frame; - unsigned long stack_page; + unsigned long stack_page, ret = 0; int count = 0; if (!p || p == current || p->state == TASK_RUNNING) return 0; + stack_page = (unsigned long)try_get_task_stack(p); + if (!stack_page) + return 0; + frame.fp = thread_saved_fp(p); frame.sp = thread_saved_sp(p); frame.pc = thread_saved_pc(p); #ifdef CONFIG_FUNCTION_GRAPH_TRACER frame.graph = p->curr_ret_stack; #endif - stack_page = (unsigned long)task_stack_page(p); do { if (frame.sp < stack_page || frame.sp >= stack_page + THREAD_SIZE || unwind_frame(p, &frame)) - return 0; - if (!in_sched_functions(frame.pc)) - return frame.pc; + goto out; + if (!in_sched_functions(frame.pc)) { + ret = frame.pc; + goto out; + } } while (count ++ < 16); - return 0; + +out: + put_task_stack(p); + return ret; } unsigned long arch_align_stack(unsigned long sp) diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index d53f99d4c223..8a552a33c6ef 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -181,6 +181,9 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) struct stack_trace_data data; struct stackframe frame; + if (!try_get_task_stack(tsk)) + return; + data.trace = trace; data.skip = trace->skip; @@ -202,6 +205,8 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) walk_stackframe(tsk, &frame, save_trace, &data); if (trace->nr_entries < trace->max_entries) trace->entries[trace->nr_entries++] = ULONG_MAX; + + put_task_stack(tsk); } void save_stack_trace(struct stack_trace *trace) diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 5bd77f37f297..86a87ae2b996 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -149,6 +149,9 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) if (!tsk) tsk = current; + if (!try_get_task_stack(tsk)) + return; + /* * Switching between stacks is valid when tracing current and in * non-preemptible context. @@ -214,6 +217,8 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) stack + sizeof(struct pt_regs)); } } + + put_task_stack(tsk); } void show_stack(struct task_struct *tsk, unsigned long *sp) -- GitLab From 0ec37136b90e94278621e0281f7865db8017ef6f Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 3 Nov 2016 20:23:09 +0000 Subject: [PATCH 010/855] UPSTREAM: arm64: move sp_el0 and tpidr_el1 into cpu_suspend_ctx When returning from idle, we rely on the fact that thread_info lives at the end of the kernel stack, and restore this by masking the saved stack pointer. Subsequent patches will sever the relationship between the stack and thread_info, and to cater for this we must save/restore sp_el0 explicitly, storing it in cpu_suspend_ctx. As cpu_suspend_ctx must be doubleword aligned, this leaves us with an extra slot in cpu_suspend_ctx. We can use this to save/restore tpidr_el1 in the same way, which simplifies the code, avoiding pointer chasing on the restore path (as we no longer need to load thread_info::cpu followed by the relevant slot in __per_cpu_offset based on this). This patch stashes both registers in cpu_suspend_ctx. Signed-off-by: Mark Rutland Tested-by: Laura Abbott Cc: James Morse Cc: Lorenzo Pieralisi Cc: Will Deacon Signed-off-by: Catalin Marinas (cherry picked from commit 623b476fc815464a0241ea7483da7b3580b7d8ac) Change-Id: I8e3343455895f1acb8c6014de8d63ece3560442d Signed-off-by: Greg Hackmann --- arch/arm64/include/asm/suspend.h | 2 +- arch/arm64/kernel/sleep.S | 3 --- arch/arm64/kernel/suspend.c | 6 ------ arch/arm64/mm/proc.S | 6 ++++++ 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/arch/arm64/include/asm/suspend.h b/arch/arm64/include/asm/suspend.h index b8a313fd7a09..de5600f40adf 100644 --- a/arch/arm64/include/asm/suspend.h +++ b/arch/arm64/include/asm/suspend.h @@ -1,7 +1,7 @@ #ifndef __ASM_SUSPEND_H #define __ASM_SUSPEND_H -#define NR_CTX_REGS 10 +#define NR_CTX_REGS 12 #define NR_CALLEE_SAVED_REGS 12 /* diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index 0030d6964e65..5a4fbcc744d2 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -125,9 +125,6 @@ ENTRY(_cpu_resume) /* load sp from context */ ldr x2, [x0, #CPU_CTX_SP] mov sp, x2 - /* save thread_info */ - and x2, x2, #~(THREAD_SIZE - 1) - msr sp_el0, x2 /* * cpu_do_resume expects x0 to contain context address pointer */ diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index bb0cd787a9d3..1e3be9064cfa 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c @@ -46,12 +46,6 @@ void notrace __cpu_suspend_exit(void) */ cpu_uninstall_idmap(); - /* - * Restore per-cpu offset before any kernel - * subsystem relying on it has a chance to run. - */ - set_my_cpu_offset(per_cpu_offset(cpu)); - /* * PSTATE was not saved over suspend/resume, re-enable any detected * features that might not have been set correctly. diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index d414c8a30858..2c364b085eb3 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -70,11 +70,14 @@ ENTRY(cpu_do_suspend) mrs x8, mdscr_el1 mrs x9, oslsr_el1 mrs x10, sctlr_el1 + mrs x11, tpidr_el1 + mrs x12, sp_el0 stp x2, x3, [x0] stp x4, xzr, [x0, #16] stp x5, x6, [x0, #32] stp x7, x8, [x0, #48] stp x9, x10, [x0, #64] + stp x11, x12, [x0, #80] ret ENDPROC(cpu_do_suspend) @@ -90,6 +93,7 @@ ENTRY(cpu_do_resume) ldp x6, x8, [x0, #32] ldp x9, x10, [x0, #48] ldp x11, x12, [x0, #64] + ldp x13, x14, [x0, #80] msr tpidr_el0, x2 msr tpidrro_el0, x3 msr contextidr_el1, x4 @@ -112,6 +116,8 @@ ENTRY(cpu_do_resume) msr mdscr_el1, x10 msr sctlr_el1, x12 + msr tpidr_el1, x13 + msr sp_el0, x14 /* * Restore oslsr_el1 by writing oslar_el1 */ -- GitLab From e9865e59a0dbb9bee231ecf99388dc3182836f80 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 3 Nov 2016 20:23:10 +0000 Subject: [PATCH 011/855] UPSTREAM: arm64: smp: prepare for smp_processor_id() rework Subsequent patches will make smp_processor_id() use a percpu variable. This will make smp_processor_id() dependent on the percpu offset, and thus we cannot use smp_processor_id() to figure out what to initialise the offset to. Prepare for this by initialising the percpu offset based on current::cpu, which will work regardless of how smp_processor_id() is implemented. Also, make this relationship obvious by placing this code together at the start of secondary_start_kernel(). Signed-off-by: Mark Rutland Tested-by: Laura Abbott Cc: Will Deacon Signed-off-by: Catalin Marinas (cherry picked from commit 580efaa7ccfb8c0790dce4396434f0e5ac8d86ee) Change-Id: Ia2a7f756a3f5049865a849643fee945e283f93b6 Signed-off-by: Greg Hackmann --- arch/arm64/kernel/smp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index a70f7d3361c4..ac5ce58cd268 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -208,7 +208,10 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) asmlinkage void secondary_start_kernel(void) { struct mm_struct *mm = &init_mm; - unsigned int cpu = smp_processor_id(); + unsigned int cpu; + + cpu = task_cpu(current); + set_my_cpu_offset(per_cpu_offset(cpu)); /* * All kernel threads share the same mm context; grab a @@ -217,8 +220,6 @@ asmlinkage void secondary_start_kernel(void) atomic_inc(&mm->mm_count); current->active_mm = mm; - set_my_cpu_offset(per_cpu_offset(smp_processor_id())); - /* * TTBR0 is only used for the identity mapping at this stage. Make it * point to zero page to avoid speculatively fetching new entries. -- GitLab From 75c9d93358f0d219b66ba6cfa6f92dfee8925b47 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 3 Nov 2016 20:23:11 +0000 Subject: [PATCH 012/855] UPSTREAM: arm64: make cpu number a percpu variable In the absence of CONFIG_THREAD_INFO_IN_TASK, core code maintains thread_info::cpu, and low-level architecture code can access this to build raw_smp_processor_id(). With CONFIG_THREAD_INFO_IN_TASK, core code maintains task_struct::cpu, which for reasons of hte header soup is not accessible to low-level arch code. Instead, we can maintain a percpu variable containing the cpu number. For both the old and new implementation of raw_smp_processor_id(), we read a syreg into a GPR, add an offset, and load the result. As the offset is now larger, it may not be folded into the load, but otherwise the assembly shouldn't change much. Signed-off-by: Mark Rutland Tested-by: Laura Abbott Cc: James Morse Cc: Suzuki K Poulose Cc: Will Deacon Signed-off-by: Catalin Marinas (cherry picked from commit 57c82954e77fa12c1023e87210d2ede77aaa0058) Change-Id: I932b9159ad8efe028d68edc9cb41844810cd6391 Signed-off-by: Greg Hackmann --- arch/arm64/include/asm/smp.h | 11 ++++++++++- arch/arm64/kernel/smp.c | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 022644704a93..968b08de820d 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -29,11 +29,20 @@ #ifndef __ASSEMBLY__ +#include + #include #include #include -#define raw_smp_processor_id() (current_thread_info()->cpu) +DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number); + +/* + * We don't use this_cpu_read(cpu_number) as that has implicit writes to + * preempt_count, and associated (compiler) barriers, that we'd like to avoid + * the expense of. If we're preemptible, the value can be stale at use anyway. + */ +#define raw_smp_processor_id() (*this_cpu_ptr(&cpu_number)) struct seq_file; diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index ac5ce58cd268..e51c8dc3e654 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -58,6 +58,9 @@ #define CREATE_TRACE_POINTS #include +DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number); +EXPORT_PER_CPU_SYMBOL(cpu_number); + /* * as from 2.5, kernels no longer have an init_tasks structure * so we need some other way of telling a new secondary core @@ -719,6 +722,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus) */ for_each_possible_cpu(cpu) { + per_cpu(cpu_number, cpu) = cpu; + if (cpu == smp_processor_id()) continue; -- GitLab From bf4efab5a1958cba0ee18c49fd2387010f52ddf6 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Thu, 1 Dec 2016 15:55:13 +0000 Subject: [PATCH 013/855] UPSTREAM: arm64: smp: Prevent raw_smp_processor_id() recursion Under CONFIG_DEBUG_PREEMPT=y, this_cpu_ptr() ends up calling back into raw_smp_processor_id(), resulting in some hilariously catastrophic infinite recursion. In the normal case, we have: #define this_cpu_ptr(ptr) raw_cpu_ptr(ptr) and everything is dandy. However for CONFIG_DEBUG_PREEMPT, this_cpu_ptr() is defined in terms of my_cpu_offset, wherein the fun begins: #define my_cpu_offset per_cpu_offset(smp_processor_id()) ... #define smp_processor_id() debug_smp_processor_id() ... notrace unsigned int debug_smp_processor_id(void) { return check_preemption_disabled("smp_processor_id", ""); ... notrace static unsigned int check_preemption_disabled(const char *what1, const char *what2) { int this_cpu = raw_smp_processor_id(); and bang. Use raw_cpu_ptr() directly to avoid that. Fixes: 57c82954e77f ("arm64: make cpu number a percpu variable") Reported-by: Marek Szyprowski Acked-by: Will Deacon Signed-off-by: Robin Murphy Tested-by: Marek Szyprowski Signed-off-by: Catalin Marinas (cherry picked from commit 34a6980c82fb1342e7064844c95aa4cf933e5ecc) Change-Id: I74182554336a04f97c869d97c8d9b1d63a2676f3 Signed-off-by: Greg Hackmann --- arch/arm64/include/asm/smp.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 968b08de820d..5eccf50ec7f8 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -41,8 +41,10 @@ DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number); * We don't use this_cpu_read(cpu_number) as that has implicit writes to * preempt_count, and associated (compiler) barriers, that we'd like to avoid * the expense of. If we're preemptible, the value can be stale at use anyway. + * And we can't use this_cpu_ptr() either, as that winds up recursing back + * here under CONFIG_DEBUG_PREEMPT=y. */ -#define raw_smp_processor_id() (*this_cpu_ptr(&cpu_number)) +#define raw_smp_processor_id() (*raw_cpu_ptr(&cpu_number)) struct seq_file; -- GitLab From 8b6c9c99c14de684f6157f3480ac8b1820a740c2 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 3 Nov 2016 20:23:12 +0000 Subject: [PATCH 014/855] UPSTREAM: arm64: assembler: introduce ldr_this_cpu Shortly we will want to load a percpu variable in the return from userspace path. We can save an instruction by folding the addition of the percpu offset into the load instruction, and this patch adds a new helper to do so. At the same time, we clean up this_cpu_ptr for consistency. As with {adr,ldr,str}_l, we change the template to take the destination register first, and name this dst. Secondly, we rename the macro to adr_this_cpu, following the scheme of adr_l, and matching the newly added ldr_this_cpu. Signed-off-by: Mark Rutland Tested-by: Laura Abbott Cc: Ard Biesheuvel Cc: James Morse Cc: Will Deacon Signed-off-by: Catalin Marinas (cherry picked from commit 1b7e2296a822dfd2349960addc42a139360ce769) Change-Id: I3f40a2dd358eca3bc19dde562e77a990bbfe72e9 Signed-off-by: Greg Hackmann --- arch/arm64/include/asm/assembler.h | 19 +++++++++++++++---- arch/arm64/kernel/entry.S | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index bfd1c63f0a8d..60ac304a3b99 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -247,14 +247,25 @@ lr .req x30 // link register .endm /* + * @dst: Result of per_cpu(sym, smp_processor_id()) * @sym: The name of the per-cpu variable - * @reg: Result of per_cpu(sym, smp_processor_id()) * @tmp: scratch register */ - .macro this_cpu_ptr, sym, reg, tmp - adr_l \reg, \sym + .macro adr_this_cpu, dst, sym, tmp + adr_l \dst, \sym + mrs \tmp, tpidr_el1 + add \dst, \dst, \tmp + .endm + + /* + * @dst: Result of READ_ONCE(per_cpu(sym, smp_processor_id())) + * @sym: The name of the per-cpu variable + * @tmp: scratch register + */ + .macro ldr_this_cpu dst, sym, tmp + adr_l \dst, \sym mrs \tmp, tpidr_el1 - add \reg, \reg, \tmp + ldr \dst, [\dst, \tmp] .endm /* diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index ef3b9a01c61d..76a160d4d438 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -302,7 +302,7 @@ alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0 cmp x25, tsk b.ne 9998f - this_cpu_ptr irq_stack, x25, x26 + adr_this_cpu x25, irq_stack, x26 mov x26, #IRQ_STACK_START_SP add x26, x25, x26 -- GitLab From 5b7e8f735ce52047a37417711b8a4e9d90ddb0f3 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 3 Nov 2016 20:23:13 +0000 Subject: [PATCH 015/855] BACKPORT: arm64: split thread_info from task stack This patch moves arm64's struct thread_info from the task stack into task_struct. This protects thread_info from corruption in the case of stack overflows, and makes its address harder to determine if stack addresses are leaked, making a number of attacks more difficult. Precise detection and handling of overflow is left for subsequent patches. Largely, this involves changing code to store the task_struct in sp_el0, and acquire the thread_info from the task struct. Core code now implements current_thread_info(), and as noted in this relies on offsetof(task_struct, thread_info) == 0, enforced by core code. This change means that the 'tsk' register used in entry.S now points to a task_struct, rather than a thread_info as it used to. To make this clear, the TI_* field offsets are renamed to TSK_TI_*, with asm-offsets appropriately updated to account for the structural change. Userspace clobbers sp_el0, and we can no longer restore this from the stack. Instead, the current task is cached in a per-cpu variable that we can safely access from early assembly as interrupts are disabled (and we are thus not preemptible). Both secondary entry and idle are updated to stash the sp and task pointer separately. Signed-off-by: Mark Rutland Tested-by: Laura Abbott Cc: AKASHI Takahiro Cc: Andy Lutomirski Cc: Ard Biesheuvel Cc: James Morse Cc: Kees Cook Cc: Suzuki K Poulose Cc: Will Deacon Signed-off-by: Catalin Marinas (cherry picked from commit c02433dd6de32f042cf3ffe476746b1115b8c096) Change-Id: I46fdcdd93dbdb5bd2344ccabeb2f27bdfb086298 [ghackmann@google.com: fix trivial merge conflicts with SW PAN emulation backport] Signed-off-by: Greg Hackmann --- arch/arm64/Kconfig | 1 + arch/arm64/include/asm/Kbuild | 1 - arch/arm64/include/asm/current.h | 22 +++++++++++++++ arch/arm64/include/asm/smp.h | 1 + arch/arm64/include/asm/thread_info.h | 24 ---------------- arch/arm64/kernel/asm-offsets.c | 8 ++++-- arch/arm64/kernel/entry.S | 41 ++++++++++++++-------------- arch/arm64/kernel/head.S | 11 ++++---- arch/arm64/kernel/process.c | 16 +++++++++++ arch/arm64/kernel/smp.c | 2 ++ 10 files changed, 73 insertions(+), 54 deletions(-) create mode 100644 arch/arm64/include/asm/current.h diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 481840bee376..ac4166df7f3e 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -110,6 +110,7 @@ config ARM64 select POWER_SUPPLY select SPARSE_IRQ select SYSCTL_EXCEPTION_TRACE + select THREAD_INFO_IN_TASK help ARM 64-bit (AArch64) Linux support. diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild index 44e1d7f10add..28196b18e394 100644 --- a/arch/arm64/include/asm/Kbuild +++ b/arch/arm64/include/asm/Kbuild @@ -1,7 +1,6 @@ generic-y += bugs.h generic-y += clkdev.h generic-y += cputime.h -generic-y += current.h generic-y += delay.h generic-y += div64.h generic-y += dma.h diff --git a/arch/arm64/include/asm/current.h b/arch/arm64/include/asm/current.h new file mode 100644 index 000000000000..f2bcbe2d9889 --- /dev/null +++ b/arch/arm64/include/asm/current.h @@ -0,0 +1,22 @@ +#ifndef __ASM_CURRENT_H +#define __ASM_CURRENT_H + +#include + +#include + +#ifndef __ASSEMBLY__ + +struct task_struct; + +static __always_inline struct task_struct *get_current(void) +{ + return (struct task_struct *)read_sysreg(sp_el0); +} + +#define current get_current() + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_CURRENT_H */ + diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 5eccf50ec7f8..d050d720a1b4 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -84,6 +84,7 @@ asmlinkage void secondary_start_kernel(void); */ struct secondary_data { void *stack; + struct task_struct *task; long status; }; diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index aec20c7c62a5..08580fa45677 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -47,44 +47,20 @@ typedef unsigned long mm_segment_t; struct thread_info { unsigned long flags; /* low level flags */ mm_segment_t addr_limit; /* address limit */ - struct task_struct *task; /* main task structure */ #ifdef CONFIG_ARM64_SW_TTBR0_PAN u64 ttbr0; /* saved TTBR0_EL1 */ #endif int preempt_count; /* 0 => preemptable, <0 => bug */ - int cpu; /* cpu */ }; #define INIT_THREAD_INFO(tsk) \ { \ - .task = &tsk, \ - .flags = 0, \ .preempt_count = INIT_PREEMPT_COUNT, \ .addr_limit = KERNEL_DS, \ } #define init_stack (init_thread_union.stack) -/* - * how to get the thread information struct from C - */ -static inline struct thread_info *current_thread_info(void) __attribute_const__; - -/* - * struct thread_info can be accessed directly via sp_el0. - * - * We don't use read_sysreg() as we want the compiler to cache the value where - * possible. - */ -static inline struct thread_info *current_thread_info(void) -{ - unsigned long sp_el0; - - asm ("mrs %0, sp_el0" : "=r" (sp_el0)); - - return (struct thread_info *)sp_el0; -} - #define thread_saved_pc(tsk) \ ((unsigned long)(tsk->thread.cpu_context.pc)) #define thread_saved_sp(tsk) \ diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 1ea3168cc429..46b4e1b3caef 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -37,12 +37,13 @@ int main(void) { DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); BLANK(); - DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); - DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); - DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit)); + DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags)); + DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count)); + DEFINE(TSK_TI_ADDR_LIMIT, offsetof(struct task_struct, thread_info.addr_limit)); #ifdef CONFIG_ARM64_SW_TTBR0_PAN DEFINE(TSK_TI_TTBR0, offsetof(struct thread_info, ttbr0)); #endif + DEFINE(TSK_STACK, offsetof(struct task_struct, stack)); BLANK(); DEFINE(THREAD_CPU_CONTEXT, offsetof(struct task_struct, thread.cpu_context)); BLANK(); @@ -125,6 +126,7 @@ int main(void) DEFINE(TZ_DSTTIME, offsetof(struct timezone, tz_dsttime)); BLANK(); DEFINE(CPU_BOOT_STACK, offsetof(struct secondary_data, stack)); + DEFINE(CPU_BOOT_TASK, offsetof(struct secondary_data, task)); BLANK(); #ifdef CONFIG_KVM_ARM_HOST DEFINE(VCPU_CONTEXT, offsetof(struct kvm_vcpu, arch.ctxt)); diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 76a160d4d438..314e8a5436d1 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -119,9 +119,8 @@ alternative_else_nop_endif .if \el == 0 mrs x21, sp_el0 - mov tsk, sp - and tsk, tsk, #~(THREAD_SIZE - 1) // Ensure MDSCR_EL1.SS is clear, - ldr x19, [tsk, #TI_FLAGS] // since we can unmask debug + ldr_this_cpu tsk, __entry_task, x20 // Ensure MDSCR_EL1.SS is clear, + ldr x19, [tsk, #TSK_TI_FLAGS] // since we can unmask debug disable_step_tsk x19, x20 // exceptions when scheduling. mov x29, xzr // fp pointed to user-space @@ -129,10 +128,10 @@ alternative_else_nop_endif add x21, sp, #S_FRAME_SIZE get_thread_info tsk /* Save the task's original addr_limit and set USER_DS */ - ldr x20, [tsk, #TI_ADDR_LIMIT] + ldr x20, [tsk, #TSK_TI_ADDR_LIMIT] str x20, [sp, #S_ORIG_ADDR_LIMIT] mov x20, #USER_DS - str x20, [tsk, #TI_ADDR_LIMIT] + str x20, [tsk, #TSK_TI_ADDR_LIMIT] /* No need to reset PSTATE.UAO, hardware's already set it to 0 for us */ .endif /* \el == 0 */ mrs x22, elr_el1 @@ -194,7 +193,7 @@ alternative_else_nop_endif .if \el != 0 /* Restore the task's original addr_limit. */ ldr x20, [sp, #S_ORIG_ADDR_LIMIT] - str x20, [tsk, #TI_ADDR_LIMIT] + str x20, [tsk, #TSK_TI_ADDR_LIMIT] /* No need to restore UAO, it will be restored from SPSR_EL1 */ .endif @@ -294,13 +293,14 @@ alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0 mov x19, sp // preserve the original sp /* - * Compare sp with the current thread_info, if the top - * ~(THREAD_SIZE - 1) bits match, we are on a task stack, and - * should switch to the irq stack. + * Compare sp with the base of the task stack. + * If the top ~(THREAD_SIZE - 1) bits match, we are on a task stack, + * and should switch to the irq stack. */ - and x25, x19, #~(THREAD_SIZE - 1) - cmp x25, tsk - b.ne 9998f + ldr x25, [tsk, TSK_STACK] + eor x25, x25, x19 + and x25, x25, #~(THREAD_SIZE - 1) + cbnz x25, 9998f adr_this_cpu x25, irq_stack, x26 mov x26, #IRQ_STACK_START_SP @@ -530,9 +530,9 @@ el1_irq: irq_handler #ifdef CONFIG_PREEMPT - ldr w24, [tsk, #TI_PREEMPT] // get preempt count + ldr w24, [tsk, #TSK_TI_PREEMPT] // get preempt count cbnz w24, 1f // preempt count != 0 - ldr x0, [tsk, #TI_FLAGS] // get flags + ldr x0, [tsk, #TSK_TI_FLAGS] // get flags tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling? bl el1_preempt 1: @@ -547,7 +547,7 @@ ENDPROC(el1_irq) el1_preempt: mov x24, lr 1: bl preempt_schedule_irq // irq en/disable is done inside - ldr x0, [tsk, #TI_FLAGS] // get new tasks TI_FLAGS + ldr x0, [tsk, #TSK_TI_FLAGS] // get new tasks TI_FLAGS tbnz x0, #TIF_NEED_RESCHED, 1b // needs rescheduling? ret x24 #endif @@ -786,8 +786,7 @@ ENTRY(cpu_switch_to) ldp x29, x9, [x8], #16 ldr lr, [x8] mov sp, x9 - and x9, x9, #~(THREAD_SIZE - 1) - msr sp_el0, x9 + msr sp_el0, x1 ret ENDPROC(cpu_switch_to) @@ -798,7 +797,7 @@ ENDPROC(cpu_switch_to) ret_fast_syscall: disable_irq // disable interrupts str x0, [sp, #S_X0] // returned x0 - ldr x1, [tsk, #TI_FLAGS] // re-check for syscall tracing + ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for syscall tracing and x2, x1, #_TIF_SYSCALL_WORK cbnz x2, ret_fast_syscall_trace and x2, x1, #_TIF_WORK_MASK @@ -818,14 +817,14 @@ work_pending: #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_on // enabled while in userspace #endif - ldr x1, [tsk, #TI_FLAGS] // re-check for single-step + ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for single-step b finish_ret_to_user /* * "slow" syscall return path. */ ret_to_user: disable_irq // disable interrupts - ldr x1, [tsk, #TI_FLAGS] + ldr x1, [tsk, #TSK_TI_FLAGS] and x2, x1, #_TIF_WORK_MASK cbnz x2, work_pending finish_ret_to_user: @@ -858,7 +857,7 @@ el0_svc_naked: // compat entry point enable_dbg_and_irq ct_user_exit 1 - ldr x16, [tsk, #TI_FLAGS] // check for syscall hooks + ldr x16, [tsk, #TSK_TI_FLAGS] // check for syscall hooks tst x16, #_TIF_SYSCALL_WORK b.ne __sys_trace cmp scno, sc_nr // check upper syscall limit diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 6bf32265909d..d479185d29c9 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -428,7 +428,8 @@ ENDPROC(__create_page_tables) __primary_switched: adrp x4, init_thread_union add sp, x4, #THREAD_SIZE - msr sp_el0, x4 // Save thread_info + adr_l x5, init_task + msr sp_el0, x5 // Save thread_info adr_l x8, vectors // load VBAR_EL1 with virtual msr vbar_el1, x8 // vector table address @@ -700,10 +701,10 @@ __secondary_switched: isb adr_l x0, secondary_data - ldr x0, [x0, #CPU_BOOT_STACK] // get secondary_data.stack - mov sp, x0 - and x0, x0, #~(THREAD_SIZE - 1) - msr sp_el0, x0 // save thread_info + ldr x1, [x0, #CPU_BOOT_STACK] // get secondary_data.stack + mov sp, x1 + ldr x2, [x0, #CPU_BOOT_TASK] + msr sp_el0, x2 mov x29, #0 b secondary_start_kernel ENDPROC(__secondary_switched) diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 5d6c9dad7689..41a1c402ab4e 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -396,6 +397,20 @@ void uao_thread_switch(struct task_struct *next) } } +/* + * We store our current task in sp_el0, which is clobbered by userspace. Keep a + * shadow copy so that we can restore this upon entry from userspace. + * + * This is *only* for exception entry from EL0, and is not valid until we + * __switch_to() a user task. + */ +DEFINE_PER_CPU(struct task_struct *, __entry_task); + +static void entry_task_switch(struct task_struct *next) +{ + __this_cpu_write(__entry_task, next); +} + /* * Thread switching. */ @@ -408,6 +423,7 @@ struct task_struct *__switch_to(struct task_struct *prev, tls_thread_switch(next); hw_breakpoint_thread_switch(next); contextidr_thread_switch(next); + entry_task_switch(next); uao_thread_switch(next); /* diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index e51c8dc3e654..9870badfd369 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -149,6 +149,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) * We need to tell the secondary core where to find its stack and the * page tables. */ + secondary_data.task = idle; secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; update_cpu_boot_status(CPU_MMU_OFF); __flush_dcache_area(&secondary_data, sizeof(secondary_data)); @@ -173,6 +174,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) pr_err("CPU%u: failed to boot: %d\n", cpu, ret); } + secondary_data.task = NULL; secondary_data.stack = NULL; status = READ_ONCE(secondary_data.status); if (ret && status) { -- GitLab From 70b330caef3ca7cb6b009a299e49b5be3a330308 Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Wed, 18 Apr 2018 15:33:53 -0700 Subject: [PATCH 016/855] ANDROID: arm64: fix ARM64_SW_TTBR0_PAN backport Point setup.c and asm-offsets.c at ttbr0's new home inside task_struct. Change-Id: I25b7913ed01b8eb15ab1200910dca769ed1d6995 Signed-off-by: Greg Hackmann --- arch/arm64/kernel/asm-offsets.c | 2 +- arch/arm64/kernel/setup.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 46b4e1b3caef..5d2d3560f186 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -41,7 +41,7 @@ int main(void) DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count)); DEFINE(TSK_TI_ADDR_LIMIT, offsetof(struct task_struct, thread_info.addr_limit)); #ifdef CONFIG_ARM64_SW_TTBR0_PAN - DEFINE(TSK_TI_TTBR0, offsetof(struct thread_info, ttbr0)); + DEFINE(TSK_TI_TTBR0, offsetof(struct task_struct, thread_info.ttbr0)); #endif DEFINE(TSK_STACK, offsetof(struct task_struct, stack)); BLANK(); diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 6a9dc51da64c..b5222094ab52 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -298,7 +298,7 @@ void __init setup_arch(char **cmdline_p) * faults in case uaccess_enable() is inadvertently called by the init * thread. */ - init_thread_info.ttbr0 = __pa_symbol(empty_zero_page); + init_task.thread_info.ttbr0 = __pa_symbol(empty_zero_page); #endif #ifdef CONFIG_VT -- GitLab From 059e38f308c9ed2da84cb9d4cedef194b13cb395 Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Mon, 23 Apr 2018 14:32:07 -0700 Subject: [PATCH 017/855] Revert "ANDROID: arm64: temporarily mark ARM64_SW_TTBR0_PAN as BROKEN" The previous patch fixed the breakage caused by moving thread_info around, so we can re-enable this option. This reverts commit 223afa4d71f73309ba78da33ed0f362229ecb368. Change-Id: I4f43b05938055ebe791a8d128f6b8b0aa5bb2d27 Signed-off-by: Greg Hackmann --- arch/arm64/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index ac4166df7f3e..85c8f47c2876 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -833,7 +833,6 @@ endif config ARM64_SW_TTBR0_PAN bool "Emulate Privileged Access Never using TTBR0_EL1 switching" - depends on BROKEN help Enabling this option prevents the kernel from accessing user-space memory directly by pointing TTBR0_EL1 to a reserved -- GitLab From 8c01d009ed72f4ca28e321d117410a6690d643d3 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 3 Jan 2017 18:27:01 +0000 Subject: [PATCH 018/855] UPSTREAM: arm64: restore get_current() optimisation Commit c02433dd6de32f04 ("arm64: split thread_info from task stack") inverted the relationship between get_current() and current_thread_info(), with sp_el0 now holding the current task_struct rather than the current thead_info. The new implementation of get_current() prevents the compiler from being able to optimize repeated calls to either, resulting in a noticeable penalty in some microbenchmarks. This patch restores the previous optimisation by implementing get_current() in the same way as our old current_thread_info(), using a non-volatile asm statement. Acked-by: Will Deacon Signed-off-by: Mark Rutland Reported-by: Davidlohr Bueso Signed-off-by: Catalin Marinas (cherry picked from commit 9d84fb27fa135c99c9fe3de33628774a336a70a8) Change-Id: Iaa615eeac18dd76b2e5c28673aac3bd0601878ab Signed-off-by: Greg Hackmann --- arch/arm64/include/asm/current.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/current.h b/arch/arm64/include/asm/current.h index f2bcbe2d9889..86c404171305 100644 --- a/arch/arm64/include/asm/current.h +++ b/arch/arm64/include/asm/current.h @@ -9,9 +9,17 @@ struct task_struct; +/* + * We don't use read_sysreg() as we want the compiler to cache the value where + * possible. + */ static __always_inline struct task_struct *get_current(void) { - return (struct task_struct *)read_sysreg(sp_el0); + unsigned long sp_el0; + + asm ("mrs %0, sp_el0" : "=r" (sp_el0)); + + return (struct task_struct *)sp_el0; } #define current get_current() -- GitLab From a08381772a433ea221c07b7bdaad714a85ac5c3c Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 11 Apr 2018 16:19:10 -0700 Subject: [PATCH 019/855] ANDROID: sdcardfs: Check for private data earlier When an sdcardfs dentry is destroyed, it may not yet have its fsdata initialized. It must be checked before we try to access the paths in its private data. Additionally, when cleaning up the superblock after a failure, we don't have our sb private data, so check for that case. Bug: 77923821 Change-Id: I89caf6e121ed86480b42024664453fe0031bbcf3 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/dentry.c | 2 ++ fs/sdcardfs/lookup.c | 2 -- fs/sdcardfs/main.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index e9426a61d04a..166f14b2400b 100644 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -131,6 +131,8 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) static void sdcardfs_d_release(struct dentry *dentry) { + if (!dentry || !dentry->d_fsdata) + return; /* release and reset the lower paths */ if (has_graft_path(dentry)) sdcardfs_put_reset_orig_path(dentry); diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 843fcd216116..98051996ad2c 100644 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -41,8 +41,6 @@ void sdcardfs_destroy_dentry_cache(void) void free_dentry_private_data(struct dentry *dentry) { - if (!dentry || !dentry->d_fsdata) - return; kmem_cache_free(sdcardfs_dentry_cachep, dentry->d_fsdata); dentry->d_fsdata = NULL; } diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index e4fd3fbb05e6..c3120108f627 100644 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -422,7 +422,7 @@ void sdcardfs_kill_sb(struct super_block *sb) { struct sdcardfs_sb_info *sbi; - if (sb->s_magic == SDCARDFS_SUPER_MAGIC) { + if (sb->s_magic == SDCARDFS_SUPER_MAGIC && sb->s_fs_info) { sbi = SDCARDFS_SB(sb); mutex_lock(&sdcardfs_super_list_lock); list_del(&sbi->list); -- GitLab From 8442aee8ba3c880149206b94b0ca74a2fcb5c4c0 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 11 Apr 2018 16:24:51 -0700 Subject: [PATCH 020/855] ANDROID: sdcardfs: d_make_root calls iput d_make_root will call iput on failure, so we shouldn't try to do that ourselves. Signed-off-by: Daniel Rosenberg Bug: 77923821 Change-Id: I1abb4afb0f894ab917b7c6be8c833676f436beb7 --- fs/sdcardfs/main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index c3120108f627..1a977493f88d 100644 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -316,7 +316,7 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, sb->s_root = d_make_root(inode); if (!sb->s_root) { err = -ENOMEM; - goto out_iput; + goto out_sput; } d_set_d_op(sb->s_root, &sdcardfs_ci_dops); @@ -361,8 +361,6 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, /* no longer needed: free_dentry_private_data(sb->s_root); */ out_freeroot: dput(sb->s_root); -out_iput: - iput(inode); out_sput: /* drop refs we took earlier */ atomic_dec(&lower_sb->s_active); -- GitLab From 132f097f65476d574e1769ddd835088129cbb053 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 11 Apr 2018 18:39:43 -0700 Subject: [PATCH 021/855] ANDROID: sdcardfs: Set s_root to NULL after putting Signed-off-by: Daniel Rosenberg Bug: 77923821 Change-Id: I1705bfd146009561d2d1da5f0e6a342ec6932a1c --- fs/sdcardfs/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 1a977493f88d..30e0c431a1ea 100644 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -361,6 +361,7 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, /* no longer needed: free_dentry_private_data(sb->s_root); */ out_freeroot: dput(sb->s_root); + sb->s_root = NULL; out_sput: /* drop refs we took earlier */ atomic_dec(&lower_sb->s_active); -- GitLab From 7cc0d0ff5f657af691d06baa8b1ad9bf385ee433 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Wed, 25 Apr 2018 22:11:01 -0700 Subject: [PATCH 022/855] ANDROID: staging: ion: Obey kptr_restrict The /sys/kernel/debug/ion/clients/ file could disobey the setting of kptr_restrict if a client went away after the file started to be accessed. Use %pK when printing the ion client to avoid this problem. Some other debugging messages also did not use %pK, but since those messages are not very useful and have been removed upstream, just remove them instead. Bug: 77937819 Change-Id: Ie45897fe2d6ec3f842a02883e8ec929ed2e76933 Signed-off-by: Alistair Strachan --- drivers/staging/android/ion/ion.c | 11 +---------- drivers/staging/android/ion/ion_cma_heap.c | 4 ---- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 209a8f7ef02b..e8c9c72555bd 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -620,7 +620,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) mutex_lock(&debugfs_mutex); if (!is_client_alive(client)) { - seq_printf(s, "ion_client 0x%p dead, can't dump its buffers\n", + seq_printf(s, "ion_client 0x%pK dead, can't dump its buffers\n", client); mutex_unlock(&debugfs_mutex); return 0; @@ -773,7 +773,6 @@ void ion_client_destroy(struct ion_client *client) struct ion_device *dev = client->dev; struct rb_node *n; - pr_debug("%s: %d\n", __func__, __LINE__); mutex_lock(&debugfs_mutex); while ((n = rb_first(&client->handles))) { struct ion_handle *handle = rb_entry(n, struct ion_handle, @@ -846,9 +845,6 @@ static void ion_buffer_sync_for_device(struct ion_buffer *buffer, int pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; int i; - pr_debug("%s: syncing for device %s\n", __func__, - dev ? dev_name(dev) : "null"); - if (!ion_buffer_fault_user_mappings(buffer)) return; @@ -902,7 +898,6 @@ static void ion_vm_open(struct vm_area_struct *vma) mutex_lock(&buffer->lock); list_add(&vma_list->list, &buffer->vmas); mutex_unlock(&buffer->lock); - pr_debug("%s: adding %p\n", __func__, vma); } static void ion_vm_close(struct vm_area_struct *vma) @@ -910,14 +905,12 @@ static void ion_vm_close(struct vm_area_struct *vma) struct ion_buffer *buffer = vma->vm_private_data; struct ion_vma_list *vma_list, *tmp; - pr_debug("%s\n", __func__); mutex_lock(&buffer->lock); list_for_each_entry_safe(vma_list, tmp, &buffer->vmas, list) { if (vma_list->vma != vma) continue; list_del(&vma_list->list); kfree(vma_list); - pr_debug("%s: deleting %p\n", __func__, vma); break; } mutex_unlock(&buffer->lock); @@ -1207,7 +1200,6 @@ static int ion_release(struct inode *inode, struct file *file) { struct ion_client *client = file->private_data; - pr_debug("%s: %d\n", __func__, __LINE__); ion_client_destroy(client); return 0; } @@ -1219,7 +1211,6 @@ static int ion_open(struct inode *inode, struct file *file) struct ion_client *client; char debug_name[64]; - pr_debug("%s: %d\n", __func__, __LINE__); snprintf(debug_name, 64, "%u", task_pid_nr(current->group_leader)); client = ion_client_create(dev, debug_name); if (IS_ERR(client)) diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index 6c7de74bc7ab..0ca90bac4e61 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -49,8 +49,6 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, struct device *dev = cma_heap->dev; struct ion_cma_buffer_info *info; - dev_dbg(dev, "Request buffer allocation len %ld\n", len); - if (buffer->flags & ION_FLAG_CACHED) return -EINVAL; @@ -79,7 +77,6 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, /* keep this for memory release */ buffer->priv_virt = info; buffer->sg_table = info->table; - dev_dbg(dev, "Allocate buffer %p\n", buffer); return 0; free_table: @@ -97,7 +94,6 @@ static void ion_cma_free(struct ion_buffer *buffer) struct device *dev = cma_heap->dev; struct ion_cma_buffer_info *info = buffer->priv_virt; - dev_dbg(dev, "Release buffer %p\n", buffer); /* release memory */ dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle); /* release sg table */ -- GitLab From 71fce1edd26db964f5fd1b76b333bbb58076259d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 19 Oct 2017 10:32:13 +0200 Subject: [PATCH 023/855] UPSTREAM: tracing: always define trace_{irq,preempt}_{enable_disable} We get a build error in the irqsoff tracer in some configurations: kernel/trace/trace_irqsoff.c: In function 'trace_preempt_on': kernel/trace/trace_irqsoff.c:855:2: error: implicit declaration of function 'trace_preempt_enable_rcuidle'; did you mean 'trace_irq_enable_rcuidle'? [-Werror=implicit-function-declaration] trace_preempt_enable_rcuidle(a0, a1); The problem is that trace_preempt_enable_rcuidle() has different definition based on multiple Kconfig symbols, but not all combinations have a valid definition. This changes the conditions so that we always get exactly one definition of each of the four tracing macros. I have not tried to verify that these definitions are sensible, but now we can build all randconfig combinations again. Link: http://lkml.kernel.org/r/20171019083230.2450779-1-arnd@arndb.de Change-Id: I46f34a021cdbff7c92567a8343265c1d644df4c1 Fixes: d59158162e03 ("tracing: Add support for preempt and irq enable/disable events") Acked-by: Joel Fernandes Signed-off-by: Arnd Bergmann Signed-off-by: Steven Rostedt (VMware) --- include/trace/events/preemptirq.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/trace/events/preemptirq.h b/include/trace/events/preemptirq.h index f5024c560d8f..9c4eb33c5a1d 100644 --- a/include/trace/events/preemptirq.h +++ b/include/trace/events/preemptirq.h @@ -56,15 +56,18 @@ DEFINE_EVENT(preemptirq_template, preempt_enable, #include -#else /* !CONFIG_PREEMPTIRQ_EVENTS */ +#endif /* !CONFIG_PREEMPTIRQ_EVENTS */ +#if !defined(CONFIG_PREEMPTIRQ_EVENTS) || defined(CONFIG_PROVE_LOCKING) #define trace_irq_enable(...) #define trace_irq_disable(...) -#define trace_preempt_enable(...) -#define trace_preempt_disable(...) #define trace_irq_enable_rcuidle(...) #define trace_irq_disable_rcuidle(...) +#endif + +#if !defined(CONFIG_PREEMPTIRQ_EVENTS) || !defined(CONFIG_DEBUG_PREEMPT) +#define trace_preempt_enable(...) +#define trace_preempt_disable(...) #define trace_preempt_enable_rcuidle(...) #define trace_preempt_disable_rcuidle(...) - #endif -- GitLab From 193038d913f47563594814c1011a3c40e15b86ac Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 20 Apr 2018 12:19:07 -0500 Subject: [PATCH 024/855] cifs: do not allow creating sockets except with SMB1 posix exensions commit 1d0cffa674cfa7d185a302c8c6850fc50b893bed upstream. RHBZ: 1453123 Since at least the 3.10 kernel and likely a lot earlier we have not been able to create unix domain sockets in a cifs share when mounted using the SFU mount option (except when mounted with the cifs unix extensions to Samba e.g.) Trying to create a socket, for example using the af_unix command from xfstests will cause : BUG: unable to handle kernel NULL pointer dereference at 00000000 00000040 Since no one uses or depends on being able to create unix domains sockets on a cifs share the easiest fix to stop this vulnerability is to simply not allow creation of any other special files than char or block devices when sfu is used. Added update to Ronnie's patch to handle a tcon link leak, and to address a buf leak noticed by Gustavo and Colin. Acked-by: Gustavo A. R. Silva CC: Colin Ian King Reviewed-by: Pavel Shilovsky Reported-by: Eryu Guan Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/cifs/dir.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index d9cbda269462..331ddd07e505 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -673,6 +673,9 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, goto mknod_out; } + if (!S_ISCHR(mode) && !S_ISBLK(mode)) + goto mknod_out; + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) goto mknod_out; @@ -681,10 +684,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); if (buf == NULL) { - kfree(full_path); rc = -ENOMEM; - free_xid(xid); - return rc; + goto mknod_out; } if (backup_cred(cifs_sb)) @@ -731,7 +732,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, pdev->minor = cpu_to_le64(MINOR(device_number)); rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, &bytes_written, iov, 1); - } /* else if (S_ISFIFO) */ + } tcon->ses->server->ops->close(xid, tcon, &fid); d_drop(direntry); -- GitLab From 01eabcde1be5b9d0d88e98d67a97589b275a8ba6 Mon Sep 17 00:00:00 2001 From: Xiaoming Gao Date: Fri, 13 Apr 2018 17:48:08 +0800 Subject: [PATCH 025/855] x86/tsc: Prevent 32bit truncation in calc_hpet_ref() commit d3878e164dcd3925a237a20e879432400e369172 upstream. The TSC calibration code uses HPET as reference. The conversion normalizes the delta of two HPET timestamps: hpetref = ((tshpet1 - tshpet2) * HPET_PERIOD) / 1e6 and then divides the normalized delta of the corresponding TSC timestamps by the result to calulate the TSC frequency. tscfreq = ((tstsc1 - tstsc2 ) * 1e6) / hpetref This uses do_div() which takes an u32 as the divisor, which worked so far because the HPET frequency was low enough that 'hpetref' never exceeded 32bit. On Skylake machines the HPET frequency increased so 'hpetref' can exceed 32bit. do_div() truncates the divisor, which causes the calibration to fail. Use div64_u64() to avoid the problem. [ tglx: Fixes whitespace mangled patch and rewrote changelog ] Signed-off-by: Xiaoming Gao Signed-off-by: Thomas Gleixner Cc: stable@vger.kernel.org Cc: peterz@infradead.org Cc: hpa@zytor.com Link: https://lkml.kernel.org/r/38894564-4fc9-b8ec-353f-de702839e44e@gmail.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/tsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index bbfb03eccb7f..da6a287a11e4 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -409,7 +409,7 @@ static unsigned long calc_hpet_ref(u64 deltatsc, u64 hpet1, u64 hpet2) hpet2 -= hpet1; tmp = ((u64)hpet2 * hpet_readl(HPET_PERIOD)); do_div(tmp, 1000000); - do_div(deltatsc, tmp); + deltatsc = div64_u64(deltatsc, tmp); return (unsigned long) deltatsc; } -- GitLab From 5ddab9f7be78b36ded2a7a93d45642dff46fd409 Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Mon, 2 Apr 2018 15:10:35 +0800 Subject: [PATCH 026/855] drm/vc4: Fix memory leak during BO teardown commit c0db1b677e1d584fab5d7ac76a32e1c0157542e0 upstream. During BO teardown, an indirect list 'uniform_addr_offsets' wasn't being freed leading to leaking many 128B allocations. Fix the memory leak by releasing it at teardown time. Cc: stable@vger.kernel.org Fixes: 6d45c81d229d ("drm/vc4: Add support for branching in shader validation.") Signed-off-by: Daniel J Blueman Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20180402071035.25356-1-daniel@quora.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vc4/vc4_bo.c | 2 ++ drivers/gpu/drm/vc4/vc4_validate_shaders.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index ec9023bd935b..d53e805d392f 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -80,6 +80,7 @@ static void vc4_bo_destroy(struct vc4_bo *bo) struct vc4_dev *vc4 = to_vc4_dev(obj->dev); if (bo->validated_shader) { + kfree(bo->validated_shader->uniform_addr_offsets); kfree(bo->validated_shader->texture_samples); kfree(bo->validated_shader); bo->validated_shader = NULL; @@ -328,6 +329,7 @@ void vc4_free_object(struct drm_gem_object *gem_bo) } if (bo->validated_shader) { + kfree(bo->validated_shader->uniform_addr_offsets); kfree(bo->validated_shader->texture_samples); kfree(bo->validated_shader); bo->validated_shader = NULL; diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c index 917321ce832f..19a5bde8e490 100644 --- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c +++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c @@ -874,6 +874,7 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) fail: kfree(validation_state.branch_targets); if (validated_shader) { + kfree(validated_shader->uniform_addr_offsets); kfree(validated_shader->texture_samples); kfree(validated_shader); } -- GitLab From 9c87602abe12b555e5176403dc7e8b4ddb8ace33 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 16 Apr 2018 18:53:09 +0300 Subject: [PATCH 027/855] drm/i915: Fix LSPCON TMDS output buffer enabling from low-power state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7eb2c4dd54ff841f2fe509a84973eb25fa20bda2 upstream. LSPCON adapters in low-power state may ignore the first I2C write during TMDS output buffer enabling, resulting in a blank screen even with an otherwise enabled pipe. Fix this by reading back and validating the written value a few times. The problem was noticed on GLK machines with an onboard LSPCON adapter after entering/exiting DC5 power state. Doing an I2C read of the adapter ID as the first transaction - instead of the I2C write to enable the TMDS buffers - returns the correct value. Based on this we assume that the transaction itself is sent properly, it's only the adapter that is not ready for some reason to accept this first write after waking from low-power state. In my case the second I2C write attempt always succeeded. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105854 Cc: Clinton Taylor Cc: Ville Syrjälä Cc: stable@vger.kernel.org Signed-off-by: Imre Deak Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180416155309.11100-1-imre.deak@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_dp_dual_mode_helper.c | 39 +++++++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_dual_mode_helper.c b/drivers/gpu/drm/drm_dp_dual_mode_helper.c index a7b2a751f6fe..cdb53586c8fe 100644 --- a/drivers/gpu/drm/drm_dp_dual_mode_helper.c +++ b/drivers/gpu/drm/drm_dp_dual_mode_helper.c @@ -322,19 +322,44 @@ int drm_dp_dual_mode_set_tmds_output(enum drm_dp_dual_mode_type type, { uint8_t tmds_oen = enable ? 0 : DP_DUAL_MODE_TMDS_DISABLE; ssize_t ret; + int retry; if (type < DRM_DP_DUAL_MODE_TYPE2_DVI) return 0; - ret = drm_dp_dual_mode_write(adapter, DP_DUAL_MODE_TMDS_OEN, - &tmds_oen, sizeof(tmds_oen)); - if (ret) { - DRM_DEBUG_KMS("Failed to %s TMDS output buffers\n", - enable ? "enable" : "disable"); - return ret; + /* + * LSPCON adapters in low-power state may ignore the first write, so + * read back and verify the written value a few times. + */ + for (retry = 0; retry < 3; retry++) { + uint8_t tmp; + + ret = drm_dp_dual_mode_write(adapter, DP_DUAL_MODE_TMDS_OEN, + &tmds_oen, sizeof(tmds_oen)); + if (ret) { + DRM_DEBUG_KMS("Failed to %s TMDS output buffers (%d attempts)\n", + enable ? "enable" : "disable", + retry + 1); + return ret; + } + + ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_TMDS_OEN, + &tmp, sizeof(tmp)); + if (ret) { + DRM_DEBUG_KMS("I2C read failed during TMDS output buffer %s (%d attempts)\n", + enable ? "enabling" : "disabling", + retry + 1); + return ret; + } + + if (tmp == tmds_oen) + return 0; } - return 0; + DRM_DEBUG_KMS("I2C write value mismatch during TMDS output buffer %s\n", + enable ? "enabling" : "disabling"); + + return -EIO; } EXPORT_SYMBOL(drm_dp_dual_mode_set_tmds_output); -- GitLab From fbd45e2957fbf7ed392deab29cd3050a1ab2562f Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 13 Oct 2016 14:10:35 +0200 Subject: [PATCH 028/855] i2c: i801: store and restore the SLVCMD register at load and unload commit 22e94bd6779e1140350c0792e85c79552ec43673 upstream. Also do not override any other configuration in this register. Signed-off-by: Benjamin Tissoires Signed-off-by: Wolfram Sang Cc: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-i801.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index e6fe21a6135b..e7c91494d1cd 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -243,6 +243,7 @@ struct i801_priv { struct i2c_adapter adapter; unsigned long smba; unsigned char original_hstcfg; + unsigned char original_slvcmd; struct pci_dev *pci_dev; unsigned int features; @@ -962,13 +963,26 @@ static int i801_enable_host_notify(struct i2c_adapter *adapter) if (!priv->host_notify) return -ENOMEM; - outb_p(SMBSLVCMD_HST_NTFY_INTREN, SMBSLVCMD(priv)); + priv->original_slvcmd = inb_p(SMBSLVCMD(priv)); + + if (!(SMBSLVCMD_HST_NTFY_INTREN & priv->original_slvcmd)) + outb_p(SMBSLVCMD_HST_NTFY_INTREN | priv->original_slvcmd, + SMBSLVCMD(priv)); + /* clear Host Notify bit to allow a new notification */ outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); return 0; } +static void i801_disable_host_notify(struct i801_priv *priv) +{ + if (!(priv->features & FEATURE_HOST_NOTIFY)) + return; + + outb_p(priv->original_slvcmd, SMBSLVCMD(priv)); +} + static const struct i2c_algorithm smbus_algorithm = { .smbus_xfer = i801_access, .functionality = i801_func, @@ -1666,6 +1680,7 @@ static void i801_remove(struct pci_dev *dev) pm_runtime_forbid(&dev->dev); pm_runtime_get_noresume(&dev->dev); + i801_disable_host_notify(priv); i801_del_mux(priv); i2c_del_adapter(&priv->adapter); i801_acpi_remove(priv); -- GitLab From 53defab7a561973cc3b815b87ce0ddbb9bc3ee18 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 11 Apr 2018 18:03:31 +0200 Subject: [PATCH 029/855] i2c: i801: Save register SMBSLVCMD value only once commit a086bb8317303dd74725dca933b9b29575159382 upstream. Saving the original value of register SMBSLVCMD in i801_enable_host_notify() doesn't work, because this function is called not only at probe time but also at resume time. Do it in i801_probe() instead, so that the saved value is not overwritten at resume time. Signed-off-by: Jean Delvare Fixes: 22e94bd6779e ("i2c: i801: store and restore the SLVCMD register at load and unload") Reviewed-by: Benjamin Tissoires Tested-by: Jason Andryuk Signed-off-by: Wolfram Sang Cc: stable@vger.kernel.org # v4.10+ Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-i801.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index e7c91494d1cd..fcffd60410eb 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -963,8 +963,6 @@ static int i801_enable_host_notify(struct i2c_adapter *adapter) if (!priv->host_notify) return -ENOMEM; - priv->original_slvcmd = inb_p(SMBSLVCMD(priv)); - if (!(SMBSLVCMD_HST_NTFY_INTREN & priv->original_slvcmd)) outb_p(SMBSLVCMD_HST_NTFY_INTREN | priv->original_slvcmd, SMBSLVCMD(priv)); @@ -1603,6 +1601,10 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) outb_p(inb_p(SMBAUXCTL(priv)) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); + /* Remember original Host Notify setting */ + if (priv->features & FEATURE_HOST_NOTIFY) + priv->original_slvcmd = inb_p(SMBSLVCMD(priv)); + /* Default timeout in interrupt mode: 200 ms */ priv->adapter.timeout = HZ / 5; -- GitLab From bd8505f3f3d408da000957452d119b97f6eb2bba Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 11 Apr 2018 18:05:34 +0200 Subject: [PATCH 030/855] i2c: i801: Restore configuration at shutdown commit f7f6d915a10f7f2bce17e3b1b7d3376562395a28 upstream. On some systems, the BIOS expects certain SMBus register values to match the hardware defaults. Restore these configuration registers at shutdown time to avoid confusing the BIOS. This avoids hard-locking such systems upon reboot. Signed-off-by: Jean Delvare Tested-by: Jason Andryuk Signed-off-by: Wolfram Sang Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-i801.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index fcffd60410eb..b32bf7eac3c8 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1696,6 +1696,15 @@ static void i801_remove(struct pci_dev *dev) */ } +static void i801_shutdown(struct pci_dev *dev) +{ + struct i801_priv *priv = pci_get_drvdata(dev); + + /* Restore config registers to avoid hard hang on some systems */ + i801_disable_host_notify(priv); + pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); +} + #ifdef CONFIG_PM static int i801_suspend(struct device *dev) { @@ -1728,6 +1737,7 @@ static struct pci_driver i801_driver = { .id_table = i801_ids, .probe = i801_probe, .remove = i801_remove, + .shutdown = i801_shutdown, .driver = { .pm = &i801_pm_ops, }, -- GitLab From c274101cd18bcf4d93941edc911b89fdb8065816 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Tue, 20 Feb 2018 07:30:10 -0600 Subject: [PATCH 031/855] usb: musb: fix enumeration after resume commit 17539f2f4f0b7fa906b508765c8ada07a1e45f52 upstream. On dm3730 there are enumeration problems after resume. Investigation led to the cause that the MUSB_POWER_SOFTCONN bit is not set. If it was set before suspend (because it was enabled via musb_pullup()), it is set in musb_restore_context() so the pullup is enabled. But then musb_start() is called which overwrites MUSB_POWER and therefore disables MUSB_POWER_SOFTCONN, so no pullup is enabled and the device is not enumerated. So let's do a subset of what musb_start() does in the same way as musb_suspend() does it. Platform-specific stuff it still called as there might be some phy-related stuff which needs to be enabled. Also interrupts are enabled, as it was the original idea of calling musb_start() in musb_resume() according to Commit 6fc6f4b87cb3 ("usb: musb: Disable interrupts on suspend, enable them on resume") Signed-off-by: Andreas Kemnade Tested-by: Tony Lindgren Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 2d9a8067eaca..0736cc27b5e7 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2710,7 +2710,8 @@ static int musb_resume(struct device *dev) if ((devctl & mask) != (musb->context.devctl & mask)) musb->port1_status = 0; - musb_start(musb); + musb_enable_interrupts(musb); + musb_platform_enable(musb); spin_lock_irqsave(&musb->lock, flags); error = musb_run_resume_work(musb); -- GitLab From 9e565114f4bc9459606dfc59d84df11fa6dc75a4 Mon Sep 17 00:00:00 2001 From: Merlijn Wajer Date: Mon, 5 Mar 2018 11:35:10 -0600 Subject: [PATCH 032/855] usb: musb: call pm_runtime_{get,put}_sync before reading vbus registers commit df6b074dbe248d8c43a82131e8fd429e401841a5 upstream. Without pm_runtime_{get,put}_sync calls in place, reading vbus status via /sys causes the following error: Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa0ab060 pgd = b333e822 [fa0ab060] *pgd=48011452(bad) [] (musb_default_readb) from [] (musb_vbus_show+0x58/0xe4) [] (musb_vbus_show) from [] (dev_attr_show+0x20/0x44) [] (dev_attr_show) from [] (sysfs_kf_seq_show+0x80/0xdc) [] (sysfs_kf_seq_show) from [] (seq_read+0x250/0x448) [] (seq_read) from [] (__vfs_read+0x1c/0x118) [] (__vfs_read) from [] (vfs_read+0x90/0x144) [] (vfs_read) from [] (SyS_read+0x3c/0x74) [] (SyS_read) from [] (ret_fast_syscall+0x0/0x54) Solution was suggested by Tony Lindgren . Signed-off-by: Merlijn Wajer Acked-by: Tony Lindgren Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 0736cc27b5e7..d4c9e9544ba0 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1774,6 +1774,7 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf) int vbus; u8 devctl; + pm_runtime_get_sync(dev); spin_lock_irqsave(&musb->lock, flags); val = musb->a_wait_bcon; vbus = musb_platform_get_vbus_status(musb); @@ -1787,6 +1788,7 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf) vbus = 0; } spin_unlock_irqrestore(&musb->lock, flags); + pm_runtime_put_sync(dev); return sprintf(buf, "Vbus %s, timeout %lu msec\n", vbus ? "on" : "off", val); -- GitLab From 4dcd6ce1dff4903a6f3a928962dd03b0a7ecef15 Mon Sep 17 00:00:00 2001 From: Merlijn Wajer Date: Tue, 13 Mar 2018 09:48:40 -0500 Subject: [PATCH 033/855] usb: musb: Fix external abort in musb_remove on omap2430 commit 94e46a4f2d5eb14059e42f313c098d4854847376 upstream. This fixes an oops on unbind / module unload (on the musb omap2430 platform). musb_remove function now calls musb_platform_exit before disabling runtime pm. Signed-off-by: Merlijn Wajer Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index d4c9e9544ba0..579aa9accafc 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2485,10 +2485,11 @@ static int musb_remove(struct platform_device *pdev) musb_generic_disable(musb); spin_unlock_irqrestore(&musb->lock, flags); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); + musb_platform_exit(musb); + pm_runtime_dont_use_autosuspend(musb->controller); pm_runtime_put_sync(musb->controller); pm_runtime_disable(musb->controller); - musb_platform_exit(musb); musb_phy_callback = NULL; if (musb->dma_controller) musb_dma_controller_destroy(musb->dma_controller); -- GitLab From 5955f16e49ecf3d9ab8ffe2c46756ba4c228ebb2 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Mon, 23 Jan 2017 14:08:13 +0000 Subject: [PATCH 034/855] MIPS: Generic: Fix big endian CPUs on generic machine commit a3078e593b74fe196e69f122f03ff0b32f652c53 upstream. Big endian CPUs require SWAP_IO_SPACE enabled to swap accesses to little endian peripherals. Without this patch, big endian kernels fail to communicate with little endian periperals, such as PCI devices, on QEMU and FPGA based platforms. Signed-off-by: Matt Redfearn Fixes: eed0eabd12ef ("MIPS: generic: Introduce generic DT-based board support") Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/15105/ Signed-off-by: Ralf Baechle Cc: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- arch/mips/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 2d2fd79ced9d..34fbbf8fdeaa 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -95,6 +95,7 @@ config MIPS_GENERIC select PCI_DRIVERS_GENERIC select PINCTRL select SMP_UP if SMP + select SWAP_IO_SPACE select SYS_HAS_CPU_MIPS32_R1 select SYS_HAS_CPU_MIPS32_R2 select SYS_HAS_CPU_MIPS32_R6 -- GitLab From 98b62bd6823dc7da57a940b84c5e16fd459dc50e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 10 Dec 2016 22:56:21 -0800 Subject: [PATCH 035/855] Input: drv260x - fix initializing overdrive voltage commit 74c82dae6c474933f2be401976e1530b5f623221 upstream. We were accidentally initializing haptics->rated_voltage twice, and did not initialize overdrive voltage. Acked-by: Dan Murphy Signed-off-by: Dmitry Torokhov Cc: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- drivers/input/misc/drv260x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index 930424e55439..251d64ca41ce 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -521,7 +521,7 @@ static int drv260x_probe(struct i2c_client *client, if (!haptics) return -ENOMEM; - haptics->rated_voltage = DRV260X_DEF_OD_CLAMP_VOLT; + haptics->overdrive_voltage = DRV260X_DEF_OD_CLAMP_VOLT; haptics->rated_voltage = DRV260X_DEF_RATED_VOLT; if (pdata) { -- GitLab From f9437fa5d27bd475017107a59a246c7eb4045b57 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 20 Jan 2017 13:25:06 +0000 Subject: [PATCH 036/855] power: supply: bq2415x: check for NULL acpi_id to avoid null pointer dereference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a1b94355ea3fde5e13db7ff37c0272fcde4e29b2 upstream. acpi_match_device can potentially return NULL, so it is prudent to check if acpi_id is null before it is dereferenced. Add a check and an error message to indicate the failure. Signed-off-by: Colin Ian King Reviewed-by: Pali Rohár Signed-off-by: Sebastian Reichel Cc: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- drivers/power/supply/bq2415x_charger.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/power/supply/bq2415x_charger.c b/drivers/power/supply/bq2415x_charger.c index 73e2f0b79dd4..c4770a94cc8e 100644 --- a/drivers/power/supply/bq2415x_charger.c +++ b/drivers/power/supply/bq2415x_charger.c @@ -1569,6 +1569,11 @@ static int bq2415x_probe(struct i2c_client *client, acpi_id = acpi_match_device(client->dev.driver->acpi_match_table, &client->dev); + if (!acpi_id) { + dev_err(&client->dev, "failed to match device name\n"); + ret = -ENODEV; + goto error_1; + } name = kasprintf(GFP_KERNEL, "%s-%d", acpi_id->id, num); } if (!name) { -- GitLab From d539f0aa5d1c07f312136363a020b7bde0d31094 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 16 Nov 2016 09:11:54 -0200 Subject: [PATCH 037/855] stk-webcam: fix an endian bug in stk_camera_read_reg() commit d08876f524a605d64c7ca32cb8e9f5be3839e82e upstream. We pass an int pointer to stk_camera_read_reg() but only write to the highest byte. It's a bug on big endian systems and generally a nasty thing to do and doesn't match the write function either. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab Cc: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/stkwebcam/stk-sensor.c | 6 +++--- drivers/media/usb/stkwebcam/stk-webcam.c | 11 ++++++----- drivers/media/usb/stkwebcam/stk-webcam.h | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/media/usb/stkwebcam/stk-sensor.c b/drivers/media/usb/stkwebcam/stk-sensor.c index e546b014d7ad..2dcc8d0be9e7 100644 --- a/drivers/media/usb/stkwebcam/stk-sensor.c +++ b/drivers/media/usb/stkwebcam/stk-sensor.c @@ -228,7 +228,7 @@ static int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val) { int i = 0; - int tmpval = 0; + u8 tmpval = 0; if (stk_camera_write_reg(dev, STK_IIC_TX_INDEX, reg)) return 1; @@ -253,7 +253,7 @@ static int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val) static int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val) { int i = 0; - int tmpval = 0; + u8 tmpval = 0; if (stk_camera_write_reg(dev, STK_IIC_RX_INDEX, reg)) return 1; @@ -274,7 +274,7 @@ static int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val) if (stk_camera_read_reg(dev, STK_IIC_RX_VALUE, &tmpval)) return 1; - *val = (u8) tmpval; + *val = tmpval; return 0; } diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 22a9aae16291..1c48f2f1e14a 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -144,7 +144,7 @@ int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value) return 0; } -int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value) +int stk_camera_read_reg(struct stk_camera *dev, u16 index, u8 *value) { struct usb_device *udev = dev->udev; unsigned char *buf; @@ -163,7 +163,7 @@ int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value) sizeof(u8), 500); if (ret >= 0) - memcpy(value, buf, sizeof(u8)); + *value = *buf; kfree(buf); return ret; @@ -171,9 +171,10 @@ int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value) static int stk_start_stream(struct stk_camera *dev) { - int value; + u8 value; int i, ret; - int value_116, value_117; + u8 value_116, value_117; + if (!is_present(dev)) return -ENODEV; @@ -213,7 +214,7 @@ static int stk_start_stream(struct stk_camera *dev) static int stk_stop_stream(struct stk_camera *dev) { - int value; + u8 value; int i; if (is_present(dev)) { stk_camera_read_reg(dev, 0x0100, &value); diff --git a/drivers/media/usb/stkwebcam/stk-webcam.h b/drivers/media/usb/stkwebcam/stk-webcam.h index 9bbfa3d9bfdd..92bb48e3c74e 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.h +++ b/drivers/media/usb/stkwebcam/stk-webcam.h @@ -129,7 +129,7 @@ struct stk_camera { #define vdev_to_camera(d) container_of(d, struct stk_camera, vdev) int stk_camera_write_reg(struct stk_camera *, u16, u8); -int stk_camera_read_reg(struct stk_camera *, u16, int *); +int stk_camera_read_reg(struct stk_camera *, u16, u8 *); int stk_sensor_init(struct stk_camera *); int stk_sensor_configure(struct stk_camera *); -- GitLab From faf6fd7539a104a6ad2d263090738ab46c1828c5 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 23 Sep 2016 16:38:27 +0100 Subject: [PATCH 038/855] OF: Prevent unaligned access in of_alias_scan() commit de96ec2a77c6d06a423c2c495bb4a2f4299f3d9e upstream. When allocating a struct alias_prop, of_alias_scan() only requested that it be aligned on a 4 byte boundary. The struct contains pointers which leads to us attempting 64 bit writes on 64 bit systems, and if the CPU doesn't support unaligned memory accesses then this causes problems - for example on some MIPS64r2 CPUs including the "mips64r2-generic" QEMU emulated CPU it will trigger an address error exception. Fix this by requesting alignment for the struct alias_prop allocation matching that which the compiler expects, using the __alignof__ keyword. Signed-off-by: Paul Burton Acked-by: Rob Herring Reviewed-by: Grant Likely Cc: Frank Rowand Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14306/ Signed-off-by: Ralf Baechle Cc: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- drivers/of/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index a0bccb54a9bd..466b285cef3e 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2109,7 +2109,7 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) continue; /* Allocate an alias_prop with enough space for the stem */ - ap = dt_alloc(sizeof(*ap) + len + 1, 4); + ap = dt_alloc(sizeof(*ap) + len + 1, __alignof__(*ap)); if (!ap) continue; memset(ap, 0, sizeof(*ap) + len + 1); -- GitLab From ff738afb8a847414f73b729cb25df624bd743089 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Feb 2017 10:14:51 +0100 Subject: [PATCH 039/855] ath9k_hw: check if the chip failed to wake up commit a34d0a0da1abae46a5f6ebd06fb0ec484ca099d9 upstream. In an RFC patch, Sven Eckelmann and Simon Wunderlich reported: "QCA 802.11n chips (especially AR9330/AR9340) sometimes end up in a state in which a read of AR_CFG always returns 0xdeadbeef. This should not happen when when the power_mode of the device is ATH9K_PM_AWAKE." Include the check for the default register state in the existing MAC hang check. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo Cc: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/hw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index a35f78be8dec..acef4ec928c1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1603,6 +1603,10 @@ bool ath9k_hw_check_alive(struct ath_hw *ah) int count = 50; u32 reg, last_val; + /* Check if chip failed to wake up */ + if (REG_READ(ah, AR_CFG) == 0xdeadbeef) + return false; + if (AR_SREV_9300(ah)) return !ath9k_hw_detect_mac_hang(ah); -- GitLab From cff3a5f282ff1813352a146c487f4d8b472c250e Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Wed, 1 Feb 2017 20:49:35 -0500 Subject: [PATCH 040/855] jbd2: fix use after free in kjournald2() commit dbfcef6b0f4012c57bc0b6e0e660d5ed12a5eaed upstream. Below is the synchronization issue between unmount and kjournald2 contexts, which results into use after free issue in kjournald2(). Fix this issue by using journal->j_state_lock to synchronize the wait_event() done in journal_kill_thread() and the wake_up() done in kjournald2(). TASK 1: umount cmd: |--jbd2_journal_destroy() { |--journal_kill_thread() { write_lock(&journal->j_state_lock); journal->j_flags |= JBD2_UNMOUNT; ... write_unlock(&journal->j_state_lock); wake_up(&journal->j_wait_commit); TASK 2 wakes up here: kjournald2() { ... checks JBD2_UNMOUNT flag and calls goto end-loop; ... end_loop: write_unlock(&journal->j_state_lock); journal->j_task = NULL; --> If this thread gets pre-empted here, then TASK 1 wait_event will exit even before this thread is completely done. wait_event(journal->j_wait_done_commit, journal->j_task == NULL); ... write_lock(&journal->j_state_lock); write_unlock(&journal->j_state_lock); } |--kfree(journal); } } wake_up(&journal->j_wait_done_commit); --> this step now results into use after free issue. } Signed-off-by: Sahitya Tummala Signed-off-by: Theodore Ts'o Cc: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/journal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 542e33d29088..d10bb2c30bf8 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -276,11 +276,11 @@ static int kjournald2(void *arg) goto loop; end_loop: - write_unlock(&journal->j_state_lock); del_timer_sync(&journal->j_commit_timer); journal->j_task = NULL; wake_up(&journal->j_wait_done_commit); jbd_debug(1, "Journal thread exiting.\n"); + write_unlock(&journal->j_state_lock); return 0; } -- GitLab From fdc2090bdadf829d5459570f4e908d47e6ec6a1c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 24 Apr 2018 15:08:40 +0200 Subject: [PATCH 041/855] Revert "perf tools: Decompress kernel module when reading DSO data" This reverts commit e2d054998b151e85b6305aa72264f67097bd78e9 which is commit 1d6b3c9ba756a5134fd7ad1959acac776d17404b upstream. It breaks the build, so obviously none of us actually tested it :( Reported-by: Maxime Hadjinlian Reported-by: Akemi Yagi Cc: Namhyung Kim Cc: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Peter Zijlstra Cc: Wang Nan Cc: kernel-team@lge.com Cc: Arnaldo Carvalho de Melo Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/dso.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 4bc58822416c..d2c6cdd9d42b 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -366,23 +366,7 @@ static int __open_dso(struct dso *dso, struct machine *machine) if (!is_regular_file(name)) return -EINVAL; - if (dso__needs_decompress(dso)) { - char newpath[KMOD_DECOMP_LEN]; - size_t len = sizeof(newpath); - - if (dso__decompress_kmodule_path(dso, name, newpath, len) < 0) { - free(name); - return -dso->load_errno; - } - - strcpy(name, newpath); - } - fd = do_open(name); - - if (dso__needs_decompress(dso)) - unlink(name); - free(name); return fd; } -- GitLab From ac6f0cb331e2ddc5d40b9059908218349064ec5c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 15 Apr 2018 11:23:51 +0200 Subject: [PATCH 042/855] perf: Fix sample_max_stack maximum check commit 5af44ca53d019de47efe6dbc4003dd518e5197ed upstream. The syzbot hit KASAN bug in perf_callchain_store having the entry stored behind the allocated bounds [1]. We miss the sample_max_stack check for the initial event that allocates callchain buffers. This missing check allows to create an event with sample_max_stack value bigger than the global sysctl maximum: # sysctl -a | grep perf_event_max_stack kernel.perf_event_max_stack = 127 # perf record -vv -C 1 -e cycles/max-stack=256/ kill ... perf_event_attr: size 112 ... sample_max_stack 256 ------------------------------------------------------------ sys_perf_event_open: pid -1 cpu 1 group_fd -1 flags 0x8 = 4 Note the '-C 1', which forces perf record to create just single event. Otherwise it opens event for every cpu, then the sample_max_stack check fails on the second event and all's fine. The fix is to run the sample_max_stack check also for the first event with callchains. [1] https://marc.info/?l=linux-kernel&m=152352732920874&w=2 Reported-by: syzbot+7c449856228b63ac951e@syzkaller.appspotmail.com Signed-off-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: H. Peter Anvin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: syzkaller-bugs@googlegroups.com Cc: x86@kernel.org Fixes: 97c79a38cd45 ("perf core: Per event callchain limit") Link: http://lkml.kernel.org/r/20180415092352.12403-2-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- kernel/events/callchain.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c index 411226b26bca..04988d6466bf 100644 --- a/kernel/events/callchain.c +++ b/kernel/events/callchain.c @@ -117,19 +117,22 @@ int get_callchain_buffers(int event_max_stack) goto exit; } + /* + * If requesting per event more than the global cap, + * return a different error to help userspace figure + * this out. + * + * And also do it here so that we have &callchain_mutex held. + */ + if (event_max_stack > sysctl_perf_event_max_stack) { + err = -EOVERFLOW; + goto exit; + } + if (count > 1) { /* If the allocation failed, give up */ if (!callchain_cpus_entries) err = -ENOMEM; - /* - * If requesting per event more than the global cap, - * return a different error to help userspace figure - * this out. - * - * And also do it here so that we have &callchain_mutex held. - */ - if (event_max_stack > sysctl_perf_event_max_stack) - err = -EOVERFLOW; goto exit; } -- GitLab From 9acdfe4eecf29d38fd7c7d342b120f430c950400 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 15 Apr 2018 11:23:50 +0200 Subject: [PATCH 043/855] perf: Return proper values for user stack errors commit 78b562fbfa2cf0a9fcb23c3154756b690f4905c1 upstream. Return immediately when we find issue in the user stack checks. The error value could get overwritten by following check for PERF_SAMPLE_REGS_INTR. Signed-off-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: H. Peter Anvin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: syzkaller-bugs@googlegroups.com Cc: x86@kernel.org Fixes: 60e2364e60e8 ("perf: Add ability to sample machine state on interrupt") Link: http://lkml.kernel.org/r/20180415092352.12403-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- kernel/events/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 74710fad35d5..b1d6b9888fba 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -9456,9 +9456,9 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr, * __u16 sample size limit. */ if (attr->sample_stack_user >= USHRT_MAX) - ret = -EINVAL; + return -EINVAL; else if (!IS_ALIGNED(attr->sample_stack_user, sizeof(u64))) - ret = -EINVAL; + return -EINVAL; } if (attr->sample_type & PERF_SAMPLE_REGS_INTR) -- GitLab From 9ffa6fb2583b2c9afdb83c14948a9e3e2192bf1f Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Sun, 11 Mar 2018 13:51:32 +0200 Subject: [PATCH 044/855] RDMA/mlx5: Fix NULL dereference while accessing XRC_TGT QPs commit 75a4598209cbe45540baa316c3b51d9db222e96e upstream. mlx5 modify_qp() relies on FW that the error will be thrown if wrong state is supplied. The missing check in FW causes the following crash while using XRC_TGT QPs. [ 14.769632] BUG: unable to handle kernel NULL pointer dereference at (null) [ 14.771085] IP: mlx5_ib_modify_qp+0xf60/0x13f0 [ 14.771894] PGD 800000001472e067 P4D 800000001472e067 PUD 14529067 PMD 0 [ 14.773126] Oops: 0002 [#1] SMP PTI [ 14.773763] CPU: 0 PID: 365 Comm: ubsan Not tainted 4.16.0-rc1-00038-g8151138c0793 #119 [ 14.775192] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 [ 14.777522] RIP: 0010:mlx5_ib_modify_qp+0xf60/0x13f0 [ 14.778417] RSP: 0018:ffffbf48001c7bd8 EFLAGS: 00010246 [ 14.779346] RAX: 0000000000000000 RBX: ffff9a8f9447d400 RCX: 0000000000000000 [ 14.780643] RDX: 0000000000000000 RSI: 000000000000000a RDI: 0000000000000000 [ 14.781930] RBP: 0000000000000000 R08: 00000000000217b0 R09: ffffffffbc9c1504 [ 14.783214] R10: fffff4a180519480 R11: ffff9a8f94523600 R12: ffff9a8f9493e240 [ 14.784507] R13: ffff9a8f9447d738 R14: 000000000000050a R15: 0000000000000000 [ 14.785800] FS: 00007f545b466700(0000) GS:ffff9a8f9fc00000(0000) knlGS:0000000000000000 [ 14.787073] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 14.787792] CR2: 0000000000000000 CR3: 00000000144be000 CR4: 00000000000006b0 [ 14.788689] Call Trace: [ 14.789007] _ib_modify_qp+0x71/0x120 [ 14.789475] modify_qp.isra.20+0x207/0x2f0 [ 14.790010] ib_uverbs_modify_qp+0x90/0xe0 [ 14.790532] ib_uverbs_write+0x1d2/0x3c0 [ 14.791049] ? __handle_mm_fault+0x93c/0xe40 [ 14.791644] __vfs_write+0x36/0x180 [ 14.792096] ? handle_mm_fault+0xc1/0x210 [ 14.792601] vfs_write+0xad/0x1e0 [ 14.793018] SyS_write+0x52/0xc0 [ 14.793422] do_syscall_64+0x75/0x180 [ 14.793888] entry_SYSCALL_64_after_hwframe+0x21/0x86 [ 14.794527] RIP: 0033:0x7f545ad76099 [ 14.794975] RSP: 002b:00007ffd78787468 EFLAGS: 00000287 ORIG_RAX: 0000000000000001 [ 14.795958] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f545ad76099 [ 14.797075] RDX: 0000000000000078 RSI: 0000000020009000 RDI: 0000000000000003 [ 14.798140] RBP: 00007ffd78787470 R08: 00007ffd78787480 R09: 00007ffd78787480 [ 14.799207] R10: 00007ffd78787480 R11: 0000000000000287 R12: 00005599ada98760 [ 14.800277] R13: 00007ffd78787560 R14: 0000000000000000 R15: 0000000000000000 [ 14.801341] Code: 4c 8b 1c 24 48 8b 83 70 02 00 00 48 c7 83 cc 02 00 00 00 00 00 00 48 c7 83 24 03 00 00 00 00 00 00 c7 83 2c 03 00 00 00 00 00 00 00 00 00 00 00 48 8b 83 70 02 00 00 c7 40 04 00 00 00 00 4c [ 14.804012] RIP: mlx5_ib_modify_qp+0xf60/0x13f0 RSP: ffffbf48001c7bd8 [ 14.804838] CR2: 0000000000000000 [ 14.805288] ---[ end trace 3f1da0df5c8b7c37 ]--- Cc: syzkaller Reported-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/qp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 403df3591d29..5b8909d1b55e 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -2848,7 +2848,8 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, * If we moved a kernel QP to RESET, clean up all old CQ * entries and reinitialize the QP. */ - if (new_state == IB_QPS_RESET && !ibqp->uobject) { + if (new_state == IB_QPS_RESET && + !ibqp->uobject && ibqp->qp_type != IB_QPT_XRC_TGT) { mlx5_ib_cq_clean(recv_cq, base->mqp.qpn, ibqp->srq ? to_msrq(ibqp->srq) : NULL); if (send_cq != recv_cq) -- GitLab From 2d1264b5e665909a3217a16c362802c14ee807c0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 30 Jan 2018 16:29:38 +0200 Subject: [PATCH 045/855] drm/i915/bxt, glk: Increase PCODE timeouts during CDCLK freq changing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5e1df40f40ee45a97bb1066c3d71f0ae920a9672 upstream. Currently we see sporadic timeouts during CDCLK changing both on BXT and GLK as reported by the Bugzilla: ticket. It's easy to reproduce this by changing the frequency in a tight loop after blanking the display. The upper bound for the completion time is 800us based on my tests, so increase it from the current 500us to 2ms; with that I couldn't trigger the problem either on BXT or GLK. Note that timeouts happened during both the change notification and the voltage level setting PCODE request. (For the latter one BSpec doesn't require us to wait for completion before further HW programming.) This issue is similar to commit 2c7d0602c815 ("drm/i915/gen9: Fix PCODE polling during CDCLK change notification") but there the PCODE request does complete (as shown by the mbox busy flag), only the reply we get from PCODE indicates a failure. So there we keep resending the request until a success reply, here we just have to increase the timeout for the one PCODE request we send. v2: - s/snb_pcode_request/sandybridge_pcode_write_timeout/ (Ville) Cc: Chris Wilson Cc: Ville Syrjälä Cc: # v4.9 Acked-by: Chris Wilson (v1) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103326 Reviewed-by: Ville Syrjälä Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20180130142939.17983-1-imre.deak@intel.com (cherry picked from commit e76019a81921e87a4d9e7b3d86102bc708a6c227) Signed-off-by: Rodrigo Vivi (Rebased for v4.9 stable tree due to upstream intel_cdclk.c, cdclk_state and pcu_lock change) Signed-off-by: Imre Deak Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_drv.h | 6 +++++- drivers/gpu/drm/i915/intel_display.c | 9 +++++---- drivers/gpu/drm/i915/intel_pm.c | 6 +++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 36a665f0e5c9..e23748cca0c0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3681,7 +3681,11 @@ extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e, struct intel_display_error_state *error); int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val); -int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u32 mbox, u32 val); +int sandybridge_pcode_write_timeout(struct drm_i915_private *dev_priv, u32 mbox, + u32 val, int timeout_us); +#define sandybridge_pcode_write(dev_priv, mbox, val) \ + sandybridge_pcode_write_timeout(dev_priv, mbox, val, 500) + int skl_pcode_request(struct drm_i915_private *dev_priv, u32 mbox, u32 request, u32 reply_mask, u32 reply, int timeout_base_ms); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ce32303b3013..c185625d67f2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6012,8 +6012,8 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, int cdclk) /* Inform power controller of upcoming frequency change */ mutex_lock(&dev_priv->rps.hw_lock); - ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, - 0x80000000); + ret = sandybridge_pcode_write_timeout(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, + 0x80000000, 2000); mutex_unlock(&dev_priv->rps.hw_lock); if (ret) { @@ -6044,8 +6044,9 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, int cdclk) I915_WRITE(CDCLK_CTL, val); mutex_lock(&dev_priv->rps.hw_lock); - ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, - DIV_ROUND_UP(cdclk, 25000)); + ret = sandybridge_pcode_write_timeout(dev_priv, + HSW_PCODE_DE_WRITE_FREQ_REQ, + DIV_ROUND_UP(cdclk, 25000), 2000); mutex_unlock(&dev_priv->rps.hw_lock); if (ret) { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 49de4760cc16..05427d292457 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -7913,8 +7913,8 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val return 0; } -int sandybridge_pcode_write(struct drm_i915_private *dev_priv, - u32 mbox, u32 val) +int sandybridge_pcode_write_timeout(struct drm_i915_private *dev_priv, + u32 mbox, u32 val, int timeout_us) { int status; @@ -7935,7 +7935,7 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, if (intel_wait_for_register_fw(dev_priv, GEN6_PCODE_MAILBOX, GEN6_PCODE_READY, 0, - 500)) { + timeout_us)) { DRM_ERROR("timeout waiting for pcode write (%d) to finish\n", mbox); return -ETIMEDOUT; } -- GitLab From 21670a464c6b05d92d24e64332e4c57b984d8701 Mon Sep 17 00:00:00 2001 From: Benjamin Beichler Date: Wed, 7 Mar 2018 18:11:07 +0100 Subject: [PATCH 046/855] mac80211_hwsim: fix use-after-free bug in hwsim_exit_net commit 8cfd36a0b53aeb4ec21d81eb79706697b84dfc3d upstream. When destroying a net namespace, all hwsim interfaces, which are not created in default namespace are deleted. But the async deletion of the interfaces could last longer than the actual destruction of the namespace, which results to an use after free bug. Therefore use synchronous deletion in this case. Fixes: 100cb9ff40e0 ("mac80211_hwsim: Allow managing radios from non-initial namespaces") Reported-by: syzbot+70ce058e01259de7bb1d@syzkaller.appspotmail.com Signed-off-by: Benjamin Beichler Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mac80211_hwsim.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 4182c3775a72..2681b5339810 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3346,8 +3346,11 @@ static void __net_exit hwsim_exit_net(struct net *net) continue; list_del(&data->list); - INIT_WORK(&data->destroy_work, destroy_radio); - schedule_work(&data->destroy_work); + spin_unlock_bh(&hwsim_radio_lock); + mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), + NULL); + spin_lock_bh(&hwsim_radio_lock); + } spin_unlock_bh(&hwsim_radio_lock); } -- GitLab From 403e7bd6ed4aa2515b05b6f5942a8bbad322d3e8 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Thu, 28 Sep 2017 11:35:00 -0700 Subject: [PATCH 047/855] r8152: add Linksys USB3GIGV1 id commit 90841047a01b452cc8c3f9b990698b264143334a upstream. This linksys dongle by default comes up in cdc_ether mode. This patch allows r8152 to claim the device: Bus 002 Device 002: ID 13b1:0041 Linksys Signed-off-by: Grant Grundler Reviewed-by: Douglas Anderson Signed-off-by: David S. Miller [krzk: Rebase on v4.4] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/cdc_ether.c | 10 ++++++++++ drivers/net/usb/r8152.c | 2 ++ 2 files changed, 12 insertions(+) diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 4fb468666b19..99424c87b464 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -530,6 +530,7 @@ static const struct driver_info wwan_info = { #define REALTEK_VENDOR_ID 0x0bda #define SAMSUNG_VENDOR_ID 0x04e8 #define LENOVO_VENDOR_ID 0x17ef +#define LINKSYS_VENDOR_ID 0x13b1 #define NVIDIA_VENDOR_ID 0x0955 #define HP_VENDOR_ID 0x03f0 @@ -719,6 +720,15 @@ static const struct usb_device_id products[] = { .driver_info = 0, }, +#if IS_ENABLED(CONFIG_USB_RTL8152) +/* Linksys USB3GIGV1 Ethernet Adapter */ +{ + USB_DEVICE_AND_INTERFACE_INFO(LINKSYS_VENDOR_ID, 0x0041, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), + .driver_info = 0, +}, +#endif + /* Lenovo Thinkpad USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */ { USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x7205, USB_CLASS_COMM, diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index b2d7c7e32250..3cdfa2465e3f 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -519,6 +519,7 @@ enum rtl8152_flags { #define VENDOR_ID_REALTEK 0x0bda #define VENDOR_ID_SAMSUNG 0x04e8 #define VENDOR_ID_LENOVO 0x17ef +#define VENDOR_ID_LINKSYS 0x13b1 #define VENDOR_ID_NVIDIA 0x0955 #define MCU_TYPE_PLA 0x0100 @@ -4506,6 +4507,7 @@ static struct usb_device_id rtl8152_table[] = { {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)}, {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7205)}, {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f)}, + {REALTEK_USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041)}, {REALTEK_USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff)}, {} }; -- GitLab From b5145685a8bbe0756e5ab8440b5012d74c0daf5b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 26 Apr 2018 17:28:00 +0200 Subject: [PATCH 048/855] Revert "pinctrl: intel: Initialize GPIO properly when used through irqchip" This reverts commit f5a26acf0162477af6ee4c11b4fb9cffe5d3e257 Mike writes: It seems that commit f5a26acf0162 ("pinctrl: intel: Initialize GPIO properly when used through irqchip") can cause problems on some Skylake systems with Sunrisepoint PCH-H. Namely on certain systems it may turn the backlight PWM pin from native mode to GPIO which makes the screen blank during boot. There is more information here: https://bugzilla.redhat.com/show_bug.cgi?id=1543769 The actual reason is that GPIO numbering used in BIOS is using "Windows" numbers meaning that they don't match the hardware 1:1 and because of this a wrong pin (backlight PWM) is picked and switched to GPIO mode. There is a proper fix for this but since it has quite many dependencies on commits that cannot be considered stable material, I suggest we revert commit f5a26acf0162 from stable trees 4.9, 4.14 and 4.15 to prevent the backlight issue. Reported-by: Mika Westerberg Fixes: f5a26acf0162 ("pinctrl: intel: Initialize GPIO properly when used through irqchip") Cc: Daniel Drake Cc: Chris Chiu Cc: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/intel/pinctrl-intel.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index df63b7d997e8..b40a074822cf 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -368,18 +368,6 @@ static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input) writel(value, padcfg0); } -static void intel_gpio_set_gpio_mode(void __iomem *padcfg0) -{ - u32 value; - - /* Put the pad into GPIO mode */ - value = readl(padcfg0) & ~PADCFG0_PMODE_MASK; - /* Disable SCI/SMI/NMI generation */ - value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI); - value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI); - writel(value, padcfg0); -} - static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned pin) @@ -387,6 +375,7 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); void __iomem *padcfg0; unsigned long flags; + u32 value; raw_spin_lock_irqsave(&pctrl->lock, flags); @@ -396,7 +385,13 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, } padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); - intel_gpio_set_gpio_mode(padcfg0); + /* Put the pad into GPIO mode */ + value = readl(padcfg0) & ~PADCFG0_PMODE_MASK; + /* Disable SCI/SMI/NMI generation */ + value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI); + value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI); + writel(value, padcfg0); + /* Disable TX buffer and enable RX (this will be input) */ __intel_gpio_set_direction(padcfg0, true); @@ -775,8 +770,6 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type) raw_spin_lock_irqsave(&pctrl->lock, flags); - intel_gpio_set_gpio_mode(reg); - value = readl(reg); value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV); -- GitLab From 237b5a362399bdd81422ef9f9ac9b9f034161efd Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 27 Mar 2018 11:25:29 +0300 Subject: [PATCH 049/855] Revert "ath10k: send (re)assoc peer command when NSS changed" commit 55cc11da69895a680940c1733caabc37be685f5e upstream. This reverts commit 55884c045d31a29cf69db8332d1064a1b61dd159. When Ath10k is in AP mode and an unassociated STA sends a VHT action frame (Operating Mode Notification for the NSS change) periodically to AP this causes ath10k to call ath10k_station_assoc() which sends WMI_PEER_ASSOC_CMDID during NSS update. Over the time (with a certain client it can happen within 15 mins when there are over 500 of these VHT action frames) continuous calls of WMI_PEER_ASSOC_CMDID cause firmware to assert due to resource exhaust. To my knowledge setting WMI_PEER_NSS peer param itself enough to handle NSS updates and no need to call ath10k_station_assoc(). So revert the original commit from 2014 as it's unclear why the change was really needed. Now the firmware assert doesn't happen anymore. Issue observed in QCA9984 platform with firmware version:10.4-3.5.3-00053. This Change tested in QCA9984 with firmware version: 10.4-3.5.3-00053 and QCA988x platform with firmware version: 10.2.4-1.0-00036. Firmware Assert log: ath10k_pci 0002:01:00.0: firmware crashed! (guid e61f1274-9acd-4c5b-bcca-e032ea6e723c) ath10k_pci 0002:01:00.0: qca9984/qca9994 hw1.0 target 0x01000000 chip_id 0x00000000 sub 168c:cafe ath10k_pci 0002:01:00.0: kconfig debug 1 debugfs 1 tracing 0 dfs 1 testmode 1 ath10k_pci 0002:01:00.0: firmware ver 10.4-3.5.3-00053 api 5 features no-p2p,mfp,peer-flow-ctrl,btcoex-param,allows-mesh-bcast crc32 4c56a386 ath10k_pci 0002:01:00.0: board_file api 2 bmi_id 0:4 crc32 c2271344 ath10k_pci 0002:01:00.0: htt-ver 2.2 wmi-op 6 htt-op 4 cal otp max-sta 512 raw 0 hwcrypto 1 ath10k_pci 0002:01:00.0: firmware register dump: ath10k_pci 0002:01:00.0: [00]: 0x0000000A 0x000015B3 0x00981E5F 0x00975B31 ath10k_pci 0002:01:00.0: [04]: 0x00981E5F 0x00060530 0x00000011 0x00446C60 ath10k_pci 0002:01:00.0: [08]: 0x0042F1FC 0x00458080 0x00000017 0x00000000 ath10k_pci 0002:01:00.0: [12]: 0x00000009 0x00000000 0x00973ABC 0x00973AD2 ath10k_pci 0002:01:00.0: [16]: 0x00973AB0 0x00960E62 0x009606CA 0x00000000 ath10k_pci 0002:01:00.0: [20]: 0x40981E5F 0x004066DC 0x00400000 0x00981E34 ath10k_pci 0002:01:00.0: [24]: 0x80983B48 0x0040673C 0x000000C0 0xC0981E5F ath10k_pci 0002:01:00.0: [28]: 0x80993DEB 0x0040676C 0x00431AB8 0x0045D0C4 ath10k_pci 0002:01:00.0: [32]: 0x80993E5C 0x004067AC 0x004303C0 0x0045D0C4 ath10k_pci 0002:01:00.0: [36]: 0x80994AAB 0x004067DC 0x00000000 0x0045D0C4 ath10k_pci 0002:01:00.0: [40]: 0x809971A0 0x0040681C 0x004303C0 0x00441B00 ath10k_pci 0002:01:00.0: [44]: 0x80991904 0x0040688C 0x004303C0 0x0045D0C4 ath10k_pci 0002:01:00.0: [48]: 0x80963AD3 0x00406A7C 0x004303C0 0x009918FC ath10k_pci 0002:01:00.0: [52]: 0x80960E80 0x00406A9C 0x0000001F 0x00400000 ath10k_pci 0002:01:00.0: [56]: 0x80960E51 0x00406ACC 0x00400000 0x00000000 ath10k_pci 0002:01:00.0: Copy Engine register dump: ath10k_pci 0002:01:00.0: index: addr: sr_wr_idx: sr_r_idx: dst_wr_idx: dst_r_idx: ath10k_pci 0002:01:00.0: [00]: 0x0004a000 15 15 3 3 ath10k_pci 0002:01:00.0: [01]: 0x0004a400 17 17 212 213 ath10k_pci 0002:01:00.0: [02]: 0x0004a800 21 21 20 21 ath10k_pci 0002:01:00.0: [03]: 0x0004ac00 25 25 27 25 ath10k_pci 0002:01:00.0: [04]: 0x0004b000 515 515 144 104 ath10k_pci 0002:01:00.0: [05]: 0x0004b400 28 28 155 156 ath10k_pci 0002:01:00.0: [06]: 0x0004b800 12 12 12 12 ath10k_pci 0002:01:00.0: [07]: 0x0004bc00 1 1 1 1 ath10k_pci 0002:01:00.0: [08]: 0x0004c000 0 0 127 0 ath10k_pci 0002:01:00.0: [09]: 0x0004c400 1 1 1 1 ath10k_pci 0002:01:00.0: [10]: 0x0004c800 0 0 0 0 ath10k_pci 0002:01:00.0: [11]: 0x0004cc00 0 0 0 0 ath10k_pci 0002:01:00.0: CE[1] write_index 212 sw_index 213 hw_index 0 nentries_mask 0x000001ff ath10k_pci 0002:01:00.0: CE[2] write_index 20 sw_index 21 hw_index 0 nentries_mask 0x0000007f ath10k_pci 0002:01:00.0: CE[5] write_index 155 sw_index 156 hw_index 0 nentries_mask 0x000001ff ath10k_pci 0002:01:00.0: DMA addr: nbytes: meta data: byte swap: gather: ath10k_pci 0002:01:00.0: [455]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [456]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [457]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [458]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [459]: 0x580c0a42 0 0 0 0 ath10k_pci 0002:01:00.0: [460]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [461]: 0x580c0c42 0 0 0 0 ath10k_pci 0002:01:00.0: [462]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [463]: 0x580c0c42 0 0 0 0 ath10k_pci 0002:01:00.0: [464]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [465]: 0x580c0a42 0 0 0 0 ath10k_pci 0002:01:00.0: [466]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [467]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [468]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [469]: 0x580c1c42 0 0 0 0 ath10k_pci 0002:01:00.0: [470]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [471]: 0x580c1c42 0 0 0 0 ath10k_pci 0002:01:00.0: [472]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [473]: 0x580c1c42 0 0 0 0 ath10k_pci 0002:01:00.0: [474]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [475]: 0x580c0642 0 0 0 0 ath10k_pci 0002:01:00.0: [476]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [477]: 0x580c0842 0 0 0 0 ath10k_pci 0002:01:00.0: [478]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [479]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [480]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [481]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [482]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [483]: 0x580c0842 0 0 0 0 ath10k_pci 0002:01:00.0: [484]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [485]: 0x580c0642 0 0 0 0 ath10k_pci 0002:01:00.0: [486]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [487]: 0x580c0642 0 0 0 0 ath10k_pci 0002:01:00.0: [488]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [489]: 0x580c0842 0 0 0 0 ath10k_pci 0002:01:00.0: [490]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [491]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [492]: 0x58174040 0 1 0 0 ath10k_pci 0002:01:00.0: [493]: 0x5a946040 0 1 0 0 ath10k_pci 0002:01:00.0: [494]: 0x59909040 0 1 0 0 ath10k_pci 0002:01:00.0: [495]: 0x5ae5a040 0 1 0 0 ath10k_pci 0002:01:00.0: [496]: 0x58096040 0 1 0 0 ath10k_pci 0002:01:00.0: [497]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [498]: 0x580c0642 0 0 0 0 ath10k_pci 0002:01:00.0: [499]: 0x5c1e0040 0 1 0 0 ath10k_pci 0002:01:00.0: [500]: 0x58153040 0 1 0 0 ath10k_pci 0002:01:00.0: [501]: 0x58129040 0 1 0 0 ath10k_pci 0002:01:00.0: [502]: 0x5952f040 0 1 0 0 ath10k_pci 0002:01:00.0: [503]: 0x59535040 0 1 0 0 ath10k_pci 0002:01:00.0: [504]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [505]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [506]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [507]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [508]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [509]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [510]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [511]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [512]: 0x5adcc040 0 1 0 0 ath10k_pci 0002:01:00.0: [513]: 0x5cf3d040 0 1 0 0 ath10k_pci 0002:01:00.0: [514]: 0x5c1e9040 64 1 0 0 ath10k_pci 0002:01:00.0: [515]: 0x00000000 0 0 0 0 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Cc: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath10k/mac.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a497bf31953d..5aa5df24f4dc 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5819,9 +5819,8 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, smps, err); } - if (changed & IEEE80211_RC_SUPP_RATES_CHANGED || - changed & IEEE80211_RC_NSS_CHANGED) { - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n", + if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", sta->addr); err = ath10k_station_assoc(ar, arvif->vif, sta, true); -- GitLab From c8b1584e5e37fdbf654113a746076d37e9a93206 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Tue, 29 Aug 2017 14:45:45 -0500 Subject: [PATCH 050/855] PCI: Wait up to 60 seconds for device to become ready after FLR commit 821cdad5c46cae94ce65b9a98614c70a6ff021f8 upstream. Sporadic reset issues have been observed with an Intel 750 NVMe drive while assigning the physical function to the guest machine. The sequence of events observed is as follows: - perform a Function Level Reset (FLR) - sleep up to 1000ms total - read ~0 from PCI_COMMAND (CRS completion for config read) - warn that the device didn't return from FLR - touch the device before it's ready - device drops config writes when we restore register settings (there's no mechanism for software to learn about CRS completions for writes) - incomplete register restore leaves device in inconsistent state - device probe fails because device is in inconsistent state After reset, an endpoint may respond to config requests with Configuration Request Retry Status (CRS) to indicate that it is not ready to accept new requests. See PCIe r3.1, sec 2.3.1 and 6.6.2. Increase the timeout value from 1 second to 60 seconds to cover the period where device responds with CRS and also report polling progress. Signed-off-by: Sinan Kaya [bhelgaas: include the mandatory 100ms in the delays we print] Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci.c | 52 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a87c8e1aef68..9c13aeeeb973 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3756,27 +3756,49 @@ int pci_wait_for_pending_transaction(struct pci_dev *dev) } EXPORT_SYMBOL(pci_wait_for_pending_transaction); -/* - * We should only need to wait 100ms after FLR, but some devices take longer. - * Wait for up to 1000ms for config space to return something other than -1. - * Intel IGD requires this when an LCD panel is attached. We read the 2nd - * dword because VFs don't implement the 1st dword. - */ static void pci_flr_wait(struct pci_dev *dev) { - int i = 0; + int delay = 1, timeout = 60000; u32 id; - do { - msleep(100); + /* + * Per PCIe r3.1, sec 6.6.2, a device must complete an FLR within + * 100ms, but may silently discard requests while the FLR is in + * progress. Wait 100ms before trying to access the device. + */ + msleep(100); + + /* + * After 100ms, the device should not silently discard config + * requests, but it may still indicate that it needs more time by + * responding to them with CRS completions. The Root Port will + * generally synthesize ~0 data to complete the read (except when + * CRS SV is enabled and the read was for the Vendor ID; in that + * case it synthesizes 0x0001 data). + * + * Wait for the device to return a non-CRS completion. Read the + * Command register instead of Vendor ID so we don't have to + * contend with the CRS SV value. + */ + pci_read_config_dword(dev, PCI_COMMAND, &id); + while (id == ~0) { + if (delay > timeout) { + dev_warn(&dev->dev, "not ready %dms after FLR; giving up\n", + 100 + delay - 1); + return; + } + + if (delay > 1000) + dev_info(&dev->dev, "not ready %dms after FLR; waiting\n", + 100 + delay - 1); + + msleep(delay); + delay *= 2; pci_read_config_dword(dev, PCI_COMMAND, &id); - } while (i++ < 10 && id == ~0); + } - if (id == ~0) - dev_warn(&dev->dev, "Failed to return from FLR\n"); - else if (i > 1) - dev_info(&dev->dev, "Required additional %dms to return from FLR\n", - (i - 1) * 100); + if (delay > 1000) + dev_info(&dev->dev, "ready %dms after FLR\n", 100 + delay - 1); } static int pcie_flr(struct pci_dev *dev, int probe) -- GitLab From d69aa5e682c3ada69902936e6b7d8cd18827297a Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Fri, 27 Apr 2018 07:36:39 +0200 Subject: [PATCH 051/855] s390: introduce CPU alternatives [ Upstream commit 686140a1a9c41d85a4212a1c26d671139b76404b ] Implement CPU alternatives, which allows to optionally patch newer instructions at runtime, based on CPU facilities availability. A new kernel boot parameter "noaltinstr" disables patching. Current implementation is derived from x86 alternatives. Although ideal instructions padding (when altinstr is longer then oldinstr) is added at compile time, and no oldinstr nops optimization has to be done at runtime. Also couple of compile time sanity checks are done: 1. oldinstr and altinstr must be <= 254 bytes long, 2. oldinstr and altinstr must not have an odd length. alternative(oldinstr, altinstr, facility); alternative_2(oldinstr, altinstr1, facility1, altinstr2, facility2); Both compile time and runtime padding consists of either 6/4/2 bytes nop or a jump (brcl) + 2 bytes nop filler if padding is longer then 6 bytes. .altinstructions and .altinstr_replacement sections are part of __init_begin : __init_end region and are freed after initialization. Signed-off-by: Vasily Gorbik Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 3 + arch/s390/Kconfig | 17 +++ arch/s390/include/asm/alternative.h | 163 ++++++++++++++++++++++++++++ arch/s390/kernel/Makefile | 1 + arch/s390/kernel/alternative.c | 110 +++++++++++++++++++ arch/s390/kernel/module.c | 17 +++ arch/s390/kernel/setup.c | 3 + arch/s390/kernel/vmlinux.lds.S | 23 ++++ 8 files changed, 337 insertions(+) create mode 100644 arch/s390/include/asm/alternative.h create mode 100644 arch/s390/kernel/alternative.c diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 466c039c622b..5f9e51436a99 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2640,6 +2640,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. noalign [KNL,ARM] + noaltinstr [S390] Disables alternative instructions patching + (CPU alternatives feature). + noapic [SMP,APIC] Tells the kernel to not make use of any IOAPICs that may be present in the system. diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 9aa0d04c9dcc..f3e43262db9d 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -704,6 +704,22 @@ config SECCOMP If unsure, say Y. +config ALTERNATIVES + def_bool y + prompt "Patch optimized instructions for running CPU type" + help + When enabled the kernel code is compiled with additional + alternative instructions blocks optimized for newer CPU types. + These alternative instructions blocks are patched at kernel boot + time when running CPU supports them. This mechanism is used to + optimize some critical code paths (i.e. spinlocks) for newer CPUs + even if kernel is build to support older machine generations. + + This mechanism could be disabled by appending "noaltinstr" + option to the kernel command line. + + If unsure, say Y. + endmenu menu "Power Management" @@ -753,6 +769,7 @@ config PFAULT config SHARED_KERNEL bool "VM shared kernel support" depends on !JUMP_LABEL + depends on !ALTERNATIVES help Select this option, if you want to share the text segment of the Linux kernel between different VM guests. This reduces memory diff --git a/arch/s390/include/asm/alternative.h b/arch/s390/include/asm/alternative.h new file mode 100644 index 000000000000..6c268f6a51d3 --- /dev/null +++ b/arch/s390/include/asm/alternative.h @@ -0,0 +1,163 @@ +#ifndef _ASM_S390_ALTERNATIVE_H +#define _ASM_S390_ALTERNATIVE_H + +#ifndef __ASSEMBLY__ + +#include +#include +#include + +struct alt_instr { + s32 instr_offset; /* original instruction */ + s32 repl_offset; /* offset to replacement instruction */ + u16 facility; /* facility bit set for replacement */ + u8 instrlen; /* length of original instruction */ + u8 replacementlen; /* length of new instruction */ +} __packed; + +#ifdef CONFIG_ALTERNATIVES +extern void apply_alternative_instructions(void); +extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end); +#else +static inline void apply_alternative_instructions(void) {}; +static inline void apply_alternatives(struct alt_instr *start, + struct alt_instr *end) {}; +#endif +/* + * |661: |662: |6620 |663: + * +-----------+---------------------+ + * | oldinstr | oldinstr_padding | + * | +----------+----------+ + * | | | | + * | | >6 bytes |6/4/2 nops| + * | |6 bytes jg-----------> + * +-----------+---------------------+ + * ^^ static padding ^^ + * + * .altinstr_replacement section + * +---------------------+-----------+ + * |6641: |6651: + * | alternative instr 1 | + * +-----------+---------+- - - - - -+ + * |6642: |6652: | + * | alternative instr 2 | padding + * +---------------------+- - - - - -+ + * ^ runtime ^ + * + * .altinstructions section + * +---------------------------------+ + * | alt_instr entries for each | + * | alternative instr | + * +---------------------------------+ + */ + +#define b_altinstr(num) "664"#num +#define e_altinstr(num) "665"#num + +#define e_oldinstr_pad_end "663" +#define oldinstr_len "662b-661b" +#define oldinstr_total_len e_oldinstr_pad_end"b-661b" +#define altinstr_len(num) e_altinstr(num)"b-"b_altinstr(num)"b" +#define oldinstr_pad_len(num) \ + "-(((" altinstr_len(num) ")-(" oldinstr_len ")) > 0) * " \ + "((" altinstr_len(num) ")-(" oldinstr_len "))" + +#define INSTR_LEN_SANITY_CHECK(len) \ + ".if " len " > 254\n" \ + "\t.error \"cpu alternatives does not support instructions " \ + "blocks > 254 bytes\"\n" \ + ".endif\n" \ + ".if (" len ") %% 2\n" \ + "\t.error \"cpu alternatives instructions length is odd\"\n" \ + ".endif\n" + +#define OLDINSTR_PADDING(oldinstr, num) \ + ".if " oldinstr_pad_len(num) " > 6\n" \ + "\tjg " e_oldinstr_pad_end "f\n" \ + "6620:\n" \ + "\t.fill (" oldinstr_pad_len(num) " - (6620b-662b)) / 2, 2, 0x0700\n" \ + ".else\n" \ + "\t.fill " oldinstr_pad_len(num) " / 6, 6, 0xc0040000\n" \ + "\t.fill " oldinstr_pad_len(num) " %% 6 / 4, 4, 0x47000000\n" \ + "\t.fill " oldinstr_pad_len(num) " %% 6 %% 4 / 2, 2, 0x0700\n" \ + ".endif\n" + +#define OLDINSTR(oldinstr, num) \ + "661:\n\t" oldinstr "\n662:\n" \ + OLDINSTR_PADDING(oldinstr, num) \ + e_oldinstr_pad_end ":\n" \ + INSTR_LEN_SANITY_CHECK(oldinstr_len) + +#define OLDINSTR_2(oldinstr, num1, num2) \ + "661:\n\t" oldinstr "\n662:\n" \ + ".if " altinstr_len(num1) " < " altinstr_len(num2) "\n" \ + OLDINSTR_PADDING(oldinstr, num2) \ + ".else\n" \ + OLDINSTR_PADDING(oldinstr, num1) \ + ".endif\n" \ + e_oldinstr_pad_end ":\n" \ + INSTR_LEN_SANITY_CHECK(oldinstr_len) + +#define ALTINSTR_ENTRY(facility, num) \ + "\t.long 661b - .\n" /* old instruction */ \ + "\t.long " b_altinstr(num)"b - .\n" /* alt instruction */ \ + "\t.word " __stringify(facility) "\n" /* facility bit */ \ + "\t.byte " oldinstr_total_len "\n" /* source len */ \ + "\t.byte " altinstr_len(num) "\n" /* alt instruction len */ + +#define ALTINSTR_REPLACEMENT(altinstr, num) /* replacement */ \ + b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n" \ + INSTR_LEN_SANITY_CHECK(altinstr_len(num)) + +#ifdef CONFIG_ALTERNATIVES +/* alternative assembly primitive: */ +#define ALTERNATIVE(oldinstr, altinstr, facility) \ + ".pushsection .altinstr_replacement, \"ax\"\n" \ + ALTINSTR_REPLACEMENT(altinstr, 1) \ + ".popsection\n" \ + OLDINSTR(oldinstr, 1) \ + ".pushsection .altinstructions,\"a\"\n" \ + ALTINSTR_ENTRY(facility, 1) \ + ".popsection\n" + +#define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2)\ + ".pushsection .altinstr_replacement, \"ax\"\n" \ + ALTINSTR_REPLACEMENT(altinstr1, 1) \ + ALTINSTR_REPLACEMENT(altinstr2, 2) \ + ".popsection\n" \ + OLDINSTR_2(oldinstr, 1, 2) \ + ".pushsection .altinstructions,\"a\"\n" \ + ALTINSTR_ENTRY(facility1, 1) \ + ALTINSTR_ENTRY(facility2, 2) \ + ".popsection\n" +#else +/* Alternative instructions are disabled, let's put just oldinstr in */ +#define ALTERNATIVE(oldinstr, altinstr, facility) \ + oldinstr "\n" + +#define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \ + oldinstr "\n" +#endif + +/* + * Alternative instructions for different CPU types or capabilities. + * + * This allows to use optimized instructions even on generic binary + * kernels. + * + * oldinstr is padded with jump and nops at compile time if altinstr is + * longer. altinstr is padded with jump and nops at run-time during patching. + * + * For non barrier like inlines please define new variants + * without volatile and memory clobber. + */ +#define alternative(oldinstr, altinstr, facility) \ + asm volatile(ALTERNATIVE(oldinstr, altinstr, facility) : : : "memory") + +#define alternative_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \ + asm volatile(ALTERNATIVE_2(oldinstr, altinstr1, facility1, \ + altinstr2, facility2) ::: "memory") + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_S390_ALTERNATIVE_H */ diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 1f0fe98f6db9..383855ebbfb0 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_UPROBES) += uprobes.o +obj-$(CONFIG_ALTERNATIVES) += alternative.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o perf_cpum_sf.o obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_events.o diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c new file mode 100644 index 000000000000..315986a06cf5 --- /dev/null +++ b/arch/s390/kernel/alternative.c @@ -0,0 +1,110 @@ +#include +#include +#include + +#define MAX_PATCH_LEN (255 - 1) + +static int __initdata_or_module alt_instr_disabled; + +static int __init disable_alternative_instructions(char *str) +{ + alt_instr_disabled = 1; + return 0; +} + +early_param("noaltinstr", disable_alternative_instructions); + +struct brcl_insn { + u16 opc; + s32 disp; +} __packed; + +static u16 __initdata_or_module nop16 = 0x0700; +static u32 __initdata_or_module nop32 = 0x47000000; +static struct brcl_insn __initdata_or_module nop48 = { + 0xc004, 0 +}; + +static const void *nops[] __initdata_or_module = { + &nop16, + &nop32, + &nop48 +}; + +static void __init_or_module add_jump_padding(void *insns, unsigned int len) +{ + struct brcl_insn brcl = { + 0xc0f4, + len / 2 + }; + + memcpy(insns, &brcl, sizeof(brcl)); + insns += sizeof(brcl); + len -= sizeof(brcl); + + while (len > 0) { + memcpy(insns, &nop16, 2); + insns += 2; + len -= 2; + } +} + +static void __init_or_module add_padding(void *insns, unsigned int len) +{ + if (len > 6) + add_jump_padding(insns, len); + else if (len >= 2) + memcpy(insns, nops[len / 2 - 1], len); +} + +static void __init_or_module __apply_alternatives(struct alt_instr *start, + struct alt_instr *end) +{ + struct alt_instr *a; + u8 *instr, *replacement; + u8 insnbuf[MAX_PATCH_LEN]; + + /* + * The scan order should be from start to end. A later scanned + * alternative code can overwrite previously scanned alternative code. + */ + for (a = start; a < end; a++) { + int insnbuf_sz = 0; + + instr = (u8 *)&a->instr_offset + a->instr_offset; + replacement = (u8 *)&a->repl_offset + a->repl_offset; + + if (!test_facility(a->facility)) + continue; + + if (unlikely(a->instrlen % 2 || a->replacementlen % 2)) { + WARN_ONCE(1, "cpu alternatives instructions length is " + "odd, skipping patching\n"); + continue; + } + + memcpy(insnbuf, replacement, a->replacementlen); + insnbuf_sz = a->replacementlen; + + if (a->instrlen > a->replacementlen) { + add_padding(insnbuf + a->replacementlen, + a->instrlen - a->replacementlen); + insnbuf_sz += a->instrlen - a->replacementlen; + } + + s390_kernel_write(instr, insnbuf, insnbuf_sz); + } +} + +void __init_or_module apply_alternatives(struct alt_instr *start, + struct alt_instr *end) +{ + if (!alt_instr_disabled) + __apply_alternatives(start, end); +} + +extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; +void __init apply_alternative_instructions(void) +{ + apply_alternatives(__alt_instructions, __alt_instructions_end); +} diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index fbc07891f9e7..186fdb7f0f3d 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -31,6 +31,7 @@ #include #include #include +#include #if 0 #define DEBUGP printk @@ -428,6 +429,22 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *me) { + const Elf_Shdr *s; + char *secstrings; + + if (IS_ENABLED(CONFIG_ALTERNATIVES)) { + secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { + if (!strcmp(".altinstructions", + secstrings + s->sh_name)) { + /* patch .altinstructions */ + void *aseg = (void *)s->sh_addr; + + apply_alternatives(aseg, aseg + s->sh_size); + } + } + } + jump_label_apply_nops(me); return 0; } diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index e974e53ab597..c3bdb3e80380 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -63,6 +63,7 @@ #include #include #include +#include #include "entry.h" /* @@ -931,6 +932,8 @@ void __init setup_arch(char **cmdline_p) conmode_default(); set_preferred_console(); + apply_alternative_instructions(); + /* Setup zfcpdump support */ setup_zfcpdump(); diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 115bda280d50..b8ec50cb1b6f 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -99,6 +99,29 @@ SECTIONS EXIT_DATA } + /* + * struct alt_inst entries. From the header (alternative.h): + * "Alternative instructions for different CPU types or capabilities" + * Think locking instructions on spinlocks. + * Note, that it is a part of __init region. + */ + . = ALIGN(8); + .altinstructions : { + __alt_instructions = .; + *(.altinstructions) + __alt_instructions_end = .; + } + + /* + * And here are the replacement instructions. The linker sticks + * them as binary blobs. The .altinstructions has enough data to + * get the address and the length of them to patch the kernel safely. + * Note, that it is a part of __init region. + */ + .altinstr_replacement : { + *(.altinstr_replacement) + } + /* early.c uses stsi, which requires page aligned data. */ . = ALIGN(PAGE_SIZE); INIT_DATA_SECTION(0x100) -- GitLab From 420fd816bd206f266cf3a1300d5590790b5cdcb8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 27 Apr 2018 07:36:40 +0200 Subject: [PATCH 052/855] s390: enable CPU alternatives unconditionally [ Upstream commit 049a2c2d486e8cc82c5cd79fa479c5b105b109e9 ] Remove the CPU_ALTERNATIVES config option and enable the code unconditionally. The config option was only added to avoid a conflict with the named saved segment support. Since that code is gone there is no reason to keep the CPU_ALTERNATIVES config option. Just enable it unconditionally to also reduce the number of config options and make it less likely that something breaks. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/Kconfig | 16 ---------------- arch/s390/include/asm/alternative.h | 20 +++----------------- arch/s390/kernel/Makefile | 3 +-- arch/s390/kernel/module.c | 15 ++++++--------- 4 files changed, 10 insertions(+), 44 deletions(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index f3e43262db9d..f5a154d438ee 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -704,22 +704,6 @@ config SECCOMP If unsure, say Y. -config ALTERNATIVES - def_bool y - prompt "Patch optimized instructions for running CPU type" - help - When enabled the kernel code is compiled with additional - alternative instructions blocks optimized for newer CPU types. - These alternative instructions blocks are patched at kernel boot - time when running CPU supports them. This mechanism is used to - optimize some critical code paths (i.e. spinlocks) for newer CPUs - even if kernel is build to support older machine generations. - - This mechanism could be disabled by appending "noaltinstr" - option to the kernel command line. - - If unsure, say Y. - endmenu menu "Power Management" diff --git a/arch/s390/include/asm/alternative.h b/arch/s390/include/asm/alternative.h index 6c268f6a51d3..a72002056b54 100644 --- a/arch/s390/include/asm/alternative.h +++ b/arch/s390/include/asm/alternative.h @@ -15,14 +15,9 @@ struct alt_instr { u8 replacementlen; /* length of new instruction */ } __packed; -#ifdef CONFIG_ALTERNATIVES -extern void apply_alternative_instructions(void); -extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end); -#else -static inline void apply_alternative_instructions(void) {}; -static inline void apply_alternatives(struct alt_instr *start, - struct alt_instr *end) {}; -#endif +void apply_alternative_instructions(void); +void apply_alternatives(struct alt_instr *start, struct alt_instr *end); + /* * |661: |662: |6620 |663: * +-----------+---------------------+ @@ -109,7 +104,6 @@ static inline void apply_alternatives(struct alt_instr *start, b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n" \ INSTR_LEN_SANITY_CHECK(altinstr_len(num)) -#ifdef CONFIG_ALTERNATIVES /* alternative assembly primitive: */ #define ALTERNATIVE(oldinstr, altinstr, facility) \ ".pushsection .altinstr_replacement, \"ax\"\n" \ @@ -130,14 +124,6 @@ static inline void apply_alternatives(struct alt_instr *start, ALTINSTR_ENTRY(facility1, 1) \ ALTINSTR_ENTRY(facility2, 2) \ ".popsection\n" -#else -/* Alternative instructions are disabled, let's put just oldinstr in */ -#define ALTERNATIVE(oldinstr, altinstr, facility) \ - oldinstr "\n" - -#define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \ - oldinstr "\n" -#endif /* * Alternative instructions for different CPU types or capabilities. diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 383855ebbfb0..d4b73f28c395 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -57,7 +57,7 @@ obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o obj-y += debug.o irq.o ipl.o dis.o diag.o sclp.o vdso.o als.o obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o obj-y += runtime_instr.o cache.o fpu.o dumpstack.o -obj-y += entry.o reipl.o relocate_kernel.o +obj-y += entry.o reipl.o relocate_kernel.o alternative.o extra-y += head.o head64.o vmlinux.lds @@ -75,7 +75,6 @@ obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_UPROBES) += uprobes.o -obj-$(CONFIG_ALTERNATIVES) += alternative.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o perf_cpum_sf.o obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_events.o diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 186fdb7f0f3d..6f68259bf80e 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -432,16 +432,13 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *s; char *secstrings; - if (IS_ENABLED(CONFIG_ALTERNATIVES)) { - secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; - for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { - if (!strcmp(".altinstructions", - secstrings + s->sh_name)) { - /* patch .altinstructions */ - void *aseg = (void *)s->sh_addr; + secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { + if (!strcmp(".altinstructions", secstrings + s->sh_name)) { + /* patch .altinstructions */ + void *aseg = (void *)s->sh_addr; - apply_alternatives(aseg, aseg + s->sh_size); - } + apply_alternatives(aseg, aseg + s->sh_size); } } -- GitLab From 4d9c2b611ff27fa1556414adf104418cba230daa Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 27 Apr 2018 07:36:41 +0200 Subject: [PATCH 053/855] KVM: s390: wire up bpb feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 35b3fde6203b932b2b1a5b53b3d8808abc9c4f60 ] The new firmware interfaces for branch prediction behaviour changes are transparently available for the guest. Nevertheless, there is new state attached that should be migrated and properly resetted. Provide a mechanism for handling reset, migration and VSIE. Signed-off-by: Christian Borntraeger Reviewed-by: David Hildenbrand Reviewed-by: Cornelia Huck [Changed capability number to 152. - Radim] Signed-off-by: Radim Krčmář Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/kvm_host.h | 3 ++- arch/s390/include/uapi/asm/kvm.h | 5 ++++- arch/s390/kvm/kvm-s390.c | 13 ++++++++++++- arch/s390/kvm/vsie.c | 10 ++++++++++ include/uapi/linux/kvm.h | 1 + 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index a41faf34b034..5792590d0e7c 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -181,7 +181,8 @@ struct kvm_s390_sie_block { __u16 ipa; /* 0x0056 */ __u32 ipb; /* 0x0058 */ __u32 scaoh; /* 0x005c */ - __u8 reserved60; /* 0x0060 */ +#define FPF_BPBC 0x20 + __u8 fpf; /* 0x0060 */ __u8 ecb; /* 0x0061 */ __u8 ecb2; /* 0x0062 */ #define ECB3_AES 0x04 diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index a2ffec4139ad..81c02e198527 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h @@ -197,6 +197,7 @@ struct kvm_guest_debug_arch { #define KVM_SYNC_VRS (1UL << 6) #define KVM_SYNC_RICCB (1UL << 7) #define KVM_SYNC_FPRS (1UL << 8) +#define KVM_SYNC_BPBC (1UL << 10) /* definition of registers in kvm_run */ struct kvm_sync_regs { __u64 prefix; /* prefix register */ @@ -217,7 +218,9 @@ struct kvm_sync_regs { }; __u8 reserved[512]; /* for future vector expansion */ __u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */ - __u8 padding[52]; /* riccb needs to be 64byte aligned */ + __u8 bpbc : 1; /* bp mode */ + __u8 reserved2 : 7; + __u8 padding1[51]; /* riccb needs to be 64byte aligned */ __u8 riccb[64]; /* runtime instrumentation controls block */ }; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index a70ff09b4982..2032ab81b2d7 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -401,6 +401,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_S390_RI: r = test_facility(64); break; + case KVM_CAP_S390_BPB: + r = test_facility(82); + break; default: r = 0; } @@ -1713,6 +1716,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) kvm_s390_set_prefix(vcpu, 0); if (test_kvm_facility(vcpu->kvm, 64)) vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB; + if (test_kvm_facility(vcpu->kvm, 82)) + vcpu->run->kvm_valid_regs |= KVM_SYNC_BPBC; /* fprs can be synchronized via vrs, even if the guest has no vx. With * MACHINE_HAS_VX, (load|store)_fpu_regs() will work with vrs format. */ @@ -1829,7 +1834,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) if (test_fp_ctl(current->thread.fpu.fpc)) /* User space provided an invalid FPC, let's clear it */ current->thread.fpu.fpc = 0; - save_access_regs(vcpu->arch.host_acrs); restore_access_regs(vcpu->run->s.regs.acrs); gmap_enable(vcpu->arch.enabled_gmap); @@ -1877,6 +1881,7 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) current->thread.fpu.fpc = 0; vcpu->arch.sie_block->gbea = 1; vcpu->arch.sie_block->pp = 0; + vcpu->arch.sie_block->fpf &= ~FPF_BPBC; vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID; kvm_clear_async_pf_completion_queue(vcpu); if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) @@ -2744,6 +2749,11 @@ static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) if (riccb->valid) vcpu->arch.sie_block->ecb3 |= 0x01; } + if ((kvm_run->kvm_dirty_regs & KVM_SYNC_BPBC) && + test_kvm_facility(vcpu->kvm, 82)) { + vcpu->arch.sie_block->fpf &= ~FPF_BPBC; + vcpu->arch.sie_block->fpf |= kvm_run->s.regs.bpbc ? FPF_BPBC : 0; + } kvm_run->kvm_dirty_regs = 0; } @@ -2762,6 +2772,7 @@ static void store_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) kvm_run->s.regs.pft = vcpu->arch.pfault_token; kvm_run->s.regs.pfs = vcpu->arch.pfault_select; kvm_run->s.regs.pfc = vcpu->arch.pfault_compare; + kvm_run->s.regs.bpbc = (vcpu->arch.sie_block->fpf & FPF_BPBC) == FPF_BPBC; } int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index d8673e243f13..e56b7724054c 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -217,6 +217,12 @@ static void unshadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) memcpy(scb_o->gcr, scb_s->gcr, 128); scb_o->pp = scb_s->pp; + /* branch prediction */ + if (test_kvm_facility(vcpu->kvm, 82)) { + scb_o->fpf &= ~FPF_BPBC; + scb_o->fpf |= scb_s->fpf & FPF_BPBC; + } + /* interrupt intercept */ switch (scb_s->icptcode) { case ICPT_PROGI: @@ -259,6 +265,7 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) scb_s->ecb3 = 0; scb_s->ecd = 0; scb_s->fac = 0; + scb_s->fpf = 0; rc = prepare_cpuflags(vcpu, vsie_page); if (rc) @@ -316,6 +323,9 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) prefix_unmapped(vsie_page); scb_s->ecb |= scb_o->ecb & 0x10U; } + /* branch prediction */ + if (test_kvm_facility(vcpu->kvm, 82)) + scb_s->fpf |= scb_o->fpf & FPF_BPBC; /* SIMD */ if (test_kvm_facility(vcpu->kvm, 129)) { scb_s->eca |= scb_o->eca & 0x00020000U; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 4ee67cb99143..05b9bb63dbec 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -870,6 +870,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_S390_USER_INSTR0 130 #define KVM_CAP_MSI_DEVID 131 #define KVM_CAP_PPC_HTM 132 +#define KVM_CAP_S390_BPB 152 #ifdef KVM_CAP_IRQ_ROUTING -- GitLab From c225febe980f6f112fc0bfce58148d8b390d4cbf Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:42 +0200 Subject: [PATCH 054/855] s390: scrub registers on kernel entry and KVM exit [ Upstream commit 7041d28115e91f2144f811ffe8a195c696b1e1d0 ] Clear all user space registers on entry to the kernel and all KVM guest registers on KVM guest exit if the register does not contain either a parameter or a result value. Reviewed-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/entry.S | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 3bc2825173ef..04bff4d0e8f2 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -255,6 +255,12 @@ ENTRY(sie64a) sie_exit: lg %r14,__SF_EMPTY+8(%r15) # load guest register save area stmg %r0,%r13,0(%r14) # save guest gprs 0-13 + xgr %r0,%r0 # clear guest registers to + xgr %r1,%r1 # prevent speculative use + xgr %r2,%r2 + xgr %r3,%r3 + xgr %r4,%r4 + xgr %r5,%r5 lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers lg %r2,__SF_EMPTY+16(%r15) # return exit reason code br %r14 @@ -290,6 +296,8 @@ ENTRY(system_call) .Lsysc_vtime: UPDATE_VTIME %r10,%r13,__LC_SYNC_ENTER_TIMER stmg %r0,%r7,__PT_R0(%r11) + # clear user controlled register to prevent speculative use + xgr %r0,%r0 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC @@ -517,6 +525,15 @@ ENTRY(pgm_check_handler) mvc __THREAD_trap_tdb(256,%r14),0(%r13) 3: la %r11,STACK_FRAME_OVERHEAD(%r15) stmg %r0,%r7,__PT_R0(%r11) + # clear user controlled registers to prevent speculative use + xgr %r0,%r0 + xgr %r1,%r1 + xgr %r2,%r2 + xgr %r3,%r3 + xgr %r4,%r4 + xgr %r5,%r5 + xgr %r6,%r6 + xgr %r7,%r7 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC stmg %r8,%r9,__PT_PSW(%r11) mvc __PT_INT_CODE(4,%r11),__LC_PGM_ILC @@ -580,6 +597,16 @@ ENTRY(io_int_handler) lmg %r8,%r9,__LC_IO_OLD_PSW SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER stmg %r0,%r7,__PT_R0(%r11) + # clear user controlled registers to prevent speculative use + xgr %r0,%r0 + xgr %r1,%r1 + xgr %r2,%r2 + xgr %r3,%r3 + xgr %r4,%r4 + xgr %r5,%r5 + xgr %r6,%r6 + xgr %r7,%r7 + xgr %r10,%r10 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC stmg %r8,%r9,__PT_PSW(%r11) mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID @@ -755,6 +782,16 @@ ENTRY(ext_int_handler) lmg %r8,%r9,__LC_EXT_OLD_PSW SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER stmg %r0,%r7,__PT_R0(%r11) + # clear user controlled registers to prevent speculative use + xgr %r0,%r0 + xgr %r1,%r1 + xgr %r2,%r2 + xgr %r3,%r3 + xgr %r4,%r4 + xgr %r5,%r5 + xgr %r6,%r6 + xgr %r7,%r7 + xgr %r10,%r10 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC stmg %r8,%r9,__PT_PSW(%r11) lghi %r1,__LC_EXT_PARAMS2 @@ -925,6 +962,16 @@ ENTRY(mcck_int_handler) .Lmcck_skip: lghi %r14,__LC_GPREGS_SAVE_AREA+64 stmg %r0,%r7,__PT_R0(%r11) + # clear user controlled registers to prevent speculative use + xgr %r0,%r0 + xgr %r1,%r1 + xgr %r2,%r2 + xgr %r3,%r3 + xgr %r4,%r4 + xgr %r5,%r5 + xgr %r6,%r6 + xgr %r7,%r7 + xgr %r10,%r10 mvc __PT_R8(64,%r11),0(%r14) stmg %r8,%r9,__PT_PSW(%r11) xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11) -- GitLab From 2dcf46aa49acc4c432ebefe3d4d413f428adc120 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:43 +0200 Subject: [PATCH 055/855] s390: add optimized array_index_mask_nospec [ Upstream commit e2dd833389cc4069a96b57bdd24227b5f52288f5 ] Add an optimized version of the array_index_mask_nospec function for s390 based on a compare and a subtract with borrow. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/barrier.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/s390/include/asm/barrier.h b/arch/s390/include/asm/barrier.h index 5c8db3ce61c8..03b2e5bf1206 100644 --- a/arch/s390/include/asm/barrier.h +++ b/arch/s390/include/asm/barrier.h @@ -48,6 +48,30 @@ do { \ #define __smp_mb__before_atomic() barrier() #define __smp_mb__after_atomic() barrier() +/** + * array_index_mask_nospec - generate a mask for array_idx() that is + * ~0UL when the bounds check succeeds and 0 otherwise + * @index: array element index + * @size: number of elements in array + */ +#define array_index_mask_nospec array_index_mask_nospec +static inline unsigned long array_index_mask_nospec(unsigned long index, + unsigned long size) +{ + unsigned long mask; + + if (__builtin_constant_p(size) && size > 0) { + asm(" clgr %2,%1\n" + " slbgr %0,%0\n" + :"=d" (mask) : "d" (size-1), "d" (index) :"cc"); + return mask; + } + asm(" clgr %1,%2\n" + " slbgr %0,%0\n" + :"=d" (mask) : "d" (size), "d" (index) :"cc"); + return ~mask; +} + #include #endif /* __ASM_BARRIER_H */ -- GitLab From 46bd2c0ffd5cf7642a9dd87b294be9d2e51adb69 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:44 +0200 Subject: [PATCH 056/855] s390/alternative: use a copy of the facility bit mask [ Upstream commit cf1489984641369611556bf00c48f945c77bcf02 ] To be able to switch off specific CPU alternatives with kernel parameters make a copy of the facility bit mask provided by STFLE and use the copy for the decision to apply an alternative. Reviewed-by: David Hildenbrand Reviewed-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/facility.h | 18 ++++++++++++++++++ arch/s390/include/asm/lowcore.h | 3 ++- arch/s390/kernel/alternative.c | 3 ++- arch/s390/kernel/early.c | 3 +++ arch/s390/kernel/setup.c | 4 +++- arch/s390/kernel/smp.c | 4 +++- 6 files changed, 31 insertions(+), 4 deletions(-) diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h index 09b406db7529..7a8a1457dbb8 100644 --- a/arch/s390/include/asm/facility.h +++ b/arch/s390/include/asm/facility.h @@ -17,6 +17,24 @@ #define MAX_FACILITY_BIT (256*8) /* stfle_fac_list has 256 bytes */ +static inline void __set_facility(unsigned long nr, void *facilities) +{ + unsigned char *ptr = (unsigned char *) facilities; + + if (nr >= MAX_FACILITY_BIT) + return; + ptr[nr >> 3] |= 0x80 >> (nr & 7); +} + +static inline void __clear_facility(unsigned long nr, void *facilities) +{ + unsigned char *ptr = (unsigned char *) facilities; + + if (nr >= MAX_FACILITY_BIT) + return; + ptr[nr >> 3] &= ~(0x80 >> (nr & 7)); +} + static inline int __test_facility(unsigned long nr, void *facilities) { unsigned char *ptr; diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 7b93b78f423c..d52e7efea7d6 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -150,7 +150,8 @@ struct lowcore { __u8 pad_0x0e20[0x0f00-0x0e20]; /* 0x0e20 */ /* Extended facility list */ - __u64 stfle_fac_list[32]; /* 0x0f00 */ + __u64 stfle_fac_list[16]; /* 0x0f00 */ + __u64 alt_stfle_fac_list[16]; /* 0x0f80 */ __u8 pad_0x1000[0x11b0-0x1000]; /* 0x1000 */ /* Pointer to vector register save area */ diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c index 315986a06cf5..f5060af61176 100644 --- a/arch/s390/kernel/alternative.c +++ b/arch/s390/kernel/alternative.c @@ -74,7 +74,8 @@ static void __init_or_module __apply_alternatives(struct alt_instr *start, instr = (u8 *)&a->instr_offset + a->instr_offset; replacement = (u8 *)&a->repl_offset + a->repl_offset; - if (!test_facility(a->facility)) + if (!__test_facility(a->facility, + S390_lowcore.alt_stfle_fac_list)) continue; if (unlikely(a->instrlen % 2 || a->replacementlen % 2)) { diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 62578989c74d..171aaa221e4b 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -299,6 +299,9 @@ static noinline __init void setup_facility_list(void) { stfle(S390_lowcore.stfle_fac_list, ARRAY_SIZE(S390_lowcore.stfle_fac_list)); + memcpy(S390_lowcore.alt_stfle_fac_list, + S390_lowcore.stfle_fac_list, + sizeof(S390_lowcore.alt_stfle_fac_list)); } static __init void detect_diag9c(void) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index c3bdb3e80380..433b380896b9 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -336,7 +336,9 @@ static void __init setup_lowcore(void) lc->machine_flags = S390_lowcore.machine_flags; lc->stfl_fac_list = S390_lowcore.stfl_fac_list; memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list, - MAX_FACILITY_BIT/8); + sizeof(lc->stfle_fac_list)); + memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list, + sizeof(lc->alt_stfle_fac_list)); if (MACHINE_HAS_VX) lc->vector_save_area_addr = (unsigned long) &lc->vector_save_area; diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 35531fe1c5ea..63c8a840d56b 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -253,7 +253,9 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) __ctl_store(lc->cregs_save_area, 0, 15); save_access_regs((unsigned int *) lc->access_regs_save_area); memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list, - MAX_FACILITY_BIT/8); + sizeof(lc->stfle_fac_list)); + memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list, + sizeof(lc->alt_stfle_fac_list)); } static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk) -- GitLab From 07f65a834a814fb1a1b428b26a671f9196031b60 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:45 +0200 Subject: [PATCH 057/855] s390: add options to change branch prediction behaviour for the kernel [ Upstream commit d768bd892fc8f066cd3aa000eb1867bcf32db0ee ] Add the PPA instruction to the system entry and exit path to switch the kernel to a different branch prediction behaviour. The instructions are added via CPU alternatives and can be disabled with the "nospec" or the "nobp=0" kernel parameter. If the default behaviour selected with CONFIG_KERNEL_NOBP is set to "n" then the "nobp=1" parameter can be used to enable the changed kernel branch prediction. Acked-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/Kconfig | 17 +++++++++++ arch/s390/include/asm/processor.h | 1 + arch/s390/kernel/alternative.c | 23 +++++++++++++++ arch/s390/kernel/early.c | 2 ++ arch/s390/kernel/entry.S | 48 +++++++++++++++++++++++++++++++ arch/s390/kernel/ipl.c | 1 + arch/s390/kernel/smp.c | 2 ++ 7 files changed, 94 insertions(+) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index f5a154d438ee..02eb7a91ad35 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -704,6 +704,23 @@ config SECCOMP If unsure, say Y. +config KERNEL_NOBP + def_bool n + prompt "Enable modified branch prediction for the kernel by default" + help + If this option is selected the kernel will switch to a modified + branch prediction mode if the firmware interface is available. + The modified branch prediction mode improves the behaviour in + regard to speculative execution. + + With the option enabled the kernel parameter "nobp=0" or "nospec" + can be used to run the kernel in the normal branch prediction mode. + + With the option disabled the modified branch prediction mode is + enabled with the "nobp=1" kernel parameter. + + If unsure, say N. + endmenu menu "Power Management" diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 6bcbbece082b..44de5d0014c5 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -84,6 +84,7 @@ void cpu_detect_mhz_feature(void); extern const struct seq_operations cpuinfo_op; extern int sysctl_ieee_emulation_warnings; extern void execve_tail(void); +extern void __bpon(void); /* * User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit. diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c index f5060af61176..ed21de98b79e 100644 --- a/arch/s390/kernel/alternative.c +++ b/arch/s390/kernel/alternative.c @@ -14,6 +14,29 @@ static int __init disable_alternative_instructions(char *str) early_param("noaltinstr", disable_alternative_instructions); +static int __init nobp_setup_early(char *str) +{ + bool enabled; + int rc; + + rc = kstrtobool(str, &enabled); + if (rc) + return rc; + if (enabled && test_facility(82)) + __set_facility(82, S390_lowcore.alt_stfle_fac_list); + else + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + return 0; +} +early_param("nobp", nobp_setup_early); + +static int __init nospec_setup_early(char *str) +{ + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + return 0; +} +early_param("nospec", nospec_setup_early); + struct brcl_insn { u16 opc; s32 disp; diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 171aaa221e4b..0c7a7d5d95f1 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -302,6 +302,8 @@ static noinline __init void setup_facility_list(void) memcpy(S390_lowcore.alt_stfle_fac_list, S390_lowcore.stfle_fac_list, sizeof(S390_lowcore.alt_stfle_fac_list)); + if (!IS_ENABLED(CONFIG_KERNEL_NOBP)) + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); } static __init void detect_diag9c(void) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 04bff4d0e8f2..bfcf04de5808 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -163,6 +163,34 @@ _PIF_WORK = (_PIF_PER_TRAP) tm off+\addr, \mask .endm + .macro BPOFF + .pushsection .altinstr_replacement, "ax" +660: .long 0xb2e8c000 + .popsection +661: .long 0x47000000 + .pushsection .altinstructions, "a" + .long 661b - . + .long 660b - . + .word 82 + .byte 4 + .byte 4 + .popsection + .endm + + .macro BPON + .pushsection .altinstr_replacement, "ax" +662: .long 0xb2e8d000 + .popsection +663: .long 0x47000000 + .pushsection .altinstructions, "a" + .long 663b - . + .long 662b - . + .word 82 + .byte 4 + .byte 4 + .popsection + .endm + .section .kprobes.text, "ax" .Ldummy: /* @@ -175,6 +203,11 @@ _PIF_WORK = (_PIF_PER_TRAP) */ nop 0 +ENTRY(__bpon) + .globl __bpon + BPON + br %r14 + /* * Scheduler resume function, called by switch_to * gpr2 = (task_struct *) prev @@ -234,7 +267,10 @@ ENTRY(sie64a) jnz .Lsie_skip TSTMSK __LC_CPU_FLAGS,_CIF_FPU jo .Lsie_skip # exit if fp/vx regs changed + BPON sie 0(%r14) +.Lsie_exit: + BPOFF .Lsie_skip: ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce @@ -286,6 +322,7 @@ ENTRY(system_call) stpt __LC_SYNC_ENTER_TIMER .Lsysc_stmg: stmg %r8,%r15,__LC_SAVE_AREA_SYNC + BPOFF lg %r10,__LC_LAST_BREAK lg %r12,__LC_THREAD_INFO lghi %r14,_PIF_SYSCALL @@ -332,6 +369,7 @@ ENTRY(system_call) jnz .Lsysc_work # check for work TSTMSK __LC_CPU_FLAGS,_CIF_WORK jnz .Lsysc_work + BPON .Lsysc_restore: lg %r14,__LC_VDSO_PER_CPU lmg %r0,%r10,__PT_R0(%r11) @@ -492,6 +530,7 @@ ENTRY(kernel_thread_starter) ENTRY(pgm_check_handler) stpt __LC_SYNC_ENTER_TIMER + BPOFF stmg %r8,%r15,__LC_SAVE_AREA_SYNC lg %r10,__LC_LAST_BREAK lg %r12,__LC_THREAD_INFO @@ -590,6 +629,7 @@ ENTRY(pgm_check_handler) ENTRY(io_int_handler) STCK __LC_INT_CLOCK stpt __LC_ASYNC_ENTER_TIMER + BPOFF stmg %r8,%r15,__LC_SAVE_AREA_ASYNC lg %r10,__LC_LAST_BREAK lg %r12,__LC_THREAD_INFO @@ -641,9 +681,13 @@ ENTRY(io_int_handler) lg %r14,__LC_VDSO_PER_CPU lmg %r0,%r10,__PT_R0(%r11) mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) + tm __PT_PSW+1(%r11),0x01 # returning to user ? + jno .Lio_exit_kernel + BPON .Lio_exit_timer: stpt __LC_EXIT_TIMER mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER +.Lio_exit_kernel: lmg %r11,%r15,__PT_R11(%r11) lpswe __LC_RETURN_PSW .Lio_done: @@ -775,6 +819,7 @@ ENTRY(io_int_handler) ENTRY(ext_int_handler) STCK __LC_INT_CLOCK stpt __LC_ASYNC_ENTER_TIMER + BPOFF stmg %r8,%r15,__LC_SAVE_AREA_ASYNC lg %r10,__LC_LAST_BREAK lg %r12,__LC_THREAD_INFO @@ -824,6 +869,7 @@ ENTRY(psw_idle) .Lpsw_idle_stcctm: #endif oi __LC_CPU_FLAGS+7,_CIF_ENABLED_WAIT + BPON STCK __CLOCK_IDLE_ENTER(%r2) stpt __TIMER_IDLE_ENTER(%r2) .Lpsw_idle_lpsw: @@ -931,6 +977,7 @@ load_fpu_regs: */ ENTRY(mcck_int_handler) STCK __LC_MCCK_CLOCK + BPOFF la %r1,4095 # revalidate r1 spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs @@ -997,6 +1044,7 @@ ENTRY(mcck_int_handler) mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? jno 0f + BPON stpt __LC_EXIT_TIMER mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER 0: lmg %r11,%r15,__PT_R11(%r11) diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 39127b691b78..df49f2a1a7e5 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -563,6 +563,7 @@ static struct kset *ipl_kset; static void __ipl_run(void *unused) { + __bpon(); diag308(DIAG308_LOAD_CLEAR, NULL); if (MACHINE_IS_VM) __cpcmd("IPL", NULL, 0, NULL); diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 63c8a840d56b..b34ff0798d38 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -304,6 +304,7 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *), mem_assign_absolute(lc->restart_fn, (unsigned long) func); mem_assign_absolute(lc->restart_data, (unsigned long) data); mem_assign_absolute(lc->restart_source, source_cpu); + __bpon(); asm volatile( "0: sigp 0,%0,%2 # sigp restart to target cpu\n" " brc 2,0b # busy, try again\n" @@ -877,6 +878,7 @@ void __cpu_die(unsigned int cpu) void __noreturn cpu_die(void) { idle_task_exit(); + __bpon(); pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0); for (;;) ; } -- GitLab From a1f44e7917a67bcd48a3c4bf5c13fd150850dc25 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:46 +0200 Subject: [PATCH 058/855] s390: run user space and KVM guests with modified branch prediction [ Upstream commit 6b73044b2b0081ee3dd1cd6eaab7dee552601efb ] Define TIF_ISOLATE_BP and TIF_ISOLATE_BP_GUEST and add the necessary plumbing in entry.S to be able to run user space and KVM guests with limited branch prediction. To switch a user space process to limited branch prediction the s390_isolate_bp() function has to be call, and to run a vCPU of a KVM guest associated with the current task with limited branch prediction call s390_isolate_bp_guest(). Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/processor.h | 3 ++ arch/s390/include/asm/thread_info.h | 4 +++ arch/s390/kernel/entry.S | 49 ++++++++++++++++++++++++++--- arch/s390/kernel/processor.c | 18 +++++++++++ 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 44de5d0014c5..d5842126ec70 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -360,6 +360,9 @@ extern void memcpy_absolute(void *, void *, size_t); memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \ } +extern int s390_isolate_bp(void); +extern int s390_isolate_bp_guest(void); + #endif /* __ASSEMBLY__ */ #endif /* __ASM_S390_PROCESSOR_H */ diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h index f15c0398c363..84f2ae44b4e9 100644 --- a/arch/s390/include/asm/thread_info.h +++ b/arch/s390/include/asm/thread_info.h @@ -79,6 +79,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); #define TIF_SECCOMP 5 /* secure computing */ #define TIF_SYSCALL_TRACEPOINT 6 /* syscall tracepoint instrumentation */ #define TIF_UPROBE 7 /* breakpointed or single-stepping */ +#define TIF_ISOLATE_BP 8 /* Run process with isolated BP */ +#define TIF_ISOLATE_BP_GUEST 9 /* Run KVM guests with isolated BP */ #define TIF_31BIT 16 /* 32bit process */ #define TIF_MEMDIE 17 /* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 18 /* restore signal mask in do_signal() */ @@ -94,6 +96,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); #define _TIF_SECCOMP _BITUL(TIF_SECCOMP) #define _TIF_SYSCALL_TRACEPOINT _BITUL(TIF_SYSCALL_TRACEPOINT) #define _TIF_UPROBE _BITUL(TIF_UPROBE) +#define _TIF_ISOLATE_BP _BITUL(TIF_ISOLATE_BP) +#define _TIF_ISOLATE_BP_GUEST _BITUL(TIF_ISOLATE_BP_GUEST) #define _TIF_31BIT _BITUL(TIF_31BIT) #define _TIF_SINGLE_STEP _BITUL(TIF_SINGLE_STEP) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index bfcf04de5808..0dd787aabac7 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -105,6 +105,7 @@ _PIF_WORK = (_PIF_PER_TRAP) j 3f 1: LAST_BREAK %r14 UPDATE_VTIME %r14,%r15,\timer + BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP 2: lg %r15,__LC_ASYNC_STACK # load async stack 3: la %r11,STACK_FRAME_OVERHEAD(%r15) .endm @@ -191,6 +192,40 @@ _PIF_WORK = (_PIF_PER_TRAP) .popsection .endm + .macro BPENTER tif_ptr,tif_mask + .pushsection .altinstr_replacement, "ax" +662: .word 0xc004, 0x0000, 0x0000 # 6 byte nop + .word 0xc004, 0x0000, 0x0000 # 6 byte nop + .popsection +664: TSTMSK \tif_ptr,\tif_mask + jz . + 8 + .long 0xb2e8d000 + .pushsection .altinstructions, "a" + .long 664b - . + .long 662b - . + .word 82 + .byte 12 + .byte 12 + .popsection + .endm + + .macro BPEXIT tif_ptr,tif_mask + TSTMSK \tif_ptr,\tif_mask + .pushsection .altinstr_replacement, "ax" +662: jnz . + 8 + .long 0xb2e8d000 + .popsection +664: jz . + 8 + .long 0xb2e8c000 + .pushsection .altinstructions, "a" + .long 664b - . + .long 662b - . + .word 82 + .byte 8 + .byte 8 + .popsection + .endm + .section .kprobes.text, "ax" .Ldummy: /* @@ -248,9 +283,11 @@ ENTRY(__switch_to) */ ENTRY(sie64a) stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers + lg %r12,__LC_CURRENT stg %r2,__SF_EMPTY(%r15) # save control block pointer stg %r3,__SF_EMPTY+8(%r15) # save guest register save area xc __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # reason code = 0 + mvc __SF_EMPTY+24(8,%r15),__TI_flags(%r12) # copy thread flags TSTMSK __LC_CPU_FLAGS,_CIF_FPU # load guest fp/vx registers ? jno .Lsie_load_guest_gprs brasl %r14,load_fpu_regs # load guest fp/vx regs @@ -267,10 +304,11 @@ ENTRY(sie64a) jnz .Lsie_skip TSTMSK __LC_CPU_FLAGS,_CIF_FPU jo .Lsie_skip # exit if fp/vx regs changed - BPON + BPEXIT __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) sie 0(%r14) .Lsie_exit: BPOFF + BPENTER __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) .Lsie_skip: ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce @@ -332,6 +370,7 @@ ENTRY(system_call) LAST_BREAK %r13 .Lsysc_vtime: UPDATE_VTIME %r10,%r13,__LC_SYNC_ENTER_TIMER + BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP stmg %r0,%r7,__PT_R0(%r11) # clear user controlled register to prevent speculative use xgr %r0,%r0 @@ -369,7 +408,7 @@ ENTRY(system_call) jnz .Lsysc_work # check for work TSTMSK __LC_CPU_FLAGS,_CIF_WORK jnz .Lsysc_work - BPON + BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP .Lsysc_restore: lg %r14,__LC_VDSO_PER_CPU lmg %r0,%r10,__PT_R0(%r11) @@ -555,6 +594,7 @@ ENTRY(pgm_check_handler) j 3f 2: LAST_BREAK %r14 UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER + BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP lg %r15,__LC_KERNEL_STACK lg %r14,__TI_task(%r12) aghi %r14,__TASK_thread # pointer to thread_struct @@ -683,7 +723,7 @@ ENTRY(io_int_handler) mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) tm __PT_PSW+1(%r11),0x01 # returning to user ? jno .Lio_exit_kernel - BPON + BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP .Lio_exit_timer: stpt __LC_EXIT_TIMER mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER @@ -1044,7 +1084,7 @@ ENTRY(mcck_int_handler) mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? jno 0f - BPON + BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP stpt __LC_EXIT_TIMER mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER 0: lmg %r11,%r15,__PT_R11(%r11) @@ -1165,6 +1205,7 @@ cleanup_critical: .quad .Lsie_done .Lcleanup_sie: + BPENTER __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) lg %r9,__SF_EMPTY(%r15) # get control block pointer ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 81d0808085e6..d856263fd768 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -179,3 +179,21 @@ const struct seq_operations cpuinfo_op = { .stop = c_stop, .show = show_cpuinfo, }; + +int s390_isolate_bp(void) +{ + if (!test_facility(82)) + return -EOPNOTSUPP; + set_thread_flag(TIF_ISOLATE_BP); + return 0; +} +EXPORT_SYMBOL(s390_isolate_bp); + +int s390_isolate_bp_guest(void) +{ + if (!test_facility(82)) + return -EOPNOTSUPP; + set_thread_flag(TIF_ISOLATE_BP_GUEST); + return 0; +} +EXPORT_SYMBOL(s390_isolate_bp_guest); -- GitLab From 24fbc4eee899f1a8d291ffe47333a673a3ed6c01 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:47 +0200 Subject: [PATCH 059/855] s390: introduce execute-trampolines for branches [ Upstream commit f19fbd5ed642dc31c809596412dab1ed56f2f156 ] Add CONFIG_EXPOLINE to enable the use of the new -mindirect-branch= and -mfunction_return= compiler options to create a kernel fortified against the specte v2 attack. With CONFIG_EXPOLINE=y all indirect branches will be issued with an execute type instruction. For z10 or newer the EXRL instruction will be used, for older machines the EX instruction. The typical indirect call basr %r14,%r1 is replaced with a PC relative call to a new thunk brasl %r14,__s390x_indirect_jump_r1 The thunk contains the EXRL/EX instruction to the indirect branch __s390x_indirect_jump_r1: exrl 0,0f j . 0: br %r1 The detour via the execute type instruction has a performance impact. To get rid of the detour the new kernel parameter "nospectre_v2" and "spectre_v2=[on,off,auto]" can be used. If the parameter is specified the kernel and module code will be patched at runtime. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/Kconfig | 28 +++++++ arch/s390/Makefile | 10 +++ arch/s390/include/asm/lowcore.h | 4 +- arch/s390/include/asm/nospec-branch.h | 18 ++++ arch/s390/kernel/Makefile | 4 + arch/s390/kernel/entry.S | 113 ++++++++++++++++++++------ arch/s390/kernel/module.c | 62 ++++++++++++-- arch/s390/kernel/nospec-branch.c | 101 +++++++++++++++++++++++ arch/s390/kernel/setup.c | 4 + arch/s390/kernel/smp.c | 1 + arch/s390/kernel/vmlinux.lds.S | 14 ++++ drivers/s390/char/Makefile | 2 + 12 files changed, 326 insertions(+), 35 deletions(-) create mode 100644 arch/s390/include/asm/nospec-branch.h create mode 100644 arch/s390/kernel/nospec-branch.c diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 02eb7a91ad35..c88bb4a50db7 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -721,6 +721,34 @@ config KERNEL_NOBP If unsure, say N. +config EXPOLINE + def_bool n + prompt "Avoid speculative indirect branches in the kernel" + help + Compile the kernel with the expoline compiler options to guard + against kernel-to-user data leaks by avoiding speculative indirect + branches. + Requires a compiler with -mindirect-branch=thunk support for full + protection. The kernel may run slower. + + If unsure, say N. + +choice + prompt "Expoline default" + depends on EXPOLINE + default EXPOLINE_FULL + +config EXPOLINE_OFF + bool "spectre_v2=off" + +config EXPOLINE_MEDIUM + bool "spectre_v2=auto" + +config EXPOLINE_FULL + bool "spectre_v2=on" + +endchoice + endmenu menu "Power Management" diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 54e00526b8df..d241a9fddf43 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -79,6 +79,16 @@ ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y) cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack endif +ifdef CONFIG_EXPOLINE + ifeq ($(call cc-option-yn,$(CC_FLAGS_MARCH) -mindirect-branch=thunk),y) + CC_FLAGS_EXPOLINE := -mindirect-branch=thunk + CC_FLAGS_EXPOLINE += -mfunction-return=thunk + CC_FLAGS_EXPOLINE += -mindirect-branch-table + export CC_FLAGS_EXPOLINE + cflags-y += $(CC_FLAGS_EXPOLINE) + endif +endif + ifdef CONFIG_FUNCTION_TRACER # make use of hotpatch feature if the compiler supports it cc_hotpatch := -mhotpatch=0,3 diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index d52e7efea7d6..ad4e0cee1557 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -135,7 +135,9 @@ struct lowcore { /* Per cpu primary space access list */ __u32 paste[16]; /* 0x0400 */ - __u8 pad_0x04c0[0x0e00-0x0440]; /* 0x0440 */ + /* br %r1 trampoline */ + __u16 br_r1_trampoline; /* 0x0440 */ + __u8 pad_0x0442[0x0e00-0x0442]; /* 0x0442 */ /* * 0xe00 contains the address of the IPL Parameter Information diff --git a/arch/s390/include/asm/nospec-branch.h b/arch/s390/include/asm/nospec-branch.h new file mode 100644 index 000000000000..7df48e5cf36f --- /dev/null +++ b/arch/s390/include/asm/nospec-branch.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_S390_EXPOLINE_H +#define _ASM_S390_EXPOLINE_H + +#ifndef __ASSEMBLY__ + +#include + +extern int nospec_call_disable; +extern int nospec_return_disable; + +void nospec_init_branches(void); +void nospec_call_revert(s32 *start, s32 *end); +void nospec_return_revert(s32 *start, s32 *end); + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_S390_EXPOLINE_H */ diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index d4b73f28c395..1c3e5d529cc1 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -42,6 +42,7 @@ ifneq ($(CC_FLAGS_MARCH),-march=z900) CFLAGS_REMOVE_sclp.o += $(CC_FLAGS_MARCH) CFLAGS_sclp.o += -march=z900 CFLAGS_REMOVE_als.o += $(CC_FLAGS_MARCH) +CFLAGS_REMOVE_als.o += $(CC_FLAGS_EXPOLINE) CFLAGS_als.o += -march=z900 AFLAGS_REMOVE_head.o += $(CC_FLAGS_MARCH) AFLAGS_head.o += -march=z900 @@ -61,6 +62,9 @@ obj-y += entry.o reipl.o relocate_kernel.o alternative.o extra-y += head.o head64.o vmlinux.lds +obj-$(CONFIG_EXPOLINE) += nospec-branch.o +CFLAGS_REMOVE_expoline.o += $(CC_FLAGS_EXPOLINE) + obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SCHED_TOPOLOGY) += topology.o diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 0dd787aabac7..8cbe75d7353d 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -226,6 +226,68 @@ _PIF_WORK = (_PIF_PER_TRAP) .popsection .endm +#ifdef CONFIG_EXPOLINE + + .macro GEN_BR_THUNK name,reg,tmp + .section .text.\name,"axG",@progbits,\name,comdat + .globl \name + .hidden \name + .type \name,@function +\name: + .cfi_startproc +#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES + exrl 0,0f +#else + larl \tmp,0f + ex 0,0(\tmp) +#endif + j . +0: br \reg + .cfi_endproc + .endm + + GEN_BR_THUNK __s390x_indirect_jump_r1use_r9,%r9,%r1 + GEN_BR_THUNK __s390x_indirect_jump_r1use_r14,%r14,%r1 + GEN_BR_THUNK __s390x_indirect_jump_r11use_r14,%r14,%r11 + + .macro BASR_R14_R9 +0: brasl %r14,__s390x_indirect_jump_r1use_r9 + .pushsection .s390_indirect_branches,"a",@progbits + .long 0b-. + .popsection + .endm + + .macro BR_R1USE_R14 +0: jg __s390x_indirect_jump_r1use_r14 + .pushsection .s390_indirect_branches,"a",@progbits + .long 0b-. + .popsection + .endm + + .macro BR_R11USE_R14 +0: jg __s390x_indirect_jump_r11use_r14 + .pushsection .s390_indirect_branches,"a",@progbits + .long 0b-. + .popsection + .endm + +#else /* CONFIG_EXPOLINE */ + + .macro BASR_R14_R9 + basr %r14,%r9 + .endm + + .macro BR_R1USE_R14 + br %r14 + .endm + + .macro BR_R11USE_R14 + br %r14 + .endm + +#endif /* CONFIG_EXPOLINE */ + + .section .kprobes.text, "ax" .Ldummy: /* @@ -241,7 +303,7 @@ _PIF_WORK = (_PIF_PER_TRAP) ENTRY(__bpon) .globl __bpon BPON - br %r14 + BR_R1USE_R14 /* * Scheduler resume function, called by switch_to @@ -269,9 +331,9 @@ ENTRY(__switch_to) mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_LPP - bzr %r14 + jz 0f .insn s,0xb2800000,__LC_LPP # set program parameter - br %r14 +0: BR_R1USE_R14 .L__critical_start: @@ -337,7 +399,7 @@ sie_exit: xgr %r5,%r5 lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers lg %r2,__SF_EMPTY+16(%r15) # return exit reason code - br %r14 + BR_R1USE_R14 .Lsie_fault: lghi %r14,-EFAULT stg %r14,__SF_EMPTY+16(%r15) # set exit reason code @@ -396,7 +458,7 @@ ENTRY(system_call) lgf %r9,0(%r8,%r10) # get system call add. TSTMSK __TI_flags(%r12),_TIF_TRACE jnz .Lsysc_tracesys - basr %r14,%r9 # call sys_xxxx + BASR_R14_R9 # call sys_xxxx stg %r2,__PT_R2(%r11) # store return value .Lsysc_return: @@ -536,7 +598,7 @@ ENTRY(system_call) lmg %r3,%r7,__PT_R3(%r11) stg %r7,STACK_FRAME_OVERHEAD(%r15) lg %r2,__PT_ORIG_GPR2(%r11) - basr %r14,%r9 # call sys_xxx + BASR_R14_R9 # call sys_xxx stg %r2,__PT_R2(%r11) # store return value .Lsysc_tracenogo: TSTMSK __TI_flags(%r12),_TIF_TRACE @@ -560,7 +622,7 @@ ENTRY(ret_from_fork) lmg %r9,%r10,__PT_R9(%r11) # load gprs ENTRY(kernel_thread_starter) la %r2,0(%r10) - basr %r14,%r9 + BASR_R14_R9 j .Lsysc_tracenogo /* @@ -634,9 +696,9 @@ ENTRY(pgm_check_handler) nill %r10,0x007f sll %r10,2 je .Lpgm_return - lgf %r1,0(%r10,%r1) # load address of handler routine + lgf %r9,0(%r10,%r1) # load address of handler routine lgr %r2,%r11 # pass pointer to pt_regs - basr %r14,%r1 # branch to interrupt-handler + BASR_R14_R9 # branch to interrupt-handler .Lpgm_return: LOCKDEP_SYS_EXIT tm __PT_PSW+1(%r11),0x01 # returning to user ? @@ -914,7 +976,7 @@ ENTRY(psw_idle) stpt __TIMER_IDLE_ENTER(%r2) .Lpsw_idle_lpsw: lpswe __SF_EMPTY(%r15) - br %r14 + BR_R1USE_R14 .Lpsw_idle_end: /* @@ -928,7 +990,7 @@ ENTRY(save_fpu_regs) lg %r2,__LC_CURRENT aghi %r2,__TASK_thread TSTMSK __LC_CPU_FLAGS,_CIF_FPU - bor %r14 + jo .Lsave_fpu_regs_exit stfpc __THREAD_FPU_fpc(%r2) .Lsave_fpu_regs_fpc_end: lg %r3,__THREAD_FPU_regs(%r2) @@ -958,7 +1020,8 @@ ENTRY(save_fpu_regs) std 15,120(%r3) .Lsave_fpu_regs_done: oi __LC_CPU_FLAGS+7,_CIF_FPU - br %r14 +.Lsave_fpu_regs_exit: + BR_R1USE_R14 .Lsave_fpu_regs_end: #if IS_ENABLED(CONFIG_KVM) EXPORT_SYMBOL(save_fpu_regs) @@ -978,7 +1041,7 @@ load_fpu_regs: lg %r4,__LC_CURRENT aghi %r4,__TASK_thread TSTMSK __LC_CPU_FLAGS,_CIF_FPU - bnor %r14 + jno .Lload_fpu_regs_exit lfpc __THREAD_FPU_fpc(%r4) TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX lg %r4,__THREAD_FPU_regs(%r4) # %r4 <- reg save area @@ -1007,7 +1070,8 @@ load_fpu_regs: ld 15,120(%r4) .Lload_fpu_regs_done: ni __LC_CPU_FLAGS+7,255-_CIF_FPU - br %r14 +.Lload_fpu_regs_exit: + BR_R1USE_R14 .Lload_fpu_regs_end: .L__critical_end: @@ -1180,7 +1244,7 @@ cleanup_critical: jl 0f clg %r9,BASED(.Lcleanup_table+104) # .Lload_fpu_regs_end jl .Lcleanup_load_fpu_regs -0: br %r14 +0: BR_R11USE_R14 .align 8 .Lcleanup_table: @@ -1210,7 +1274,7 @@ cleanup_critical: ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce larl %r9,sie_exit # skip forward to sie_exit - br %r14 + BR_R11USE_R14 #endif .Lcleanup_system_call: @@ -1267,7 +1331,7 @@ cleanup_critical: stg %r15,56(%r11) # r15 stack pointer # set new psw address and exit larl %r9,.Lsysc_do_svc - br %r14 + BR_R11USE_R14 .Lcleanup_system_call_insn: .quad system_call .quad .Lsysc_stmg @@ -1277,7 +1341,7 @@ cleanup_critical: .Lcleanup_sysc_tif: larl %r9,.Lsysc_tif - br %r14 + BR_R11USE_R14 .Lcleanup_sysc_restore: # check if stpt has been executed @@ -1294,14 +1358,14 @@ cleanup_critical: mvc 0(64,%r11),__PT_R8(%r9) lmg %r0,%r7,__PT_R0(%r9) 1: lmg %r8,%r9,__LC_RETURN_PSW - br %r14 + BR_R11USE_R14 .Lcleanup_sysc_restore_insn: .quad .Lsysc_exit_timer .quad .Lsysc_done - 4 .Lcleanup_io_tif: larl %r9,.Lio_tif - br %r14 + BR_R11USE_R14 .Lcleanup_io_restore: # check if stpt has been executed @@ -1315,7 +1379,7 @@ cleanup_critical: mvc 0(64,%r11),__PT_R8(%r9) lmg %r0,%r7,__PT_R0(%r9) 1: lmg %r8,%r9,__LC_RETURN_PSW - br %r14 + BR_R11USE_R14 .Lcleanup_io_restore_insn: .quad .Lio_exit_timer .quad .Lio_done - 4 @@ -1368,17 +1432,17 @@ cleanup_critical: # prepare return psw nihh %r8,0xfcfd # clear irq & wait state bits lg %r9,48(%r11) # return from psw_idle - br %r14 + BR_R11USE_R14 .Lcleanup_idle_insn: .quad .Lpsw_idle_lpsw .Lcleanup_save_fpu_regs: larl %r9,save_fpu_regs - br %r14 + BR_R11USE_R14 .Lcleanup_load_fpu_regs: larl %r9,load_fpu_regs - br %r14 + BR_R11USE_R14 /* * Integer constants @@ -1394,7 +1458,6 @@ cleanup_critical: .Lsie_critical_length: .quad .Lsie_done - .Lsie_gmap #endif - .section .rodata, "a" #define SYSCALL(esame,emu) .long esame .globl sys_call_table diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 6f68259bf80e..f461b09b3e85 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #if 0 #define DEBUGP printk @@ -168,7 +170,11 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, me->arch.got_offset = me->core_layout.size; me->core_layout.size += me->arch.got_size; me->arch.plt_offset = me->core_layout.size; - me->core_layout.size += me->arch.plt_size; + if (me->arch.plt_size) { + if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_call_disable) + me->arch.plt_size += PLT_ENTRY_SIZE; + me->core_layout.size += me->arch.plt_size; + } return 0; } @@ -322,9 +328,21 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, unsigned int *ip; ip = me->core_layout.base + me->arch.plt_offset + info->plt_offset; - ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */ - ip[1] = 0x100a0004; - ip[2] = 0x07f10000; + ip[0] = 0x0d10e310; /* basr 1,0 */ + ip[1] = 0x100a0004; /* lg 1,10(1) */ + if (IS_ENABLED(CONFIG_EXPOLINE) && + !nospec_call_disable) { + unsigned int *ij; + ij = me->core_layout.base + + me->arch.plt_offset + + me->arch.plt_size - PLT_ENTRY_SIZE; + ip[2] = 0xa7f40000 + /* j __jump_r1 */ + (unsigned int)(u16) + (((unsigned long) ij - 8 - + (unsigned long) ip) / 2); + } else { + ip[2] = 0x07f10000; /* br %r1 */ + } ip[3] = (unsigned int) (val >> 32); ip[4] = (unsigned int) val; info->plt_initialized = 1; @@ -430,16 +448,42 @@ int module_finalize(const Elf_Ehdr *hdr, struct module *me) { const Elf_Shdr *s; - char *secstrings; + char *secstrings, *secname; + void *aseg; + + if (IS_ENABLED(CONFIG_EXPOLINE) && + !nospec_call_disable && me->arch.plt_size) { + unsigned int *ij; + + ij = me->core_layout.base + me->arch.plt_offset + + me->arch.plt_size - PLT_ENTRY_SIZE; + if (test_facility(35)) { + ij[0] = 0xc6000000; /* exrl %r0,.+10 */ + ij[1] = 0x0005a7f4; /* j . */ + ij[2] = 0x000007f1; /* br %r1 */ + } else { + ij[0] = 0x44000000 | (unsigned int) + offsetof(struct lowcore, br_r1_trampoline); + ij[1] = 0xa7f40000; /* j . */ + } + } secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { - if (!strcmp(".altinstructions", secstrings + s->sh_name)) { - /* patch .altinstructions */ - void *aseg = (void *)s->sh_addr; + aseg = (void *) s->sh_addr; + secname = secstrings + s->sh_name; + if (!strcmp(".altinstructions", secname)) + /* patch .altinstructions */ apply_alternatives(aseg, aseg + s->sh_size); - } + + if (IS_ENABLED(CONFIG_EXPOLINE) && + (!strcmp(".nospec_call_table", secname))) + nospec_call_revert(aseg, aseg + s->sh_size); + + if (IS_ENABLED(CONFIG_EXPOLINE) && + (!strcmp(".nospec_return_table", secname))) + nospec_return_revert(aseg, aseg + s->sh_size); } jump_label_apply_nops(me); diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c new file mode 100644 index 000000000000..86ee26a612cf --- /dev/null +++ b/arch/s390/kernel/nospec-branch.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +int nospec_call_disable = IS_ENABLED(EXPOLINE_OFF); +int nospec_return_disable = !IS_ENABLED(EXPOLINE_FULL); + +static int __init nospectre_v2_setup_early(char *str) +{ + nospec_call_disable = 1; + nospec_return_disable = 1; + return 0; +} +early_param("nospectre_v2", nospectre_v2_setup_early); + +static int __init spectre_v2_setup_early(char *str) +{ + if (str && !strncmp(str, "on", 2)) { + nospec_call_disable = 0; + nospec_return_disable = 0; + } + if (str && !strncmp(str, "off", 3)) { + nospec_call_disable = 1; + nospec_return_disable = 1; + } + if (str && !strncmp(str, "auto", 4)) { + nospec_call_disable = 0; + nospec_return_disable = 1; + } + return 0; +} +early_param("spectre_v2", spectre_v2_setup_early); + +static void __init_or_module __nospec_revert(s32 *start, s32 *end) +{ + enum { BRCL_EXPOLINE, BRASL_EXPOLINE } type; + u8 *instr, *thunk, *br; + u8 insnbuf[6]; + s32 *epo; + + /* Second part of the instruction replace is always a nop */ + memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x00, 0x00 }, 4); + for (epo = start; epo < end; epo++) { + instr = (u8 *) epo + *epo; + if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x04) + type = BRCL_EXPOLINE; /* brcl instruction */ + else if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x05) + type = BRASL_EXPOLINE; /* brasl instruction */ + else + continue; + thunk = instr + (*(int *)(instr + 2)) * 2; + if (thunk[0] == 0xc6 && thunk[1] == 0x00) + /* exrl %r0, */ + br = thunk + (*(int *)(thunk + 2)) * 2; + else if (thunk[0] == 0xc0 && (thunk[1] & 0x0f) == 0x00 && + thunk[6] == 0x44 && thunk[7] == 0x00 && + (thunk[8] & 0x0f) == 0x00 && thunk[9] == 0x00 && + (thunk[1] & 0xf0) == (thunk[8] & 0xf0)) + /* larl %rx, + ex %r0,0(%rx) */ + br = thunk + (*(int *)(thunk + 2)) * 2; + else + continue; + if (br[0] != 0x07 || (br[1] & 0xf0) != 0xf0) + continue; + switch (type) { + case BRCL_EXPOLINE: + /* brcl to thunk, replace with br + nop */ + insnbuf[0] = br[0]; + insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f); + break; + case BRASL_EXPOLINE: + /* brasl to thunk, replace with basr + nop */ + insnbuf[0] = 0x0d; + insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f); + break; + } + + s390_kernel_write(instr, insnbuf, 6); + } +} + +void __init_or_module nospec_call_revert(s32 *start, s32 *end) +{ + if (nospec_call_disable) + __nospec_revert(start, end); +} + +void __init_or_module nospec_return_revert(s32 *start, s32 *end) +{ + if (nospec_return_disable) + __nospec_revert(start, end); +} + +extern s32 __nospec_call_start[], __nospec_call_end[]; +extern s32 __nospec_return_start[], __nospec_return_end[]; +void __init nospec_init_branches(void) +{ + nospec_call_revert(__nospec_call_start, __nospec_call_end); + nospec_return_revert(__nospec_return_start, __nospec_return_end); +} diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 433b380896b9..bc25366f0244 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -64,6 +64,7 @@ #include #include #include +#include #include "entry.h" /* @@ -375,6 +376,7 @@ static void __init setup_lowcore(void) #ifdef CONFIG_SMP lc->spinlock_lockval = arch_spin_lockval(0); #endif + lc->br_r1_trampoline = 0x07f1; /* br %r1 */ set_prefix((u32)(unsigned long) lc); lowcore_ptr[0] = lc; @@ -935,6 +937,8 @@ void __init setup_arch(char **cmdline_p) set_preferred_console(); apply_alternative_instructions(); + if (IS_ENABLED(CONFIG_EXPOLINE)) + nospec_init_branches(); /* Setup zfcpdump support */ setup_zfcpdump(); diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index b34ff0798d38..0a31110f41f6 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -205,6 +205,7 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) lc->panic_stack = panic_stack + PANIC_FRAME_OFFSET; lc->cpu_nr = cpu; lc->spinlock_lockval = arch_spin_lockval(cpu); + lc->br_r1_trampoline = 0x07f1; /* br %r1 */ if (MACHINE_HAS_VX) lc->vector_save_area_addr = (unsigned long) &lc->vector_save_area; diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index b8ec50cb1b6f..dd96b467946b 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -122,6 +122,20 @@ SECTIONS *(.altinstr_replacement) } + /* + * Table with the patch locations to undo expolines + */ + .nospec_call_table : { + __nospec_call_start = . ; + *(.s390_indirect*) + __nospec_call_end = . ; + } + .nospec_return_table : { + __nospec_return_start = . ; + *(.s390_return*) + __nospec_return_end = . ; + } + /* early.c uses stsi, which requires page aligned data. */ . = ALIGN(PAGE_SIZE); INIT_DATA_SECTION(0x100) diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 41e28b23b26a..8ac27efe34fc 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -2,6 +2,8 @@ # S/390 character devices # +CFLAGS_REMOVE_sclp_early_core.o += $(CC_FLAGS_EXPOLINE) + obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \ sclp_early.o -- GitLab From 2a0b0e13a8dedcc366fa59656fbcad45c632ac92 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 27 Apr 2018 07:36:48 +0200 Subject: [PATCH 060/855] KVM: s390: force bp isolation for VSIE [ Upstream commit f315104ad8b0c32be13eac628569ae707c332cb5 ] If the guest runs with bp isolation when doing a SIE instruction, we must also run the nested guest with bp isolation when emulating that SIE instruction. This is done by activating BPBC in the lpar, which acts as an override for lower level guests. Signed-off-by: Christian Borntraeger Reviewed-by: Janosch Frank Reviewed-by: David Hildenbrand Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kvm/vsie.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index e56b7724054c..ced6c9b8f04d 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -764,6 +764,7 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) { struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; + int guest_bp_isolation; int rc; handle_last_fault(vcpu, vsie_page); @@ -774,6 +775,20 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) s390_handle_mcck(); srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); + + /* save current guest state of bp isolation override */ + guest_bp_isolation = test_thread_flag(TIF_ISOLATE_BP_GUEST); + + /* + * The guest is running with BPBC, so we have to force it on for our + * nested guest. This is done by enabling BPBC globally, so the BPBC + * control in the SCB (which the nested guest can modify) is simply + * ignored. + */ + if (test_kvm_facility(vcpu->kvm, 82) && + vcpu->arch.sie_block->fpf & FPF_BPBC) + set_thread_flag(TIF_ISOLATE_BP_GUEST); + local_irq_disable(); guest_enter_irqoff(); local_irq_enable(); @@ -783,6 +798,11 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) local_irq_disable(); guest_exit_irqoff(); local_irq_enable(); + + /* restore guest state for bp isolation override */ + if (!guest_bp_isolation) + clear_thread_flag(TIF_ISOLATE_BP_GUEST); + vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); if (rc > 0) -- GitLab From 49a48a0ec7c1f078fc6215ccaf2a5d277c5495c0 Mon Sep 17 00:00:00 2001 From: Eugeniu Rosca Date: Fri, 27 Apr 2018 07:36:49 +0200 Subject: [PATCH 061/855] s390: Replace IS_ENABLED(EXPOLINE_*) with IS_ENABLED(CONFIG_EXPOLINE_*) [ Upstream commit 2cb370d615e9fbed9e95ed222c2c8f337181aa90 ] I've accidentally stumbled upon the IS_ENABLED(EXPOLINE_*) lines, which obviously always evaluate to false. Fix this. Fixes: f19fbd5ed642 ("s390: introduce execute-trampolines for branches") Signed-off-by: Eugeniu Rosca Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/nospec-branch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 86ee26a612cf..57f55c24c21c 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -3,8 +3,8 @@ #include #include -int nospec_call_disable = IS_ENABLED(EXPOLINE_OFF); -int nospec_return_disable = !IS_ENABLED(EXPOLINE_FULL); +int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); +int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL); static int __init nospectre_v2_setup_early(char *str) { -- GitLab From 7ae60d00c31e5db697a1518ce94749a0852c1d0c Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:50 +0200 Subject: [PATCH 062/855] s390: do not bypass BPENTER for interrupt system calls [ Upstream commit d5feec04fe578c8dbd9e2e1439afc2f0af761ed4 ] The system call path can be interrupted before the switch back to the standard branch prediction with BPENTER has been done. The critical section cleanup code skips forward to .Lsysc_do_svc and bypasses the BPENTER. In this case the kernel and all subsequent code will run with the limited branch prediction. Fixes: eacf67eb9b32 ("s390: run user space and KVM guests with modified branch prediction") Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/entry.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 8cbe75d7353d..c3e28af207cf 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -1316,7 +1316,8 @@ cleanup_critical: srag %r9,%r9,23 jz 0f mvc __TI_last_break(8,%r12),16(%r11) -0: # set up saved register r11 +0: BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP + # set up saved register r11 lg %r15,__LC_KERNEL_STACK la %r9,STACK_FRAME_OVERHEAD(%r15) stg %r9,24(%r11) # r11 pt_regs pointer -- GitLab From 7634817fc5fad945d67c578f04c731ce25dc86bc Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 27 Apr 2018 07:36:51 +0200 Subject: [PATCH 063/855] s390/entry.S: fix spurious zeroing of r0 [ Upstream commit d3f468963cd6fd6d2aa5e26aed8b24232096d0e1 ] when a system call is interrupted we might call the critical section cleanup handler that re-does some of the operations. When we are between .Lsysc_vtime and .Lsysc_do_svc we might also redo the saving of the problem state registers r0-r7: .Lcleanup_system_call: [...] 0: # update accounting time stamp mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER # set up saved register r11 lg %r15,__LC_KERNEL_STACK la %r9,STACK_FRAME_OVERHEAD(%r15) stg %r9,24(%r11) # r11 pt_regs pointer # fill pt_regs mvc __PT_R8(64,%r9),__LC_SAVE_AREA_SYNC ---> stmg %r0,%r7,__PT_R0(%r9) The problem is now, that we might have already zeroed out r0. The fix is to move the zeroing of r0 after sysc_do_svc. Reported-by: Farhan Ali Fixes: 7041d28115e91 ("s390: scrub registers on kernel entry and KVM exit") Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky Signed-off-by: Martin Schwidefsky Signed-off-by: Martin Schwidefsky Signed-off-by: Martin Schwidefsky Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/entry.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index c3e28af207cf..1996afeb2e81 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -434,13 +434,13 @@ ENTRY(system_call) UPDATE_VTIME %r10,%r13,__LC_SYNC_ENTER_TIMER BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP stmg %r0,%r7,__PT_R0(%r11) - # clear user controlled register to prevent speculative use - xgr %r0,%r0 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC stg %r14,__PT_FLAGS(%r11) .Lsysc_do_svc: + # clear user controlled register to prevent speculative use + xgr %r0,%r0 lg %r10,__TI_sysc_table(%r12) # address of system call table llgh %r8,__PT_INT_CODE+2(%r11) slag %r8,%r8,2 # shift and test for svc 0 -- GitLab From 2afb4e9dfc0a44a4b616e4461fbf972e5ad4b0fe Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:52 +0200 Subject: [PATCH 064/855] s390: move nobp parameter functions to nospec-branch.c [ Upstream commit b2e2f43a01bace1a25bdbae04c9f9846882b727a ] Keep the code for the nobp parameter handling with the code for expolines. Both are related to the spectre v2 mitigation. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/Makefile | 4 ++-- arch/s390/kernel/alternative.c | 23 ----------------------- arch/s390/kernel/nospec-branch.c | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 1c3e5d529cc1..0501cac2ab95 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -59,11 +59,11 @@ obj-y += debug.o irq.o ipl.o dis.o diag.o sclp.o vdso.o als.o obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o obj-y += runtime_instr.o cache.o fpu.o dumpstack.o obj-y += entry.o reipl.o relocate_kernel.o alternative.o +obj-y += nospec-branch.o extra-y += head.o head64.o vmlinux.lds -obj-$(CONFIG_EXPOLINE) += nospec-branch.o -CFLAGS_REMOVE_expoline.o += $(CC_FLAGS_EXPOLINE) +CFLAGS_REMOVE_nospec-branch.o += $(CC_FLAGS_EXPOLINE) obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c index ed21de98b79e..f5060af61176 100644 --- a/arch/s390/kernel/alternative.c +++ b/arch/s390/kernel/alternative.c @@ -14,29 +14,6 @@ static int __init disable_alternative_instructions(char *str) early_param("noaltinstr", disable_alternative_instructions); -static int __init nobp_setup_early(char *str) -{ - bool enabled; - int rc; - - rc = kstrtobool(str, &enabled); - if (rc) - return rc; - if (enabled && test_facility(82)) - __set_facility(82, S390_lowcore.alt_stfle_fac_list); - else - __clear_facility(82, S390_lowcore.alt_stfle_fac_list); - return 0; -} -early_param("nobp", nobp_setup_early); - -static int __init nospec_setup_early(char *str) -{ - __clear_facility(82, S390_lowcore.alt_stfle_fac_list); - return 0; -} -early_param("nospec", nospec_setup_early); - struct brcl_insn { u16 opc; s32 disp; diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 57f55c24c21c..3ce59d044a4d 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -3,6 +3,31 @@ #include #include +static int __init nobp_setup_early(char *str) +{ + bool enabled; + int rc; + + rc = kstrtobool(str, &enabled); + if (rc) + return rc; + if (enabled && test_facility(82)) + __set_facility(82, S390_lowcore.alt_stfle_fac_list); + else + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + return 0; +} +early_param("nobp", nobp_setup_early); + +static int __init nospec_setup_early(char *str) +{ + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + return 0; +} +early_param("nospec", nospec_setup_early); + +#ifdef CONFIG_EXPOLINE + int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL); @@ -99,3 +124,5 @@ void __init nospec_init_branches(void) nospec_call_revert(__nospec_call_start, __nospec_call_end); nospec_return_revert(__nospec_return_start, __nospec_return_end); } + +#endif /* CONFIG_EXPOLINE */ -- GitLab From 3e17958c6b3159cebc09f24344176e9a12b15e30 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:53 +0200 Subject: [PATCH 065/855] s390: add automatic detection of the spectre defense [ Upstream commit 6e179d64126b909f0b288fa63cdbf07c531e9b1d ] Automatically decide between nobp vs. expolines if the spectre_v2=auto kernel parameter is specified or CONFIG_EXPOLINE_AUTO=y is set. The decision made at boot time due to CONFIG_EXPOLINE_AUTO=y being set can be overruled with the nobp, nospec and spectre_v2 kernel parameters. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/Kconfig | 2 +- arch/s390/Makefile | 2 +- arch/s390/include/asm/nospec-branch.h | 6 +-- arch/s390/kernel/alternative.c | 1 + arch/s390/kernel/module.c | 11 ++--- arch/s390/kernel/nospec-branch.c | 68 +++++++++++++++++---------- 6 files changed, 52 insertions(+), 38 deletions(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index c88bb4a50db7..fbb8fca6f9c2 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -741,7 +741,7 @@ choice config EXPOLINE_OFF bool "spectre_v2=off" -config EXPOLINE_MEDIUM +config EXPOLINE_AUTO bool "spectre_v2=auto" config EXPOLINE_FULL diff --git a/arch/s390/Makefile b/arch/s390/Makefile index d241a9fddf43..bef67c0f63e2 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -85,7 +85,7 @@ ifdef CONFIG_EXPOLINE CC_FLAGS_EXPOLINE += -mfunction-return=thunk CC_FLAGS_EXPOLINE += -mindirect-branch-table export CC_FLAGS_EXPOLINE - cflags-y += $(CC_FLAGS_EXPOLINE) + cflags-y += $(CC_FLAGS_EXPOLINE) -DCC_USING_EXPOLINE endif endif diff --git a/arch/s390/include/asm/nospec-branch.h b/arch/s390/include/asm/nospec-branch.h index 7df48e5cf36f..35bf28fe4c64 100644 --- a/arch/s390/include/asm/nospec-branch.h +++ b/arch/s390/include/asm/nospec-branch.h @@ -6,12 +6,10 @@ #include -extern int nospec_call_disable; -extern int nospec_return_disable; +extern int nospec_disable; void nospec_init_branches(void); -void nospec_call_revert(s32 *start, s32 *end); -void nospec_return_revert(s32 *start, s32 *end); +void nospec_revert(s32 *start, s32 *end); #endif /* __ASSEMBLY__ */ diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c index f5060af61176..b57b293998dc 100644 --- a/arch/s390/kernel/alternative.c +++ b/arch/s390/kernel/alternative.c @@ -1,6 +1,7 @@ #include #include #include +#include #define MAX_PATCH_LEN (255 - 1) diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index f461b09b3e85..f3f7321bef1a 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -171,7 +171,7 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, me->core_layout.size += me->arch.got_size; me->arch.plt_offset = me->core_layout.size; if (me->arch.plt_size) { - if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_call_disable) + if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) me->arch.plt_size += PLT_ENTRY_SIZE; me->core_layout.size += me->arch.plt_size; } @@ -330,8 +330,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, info->plt_offset; ip[0] = 0x0d10e310; /* basr 1,0 */ ip[1] = 0x100a0004; /* lg 1,10(1) */ - if (IS_ENABLED(CONFIG_EXPOLINE) && - !nospec_call_disable) { + if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) { unsigned int *ij; ij = me->core_layout.base + me->arch.plt_offset + @@ -452,7 +451,7 @@ int module_finalize(const Elf_Ehdr *hdr, void *aseg; if (IS_ENABLED(CONFIG_EXPOLINE) && - !nospec_call_disable && me->arch.plt_size) { + !nospec_disable && me->arch.plt_size) { unsigned int *ij; ij = me->core_layout.base + me->arch.plt_offset + @@ -479,11 +478,11 @@ int module_finalize(const Elf_Ehdr *hdr, if (IS_ENABLED(CONFIG_EXPOLINE) && (!strcmp(".nospec_call_table", secname))) - nospec_call_revert(aseg, aseg + s->sh_size); + nospec_revert(aseg, aseg + s->sh_size); if (IS_ENABLED(CONFIG_EXPOLINE) && (!strcmp(".nospec_return_table", secname))) - nospec_return_revert(aseg, aseg + s->sh_size); + nospec_revert(aseg, aseg + s->sh_size); } jump_label_apply_nops(me); diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 3ce59d044a4d..daa36a38a8b7 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -11,10 +11,17 @@ static int __init nobp_setup_early(char *str) rc = kstrtobool(str, &enabled); if (rc) return rc; - if (enabled && test_facility(82)) + if (enabled && test_facility(82)) { + /* + * The user explicitely requested nobp=1, enable it and + * disable the expoline support. + */ __set_facility(82, S390_lowcore.alt_stfle_fac_list); - else + if (IS_ENABLED(CONFIG_EXPOLINE)) + nospec_disable = 1; + } else { __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + } return 0; } early_param("nobp", nobp_setup_early); @@ -28,31 +35,46 @@ early_param("nospec", nospec_setup_early); #ifdef CONFIG_EXPOLINE -int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); -int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL); +int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); static int __init nospectre_v2_setup_early(char *str) { - nospec_call_disable = 1; - nospec_return_disable = 1; + nospec_disable = 1; return 0; } early_param("nospectre_v2", nospectre_v2_setup_early); +static int __init spectre_v2_auto_early(void) +{ + if (IS_ENABLED(CC_USING_EXPOLINE)) { + /* + * The kernel has been compiled with expolines. + * Keep expolines enabled and disable nobp. + */ + nospec_disable = 0; + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + } + /* + * If the kernel has not been compiled with expolines the + * nobp setting decides what is done, this depends on the + * CONFIG_KERNEL_NP option and the nobp/nospec parameters. + */ + return 0; +} +#ifdef CONFIG_EXPOLINE_AUTO +early_initcall(spectre_v2_auto_early); +#endif + static int __init spectre_v2_setup_early(char *str) { if (str && !strncmp(str, "on", 2)) { - nospec_call_disable = 0; - nospec_return_disable = 0; - } - if (str && !strncmp(str, "off", 3)) { - nospec_call_disable = 1; - nospec_return_disable = 1; - } - if (str && !strncmp(str, "auto", 4)) { - nospec_call_disable = 0; - nospec_return_disable = 1; + nospec_disable = 0; + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); } + if (str && !strncmp(str, "off", 3)) + nospec_disable = 1; + if (str && !strncmp(str, "auto", 4)) + spectre_v2_auto_early(); return 0; } early_param("spectre_v2", spectre_v2_setup_early); @@ -105,15 +127,9 @@ static void __init_or_module __nospec_revert(s32 *start, s32 *end) } } -void __init_or_module nospec_call_revert(s32 *start, s32 *end) -{ - if (nospec_call_disable) - __nospec_revert(start, end); -} - -void __init_or_module nospec_return_revert(s32 *start, s32 *end) +void __init_or_module nospec_revert(s32 *start, s32 *end) { - if (nospec_return_disable) + if (nospec_disable) __nospec_revert(start, end); } @@ -121,8 +137,8 @@ extern s32 __nospec_call_start[], __nospec_call_end[]; extern s32 __nospec_return_start[], __nospec_return_end[]; void __init nospec_init_branches(void) { - nospec_call_revert(__nospec_call_start, __nospec_call_end); - nospec_return_revert(__nospec_return_start, __nospec_return_end); + nospec_revert(__nospec_call_start, __nospec_call_end); + nospec_revert(__nospec_return_start, __nospec_return_end); } #endif /* CONFIG_EXPOLINE */ -- GitLab From 4a51204f8b38e5533d0abf110dc922210b2b5f62 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:54 +0200 Subject: [PATCH 066/855] s390: report spectre mitigation via syslog [ Upstream commit bc035599718412cfba9249aa713f90ef13f13ee9 ] Add a boot message if either of the spectre defenses is active. The message is "Spectre V2 mitigation: execute trampolines." or "Spectre V2 mitigation: limited branch prediction." Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/nospec-branch.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index daa36a38a8b7..7387ebace891 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -33,6 +33,16 @@ static int __init nospec_setup_early(char *str) } early_param("nospec", nospec_setup_early); +static int __init nospec_report(void) +{ + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) + pr_info("Spectre V2 mitigation: execute trampolines.\n"); + if (__test_facility(82, S390_lowcore.alt_stfle_fac_list)) + pr_info("Spectre V2 mitigation: limited branch prediction.\n"); + return 0; +} +arch_initcall(nospec_report); + #ifdef CONFIG_EXPOLINE int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); -- GitLab From fa90b9a2b63e2d84d169cb640f47fc6d9af17c6c Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:55 +0200 Subject: [PATCH 067/855] s390: add sysfs attributes for spectre [ Upstream commit d424986f1d6b16079b3231db0314923f4f8deed1 ] Set CONFIG_GENERIC_CPU_VULNERABILITIES and provide the two functions cpu_show_spectre_v1 and cpu_show_spectre_v2 to report the spectre mitigations. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/Kconfig | 1 + arch/s390/kernel/nospec-branch.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index fbb8fca6f9c2..1c4a595e8224 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -118,6 +118,7 @@ config S390 select GENERIC_CLOCKEVENTS select GENERIC_CPU_AUTOPROBE select GENERIC_CPU_DEVICES if !SMP + select GENERIC_CPU_VULNERABILITIES select GENERIC_FIND_FIRST_BIT select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 7387ebace891..73c06d42792d 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include #include @@ -43,6 +44,24 @@ static int __init nospec_report(void) } arch_initcall(nospec_report); +#ifdef CONFIG_SYSFS +ssize_t cpu_show_spectre_v1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Mitigation: __user pointer sanitization\n"); +} + +ssize_t cpu_show_spectre_v2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) + return sprintf(buf, "Mitigation: execute trampolines\n"); + if (__test_facility(82, S390_lowcore.alt_stfle_fac_list)) + return sprintf(buf, "Mitigation: limited branch prediction.\n"); + return sprintf(buf, "Vulnerable\n"); +} +#endif + #ifdef CONFIG_EXPOLINE int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); -- GitLab From 906cd975f6d4bcfdf26a12f4e13e826d089a42a3 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:56 +0200 Subject: [PATCH 068/855] s390: correct nospec auto detection init order [ Upstream commit 6a3d1e81a434fc311f224b8be77258bafc18ccc6 ] With CONFIG_EXPOLINE_AUTO=y the call of spectre_v2_auto_early() via early_initcall is done *after* the early_param functions. This overwrites any settings done with the nobp/no_spectre_v2/spectre_v2 parameters. The code patching for the kernel is done after the evaluation of the early parameters but before the early_initcall is done. The end result is a kernel image that is patched correctly but the kernel modules are not. Make sure that the nospec auto detection function is called before the early parameters are evaluated and before the code patching is done. Fixes: 6e179d64126b ("s390: add automatic detection of the spectre defense") Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/nospec-branch.h | 1 + arch/s390/kernel/nospec-branch.c | 8 ++------ arch/s390/kernel/setup.c | 3 +++ 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/s390/include/asm/nospec-branch.h b/arch/s390/include/asm/nospec-branch.h index 35bf28fe4c64..b4bd8c41e9d3 100644 --- a/arch/s390/include/asm/nospec-branch.h +++ b/arch/s390/include/asm/nospec-branch.h @@ -9,6 +9,7 @@ extern int nospec_disable; void nospec_init_branches(void); +void nospec_auto_detect(void); void nospec_revert(s32 *start, s32 *end); #endif /* __ASSEMBLY__ */ diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 73c06d42792d..9f3b5b382743 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -73,7 +73,7 @@ static int __init nospectre_v2_setup_early(char *str) } early_param("nospectre_v2", nospectre_v2_setup_early); -static int __init spectre_v2_auto_early(void) +void __init nospec_auto_detect(void) { if (IS_ENABLED(CC_USING_EXPOLINE)) { /* @@ -88,11 +88,7 @@ static int __init spectre_v2_auto_early(void) * nobp setting decides what is done, this depends on the * CONFIG_KERNEL_NP option and the nobp/nospec parameters. */ - return 0; } -#ifdef CONFIG_EXPOLINE_AUTO -early_initcall(spectre_v2_auto_early); -#endif static int __init spectre_v2_setup_early(char *str) { @@ -103,7 +99,7 @@ static int __init spectre_v2_setup_early(char *str) if (str && !strncmp(str, "off", 3)) nospec_disable = 1; if (str && !strncmp(str, "auto", 4)) - spectre_v2_auto_early(); + nospec_auto_detect(); return 0; } early_param("spectre_v2", spectre_v2_setup_early); diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index bc25366f0244..feb9d97a9d14 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -876,6 +876,9 @@ void __init setup_arch(char **cmdline_p) init_mm.end_data = (unsigned long) &_edata; init_mm.brk = (unsigned long) &_end; + if (IS_ENABLED(CONFIG_EXPOLINE_AUTO)) + nospec_auto_detect(); + parse_early_param(); #ifdef CONFIG_CRASH_DUMP /* Deactivate elfcorehdr= kernel parameter */ -- GitLab From 037069f2c62510b23dbc67b6894a1c152562f7b5 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:57 +0200 Subject: [PATCH 069/855] s390: correct module section names for expoline code revert [ Upstream commit 6cf09958f32b9667bb3ebadf74367c791112771b ] The main linker script vmlinux.lds.S for the kernel image merges the expoline code patch tables into two section ".nospec_call_table" and ".nospec_return_table". This is *not* done for the modules, there the sections retain their original names as generated by gcc: ".s390_indirect_call", ".s390_return_mem" and ".s390_return_reg". The module_finalize code has to check for the compiler generated section names, otherwise no code patching is done. This slows down the module code in case of "spectre_v2=off". Cc: stable@vger.kernel.org # 4.16 Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches") Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/module.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index f3f7321bef1a..64ccfdf96b32 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -477,11 +477,11 @@ int module_finalize(const Elf_Ehdr *hdr, apply_alternatives(aseg, aseg + s->sh_size); if (IS_ENABLED(CONFIG_EXPOLINE) && - (!strcmp(".nospec_call_table", secname))) + (!strncmp(".s390_indirect", secname, 14))) nospec_revert(aseg, aseg + s->sh_size); if (IS_ENABLED(CONFIG_EXPOLINE) && - (!strcmp(".nospec_return_table", secname))) + (!strncmp(".s390_return", secname, 12))) nospec_revert(aseg, aseg + s->sh_size); } -- GitLab From a43e7cba5444f062defc2145fe0b83b28ac35d5f Mon Sep 17 00:00:00 2001 From: Xin Long Date: Sun, 22 Apr 2018 19:11:50 +0800 Subject: [PATCH 070/855] bonding: do not set slave_dev npinfo before slave_enable_netpoll in bond_enslave [ Upstream commit ddea788c63094f7c483783265563dd5b50052e28 ] After Commit 8a8efa22f51b ("bonding: sync netpoll code with bridge"), it would set slave_dev npinfo in slave_enable_netpoll when enslaving a dev if bond->dev->npinfo was set. However now slave_dev npinfo is set with bond->dev->npinfo before calling slave_enable_netpoll. With slave_dev npinfo set, __netpoll_setup called in slave_enable_netpoll will not call slave dev's .ndo_netpoll_setup(). It causes that the lower dev of this slave dev can't set its npinfo. One way to reproduce it: # modprobe bonding # brctl addbr br0 # brctl addif br0 eth1 # ifconfig bond0 192.168.122.1/24 up # ifenslave bond0 eth2 # systemctl restart netconsole # ifenslave bond0 br0 # ifconfig eth2 down # systemctl restart netconsole The netpoll won't really work. This patch is to remove that slave_dev npinfo setting in bond_enslave(). Fixes: 8a8efa22f51b ("bonding: sync netpoll code with bridge") Signed-off-by: Xin Long Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 513457a2a7bf..13a015b8052b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1654,8 +1654,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } /* switch(bond_mode) */ #ifdef CONFIG_NET_POLL_CONTROLLER - slave_dev->npinfo = bond->dev->npinfo; - if (slave_dev->npinfo) { + if (bond->dev->npinfo) { if (slave_enable_netpoll(new_slave)) { netdev_info(bond_dev, "master_dev is using netpoll, but new slave device does not support netpoll\n"); res = -EBUSY; -- GitLab From 06a02a81689074406d70979837518b1f747767af Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 17 Apr 2018 12:07:06 -0700 Subject: [PATCH 071/855] KEYS: DNS: limit the length of option strings [ Upstream commit 9c438d7a3a52dcc2b9ed095cb87d3a5e83cf7e60 ] Adding a dns_resolver key whose payload contains a very long option name resulted in that string being printed in full. This hit the WARN_ONCE() in set_precision() during the printk(), because printk() only supports a precision of up to 32767 bytes: precision 1000000 too large WARNING: CPU: 0 PID: 752 at lib/vsprintf.c:2189 vsnprintf+0x4bc/0x5b0 Fix it by limiting option strings (combined name + value) to a much more reasonable 128 bytes. The exact limit is arbitrary, but currently the only recognized option is formatted as "dnserror=%lu" which fits well within this limit. Also ratelimit the printks. Reproducer: perl -e 'print "#", "A" x 1000000, "\x00"' | keyctl padd dns_resolver desc @s This bug was found using syzkaller. Reported-by: Mark Rutland Fixes: 4a2d789267e0 ("DNS: If the DNS server returns an error, allow that to be cached [ver #2]") Signed-off-by: Eric Biggers Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dns_resolver/dns_key.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index e1d4d898a007..f0252768ecf4 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -91,9 +92,9 @@ dns_resolver_preparse(struct key_preparsed_payload *prep) next_opt = memchr(opt, '#', end - opt) ?: end; opt_len = next_opt - opt; - if (!opt_len) { - printk(KERN_WARNING - "Empty option to dns_resolver key\n"); + if (opt_len <= 0 || opt_len > 128) { + pr_warn_ratelimited("Invalid option length (%d) for dns_resolver key\n", + opt_len); return -EINVAL; } @@ -127,10 +128,8 @@ dns_resolver_preparse(struct key_preparsed_payload *prep) } bad_option_value: - printk(KERN_WARNING - "Option '%*.*s' to dns_resolver key:" - " bad/missing value\n", - opt_nlen, opt_nlen, opt); + pr_warn_ratelimited("Option '%*.*s' to dns_resolver key: bad/missing value\n", + opt_nlen, opt_nlen, opt); return -EINVAL; } while (opt = next_opt + 1, opt < end); } -- GitLab From e9c46600cdf19bd790a0a2e2aeb6675f61d3aed5 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Mon, 23 Apr 2018 16:15:14 +0200 Subject: [PATCH 072/855] l2tp: check sockaddr length in pppol2tp_connect() [ Upstream commit eb1c28c05894a4b1f6b56c5bf072205e64cfa280 ] Check sockaddr_len before dereferencing sp->sa_protocol, to ensure that it actually points to valid data. Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts") Reported-by: syzbot+a70ac890b23b1bf29f5c@syzkaller.appspotmail.com Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_ppp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 163f1fa53917..9b214f313cc0 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -590,6 +590,13 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, lock_sock(sk); error = -EINVAL; + + if (sockaddr_len != sizeof(struct sockaddr_pppol2tp) && + sockaddr_len != sizeof(struct sockaddr_pppol2tpv3) && + sockaddr_len != sizeof(struct sockaddr_pppol2tpin6) && + sockaddr_len != sizeof(struct sockaddr_pppol2tpv3in6)) + goto end; + if (sp->sa_protocol != PX_PROTO_OL2TP) goto end; -- GitLab From 0e770d2927b7b5fed0859ac46861d00f762b2407 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 11 Apr 2018 14:46:00 -0700 Subject: [PATCH 073/855] net: validate attribute sizes in neigh_dump_table() [ Upstream commit 7dd07c143a4b54d050e748bee4b4b9e94a7b1744 ] Since neigh_dump_table() calls nlmsg_parse() without giving policy constraints, attributes can have arbirary size that we must validate Reported by syzbot/KMSAN : BUG: KMSAN: uninit-value in neigh_master_filtered net/core/neighbour.c:2292 [inline] BUG: KMSAN: uninit-value in neigh_dump_table net/core/neighbour.c:2348 [inline] BUG: KMSAN: uninit-value in neigh_dump_info+0x1af0/0x2250 net/core/neighbour.c:2438 CPU: 1 PID: 3575 Comm: syzkaller268891 Not tainted 4.16.0+ #83 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 neigh_master_filtered net/core/neighbour.c:2292 [inline] neigh_dump_table net/core/neighbour.c:2348 [inline] neigh_dump_info+0x1af0/0x2250 net/core/neighbour.c:2438 netlink_dump+0x9ad/0x1540 net/netlink/af_netlink.c:2225 __netlink_dump_start+0x1167/0x12a0 net/netlink/af_netlink.c:2322 netlink_dump_start include/linux/netlink.h:214 [inline] rtnetlink_rcv_msg+0x1435/0x1560 net/core/rtnetlink.c:4598 netlink_rcv_skb+0x355/0x5f0 net/netlink/af_netlink.c:2447 rtnetlink_rcv+0x50/0x60 net/core/rtnetlink.c:4653 netlink_unicast_kernel net/netlink/af_netlink.c:1311 [inline] netlink_unicast+0x1672/0x1750 net/netlink/af_netlink.c:1337 netlink_sendmsg+0x1048/0x1310 net/netlink/af_netlink.c:1900 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2046 __sys_sendmsg net/socket.c:2080 [inline] SYSC_sendmsg+0x2a3/0x3d0 net/socket.c:2091 SyS_sendmsg+0x54/0x80 net/socket.c:2087 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x43fed9 RSP: 002b:00007ffddbee2798 EFLAGS: 00000213 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 000000000043fed9 RDX: 0000000000000000 RSI: 0000000020005000 RDI: 0000000000000003 RBP: 00000000006ca018 R08: 00000000004002c8 R09: 00000000004002c8 R10: 00000000004002c8 R11: 0000000000000213 R12: 0000000000401800 R13: 0000000000401890 R14: 0000000000000000 R15: 0000000000000000 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:188 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:314 kmsan_slab_alloc+0x11/0x20 mm/kmsan/kmsan.c:321 slab_post_alloc_hook mm/slab.h:445 [inline] slab_alloc_node mm/slub.c:2737 [inline] __kmalloc_node_track_caller+0xaed/0x11c0 mm/slub.c:4369 __kmalloc_reserve net/core/skbuff.c:138 [inline] __alloc_skb+0x2cf/0x9f0 net/core/skbuff.c:206 alloc_skb include/linux/skbuff.h:984 [inline] netlink_alloc_large_skb net/netlink/af_netlink.c:1183 [inline] netlink_sendmsg+0x9a6/0x1310 net/netlink/af_netlink.c:1875 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2046 __sys_sendmsg net/socket.c:2080 [inline] SYSC_sendmsg+0x2a3/0x3d0 net/socket.c:2091 SyS_sendmsg+0x54/0x80 net/socket.c:2087 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Fixes: 21fdd092acc7 ("net: Add support for filtering neigh dump by master device") Signed-off-by: Eric Dumazet Cc: David Ahern Reported-by: syzbot Acked-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/neighbour.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index a426790b0688..ce5bbf8b1f67 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2279,12 +2279,16 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL); if (!err) { - if (tb[NDA_IFINDEX]) + if (tb[NDA_IFINDEX]) { + if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32)) + return -EINVAL; filter_idx = nla_get_u32(tb[NDA_IFINDEX]); - - if (tb[NDA_MASTER]) + } + if (tb[NDA_MASTER]) { + if (nla_len(tb[NDA_MASTER]) != sizeof(u32)) + return -EINVAL; filter_master_idx = nla_get_u32(tb[NDA_MASTER]); - + } if (filter_idx || filter_master_idx) flags |= NLM_F_DUMP_FILTERED; } -- GitLab From e202fa9ea5a33723a6dd048e5e272335bfdf8113 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Thu, 19 Apr 2018 12:25:38 -0700 Subject: [PATCH 074/855] llc: delete timers synchronously in llc_sk_free() [ Upstream commit b905ef9ab90115d001c1658259af4b1c65088779 ] The connection timers of an llc sock could be still flying after we delete them in llc_sk_free(), and even possibly after we free the sock. We could just wait synchronously here in case of troubles. Note, I leave other call paths as they are, since they may not have to wait, at least we can change them to synchronously when needed. Also, move the code to net/llc/llc_conn.c, which is apparently a better place. Reported-by: Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/llc_conn.h | 1 + net/llc/llc_c_ac.c | 9 +-------- net/llc/llc_conn.c | 22 +++++++++++++++++++++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index fe994d2e5286..ea985aa7a6c5 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h @@ -97,6 +97,7 @@ static __inline__ char llc_backlog_type(struct sk_buff *skb) struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot, int kern); +void llc_sk_stop_all_timers(struct sock *sk, bool sync); void llc_sk_free(struct sock *sk); void llc_sk_reset(struct sock *sk); diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c index ea225bd2672c..f8d4ab8ca1a5 100644 --- a/net/llc/llc_c_ac.c +++ b/net/llc/llc_c_ac.c @@ -1096,14 +1096,7 @@ int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_stop_all_timers(struct sock *sk, struct sk_buff *skb) { - struct llc_sock *llc = llc_sk(sk); - - del_timer(&llc->pf_cycle_timer.timer); - del_timer(&llc->ack_timer.timer); - del_timer(&llc->rej_sent_timer.timer); - del_timer(&llc->busy_state_timer.timer); - llc->ack_must_be_send = 0; - llc->ack_pf = 0; + llc_sk_stop_all_timers(sk, false); return 0; } diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 8bc5a1bd2d45..d861b74ad068 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -951,6 +951,26 @@ struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct pr return sk; } +void llc_sk_stop_all_timers(struct sock *sk, bool sync) +{ + struct llc_sock *llc = llc_sk(sk); + + if (sync) { + del_timer_sync(&llc->pf_cycle_timer.timer); + del_timer_sync(&llc->ack_timer.timer); + del_timer_sync(&llc->rej_sent_timer.timer); + del_timer_sync(&llc->busy_state_timer.timer); + } else { + del_timer(&llc->pf_cycle_timer.timer); + del_timer(&llc->ack_timer.timer); + del_timer(&llc->rej_sent_timer.timer); + del_timer(&llc->busy_state_timer.timer); + } + + llc->ack_must_be_send = 0; + llc->ack_pf = 0; +} + /** * llc_sk_free - Frees a LLC socket * @sk - socket to free @@ -963,7 +983,7 @@ void llc_sk_free(struct sock *sk) llc->state = LLC_CONN_OUT_OF_SVC; /* Stop all (possibly) running timers */ - llc_conn_ac_stop_all_timers(sk, NULL); + llc_sk_stop_all_timers(sk, true); #ifdef DEBUG_LLC_CONN_ALLOC printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __func__, skb_queue_len(&llc->pdu_unack_q), -- GitLab From f838259677f3ce937756018ce999339e07f8c351 Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Fri, 20 Apr 2018 15:57:30 +0200 Subject: [PATCH 075/855] tcp: don't read out-of-bounds opsize [ Upstream commit 7e5a206ab686f098367b61aca989f5cdfa8114a3 ] The old code reads the "opsize" variable from out-of-bounds memory (first byte behind the segment) if a broken TCP segment ends directly after an opcode that is neither EOL nor NOP. The result of the read isn't used for anything, so the worst thing that could theoretically happen is a pagefault; and since the physmap is usually mostly contiguous, even that seems pretty unlikely. The following C reproducer triggers the uninitialized read - however, you can't actually see anything happen unless you put something like a pr_warn() in tcp_parse_md5sig_option() to print the opsize. ==================================== #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void systemf(const char *command, ...) { char *full_command; va_list ap; va_start(ap, command); if (vasprintf(&full_command, command, ap) == -1) err(1, "vasprintf"); va_end(ap); printf("systemf: <<<%s>>>\n", full_command); system(full_command); } char *devname; int tun_alloc(char *name) { int fd = open("/dev/net/tun", O_RDWR); if (fd == -1) err(1, "open tun dev"); static struct ifreq req = { .ifr_flags = IFF_TUN|IFF_NO_PI }; strcpy(req.ifr_name, name); if (ioctl(fd, TUNSETIFF, &req)) err(1, "TUNSETIFF"); devname = req.ifr_name; printf("device name: %s\n", devname); return fd; } #define IPADDR(a,b,c,d) (((a)<<0)+((b)<<8)+((c)<<16)+((d)<<24)) void sum_accumulate(unsigned int *sum, void *data, int len) { assert((len&2)==0); for (int i=0; i> 16) + (sum & 0xffff); sum = (sum >> 16) + (sum & 0xffff); return htons(~sum); } void fix_ip_sum(struct iphdr *ip) { unsigned int sum = 0; sum_accumulate(&sum, ip, sizeof(*ip)); ip->check = sum_final(sum); } void fix_tcp_sum(struct iphdr *ip, struct tcphdr *tcp) { unsigned int sum = 0; struct { unsigned int saddr; unsigned int daddr; unsigned char pad; unsigned char proto_num; unsigned short tcp_len; } fakehdr = { .saddr = ip->saddr, .daddr = ip->daddr, .proto_num = ip->protocol, .tcp_len = htons(ntohs(ip->tot_len) - ip->ihl*4) }; sum_accumulate(&sum, &fakehdr, sizeof(fakehdr)); sum_accumulate(&sum, tcp, tcp->doff*4); tcp->check = sum_final(sum); } int main(void) { int tun_fd = tun_alloc("inject_dev%d"); systemf("ip link set %s up", devname); systemf("ip addr add 192.168.42.1/24 dev %s", devname); struct { struct iphdr ip; struct tcphdr tcp; unsigned char tcp_opts[20]; } __attribute__((packed)) syn_packet = { .ip = { .ihl = sizeof(struct iphdr)/4, .version = 4, .tot_len = htons(sizeof(syn_packet)), .ttl = 30, .protocol = IPPROTO_TCP, /* FIXUP check */ .saddr = IPADDR(192,168,42,2), .daddr = IPADDR(192,168,42,1) }, .tcp = { .source = htons(1), .dest = htons(1337), .seq = 0x12345678, .doff = (sizeof(syn_packet.tcp)+sizeof(syn_packet.tcp_opts))/4, .syn = 1, .window = htons(64), .check = 0 /*FIXUP*/ }, .tcp_opts = { /* INVALID: trailing MD5SIG opcode after NOPs */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19 } }; fix_ip_sum(&syn_packet.ip); fix_tcp_sum(&syn_packet.ip, &syn_packet.tcp); while (1) { int write_res = write(tun_fd, &syn_packet, sizeof(syn_packet)); if (write_res != sizeof(syn_packet)) err(1, "packet write failed"); } } ==================================== Fixes: cfb6eeb4c860 ("[TCP]: MD5 Signature Option (RFC2385) support.") Signed-off-by: Jann Horn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index eb05ad940e37..52b0a84be765 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3943,11 +3943,8 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th) int length = (th->doff << 2) - sizeof(*th); const u8 *ptr = (const u8 *)(th + 1); - /* If the TCP option is too short, we can short cut */ - if (length < TCPOLEN_MD5SIG) - return NULL; - - while (length > 0) { + /* If not enough data remaining, we can short cut */ + while (length >= TCPOLEN_MD5SIG) { int opcode = *ptr++; int opsize; -- GitLab From 3626fb04d050139b1fe1249f67c7c3efbe73b0ad Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 13 Apr 2018 13:59:25 +0200 Subject: [PATCH 076/855] team: avoid adding twice the same option to the event list [ Upstream commit 4fb0534fb7bbc2346ba7d3a072b538007f4135a5 ] When parsing the options provided by the user space, team_nl_cmd_options_set() insert them in a temporary list to send multiple events with a single message. While each option's attribute is correctly validated, the code does not check for duplicate entries before inserting into the event list. Exploiting the above, the syzbot was able to trigger the following splat: kernel BUG at lib/list_debug.c:31! invalid opcode: 0000 [#1] SMP KASAN Dumping ftrace buffer: (ftrace buffer empty) Modules linked in: CPU: 0 PID: 4466 Comm: syzkaller556835 Not tainted 4.16.0+ #17 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:__list_add_valid+0xaa/0xb0 lib/list_debug.c:29 RSP: 0018:ffff8801b04bf248 EFLAGS: 00010286 RAX: 0000000000000058 RBX: ffff8801c8fc7a90 RCX: 0000000000000000 RDX: 0000000000000058 RSI: ffffffff815fbf41 RDI: ffffed0036097e3f RBP: ffff8801b04bf260 R08: ffff8801b0b2a700 R09: ffffed003b604f90 R10: ffffed003b604f90 R11: ffff8801db027c87 R12: ffff8801c8fc7a90 R13: ffff8801c8fc7a90 R14: dffffc0000000000 R15: 0000000000000000 FS: 0000000000b98880(0000) GS:ffff8801db000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000000043fc30 CR3: 00000001afe8e000 CR4: 00000000001406f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: __list_add include/linux/list.h:60 [inline] list_add include/linux/list.h:79 [inline] team_nl_cmd_options_set+0x9ff/0x12b0 drivers/net/team/team.c:2571 genl_family_rcv_msg+0x889/0x1120 net/netlink/genetlink.c:599 genl_rcv_msg+0xc6/0x170 net/netlink/genetlink.c:624 netlink_rcv_skb+0x172/0x440 net/netlink/af_netlink.c:2448 genl_rcv+0x28/0x40 net/netlink/genetlink.c:635 netlink_unicast_kernel net/netlink/af_netlink.c:1310 [inline] netlink_unicast+0x58b/0x740 net/netlink/af_netlink.c:1336 netlink_sendmsg+0x9f0/0xfa0 net/netlink/af_netlink.c:1901 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg+0xd5/0x120 net/socket.c:639 ___sys_sendmsg+0x805/0x940 net/socket.c:2117 __sys_sendmsg+0x115/0x270 net/socket.c:2155 SYSC_sendmsg net/socket.c:2164 [inline] SyS_sendmsg+0x29/0x30 net/socket.c:2162 do_syscall_64+0x29e/0x9d0 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x4458b9 RSP: 002b:00007ffd1d4a7278 EFLAGS: 00000213 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 000000000000001b RCX: 00000000004458b9 RDX: 0000000000000010 RSI: 0000000020000d00 RDI: 0000000000000004 RBP: 00000000004a74ed R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000213 R12: 00007ffd1d4a7348 R13: 0000000000402a60 R14: 0000000000000000 R15: 0000000000000000 Code: 75 e8 eb a9 48 89 f7 48 89 75 e8 e8 d1 85 7b fe 48 8b 75 e8 eb bb 48 89 f2 48 89 d9 4c 89 e6 48 c7 c7 a0 84 d8 87 e8 ea 67 28 fe <0f> 0b 0f 1f 40 00 48 b8 00 00 00 00 00 fc ff df 55 48 89 e5 41 RIP: __list_add_valid+0xaa/0xb0 lib/list_debug.c:29 RSP: ffff8801b04bf248 This changeset addresses the avoiding list_add() if the current option is already present in the event list. Reported-and-tested-by: syzbot+4d4af685432dc0e56c91@syzkaller.appspotmail.com Signed-off-by: Paolo Abeni Fixes: 2fcdb2c9e659 ("team: allow to send multiple set events in one message") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/team/team.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 8673ef3c9cdc..e5941e86f64a 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -261,6 +261,17 @@ static void __team_option_inst_mark_removed_port(struct team *team, } } +static bool __team_option_inst_tmp_find(const struct list_head *opts, + const struct team_option_inst *needle) +{ + struct team_option_inst *opt_inst; + + list_for_each_entry(opt_inst, opts, tmp_list) + if (opt_inst == needle) + return true; + return false; +} + static int __team_options_register(struct team *team, const struct team_option *option, size_t option_count) @@ -2569,6 +2580,14 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) if (err) goto team_put; opt_inst->changed = true; + + /* dumb/evil user-space can send us duplicate opt, + * keep only the last one + */ + if (__team_option_inst_tmp_find(&opt_inst_list, + opt_inst)) + continue; + list_add(&opt_inst->tmp_list, &opt_inst_list); } if (!opt_found) { -- GitLab From 8599a1fe10b8c3f6e17568a1c43bfaccfeaff75c Mon Sep 17 00:00:00 2001 From: Xin Long Date: Tue, 24 Apr 2018 14:33:37 +0800 Subject: [PATCH 077/855] team: fix netconsole setup over team MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9cf2f437ca5b39828984064fad213e68fc17ef11 ] The same fix in Commit dbe173079ab5 ("bridge: fix netconsole setup over bridge") is also needed for team driver. While at it, remove the unnecessary parameter *team from team_port_enable_netpoll(). v1->v2: - fix it in a better way, as does bridge. Fixes: 0fb52a27a04a ("team: cleanup netpoll clode") Reported-by: João Avelino Bellomo Filho Signed-off-by: Xin Long Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/team/team.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index e5941e86f64a..36963685d42a 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1078,14 +1078,11 @@ static void team_port_leave(struct team *team, struct team_port *port) } #ifdef CONFIG_NET_POLL_CONTROLLER -static int team_port_enable_netpoll(struct team *team, struct team_port *port) +static int __team_port_enable_netpoll(struct team_port *port) { struct netpoll *np; int err; - if (!team->dev->npinfo) - return 0; - np = kzalloc(sizeof(*np), GFP_KERNEL); if (!np) return -ENOMEM; @@ -1099,6 +1096,14 @@ static int team_port_enable_netpoll(struct team *team, struct team_port *port) return err; } +static int team_port_enable_netpoll(struct team_port *port) +{ + if (!port->team->dev->npinfo) + return 0; + + return __team_port_enable_netpoll(port); +} + static void team_port_disable_netpoll(struct team_port *port) { struct netpoll *np = port->np; @@ -1113,7 +1118,7 @@ static void team_port_disable_netpoll(struct team_port *port) kfree(np); } #else -static int team_port_enable_netpoll(struct team *team, struct team_port *port) +static int team_port_enable_netpoll(struct team_port *port) { return 0; } @@ -1221,7 +1226,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev) goto err_vids_add; } - err = team_port_enable_netpoll(team, port); + err = team_port_enable_netpoll(port); if (err) { netdev_err(dev, "Failed to enable netpoll on device %s\n", portname); @@ -1919,7 +1924,7 @@ static int team_netpoll_setup(struct net_device *dev, mutex_lock(&team->lock); list_for_each_entry(port, &team->port_list, list) { - err = team_port_enable_netpoll(team, port); + err = __team_port_enable_netpoll(port); if (err) { __team_netpoll_cleanup(team); break; -- GitLab From b2a5207f8c45359d2404562e31fbca2b2fee6c56 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 23 Apr 2018 17:37:03 -0400 Subject: [PATCH 078/855] packet: fix bitfield update race [ Upstream commit a6361f0ca4b25460f2cdf3235ebe8115f622901e ] Updates to the bitfields in struct packet_sock are not atomic. Serialize these read-modify-write cycles. Move po->running into a separate variable. Its writes are protected by po->bind_lock (except for one startup case at packet_create). Also replace a textual precondition warning with lockdep annotation. All others are set only in packet_setsockopt. Serialize these updates by holding the socket lock. Analogous to other field updates, also hold the lock when testing whether a ring is active (pg_vec). Fixes: 8dc419447415 ("[PACKET]: Add optional checksum computation for recvmsg") Reported-by: DaeRyong Jeong Reported-by: Byoungyoung Lee Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/packet/af_packet.c | 60 +++++++++++++++++++++++++++++++----------- net/packet/internal.h | 10 +++---- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 267db0d603bc..759e005623aa 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -333,11 +333,11 @@ static void packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb) skb_set_queue_mapping(skb, queue_index); } -/* register_prot_hook must be invoked with the po->bind_lock held, +/* __register_prot_hook must be invoked through register_prot_hook * or from a context in which asynchronous accesses to the packet * socket is not possible (packet_create()). */ -static void register_prot_hook(struct sock *sk) +static void __register_prot_hook(struct sock *sk) { struct packet_sock *po = pkt_sk(sk); @@ -352,8 +352,13 @@ static void register_prot_hook(struct sock *sk) } } -/* {,__}unregister_prot_hook() must be invoked with the po->bind_lock - * held. If the sync parameter is true, we will temporarily drop +static void register_prot_hook(struct sock *sk) +{ + lockdep_assert_held_once(&pkt_sk(sk)->bind_lock); + __register_prot_hook(sk); +} + +/* If the sync parameter is true, we will temporarily drop * the po->bind_lock and do a synchronize_net to make sure no * asynchronous packet processing paths still refer to the elements * of po->prot_hook. If the sync parameter is false, it is the @@ -363,6 +368,8 @@ static void __unregister_prot_hook(struct sock *sk, bool sync) { struct packet_sock *po = pkt_sk(sk); + lockdep_assert_held_once(&po->bind_lock); + po->running = 0; if (po->fanout) @@ -3259,7 +3266,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, if (proto) { po->prot_hook.type = proto; - register_prot_hook(sk); + __register_prot_hook(sk); } mutex_lock(&net->packet.sklist_lock); @@ -3735,12 +3742,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (optlen != sizeof(val)) return -EINVAL; - if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) - return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; - po->tp_loss = !!val; - return 0; + + lock_sock(sk); + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) { + ret = -EBUSY; + } else { + po->tp_loss = !!val; + ret = 0; + } + release_sock(sk); + return ret; } case PACKET_AUXDATA: { @@ -3751,7 +3764,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; + lock_sock(sk); po->auxdata = !!val; + release_sock(sk); return 0; } case PACKET_ORIGDEV: @@ -3763,7 +3778,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; + lock_sock(sk); po->origdev = !!val; + release_sock(sk); return 0; } case PACKET_VNET_HDR: @@ -3772,15 +3789,20 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (sock->type != SOCK_RAW) return -EINVAL; - if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) - return -EBUSY; if (optlen < sizeof(val)) return -EINVAL; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; - po->has_vnet_hdr = !!val; - return 0; + lock_sock(sk); + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) { + ret = -EBUSY; + } else { + po->has_vnet_hdr = !!val; + ret = 0; + } + release_sock(sk); + return ret; } case PACKET_TIMESTAMP: { @@ -3818,11 +3840,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (optlen != sizeof(val)) return -EINVAL; - if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) - return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; - po->tp_tx_has_off = !!val; + + lock_sock(sk); + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) { + ret = -EBUSY; + } else { + po->tp_tx_has_off = !!val; + ret = 0; + } + release_sock(sk); return 0; } case PACKET_QDISC_BYPASS: diff --git a/net/packet/internal.h b/net/packet/internal.h index d55bfc34d6b3..1309e2a7baad 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -109,10 +109,12 @@ struct packet_sock { int copy_thresh; spinlock_t bind_lock; struct mutex pg_vec_lock; - unsigned int running:1, /* prot_hook is attached*/ - auxdata:1, + unsigned int running; /* bind_lock must be held */ + unsigned int auxdata:1, /* writer must hold sock lock */ origdev:1, - has_vnet_hdr:1; + has_vnet_hdr:1, + tp_loss:1, + tp_tx_has_off:1; int pressure; int ifindex; /* bound device */ __be16 num; @@ -122,8 +124,6 @@ struct packet_sock { enum tpacket_versions tp_version; unsigned int tp_hdrlen; unsigned int tp_reserve; - unsigned int tp_loss:1; - unsigned int tp_tx_has_off:1; unsigned int tp_tstamp; struct net_device __rcu *cached_dev; int (*xmit)(struct sk_buff *skb); -- GitLab From 0b6693b49e4d36846ab0d638ff062920d0ec10e7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 16 Apr 2018 08:29:42 -0700 Subject: [PATCH 079/855] tipc: add policy for TIPC_NLA_NET_ADDR [ Upstream commit ec518f21cb1a1b1f8a516499ea05c60299e04963 ] Before syzbot/KMSAN bites, add the missing policy for TIPC_NLA_NET_ADDR Fixes: 27c21416727a ("tipc: add net set to new netlink api") Signed-off-by: Eric Dumazet Cc: Jon Maloy Cc: Ying Xue Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/tipc/netlink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 3200059d14b2..9ba3c462f86e 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c @@ -79,7 +79,8 @@ const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = { const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = { [TIPC_NLA_NET_UNSPEC] = { .type = NLA_UNSPEC }, - [TIPC_NLA_NET_ID] = { .type = NLA_U32 } + [TIPC_NLA_NET_ID] = { .type = NLA_U32 }, + [TIPC_NLA_NET_ADDR] = { .type = NLA_U32 }, }; const struct nla_policy tipc_nl_link_policy[TIPC_NLA_LINK_MAX + 1] = { -- GitLab From ecaae08d72bd353c548545e521b68b00749f479a Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Mon, 23 Apr 2018 16:38:27 +0200 Subject: [PATCH 080/855] pppoe: check sockaddr length in pppoe_connect() [ Upstream commit a49e2f5d5fb141884452ddb428f551b123d436b5 ] We must validate sockaddr_len, otherwise userspace can pass fewer data than we expect and we end up accessing invalid data. Fixes: 224cf5ad14c0 ("ppp: Move the PPP drivers") Reported-by: syzbot+4f03bdf92fdf9ef5ddab@syzkaller.appspotmail.com Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ppp/pppoe.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index dc36c2ec1d10..fa2c7bd638be 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -620,6 +620,10 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, lock_sock(sk); error = -EINVAL; + + if (sockaddr_len != sizeof(struct sockaddr_pppox)) + goto end; + if (sp->sa_protocol != PX_PROTO_OE) goto end; -- GitLab From 9d33bfffd39bd1c2bf5d55f8b1f1e0cebf26f666 Mon Sep 17 00:00:00 2001 From: Toshiaki Makita Date: Tue, 17 Apr 2018 18:46:14 +0900 Subject: [PATCH 081/855] vlan: Fix reading memory beyond skb->tail in skb_vlan_tagged_multi [ Upstream commit 7ce2367254e84753bceb07327aaf5c953cfce117 ] Syzkaller spotted an old bug which leads to reading skb beyond tail by 4 bytes on vlan tagged packets. This is caused because skb_vlan_tagged_multi() did not check skb_headlen. BUG: KMSAN: uninit-value in eth_type_vlan include/linux/if_vlan.h:283 [inline] BUG: KMSAN: uninit-value in skb_vlan_tagged_multi include/linux/if_vlan.h:656 [inline] BUG: KMSAN: uninit-value in vlan_features_check include/linux/if_vlan.h:672 [inline] BUG: KMSAN: uninit-value in dflt_features_check net/core/dev.c:2949 [inline] BUG: KMSAN: uninit-value in netif_skb_features+0xd1b/0xdc0 net/core/dev.c:3009 CPU: 1 PID: 3582 Comm: syzkaller435149 Not tainted 4.16.0+ #82 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 eth_type_vlan include/linux/if_vlan.h:283 [inline] skb_vlan_tagged_multi include/linux/if_vlan.h:656 [inline] vlan_features_check include/linux/if_vlan.h:672 [inline] dflt_features_check net/core/dev.c:2949 [inline] netif_skb_features+0xd1b/0xdc0 net/core/dev.c:3009 validate_xmit_skb+0x89/0x1320 net/core/dev.c:3084 __dev_queue_xmit+0x1cb2/0x2b60 net/core/dev.c:3549 dev_queue_xmit+0x4b/0x60 net/core/dev.c:3590 packet_snd net/packet/af_packet.c:2944 [inline] packet_sendmsg+0x7c57/0x8a10 net/packet/af_packet.c:2969 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] sock_write_iter+0x3b9/0x470 net/socket.c:909 do_iter_readv_writev+0x7bb/0x970 include/linux/fs.h:1776 do_iter_write+0x30d/0xd40 fs/read_write.c:932 vfs_writev fs/read_write.c:977 [inline] do_writev+0x3c9/0x830 fs/read_write.c:1012 SYSC_writev+0x9b/0xb0 fs/read_write.c:1085 SyS_writev+0x56/0x80 fs/read_write.c:1082 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x43ffa9 RSP: 002b:00007fff2cff3948 EFLAGS: 00000217 ORIG_RAX: 0000000000000014 RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 000000000043ffa9 RDX: 0000000000000001 RSI: 0000000020000080 RDI: 0000000000000003 RBP: 00000000006cb018 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000217 R12: 00000000004018d0 R13: 0000000000401960 R14: 0000000000000000 R15: 0000000000000000 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:188 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:314 kmsan_slab_alloc+0x11/0x20 mm/kmsan/kmsan.c:321 slab_post_alloc_hook mm/slab.h:445 [inline] slab_alloc_node mm/slub.c:2737 [inline] __kmalloc_node_track_caller+0xaed/0x11c0 mm/slub.c:4369 __kmalloc_reserve net/core/skbuff.c:138 [inline] __alloc_skb+0x2cf/0x9f0 net/core/skbuff.c:206 alloc_skb include/linux/skbuff.h:984 [inline] alloc_skb_with_frags+0x1d4/0xb20 net/core/skbuff.c:5234 sock_alloc_send_pskb+0xb56/0x1190 net/core/sock.c:2085 packet_alloc_skb net/packet/af_packet.c:2803 [inline] packet_snd net/packet/af_packet.c:2894 [inline] packet_sendmsg+0x6444/0x8a10 net/packet/af_packet.c:2969 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] sock_write_iter+0x3b9/0x470 net/socket.c:909 do_iter_readv_writev+0x7bb/0x970 include/linux/fs.h:1776 do_iter_write+0x30d/0xd40 fs/read_write.c:932 vfs_writev fs/read_write.c:977 [inline] do_writev+0x3c9/0x830 fs/read_write.c:1012 SYSC_writev+0x9b/0xb0 fs/read_write.c:1085 SyS_writev+0x56/0x80 fs/read_write.c:1082 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Fixes: 58e998c6d239 ("offloading: Force software GSO for multiple vlan tags.") Reported-and-tested-by: syzbot+0bbe42c764feafa82c5a@syzkaller.appspotmail.com Signed-off-by: Toshiaki Makita Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/if_vlan.h | 7 +++++-- net/core/dev.c | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 8feecd5345e7..7e39719e27cb 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -600,7 +600,7 @@ static inline bool skb_vlan_tagged(const struct sk_buff *skb) * Returns true if the skb is tagged with multiple vlan headers, regardless * of whether it is hardware accelerated or not. */ -static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb) +static inline bool skb_vlan_tagged_multi(struct sk_buff *skb) { __be16 protocol = skb->protocol; @@ -610,6 +610,9 @@ static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb) if (likely(!eth_type_vlan(protocol))) return false; + if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN))) + return false; + veh = (struct vlan_ethhdr *)skb->data; protocol = veh->h_vlan_encapsulated_proto; } @@ -627,7 +630,7 @@ static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb) * * Returns features without unsafe ones if the skb has multiple tags. */ -static inline netdev_features_t vlan_features_check(const struct sk_buff *skb, +static inline netdev_features_t vlan_features_check(struct sk_buff *skb, netdev_features_t features) { if (skb_vlan_tagged_multi(skb)) { diff --git a/net/core/dev.c b/net/core/dev.c index 3d9190c2940d..5407d5f7b2d0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2871,7 +2871,7 @@ netdev_features_t passthru_features_check(struct sk_buff *skb, } EXPORT_SYMBOL(passthru_features_check); -static netdev_features_t dflt_features_check(const struct sk_buff *skb, +static netdev_features_t dflt_features_check(struct sk_buff *skb, struct net_device *dev, netdev_features_t features) { -- GitLab From 2de74b91a85e4928600543841752b70af22d3d50 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Thu, 12 Apr 2018 14:24:31 +0800 Subject: [PATCH 082/855] sctp: do not check port in sctp_inet6_cmp_addr [ Upstream commit 1071ec9d453a38023579714b64a951a2fb982071 ] pf->cmp_addr() is called before binding a v6 address to the sock. It should not check ports, like in sctp_inet_cmp_addr. But sctp_inet6_cmp_addr checks the addr by invoking af(6)->cmp_addr, sctp_v6_cmp_addr where it also compares the ports. This would cause that setsockopt(SCTP_SOCKOPT_BINDX_ADD) could bind multiple duplicated IPv6 addresses after Commit 40b4f0fd74e4 ("sctp: lack the check for ports in sctp_v6_cmp_addr"). This patch is to remove af->cmp_addr called in sctp_inet6_cmp_addr, but do the proper check for both v6 addrs and v4mapped addrs. v1->v2: - define __sctp_v6_cmp_addr to do the common address comparison used for both pf and af v6 cmp_addr. Fixes: 40b4f0fd74e4 ("sctp: lack the check for ports in sctp_v6_cmp_addr") Reported-by: Jianwen Ji Signed-off-by: Xin Long Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/ipv6.c | 60 ++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 355d95a7cd81..e031797ad311 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -521,46 +521,49 @@ static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr, addr->v6.sin6_scope_id = 0; } -/* Compare addresses exactly. - * v4-mapped-v6 is also in consideration. - */ -static int sctp_v6_cmp_addr(const union sctp_addr *addr1, - const union sctp_addr *addr2) +static int __sctp_v6_cmp_addr(const union sctp_addr *addr1, + const union sctp_addr *addr2) { if (addr1->sa.sa_family != addr2->sa.sa_family) { if (addr1->sa.sa_family == AF_INET && addr2->sa.sa_family == AF_INET6 && - ipv6_addr_v4mapped(&addr2->v6.sin6_addr)) { - if (addr2->v6.sin6_port == addr1->v4.sin_port && - addr2->v6.sin6_addr.s6_addr32[3] == - addr1->v4.sin_addr.s_addr) - return 1; - } + ipv6_addr_v4mapped(&addr2->v6.sin6_addr) && + addr2->v6.sin6_addr.s6_addr32[3] == + addr1->v4.sin_addr.s_addr) + return 1; + if (addr2->sa.sa_family == AF_INET && addr1->sa.sa_family == AF_INET6 && - ipv6_addr_v4mapped(&addr1->v6.sin6_addr)) { - if (addr1->v6.sin6_port == addr2->v4.sin_port && - addr1->v6.sin6_addr.s6_addr32[3] == - addr2->v4.sin_addr.s_addr) - return 1; - } + ipv6_addr_v4mapped(&addr1->v6.sin6_addr) && + addr1->v6.sin6_addr.s6_addr32[3] == + addr2->v4.sin_addr.s_addr) + return 1; + return 0; } - if (addr1->v6.sin6_port != addr2->v6.sin6_port) - return 0; + if (!ipv6_addr_equal(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr)) return 0; + /* If this is a linklocal address, compare the scope_id. */ - if (ipv6_addr_type(&addr1->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) { - if (addr1->v6.sin6_scope_id && addr2->v6.sin6_scope_id && - (addr1->v6.sin6_scope_id != addr2->v6.sin6_scope_id)) { - return 0; - } - } + if ((ipv6_addr_type(&addr1->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) && + addr1->v6.sin6_scope_id && addr2->v6.sin6_scope_id && + addr1->v6.sin6_scope_id != addr2->v6.sin6_scope_id) + return 0; return 1; } +/* Compare addresses exactly. + * v4-mapped-v6 is also in consideration. + */ +static int sctp_v6_cmp_addr(const union sctp_addr *addr1, + const union sctp_addr *addr2) +{ + return __sctp_v6_cmp_addr(addr1, addr2) && + addr1->v6.sin6_port == addr2->v6.sin6_port; +} + /* Initialize addr struct to INADDR_ANY. */ static void sctp_v6_inaddr_any(union sctp_addr *addr, __be16 port) { @@ -844,8 +847,8 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1, const union sctp_addr *addr2, struct sctp_sock *opt) { - struct sctp_af *af1, *af2; struct sock *sk = sctp_opt2sk(opt); + struct sctp_af *af1, *af2; af1 = sctp_get_af_specific(addr1->sa.sa_family); af2 = sctp_get_af_specific(addr2->sa.sa_family); @@ -861,10 +864,7 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1, if (sctp_is_any(sk, addr1) || sctp_is_any(sk, addr2)) return 1; - if (addr1->sa.sa_family != addr2->sa.sa_family) - return 0; - - return af1->cmp_addr(addr1, addr2); + return __sctp_v6_cmp_addr(addr1, addr2); } /* Verify that the provided sockaddr looks bindable. Common verification, -- GitLab From e5d0f6a6935a6b58e2b343010a260b58594566bf Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 20 Apr 2018 15:15:03 -0400 Subject: [PATCH 083/855] net: sched: ife: signal not finding metaid [ Upstream commit f6cd14537ff9919081be19b9c53b9b19c0d3ea97 ] We need to record stats for received metadata that we dont know how to process. Have find_decode_metaid() return -ENOENT to capture this. Signed-off-by: Alexander Aring Reviewed-by: Yotam Gigi Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_ife.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c index 95c463cbb9a6..235db2c9bbbb 100644 --- a/net/sched/act_ife.c +++ b/net/sched/act_ife.c @@ -634,7 +634,7 @@ int find_decode_metaid(struct sk_buff *skb, struct tcf_ife_info *ife, } } - return 0; + return -ENOENT; } struct ifeheadr { -- GitLab From 90e19ec22499f6182134f5a8b8461de2a0abe987 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Wed, 18 Apr 2018 11:51:56 -0700 Subject: [PATCH 084/855] llc: hold llc_sap before release_sock() [ Upstream commit f7e43672683b097bb074a8fe7af9bc600a23f231 ] syzbot reported we still access llc->sap in llc_backlog_rcv() after it is freed in llc_sap_remove_socket(): Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x1b9/0x294 lib/dump_stack.c:113 print_address_description+0x6c/0x20b mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report.cold.7+0x242/0x2fe mm/kasan/report.c:412 __asan_report_load1_noabort+0x14/0x20 mm/kasan/report.c:430 llc_conn_ac_send_sabme_cmd_p_set_x+0x3a8/0x460 net/llc/llc_c_ac.c:785 llc_exec_conn_trans_actions net/llc/llc_conn.c:475 [inline] llc_conn_service net/llc/llc_conn.c:400 [inline] llc_conn_state_process+0x4e1/0x13a0 net/llc/llc_conn.c:75 llc_backlog_rcv+0x195/0x1e0 net/llc/llc_conn.c:891 sk_backlog_rcv include/net/sock.h:909 [inline] __release_sock+0x12f/0x3a0 net/core/sock.c:2335 release_sock+0xa4/0x2b0 net/core/sock.c:2850 llc_ui_release+0xc8/0x220 net/llc/af_llc.c:204 llc->sap is refcount'ed and llc_sap_remove_socket() is paired with llc_sap_add_socket(). This can be amended by holding its refcount before llc_sap_remove_socket() and releasing it after release_sock(). Reported-by: Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/llc/af_llc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index f7caf0f5d9c8..dd4fcf0acea5 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -187,6 +187,7 @@ static int llc_ui_release(struct socket *sock) { struct sock *sk = sock->sk; struct llc_sock *llc; + struct llc_sap *sap; if (unlikely(sk == NULL)) goto out; @@ -197,9 +198,15 @@ static int llc_ui_release(struct socket *sock) llc->laddr.lsap, llc->daddr.lsap); if (!llc_send_disc(sk)) llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); + sap = llc->sap; + /* Hold this for release_sock(), so that llc_backlog_rcv() could still + * use it. + */ + llc_sap_hold(sap); if (!sock_flag(sk, SOCK_ZAPPED)) llc_sap_remove_socket(llc->sap, sk); release_sock(sk); + llc_sap_put(sap); if (llc->dev) dev_put(llc->dev); sock_put(sk); -- GitLab From 7b80c16871489c7aa4b283ebc12e226b27c4c73b Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Thu, 19 Apr 2018 21:54:34 -0700 Subject: [PATCH 085/855] llc: fix NULL pointer deref for SOCK_ZAPPED [ Upstream commit 3a04ce7130a7e5dad4e78d45d50313747f8c830f ] For SOCK_ZAPPED socket, we don't need to care about llc->sap, so we should just skip these refcount functions in this case. Fixes: f7e43672683b ("llc: hold llc_sap before release_sock()") Reported-by: kernel test robot Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/llc/af_llc.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index dd4fcf0acea5..d6bc5f2a1175 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -187,7 +187,6 @@ static int llc_ui_release(struct socket *sock) { struct sock *sk = sock->sk; struct llc_sock *llc; - struct llc_sap *sap; if (unlikely(sk == NULL)) goto out; @@ -198,15 +197,19 @@ static int llc_ui_release(struct socket *sock) llc->laddr.lsap, llc->daddr.lsap); if (!llc_send_disc(sk)) llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); - sap = llc->sap; - /* Hold this for release_sock(), so that llc_backlog_rcv() could still - * use it. - */ - llc_sap_hold(sap); - if (!sock_flag(sk, SOCK_ZAPPED)) + if (!sock_flag(sk, SOCK_ZAPPED)) { + struct llc_sap *sap = llc->sap; + + /* Hold this for release_sock(), so that llc_backlog_rcv() + * could still use it. + */ + llc_sap_hold(sap); llc_sap_remove_socket(llc->sap, sk); - release_sock(sk); - llc_sap_put(sap); + release_sock(sk); + llc_sap_put(sap); + } else { + release_sock(sk); + } if (llc->dev) dev_put(llc->dev); sock_put(sk); -- GitLab From b031b84f3c39cfd0b69e7d40eebc20c3a6bd9193 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Thu, 19 Apr 2018 22:49:09 +0300 Subject: [PATCH 086/855] net: ethernet: ti: cpsw: fix tx vlan priority mapping [ Upstream commit 5e391dc5a8d801a2410d0032ad4a428d1d61800c ] The CPDMA_TX_PRIORITY_MAP in real is vlan pcp field priority mapping register and basically replaces vlan pcp field for tagged packets. So, set it to be 1:1 mapping. Otherwise, it will cause unexpected change of egress vlan tagged packets, like prio 2 -> prio 5. Fixes: e05107e6b747 ("net: ethernet: ti: cpsw: add multi queue support") Reviewed-by: Grygorii Strashko Signed-off-by: Ivan Khoronzhuk Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/ti/cpsw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 552de9c490c6..de336897a28a 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -124,7 +124,7 @@ do { \ #define RX_PRIORITY_MAPPING 0x76543210 #define TX_PRIORITY_MAPPING 0x33221100 -#define CPDMA_TX_PRIORITY_MAP 0x01234567 +#define CPDMA_TX_PRIORITY_MAP 0x76543210 #define CPSW_VLAN_AWARE BIT(1) #define CPSW_ALE_VLAN_AWARE 1 -- GitLab From 581cb195c59f0da31878c10e40893ec2d1d7b122 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Thu, 12 Apr 2018 10:46:55 +0200 Subject: [PATCH 087/855] net: fix deadlock while clearing neighbor proxy table [ Upstream commit 53b76cdf7e8fecec1d09e38aad2f8579882591a8 ] When coming from ndisc_netdev_event() in net/ipv6/ndisc.c, neigh_ifdown() is called with &nd_tbl, locking this while clearing the proxy neighbor entries when eg. deleting an interface. Calling the table's pndisc_destructor() with the lock still held, however, can cause a deadlock: When a multicast listener is available an IGMP packet of type ICMPV6_MGM_REDUCTION may be sent out. When reaching ip6_finish_output2(), if no neighbor entry for the target address is found, __neigh_create() is called with &nd_tbl, which it'll want to lock. Move the elements into their own list, then unlock the table and perform the destruction. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=199289 Fixes: 6fd6ce2056de ("ipv6: Do not depend on rt->n in ip6_finish_output2().") Signed-off-by: Wolfgang Bumiller Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/neighbour.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index ce5bbf8b1f67..128c811dcb1a 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -54,7 +54,8 @@ do { \ static void neigh_timer_handler(unsigned long arg); static void __neigh_notify(struct neighbour *n, int type, int flags); static void neigh_update_notify(struct neighbour *neigh); -static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev); +static int pneigh_ifdown_and_unlock(struct neigh_table *tbl, + struct net_device *dev); #ifdef CONFIG_PROC_FS static const struct file_operations neigh_stat_seq_fops; @@ -254,8 +255,7 @@ int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) { write_lock_bh(&tbl->lock); neigh_flush_dev(tbl, dev); - pneigh_ifdown(tbl, dev); - write_unlock_bh(&tbl->lock); + pneigh_ifdown_and_unlock(tbl, dev); del_timer_sync(&tbl->proxy_timer); pneigh_queue_purge(&tbl->proxy_queue); @@ -645,9 +645,10 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey, return -ENOENT; } -static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev) +static int pneigh_ifdown_and_unlock(struct neigh_table *tbl, + struct net_device *dev) { - struct pneigh_entry *n, **np; + struct pneigh_entry *n, **np, *freelist = NULL; u32 h; for (h = 0; h <= PNEIGH_HASHMASK; h++) { @@ -655,16 +656,23 @@ static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev) while ((n = *np) != NULL) { if (!dev || n->dev == dev) { *np = n->next; - if (tbl->pdestructor) - tbl->pdestructor(n); - if (n->dev) - dev_put(n->dev); - kfree(n); + n->next = freelist; + freelist = n; continue; } np = &n->next; } } + write_unlock_bh(&tbl->lock); + while ((n = freelist)) { + freelist = n->next; + n->next = NULL; + if (tbl->pdestructor) + tbl->pdestructor(n); + if (n->dev) + dev_put(n->dev); + kfree(n); + } return -ENOENT; } -- GitLab From 228ce13c3064fcc8b30d21f95a9c246a23196daa Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 11 Apr 2018 14:36:28 -0700 Subject: [PATCH 088/855] tcp: md5: reject TCP_MD5SIG or TCP_MD5SIG_EXT on established sockets [ Upstream commit 7212303268918b9a203aebeacfdbd83b5e87b20d ] syzbot/KMSAN reported an uninit-value in tcp_parse_options() [1] I believe this was caused by a TCP_MD5SIG being set on live flow. This is highly unexpected, since TCP option space is limited. For instance, presence of TCP MD5 option automatically disables TCP TimeStamp option at SYN/SYNACK time, which we can not do once flow has been established. Really, adding/deleting an MD5 key only makes sense on sockets in CLOSE or LISTEN state. [1] BUG: KMSAN: uninit-value in tcp_parse_options+0xd74/0x1a30 net/ipv4/tcp_input.c:3720 CPU: 1 PID: 6177 Comm: syzkaller192004 Not tainted 4.16.0+ #83 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 tcp_parse_options+0xd74/0x1a30 net/ipv4/tcp_input.c:3720 tcp_fast_parse_options net/ipv4/tcp_input.c:3858 [inline] tcp_validate_incoming+0x4f1/0x2790 net/ipv4/tcp_input.c:5184 tcp_rcv_established+0xf60/0x2bb0 net/ipv4/tcp_input.c:5453 tcp_v4_do_rcv+0x6cd/0xd90 net/ipv4/tcp_ipv4.c:1469 sk_backlog_rcv include/net/sock.h:908 [inline] __release_sock+0x2d6/0x680 net/core/sock.c:2271 release_sock+0x97/0x2a0 net/core/sock.c:2786 tcp_sendmsg+0xd6/0x100 net/ipv4/tcp.c:1464 inet_sendmsg+0x48d/0x740 net/ipv4/af_inet.c:764 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] SYSC_sendto+0x6c3/0x7e0 net/socket.c:1747 SyS_sendto+0x8a/0xb0 net/socket.c:1715 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x448fe9 RSP: 002b:00007fd472c64d38 EFLAGS: 00000216 ORIG_RAX: 000000000000002c RAX: ffffffffffffffda RBX: 00000000006e5a30 RCX: 0000000000448fe9 RDX: 000000000000029f RSI: 0000000020a88f88 RDI: 0000000000000004 RBP: 00000000006e5a34 R08: 0000000020e68000 R09: 0000000000000010 R10: 00000000200007fd R11: 0000000000000216 R12: 0000000000000000 R13: 00007fff074899ef R14: 00007fd472c659c0 R15: 0000000000000009 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:188 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:314 kmsan_slab_alloc+0x11/0x20 mm/kmsan/kmsan.c:321 slab_post_alloc_hook mm/slab.h:445 [inline] slab_alloc_node mm/slub.c:2737 [inline] __kmalloc_node_track_caller+0xaed/0x11c0 mm/slub.c:4369 __kmalloc_reserve net/core/skbuff.c:138 [inline] __alloc_skb+0x2cf/0x9f0 net/core/skbuff.c:206 alloc_skb include/linux/skbuff.h:984 [inline] tcp_send_ack+0x18c/0x910 net/ipv4/tcp_output.c:3624 __tcp_ack_snd_check net/ipv4/tcp_input.c:5040 [inline] tcp_ack_snd_check net/ipv4/tcp_input.c:5053 [inline] tcp_rcv_established+0x2103/0x2bb0 net/ipv4/tcp_input.c:5469 tcp_v4_do_rcv+0x6cd/0xd90 net/ipv4/tcp_ipv4.c:1469 sk_backlog_rcv include/net/sock.h:908 [inline] __release_sock+0x2d6/0x680 net/core/sock.c:2271 release_sock+0x97/0x2a0 net/core/sock.c:2786 tcp_sendmsg+0xd6/0x100 net/ipv4/tcp.c:1464 inet_sendmsg+0x48d/0x740 net/ipv4/af_inet.c:764 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] SYSC_sendto+0x6c3/0x7e0 net/socket.c:1747 SyS_sendto+0x8a/0xb0 net/socket.c:1715 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Fixes: cfb6eeb4c860 ("[TCP]: MD5 Signature Option (RFC2385) support.") Signed-off-by: Eric Dumazet Reported-by: syzbot Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 0d1a767db1bb..0fc5dad02fe8 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2662,8 +2662,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level, #ifdef CONFIG_TCP_MD5SIG case TCP_MD5SIG: - /* Read the IP->Key mappings from userspace */ - err = tp->af_specific->md5_parse(sk, optval, optlen); + if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) + err = tp->af_specific->md5_parse(sk, optval, optlen); + else + err = -EINVAL; break; #endif case TCP_USER_TIMEOUT: -- GitLab From 55ca7b1d43a9d9958ce8544dee938e6c62c263ec Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 15 Apr 2018 17:52:04 -0700 Subject: [PATCH 089/855] net: af_packet: fix race in PACKET_{R|T}X_RING [ Upstream commit 5171b37d959641bbc619781caf62e61f7b940871 ] In order to remove the race caught by syzbot [1], we need to lock the socket before using po->tp_version as this could change under us otherwise. This means lock_sock() and release_sock() must be done by packet_set_ring() callers. [1] : BUG: KMSAN: uninit-value in packet_set_ring+0x1254/0x3870 net/packet/af_packet.c:4249 CPU: 0 PID: 20195 Comm: syzkaller707632 Not tainted 4.16.0+ #83 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 packet_set_ring+0x1254/0x3870 net/packet/af_packet.c:4249 packet_setsockopt+0x12c6/0x5a90 net/packet/af_packet.c:3662 SYSC_setsockopt+0x4b8/0x570 net/socket.c:1849 SyS_setsockopt+0x76/0xa0 net/socket.c:1828 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x449099 RSP: 002b:00007f42b5307ce8 EFLAGS: 00000246 ORIG_RAX: 0000000000000036 RAX: ffffffffffffffda RBX: 000000000070003c RCX: 0000000000449099 RDX: 0000000000000005 RSI: 0000000000000107 RDI: 0000000000000003 RBP: 0000000000700038 R08: 000000000000001c R09: 0000000000000000 R10: 00000000200000c0 R11: 0000000000000246 R12: 0000000000000000 R13: 000000000080eecf R14: 00007f42b53089c0 R15: 0000000000000001 Local variable description: ----req_u@packet_setsockopt Variable was created at: packet_setsockopt+0x13f/0x5a90 net/packet/af_packet.c:3612 SYSC_setsockopt+0x4b8/0x570 net/socket.c:1849 Fixes: f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation.") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/packet/af_packet.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 759e005623aa..a027f8c00944 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -3024,6 +3024,7 @@ static int packet_release(struct socket *sock) packet_flush_mclist(sk); + lock_sock(sk); if (po->rx_ring.pg_vec) { memset(&req_u, 0, sizeof(req_u)); packet_set_ring(sk, &req_u, 1, 0); @@ -3033,6 +3034,7 @@ static int packet_release(struct socket *sock) memset(&req_u, 0, sizeof(req_u)); packet_set_ring(sk, &req_u, 1, 1); } + release_sock(sk); f = fanout_release(sk); @@ -3661,6 +3663,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv union tpacket_req_u req_u; int len; + lock_sock(sk); switch (po->tp_version) { case TPACKET_V1: case TPACKET_V2: @@ -3671,12 +3674,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv len = sizeof(req_u.req3); break; } - if (optlen < len) - return -EINVAL; - if (copy_from_user(&req_u.req, optval, len)) - return -EFAULT; - return packet_set_ring(sk, &req_u, 0, - optname == PACKET_TX_RING); + if (optlen < len) { + ret = -EINVAL; + } else { + if (copy_from_user(&req_u.req, optval, len)) + ret = -EFAULT; + else + ret = packet_set_ring(sk, &req_u, 0, + optname == PACKET_TX_RING); + } + release_sock(sk); + return ret; } case PACKET_COPY_THRESH: { @@ -4247,7 +4255,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, /* Added to avoid minimal code churn */ struct tpacket_req *req = &req_u->req; - lock_sock(sk); /* Opening a Tx-ring is NOT supported in TPACKET_V3 */ if (!closing && tx_ring && (po->tp_version > TPACKET_V2)) { net_warn_ratelimited("Tx-ring is not supported.\n"); @@ -4383,7 +4390,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, if (pg_vec) free_pg_vec(pg_vec, order, req->tp_block_nr); out: - release_sock(sk); return err; } -- GitLab From e2956fc8356549c7072a6b420b500bb5fe32c4fb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 22 Apr 2018 18:29:23 -0700 Subject: [PATCH 090/855] ipv6: add RTA_TABLE and RTA_PREFSRC to rtm_ipv6_policy [ Upstream commit aa8f8778493c85fff480cdf8b349b1e1dcb5f243 ] KMSAN reported use of uninit-value that I tracked to lack of proper size check on RTA_TABLE attribute. I also believe RTA_PREFSRC lacks a similar check. Fixes: 86872cb57925 ("[IPv6] route: FIB6 configuration using struct fib6_config") Fixes: c3968a857a6b ("ipv6: RTA_PREFSRC support for ipv6 route source address selection") Signed-off-by: Eric Dumazet Reported-by: syzbot Acked-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/route.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d6a4b2c73a7c..f6ac472acd0f 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2811,6 +2811,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned int mtu) static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) }, + [RTA_PREFSRC] = { .len = sizeof(struct in6_addr) }, [RTA_OIF] = { .type = NLA_U32 }, [RTA_IIF] = { .type = NLA_U32 }, [RTA_PRIORITY] = { .type = NLA_U32 }, @@ -2820,6 +2821,7 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { [RTA_ENCAP_TYPE] = { .type = NLA_U16 }, [RTA_ENCAP] = { .type = NLA_NESTED }, [RTA_EXPIRES] = { .type = NLA_U32 }, + [RTA_TABLE] = { .type = NLA_U32 }, }; static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, -- GitLab From 2f7be1262873bb200ab18fe7627231c9da9f22b2 Mon Sep 17 00:00:00 2001 From: Doron Roberts-Kedes Date: Wed, 11 Apr 2018 15:05:16 -0700 Subject: [PATCH 091/855] strparser: Fix incorrect strp->need_bytes value. [ Upstream commit 9d0c75bf6e03d9bf80c55b0f677dc9b982958fd5 ] strp_data_ready resets strp->need_bytes to 0 if strp_peek_len indicates that the remainder of the message has been received. However, do_strp_work does not reset strp->need_bytes to 0. If do_strp_work completes a partial message, the value of strp->need_bytes will continue to reflect the needed bytes of the previous message, causing future invocations of strp_data_ready to return early if strp->need_bytes is less than strp_peek_len. Resetting strp->need_bytes to 0 in __strp_recv on handing a full message to the upper layer solves this problem. __strp_recv also calculates strp->need_bytes using stm->accum_len before stm->accum_len has been incremented by cand_len. This can cause strp->need_bytes to be equal to the full length of the message instead of the full length minus the accumulated length. This, in turn, causes strp_data_ready to return early, even when there is sufficient data to complete the partial message. Incrementing stm->accum_len before using it to calculate strp->need_bytes solves this problem. Found while testing net/tls_sw recv path. Fixes: 43a0c6751a322847 ("strparser: Stream parser for messages") Signed-off-by: Doron Roberts-Kedes Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/strparser/strparser.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c index 6cbc935ddd96..bbee334ab1b0 100644 --- a/net/strparser/strparser.c +++ b/net/strparser/strparser.c @@ -285,9 +285,9 @@ static int strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, strp_start_rx_timer(strp); } + rxm->accum_len += cand_len; strp->rx_need_bytes = rxm->strp.full_len - rxm->accum_len; - rxm->accum_len += cand_len; rxm->early_eaten = cand_len; STRP_STATS_ADD(strp->stats.rx_bytes, cand_len); desc->count = 0; /* Stop reading socket */ @@ -310,6 +310,7 @@ static int strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, /* Hurray, we have a new message! */ del_timer(&strp->rx_msg_timer); strp->rx_skb_head = NULL; + strp->rx_need_bytes = 0; STRP_STATS_INCR(strp->stats.rx_msgs); /* Give skb to upper layer */ @@ -374,9 +375,7 @@ void strp_data_ready(struct strparser *strp) return; if (strp->rx_need_bytes) { - if (strp_peek_len(strp) >= strp->rx_need_bytes) - strp->rx_need_bytes = 0; - else + if (strp_peek_len(strp) < strp->rx_need_bytes) return; } -- GitLab From 70f2351eca535c590dad1657a3761650c8515acb Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Wed, 18 Apr 2018 22:54:59 -0400 Subject: [PATCH 092/855] scsi: mptsas: Disable WRITE SAME commit 94e5395d2403c8bc2504a7cbe4c4caaacb7b8b84 upstream. First generation MPT Fusion controllers can not translate WRITE SAME when the attached device is a SATA drive. Disable WRITE SAME support. Reported-by: Nikola Ciprich Cc: Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/message/fusion/mptsas.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 7ee1667acde4..00dff9b5a6c4 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1994,6 +1994,7 @@ static struct scsi_host_template mptsas_driver_template = { .cmd_per_lun = 7, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = mptscsih_host_attrs, + .no_write_same = 1, }; static int mptsas_get_linkerrors(struct sas_phy *phy) -- GitLab From 4bd744b86114a406efb563c8717e5bea7672d427 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 18 Apr 2018 12:51:31 +0300 Subject: [PATCH 093/855] cdrom: information leak in cdrom_ioctl_media_changed() commit 9de4ee40547fd315d4a0ed1dd15a2fa3559ad707 upstream. This cast is wrong. "cdi->capacity" is an int and "arg" is an unsigned long. The way the check is written now, if one of the high 32 bits is set then we could read outside the info->slots[] array. This bug is pretty old and it predates git. Reviewed-by: Christoph Hellwig Cc: stable@vger.kernel.org Signed-off-by: Dan Carpenter Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/cdrom/cdrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 5d475b3a0b2e..128ebd439221 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2368,7 +2368,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi, if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT) return media_changed(cdi, 1); - if ((unsigned int)arg >= cdi->capacity) + if (arg >= cdi->capacity) return -EINVAL; info = kmalloc(sizeof(*info), GFP_KERNEL); -- GitLab From 04f87299884a26f64b643d810e68d56685d6ffc1 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Wed, 11 Apr 2018 11:21:17 +0200 Subject: [PATCH 094/855] s390/cio: update chpid descriptor after resource accessibility event commit af2e460ade0b0180d0f3812ca4f4f59cc9597f3e upstream. Channel path descriptors have been seen as something stable (as long as the chpid is configured). Recent tests have shown that the descriptor can also be altered when the link state of a channel path changes. Thus it is necessary to update the descriptor during handling of resource accessibility events. Cc: Signed-off-by: Sebastian Ott Reviewed-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/chsc.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 11674698b36d..67903c93328b 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -451,6 +451,7 @@ static void chsc_process_sei_link_incident(struct chsc_sei_nt0_area *sei_area) static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area) { + struct channel_path *chp; struct chp_link link; struct chp_id chpid; int status; @@ -463,10 +464,17 @@ static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area) chpid.id = sei_area->rsid; /* allocate a new channel path structure, if needed */ status = chp_get_status(chpid); - if (status < 0) - chp_new(chpid); - else if (!status) + if (!status) return; + + if (status < 0) { + chp_new(chpid); + } else { + chp = chpid_to_chp(chpid); + mutex_lock(&chp->lock); + chp_update_desc(chp); + mutex_unlock(&chp->lock); + } memset(&link, 0, sizeof(struct chp_link)); link.chpid = chpid; if ((sei_area->vf & 0xc0) != 0) { -- GitLab From a714a5f3afdd8de38985a88fc6d29f81873369d1 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Thu, 12 Apr 2018 13:38:22 +0200 Subject: [PATCH 095/855] s390/dasd: fix IO error for newly defined devices commit 5d27a2bf6e14f5c7d1033ad1e993fcd0eba43e83 upstream. When a new CKD storage volume is defined at the storage server, Linux may be relying on outdated information about that volume, which leads to the following errors: 1. Command Reject Errors for minidisk on z/VM: dasd-eckd.b3193d: 0.0.XXXX: An error occurred in the DASD device driver, reason=09 dasd(eckd): I/O status report for device 0.0.XXXX: dasd(eckd): in req: 00000000XXXXXXXX CC:00 FC:04 AC:00 SC:17 DS:02 CS:00 RC:0 dasd(eckd): device 0.0.2046: Failing CCW: 00000000XXXXXXXX dasd(eckd): Sense(hex) 0- 7: 80 00 00 00 00 00 00 00 dasd(eckd): Sense(hex) 8-15: 00 00 00 00 00 00 00 00 dasd(eckd): Sense(hex) 16-23: 00 00 00 00 e1 00 0f 00 dasd(eckd): Sense(hex) 24-31: 00 00 40 e2 00 00 00 00 dasd(eckd): 24 Byte: 0 MSG 0, no MSGb to SYSOP 2. Equipment Check errors on LPAR or for dedicated devices on z/VM: dasd(eckd): I/O status report for device 0.0.XXXX: dasd(eckd): in req: 00000000XXXXXXXX CC:00 FC:04 AC:00 SC:17 DS:0E CS:40 fcxs:01 schxs:00 RC:0 dasd(eckd): device 0.0.9713: Failing TCW: 00000000XXXXXXXX dasd(eckd): Sense(hex) 0- 7: 10 00 00 00 13 58 4d 0f dasd(eckd): Sense(hex) 8-15: 67 00 00 00 00 00 00 04 dasd(eckd): Sense(hex) 16-23: e5 18 05 33 97 01 0f 0f dasd(eckd): Sense(hex) 24-31: 00 00 40 e2 00 04 58 0d dasd(eckd): 24 Byte: 0 MSG f, no MSGb to SYSOP Fix this problem by using the up-to-date information provided during online processing via the device specific SNEQ to detect the case of outdated LCU data. If there is a difference, perform a re-read of that data. Cc: stable@vger.kernel.org Reviewed-by: Jan Hoeppner Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- drivers/s390/block/dasd_alias.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 1e560188dd13..e453d2a7d7f9 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -591,13 +591,22 @@ static int _schedule_lcu_update(struct alias_lcu *lcu, int dasd_alias_add_device(struct dasd_device *device) { struct dasd_eckd_private *private = device->private; - struct alias_lcu *lcu; + __u8 uaddr = private->uid.real_unit_addr; + struct alias_lcu *lcu = private->lcu; unsigned long flags; int rc; - lcu = private->lcu; rc = 0; spin_lock_irqsave(&lcu->lock, flags); + /* + * Check if device and lcu type differ. If so, the uac data may be + * outdated and needs to be updated. + */ + if (private->uid.type != lcu->uac->unit[uaddr].ua_type) { + lcu->flags |= UPDATE_PENDING; + DBF_DEV_EVENT(DBF_WARNING, device, "%s", + "uid type mismatch - trigger rescan"); + } if (!(lcu->flags & UPDATE_PENDING)) { rc = _add_device_to_lcu(lcu, device, device); if (rc) -- GitLab From bed2d7627a9d95ecf4662fbcd7dd30d762997b1a Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 16 Apr 2018 12:22:24 +0200 Subject: [PATCH 096/855] s390/uprobes: implement arch_uretprobe_is_alive() commit 783c3b53b9506db3e05daacfe34e0287eebb09d8 upstream. Implement s390 specific arch_uretprobe_is_alive() to avoid SIGSEGVs observed with uretprobes in combination with setjmp/longjmp. See commit 2dea1d9c38e4 ("powerpc/uprobes: Implement arch_uretprobe_is_alive()") for more details. With this implemented all test cases referenced in the above commit pass. Reported-by: Ziqian SUN Cc: # v4.3+ Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/uprobes.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/s390/kernel/uprobes.c b/arch/s390/kernel/uprobes.c index 66956c09d5bf..3d04dfdabc9f 100644 --- a/arch/s390/kernel/uprobes.c +++ b/arch/s390/kernel/uprobes.c @@ -147,6 +147,15 @@ unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline, return orig; } +bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx, + struct pt_regs *regs) +{ + if (ctx == RP_CHECK_CHAIN_CALL) + return user_stack_pointer(regs) <= ret->stack; + else + return user_stack_pointer(regs) < ret->stack; +} + /* Instruction Emulation */ static void adjust_psw_addr(psw_t *psw, unsigned long len) -- GitLab From 4959a913ef6b274cedbc7fc06d5606aafd32ef80 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 17 Apr 2018 18:23:50 +0200 Subject: [PATCH 097/855] ACPI / video: Only default only_lcd to true on Win8-ready _desktops_ commit 53fa1f6e8a5958da698a31edf366ffe90596b490 upstream. Commit 5928c281524f (ACPI / video: Default lcd_only to true on Win8-ready and newer machines) made only_lcd default to true on all machines where acpi_osi_is_win8() returns true, including laptops. The purpose of this is to avoid the bogus / non-working acpi backlight interface which many newer BIOS-es define on desktop machines. But this is causing a regression on some laptops, specifically on the Dell XPS 13 2013 model, which does not have the LCD flag set for its fully functional ACPI backlight interface. Rather then DMI quirking our way out of this, this commits changes the logic for setting only_lcd to true, to only do this on machines with a desktop (or server) dmi chassis-type. Note that we cannot simply only check the chassis-type and not register the backlight interface based on that as there are some laptops and tablets which have their chassis-type set to "3" aka desktop. Hopefully the combination of checking the LCD flag, but only on devices with a desktop(ish) chassis-type will avoid the needs for DMI quirks for this, or at least limit the amount of DMI quirks which we need to a minimum. Fixes: 5928c281524f (ACPI / video: Default lcd_only to true on Win8-ready and newer machines) Reported-and-tested-by: James Hogan Signed-off-by: Hans de Goede Cc: 4.15+ # 4.15+ Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpi_video.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 94e04c9de12b..667dc5c86fef 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -2069,6 +2069,25 @@ static int __init intel_opregion_present(void) return opregion; } +static bool dmi_is_desktop(void) +{ + const char *chassis_type; + + chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); + if (!chassis_type) + return false; + + if (!strcmp(chassis_type, "3") || /* 3: Desktop */ + !strcmp(chassis_type, "4") || /* 4: Low Profile Desktop */ + !strcmp(chassis_type, "5") || /* 5: Pizza Box */ + !strcmp(chassis_type, "6") || /* 6: Mini Tower */ + !strcmp(chassis_type, "7") || /* 7: Tower */ + !strcmp(chassis_type, "11")) /* 11: Main Server Chassis */ + return true; + + return false; +} + int acpi_video_register(void) { int ret = 0; @@ -2089,8 +2108,12 @@ int acpi_video_register(void) * win8 ready (where we also prefer the native backlight driver, so * normally the acpi_video code should not register there anyways). */ - if (only_lcd == -1) - only_lcd = acpi_osi_is_win8(); + if (only_lcd == -1) { + if (dmi_is_desktop() && acpi_osi_is_win8()) + only_lcd = true; + else + only_lcd = false; + } dmi_check_system(video_dmi_table); -- GitLab From ba3cd5796223e0971d30e910e0d5b953576f8629 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 29 Apr 2018 11:32:03 +0200 Subject: [PATCH 098/855] Linux 4.9.97 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 50ae573e8951..ee3e943c3bd9 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 96 +SUBLEVEL = 97 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 089f046e33177e0b37d9d78f34578c23e9a69872 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 12 Jun 2017 17:55:10 +0200 Subject: [PATCH 099/855] BACKPORT: ARM: cpuidle: Support asymmetric idle definition [ Upstream commit d50a7d8acd780f54c48703ab1069c2e64a24e4a0 ] Some hardware have clusters with different idle states. The current code does not support this and fails as it expects all the idle states to be identical. Because of this, the Mediatek mtk8173 had to create the same idle state for a big.Little system and now the Hisilicon 960 is facing the same situation. Solve this by simply assuming the multiple driver will be needed for all the platforms using the ARM generic cpuidle driver which makes sense because of the different topologies we can support with a single kernel for ARM32 or ARM64. Every CPU has its own driver, so every single CPU can specify in the DT the idle states. This simple approach allows to support the future dynamIQ system, current SMP and HMP. Tested on: - 96boards: Hikey 620 - 96boards: Hikey 960 - 96boards: dragonboard410c - Mediatek 8173 Change-Id: I523898903981801778a5b84ac8e83b27335d21bd Tested-by: Leo Yan Signed-off-by: Daniel Lezcano Acked-by: Sudeep Holla Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/Kconfig.arm | 1 + drivers/cpuidle/cpuidle-arm.c | 62 +++++++++++++++++++++-------------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm index 21340e0be73e..f52144808455 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -4,6 +4,7 @@ config ARM_CPUIDLE bool "Generic ARM/ARM64 CPU idle Driver" select DT_IDLE_STATES + select CPU_IDLE_MULTIPLE_DRIVERS help Select this to enable generic cpuidle driver for ARM. It provides a generic idle driver whose idle states are configured diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c index f440d385ed34..7080c384ad5d 100644 --- a/drivers/cpuidle/cpuidle-arm.c +++ b/drivers/cpuidle/cpuidle-arm.c @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -44,7 +45,7 @@ static int arm_enter_idle_state(struct cpuidle_device *dev, return CPU_PM_CPU_IDLE_ENTER(arm_cpuidle_suspend, idx); } -static struct cpuidle_driver arm_idle_driver = { +static struct cpuidle_driver arm_idle_driver __initdata = { .name = "arm_idle", .owner = THIS_MODULE, /* @@ -80,30 +81,42 @@ static const struct of_device_id arm_idle_state_match[] __initconst = { static int __init arm_idle_init(void) { int cpu, ret; - struct cpuidle_driver *drv = &arm_idle_driver; + struct cpuidle_driver *drv; struct cpuidle_device *dev; - /* - * Initialize idle states data, starting at index 1. - * This driver is DT only, if no DT idle states are detected (ret == 0) - * let the driver initialization fail accordingly since there is no - * reason to initialize the idle driver if only wfi is supported. - */ - ret = dt_init_idle_driver(drv, arm_idle_state_match, 1); - if (ret <= 0) - return ret ? : -ENODEV; - - ret = cpuidle_register_driver(drv); - if (ret) { - pr_err("Failed to register cpuidle driver\n"); - return ret; - } - - /* - * Call arch CPU operations in order to initialize - * idle states suspend back-end specific data - */ for_each_possible_cpu(cpu) { + + drv = kmemdup(&arm_idle_driver, sizeof(*drv), GFP_KERNEL); + if (!drv) { + ret = -ENOMEM; + goto out_fail; + } + + drv->cpumask = (struct cpumask *)cpumask_of(cpu); + + /* + * Initialize idle states data, starting at index 1. This + * driver is DT only, if no DT idle states are detected (ret + * == 0) let the driver initialization fail accordingly since + * there is no reason to initialize the idle driver if only + * wfi is supported. + */ + ret = dt_init_idle_driver(drv, arm_idle_state_match, 1); + if (ret <= 0) { + ret = ret ? : -ENODEV; + goto out_fail; + } + + ret = cpuidle_register_driver(drv); + if (ret) { + pr_err("Failed to register cpuidle driver\n"); + goto out_fail; + } + + /* + * Call arch CPU operations in order to initialize + * idle states suspend back-end specific data + */ ret = arm_cpuidle_init(cpu); /* @@ -141,10 +154,11 @@ static int __init arm_idle_init(void) dev = per_cpu(cpuidle_devices, cpu); cpuidle_unregister_device(dev); kfree(dev); + drv = cpuidle_get_driver(); + cpuidle_unregister_driver(drv); + kfree(drv); } - cpuidle_unregister_driver(drv); - return ret; } device_initcall(arm_idle_init); -- GitLab From 9817c0e3f52d0050eeef4498106e0a57df1c77e3 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Thu, 31 Aug 2017 22:24:36 +0200 Subject: [PATCH 100/855] BACKPORT: ARM: cpuidle: Avoid memleak if init fail [ Upstream commit ed40fad9a568efe83f5e80897ded71117b6911b3 ] In case there are no DT idle states defined or cpuidle_register_driver() fails, the copy of the idle driver is leaked: unreferenced object 0xede0dc00 (size 1024): comm "swapper/0", pid 1, jiffies 4294937431 (age 744.510s) hex dump (first 32 bytes): 94 9e 0b c1 00 00 00 00 00 00 00 00 00 00 00 00 ................ 57 46 49 00 00 00 00 00 00 00 00 00 00 00 00 00 WFI............. backtrace: [] arm_idle_init+0x44/0x1ac [] do_one_initcall+0x3c/0x16c [] kernel_init_freeable+0x110/0x1d0 [] kernel_init+0x8/0x114 [] ret_from_fork+0x14/0x3c So fix this by freeing the unregistered copy in error case. Change-Id: I91eeab447fe163f550958bc4c40cac6d27234a42 Signed-off-by: Stefan Wahren Fixes: d50a7d8acd78 (ARM: cpuidle: Support asymmetric idle definition) Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle-arm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c index 7080c384ad5d..52a75053ee03 100644 --- a/drivers/cpuidle/cpuidle-arm.c +++ b/drivers/cpuidle/cpuidle-arm.c @@ -104,13 +104,13 @@ static int __init arm_idle_init(void) ret = dt_init_idle_driver(drv, arm_idle_state_match, 1); if (ret <= 0) { ret = ret ? : -ENODEV; - goto out_fail; + goto init_fail; } ret = cpuidle_register_driver(drv); if (ret) { pr_err("Failed to register cpuidle driver\n"); - goto out_fail; + goto init_fail; } /* @@ -149,6 +149,8 @@ static int __init arm_idle_init(void) } return 0; +init_fail: + kfree(drv); out_fail: while (--cpu >= 0) { dev = per_cpu(cpuidle_devices, cpu); -- GitLab From 19bd3e34d859b03a82eae2c0be10af5e9881b265 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 10 Oct 2017 13:47:55 +0800 Subject: [PATCH 101/855] BACKPORT: ARM: cpuidle: Correct driver unregistration if init fails [ Upstream commit 0f87855d969a87f02048ff5ced7503465d5ab2f1 ] If cpuidle init fails, the code misses to unregister the driver for current CPU. Furthermore, we also need to rollback to cancel all previous CPUs registration; but the code retrieves driver handler by using function cpuidle_get_driver(), this function returns back current CPU driver handler but not previous CPU's handler, which leads to the failure handling code cannot unregister previous CPUs driver. This commit fixes two mentioned issues, it adds error handling path 'goto out_unregister_drv' for current CPU driver unregistration; and it is to replace cpuidle_get_driver() with cpuidle_get_cpu_driver(), the later function can retrieve driver handler for previous CPUs according to the CPU device handler so can unregister the driver properly. This patch also adds extra error handling paths 'goto out_kfree_dev' and 'goto out_kfree_drv' and adjusts the freeing sentences for previous CPUs; so make the code more readable for freeing 'dev' and 'drv' structures. Change-Id: Ib7ca13b641d7480c03ad67f2de7dac42e5bed87a Suggested-by: Daniel Lezcano Signed-off-by: Leo Yan Fixes: d50a7d8acd78 (ARM: cpuidle: Support asymmetric idle definition) Acked-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle-arm.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c index 52a75053ee03..f47c54546752 100644 --- a/drivers/cpuidle/cpuidle-arm.c +++ b/drivers/cpuidle/cpuidle-arm.c @@ -104,13 +104,13 @@ static int __init arm_idle_init(void) ret = dt_init_idle_driver(drv, arm_idle_state_match, 1); if (ret <= 0) { ret = ret ? : -ENODEV; - goto init_fail; + goto out_kfree_drv; } ret = cpuidle_register_driver(drv); if (ret) { pr_err("Failed to register cpuidle driver\n"); - goto init_fail; + goto out_kfree_drv; } /* @@ -128,14 +128,14 @@ static int __init arm_idle_init(void) if (ret) { pr_err("CPU %d failed to init idle CPU ops\n", cpu); - goto out_fail; + goto out_unregister_drv; } dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { pr_err("Failed to allocate cpuidle device\n"); ret = -ENOMEM; - goto out_fail; + goto out_unregister_drv; } dev->cpu = cpu; @@ -143,21 +143,25 @@ static int __init arm_idle_init(void) if (ret) { pr_err("Failed to register cpuidle device for CPU %d\n", cpu); - kfree(dev); - goto out_fail; + goto out_kfree_dev; } } return 0; -init_fail: + +out_kfree_dev: + kfree(dev); +out_unregister_drv: + cpuidle_unregister_driver(drv); +out_kfree_drv: kfree(drv); out_fail: while (--cpu >= 0) { dev = per_cpu(cpuidle_devices, cpu); + drv = cpuidle_get_cpu_driver(dev); cpuidle_unregister_device(dev); - kfree(dev); - drv = cpuidle_get_driver(); cpuidle_unregister_driver(drv); + kfree(dev); kfree(drv); } -- GitLab From 90d98b524875e7709ae61a9ca458d57be6f84a0c Mon Sep 17 00:00:00 2001 From: Lynus Vaz Date: Mon, 9 Apr 2018 14:45:36 +0530 Subject: [PATCH 102/855] msm: kgsl: Use a common sharedmem init function Since we initialize the kgsl sharedmem structures from various places, use a common function to avoid code duplication. Change-Id: I5953dc44f4fbd89ce57dffe933369f58a6c19bde Signed-off-by: Lynus Vaz --- drivers/gpu/msm/kgsl.c | 70 ++++++++------------------------ drivers/gpu/msm/kgsl_iommu.c | 7 ++-- drivers/gpu/msm/kgsl_sharedmem.c | 38 +++++++++++++++-- drivers/gpu/msm/kgsl_sharedmem.h | 9 ++-- 4 files changed, 61 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index bb9f9ff1b4c1..57e20507bb64 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -2384,7 +2384,6 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv, struct kgsl_gpuobj_import *param = data; struct kgsl_mem_entry *entry; int ret, fd = -1; - struct kgsl_mmu *mmu = &dev_priv->device->mmu; entry = kgsl_mem_entry_create(); if (entry == NULL) @@ -2398,18 +2397,10 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv, | KGSL_MEMFLAGS_FORCE_32BIT | KGSL_MEMFLAGS_IOCOHERENT; - /* Disable IO coherence if it is not supported on the chip */ - if (!MMU_FEATURE(mmu, KGSL_MMU_IO_COHERENT)) - param->flags &= ~((uint64_t)KGSL_MEMFLAGS_IOCOHERENT); - if (kgsl_is_compat_task()) param->flags |= KGSL_MEMFLAGS_FORCE_32BIT; - entry->memdesc.flags = param->flags; - - if (MMU_FEATURE(mmu, KGSL_MMU_NEED_GUARD_PAGE)) - entry->memdesc.priv |= KGSL_MEMDESC_GUARD_PAGE; - + kgsl_memdesc_init(dev_priv->device, &entry->memdesc, param->flags); if (param->type == KGSL_USER_MEM_TYPE_ADDR) ret = _gpuobj_map_useraddr(dev_priv->device, private->pagetable, entry, param); @@ -2648,6 +2639,7 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_mmu *mmu = &dev_priv->device->mmu; unsigned int memtype; + uint64_t flags; /* * If content protection is not enabled and secure buffer @@ -2684,30 +2676,17 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, * Note: CACHEMODE is ignored for this call. Caching should be * determined by type of allocation being mapped. */ - param->flags &= KGSL_MEMFLAGS_GPUREADONLY - | KGSL_MEMTYPE_MASK - | KGSL_MEMALIGN_MASK - | KGSL_MEMFLAGS_USE_CPU_MAP - | KGSL_MEMFLAGS_SECURE - | KGSL_MEMFLAGS_IOCOHERENT; - - /* Disable IO coherence if it is not supported on the chip */ - if (!MMU_FEATURE(mmu, KGSL_MMU_IO_COHERENT)) - param->flags &= ~((uint64_t)KGSL_MEMFLAGS_IOCOHERENT); - - entry->memdesc.flags = (uint64_t) param->flags; + flags = param->flags & (KGSL_MEMFLAGS_GPUREADONLY + | KGSL_MEMTYPE_MASK + | KGSL_MEMALIGN_MASK + | KGSL_MEMFLAGS_USE_CPU_MAP + | KGSL_MEMFLAGS_SECURE + | KGSL_MEMFLAGS_IOCOHERENT); if (kgsl_is_compat_task()) - entry->memdesc.flags |= KGSL_MEMFLAGS_FORCE_32BIT; - - if (!kgsl_mmu_use_cpu_map(mmu)) - entry->memdesc.flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP); - - if (MMU_FEATURE(mmu, KGSL_MMU_NEED_GUARD_PAGE)) - entry->memdesc.priv |= KGSL_MEMDESC_GUARD_PAGE; + flags |= KGSL_MEMFLAGS_FORCE_32BIT; - if (param->flags & KGSL_MEMFLAGS_SECURE) - entry->memdesc.priv |= KGSL_MEMDESC_SECURE; + kgsl_memdesc_init(dev_priv->device, &entry->memdesc, flags); switch (memtype) { case KGSL_MEM_ENTRY_USER: @@ -3103,10 +3082,6 @@ struct kgsl_mem_entry *gpumem_alloc_entry( | KGSL_MEMFLAGS_FORCE_32BIT | KGSL_MEMFLAGS_IOCOHERENT; - /* Turn off SVM if the system doesn't support it */ - if (!kgsl_mmu_use_cpu_map(mmu)) - flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP); - /* Return not supported error if secure memory isn't enabled */ if (!kgsl_mmu_is_secured(mmu) && (flags & KGSL_MEMFLAGS_SECURE)) { @@ -3115,10 +3090,6 @@ struct kgsl_mem_entry *gpumem_alloc_entry( return ERR_PTR(-EOPNOTSUPP); } - /* Secure memory disables advanced addressing modes */ - if (flags & KGSL_MEMFLAGS_SECURE) - flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP); - /* Cap the alignment bits to the highest number we can handle */ align = MEMFLAGS(flags, KGSL_MEMALIGN_MASK, KGSL_MEMALIGN_SHIFT); if (align >= ilog2(KGSL_MAX_ALIGN)) { @@ -3137,20 +3108,10 @@ struct kgsl_mem_entry *gpumem_alloc_entry( flags = kgsl_filter_cachemode(flags); - /* Disable IO coherence if it is not supported on the chip */ - if (!MMU_FEATURE(mmu, KGSL_MMU_IO_COHERENT)) - flags &= ~((uint64_t)KGSL_MEMFLAGS_IOCOHERENT); - entry = kgsl_mem_entry_create(); if (entry == NULL) return ERR_PTR(-ENOMEM); - if (MMU_FEATURE(mmu, KGSL_MMU_NEED_GUARD_PAGE)) - entry->memdesc.priv |= KGSL_MEMDESC_GUARD_PAGE; - - if (flags & KGSL_MEMFLAGS_SECURE) - entry->memdesc.priv |= KGSL_MEMDESC_SECURE; - ret = kgsl_allocate_user(dev_priv->device, &entry->memdesc, size, flags); if (ret != 0) @@ -3334,6 +3295,7 @@ long kgsl_ioctl_sparse_phys_alloc(struct kgsl_device_private *dev_priv, struct kgsl_process_private *process = dev_priv->process_priv; struct kgsl_sparse_phys_alloc *param = data; struct kgsl_mem_entry *entry; + uint64_t flags; int ret; int id; @@ -3366,11 +3328,12 @@ long kgsl_ioctl_sparse_phys_alloc(struct kgsl_device_private *dev_priv, entry->id = id; entry->priv = process; - entry->memdesc.flags = KGSL_MEMFLAGS_SPARSE_PHYS; - kgsl_memdesc_set_align(&entry->memdesc, ilog2(param->pagesize)); + flags = KGSL_MEMFLAGS_SPARSE_PHYS | + ((ilog2(param->pagesize) << KGSL_MEMALIGN_SHIFT) & + KGSL_MEMALIGN_MASK); ret = kgsl_allocate_user(dev_priv->device, &entry->memdesc, - param->size, entry->memdesc.flags); + param->size, flags); if (ret) goto err_remove_idr; @@ -3459,7 +3422,8 @@ long kgsl_ioctl_sparse_virt_alloc(struct kgsl_device_private *dev_priv, if (entry == NULL) return -ENOMEM; - entry->memdesc.flags = KGSL_MEMFLAGS_SPARSE_VIRT; + kgsl_memdesc_init(dev_priv->device, &entry->memdesc, + KGSL_MEMFLAGS_SPARSE_VIRT); entry->memdesc.size = param->size; entry->memdesc.cur_bindings = 0; kgsl_memdesc_set_align(&entry->memdesc, ilog2(param->pagesize)); diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 0ce72f636d6e..c2266d4da56e 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -262,13 +262,12 @@ static void kgsl_setup_qdss_desc(struct kgsl_device *device) return; } - gpu_qdss_desc.flags = 0; + kgsl_memdesc_init(device, &gpu_qdss_desc, 0); gpu_qdss_desc.priv = 0; gpu_qdss_desc.physaddr = gpu_qdss_entry[0]; gpu_qdss_desc.size = gpu_qdss_entry[1]; gpu_qdss_desc.pagetable = NULL; gpu_qdss_desc.ops = NULL; - gpu_qdss_desc.dev = device->dev->parent; gpu_qdss_desc.hostptr = NULL; result = memdesc_sg_dma(&gpu_qdss_desc, gpu_qdss_desc.physaddr, @@ -307,13 +306,12 @@ static void kgsl_setup_qtimer_desc(struct kgsl_device *device) return; } - gpu_qtimer_desc.flags = 0; + kgsl_memdesc_init(device, &gpu_qtimer_desc, 0); gpu_qtimer_desc.priv = 0; gpu_qtimer_desc.physaddr = gpu_qtimer_entry[0]; gpu_qtimer_desc.size = gpu_qtimer_entry[1]; gpu_qtimer_desc.pagetable = NULL; gpu_qtimer_desc.ops = NULL; - gpu_qtimer_desc.dev = device->dev->parent; gpu_qtimer_desc.hostptr = NULL; result = memdesc_sg_dma(&gpu_qtimer_desc, gpu_qtimer_desc.physaddr, @@ -1482,6 +1480,7 @@ static int _setstate_alloc(struct kgsl_device *device, { int ret; + kgsl_memdesc_init(device, &iommu->setstate, 0); ret = kgsl_sharedmem_alloc_contig(device, &iommu->setstate, PAGE_SIZE); if (!ret) { diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 3702893566b5..f69e61f536e8 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -340,7 +340,7 @@ int kgsl_allocate_user(struct kgsl_device *device, { int ret; - memdesc->flags = flags; + kgsl_memdesc_init(device, memdesc, flags); if (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE) ret = kgsl_sharedmem_alloc_contig(device, memdesc, size); @@ -696,6 +696,40 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset, } EXPORT_SYMBOL(kgsl_cache_range_op); +void kgsl_memdesc_init(struct kgsl_device *device, + struct kgsl_memdesc *memdesc, uint64_t flags) +{ + struct kgsl_mmu *mmu = &device->mmu; + unsigned int align; + + memset(memdesc, 0, sizeof(*memdesc)); + /* Turn off SVM if the system doesn't support it */ + if (!kgsl_mmu_use_cpu_map(mmu)) + flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP); + + /* Secure memory disables advanced addressing modes */ + if (flags & KGSL_MEMFLAGS_SECURE) + flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP); + + /* Disable IO coherence if it is not supported on the chip */ + if (!MMU_FEATURE(mmu, KGSL_MMU_IO_COHERENT)) + flags &= ~((uint64_t) KGSL_MEMFLAGS_IOCOHERENT); + + if (MMU_FEATURE(mmu, KGSL_MMU_NEED_GUARD_PAGE)) + memdesc->priv |= KGSL_MEMDESC_GUARD_PAGE; + + if (flags & KGSL_MEMFLAGS_SECURE) + memdesc->priv |= KGSL_MEMDESC_SECURE; + + memdesc->flags = flags; + memdesc->dev = device->dev->parent; + + align = max_t(unsigned int, + (memdesc->flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT, + ilog2(PAGE_SIZE)); + kgsl_memdesc_set_align(memdesc, align); +} + int kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, uint64_t size) @@ -896,8 +930,6 @@ void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc) if (memdesc->pages) kgsl_free(memdesc->pages); - - memset(memdesc, 0, sizeof(*memdesc)); } EXPORT_SYMBOL(kgsl_sharedmem_free); diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index 55bb34f748db..976752d67b22 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -57,6 +57,9 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset, uint64_t size, unsigned int op); +void kgsl_memdesc_init(struct kgsl_device *device, + struct kgsl_memdesc *memdesc, uint64_t flags); + void kgsl_process_init_sysfs(struct kgsl_device *device, struct kgsl_process_private *private); void kgsl_process_uninit_sysfs(struct kgsl_process_private *private); @@ -282,8 +285,8 @@ static inline int kgsl_allocate_global(struct kgsl_device *device, { int ret; - memdesc->flags = flags; - memdesc->priv = priv; + kgsl_memdesc_init(device, memdesc, flags); + memdesc->priv |= priv; if (((memdesc->priv & KGSL_MEMDESC_CONTIG) != 0) || (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE)) -- GitLab From 1321d422617691b1bf56d1486436c1f10f2abb80 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 30 Apr 2018 12:23:14 -0700 Subject: [PATCH 103/855] cfi: print target address on failure Bug: 78862212 Bug: 67506682 Change-Id: Ifaa3e3f8fc5f19649f4857d185d50383b4a89055 Signed-off-by: Sami Tolvanen --- kernel/cfi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/kernel/cfi.c b/kernel/cfi.c index 87053e2c0acf..6951c25d311b 100644 --- a/kernel/cfi.c +++ b/kernel/cfi.c @@ -23,12 +23,12 @@ #define cfi_slowpath_handler __cfi_slowpath #endif /* CONFIG_CFI_PERMISSIVE */ -static inline void handle_cfi_failure() +static inline void handle_cfi_failure(void *ptr) { #ifdef CONFIG_CFI_PERMISSIVE - WARN_RATELIMIT(1, "CFI failure:\n"); + WARN_RATELIMIT(1, "CFI failure (target: [<%px>] %pF):\n", ptr, ptr); #else - pr_err("CFI failure:\n"); + pr_err("CFI failure (target: [<%px>] %pF):\n", ptr, ptr); BUG(); #endif } @@ -282,18 +282,18 @@ void cfi_slowpath_handler(uint64_t id, void *ptr, void *diag) if (likely(check)) check(id, ptr, diag); else /* Don't allow unchecked modules */ - handle_cfi_failure(); + handle_cfi_failure(ptr); } EXPORT_SYMBOL(cfi_slowpath_handler); #endif /* CONFIG_MODULES */ -void cfi_failure_handler(void *data, void *value, void *vtable) +void cfi_failure_handler(void *data, void *ptr, void *vtable) { - handle_cfi_failure(); + handle_cfi_failure(ptr); } EXPORT_SYMBOL(cfi_failure_handler); -void __cfi_check_fail(void *data, void *value) +void __cfi_check_fail(void *data, void *ptr) { - handle_cfi_failure(); + handle_cfi_failure(ptr); } -- GitLab From a405a2a02793b217b4402ab898f877dac4db7e66 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 12 Apr 2018 11:48:09 -0400 Subject: [PATCH 104/855] ext4: prevent right-shifting extents beyond EXT_MAX_BLOCKS commit 349fa7d6e1935f49bf4161c4900711b2989180a9 upstream. During the "insert range" fallocate operation, extents starting at the range offset are shifted "right" (to a higher file offset) by the range length. But, as shown by syzbot, it's not validated that this doesn't cause extents to be shifted beyond EXT_MAX_BLOCKS. In that case ->ee_block can wrap around, corrupting the extent tree. Fix it by returning an error if the space between the end of the last extent and EXT4_MAX_BLOCKS is smaller than the range being inserted. This bug can be reproduced by running the following commands when the current directory is on an ext4 filesystem with a 4k block size: fallocate -l 8192 file fallocate --keep-size -o 0xfffffffe000 -l 4096 -n file fallocate --insert-range -l 8192 file Then after unmounting the filesystem, e2fsck reports corruption. Reported-by: syzbot+06c885be0edcdaeab40c@syzkaller.appspotmail.com Fixes: 331573febb6a ("ext4: Add support FALLOC_FL_INSERT_RANGE for fallocate") Cc: stable@vger.kernel.org # v4.2+ Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- fs/ext4/extents.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 1a0c57100f28..63c702b4b24c 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -5356,8 +5356,9 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, stop = le32_to_cpu(extent->ee_block); /* - * In case of left shift, Don't start shifting extents until we make - * sure the hole is big enough to accommodate the shift. + * For left shifts, make sure the hole on the left is big enough to + * accommodate the shift. For right shifts, make sure the last extent + * won't be shifted beyond EXT_MAX_BLOCKS. */ if (SHIFT == SHIFT_LEFT) { path = ext4_find_extent(inode, start - 1, &path, @@ -5377,9 +5378,14 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, if ((start == ex_start && shift > ex_start) || (shift > start - ex_end)) { - ext4_ext_drop_refs(path); - kfree(path); - return -EINVAL; + ret = -EINVAL; + goto out; + } + } else { + if (shift > EXT_MAX_BLOCKS - + (stop + ext4_ext_get_actual_len(extent))) { + ret = -EINVAL; + goto out; } } -- GitLab From 2e54d7c12c34edba7f4c796697e8fd0b4a0cb118 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 18 Apr 2018 11:49:31 -0400 Subject: [PATCH 105/855] ext4: set h_journal if there is a failure starting a reserved handle commit b2569260d55228b617bd82aba6d0db2faeeb4116 upstream. If ext4 tries to start a reserved handle via jbd2_journal_start_reserved(), and the journal has been aborted, this can result in a NULL pointer dereference. This is because the fields h_journal and h_transaction in the handle structure share the same memory, via a union, so jbd2_journal_start_reserved() will clear h_journal before calling start_this_handle(). If this function fails due to an aborted handle, h_journal will still be NULL, and the call to jbd2_journal_free_reserved() will pass a NULL journal to sub_reserve_credits(). This can be reproduced by running "kvm-xfstests -c dioread_nolock generic/475". Cc: stable@kernel.org # 3.11 Fixes: 8f7d89f36829b ("jbd2: transaction reservation support") Signed-off-by: Theodore Ts'o Reviewed-by: Andreas Dilger Reviewed-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/transaction.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 4e5c6103b76c..9e9e0936138b 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -528,6 +528,7 @@ int jbd2_journal_start_reserved(handle_t *handle, unsigned int type, */ ret = start_this_handle(journal, handle, GFP_NOFS); if (ret < 0) { + handle->h_journal = journal; jbd2_journal_free_reserved(handle); return ret; } -- GitLab From 76964816c83d3e4e8a6a393777b30f22a6f9cd51 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 26 Mar 2018 23:54:10 -0400 Subject: [PATCH 106/855] ext4: add validity checks for bitmap block numbers commit 7dac4a1726a9c64a517d595c40e95e2d0d135f6f upstream. An privileged attacker can cause a crash by mounting a crafted ext4 image which triggers a out-of-bounds read in the function ext4_valid_block_bitmap() in fs/ext4/balloc.c. This issue has been assigned CVE-2018-1093. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=199181 BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1560782 Reported-by: Wen Xu Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/balloc.c | 16 ++++++++++++++-- fs/ext4/ialloc.c | 7 +++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 176b4b27a27a..49567ceb7664 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -337,20 +337,25 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb, /* check whether block bitmap block number is set */ blk = ext4_block_bitmap(sb, desc); offset = blk - group_first_block; - if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) + if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || + !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) /* bad block bitmap */ return blk; /* check whether the inode bitmap block number is set */ blk = ext4_inode_bitmap(sb, desc); offset = blk - group_first_block; - if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) + if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || + !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) /* bad block bitmap */ return blk; /* check whether the inode table block number is set */ blk = ext4_inode_table(sb, desc); offset = blk - group_first_block; + if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || + EXT4_B2C(sbi, offset + sbi->s_itb_per_group) >= sb->s_blocksize) + return blk; next_zero_bit = ext4_find_next_zero_bit(bh->b_data, EXT4_B2C(sbi, offset + EXT4_SB(sb)->s_itb_per_group), EXT4_B2C(sbi, offset)); @@ -416,6 +421,7 @@ struct buffer_head * ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) { struct ext4_group_desc *desc; + struct ext4_sb_info *sbi = EXT4_SB(sb); struct buffer_head *bh; ext4_fsblk_t bitmap_blk; int err; @@ -424,6 +430,12 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) if (!desc) return ERR_PTR(-EFSCORRUPTED); bitmap_blk = ext4_block_bitmap(sb, desc); + if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || + (bitmap_blk >= ext4_blocks_count(sbi->s_es))) { + ext4_error(sb, "Invalid block bitmap block %llu in " + "block_group %u", bitmap_blk, block_group); + return ERR_PTR(-EFSCORRUPTED); + } bh = sb_getblk(sb, bitmap_blk); if (unlikely(!bh)) { ext4_error(sb, "Cannot get buffer for block bitmap - " diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 79a9a1bddafc..dcf63daefee0 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -119,6 +119,7 @@ static struct buffer_head * ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) { struct ext4_group_desc *desc; + struct ext4_sb_info *sbi = EXT4_SB(sb); struct buffer_head *bh = NULL; ext4_fsblk_t bitmap_blk; int err; @@ -128,6 +129,12 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) return ERR_PTR(-EFSCORRUPTED); bitmap_blk = ext4_inode_bitmap(sb, desc); + if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || + (bitmap_blk >= ext4_blocks_count(sbi->s_es))) { + ext4_error(sb, "Invalid inode bitmap blk %llu in " + "block_group %u", bitmap_blk, block_group); + return ERR_PTR(-EFSCORRUPTED); + } bh = sb_getblk(sb, bitmap_blk); if (unlikely(!bh)) { ext4_error(sb, "Cannot read inode bitmap - " -- GitLab From 1fd7c778ebf0f74e0aadcdf112800736cfdbca00 Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Tue, 24 Apr 2018 11:31:44 -0400 Subject: [PATCH 107/855] ext4: fix bitmap position validation commit 22be37acce25d66ecf6403fc8f44df9c5ded2372 upstream. Currently in ext4_valid_block_bitmap() we expect the bitmap to be positioned anywhere between 0 and s_blocksize clusters, but that's wrong because the bitmap can be placed anywhere in the block group. This causes false positives when validating bitmaps on perfectly valid file system layouts. Fix it by checking whether the bitmap is within the group boundary. The problem can be reproduced using the following mkfs -t ext3 -E stride=256 /dev/vdb1 mount /dev/vdb1 /mnt/test cd /mnt/test wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.16.3.tar.xz tar xf linux-4.16.3.tar.xz This will result in the warnings in the logs EXT4-fs error (device vdb1): ext4_validate_block_bitmap:399: comm tar: bg 84: block 2774529: invalid block bitmap [ Changed slightly for clarity and to not drop a overflow test -- TYT ] Signed-off-by: Lukas Czerner Signed-off-by: Theodore Ts'o Reported-by: Ilya Dryomov Fixes: 7dac4a1726a9 ("ext4: add validity checks for bitmap block numbers") Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/balloc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 49567ceb7664..6776f4aa3d12 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -320,6 +320,7 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb, struct ext4_sb_info *sbi = EXT4_SB(sb); ext4_grpblk_t offset; ext4_grpblk_t next_zero_bit; + ext4_grpblk_t max_bit = EXT4_CLUSTERS_PER_GROUP(sb); ext4_fsblk_t blk; ext4_fsblk_t group_first_block; @@ -337,7 +338,7 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb, /* check whether block bitmap block number is set */ blk = ext4_block_bitmap(sb, desc); offset = blk - group_first_block; - if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || + if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit || !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) /* bad block bitmap */ return blk; @@ -345,7 +346,7 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb, /* check whether the inode bitmap block number is set */ blk = ext4_inode_bitmap(sb, desc); offset = blk - group_first_block; - if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || + if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit || !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) /* bad block bitmap */ return blk; @@ -353,8 +354,8 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb, /* check whether the inode table block number is set */ blk = ext4_inode_table(sb, desc); offset = blk - group_first_block; - if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || - EXT4_B2C(sbi, offset + sbi->s_itb_per_group) >= sb->s_blocksize) + if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit || + EXT4_B2C(sbi, offset + sbi->s_itb_per_group) >= max_bit) return blk; next_zero_bit = ext4_find_next_zero_bit(bh->b_data, EXT4_B2C(sbi, offset + EXT4_SB(sb)->s_itb_per_group), -- GitLab From 2971585b27f6a810c50b6f3a9ac391aa4d13fdf5 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 11 Apr 2018 15:23:56 -0400 Subject: [PATCH 108/855] random: set up the NUMA crng instances after the CRNG is fully initialized commit 8ef35c866f8862df074a49a93b0309725812dea8 upstream. Until the primary_crng is fully initialized, don't initialize the NUMA crng nodes. Otherwise users of /dev/urandom on NUMA systems before the CRNG is fully initialized can get very bad quality randomness. Of course everyone should move to getrandom(2) where this won't be an issue, but there's a lot of legacy code out there. This related to CVE-2018-1108. Reported-by: Jann Horn Fixes: 1e7f583af67b ("random: make /dev/urandom scalable for silly...") Cc: stable@kernel.org # 4.8+ Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 46 +++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 8d08a8062904..b979173cb0e1 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -819,6 +819,32 @@ static int crng_fast_load(const char *cp, size_t len) return 1; } +#ifdef CONFIG_NUMA +static void numa_crng_init(void) +{ + int i; + struct crng_state *crng; + struct crng_state **pool; + + pool = kcalloc(nr_node_ids, sizeof(*pool), GFP_KERNEL|__GFP_NOFAIL); + for_each_online_node(i) { + crng = kmalloc_node(sizeof(struct crng_state), + GFP_KERNEL | __GFP_NOFAIL, i); + spin_lock_init(&crng->lock); + crng_initialize(crng); + pool[i] = crng; + } + mb(); + if (cmpxchg(&crng_node_pool, NULL, pool)) { + for_each_node(i) + kfree(pool[i]); + kfree(pool); + } +} +#else +static void numa_crng_init(void) {} +#endif + static void crng_reseed(struct crng_state *crng, struct entropy_store *r) { unsigned long flags; @@ -848,6 +874,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) memzero_explicit(&buf, sizeof(buf)); crng->init_time = jiffies; if (crng == &primary_crng && crng_init < 2) { + numa_crng_init(); crng_init = 2; process_random_ready_list(); wake_up_interruptible(&crng_init_wait); @@ -1661,29 +1688,10 @@ static void init_std_data(struct entropy_store *r) */ static int rand_initialize(void) { -#ifdef CONFIG_NUMA - int i; - struct crng_state *crng; - struct crng_state **pool; -#endif - init_std_data(&input_pool); init_std_data(&blocking_pool); crng_initialize(&primary_crng); crng_global_init_time = jiffies; - -#ifdef CONFIG_NUMA - pool = kcalloc(nr_node_ids, sizeof(*pool), GFP_KERNEL|__GFP_NOFAIL); - for_each_online_node(i) { - crng = kmalloc_node(sizeof(struct crng_state), - GFP_KERNEL | __GFP_NOFAIL, i); - spin_lock_init(&crng->lock); - crng_initialize(crng); - pool[i] = crng; - } - mb(); - crng_node_pool = pool; -#endif return 0; } early_initcall(rand_initialize); -- GitLab From c3ff2da5cef05676d490fa9057b2dceb5e48cdb9 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 23 Apr 2018 18:51:28 -0400 Subject: [PATCH 109/855] random: fix possible sleeping allocation from irq context commit 6c1e851c4edc13a43adb3ea4044e3fc8f43ccf7d upstream. We can do a sleeping allocation from an irq context when CONFIG_NUMA is enabled. Fix this by initializing the NUMA crng instances in a workqueue. Reported-by: Tetsuo Handa Reported-by: syzbot+9de458f6a5e713ee8c1a@syzkaller.appspotmail.com Fixes: 8ef35c866f8862df ("random: set up the NUMA crng instances...") Cc: stable@vger.kernel.org Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index b979173cb0e1..dbfb3e69600b 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -820,7 +820,7 @@ static int crng_fast_load(const char *cp, size_t len) } #ifdef CONFIG_NUMA -static void numa_crng_init(void) +static void do_numa_crng_init(struct work_struct *work) { int i; struct crng_state *crng; @@ -841,6 +841,13 @@ static void numa_crng_init(void) kfree(pool); } } + +static DECLARE_WORK(numa_crng_init_work, do_numa_crng_init); + +static void numa_crng_init(void) +{ + schedule_work(&numa_crng_init_work); +} #else static void numa_crng_init(void) {} #endif -- GitLab From 17e20c8b5a2c0165516f9595e6ef65471326d532 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 25 Apr 2018 01:12:32 -0400 Subject: [PATCH 110/855] random: rate limit unseeded randomness warnings commit 4e00b339e264802851aff8e73cde7d24b57b18ce upstream. On systems without sufficient boot randomness, no point spamming dmesg. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index dbfb3e69600b..ddeac4eefd0a 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -259,6 +259,7 @@ #include #include #include +#include #include #include #include @@ -444,6 +445,16 @@ static void _crng_backtrack_protect(struct crng_state *crng, __u8 tmp[CHACHA20_BLOCK_SIZE], int used); static void process_random_ready_list(void); +static struct ratelimit_state unseeded_warning = + RATELIMIT_STATE_INIT("warn_unseeded_randomness", HZ, 3); +static struct ratelimit_state urandom_warning = + RATELIMIT_STATE_INIT("warn_urandom_randomness", HZ, 3); + +static int ratelimit_disable __read_mostly; + +module_param_named(ratelimit_disable, ratelimit_disable, int, 0644); +MODULE_PARM_DESC(ratelimit_disable, "Disable random ratelimit suppression"); + /********************************************************************** * * OS independent entropy store. Here are the functions which handle @@ -886,6 +897,18 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) process_random_ready_list(); wake_up_interruptible(&crng_init_wait); pr_notice("random: crng init done\n"); + if (unseeded_warning.missed) { + pr_notice("random: %d get_random_xx warning(s) missed " + "due to ratelimiting\n", + unseeded_warning.missed); + unseeded_warning.missed = 0; + } + if (urandom_warning.missed) { + pr_notice("random: %d urandom warning(s) missed " + "due to ratelimiting\n", + urandom_warning.missed); + urandom_warning.missed = 0; + } } spin_unlock_irqrestore(&crng->lock, flags); } @@ -1699,6 +1722,10 @@ static int rand_initialize(void) init_std_data(&blocking_pool); crng_initialize(&primary_crng); crng_global_init_time = jiffies; + if (ratelimit_disable) { + urandom_warning.interval = 0; + unseeded_warning.interval = 0; + } return 0; } early_initcall(rand_initialize); @@ -1766,9 +1793,10 @@ urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) if (!crng_ready() && maxwarn > 0) { maxwarn--; - printk(KERN_NOTICE "random: %s: uninitialized urandom read " - "(%zd bytes read)\n", - current->comm, nbytes); + if (__ratelimit(&urandom_warning)) + printk(KERN_NOTICE "random: %s: uninitialized " + "urandom read (%zd bytes read)\n", + current->comm, nbytes); spin_lock_irqsave(&primary_crng.lock, flags); crng_init_cnt = 0; spin_unlock_irqrestore(&primary_crng.lock, flags); -- GitLab From 3bebadf9931e00901f62f45f5b73ee49989bec7f Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 5 Apr 2018 16:29:50 -0600 Subject: [PATCH 111/855] usbip: usbip_event: fix to not print kernel pointer address commit 4c982482341c64f55daf69b6caa5a2bcd9b43824 upstream. Fix it to not print kernel pointer address. Remove the conditional and debug message as it isn't very useful. Signed-off-by: Shuah Khan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/usbip_event.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/usb/usbip/usbip_event.c b/drivers/usb/usbip/usbip_event.c index f1635662c299..f8f7f3803a99 100644 --- a/drivers/usb/usbip/usbip_event.c +++ b/drivers/usb/usbip/usbip_event.c @@ -105,10 +105,6 @@ static void event_handler(struct work_struct *work) unset_event(ud, USBIP_EH_UNUSABLE); } - /* Stop the error handler. */ - if (ud->event & USBIP_EH_BYE) - usbip_dbg_eh("removed %p\n", ud); - wake_up(&ud->eh_waitq); } } -- GitLab From 039cb1bb0b8904d3105150bb6908d05de7202111 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 5 Apr 2018 16:29:04 -0600 Subject: [PATCH 112/855] usbip: usbip_host: fix to hold parent lock for device_attach() calls commit 4bfb141bc01312a817d36627cc47c93f801c216d upstream. usbip_host calls device_attach() without holding dev->parent lock. Fix it. Signed-off-by: Shuah Khan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/stub_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index 325b4c05acdd..f761e02e75c9 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -201,7 +201,12 @@ static ssize_t rebind_store(struct device_driver *dev, const char *buf, if (!bid) return -ENODEV; + /* device_attach() callers should hold parent lock for USB */ + if (bid->udev->dev.parent) + device_lock(bid->udev->dev.parent); ret = device_attach(&bid->udev->dev); + if (bid->udev->dev.parent) + device_unlock(bid->udev->dev.parent); if (ret < 0) { dev_err(&bid->udev->dev, "rebind failed\n"); return ret; -- GitLab From c0182ba5accbb1d8c7cc84a25cadb6fcf0132c98 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Mon, 2 Apr 2018 14:52:32 -0600 Subject: [PATCH 113/855] usbip: vhci_hcd: Fix usb device and sockfd leaks commit 9020a7efe537856eb3e826ebebdf38a5d07a7857 upstream. vhci_hcd fails to do reset to put usb device and sockfd in the module remove/stop paths. Fix the leak. Signed-off-by: Shuah Khan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/usbip_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h index f0b955f8504e..109e65ba01a0 100644 --- a/drivers/usb/usbip/usbip_common.h +++ b/drivers/usb/usbip/usbip_common.h @@ -258,7 +258,7 @@ enum usbip_side { #define VUDC_EVENT_ERROR_USB (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE) #define VUDC_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE) -#define VDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_BYE) +#define VDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_RESET | USBIP_EH_BYE) #define VDEV_EVENT_DOWN (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) #define VDEV_EVENT_ERROR_TCP (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) #define VDEV_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE) -- GitLab From af50b899fe3871cf4d1b2d5cffe1e6f218dfffde Mon Sep 17 00:00:00 2001 From: Collin May Date: Sat, 7 Apr 2018 14:32:48 -0700 Subject: [PATCH 114/855] USB: serial: simple: add libtransistor console commit fe710508b6ba9d28730f3021fed70e7043433b2e upstream. Add simple driver for libtransistor USB console. This device is implemented in software: https://github.com/reswitched/libtransistor/blob/development/lib/usb_serial.c Signed-off-by: Collin May Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/Kconfig | 1 + drivers/usb/serial/usb-serial-simple.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 584ae8cbaf1c..77c3ebe860c5 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -62,6 +62,7 @@ config USB_SERIAL_SIMPLE - Fundamental Software dongle. - Google USB serial devices - HP4x calculators + - Libtransistor USB console - a number of Motorola phones - Motorola Tetra devices - Novatel Wireless GPS receivers diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 6aa7ff2c1cf7..2674da40d9cd 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -66,6 +66,11 @@ DEVICE(flashloader, FLASHLOADER_IDS); 0x01) } DEVICE(google, GOOGLE_IDS); +/* Libtransistor USB console */ +#define LIBTRANSISTOR_IDS() \ + { USB_DEVICE(0x1209, 0x8b00) } +DEVICE(libtransistor, LIBTRANSISTOR_IDS); + /* ViVOpay USB Serial Driver */ #define VIVOPAY_IDS() \ { USB_DEVICE(0x1d5f, 0x1004) } /* ViVOpay 8800 */ @@ -113,6 +118,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &funsoft_device, &flashloader_device, &google_device, + &libtransistor_device, &vivopay_device, &moto_modem_device, &motorola_tetra_device, @@ -129,6 +135,7 @@ static const struct usb_device_id id_table[] = { FUNSOFT_IDS(), FLASHLOADER_IDS(), GOOGLE_IDS(), + LIBTRANSISTOR_IDS(), VIVOPAY_IDS(), MOTO_IDS(), MOTOROLA_TETRA_IDS(), -- GitLab From 1c971e495035973c962b1bdc56086966fc4382e2 Mon Sep 17 00:00:00 2001 From: Vasyl Vavrychuk Date: Wed, 11 Apr 2018 17:05:13 +0300 Subject: [PATCH 115/855] USB: serial: ftdi_sio: use jtag quirk for Arrow USB Blaster commit 470b5d6f0cf4674be2d1ec94e54283a1770b6a1a upstream. Arrow USB Blaster integrated on MAX1000 board uses the same vendor ID (0x0403) and product ID (0x6010) as the "original" FTDI device. This patch avoids picking up by ftdi_sio of the first interface of this USB device. After that this device can be used by Arrow user-space JTAG driver. Signed-off-by: Vasyl Vavrychuk Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 71cbc6890ac4..2e2f736384ab 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1911,7 +1911,8 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial) return ftdi_jtag_probe(serial); if (udev->product && - (!strcmp(udev->product, "BeagleBone/XDS100V2") || + (!strcmp(udev->product, "Arrow USB Blaster") || + !strcmp(udev->product, "BeagleBone/XDS100V2") || !strcmp(udev->product, "SNAP Connect E10"))) return ftdi_jtag_probe(serial); -- GitLab From 52721f22b88e549786611772629fdfbc9b8bab2e Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Mon, 9 Apr 2018 10:23:55 -0500 Subject: [PATCH 116/855] USB: serial: cp210x: add ID for NI USB serial console commit 1e23aace21515a8f7615a1de016c0ea8d4e0cc6e upstream. Added the USB VID and PID for the USB serial console on some National Instruments devices. Signed-off-by: Kyle Roeschley Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index cab80acace4e..d98531823998 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -211,6 +211,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */ { USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */ { USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */ + { USB_DEVICE(0x3923, 0x7A0B) }, /* National Instruments USB Serial Console */ { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ { } /* Terminating Entry */ }; -- GitLab From e4f3654446490508caf7d64b8f10d429be49f0c8 Mon Sep 17 00:00:00 2001 From: Kamil Lulko Date: Thu, 19 Apr 2018 16:54:02 -0700 Subject: [PATCH 117/855] usb: core: Add quirk for HP v222w 16GB Mini commit 3180dabe08e3653bf0a838553905d88f3773f29c upstream. Add DELAY_INIT quirk to fix the following problem with HP v222w 16GB Mini: usb 1-3: unable to read config index 0 descriptor/start: -110 usb 1-3: can't read configurations, error -110 usb 1-3: can't set config #1, error -110 Signed-off-by: Kamil Lulko Signed-off-by: Kuppuswamy Sathyanarayanan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 4f1c6f8d4352..40ce175655e6 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -45,6 +45,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 }, + /* HP v222w 16GB Mini USB Drive */ + { USB_DEVICE(0x03f0, 0x3f40), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Creative SB Audigy 2 NX */ { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, -- GitLab From 00bc34802fb84aafa5cc11f5fcd568b9a53b05f0 Mon Sep 17 00:00:00 2001 From: Ravi Chandra Sadineni Date: Fri, 20 Apr 2018 11:08:21 -0700 Subject: [PATCH 118/855] USB: Increment wakeup count on remote wakeup. commit 83a62c51ba7b3c0bf45150c4eac7aefc6c785e94 upstream. On chromebooks we depend on wakeup count to identify the wakeup source. But currently USB devices do not increment the wakeup count when they trigger the remote wake. This patch addresses the same. Resume condition is reported differently on USB 2.0 and USB 3.0 devices. On USB 2.0 devices, a wake capable device, if wake enabled, drives resume signal to indicate a remote wake (USB 2.0 spec section 7.1.7.7). The upstream facing port then sets C_PORT_SUSPEND bit and reports a port change event (USB 2.0 spec section 11.24.2.7.2.3). Thus if a port has resumed before driving the resume signal from the host and C_PORT_SUSPEND is set, then the device attached to the given port might be the reason for the last system wakeup. Increment the wakeup count for the same. On USB 3.0 devices, a function may signal that it wants to exit from device suspend by sending a Function Wake Device Notification to the host (USB3.0 spec section 8.5.6.4) Thus on receiving the Function Wake, increment the wakeup count. Signed-off-by: Ravi Chandra Sadineni Acked-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 1 + drivers/usb/core/hub.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index fcc7aa248ce7..bdb0d7a08ff9 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2365,6 +2365,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd) spin_lock_irqsave (&hcd_root_hub_lock, flags); if (hcd->rh_registered) { + pm_wakeup_event(&hcd->self.root_hub->dev, 0); set_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags); queue_work(pm_wq, &hcd->wakeup_work); } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index d0d3f9ef9f10..d8d992b73e88 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -648,12 +648,17 @@ void usb_wakeup_notification(struct usb_device *hdev, unsigned int portnum) { struct usb_hub *hub; + struct usb_port *port_dev; if (!hdev) return; hub = usb_hub_to_struct_hub(hdev); if (hub) { + port_dev = hub->ports[portnum - 1]; + if (port_dev && port_dev->child) + pm_wakeup_event(&port_dev->child->dev, 0); + set_bit(portnum, hub->wakeup_bits); kick_hub_wq(hub); } @@ -3417,8 +3422,11 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) /* Skip the initial Clear-Suspend step for a remote wakeup */ status = hub_port_status(hub, port1, &portstatus, &portchange); - if (status == 0 && !port_is_suspended(hub, portstatus)) + if (status == 0 && !port_is_suspended(hub, portstatus)) { + if (portchange & USB_PORT_STAT_C_SUSPEND) + pm_wakeup_event(&udev->dev, 0); goto SuspendCleared; + } /* see 7.1.7.7; affects power usage, but not budgeting */ if (hub_is_superspeed(hub->hdev)) -- GitLab From 0160bda77b3360ee3a2993ae8ac64fed90998375 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 11:11:48 +0200 Subject: [PATCH 119/855] ALSA: usb-audio: Skip broken EU on Dell dock USB-audio commit 1d8d6428d1da642ddd75b0be2d1bb1123ff8e017 upstream. The Dell Dock USB-audio device with 0bda:4014 is behaving notoriously bad, and we have already applied some workaround to avoid the firmware hiccup. Yet we still need to skip one thing, the Extension Unit at ID 4, which doesn't react correctly to the mixer ctl access. Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1090658 Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/mixer_maps.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 9038b2e7df73..eaa03acd4686 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -353,8 +353,11 @@ static struct usbmix_name_map bose_companion5_map[] = { /* * Dell usb dock with ALC4020 codec had a firmware problem where it got * screwed up when zero volume is passed; just skip it as a workaround + * + * Also the extension unit gives an access error, so skip it as well. */ static const struct usbmix_name_map dell_alc4020_map[] = { + { 4, NULL }, /* extension unit */ { 16, NULL }, { 19, NULL }, { 0 } -- GitLab From 90488aaaf37f7cf3b49f834b4fd9a66bf773d7ec Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 20 Apr 2018 20:22:40 +0300 Subject: [PATCH 120/855] virtio: add ability to iterate over vqs commit 24a7e4d20783c0514850f24a5c41ede46ab058f0 upstream. For cleanup it's helpful to be able to simply scan all vqs and discard all data. Add an iterator to do that. Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- include/linux/virtio.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/virtio.h b/include/linux/virtio.h index d5eb5479a425..3f8f35053260 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -143,6 +143,9 @@ int virtio_device_freeze(struct virtio_device *dev); int virtio_device_restore(struct virtio_device *dev); #endif +#define virtio_device_for_each_vq(vdev, vq) \ + list_for_each_entry(vq, &vdev->vqs, list) + /** * virtio_driver - operations for a virtio I/O driver * @driver: underlying device driver (populate name and owner). -- GitLab From 47cb14192bcbba3f15b1c3561e05e084e56fdef6 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 20 Apr 2018 20:24:23 +0300 Subject: [PATCH 121/855] virtio_console: free buffers after reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a7a69ec0d8e4a58be7db88d33cbfa2912807bb2b upstream. Console driver is out of spec. The spec says: A driver MUST NOT decrement the available idx on a live virtqueue (ie. there is no way to “unexpose” buffers). and it does exactly that by trying to detach unused buffers without doing a device reset first. Defer detaching the buffers until device unplug. Of course this means we might get an interrupt for a vq without an attached port now. Handle that by discarding the consumed buffer. Reported-by: Tiwei Bie Fixes: b3258ff1d6 ("virtio: Decrement avail idx on buffer detach") Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/char/virtio_console.c | 49 +++++++++++++++++------------------ 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8f890c1aca57..8c0017d48571 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1405,7 +1405,6 @@ static int add_port(struct ports_device *portdev, u32 id) { char debugfs_name[16]; struct port *port; - struct port_buffer *buf; dev_t devt; unsigned int nr_added_bufs; int err; @@ -1516,8 +1515,6 @@ static int add_port(struct ports_device *portdev, u32 id) return 0; free_inbufs: - while ((buf = virtqueue_detach_unused_buf(port->in_vq))) - free_buf(buf, true); free_device: device_destroy(pdrvdata.class, port->dev->devt); free_cdev: @@ -1542,34 +1539,14 @@ static void remove_port(struct kref *kref) static void remove_port_data(struct port *port) { - struct port_buffer *buf; - spin_lock_irq(&port->inbuf_lock); /* Remove unused data this port might have received. */ discard_port_data(port); spin_unlock_irq(&port->inbuf_lock); - /* Remove buffers we queued up for the Host to send us data in. */ - do { - spin_lock_irq(&port->inbuf_lock); - buf = virtqueue_detach_unused_buf(port->in_vq); - spin_unlock_irq(&port->inbuf_lock); - if (buf) - free_buf(buf, true); - } while (buf); - spin_lock_irq(&port->outvq_lock); reclaim_consumed_buffers(port); spin_unlock_irq(&port->outvq_lock); - - /* Free pending buffers from the out-queue. */ - do { - spin_lock_irq(&port->outvq_lock); - buf = virtqueue_detach_unused_buf(port->out_vq); - spin_unlock_irq(&port->outvq_lock); - if (buf) - free_buf(buf, true); - } while (buf); } /* @@ -1794,13 +1771,24 @@ static void control_work_handler(struct work_struct *work) spin_unlock(&portdev->c_ivq_lock); } +static void flush_bufs(struct virtqueue *vq, bool can_sleep) +{ + struct port_buffer *buf; + unsigned int len; + + while ((buf = virtqueue_get_buf(vq, &len))) + free_buf(buf, can_sleep); +} + static void out_intr(struct virtqueue *vq) { struct port *port; port = find_port_by_vq(vq->vdev->priv, vq); - if (!port) + if (!port) { + flush_bufs(vq, false); return; + } wake_up_interruptible(&port->waitqueue); } @@ -1811,8 +1799,10 @@ static void in_intr(struct virtqueue *vq) unsigned long flags; port = find_port_by_vq(vq->vdev->priv, vq); - if (!port) + if (!port) { + flush_bufs(vq, false); return; + } spin_lock_irqsave(&port->inbuf_lock, flags); port->inbuf = get_inbuf(port); @@ -1987,6 +1977,15 @@ static const struct file_operations portdev_fops = { static void remove_vqs(struct ports_device *portdev) { + struct virtqueue *vq; + + virtio_device_for_each_vq(portdev->vdev, vq) { + struct port_buffer *buf; + + flush_bufs(vq, true); + while ((buf = virtqueue_detach_unused_buf(vq))) + free_buf(buf, true); + } portdev->vdev->config->del_vqs(portdev->vdev); kfree(portdev->in_vqs); kfree(portdev->out_vqs); -- GitLab From 97f54c13b6aaa49eeb9688e851d1ff955f45f5c3 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 3 Apr 2018 11:59:04 +0200 Subject: [PATCH 122/855] drm/virtio: fix vq wait_event condition commit d02d270014f70dcab0117776b81a37b6fca745ae upstream. Wait until we have enough space in the virt queue to actually queue up our request. Avoids the guest spinning in case we have a non-zero amount of free entries but not enough for the request. Cc: stable@vger.kernel.org Reported-by: Alain Magloire Signed-off-by: Gerd Hoffmann Reviewed-by: Dave Airlie Link: http://patchwork.freedesktop.org/patch/msgid/20180403095904.11152-1-kraxel@redhat.com Signed-off-by: Sean Paul Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/virtio/virtgpu_vq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 5a0f8a745b9d..52436b3c01bb 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -324,7 +324,7 @@ static int virtio_gpu_queue_ctrl_buffer_locked(struct virtio_gpu_device *vgdev, ret = virtqueue_add_sgs(vq, sgs, outcnt, incnt, vbuf, GFP_ATOMIC); if (ret == -ENOSPC) { spin_unlock(&vgdev->ctrlq.qlock); - wait_event(vgdev->ctrlq.ack_queue, vq->num_free); + wait_event(vgdev->ctrlq.ack_queue, vq->num_free >= outcnt + incnt); spin_lock(&vgdev->ctrlq.qlock); goto retry; } else { @@ -399,7 +399,7 @@ static int virtio_gpu_queue_cursor(struct virtio_gpu_device *vgdev, ret = virtqueue_add_sgs(vq, sgs, outcnt, 0, vbuf, GFP_ATOMIC); if (ret == -ENOSPC) { spin_unlock(&vgdev->cursorq.qlock); - wait_event(vgdev->cursorq.ack_queue, vq->num_free); + wait_event(vgdev->cursorq.ack_queue, vq->num_free >= outcnt); spin_lock(&vgdev->cursorq.qlock); goto retry; } else { -- GitLab From 6a506d48c187e621ca846b6c5b951411d5b7f531 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 5 Apr 2018 19:40:16 +0900 Subject: [PATCH 123/855] tty: Don't call panic() at tty_ldisc_init() commit 903f9db10f18f735e62ba447147b6c434b6af003 upstream. syzbot is reporting kernel panic [1] triggered by memory allocation failure at tty_ldisc_get() from tty_ldisc_init(). But since both tty_ldisc_get() and caller of tty_ldisc_init() can cleanly handle errors, tty_ldisc_init() does not need to call panic() when tty_ldisc_get() failed. [1] https://syzkaller.appspot.com/bug?id=883431818e036ae6a9981156a64b821110f39187 Signed-off-by: Tetsuo Handa Reported-by: syzbot Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 5 ++++- drivers/tty/tty_ldisc.c | 5 +++-- include/linux/tty.h | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 4ee0a9de7556..789c81482542 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3170,7 +3170,10 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) kref_init(&tty->kref); tty->magic = TTY_MAGIC; - tty_ldisc_init(tty); + if (tty_ldisc_init(tty)) { + kfree(tty); + return NULL; + } tty->session = NULL; tty->pgrp = NULL; mutex_init(&tty->legacy_mutex); diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 3a9e2a2fd4c6..96f0d1090888 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -753,12 +753,13 @@ void tty_ldisc_release(struct tty_struct *tty) * the tty structure is not completely set up when this call is made. */ -void tty_ldisc_init(struct tty_struct *tty) +int tty_ldisc_init(struct tty_struct *tty) { struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY); if (IS_ERR(ld)) - panic("n_tty: init_tty"); + return PTR_ERR(ld); tty->ldisc = ld; + return 0; } /** diff --git a/include/linux/tty.h b/include/linux/tty.h index 6f1ee8528210..fe1b8623a3a1 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -657,7 +657,7 @@ extern int tty_unregister_ldisc(int disc); extern int tty_set_ldisc(struct tty_struct *tty, int disc); extern int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty); extern void tty_ldisc_release(struct tty_struct *tty); -extern void tty_ldisc_init(struct tty_struct *tty); +extern int __must_check tty_ldisc_init(struct tty_struct *tty); extern void tty_ldisc_deinit(struct tty_struct *tty); extern int tty_ldisc_receive_buf(struct tty_ldisc *ld, unsigned char *p, char *f, int count); -- GitLab From 11723a916fb7d7e1b303e0a331e4a8214830a9e4 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sat, 7 Apr 2018 10:19:50 -0700 Subject: [PATCH 124/855] tty: n_gsm: Fix long delays with control frame timeouts in ADM mode commit e9ec22547986dd32c5c70da78107ce35dbff1344 upstream. Commit ea3d8465ab9b ("tty: n_gsm: Allow ADM response in addition to UA for control dlci") added support for DLCI to stay in Asynchronous Disconnected Mode (ADM). But we still get long delays waiting for commands to other DLCI to complete: --> 5) C: SABM(P) Q> 0) C: UIH(F) Q> 0) C: UIH(F) Q> 0) C: UIH(F) ... This happens because gsm_control_send() sets cretries timer to T2 that is by default set to 34. This will cause resend for T2 times for the control frame. In ADM mode, we will never get a response so the control frame, so retries are just delaying all the commands. Let's fix the issue by setting DLCI_MODE_ADM flag after detecting the ADM mode for the control DLCI. Then we can use that in gsm_control_send() to set retries to 1. This means the control frame will be sent once allowing the other end at an opportunity to switch from ADM to ABM mode. Note that retries will be decremented in gsm_control_retransmit() so we don't want to set it to 0 here. Fixes: ea3d8465ab9b ("tty: n_gsm: Allow ADM response in addition to UA for control dlci") Cc: linux-serial@vger.kernel.org Cc: Alan Cox Cc: Dan Williams Cc: Jiri Prchal Cc: Jiri Slaby Cc: Marcel Partap Cc: Merlijn Wajer Cc: Michael Nazzareno Trimarchi Cc: Michael Scott Cc: Pavel Machek Cc: Peter Hurley Cc: Russ Gorby Cc: Sascha Hauer Cc: Sebastian Reichel Signed-off-by: Tony Lindgren Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index fe2291795d2f..f2ba65ba1ef6 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -137,6 +137,9 @@ struct gsm_dlci { struct mutex mutex; /* Link layer */ + int mode; +#define DLCI_MODE_ABM 0 /* Normal Asynchronous Balanced Mode */ +#define DLCI_MODE_ADM 1 /* Asynchronous Disconnected Mode */ spinlock_t lock; /* Protects the internal state */ struct timer_list t1; /* Retransmit timer for SABM and UA */ int retries; @@ -1380,7 +1383,13 @@ static struct gsm_control *gsm_control_send(struct gsm_mux *gsm, ctrl->data = data; ctrl->len = clen; gsm->pending_cmd = ctrl; - gsm->cretries = gsm->n2; + + /* If DLCI0 is in ADM mode skip retries, it won't respond */ + if (gsm->dlci[0]->mode == DLCI_MODE_ADM) + gsm->cretries = 1; + else + gsm->cretries = gsm->n2; + mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100); gsm_control_transmit(gsm, ctrl); spin_unlock_irqrestore(&gsm->control_lock, flags); @@ -1488,6 +1497,7 @@ static void gsm_dlci_t1(unsigned long data) if (debug & 8) pr_info("DLCI %d opening in ADM mode.\n", dlci->addr); + dlci->mode = DLCI_MODE_ADM; gsm_dlci_open(dlci); } else { gsm_dlci_close(dlci); -- GitLab From 5080d3339eaf9eff6765ec99c29bede5df80a360 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sat, 7 Apr 2018 10:19:51 -0700 Subject: [PATCH 125/855] tty: n_gsm: Fix DLCI handling for ADM mode if debug & 2 is not set commit b2d89ad9c9682e795ed6eeb9ed455789ad6cedf1 upstream. At least on droid 4 with control channel in ADM mode, there is no response to Modem Status Command (MSC). Currently gsmtty_modem_update() expects to have data in dlci->modem_rx unless debug & 2 is set. This means that on droid 4, things only work if debug & 2 is set. Let's fix the issue by ignoring empty dlci->modem_rx for ADM mode. In the AMD mode, CMD_MSC will never respond and gsm_process_modem() won't get called to set dlci->modem_rx. And according to ts_127010v140000p.pdf, MSC is only relevant if basic option is chosen, so let's test for that too. Fixes: ea3d8465ab9b ("tty: n_gsm: Allow ADM response in addition to UA for control dlci") Cc: linux-serial@vger.kernel.org Cc: Alan Cox Cc: Dan Williams Cc: Jiri Prchal Cc: Jiri Slaby Cc: Marcel Partap Cc: Merlijn Wajer Cc: Michael Nazzareno Trimarchi Cc: Michael Scott Cc: Pavel Machek Cc: Peter Hurley Cc: Russ Gorby Cc: Sascha Hauer Cc: Sebastian Reichel Signed-off-by: Tony Lindgren Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index f2ba65ba1ef6..9e9016e67843 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2875,11 +2875,22 @@ static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk) static int gsm_carrier_raised(struct tty_port *port) { struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port); + struct gsm_mux *gsm = dlci->gsm; + /* Not yet open so no carrier info */ if (dlci->state != DLCI_OPEN) return 0; if (debug & 2) return 1; + + /* + * Basic mode with control channel in ADM mode may not respond + * to CMD_MSC at all and modem_rx is empty. + */ + if (gsm->encoding == 0 && gsm->dlci[0]->mode == DLCI_MODE_ADM && + !dlci->modem_rx) + return 1; + return dlci->modem_rx & TIOCM_CD; } -- GitLab From ad30f0539ae71c09bba067ad72770b3a0d800686 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 25 Apr 2018 20:12:31 +0900 Subject: [PATCH 126/855] tty: Use __GFP_NOFAIL for tty_ldisc_get() commit bcdd0ca8cb8730573afebcaae4138f8f4c8eaa20 upstream. syzbot is reporting crashes triggered by memory allocation fault injection at tty_ldisc_get() [1]. As an attempt to handle OOM in a graceful way, we have tried commit 5362544bebe85071 ("tty: don't panic on OOM in tty_set_ldisc()"). But we reverted that attempt by commit a8983d01f9b7d600 ("Revert "tty: don't panic on OOM in tty_set_ldisc()"") due to reproducible crash. We should spend resource for finding and fixing race condition bugs rather than complicate error paths for 2 * sizeof(void *) bytes allocation failure. [1] https://syzkaller.appspot.com/bug?id=489d33fa386453859ead58ff5171d43772b13aa3 Signed-off-by: Tetsuo Handa Reported-by: syzbot Cc: Michal Hocko Cc: Vegard Nossum Cc: Dmitry Vyukov Cc: Jiri Slaby Cc: Peter Hurley Cc: One Thousand Gnomes Cc: Linus Torvalds Cc: stable Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ldisc.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 96f0d1090888..4ab518d43758 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -175,12 +175,11 @@ static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc) return ERR_CAST(ldops); } - ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL); - if (ld == NULL) { - put_ldops(ldops); - return ERR_PTR(-ENOMEM); - } - + /* + * There is no way to handle allocation failure of only 16 bytes. + * Let's simplify error handling and save more memory. + */ + ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL | __GFP_NOFAIL); ld->ops = ldops; ld->tty = tty; -- GitLab From c2424856f87b8ab41fc2ee8310663f10e6654eb6 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 22 Apr 2018 21:19:24 +0900 Subject: [PATCH 127/855] ALSA: dice: fix OUI for TC group commit 10412c420af9ba1f3de8483a95d360e5eb5bfc84 upstream. OUI for TC Electronic is 0x000166, for TC GROUP A/S. 0x001486 is for Echo Digital Audio Corporation. Fixes: 7cafc65b3aa1 ('ALSA: dice: force to add two pcm devices for listed models') Cc: # v4.6+ Reference: http://standards-oui.ieee.org/oui/oui.txt Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/firewire/dice/dice.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 25e9f77275c4..0d3d36fb1540 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -14,7 +14,7 @@ MODULE_LICENSE("GPL v2"); #define OUI_WEISS 0x001c6a #define OUI_LOUD 0x000ff2 #define OUI_FOCUSRITE 0x00130e -#define OUI_TCELECTRONIC 0x001486 +#define OUI_TCELECTRONIC 0x000166 #define DICE_CATEGORY_ID 0x04 #define WEISS_CATEGORY_ID 0x00 -- GitLab From 880c971350ebe1c9a71a8b24cb9f2acc7551d41e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 26 Apr 2018 22:00:29 +0900 Subject: [PATCH 128/855] ALSA: dice: fix error path to destroy initialized stream data commit 0f925660a7bc49b269c163249a5d06da3a0c7b0a upstream. In error path of snd_dice_stream_init_duplex(), stream data for incoming packet can be left to be initialized. This commit fixes it. Fixes: 436b5abe2224 ('ALSA: dice: handle whole available isochronous streams') Cc: # v4.6+ Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/firewire/dice/dice-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index ec4db3a514fc..257cfbfadb4a 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -425,7 +425,7 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice) err = init_stream(dice, AMDTP_IN_STREAM, i); if (err < 0) { for (; i >= 0; i--) - destroy_stream(dice, AMDTP_OUT_STREAM, i); + destroy_stream(dice, AMDTP_IN_STREAM, i); goto end; } } -- GitLab From 551a1c8aa4295a8f5bec7f8da4e1ed24b4e8f06c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 07:56:07 +0200 Subject: [PATCH 129/855] ALSA: opl3: Hardening for potential Spectre v1 commit 7f054a5bee0987f1e2d4e59daea462421c76f2cb upstream. As recently Smatch suggested, one place in OPL3 driver may expand the array directly from the user-space value with speculation: sound/drivers/opl3/opl3_synth.c:476 snd_opl3_set_voice() warn: potential spectre issue 'snd_opl3_regmap' This patch puts array_index_nospec() for hardening against it. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/drivers/opl3/opl3_synth.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c index ddcc1a325a61..42920a243328 100644 --- a/sound/drivers/opl3/opl3_synth.c +++ b/sound/drivers/opl3/opl3_synth.c @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -448,7 +449,7 @@ static int snd_opl3_set_voice(struct snd_opl3 * opl3, struct snd_dm_fm_voice * v { unsigned short reg_side; unsigned char op_offset; - unsigned char voice_offset; + unsigned char voice_offset, voice_op; unsigned short opl3_reg; unsigned char reg_val; @@ -473,7 +474,9 @@ static int snd_opl3_set_voice(struct snd_opl3 * opl3, struct snd_dm_fm_voice * v voice_offset = voice->voice - MAX_OPL2_VOICES; } /* Get register offset of operator */ - op_offset = snd_opl3_regmap[voice_offset][voice->op]; + voice_offset = array_index_nospec(voice_offset, MAX_OPL2_VOICES); + voice_op = array_index_nospec(voice->op, 4); + op_offset = snd_opl3_regmap[voice_offset][voice_op]; reg_val = 0x00; /* Set amplitude modulation (tremolo) effect */ -- GitLab From 9aa81e730fbdbcaff42e29f9213d10dc6d36bc0f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 08:01:48 +0200 Subject: [PATCH 130/855] ALSA: asihpi: Hardening for potential Spectre v1 commit f9d94b57e30fd1575b4935045b32d738668aa74b upstream. As recently Smatch suggested, a couple of places in ASIHPI driver may expand the array directly from the user-space value with speculation: sound/pci/asihpi/hpimsginit.c:70 hpi_init_response() warn: potential spectre issue 'res_size' (local cap) sound/pci/asihpi/hpioctl.c:189 asihpi_hpi_ioctl() warn: potential spectre issue 'adapters' This patch puts array_index_nospec() for hardening against them. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/asihpi/hpimsginit.c | 13 +++++++++---- sound/pci/asihpi/hpioctl.c | 4 +++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/sound/pci/asihpi/hpimsginit.c b/sound/pci/asihpi/hpimsginit.c index 7eb617175fde..a31a70dccecf 100644 --- a/sound/pci/asihpi/hpimsginit.c +++ b/sound/pci/asihpi/hpimsginit.c @@ -23,6 +23,7 @@ #include "hpi_internal.h" #include "hpimsginit.h" +#include /* The actual message size for each object type */ static u16 msg_size[HPI_OBJ_MAXINDEX + 1] = HPI_MESSAGE_SIZE_BY_OBJECT; @@ -39,10 +40,12 @@ static void hpi_init_message(struct hpi_message *phm, u16 object, { u16 size; - if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) + if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) { + object = array_index_nospec(object, HPI_OBJ_MAXINDEX + 1); size = msg_size[object]; - else + } else { size = sizeof(*phm); + } memset(phm, 0, size); phm->size = size; @@ -66,10 +69,12 @@ void hpi_init_response(struct hpi_response *phr, u16 object, u16 function, { u16 size; - if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) + if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) { + object = array_index_nospec(object, HPI_OBJ_MAXINDEX + 1); size = res_size[object]; - else + } else { size = sizeof(*phr); + } memset(phr, 0, sizeof(*phr)); phr->size = size; diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 7e3aa50b21f9..3ef9af53ef49 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef MODULE_FIRMWARE MODULE_FIRMWARE("asihpi/dsp5000.bin"); @@ -182,7 +183,8 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct hpi_adapter *pa = NULL; if (hm->h.adapter_index < ARRAY_SIZE(adapters)) - pa = &adapters[hm->h.adapter_index]; + pa = &adapters[array_index_nospec(hm->h.adapter_index, + ARRAY_SIZE(adapters))]; if (!pa || !pa->adapter || !pa->adapter->type) { hpi_init_response(&hr->r0, hm->h.object, -- GitLab From 44bb265eca2c34d6d9a253ccb2071840ad14616e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 08:03:14 +0200 Subject: [PATCH 131/855] ALSA: hdspm: Hardening for potential Spectre v1 commit 10513142a7114d251670361ad40cba2c61403406 upstream. As recently Smatch suggested, a couple of places in HDSP MADI driver may expand the array directly from the user-space value with speculation: sound/pci/rme9652/hdspm.c:5717 snd_hdspm_channel_info() warn: potential spectre issue 'hdspm->channel_map_out' (local cap) sound/pci/rme9652/hdspm.c:5734 snd_hdspm_channel_info() warn: potential spectre issue 'hdspm->channel_map_in' (local cap) This patch puts array_index_nospec() for hardening against them. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/rme9652/hdspm.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 14bbf55c1ef9..9899ef4c7efa 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -137,6 +137,7 @@ #include #include #include +#include #include #include @@ -5692,40 +5693,43 @@ static int snd_hdspm_channel_info(struct snd_pcm_substream *substream, struct snd_pcm_channel_info *info) { struct hdspm *hdspm = snd_pcm_substream_chip(substream); + unsigned int channel = info->channel; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (snd_BUG_ON(info->channel >= hdspm->max_channels_out)) { + if (snd_BUG_ON(channel >= hdspm->max_channels_out)) { dev_info(hdspm->card->dev, "snd_hdspm_channel_info: output channel out of range (%d)\n", - info->channel); + channel); return -EINVAL; } - if (hdspm->channel_map_out[info->channel] < 0) { + channel = array_index_nospec(channel, hdspm->max_channels_out); + if (hdspm->channel_map_out[channel] < 0) { dev_info(hdspm->card->dev, "snd_hdspm_channel_info: output channel %d mapped out\n", - info->channel); + channel); return -EINVAL; } - info->offset = hdspm->channel_map_out[info->channel] * + info->offset = hdspm->channel_map_out[channel] * HDSPM_CHANNEL_BUFFER_BYTES; } else { - if (snd_BUG_ON(info->channel >= hdspm->max_channels_in)) { + if (snd_BUG_ON(channel >= hdspm->max_channels_in)) { dev_info(hdspm->card->dev, "snd_hdspm_channel_info: input channel out of range (%d)\n", - info->channel); + channel); return -EINVAL; } - if (hdspm->channel_map_in[info->channel] < 0) { + channel = array_index_nospec(channel, hdspm->max_channels_in); + if (hdspm->channel_map_in[channel] < 0) { dev_info(hdspm->card->dev, "snd_hdspm_channel_info: input channel %d mapped out\n", - info->channel); + channel); return -EINVAL; } - info->offset = hdspm->channel_map_in[info->channel] * + info->offset = hdspm->channel_map_in[channel] * HDSPM_CHANNEL_BUFFER_BYTES; } -- GitLab From 92a35c4de4b13194b6c79349dac215eb808f2ae3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 08:04:41 +0200 Subject: [PATCH 132/855] ALSA: rme9652: Hardening for potential Spectre v1 commit f526afcd8f71945c23ce581d7864ace93de8a4f7 upstream. As recently Smatch suggested, one place in RME9652 driver may expand the array directly from the user-space value with speculation: sound/pci/rme9652/rme9652.c:2074 snd_rme9652_channel_info() warn: potential spectre issue 'rme9652->channel_map' (local cap) This patch puts array_index_nospec() for hardening against it. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/rme9652/rme9652.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 55172c689991..a76b1f147660 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -2036,9 +2037,10 @@ static int snd_rme9652_channel_info(struct snd_pcm_substream *substream, if (snd_BUG_ON(info->channel >= RME9652_NCHANNELS)) return -EINVAL; - if ((chn = rme9652->channel_map[info->channel]) < 0) { + chn = rme9652->channel_map[array_index_nospec(info->channel, + RME9652_NCHANNELS)]; + if (chn < 0) return -EINVAL; - } info->offset = chn * RME9652_CHANNEL_BUFFER_BYTES; info->first = 0; -- GitLab From ccbb19cf7af3907bbc9a13a5a50a17c9114d820b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 07:45:56 +0200 Subject: [PATCH 133/855] ALSA: control: Hardening for potential Spectre v1 commit 088e861edffb84879cf0c0d1b02eda078c3a0ffe upstream. As recently Smatch suggested, a few places in ALSA control core codes may expand the array directly from the user-space value with speculation: sound/core/control.c:1003 snd_ctl_elem_lock() warn: potential spectre issue 'kctl->vd' sound/core/control.c:1031 snd_ctl_elem_unlock() warn: potential spectre issue 'kctl->vd' sound/core/control.c:844 snd_ctl_elem_info() warn: potential spectre issue 'kctl->vd' sound/core/control.c:891 snd_ctl_elem_read() warn: potential spectre issue 'kctl->vd' sound/core/control.c:939 snd_ctl_elem_write() warn: potential spectre issue 'kctl->vd' Although all these seem doing only the first load without further reference, we may want to stay in a safer side, so hardening with array_index_nospec() would still make sense. In this patch, we put array_index_nospec() to the common snd_ctl_get_ioff*() helpers instead of each caller. These helpers are also referred from some drivers, too, and basically all usages are to calculate the array index from the user-space value, hence it's better to cover there. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- include/sound/control.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/sound/control.h b/include/sound/control.h index 21d047f229a1..4142757080f8 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -22,6 +22,7 @@ * */ +#include #include #define snd_kcontrol_chip(kcontrol) ((kcontrol)->private_data) @@ -147,12 +148,14 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type); static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) { - return id->numid - kctl->id.numid; + unsigned int ioff = id->numid - kctl->id.numid; + return array_index_nospec(ioff, kctl->count); } static inline unsigned int snd_ctl_get_ioffidx(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) { - return id->index - kctl->id.index; + unsigned int ioff = id->index - kctl->id.index; + return array_index_nospec(ioff, kctl->count); } static inline unsigned int snd_ctl_get_ioff(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) -- GitLab From 1704aa184b1e929b8170eb96ba5542a917fa2cda Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Sat, 21 Apr 2018 14:57:40 +0200 Subject: [PATCH 134/855] ALSA: core: Report audio_tstamp in snd_pcm_sync_ptr commit f853dcaae2f5bbe021161e421bd1576845bae8f6 upstream. It looks like a simple mistake that this struct member was forgotten. Audio_tstamp isn't used much, and on some archs (such as x86) this ioctl is not used by default, so that might be the reason why this has slipped for so long. Fixes: 4eeaaeaea1ce ("ALSA: core: add hooks for audio timestamps") Signed-off-by: David Henningsson Reviewed-by: Takashi Sakamoto Cc: # v3.8+ Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/pcm_native.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index d503285867e7..79018697b477 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2729,6 +2729,7 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, sync_ptr.s.status.hw_ptr = status->hw_ptr; sync_ptr.s.status.tstamp = status->tstamp; sync_ptr.s.status.suspended_state = status->suspended_state; + sync_ptr.s.status.audio_tstamp = status->audio_tstamp; snd_pcm_stream_unlock_irq(substream); if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) return -EFAULT; -- GitLab From 694f384e1a4df35e2f89104d5a7589ea8c09fcb6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 07:26:59 +0200 Subject: [PATCH 135/855] ALSA: seq: oss: Fix unbalanced use lock for synth MIDI device commit f5e94b4c6ebdabe0f602d796e0430180927521a0 upstream. When get_synthdev() is called for a MIDI device, it returns the fixed midi_synth_dev without the use refcounting. OTOH, the caller is supposed to unreference unconditionally after the usage, so this would lead to unbalanced refcount. This patch corrects the behavior and keep up the refcount balance also for the MIDI synth device. Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/oss/seq_oss_synth.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index cd0e0ebbfdb1..9e2b250ae780 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -363,10 +363,14 @@ get_synthdev(struct seq_oss_devinfo *dp, int dev) return NULL; if (! dp->synths[dev].opened) return NULL; - if (dp->synths[dev].is_midi) - return &midi_synth_dev; - if ((rec = get_sdev(dev)) == NULL) - return NULL; + if (dp->synths[dev].is_midi) { + rec = &midi_synth_dev; + snd_use_lock_use(&rec->use_lock); + } else { + rec = get_sdev(dev); + if (!rec) + return NULL; + } if (! rec->opened) { snd_use_lock_free(&rec->use_lock); return NULL; -- GitLab From 1e0130b609174a97331e17631883bded42852224 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 07:31:54 +0200 Subject: [PATCH 136/855] ALSA: seq: oss: Hardening for potential Spectre v1 commit 8d218dd8116695ecda7164f97631c069938aa22e upstream. As Smatch recently suggested, a few places in OSS sequencer codes may expand the array directly from the user-space value with speculation, namely there are a significant amount of references to either info->ch[] or dp->synths[] array: sound/core/seq/oss/seq_oss_event.c:315 note_on_event() warn: potential spectre issue 'info->ch' (local cap) sound/core/seq/oss/seq_oss_event.c:362 note_off_event() warn: potential spectre issue 'info->ch' (local cap) sound/core/seq/oss/seq_oss_synth.c:470 snd_seq_oss_synth_load_patch() warn: potential spectre issue 'dp->synths' (local cap) sound/core/seq/oss/seq_oss_event.c:293 note_on_event() warn: potential spectre issue 'dp->synths' sound/core/seq/oss/seq_oss_event.c:353 note_off_event() warn: potential spectre issue 'dp->synths' sound/core/seq/oss/seq_oss_synth.c:506 snd_seq_oss_synth_sysex() warn: potential spectre issue 'dp->synths' sound/core/seq/oss/seq_oss_synth.c:580 snd_seq_oss_synth_ioctl() warn: potential spectre issue 'dp->synths' Although all these seem doing only the first load without further reference, we may want to stay in a safer side, so hardening with array_index_nospec() would still make sense. We may put array_index_nospec() at each place, but here we take a different approach: - For dp->synths[], change the helpers to retrieve seq_oss_synthinfo pointer directly instead of the array expansion at each place - For info->ch[], harden in a normal way, as there are only a couple of places As a result, the existing helper, snd_seq_oss_synth_is_valid() is replaced with snd_seq_oss_synth_info(). Also, we cover MIDI device where a similar array expansion is done, too, although it wasn't reported by Smatch. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/oss/seq_oss_event.c | 15 +++--- sound/core/seq/oss/seq_oss_midi.c | 2 + sound/core/seq/oss/seq_oss_synth.c | 75 +++++++++++++++++------------- sound/core/seq/oss/seq_oss_synth.h | 3 +- 4 files changed, 55 insertions(+), 40 deletions(-) diff --git a/sound/core/seq/oss/seq_oss_event.c b/sound/core/seq/oss/seq_oss_event.c index c3908862bc8b..86ca584c27b2 100644 --- a/sound/core/seq/oss/seq_oss_event.c +++ b/sound/core/seq/oss/seq_oss_event.c @@ -26,6 +26,7 @@ #include #include "seq_oss_readq.h" #include "seq_oss_writeq.h" +#include /* @@ -287,10 +288,10 @@ note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, st { struct seq_oss_synthinfo *info; - if (!snd_seq_oss_synth_is_valid(dp, dev)) + info = snd_seq_oss_synth_info(dp, dev); + if (!info) return -ENXIO; - info = &dp->synths[dev]; switch (info->arg.event_passing) { case SNDRV_SEQ_OSS_PROCESS_EVENTS: if (! info->ch || ch < 0 || ch >= info->nr_voices) { @@ -298,6 +299,7 @@ note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, st return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); } + ch = array_index_nospec(ch, info->nr_voices); if (note == 255 && info->ch[ch].note >= 0) { /* volume control */ int type; @@ -347,10 +349,10 @@ note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, s { struct seq_oss_synthinfo *info; - if (!snd_seq_oss_synth_is_valid(dp, dev)) + info = snd_seq_oss_synth_info(dp, dev); + if (!info) return -ENXIO; - info = &dp->synths[dev]; switch (info->arg.event_passing) { case SNDRV_SEQ_OSS_PROCESS_EVENTS: if (! info->ch || ch < 0 || ch >= info->nr_voices) { @@ -358,6 +360,7 @@ note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, s return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); } + ch = array_index_nospec(ch, info->nr_voices); if (info->ch[ch].note >= 0) { note = info->ch[ch].note; info->ch[ch].vel = 0; @@ -381,7 +384,7 @@ note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, s static int set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, int vel, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev)) + if (!snd_seq_oss_synth_info(dp, dev)) return -ENXIO; ev->type = type; @@ -399,7 +402,7 @@ set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, static int set_control_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int param, int val, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev)) + if (!snd_seq_oss_synth_info(dp, dev)) return -ENXIO; ev->type = type; diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index b30b2139e3f0..9debd1b8fd28 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -29,6 +29,7 @@ #include "../seq_lock.h" #include #include +#include /* @@ -315,6 +316,7 @@ get_mididev(struct seq_oss_devinfo *dp, int dev) { if (dev < 0 || dev >= dp->max_mididev) return NULL; + dev = array_index_nospec(dev, dp->max_mididev); return get_mdev(dev); } diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 9e2b250ae780..278ebb993122 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -26,6 +26,7 @@ #include #include #include +#include /* * constants @@ -339,17 +340,13 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp) dp->max_synthdev = 0; } -/* - * check if the specified device is MIDI mapped device - */ -static int -is_midi_dev(struct seq_oss_devinfo *dp, int dev) +static struct seq_oss_synthinfo * +get_synthinfo_nospec(struct seq_oss_devinfo *dp, int dev) { if (dev < 0 || dev >= dp->max_synthdev) - return 0; - if (dp->synths[dev].is_midi) - return 1; - return 0; + return NULL; + dev = array_index_nospec(dev, SNDRV_SEQ_OSS_MAX_SYNTH_DEVS); + return &dp->synths[dev]; } /* @@ -359,11 +356,13 @@ static struct seq_oss_synth * get_synthdev(struct seq_oss_devinfo *dp, int dev) { struct seq_oss_synth *rec; - if (dev < 0 || dev >= dp->max_synthdev) + struct seq_oss_synthinfo *info = get_synthinfo_nospec(dp, dev); + + if (!info) return NULL; - if (! dp->synths[dev].opened) + if (!info->opened) return NULL; - if (dp->synths[dev].is_midi) { + if (info->is_midi) { rec = &midi_synth_dev; snd_use_lock_use(&rec->use_lock); } else { @@ -406,10 +405,8 @@ snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev) struct seq_oss_synth *rec; struct seq_oss_synthinfo *info; - if (snd_BUG_ON(dev < 0 || dev >= dp->max_synthdev)) - return; - info = &dp->synths[dev]; - if (! info->opened) + info = get_synthinfo_nospec(dp, dev); + if (!info || !info->opened) return; if (info->sysex) info->sysex->len = 0; /* reset sysex */ @@ -458,12 +455,14 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, const char __user *buf, int p, int c) { struct seq_oss_synth *rec; + struct seq_oss_synthinfo *info; int rc; - if (dev < 0 || dev >= dp->max_synthdev) + info = get_synthinfo_nospec(dp, dev); + if (!info) return -ENXIO; - if (is_midi_dev(dp, dev)) + if (info->is_midi) return 0; if ((rec = get_synthdev(dp, dev)) == NULL) return -ENXIO; @@ -471,24 +470,25 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, if (rec->oper.load_patch == NULL) rc = -ENXIO; else - rc = rec->oper.load_patch(&dp->synths[dev].arg, fmt, buf, p, c); + rc = rec->oper.load_patch(&info->arg, fmt, buf, p, c); snd_use_lock_free(&rec->use_lock); return rc; } /* - * check if the device is valid synth device + * check if the device is valid synth device and return the synth info */ -int -snd_seq_oss_synth_is_valid(struct seq_oss_devinfo *dp, int dev) +struct seq_oss_synthinfo * +snd_seq_oss_synth_info(struct seq_oss_devinfo *dp, int dev) { struct seq_oss_synth *rec; + rec = get_synthdev(dp, dev); if (rec) { snd_use_lock_free(&rec->use_lock); - return 1; + return get_synthinfo_nospec(dp, dev); } - return 0; + return NULL; } @@ -503,16 +503,18 @@ snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf, int i, send; unsigned char *dest; struct seq_oss_synth_sysex *sysex; + struct seq_oss_synthinfo *info; - if (! snd_seq_oss_synth_is_valid(dp, dev)) + info = snd_seq_oss_synth_info(dp, dev); + if (!info) return -ENXIO; - sysex = dp->synths[dev].sysex; + sysex = info->sysex; if (sysex == NULL) { sysex = kzalloc(sizeof(*sysex), GFP_KERNEL); if (sysex == NULL) return -ENOMEM; - dp->synths[dev].sysex = sysex; + info->sysex = sysex; } send = 0; @@ -557,10 +559,12 @@ snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf, int snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev)) + struct seq_oss_synthinfo *info = snd_seq_oss_synth_info(dp, dev); + + if (!info) return -EINVAL; - snd_seq_oss_fill_addr(dp, ev, dp->synths[dev].arg.addr.client, - dp->synths[dev].arg.addr.port); + snd_seq_oss_fill_addr(dp, ev, info->arg.addr.client, + info->arg.addr.port); return 0; } @@ -572,16 +576,18 @@ int snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, unsigned long addr) { struct seq_oss_synth *rec; + struct seq_oss_synthinfo *info; int rc; - if (is_midi_dev(dp, dev)) + info = get_synthinfo_nospec(dp, dev); + if (!info || info->is_midi) return -ENXIO; if ((rec = get_synthdev(dp, dev)) == NULL) return -ENXIO; if (rec->oper.ioctl == NULL) rc = -ENXIO; else - rc = rec->oper.ioctl(&dp->synths[dev].arg, cmd, addr); + rc = rec->oper.ioctl(&info->arg, cmd, addr); snd_use_lock_free(&rec->use_lock); return rc; } @@ -593,7 +599,10 @@ snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, u int snd_seq_oss_synth_raw_event(struct seq_oss_devinfo *dp, int dev, unsigned char *data, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev) || is_midi_dev(dp, dev)) + struct seq_oss_synthinfo *info; + + info = snd_seq_oss_synth_info(dp, dev); + if (!info || info->is_midi) return -ENXIO; ev->type = SNDRV_SEQ_EVENT_OSS; memcpy(ev->data.raw8.d, data, 8); diff --git a/sound/core/seq/oss/seq_oss_synth.h b/sound/core/seq/oss/seq_oss_synth.h index 74ac55f166b6..a63f9e22974d 100644 --- a/sound/core/seq/oss/seq_oss_synth.h +++ b/sound/core/seq/oss/seq_oss_synth.h @@ -37,7 +37,8 @@ void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp); void snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev); int snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, const char __user *buf, int p, int c); -int snd_seq_oss_synth_is_valid(struct seq_oss_devinfo *dp, int dev); +struct seq_oss_synthinfo *snd_seq_oss_synth_info(struct seq_oss_devinfo *dp, + int dev); int snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf, struct snd_seq_event *ev); int snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event *ev); -- GitLab From 69bd3f023770c0d6b223e7418a73246a38b60365 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 07:50:50 +0200 Subject: [PATCH 137/855] ALSA: hda: Hardening for potential Spectre v1 commit 69fa6f19b95597618ab30438a27b67ad93daa7c7 upstream. As recently Smatch suggested, one place in HD-audio hwdep ioctl codes may expand the array directly from the user-space value with speculation: sound/pci/hda/hda_local.h:467 get_wcaps() warn: potential spectre issue 'codec->wcaps' As get_wcaps() itself is a fairly frequently called inline function, and there is only one single call with a user-space value, we replace only the latter one to open-code locally with array_index_nospec() hardening in this patch. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_hwdep.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 57df06e76968..cc009a4a3d1d 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "hda_codec.h" #include "hda_local.h" @@ -51,7 +52,16 @@ static int get_wcap_ioctl(struct hda_codec *codec, if (get_user(verb, &arg->verb)) return -EFAULT; - res = get_wcaps(codec, verb >> 24); + /* open-code get_wcaps(verb>>24) with nospec */ + verb >>= 24; + if (verb < codec->core.start_nid || + verb >= codec->core.start_nid + codec->core.num_nodes) { + res = 0; + } else { + verb -= codec->core.start_nid; + verb = array_index_nospec(verb, codec->core.num_nodes); + res = codec->wcaps[verb]; + } if (put_user(res, &arg->res)) return -EFAULT; return 0; -- GitLab From d197dfc89cfb9b2afb014f098a55be77102c6cba Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Wed, 25 Apr 2018 15:31:52 +0800 Subject: [PATCH 138/855] ALSA: hda/realtek - Add some fixes for ALC233 commit ea04a1dbf8b1d6af759d58e705636fde48583f8f upstream. Fill COEF to change EAPD to verb control. Assigned codec type. This is an additional fix over 92f974df3460 ("ALSA: hda/realtek - New vendor ID for ALC233"). [ More notes: according to Kailang, the chip is 10ec:0235 bonding for ALC233b, which is equivalent with ALC255. It's only used for Lenovo. The chip needs no alc_process_coef_fw() for headset unlike ALC255. ] Signed-off-by: Kailang Yang Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e2230bed7409..7ece1ab57eef 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -329,6 +329,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) break; case 0x10ec0225: case 0x10ec0233: + case 0x10ec0235: case 0x10ec0236: case 0x10ec0255: case 0x10ec0256: @@ -6359,6 +6360,7 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0298: spec->codec_variant = ALC269_TYPE_ALC298; break; + case 0x10ec0235: case 0x10ec0255: spec->codec_variant = ALC269_TYPE_ALC255; break; -- GitLab From 54a21fe4d8bbb0e82ac75e55bb8d46c4c3326ee4 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 1 Mar 2018 14:39:39 +0100 Subject: [PATCH 139/855] mtd: cfi: cmdset_0001: Do not allow read/write to suspend erase block. commit 6510bbc88e3258631831ade49033537081950605 upstream. Currently it is possible to read and/or write to suspend EB's. Writing /dev/mtdX or /dev/mtdblockX from several processes may break the flash state machine. Signed-off-by: Joakim Tjernlund Cc: Reviewed-by: Richard Weinberger Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0001.c | 16 +++++++++++----- include/linux/mtd/flashchip.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 5e1b68cbcd0a..a239ed4cb076 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -831,21 +831,25 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1)))) goto sleep; + /* Do not allow suspend iff read/write to EB address */ + if ((adr & chip->in_progress_block_mask) == + chip->in_progress_block_addr) + goto sleep; /* Erase suspend */ - map_write(map, CMD(0xB0), adr); + map_write(map, CMD(0xB0), chip->in_progress_block_addr); /* If the flash has finished erasing, then 'erase suspend' * appears to make some (28F320) flash devices switch to * 'read' mode. Make sure that we switch to 'read status' * mode so we get the right data. --rmk */ - map_write(map, CMD(0x70), adr); + map_write(map, CMD(0x70), chip->in_progress_block_addr); chip->oldstate = FL_ERASING; chip->state = FL_ERASE_SUSPENDING; chip->erase_suspended = 1; for (;;) { - status = map_read(map, adr); + status = map_read(map, chip->in_progress_block_addr); if (map_word_andequal(map, status, status_OK, status_OK)) break; @@ -1041,8 +1045,8 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad sending the 0x70 (Read Status) command to an erasing chip and expecting it to be ignored, that's what we do. */ - map_write(map, CMD(0xd0), adr); - map_write(map, CMD(0x70), adr); + map_write(map, CMD(0xd0), chip->in_progress_block_addr); + map_write(map, CMD(0x70), chip->in_progress_block_addr); chip->oldstate = FL_READY; chip->state = FL_ERASING; break; @@ -1933,6 +1937,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, map_write(map, CMD(0xD0), adr); chip->state = FL_ERASING; chip->erase_suspended = 0; + chip->in_progress_block_addr = adr; + chip->in_progress_block_mask = ~(len - 1); ret = INVAL_CACHE_AND_WAIT(map, chip, adr, adr, len, diff --git a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h index b63fa457febd..3529683f691e 100644 --- a/include/linux/mtd/flashchip.h +++ b/include/linux/mtd/flashchip.h @@ -85,6 +85,7 @@ struct flchip { unsigned int write_suspended:1; unsigned int erase_suspended:1; unsigned long in_progress_block_addr; + unsigned long in_progress_block_mask; struct mutex mutex; wait_queue_head_t wq; /* Wait on here when we're waiting for the chip -- GitLab From 0d8f3797ed5d7204c0238825fe434a949822c60e Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 1 Mar 2018 14:39:40 +0100 Subject: [PATCH 140/855] mtd: cfi: cmdset_0001: Workaround Micron Erase suspend bug. commit 46a16a2283f9e678a4e26829175e0c37a5191860 upstream. Some Micron chips does not work well wrt Erase suspend for boot blocks. This avoids the issue by not allowing Erase suspend for the boot blocks for the 28F00AP30(1GBit) chip. Signed-off-by: Joakim Tjernlund Cc: Reviewed-by: Richard Weinberger Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0001.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index a239ed4cb076..e1b603ca0170 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -45,6 +45,7 @@ #define I82802AB 0x00ad #define I82802AC 0x00ac #define PF38F4476 0x881c +#define M28F00AP30 0x8963 /* STMicroelectronics chips */ #define M50LPW080 0x002F #define M50FLW080A 0x0080 @@ -375,6 +376,17 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi, extp->MinorVersion = '1'; } +static int cfi_is_micron_28F00AP30(struct cfi_private *cfi, struct flchip *chip) +{ + /* + * Micron(was Numonyx) 1Gbit bottom boot are buggy w.r.t + * Erase Supend for their small Erase Blocks(0x8000) + */ + if (cfi->mfr == CFI_MFR_INTEL && cfi->id == M28F00AP30) + return 1; + return 0; +} + static inline struct cfi_pri_intelext * read_pri_intelext(struct map_info *map, __u16 adr) { @@ -836,6 +848,11 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long chip->in_progress_block_addr) goto sleep; + /* do not suspend small EBs, buggy Micron Chips */ + if (cfi_is_micron_28F00AP30(cfi, chip) && + (chip->in_progress_block_mask == ~(0x8000-1))) + goto sleep; + /* Erase suspend */ map_write(map, CMD(0xB0), chip->in_progress_block_addr); -- GitLab From f48bbbae0421bdf002f3fb565f1308695b2560a6 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 1 Mar 2018 14:39:41 +0100 Subject: [PATCH 141/855] mtd: cfi: cmdset_0002: Do not allow read/write to suspend erase block. commit 7b70eb14392a7cf505f9b358d06c33b5af73d1e7 upstream. Currently it is possible to read and/or write to suspend EB's. Writing /dev/mtdX or /dev/mtdblockX from several processes may break the flash state machine. Taken from cfi_cmdset_0001 driver. Signed-off-by: Joakim Tjernlund Cc: Reviewed-by: Richard Weinberger Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0002.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 9dca881bb378..107c05b3ddbb 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -812,9 +812,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)))) goto sleep; - /* We could check to see if we're trying to access the sector - * that is currently being erased. However, no user will try - * anything like that so we just wait for the timeout. */ + /* Do not allow suspend iff read/write to EB address */ + if ((adr & chip->in_progress_block_mask) == + chip->in_progress_block_addr) + goto sleep; /* Erase suspend */ /* It's harmless to issue the Erase-Suspend and Erase-Resume @@ -2263,6 +2264,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) chip->state = FL_ERASING; chip->erase_suspended = 0; chip->in_progress_block_addr = adr; + chip->in_progress_block_mask = ~(map->size - 1); INVALIDATE_CACHE_UDELAY(map, chip, adr, map->size, @@ -2352,6 +2354,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, chip->state = FL_ERASING; chip->erase_suspended = 0; chip->in_progress_block_addr = adr; + chip->in_progress_block_mask = ~(len - 1); INVALIDATE_CACHE_UDELAY(map, chip, adr, len, -- GitLab From 6ab441353d668f98b98c6710e2024e6a777c9241 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 11 Apr 2018 17:22:43 +0200 Subject: [PATCH 142/855] kobject: don't use WARN for registration failures commit 3e14c6abbfb5c94506edda9d8e2c145d79375798 upstream. This WARNING proved to be noisy. The function still returns an error and callers should handle it. That's how most of kernel code works. Downgrade the WARNING to pr_err() and leave WARNINGs for kernel bugs. Signed-off-by: Dmitry Vyukov Reported-by: syzbot+209c0f67f99fec8eb14b@syzkaller.appspotmail.com Reported-by: syzbot+7fb6d9525a4528104e05@syzkaller.appspotmail.com Reported-by: syzbot+2e63711063e2d8f9ea27@syzkaller.appspotmail.com Reported-by: syzbot+de73361ee4971b6e6f75@syzkaller.appspotmail.com Cc: stable Signed-off-by: Greg Kroah-Hartman --- lib/kobject.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/kobject.c b/lib/kobject.c index 445dcaeb0f56..b733a83e5294 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -234,14 +234,12 @@ static int kobject_add_internal(struct kobject *kobj) /* be noisy on error issues */ if (error == -EEXIST) - WARN(1, "%s failed for %s with " - "-EEXIST, don't try to register things with " - "the same name in the same directory.\n", - __func__, kobject_name(kobj)); + pr_err("%s failed for %s with -EEXIST, don't try to register things with the same name in the same directory.\n", + __func__, kobject_name(kobj)); else - WARN(1, "%s failed for %s (error: %d parent: %s)\n", - __func__, kobject_name(kobj), error, - parent ? kobject_name(parent) : "'none'"); + pr_err("%s failed for %s (error: %d parent: %s)\n", + __func__, kobject_name(kobj), error, + parent ? kobject_name(parent) : "'none'"); } else kobj->state_in_sysfs = 1; -- GitLab From dbf1c17b6c2d4249d31a7b2516cdc2881c0a4860 Mon Sep 17 00:00:00 2001 From: Mahesh Rajashekhara Date: Tue, 17 Apr 2018 17:03:12 +0530 Subject: [PATCH 143/855] scsi: sd: Defer spinning up drive while SANITIZE is in progress commit 505aa4b6a8834a2300971c5220c380c3271ebde3 upstream. A drive being sanitized will return NOT READY / ASC 0x4 / ASCQ 0x1b ("LOGICAL UNIT NOT READY. SANITIZE IN PROGRESS"). Prevent spinning up the drive until this condition clears. [mkp: tweaked commit message] Signed-off-by: Mahesh Rajashekhara Cc: Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index ace56c5e61e1..14ba1a2c0b7c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1935,6 +1935,8 @@ sd_spinup_disk(struct scsi_disk *sdkp) break; /* standby */ if (sshdr.asc == 4 && sshdr.ascq == 0xc) break; /* unavailable */ + if (sshdr.asc == 4 && sshdr.ascq == 0x1b) + break; /* sanitize in progress */ /* * Issue command to spin up drive when not ready */ -- GitLab From d6bc6d12b532265027aee080dc171c557d827206 Mon Sep 17 00:00:00 2001 From: Victor Gu Date: Fri, 6 Apr 2018 16:55:31 +0200 Subject: [PATCH 144/855] PCI: aardvark: Fix logic in advk_pcie_{rd,wr}_conf() commit 660661afcd40ed7f515ef3369721ed58e80c0fc5 upstream. The PCI configuration space read/write functions were special casing the situation where PCI_SLOT(devfn) != 0, and returned PCIBIOS_DEVICE_NOT_FOUND in this case. However, while this is what is intended for the root bus, it is not intended for the child busses, as it prevents discovering devices with PCI_SLOT(x) != 0. Therefore, we return PCIBIOS_DEVICE_NOT_FOUND only if we're on the root bus. Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") Cc: Signed-off-by: Victor Gu Reviewed-by: Wilson Ding Reviewed-by: Nadav Haklai [Thomas: tweak commit log.] Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/host/pci-aardvark.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c index 4fce494271cc..9437840bee6d 100644 --- a/drivers/pci/host/pci-aardvark.c +++ b/drivers/pci/host/pci-aardvark.c @@ -439,7 +439,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, u32 reg; int ret; - if (PCI_SLOT(devfn) != 0) { + if ((bus->number == pcie->root_bus_nr) && PCI_SLOT(devfn) != 0) { *val = 0xffffffff; return PCIBIOS_DEVICE_NOT_FOUND; } @@ -493,7 +493,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn, int offset; int ret; - if (PCI_SLOT(devfn) != 0) + if ((bus->number == pcie->root_bus_nr) && PCI_SLOT(devfn) != 0) return PCIBIOS_DEVICE_NOT_FOUND; if (where % size) -- GitLab From e57bde8bbd4ed072120d3fc088fc147ccc29bed4 Mon Sep 17 00:00:00 2001 From: Victor Gu Date: Fri, 6 Apr 2018 16:55:32 +0200 Subject: [PATCH 145/855] PCI: aardvark: Set PIO_ADDR_LS correctly in advk_pcie_rd_conf() commit 4fa3999ee672c54a5498ce98e20fe3fdf9c1cbb4 upstream. When setting the PIO_ADDR_LS register during a configuration read, we were properly passing the device number, function number and register number, but not the bus number, causing issues when reading the configuration of PCIe devices. Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") Cc: Signed-off-by: Victor Gu Reviewed-by: Wilson Ding Reviewed-by: Nadav Haklai [Thomas: tweak commit log.] Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/host/pci-aardvark.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c index 9437840bee6d..d3d24257c65a 100644 --- a/drivers/pci/host/pci-aardvark.c +++ b/drivers/pci/host/pci-aardvark.c @@ -175,8 +175,6 @@ #define PCIE_CONFIG_WR_TYPE0 0xa #define PCIE_CONFIG_WR_TYPE1 0xb -/* PCI_BDF shifts 8bit, so we need extra 4bit shift */ -#define PCIE_BDF(dev) (dev << 4) #define PCIE_CONF_BUS(bus) (((bus) & 0xff) << 20) #define PCIE_CONF_DEV(dev) (((dev) & 0x1f) << 15) #define PCIE_CONF_FUNC(fun) (((fun) & 0x7) << 12) @@ -458,7 +456,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, advk_writel(pcie, reg, PIO_CTRL); /* Program the address registers */ - reg = PCIE_BDF(devfn) | PCIE_CONF_REG(where); + reg = PCIE_CONF_ADDR(bus->number, devfn, where); advk_writel(pcie, reg, PIO_ADDR_LS); advk_writel(pcie, 0, PIO_ADDR_MS); -- GitLab From 5b066d6423b23fd95334184f721b94f8b61f7d21 Mon Sep 17 00:00:00 2001 From: Evan Wang Date: Fri, 6 Apr 2018 16:55:34 +0200 Subject: [PATCH 146/855] PCI: aardvark: Fix PCIe Max Read Request Size setting commit fc31c4e347c9dad50544d01d5ee98b22c7df88bb upstream. There is an obvious typo issue in the definition of the PCIe maximum read request size: a bit shift is directly used as a value, while it should be used to shift the correct value. Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") Cc: Signed-off-by: Evan Wang Reviewed-by: Victor Gu Reviewed-by: Nadav Haklai [Thomas: tweak commit log.] Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/host/pci-aardvark.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c index d3d24257c65a..11bad826683e 100644 --- a/drivers/pci/host/pci-aardvark.c +++ b/drivers/pci/host/pci-aardvark.c @@ -32,6 +32,7 @@ #define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT 5 #define PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE (0 << 11) #define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT 12 +#define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SZ 0x2 #define PCIE_CORE_LINK_CTRL_STAT_REG 0xd0 #define PCIE_CORE_LINK_L0S_ENTRY BIT(0) #define PCIE_CORE_LINK_TRAINING BIT(5) @@ -296,7 +297,8 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie) reg = PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE | (7 << PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT) | PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE | - PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT; + (PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SZ << + PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT); advk_writel(pcie, reg, PCIE_CORE_DEV_CTRL_STATS_REG); /* Program PCIe Control 2 to disable strict ordering */ -- GitLab From a4e38e8dd596a3e03eeffb55df4aab27acd5eb2d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Apr 2018 15:21:43 +0200 Subject: [PATCH 147/855] ARM: amba: Make driver_override output consistent with other buses commit 5f53624662eaac89598641cee6cd54fc192572d9 upstream. For AMBA devices with unconfigured driver override, the "driver_override" sysfs virtual file is empty, while it contains "(null)" for platform and PCI devices. Make AMBA consistent with other buses by dropping the test for a NULL pointer. Note that contrary to popular belief, sprintf() handles NULL pointers fine; they are printed as "(null)". Signed-off-by: Geert Uytterhoeven Cc: stable Reviewed-by: Todd Kjos Signed-off-by: Greg Kroah-Hartman --- drivers/amba/bus.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index a56fa2a1e9aa..b8642519fc92 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -70,9 +70,6 @@ static ssize_t driver_override_show(struct device *_dev, { struct amba_device *dev = to_amba_device(_dev); - if (!dev->driver_override) - return 0; - return sprintf(buf, "%s\n", dev->driver_override); } -- GitLab From 272c99cf85a371401b78f3c56a18745bf07817a3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Apr 2018 15:21:44 +0200 Subject: [PATCH 148/855] ARM: amba: Fix race condition with driver_override commit 6a7228d90d42bcacfe38786756ba62762b91c20a upstream. The driver_override implementation is susceptible to a race condition when different threads are reading vs storing a different driver override. Add locking to avoid this race condition. Cfr. commits 6265539776a0810b ("driver core: platform: fix race condition with driver_override") and 9561475db680f714 ("PCI: Fix race condition with driver_override"). Fixes: 3cf385713460eb2b ("ARM: 8256/1: driver coamba: add device binding path 'driver_override'") Signed-off-by: Geert Uytterhoeven Reviewed-by: Todd Kjos Cc: stable Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/amba/bus.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index b8642519fc92..1c25b6ee9651 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -69,8 +69,12 @@ static ssize_t driver_override_show(struct device *_dev, struct device_attribute *attr, char *buf) { struct amba_device *dev = to_amba_device(_dev); + ssize_t len; - return sprintf(buf, "%s\n", dev->driver_override); + device_lock(_dev); + len = sprintf(buf, "%s\n", dev->driver_override); + device_unlock(_dev); + return len; } static ssize_t driver_override_store(struct device *_dev, @@ -78,7 +82,7 @@ static ssize_t driver_override_store(struct device *_dev, const char *buf, size_t count) { struct amba_device *dev = to_amba_device(_dev); - char *driver_override, *old = dev->driver_override, *cp; + char *driver_override, *old, *cp; if (count > PATH_MAX) return -EINVAL; @@ -91,12 +95,15 @@ static ssize_t driver_override_store(struct device *_dev, if (cp) *cp = '\0'; + device_lock(_dev); + old = dev->driver_override; if (strlen(driver_override)) { dev->driver_override = driver_override; } else { kfree(driver_override); dev->driver_override = NULL; } + device_unlock(_dev); kfree(old); -- GitLab From 8970c12ac9b917b27e42c0537ab7fce0357f0cf3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Apr 2018 15:21:45 +0200 Subject: [PATCH 149/855] ARM: amba: Don't read past the end of sysfs "driver_override" buffer commit d2ffed5185df9d8d9ccd150e4340e3b6f96a8381 upstream. When printing the driver_override parameter when it is 4095 and 4094 bytes long, the printing code would access invalid memory because we need count + 1 bytes for printing. Cfr. commits 4efe874aace57dba ("PCI: Don't read past the end of sysfs "driver_override" buffer") and bf563b01c2895a4b ("driver core: platform: Don't read past the end of "driver_override" buffer"). Fixes: 3cf385713460eb2b ("ARM: 8256/1: driver coamba: add device binding path 'driver_override'") Signed-off-by: Geert Uytterhoeven Reviewed-by: Todd Kjos Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/amba/bus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 1c25b6ee9651..93888ccb4e26 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -84,7 +84,8 @@ static ssize_t driver_override_store(struct device *_dev, struct amba_device *dev = to_amba_device(_dev); char *driver_override, *old, *cp; - if (count > PATH_MAX) + /* We need to keep extra room for a newline */ + if (count >= (PAGE_SIZE - 1)) return -EINVAL; driver_override = kstrndup(buf, count, GFP_KERNEL); -- GitLab From 2e2d6f1e783fc6d827ca32a6ca41ebdda855cfd8 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Thu, 12 Apr 2018 08:40:55 +0200 Subject: [PATCH 150/855] crypto: drbg - set freed buffers to NULL commit eea0d3ea7546961f69f55b26714ac8fd71c7c020 upstream. During freeing of the internal buffers used by the DRBG, set the pointer to NULL. It is possible that the context with the freed buffers is reused. In case of an error during initialization where the pointers do not yet point to allocated memory, the NULL value prevents a double free. Cc: stable@vger.kernel.org Fixes: 3cfc3b9721123 ("crypto: drbg - use aligned buffers") Signed-off-by: Stephan Mueller Reported-by: syzbot+75397ee3df5c70164154@syzkaller.appspotmail.com Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/drbg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crypto/drbg.c b/crypto/drbg.c index 942ddff68408..4bb5f93c94cd 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1134,8 +1134,10 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) if (!drbg) return; kzfree(drbg->Vbuf); + drbg->Vbuf = NULL; drbg->V = NULL; kzfree(drbg->Cbuf); + drbg->Cbuf = NULL; drbg->C = NULL; kzfree(drbg->scratchpadbuf); drbg->scratchpadbuf = NULL; -- GitLab From ddf02dbc17279f9e9aacbe52f556764493147afa Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 8 Apr 2018 16:57:35 -0700 Subject: [PATCH 151/855] ASoC: fsl_esai: Fix divisor calculation failure at lower ratio commit c656941df9bc80f7ec65b92ca73c42f8b0b62628 upstream. When the desired ratio is less than 256, the savesub (tolerance) in the calculation would become 0. This will then fail the loop- search immediately without reporting any errors. But if the ratio is smaller enough, there is no need to calculate the tolerance because PM divisor alone is enough to get the ratio. So a simple fix could be just to set PM directly instead of going into the loop-search. Reported-by: Marek Vasut Signed-off-by: Nicolin Chen Tested-by: Marek Vasut Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/fsl/fsl_esai.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 38bfd46f4ad8..3ef174531344 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -145,6 +145,13 @@ static int fsl_esai_divisor_cal(struct snd_soc_dai *dai, bool tx, u32 ratio, psr = ratio <= 256 * maxfp ? ESAI_xCCR_xPSR_BYPASS : ESAI_xCCR_xPSR_DIV8; + /* Do not loop-search if PM (1 ~ 256) alone can serve the ratio */ + if (ratio <= 256) { + pm = ratio; + fp = 1; + goto out; + } + /* Set the max fluctuation -- 0.1% of the max devisor */ savesub = (psr ? 1 : 8) * 256 * maxfp / 1000; -- GitLab From 480179a1570d5d251be6c6bc02634611850d3c9a Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Mon, 23 Apr 2018 15:25:10 +0200 Subject: [PATCH 152/855] libceph: un-backoff on tick when we have a authenticated session commit facb9f6eba3df4e8027301cc0e514dc582a1b366 upstream. This means that if we do some backoff, then authenticate, and are healthy for an extended period of time, a subsequent failure won't leave us starting our hunting sequence with a large backoff. Mirrors ceph.git commit d466bc6e66abba9b464b0b69687cf45c9dccf383. Cc: stable@vger.kernel.org # 4.7+ Signed-off-by: Ilya Dryomov Reviewed-by: Jason Dillaman Signed-off-by: Greg Kroah-Hartman --- net/ceph/mon_client.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index a8effc8b7280..be3567447b41 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -209,6 +209,14 @@ static void reopen_session(struct ceph_mon_client *monc) __open_session(monc); } +static void un_backoff(struct ceph_mon_client *monc) +{ + monc->hunt_mult /= 2; /* reduce by 50% */ + if (monc->hunt_mult < 1) + monc->hunt_mult = 1; + dout("%s hunt_mult now %d\n", __func__, monc->hunt_mult); +} + /* * Reschedule delayed work timer. */ @@ -955,6 +963,7 @@ static void delayed_work(struct work_struct *work) if (!monc->hunting) { ceph_con_keepalive(&monc->con); __validate_auth(monc); + un_backoff(monc); } if (is_auth) { @@ -1114,9 +1123,7 @@ static void finish_hunting(struct ceph_mon_client *monc) dout("%s found mon%d\n", __func__, monc->cur_mon); monc->hunting = false; monc->had_a_connection = true; - monc->hunt_mult /= 2; /* reduce by 50% */ - if (monc->hunt_mult < 1) - monc->hunt_mult = 1; + un_backoff(monc); } } -- GitLab From 6044c69297adb224e4a2ec1bc8680b2e51428cc9 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Mon, 23 Apr 2018 15:25:10 +0200 Subject: [PATCH 153/855] libceph: reschedule a tick in finish_hunting() commit 7b4c443d139f1d2b5570da475f7a9cbcef86740c upstream. If we go without an established session for a while, backoff delay will climb to 30 seconds. The keepalive timeout is also 30 seconds, so it's pretty easily hit after a prolonged hunting for a monitor: we don't get a chance to send out a keepalive in time, which means we never get back a keepalive ack in time, cutting an established session and attempting to connect to a different monitor every 30 seconds: [Sun Apr 1 23:37:05 2018] libceph: mon0 10.80.20.99:6789 session established [Sun Apr 1 23:37:36 2018] libceph: mon0 10.80.20.99:6789 session lost, hunting for new mon [Sun Apr 1 23:37:36 2018] libceph: mon2 10.80.20.103:6789 session established [Sun Apr 1 23:38:07 2018] libceph: mon2 10.80.20.103:6789 session lost, hunting for new mon [Sun Apr 1 23:38:07 2018] libceph: mon1 10.80.20.100:6789 session established [Sun Apr 1 23:38:37 2018] libceph: mon1 10.80.20.100:6789 session lost, hunting for new mon [Sun Apr 1 23:38:37 2018] libceph: mon2 10.80.20.103:6789 session established [Sun Apr 1 23:39:08 2018] libceph: mon2 10.80.20.103:6789 session lost, hunting for new mon The regular keepalive interval is 10 seconds. After ->hunting is cleared in finish_hunting(), call __schedule_delayed() to ensure we send out a keepalive after 10 seconds. Cc: stable@vger.kernel.org # 4.7+ Link: http://tracker.ceph.com/issues/23537 Signed-off-by: Ilya Dryomov Reviewed-by: Jason Dillaman Signed-off-by: Greg Kroah-Hartman --- net/ceph/mon_client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index be3567447b41..500481003de4 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -1124,6 +1124,7 @@ static void finish_hunting(struct ceph_mon_client *monc) monc->hunting = false; monc->had_a_connection = true; un_backoff(monc); + __schedule_delayed(monc); } } -- GitLab From 30c85553d822c2d882ed5fe1652be5acdf405509 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 24 Apr 2018 19:10:55 +0200 Subject: [PATCH 154/855] libceph: validate con->state at the top of try_write() commit 9c55ad1c214d9f8c4594ac2c3fa392c1c32431a7 upstream. ceph_con_workfn() validates con->state before calling try_read() and then try_write(). However, try_read() temporarily releases con->mutex, notably in process_message() and ceph_con_in_msg_alloc(), opening the window for ceph_con_close() to sneak in, close the connection and release con->sock. When try_write() is called on the assumption that con->state is still valid (i.e. not STANDBY or CLOSED), a NULL sock gets passed to the networking stack: BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 IP: selinux_socket_sendmsg+0x5/0x20 Make sure con->state is valid at the top of try_write() and add an explicit BUG_ON for this, similar to try_read(). Cc: stable@vger.kernel.org Link: https://tracker.ceph.com/issues/23706 Signed-off-by: Ilya Dryomov Reviewed-by: Jason Dillaman Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 25a30be862e9..98ea28dc03f9 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2512,6 +2512,11 @@ static int try_write(struct ceph_connection *con) int ret = 1; dout("try_write start %p state %lu\n", con, con->state); + if (con->state != CON_STATE_PREOPEN && + con->state != CON_STATE_CONNECTING && + con->state != CON_STATE_NEGOTIATING && + con->state != CON_STATE_OPEN) + return 0; more: dout("try_write out_kvec_bytes %d\n", con->out_kvec_bytes); @@ -2537,6 +2542,8 @@ static int try_write(struct ceph_connection *con) } more_kvec: + BUG_ON(!con->sock); + /* kvec data queued? */ if (con->out_kvec_left) { ret = write_partial_kvec(con); -- GitLab From a72ac679ca58e873670a4f8e935f302fd605fea5 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 6 Apr 2018 17:21:53 -0600 Subject: [PATCH 155/855] earlycon: Use a pointer table to fix __earlycon_table stride commit dd709e72cb934eefd44de8d9969097173fbf45dc upstream. Commit 99492c39f39f ("earlycon: Fix __earlycon_table stride") tried to fix __earlycon_table stride by forcing the earlycon_id struct alignment to 32 and asking the linker to 32-byte align the __earlycon_table symbol. This fix was based on commit 07fca0e57fca92 ("tracing: Properly align linker defined symbols") which tried a similar fix for the tracing subsystem. However, this fix doesn't quite work because there is no guarantee that gcc will place structures packed into an array format. In fact, gcc 4.9 chooses to 64-byte align these structs by inserting additional padding between the entries because it has no clue that they are supposed to be in an array. If we are unlucky, the linker will assign symbol "__earlycon_table" to a 32-byte aligned address which does not correspond to the 64-byte aligned contents of section "__earlycon_table". To address this same problem, the fix to the tracing system was subsequently re-implemented using a more robust table of pointers approach by commits: 3d56e331b653 ("tracing: Replace syscall_meta_data struct array with pointer array") 654986462939 ("tracepoints: Fix section alignment using pointer array") e4a9ea5ee7c8 ("tracing: Replace trace_event struct array with pointer array") Let's use this same "array of pointers to structs" approach for EARLYCON_TABLE. Fixes: 99492c39f39f ("earlycon: Fix __earlycon_table stride") Signed-off-by: Daniel Kurtz Suggested-by: Aaron Durbin Reviewed-by: Rob Herring Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/of/fdt.c | 7 +++++-- drivers/tty/serial/earlycon.c | 6 ++++-- include/asm-generic/vmlinux.lds.h | 2 +- include/linux/serial_core.h | 21 ++++++++++++++------- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 502f5547a1f2..e9360d5cbcba 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -935,7 +935,7 @@ int __init early_init_dt_scan_chosen_stdout(void) int offset; const char *p, *q, *options = NULL; int l; - const struct earlycon_id *match; + const struct earlycon_id **p_match; const void *fdt = initial_boot_params; offset = fdt_path_offset(fdt, "/chosen"); @@ -962,7 +962,10 @@ int __init early_init_dt_scan_chosen_stdout(void) return 0; } - for (match = __earlycon_table; match < __earlycon_table_end; match++) { + for (p_match = __earlycon_table; p_match < __earlycon_table_end; + p_match++) { + const struct earlycon_id *match = *p_match; + if (!match->compatible[0]) continue; diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 3b31fd8863eb..b9a4625b8690 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -172,7 +172,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match) */ int __init setup_earlycon(char *buf) { - const struct earlycon_id *match; + const struct earlycon_id **p_match; if (!buf || !buf[0]) return -EINVAL; @@ -180,7 +180,9 @@ int __init setup_earlycon(char *buf) if (early_con.flags & CON_ENABLED) return -EALREADY; - for (match = __earlycon_table; match < __earlycon_table_end; match++) { + for (p_match = __earlycon_table; p_match < __earlycon_table_end; + p_match++) { + const struct earlycon_id *match = *p_match; size_t len = strlen(match->name); if (strncmp(buf, match->name, len)) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 2e6000a4eb2c..1462071a19bf 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -170,7 +170,7 @@ #endif #ifdef CONFIG_SERIAL_EARLYCON -#define EARLYCON_TABLE() STRUCT_ALIGN(); \ +#define EARLYCON_TABLE() . = ALIGN(8); \ VMLINUX_SYMBOL(__earlycon_table) = .; \ *(__earlycon_table) \ VMLINUX_SYMBOL(__earlycon_table_end) = .; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 344201437017..7b16c5322673 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -347,10 +347,10 @@ struct earlycon_id { char name[16]; char compatible[128]; int (*setup)(struct earlycon_device *, const char *options); -} __aligned(32); +}; -extern const struct earlycon_id __earlycon_table[]; -extern const struct earlycon_id __earlycon_table_end[]; +extern const struct earlycon_id *__earlycon_table[]; +extern const struct earlycon_id *__earlycon_table_end[]; #if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE) #define EARLYCON_USED_OR_UNUSED __used @@ -358,12 +358,19 @@ extern const struct earlycon_id __earlycon_table_end[]; #define EARLYCON_USED_OR_UNUSED __maybe_unused #endif -#define OF_EARLYCON_DECLARE(_name, compat, fn) \ - static const struct earlycon_id __UNIQUE_ID(__earlycon_##_name) \ - EARLYCON_USED_OR_UNUSED __section(__earlycon_table) \ +#define _OF_EARLYCON_DECLARE(_name, compat, fn, unique_id) \ + static const struct earlycon_id unique_id \ + EARLYCON_USED_OR_UNUSED __initconst \ = { .name = __stringify(_name), \ .compatible = compat, \ - .setup = fn } + .setup = fn }; \ + static const struct earlycon_id EARLYCON_USED_OR_UNUSED \ + __section(__earlycon_table) \ + * const __PASTE(__p, unique_id) = &unique_id + +#define OF_EARLYCON_DECLARE(_name, compat, fn) \ + _OF_EARLYCON_DECLARE(_name, compat, fn, \ + __UNIQUE_ID(__earlycon_##_name)) #define EARLYCON_DECLARE(_name, fn) OF_EARLYCON_DECLARE(_name, "", fn) -- GitLab From 4edf8ffe0c826dab2a8c418fb44bef74a6be41ed Mon Sep 17 00:00:00 2001 From: Shilpasri G Bhat Date: Wed, 25 Apr 2018 16:29:31 +0530 Subject: [PATCH 156/855] cpufreq: powernv: Fix hardlockup due to synchronous smp_call in timer interrupt commit c0f7f5b6c69107ca92909512533e70258ee19188 upstream. gpstate_timer_handler() uses synchronous smp_call to set the pstate on the requested core. This causes the below hard lockup: smp_call_function_single+0x110/0x180 (unreliable) smp_call_function_any+0x180/0x250 gpstate_timer_handler+0x1e8/0x580 call_timer_fn+0x50/0x1c0 expire_timers+0x138/0x1f0 run_timer_softirq+0x1e8/0x270 __do_softirq+0x158/0x3e4 irq_exit+0xe8/0x120 timer_interrupt+0x9c/0xe0 decrementer_common+0x114/0x120 -- interrupt: 901 at doorbell_global_ipi+0x34/0x50 LR = arch_send_call_function_ipi_mask+0x120/0x130 arch_send_call_function_ipi_mask+0x4c/0x130 smp_call_function_many+0x340/0x450 pmdp_invalidate+0x98/0xe0 change_huge_pmd+0xe0/0x270 change_protection_range+0xb88/0xe40 mprotect_fixup+0x140/0x340 SyS_mprotect+0x1b4/0x350 system_call+0x58/0x6c One way to avoid this is removing the smp-call. We can ensure that the timer always runs on one of the policy-cpus. If the timer gets migrated to a cpu outside the policy then re-queue it back on the policy->cpus. This way we can get rid of the smp-call which was being used to set the pstate on the policy->cpus. Fixes: 7bc54b652f13 ("timers, cpufreq/powernv: Initialize the gpstate timer as pinned") Cc: stable@vger.kernel.org # v4.8+ Reported-by: Nicholas Piggin Reported-by: Pridhiviraj Paidipeddi Signed-off-by: Shilpasri G Bhat Acked-by: Nicholas Piggin Acked-by: Viresh Kumar Acked-by: Vaidyanathan Srinivasan Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/powernv-cpufreq.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 6fb3cd24c1b6..a1d7fa48229d 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -599,6 +599,16 @@ void gpstate_timer_handler(unsigned long data) if (!spin_trylock(&gpstates->gpstate_lock)) return; + /* + * If the timer has migrated to the different cpu then bring + * it back to one of the policy->cpus + */ + if (!cpumask_test_cpu(raw_smp_processor_id(), policy->cpus)) { + gpstates->timer.expires = jiffies + msecs_to_jiffies(1); + add_timer_on(&gpstates->timer, cpumask_first(policy->cpus)); + spin_unlock(&gpstates->gpstate_lock); + return; + } gpstates->last_sampled_time += time_diff; gpstates->elapsed_time += time_diff; @@ -626,10 +636,8 @@ void gpstate_timer_handler(unsigned long data) gpstates->last_gpstate_idx = pstate_to_idx(freq_data.gpstate_id); gpstates->last_lpstate_idx = pstate_to_idx(freq_data.pstate_id); + set_pstate(&freq_data); spin_unlock(&gpstates->gpstate_lock); - - /* Timer may get migrated to a different cpu on cpu hot unplug */ - smp_call_function_any(policy->cpus, set_pstate, &freq_data, 1); } /* -- GitLab From a2a8b263ebff901c789517908a779f54fad3f2d0 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 10 Apr 2018 21:49:32 +1000 Subject: [PATCH 157/855] rtc: opal: Fix OPAL RTC driver OPAL_BUSY loops commit 682e6b4da5cbe8e9a53f979a58c2a9d7dc997175 upstream. The OPAL RTC driver does not sleep in case it gets OPAL_BUSY or OPAL_BUSY_EVENT from firmware, which causes large scheduling latencies, up to 50 seconds have been observed here when RTC stops responding (BMC reboot can do it). Fix this by converting it to the standard form OPAL_BUSY loop that sleeps. Fixes: 628daa8d5abf ("powerpc/powernv: Add RTC and NVRAM support plus RTAS fallbacks") Cc: stable@vger.kernel.org # v3.2+ Signed-off-by: Nicholas Piggin Acked-by: Alexandre Belloni Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/opal-rtc.c | 8 +++-- drivers/rtc/rtc-opal.c | 37 ++++++++++++++--------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/platforms/powernv/opal-rtc.c b/arch/powerpc/platforms/powernv/opal-rtc.c index f8868864f373..aa2a5139462e 100644 --- a/arch/powerpc/platforms/powernv/opal-rtc.c +++ b/arch/powerpc/platforms/powernv/opal-rtc.c @@ -48,10 +48,12 @@ unsigned long __init opal_get_boot_time(void) while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms); - if (rc == OPAL_BUSY_EVENT) + if (rc == OPAL_BUSY_EVENT) { + mdelay(OPAL_BUSY_DELAY_MS); opal_poll_events(NULL); - else if (rc == OPAL_BUSY) - mdelay(10); + } else if (rc == OPAL_BUSY) { + mdelay(OPAL_BUSY_DELAY_MS); + } } if (rc != OPAL_SUCCESS) return 0; diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index aa53fceaa5e0..180ec1f8c917 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -57,7 +57,7 @@ static void tm_to_opal(struct rtc_time *tm, u32 *y_m_d, u64 *h_m_s_ms) static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm) { - long rc = OPAL_BUSY; + s64 rc = OPAL_BUSY; int retries = 10; u32 y_m_d; u64 h_m_s_ms; @@ -66,13 +66,17 @@ static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm) while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms); - if (rc == OPAL_BUSY_EVENT) + if (rc == OPAL_BUSY_EVENT) { + msleep(OPAL_BUSY_DELAY_MS); opal_poll_events(NULL); - else if (retries-- && (rc == OPAL_HARDWARE - || rc == OPAL_INTERNAL_ERROR)) - msleep(10); - else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT) - break; + } else if (rc == OPAL_BUSY) { + msleep(OPAL_BUSY_DELAY_MS); + } else if (rc == OPAL_HARDWARE || rc == OPAL_INTERNAL_ERROR) { + if (retries--) { + msleep(10); /* Wait 10ms before retry */ + rc = OPAL_BUSY; /* go around again */ + } + } } if (rc != OPAL_SUCCESS) @@ -87,21 +91,26 @@ static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm) static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm) { - long rc = OPAL_BUSY; + s64 rc = OPAL_BUSY; int retries = 10; u32 y_m_d = 0; u64 h_m_s_ms = 0; tm_to_opal(tm, &y_m_d, &h_m_s_ms); + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { rc = opal_rtc_write(y_m_d, h_m_s_ms); - if (rc == OPAL_BUSY_EVENT) + if (rc == OPAL_BUSY_EVENT) { + msleep(OPAL_BUSY_DELAY_MS); opal_poll_events(NULL); - else if (retries-- && (rc == OPAL_HARDWARE - || rc == OPAL_INTERNAL_ERROR)) - msleep(10); - else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT) - break; + } else if (rc == OPAL_BUSY) { + msleep(OPAL_BUSY_DELAY_MS); + } else if (rc == OPAL_HARDWARE || rc == OPAL_INTERNAL_ERROR) { + if (retries--) { + msleep(10); /* Wait 10ms before retry */ + rc = OPAL_BUSY; /* go around again */ + } + } } return rc == OPAL_SUCCESS ? 0 : -EIO; -- GitLab From 537ef3ab077d68d7c46b9cbf41018a93882b35ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolai=20H=C3=A4hnle?= Date: Thu, 12 Apr 2018 16:34:19 +0200 Subject: [PATCH 158/855] drm/amdgpu: set COMPUTE_PGM_RSRC1 for SGPR/VGPR clearing shaders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 75569c182e4f65cd8826a5853dc9cbca703cbd0e upstream. Otherwise, the SQ may skip some of the register writes, or shader waves may be allocated where we don't expect them, so that as a result we don't actually reset all of the register SRAMs. This can lead to spurious ECC errors later on if a shader uses an uninitialized register. Signed-off-by: Nicolai Hähnle Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index a88d365be4c5..564362e8b486 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -1484,10 +1484,11 @@ static const u32 sgpr_init_compute_shader[] = static const u32 vgpr_init_regs[] = { mmCOMPUTE_STATIC_THREAD_MGMT_SE0, 0xffffffff, - mmCOMPUTE_RESOURCE_LIMITS, 0, + mmCOMPUTE_RESOURCE_LIMITS, 0x1000000, /* CU_GROUP_COUNT=1 */ mmCOMPUTE_NUM_THREAD_X, 256*4, mmCOMPUTE_NUM_THREAD_Y, 1, mmCOMPUTE_NUM_THREAD_Z, 1, + mmCOMPUTE_PGM_RSRC1, 0x100004f, /* VGPRS=15 (64 logical VGPRs), SGPRS=1 (16 SGPRs), BULKY=1 */ mmCOMPUTE_PGM_RSRC2, 20, mmCOMPUTE_USER_DATA_0, 0xedcedc00, mmCOMPUTE_USER_DATA_1, 0xedcedc01, @@ -1504,10 +1505,11 @@ static const u32 vgpr_init_regs[] = static const u32 sgpr1_init_regs[] = { mmCOMPUTE_STATIC_THREAD_MGMT_SE0, 0x0f, - mmCOMPUTE_RESOURCE_LIMITS, 0x1000000, + mmCOMPUTE_RESOURCE_LIMITS, 0x1000000, /* CU_GROUP_COUNT=1 */ mmCOMPUTE_NUM_THREAD_X, 256*5, mmCOMPUTE_NUM_THREAD_Y, 1, mmCOMPUTE_NUM_THREAD_Z, 1, + mmCOMPUTE_PGM_RSRC1, 0x240, /* SGPRS=9 (80 GPRS) */ mmCOMPUTE_PGM_RSRC2, 20, mmCOMPUTE_USER_DATA_0, 0xedcedc00, mmCOMPUTE_USER_DATA_1, 0xedcedc01, @@ -1528,6 +1530,7 @@ static const u32 sgpr2_init_regs[] = mmCOMPUTE_NUM_THREAD_X, 256*5, mmCOMPUTE_NUM_THREAD_Y, 1, mmCOMPUTE_NUM_THREAD_Z, 1, + mmCOMPUTE_PGM_RSRC1, 0x240, /* SGPRS=9 (80 GPRS) */ mmCOMPUTE_PGM_RSRC2, 20, mmCOMPUTE_USER_DATA_0, 0xedcedc00, mmCOMPUTE_USER_DATA_1, 0xedcedc01, -- GitLab From 20d10d70f0ed262e93589e6ac0171dbebf825859 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 15 Mar 2018 22:11:54 -0500 Subject: [PATCH 159/855] objtool, perf: Fix GCC 8 -Wrestrict error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 854e55ad289ef8888e7991f0ada85d5846f5afb9 upstream. Starting with recent GCC 8 builds, objtool and perf fail to build with the following error: ../str_error_r.c: In function ‘str_error_r’: ../str_error_r.c:25:3: error: passing argument 1 to restrict-qualified parameter aliases with argument 5 [-Werror=restrict] snprintf(buf, buflen, "INTERNAL ERROR: strerror_r(%d, %p, %zd)=%d", errnum, buf, buflen, err); The code seems harmless, but there's probably no benefit in printing the 'buf' pointer in this situation anyway, so just remove it to make GCC happy. Reported-by: Laura Abbott Signed-off-by: Josh Poimboeuf Tested-by: Laura Abbott Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/r/20180316031154.juk2uncs7baffctp@treble Signed-off-by: Arnaldo Carvalho de Melo Cc: Fredrik Schön Signed-off-by: Greg Kroah-Hartman --- tools/lib/str_error_r.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lib/str_error_r.c b/tools/lib/str_error_r.c index 503ae072244c..9ab2d0ad22d5 100644 --- a/tools/lib/str_error_r.c +++ b/tools/lib/str_error_r.c @@ -21,6 +21,6 @@ char *str_error_r(int errnum, char *buf, size_t buflen) { int err = strerror_r(errnum, buf, buflen); if (err) - snprintf(buf, buflen, "INTERNAL ERROR: strerror_r(%d, %p, %zd)=%d", errnum, buf, buflen, err); + snprintf(buf, buflen, "INTERNAL ERROR: strerror_r(%d, [buf], %zd)=%d", errnum, buflen, err); return buf; } -- GitLab From d8d835584146c2ce701c1d26c916cdd137b89517 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 6 Feb 2018 15:37:52 -0800 Subject: [PATCH 160/855] tools/lib/subcmd/pager.c: do not alias select() params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ad343a98e74e85aa91d844310e797f96fee6983b upstream. Use a separate fd set for select()-s exception fds param to fix the following gcc warning: pager.c:36:12: error: passing argument 2 to restrict-qualified parameter aliases with argument 4 [-Werror=restrict] select(1, &in, NULL, &in, NULL); ^~~ ~~~ Link: http://lkml.kernel.org/r/20180101105626.7168-1-sergey.senozhatsky@gmail.com Signed-off-by: Sergey Senozhatsky Cc: Arnaldo Carvalho de Melo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Fredrik Schön Signed-off-by: Greg Kroah-Hartman --- tools/lib/subcmd/pager.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/lib/subcmd/pager.c b/tools/lib/subcmd/pager.c index 6518bea926d6..68af60fdf0b9 100644 --- a/tools/lib/subcmd/pager.c +++ b/tools/lib/subcmd/pager.c @@ -29,10 +29,13 @@ static void pager_preexec(void) * have real input */ fd_set in; + fd_set exception; FD_ZERO(&in); + FD_ZERO(&exception); FD_SET(0, &in); - select(1, &in, NULL, &in, NULL); + FD_SET(0, &exception); + select(1, &in, NULL, &exception, NULL); setenv("LESS", "FRSX", 0); } -- GitLab From 41b0aa3c18d2db3b6597b48833f058698fd25d16 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 24 Apr 2018 23:19:51 +0200 Subject: [PATCH 161/855] x86/ipc: Fix x32 version of shmid64_ds and msqid64_ds commit 1a512c0882bd311c5b5561840fcfbe4c25b8f319 upstream. A bugfix broke the x32 shmid64_ds and msqid64_ds data structure layout (as seen from user space) a few years ago: Originally, __BITS_PER_LONG was defined as 64 on x32, so we did not have padding after the 64-bit __kernel_time_t fields, After __BITS_PER_LONG got changed to 32, applications would observe extra padding. In other parts of the uapi headers we seem to have a mix of those expecting either 32 or 64 on x32 applications, so we can't easily revert the path that broke these two structures. Instead, this patch decouples x32 from the other architectures and moves it back into arch specific headers, partially reverting the even older commit 73a2d096fdf2 ("x86: remove all now-duplicate header files"). It's not clear whether this ever made any difference, since at least glibc carries its own (correct) copy of both of these header files, so possibly no application has ever observed the definitions here. Based on a suggestion from H.J. Lu, I tried out the tool from https://github.com/hjl-tools/linux-header to find other such bugs, which pointed out the same bug in statfs(), which also has a separate (correct) copy in glibc. Fixes: f4b4aae18288 ("x86/headers/uapi: Fix __BITS_PER_LONG value for x32 builds") Signed-off-by: Arnd Bergmann Signed-off-by: Thomas Gleixner Cc: "H . J . Lu" Cc: Jeffrey Walton Cc: stable@vger.kernel.org Cc: "H. Peter Anvin" Link: https://lkml.kernel.org/r/20180424212013.3967461-1-arnd@arndb.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/uapi/asm/msgbuf.h | 31 ++++++++++++++++++++++ arch/x86/include/uapi/asm/shmbuf.h | 42 ++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/arch/x86/include/uapi/asm/msgbuf.h b/arch/x86/include/uapi/asm/msgbuf.h index 809134c644a6..90ab9a795b49 100644 --- a/arch/x86/include/uapi/asm/msgbuf.h +++ b/arch/x86/include/uapi/asm/msgbuf.h @@ -1 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __ASM_X64_MSGBUF_H +#define __ASM_X64_MSGBUF_H + +#if !defined(__x86_64__) || !defined(__ILP32__) #include +#else +/* + * The msqid64_ds structure for x86 architecture with x32 ABI. + * + * On x86-32 and x86-64 we can just use the generic definition, but + * x32 uses the same binary layout as x86_64, which is differnet + * from other 32-bit architectures. + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; + __kernel_time_t msg_stime; /* last msgsnd time */ + __kernel_time_t msg_rtime; /* last msgrcv time */ + __kernel_time_t msg_ctime; /* last change time */ + __kernel_ulong_t msg_cbytes; /* current number of bytes on queue */ + __kernel_ulong_t msg_qnum; /* number of messages in queue */ + __kernel_ulong_t msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + __kernel_ulong_t __unused4; + __kernel_ulong_t __unused5; +}; + +#endif + +#endif /* __ASM_GENERIC_MSGBUF_H */ diff --git a/arch/x86/include/uapi/asm/shmbuf.h b/arch/x86/include/uapi/asm/shmbuf.h index 83c05fc2de38..644421f3823b 100644 --- a/arch/x86/include/uapi/asm/shmbuf.h +++ b/arch/x86/include/uapi/asm/shmbuf.h @@ -1 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __ASM_X86_SHMBUF_H +#define __ASM_X86_SHMBUF_H + +#if !defined(__x86_64__) || !defined(__ILP32__) #include +#else +/* + * The shmid64_ds structure for x86 architecture with x32 ABI. + * + * On x86-32 and x86-64 we can just use the generic definition, but + * x32 uses the same binary layout as x86_64, which is differnet + * from other 32-bit architectures. + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ + __kernel_time_t shm_atime; /* last attach time */ + __kernel_time_t shm_dtime; /* last detach time */ + __kernel_time_t shm_ctime; /* last change time */ + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + __kernel_ulong_t shm_nattch; /* no. of current attaches */ + __kernel_ulong_t __unused4; + __kernel_ulong_t __unused5; +}; + +struct shminfo64 { + __kernel_ulong_t shmmax; + __kernel_ulong_t shmmin; + __kernel_ulong_t shmmni; + __kernel_ulong_t shmseg; + __kernel_ulong_t shmall; + __kernel_ulong_t __unused1; + __kernel_ulong_t __unused2; + __kernel_ulong_t __unused3; + __kernel_ulong_t __unused4; +}; + +#endif + +#endif /* __ASM_X86_SHMBUF_H */ -- GitLab From 09e43b9be9657f25a66ec82a273ffd0d580e785d Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Tue, 3 Apr 2018 09:02:28 -0500 Subject: [PATCH 162/855] x86/smpboot: Don't use mwait_play_dead() on AMD systems commit da6fa7ef67f07108a1b0cb9fd9e7fcaabd39c051 upstream. Recent AMD systems support using MWAIT for C1 state. However, MWAIT will not allow deeper cstates than C1 on current systems. play_dead() expects to use the deepest state available. The deepest state available on AMD systems is reached through SystemIO or HALT. If MWAIT is available, it is preferred over the other methods, so the CPU never reaches the deepest possible state. Don't try to use MWAIT to play_dead() on AMD systems. Instead, use CPUIDLE to enter the deepest state advertised by firmware. If CPUIDLE is not available then fallback to HALT. Signed-off-by: Yazen Ghannam Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Cc: stable@vger.kernel.org Cc: Yazen Ghannam Link: https://lkml.kernel.org/r/20180403140228.58540-1-Yazen.Ghannam@amd.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/smpboot.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index e803d72ef525..83929cc47a4b 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1591,6 +1591,8 @@ static inline void mwait_play_dead(void) void *mwait_ptr; int i; + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + return; if (!this_cpu_has(X86_FEATURE_MWAIT)) return; if (!this_cpu_has(X86_FEATURE_CLFLUSH)) -- GitLab From c11a6ed509f086efebc52ad4fd8713e7acfbc076 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sat, 21 Apr 2018 10:19:29 +0200 Subject: [PATCH 163/855] x86/microcode/intel: Save microcode patch unconditionally commit 84749d83758af6576552046b215b9b7f37f9556b upstream. save_mc_for_early() was a no-op on !CONFIG_HOTPLUG_CPU but the generic_load_microcode() path saves the microcode patches it has found into the cache of patches which is used for late loading too. Regardless of whether CPU hotplug is used or not. Make the saving unconditional so that late loading can find the proper patch. Reported-by: Vitezslav Samel Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Tested-by: Vitezslav Samel Tested-by: Ashok Raj Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20180418081140.GA2439@pc11.op.pod.cz Link: https://lkml.kernel.org/r/20180421081930.15741-1-bp@alien8.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/intel.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 4bcd30c87531..79291d6fb301 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -474,7 +474,6 @@ static void show_saved_mc(void) */ static void save_mc_for_early(u8 *mc) { -#ifdef CONFIG_HOTPLUG_CPU /* Synchronization during CPU hotplug. */ static DEFINE_MUTEX(x86_cpu_microcode_mutex); @@ -521,7 +520,6 @@ static void save_mc_for_early(u8 *mc) out: mutex_unlock(&x86_cpu_microcode_mutex); -#endif } static bool __init load_builtin_intel_microcode(struct cpio_data *cp) -- GitLab From 80bb480f341dc75ca4cf7f3a1496d6493503c42a Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 26 Mar 2018 15:17:07 +1100 Subject: [PATCH 164/855] powerpc/eeh: Fix race with driver un/bind commit f0295e047fcf52ccb42561fb7de6942f5201b676 upstream. The current EEH callbacks can race with a driver unbind. This can result in a backtraces like this: EEH: Frozen PHB#0-PE#1fc detected EEH: PE location: S000009, PHB location: N/A CPU: 2 PID: 2312 Comm: kworker/u258:3 Not tainted 4.15.6-openpower1 #2 Workqueue: nvme-wq nvme_reset_work [nvme] Call Trace: dump_stack+0x9c/0xd0 (unreliable) eeh_dev_check_failure+0x420/0x470 eeh_check_failure+0xa0/0xa4 nvme_reset_work+0x138/0x1414 [nvme] process_one_work+0x1ec/0x328 worker_thread+0x2e4/0x3a8 kthread+0x14c/0x154 ret_from_kernel_thread+0x5c/0xc8 nvme nvme1: Removing after probe failure status: -19 cpu 0x23: Vector: 300 (Data Access) at [c000000ff50f3800] pc: c0080000089a0eb0: nvme_error_detected+0x4c/0x90 [nvme] lr: c000000000026564: eeh_report_error+0xe0/0x110 sp: c000000ff50f3a80 msr: 9000000000009033 dar: 400 dsisr: 40000000 current = 0xc000000ff507c000 paca = 0xc00000000fdc9d80 softe: 0 irq_happened: 0x01 pid = 782, comm = eehd Linux version 4.15.6-openpower1 (smc@smc-desktop) (gcc version 6.4.0 (Buildroot 2017.11.2-00008-g4b6188e)) #2 SM P Tue Feb 27 12:33:27 PST 2018 enter ? for help eeh_report_error+0xe0/0x110 eeh_pe_dev_traverse+0xc0/0xdc eeh_handle_normal_event+0x184/0x4c4 eeh_handle_event+0x30/0x288 eeh_event_handler+0x124/0x170 kthread+0x14c/0x154 ret_from_kernel_thread+0x5c/0xc8 The first part is an EEH (on boot), the second half is the resulting crash. nvme probe starts the nvme_reset_work() worker thread. This worker thread starts touching the device which see a device error (EEH) and hence queues up an event in the powerpc EEH worker thread. nvme_reset_work() then continues and runs nvme_remove_dead_ctrl_work() which results in unbinding the driver from the device and hence releases all resources. At the same time, the EEH worker thread starts doing the EEH .error_detected() driver callback, which no longer works since the resources have been freed. This fixes the problem in the same way the generic PCIe AER code (in drivers/pci/pcie/aer/aerdrv_core.c) does. It makes the EEH code hold the device_lock() while performing the driver EEH callbacks and associated code. This ensures either the callbacks are no longer register, or if they are registered the driver will not be removed from underneath us. This has been broken forever. The EEH call backs were first introduced in 2005 (in 77bd7415610) but it's not clear if a lock was needed back then. Fixes: 77bd74156101 ("[PATCH] powerpc: PCI Error Recovery: PPC64 core recovery routines") Cc: stable@vger.kernel.org # v2.6.16+ Signed-off-by: Michael Neuling Reviewed-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/eeh_driver.c | 61 ++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index 6ef8f0bceacd..27843665da9e 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -207,18 +207,18 @@ static void *eeh_report_error(void *data, void *userdata) if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) return NULL; + + device_lock(&dev->dev); dev->error_state = pci_channel_io_frozen; driver = eeh_pcid_get(dev); - if (!driver) return NULL; + if (!driver) goto out_no_dev; eeh_disable_irq(dev); if (!driver->err_handler || - !driver->err_handler->error_detected) { - eeh_pcid_put(dev); - return NULL; - } + !driver->err_handler->error_detected) + goto out; rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen); @@ -227,7 +227,10 @@ static void *eeh_report_error(void *data, void *userdata) if (*res == PCI_ERS_RESULT_NONE) *res = rc; edev->in_error = true; +out: eeh_pcid_put(dev); +out_no_dev: + device_unlock(&dev->dev); return NULL; } @@ -250,15 +253,14 @@ static void *eeh_report_mmio_enabled(void *data, void *userdata) if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) return NULL; + device_lock(&dev->dev); driver = eeh_pcid_get(dev); - if (!driver) return NULL; + if (!driver) goto out_no_dev; if (!driver->err_handler || !driver->err_handler->mmio_enabled || - (edev->mode & EEH_DEV_NO_HANDLER)) { - eeh_pcid_put(dev); - return NULL; - } + (edev->mode & EEH_DEV_NO_HANDLER)) + goto out; rc = driver->err_handler->mmio_enabled(dev); @@ -266,7 +268,10 @@ static void *eeh_report_mmio_enabled(void *data, void *userdata) if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; if (*res == PCI_ERS_RESULT_NONE) *res = rc; +out: eeh_pcid_put(dev); +out_no_dev: + device_unlock(&dev->dev); return NULL; } @@ -289,20 +294,20 @@ static void *eeh_report_reset(void *data, void *userdata) if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) return NULL; + + device_lock(&dev->dev); dev->error_state = pci_channel_io_normal; driver = eeh_pcid_get(dev); - if (!driver) return NULL; + if (!driver) goto out_no_dev; eeh_enable_irq(dev); if (!driver->err_handler || !driver->err_handler->slot_reset || (edev->mode & EEH_DEV_NO_HANDLER) || - (!edev->in_error)) { - eeh_pcid_put(dev); - return NULL; - } + (!edev->in_error)) + goto out; rc = driver->err_handler->slot_reset(dev); if ((*res == PCI_ERS_RESULT_NONE) || @@ -310,7 +315,10 @@ static void *eeh_report_reset(void *data, void *userdata) if (*res == PCI_ERS_RESULT_DISCONNECT && rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; +out: eeh_pcid_put(dev); +out_no_dev: + device_unlock(&dev->dev); return NULL; } @@ -361,10 +369,12 @@ static void *eeh_report_resume(void *data, void *userdata) if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) return NULL; + + device_lock(&dev->dev); dev->error_state = pci_channel_io_normal; driver = eeh_pcid_get(dev); - if (!driver) return NULL; + if (!driver) goto out_no_dev; was_in_error = edev->in_error; edev->in_error = false; @@ -374,13 +384,15 @@ static void *eeh_report_resume(void *data, void *userdata) !driver->err_handler->resume || (edev->mode & EEH_DEV_NO_HANDLER) || !was_in_error) { edev->mode &= ~EEH_DEV_NO_HANDLER; - eeh_pcid_put(dev); - return NULL; + goto out; } driver->err_handler->resume(dev); +out: eeh_pcid_put(dev); +out_no_dev: + device_unlock(&dev->dev); return NULL; } @@ -400,22 +412,25 @@ static void *eeh_report_failure(void *data, void *userdata) if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) return NULL; + + device_lock(&dev->dev); dev->error_state = pci_channel_io_perm_failure; driver = eeh_pcid_get(dev); - if (!driver) return NULL; + if (!driver) goto out_no_dev; eeh_disable_irq(dev); if (!driver->err_handler || - !driver->err_handler->error_detected) { - eeh_pcid_put(dev); - return NULL; - } + !driver->err_handler->error_detected) + goto out; driver->err_handler->error_detected(dev, pci_channel_io_perm_failure); +out: eeh_pcid_put(dev); +out_no_dev: + device_unlock(&dev->dev); return NULL; } -- GitLab From eff40cb1908ba6ba604068d6273584fc28e3bac8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 1 May 2018 15:13:10 -0700 Subject: [PATCH 165/855] Linux 4.9.98 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ee3e943c3bd9..96d770488ae6 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 97 +SUBLEVEL = 98 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 334bf92c33449c994004e9d1340fd552fcf33ef3 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Wed, 2 May 2018 12:02:40 -0700 Subject: [PATCH 166/855] FROMLIST: staging: vsoc: Create wc kernel mapping for region shm. Map the region shm as write-combining instead of uncachable. Signed-off-by: Alistair Strachan [sent upstream via staging https://patchwork.kernel.org/patch/10376965/] Bug: 702147120 Change-Id: If587b4f26abaa3580b889b04dbb655f8d5b4a8ee --- drivers/staging/android/TODO | 1 - drivers/staging/android/vsoc.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/staging/android/TODO b/drivers/staging/android/TODO index dd64148f1587..edfb6809eb9e 100644 --- a/drivers/staging/android/TODO +++ b/drivers/staging/android/TODO @@ -39,7 +39,6 @@ vsoc.c, uapi/vsoc_shm.h waiting threads. We should eventually use multiple queues and select the queue based on the region. - Add debugfs support for examining the permissions of regions. - - Use ioremap_wc instead of ioremap_nocache. - Remove VSOC_WAIT_FOR_INCOMING_INTERRUPT ioctl. This functionality has been superseded by the futex and is there for legacy reasons. diff --git a/drivers/staging/android/vsoc.c b/drivers/staging/android/vsoc.c index 587c66d709b9..794137b7751f 100644 --- a/drivers/staging/android/vsoc.c +++ b/drivers/staging/android/vsoc.c @@ -802,9 +802,7 @@ static int vsoc_probe_device(struct pci_dev *pdev, dev_info(&pdev->dev, "shared memory @ DMA %p size=0x%zx\n", (void *)vsoc_dev.shm_phys_start, vsoc_dev.shm_size); - /* TODO(ghartman): ioremap_wc should work here */ - vsoc_dev.kernel_mapped_shm = ioremap_nocache( - vsoc_dev.shm_phys_start, vsoc_dev.shm_size); + vsoc_dev.kernel_mapped_shm = pci_iomap_wc(pdev, SHARED_MEMORY_BAR, 0); if (!vsoc_dev.kernel_mapped_shm) { dev_err(&vsoc_dev.dev->dev, "cannot iomap region\n"); vsoc_remove_device(pdev); -- GitLab From 4a0c0eedc86c20a1deb4e58041733cbc33049c63 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Wed, 2 May 2018 12:03:20 -0700 Subject: [PATCH 167/855] FROMLIST: staging: vsoc: Fix a i386-randconfig warning. Fix "warning: cast to pointer from integer of different size" when printing the region shm physical address. Use the %pa conversion specifier and pass the resource by reference. Signed-off-by: Alistair Strachan [sent upstream via staging https://patchwork.kernel.org/patch/10376967/] Bug: 702147120 Change-Id: Ibb0c32b461821235155c464bfd5c5963db512734 --- drivers/staging/android/vsoc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/android/vsoc.c b/drivers/staging/android/vsoc.c index 794137b7751f..3e6e4af7d6a1 100644 --- a/drivers/staging/android/vsoc.c +++ b/drivers/staging/android/vsoc.c @@ -800,8 +800,8 @@ static int vsoc_probe_device(struct pci_dev *pdev, vsoc_dev.shm_phys_start = pci_resource_start(pdev, SHARED_MEMORY_BAR); vsoc_dev.shm_size = pci_resource_len(pdev, SHARED_MEMORY_BAR); - dev_info(&pdev->dev, "shared memory @ DMA %p size=0x%zx\n", - (void *)vsoc_dev.shm_phys_start, vsoc_dev.shm_size); + dev_info(&pdev->dev, "shared memory @ DMA %pa size=0x%zx\n", + &vsoc_dev.shm_phys_start, vsoc_dev.shm_size); vsoc_dev.kernel_mapped_shm = pci_iomap_wc(pdev, SHARED_MEMORY_BAR, 0); if (!vsoc_dev.kernel_mapped_shm) { dev_err(&vsoc_dev.dev->dev, "cannot iomap region\n"); -- GitLab From 0e25e2cab07a5398d912531ef02ab118735f1aa4 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Wed, 2 May 2018 11:46:03 -0700 Subject: [PATCH 168/855] FROMLIST: staging: Fix sparse warnings in vsoc driver. Signed-off-by: Alistair Strachan [sent upstream via staging https://patchwork.kernel.org/patch/10376969/] Bug: 702147120 Change-Id: I762db3bdb5e931be70ddac58f9d4e05cafb5986d --- drivers/staging/android/vsoc.c | 100 ++++++++++++++++----------------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/drivers/staging/android/vsoc.c b/drivers/staging/android/vsoc.c index 3e6e4af7d6a1..954ed2c5d807 100644 --- a/drivers/staging/android/vsoc.c +++ b/drivers/staging/android/vsoc.c @@ -81,8 +81,8 @@ struct vsoc_region_data { atomic_t *incoming_signalled; /* Flag indicating the guest has signalled the host. */ atomic_t *outgoing_signalled; - int irq_requested; - int device_created; + bool irq_requested; + bool device_created; }; struct vsoc_device { @@ -91,7 +91,7 @@ struct vsoc_device { /* Physical address of SHARED_MEMORY_BAR. */ phys_addr_t shm_phys_start; /* Kernel virtual address of SHARED_MEMORY_BAR. */ - void *kernel_mapped_shm; + void __iomem *kernel_mapped_shm; /* Size of the entire shared memory window in bytes. */ size_t shm_size; /* @@ -116,22 +116,23 @@ struct vsoc_device { * vsoc_region_data because the kernel deals with them as an array. */ struct msix_entry *msix_entries; - /* - * Flags that indicate what we've initialzied. These are used to do an - * orderly cleanup of the device. - */ - char enabled_device; - char requested_regions; - char cdev_added; - char class_added; - char msix_enabled; /* Mutex that protectes the permission list */ struct mutex mtx; /* Major number assigned by the kernel */ int major; - + /* Character device assigned by the kernel */ struct cdev cdev; + /* Device class assigned by the kernel */ struct class *class; + /* + * Flags that indicate what we've initialized. These are used to do an + * orderly cleanup of the device. + */ + bool enabled_device; + bool requested_regions; + bool cdev_added; + bool class_added; + bool msix_enabled; }; static struct vsoc_device vsoc_dev; @@ -153,13 +154,13 @@ static long vsoc_ioctl(struct file *, unsigned int, unsigned long); static int vsoc_mmap(struct file *, struct vm_area_struct *); static int vsoc_open(struct inode *, struct file *); static int vsoc_release(struct inode *, struct file *); -static ssize_t vsoc_read(struct file *, char *, size_t, loff_t *); -static ssize_t vsoc_write(struct file *, const char *, size_t, loff_t *); +static ssize_t vsoc_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t vsoc_write(struct file *, const char __user *, size_t, loff_t *); static loff_t vsoc_lseek(struct file *filp, loff_t offset, int origin); static int do_create_fd_scoped_permission( struct vsoc_device_region *region_p, struct fd_scoped_permission_node *np, - struct fd_scoped_permission_arg *__user arg); + struct fd_scoped_permission_arg __user *arg); static void do_destroy_fd_scoped_permission( struct vsoc_device_region *owner_region_p, struct fd_scoped_permission *perm); @@ -198,7 +199,7 @@ inline int vsoc_validate_filep(struct file *filp) /* Converts from shared memory offset to virtual address */ static inline void *shm_off_to_virtual_addr(__u32 offset) { - return vsoc_dev.kernel_mapped_shm + offset; + return (void __force *)vsoc_dev.kernel_mapped_shm + offset; } /* Converts from shared memory offset to physical address */ @@ -261,7 +262,7 @@ static struct pci_driver vsoc_pci_driver = { static int do_create_fd_scoped_permission( struct vsoc_device_region *region_p, struct fd_scoped_permission_node *np, - struct fd_scoped_permission_arg *__user arg) + struct fd_scoped_permission_arg __user *arg) { struct file *managed_filp; s32 managed_fd; @@ -632,11 +633,11 @@ static long vsoc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return 0; } -static ssize_t vsoc_read(struct file *filp, char *buffer, size_t len, +static ssize_t vsoc_read(struct file *filp, char __user *buffer, size_t len, loff_t *poffset) { __u32 area_off; - void *area_p; + const void *area_p; ssize_t area_len; int retval = vsoc_validate_filep(filp); @@ -706,7 +707,7 @@ static loff_t vsoc_lseek(struct file *filp, loff_t offset, int origin) return offset; } -static ssize_t vsoc_write(struct file *filp, const char *buffer, +static ssize_t vsoc_write(struct file *filp, const char __user *buffer, size_t len, loff_t *poffset) { __u32 area_off; @@ -772,14 +773,14 @@ static int vsoc_probe_device(struct pci_dev *pdev, pci_name(pdev), result); return result; } - vsoc_dev.enabled_device = 1; + vsoc_dev.enabled_device = true; result = pci_request_regions(pdev, "vsoc"); if (result < 0) { dev_err(&pdev->dev, "pci_request_regions failed\n"); vsoc_remove_device(pdev); return -EBUSY; } - vsoc_dev.requested_regions = 1; + vsoc_dev.requested_regions = true; /* Set up the control registers in BAR 0 */ reg_size = pci_resource_len(pdev, REGISTER_BAR); if (reg_size > MAX_REGISTER_BAR_LEN) @@ -790,7 +791,7 @@ static int vsoc_probe_device(struct pci_dev *pdev, if (!vsoc_dev.regs) { dev_err(&pdev->dev, - "cannot ioremap registers of size %zu\n", + "cannot map registers of size %zu\n", (size_t)reg_size); vsoc_remove_device(pdev); return -EBUSY; @@ -809,8 +810,8 @@ static int vsoc_probe_device(struct pci_dev *pdev, return -EBUSY; } - vsoc_dev.layout = - (struct vsoc_shm_layout_descriptor *)vsoc_dev.kernel_mapped_shm; + vsoc_dev.layout = (struct vsoc_shm_layout_descriptor __force *) + vsoc_dev.kernel_mapped_shm; dev_info(&pdev->dev, "major_version: %d\n", vsoc_dev.layout->major_version); dev_info(&pdev->dev, "minor_version: %d\n", @@ -841,16 +842,16 @@ static int vsoc_probe_device(struct pci_dev *pdev, vsoc_remove_device(pdev); return -EBUSY; } - vsoc_dev.cdev_added = 1; + vsoc_dev.cdev_added = true; vsoc_dev.class = class_create(THIS_MODULE, VSOC_DEV_NAME); if (IS_ERR(vsoc_dev.class)) { dev_err(&vsoc_dev.dev->dev, "class_create failed\n"); vsoc_remove_device(pdev); return PTR_ERR(vsoc_dev.class); } - vsoc_dev.class_added = 1; - vsoc_dev.regions = (struct vsoc_device_region *) - (vsoc_dev.kernel_mapped_shm + + vsoc_dev.class_added = true; + vsoc_dev.regions = (struct vsoc_device_region __force *) + ((void *)vsoc_dev.layout + vsoc_dev.layout->vsoc_region_desc_offset); vsoc_dev.msix_entries = kcalloc( vsoc_dev.layout->region_count, @@ -910,7 +911,7 @@ static int vsoc_probe_device(struct pci_dev *pdev, return -EFAULT; } } - vsoc_dev.msix_enabled = 1; + vsoc_dev.msix_enabled = true; for (i = 0; i < vsoc_dev.layout->region_count; ++i) { const struct vsoc_device_region *region = vsoc_dev.regions + i; size_t name_sz = sizeof(vsoc_dev.regions_data[i].name) - 1; @@ -928,14 +929,11 @@ static int vsoc_probe_device(struct pci_dev *pdev, &vsoc_dev.regions_data[i].interrupt_wait_queue); init_waitqueue_head(&vsoc_dev.regions_data[i].futex_wait_queue); vsoc_dev.regions_data[i].incoming_signalled = - vsoc_dev.kernel_mapped_shm + - region->region_begin_offset + + shm_off_to_virtual_addr(region->region_begin_offset) + h_to_g_signal_table->interrupt_signalled_offset; vsoc_dev.regions_data[i].outgoing_signalled = - vsoc_dev.kernel_mapped_shm + - region->region_begin_offset + + shm_off_to_virtual_addr(region->region_begin_offset) + g_to_h_signal_table->interrupt_signalled_offset; - result = request_irq( vsoc_dev.msix_entries[i].vector, vsoc_interrupt, 0, @@ -948,7 +946,7 @@ static int vsoc_probe_device(struct pci_dev *pdev, vsoc_remove_device(pdev); return -ENOSPC; } - vsoc_dev.regions_data[i].irq_requested = 1; + vsoc_dev.regions_data[i].irq_requested = true; if (!device_create(vsoc_dev.class, NULL, MKDEV(vsoc_dev.major, i), NULL, vsoc_dev.regions_data[i].name)) { @@ -956,7 +954,7 @@ static int vsoc_probe_device(struct pci_dev *pdev, vsoc_remove_device(pdev); return -EBUSY; } - vsoc_dev.regions_data[i].device_created = 1; + vsoc_dev.regions_data[i].device_created = true; } return 0; } @@ -988,51 +986,51 @@ static void vsoc_remove_device(struct pci_dev *pdev) if (vsoc_dev.regions_data[i].device_created) { device_destroy(vsoc_dev.class, MKDEV(vsoc_dev.major, i)); - vsoc_dev.regions_data[i].device_created = 0; + vsoc_dev.regions_data[i].device_created = false; } if (vsoc_dev.regions_data[i].irq_requested) free_irq(vsoc_dev.msix_entries[i].vector, NULL); - vsoc_dev.regions_data[i].irq_requested = 0; + vsoc_dev.regions_data[i].irq_requested = false; } kfree(vsoc_dev.regions_data); - vsoc_dev.regions_data = 0; + vsoc_dev.regions_data = NULL; } if (vsoc_dev.msix_enabled) { pci_disable_msix(pdev); - vsoc_dev.msix_enabled = 0; + vsoc_dev.msix_enabled = false; } kfree(vsoc_dev.msix_entries); - vsoc_dev.msix_entries = 0; - vsoc_dev.regions = 0; + vsoc_dev.msix_entries = NULL; + vsoc_dev.regions = NULL; if (vsoc_dev.class_added) { class_destroy(vsoc_dev.class); - vsoc_dev.class_added = 0; + vsoc_dev.class_added = false; } if (vsoc_dev.cdev_added) { cdev_del(&vsoc_dev.cdev); - vsoc_dev.cdev_added = 0; + vsoc_dev.cdev_added = false; } if (vsoc_dev.major && vsoc_dev.layout) { unregister_chrdev_region(MKDEV(vsoc_dev.major, 0), vsoc_dev.layout->region_count); vsoc_dev.major = 0; } - vsoc_dev.layout = 0; + vsoc_dev.layout = NULL; if (vsoc_dev.kernel_mapped_shm) { pci_iounmap(pdev, vsoc_dev.kernel_mapped_shm); - vsoc_dev.kernel_mapped_shm = 0; + vsoc_dev.kernel_mapped_shm = NULL; } if (vsoc_dev.regs) { pci_iounmap(pdev, vsoc_dev.regs); - vsoc_dev.regs = 0; + vsoc_dev.regs = NULL; } if (vsoc_dev.requested_regions) { pci_release_regions(pdev); - vsoc_dev.requested_regions = 0; + vsoc_dev.requested_regions = false; } if (vsoc_dev.enabled_device) { pci_disable_device(pdev); - vsoc_dev.enabled_device = 0; + vsoc_dev.enabled_device = false; } /* Do this last: it indicates that the device is not initialized. */ vsoc_dev.dev = NULL; -- GitLab From 692f73f7a27e08986f5c5bfe84cd5c548664ad07 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 2 May 2018 15:11:32 -0700 Subject: [PATCH 169/855] ARM: dts: msm: Add camnoc-min-bw entry in cpas node for sdm670/sdm845 This field determines the min camnoc axi bw needed based on the target. Currently this value is defined as a macro, moving this field to the device tree. Change-Id: I258c9711729f52e812d51241cfa6b38ed6a8c700 Signed-off-by: Karthik Anantha Ram --- arch/arm64/boot/dts/qcom/sdm670-camera.dtsi | 1 + arch/arm64/boot/dts/qcom/sdm845-camera.dtsi | 1 + arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi index fc46e9aeab3e..f999cd8826fa 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi @@ -408,6 +408,7 @@ interrupt-names = "cpas_camnoc"; interrupts = <0 459 0>; qcom,cpas-hw-ver = <0x170110>; /* Titan v170 v1.1.0 */ + camnoc-axi-min-ib-bw = <3000000000>; regulator-names = "camss-vdd"; camss-vdd-supply = <&titan_top_gdsc>; clock-names = "gcc_ahb_clk", diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi index fd6a0c751ad6..2e2de74999af 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi @@ -381,6 +381,7 @@ interrupt-names = "cpas_camnoc"; interrupts = <0 459 0>; qcom,cpas-hw-ver = <0x170100>; /* Titan v170 v1.0.0 */ + camnoc-axi-min-ib-bw = <3000000000>; regulator-names = "camss-vdd"; camss-vdd-supply = <&titan_top_gdsc>; clock-names = "gcc_ahb_clk", diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi index 85419c807270..97cb9814b65d 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi @@ -302,6 +302,7 @@ interrupt-names = "cpas_camnoc"; interrupts = <0 459 0>; qcom,cpas-hw-ver = <0x170110>; /* Titan v170 v1.1.0 */ + camnoc-axi-min-ib-bw = <3000000000>; regulator-names = "camss-vdd"; camss-vdd-supply = <&titan_top_gdsc>; clock-names = "gcc_ahb_clk", -- GitLab From f5a861c30cb747052533025bc8dd2f8b76a24451 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 3 May 2017 16:09:38 +0100 Subject: [PATCH 170/855] UPSTREAM: arm64: uaccess: suppress spurious clang warning Clang tries to warn when there's a mismatch between an operand's size, and the size of the register it is held in, as this may indicate a bug. Specifically, clang warns when the operand's type is less than 64 bits wide, and the register is used unqualified (i.e. %N rather than %xN or %wN). Unfortunately clang can generate these warnings for unreachable code. For example, for code like: do { \ typeof(*(ptr)) __v = (v); \ switch(sizeof(*(ptr))) { \ case 1: \ // assume __v is 1 byte wide \ asm ("{op}b %w0" : : "r" (v)); \ break; \ case 8: \ // assume __v is 8 bytes wide \ asm ("{op} %0" : : "r" (v)); \ break; \ } while (0) ... if op() were passed a char value and pointer to char, clang may produce a warning for the unreachable case where sizeof(*(ptr)) is 8. For the same reasons, clang produces warnings when __put_user_err() is used for types that are less than 64 bits wide. We could avoid this with a cast to a fixed-width type in each of the cases. However, GCC will then warn that pointer types are being cast to mismatched integer sizes (in unreachable paths). Another option would be to use the same union trickery as we do for __smp_store_release() and __smp_load_acquire(), but this is fairly invasive. Instead, this patch suppresses the clang warning by using an x modifier in the assembly for the 8 byte case of __put_user_err(). No additional work is necessary as the value has been cast to typeof(*(ptr)), so the compiler will have performed any necessary extension for the reachable case. For consistency, __get_user_err() is also updated to use the x modifier for its 8 byte case. Acked-by: Will Deacon Signed-off-by: Mark Rutland Reported-by: Matthias Kaehlcke Signed-off-by: Catalin Marinas Change-Id: Ia247c38c824826b7b64991ea3bf0649e84d3a808 (cherry picked from commit d135b8b5060ea91dd751ff172d179eb4eab1e966) Signed-off-by: Sami Tolvanen --- arch/arm64/include/asm/uaccess.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 0d71949e4a4c..ed846aff603c 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -311,7 +311,7 @@ do { \ (err), ARM64_HAS_UAO); \ break; \ case 8: \ - __get_user_asm("ldr", "ldtr", "%", __gu_val, (ptr), \ + __get_user_asm("ldr", "ldtr", "%x", __gu_val, (ptr), \ (err), ARM64_HAS_UAO); \ break; \ default: \ @@ -383,7 +383,7 @@ do { \ (err), ARM64_HAS_UAO); \ break; \ case 8: \ - __put_user_asm("str", "sttr", "%", __pu_val, (ptr), \ + __put_user_asm("str", "sttr", "%x", __pu_val, (ptr), \ (err), ARM64_HAS_UAO); \ break; \ default: \ -- GitLab From ea5ec6ca85f9b5fd5d99411632ceff1deb2f8d6b Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 25 Jul 2017 11:36:25 -0700 Subject: [PATCH 171/855] UPSTREAM: netpoll: Fix device name check in netpoll_setup() Apparently netpoll_setup() assumes that netpoll.dev_name is a pointer when checking if the device name is set: if (np->dev_name) { ... However the field is a character array, therefore the condition always yields true. Check instead whether the first byte of the array has a non-zero value. Signed-off-by: Matthias Kaehlcke Signed-off-by: David S. Miller (cherry picked from commit 0c3a8f8b8fabff4f3ad2dd7b95ae0e90cdd1aebb) Bug: 78886293 Change-Id: I1a6eec091c4bab5769a3519196f529030a71b6dd Signed-off-by: Alistair Strachan --- net/core/netpoll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 457f882b0f7b..9b2d61120c0d 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -666,7 +666,7 @@ int netpoll_setup(struct netpoll *np) int err; rtnl_lock(); - if (np->dev_name) { + if (np->dev_name[0]) { struct net *net = current->nsproxy->net_ns; ndev = __dev_get_by_name(net, np->dev_name); } -- GitLab From 1201ddda31076a8ca2f15f4a3eb50b5c64e973a1 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 18 Apr 2017 16:30:37 -0700 Subject: [PATCH 172/855] BACKPORT: clocksource: Use GENMASK_ULL in definition of CLOCKSOURCE_MASK Besides reusing existing code this removes the special case handling for 64-bit masks, which causes clang to raise a shift count overflow warning due to https://bugs.llvm.org//show_bug.cgi?id=10030. Suggested-by: Dmitry Torokhov Signed-off-by: Matthias Kaehlcke Cc: Grant Grundler Cc: Greg Hackmann Cc: Michael Davidson Cc: John Stultz Link: http://lkml.kernel.org/r/20170418233037.70990-1-mka@chromium.org Signed-off-by: Thomas Gleixner (cherry picked from commit 0773cea37470f8e080c510fe720fc356cf35df3a) [astrachan: minor re-diff; (cycle_t) vs (u64) cast] Bug: 78886293 Change-Id: I97df9621cc65bba74a5086c2c35c2224b559a156 Signed-off-by: Alistair Strachan --- include/linux/clocksource.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 08398182f56e..36dc52067377 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -117,7 +117,7 @@ struct clocksource { #define CLOCK_SOURCE_RESELECT 0x100 /* simplify initialization of mask field */ -#define CLOCKSOURCE_MASK(bits) (cycle_t)((bits) < 64 ? ((1ULL<<(bits))-1) : -1) +#define CLOCKSOURCE_MASK(bits) GENMASK_ULL((bits) - 1, 0) static inline u32 clocksource_freq2mult(u32 freq, u32 shift_constant, u64 from) { -- GitLab From 3341c56cc76bf2b9b4a5f03c1342fdd108ca594e Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Fri, 21 Apr 2017 16:41:10 -0700 Subject: [PATCH 173/855] UPSTREAM: tracing: Use cpumask_available() to check if cpumask variable may be used This fixes the following clang warning: kernel/trace/trace.c:3231:12: warning: address of array 'iter->started' will always evaluate to 'true' [-Wpointer-bool-conversion] if (iter->started) Link: http://lkml.kernel.org/r/20170421234110.117075-1-mka@chromium.org Signed-off-by: Matthias Kaehlcke Signed-off-by: Steven Rostedt (VMware) (cherry picked from commit 4dbbe2d8e95c351157f292ece067f985c30c7b53) Bug: 78886293 Change-Id: Ib17a68ce55ca80b04bdea2d232f8ca9f88b1b8a3 Signed-off-by: Alistair Strachan --- kernel/trace/trace.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 7590d6acc82b..35cfccbede3d 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3051,13 +3051,14 @@ static void test_cpu_buff_start(struct trace_iterator *iter) if (!(iter->iter_flags & TRACE_FILE_ANNOTATE)) return; - if (iter->started && cpumask_test_cpu(iter->cpu, iter->started)) + if (cpumask_available(iter->started) && + cpumask_test_cpu(iter->cpu, iter->started)) return; if (per_cpu_ptr(iter->trace_buffer->data, iter->cpu)->skipped_entries) return; - if (iter->started) + if (cpumask_available(iter->started)) cpumask_set_cpu(iter->cpu, iter->started); /* Don't print started cpu buffer for the first entry of the trace */ -- GitLab From b805351b41f9b2bb2b11179ed9632201b638beeb Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Sun, 21 May 2017 01:58:07 -0700 Subject: [PATCH 174/855] UPSTREAM: sysfs: remove signedness from sysfs_get_dirent sysfs_get_dirent is usually invoked with a string literal, which have the type char[]. While the toplevel Makefile disables -Wpointer-sign, other Makefiles like arch/x86/boot/compressed/Makefile redefine KBUILD_CFLAGS. Fixes the warning: In file included from arch/x86/boot/compressed/kaslr.c:17: In file included from ./include/linux/module.h:17: In file included from ./include/linux/kobject.h:21: ./include/linux/sysfs.h:517:37: warning: passing 'const unsigned char *' to parameter of type 'const char *' converts between pointers to integer types with different sign [-Wpointer-sign] return kernfs_find_and_get(parent, name); ^~~~ ./include/linux/kernfs.h:462:57: note: passing argument to parameter 'name' here kernfs_find_and_get(struct kernfs_node *kn, const char *name) ^ Signed-off-by: Nick Desaulniers Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 89cf2a20c3f13dbb4c15a0c6d2e390e700992173) Bug: 78886293 Change-Id: Ic03f7b132fbf67b3543462448aa3f3633eae49a6 Signed-off-by: Alistair Strachan --- include/linux/sysfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 00a1f330f93a..9c452f6db438 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -518,7 +518,7 @@ static inline void sysfs_notify_dirent(struct kernfs_node *kn) } static inline struct kernfs_node *sysfs_get_dirent(struct kernfs_node *parent, - const unsigned char *name) + const char *name) { return kernfs_find_and_get(parent, name); } -- GitLab From 63a812bb84e4d1d9af530075a2831d9374ff8ed3 Mon Sep 17 00:00:00 2001 From: Greg Hartman Date: Fri, 4 May 2018 14:45:44 -0700 Subject: [PATCH 175/855] ANDROID: x86_64_cuttlefish_defconfig: Disable KPTI Disable page table isolation to avoid kernel panics when booting kernels under KVM. Temporary workaround while this issue is investigated. Bug: 78252157 Bug: 71362031 Change-Id: I5ba126b08678fcb8fd7bc31fe79de80fa81cf869 Signed-off-by: Greg Hartman Signed-off-by: Alistair Strachan --- arch/x86/configs/x86_64_cuttlefish_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 43c95758a914..5b06edda428f 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -59,7 +59,7 @@ CONFIG_PHYSICAL_START=0x200000 CONFIG_RANDOMIZE_BASE=y CONFIG_PHYSICAL_ALIGN=0x1000000 CONFIG_CMDLINE_BOOL=y -CONFIG_CMDLINE="console=ttyS0 reboot=p" +CONFIG_CMDLINE="console=ttyS0 reboot=p nopti" CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set -- GitLab From a03d0bbacd41b7f3f94431ba607193d013634671 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Thu, 3 May 2018 22:16:10 -0700 Subject: [PATCH 176/855] ANDROID: build.config: enforce trace_printk check Bug: 79166848 Change-Id: I41d2fe57b377e305b4b68c30c98ee94643d142e4 Test: Build a kernel with trace_prink and see warning Signed-off-by: Wei Wang --- build.config.cuttlefish.x86_64 | 1 + build.config.goldfish.arm | 1 + build.config.goldfish.arm64 | 1 + build.config.goldfish.mips | 1 + build.config.goldfish.mips64 | 1 + build.config.goldfish.x86 | 1 + build.config.goldfish.x86_64 | 1 + 7 files changed, 7 insertions(+) diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64 index 5a9656359f0b..edfa1506dcff 100644 --- a/build.config.cuttlefish.x86_64 +++ b/build.config.cuttlefish.x86_64 @@ -13,3 +13,4 @@ arch/x86/boot/bzImage vmlinux System.map " +STOP_SHIP_TRACEPRINTK=1 diff --git a/build.config.goldfish.arm b/build.config.goldfish.arm index 866da9361b71..ff5646ab4f40 100644 --- a/build.config.goldfish.arm +++ b/build.config.goldfish.arm @@ -10,3 +10,4 @@ arch/arm/boot/zImage vmlinux System.map " +STOP_SHIP_TRACEPRINTK=1 diff --git a/build.config.goldfish.arm64 b/build.config.goldfish.arm64 index 9c963cf4a3d8..4c896a679ab9 100644 --- a/build.config.goldfish.arm64 +++ b/build.config.goldfish.arm64 @@ -10,3 +10,4 @@ arch/arm64/boot/Image vmlinux System.map " +STOP_SHIP_TRACEPRINTK=1 diff --git a/build.config.goldfish.mips b/build.config.goldfish.mips index 8af53d2c2940..9a14a444ac14 100644 --- a/build.config.goldfish.mips +++ b/build.config.goldfish.mips @@ -9,3 +9,4 @@ FILES=" vmlinux System.map " +STOP_SHIP_TRACEPRINTK=1 diff --git a/build.config.goldfish.mips64 b/build.config.goldfish.mips64 index 2a33d36dc4c8..6ad9759f5f4a 100644 --- a/build.config.goldfish.mips64 +++ b/build.config.goldfish.mips64 @@ -9,3 +9,4 @@ FILES=" vmlinux System.map " +STOP_SHIP_TRACEPRINTK=1 diff --git a/build.config.goldfish.x86 b/build.config.goldfish.x86 index f86253f58d4d..2266c621835e 100644 --- a/build.config.goldfish.x86 +++ b/build.config.goldfish.x86 @@ -10,3 +10,4 @@ arch/x86/boot/bzImage vmlinux System.map " +STOP_SHIP_TRACEPRINTK=1 diff --git a/build.config.goldfish.x86_64 b/build.config.goldfish.x86_64 index e1738861ec5c..08c42c2eba03 100644 --- a/build.config.goldfish.x86_64 +++ b/build.config.goldfish.x86_64 @@ -10,3 +10,4 @@ arch/x86/boot/bzImage vmlinux System.map " +STOP_SHIP_TRACEPRINTK=1 -- GitLab From 6a70286b43e22f808929f116b2ceed523bba16e1 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 3 May 2018 23:26:02 -0700 Subject: [PATCH 177/855] UPSTREAM: f2fs: avoid fsync() failure caused by EAGAIN in writepage() pageout() in MM traslates EAGAIN, so calls handle_write_error() -> mapping_set_error() -> set_bit(AS_EIO, ...). file_write_and_wait_range() will see EIO error, which is critical to return value of fsync() followed by atomic_write failure to user. Change-Id: I25a2b2e020ddb9df24b07bc73ac039a4e47e5ca0 Signed-off-by: Jaegeuk Kim (cherry picked from commit 5b37ebbaebc64e25dc4a2a618666628d49ecc5f3) --- fs/f2fs/data.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index b1fd4e2f63a5..a481dde24870 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1903,7 +1903,13 @@ static int __write_data_page(struct page *page, bool *submitted, redirty_out: redirty_page_for_writepage(wbc, page); - if (!err) + /* + * pageout() in MM traslates EAGAIN, so calls handle_write_error() + * -> mapping_set_error() -> set_bit(AS_EIO, ...). + * file_write_and_wait_range() will see EIO error, which is critical + * to return value of fsync() followed by atomic_write failure to user. + */ + if (!err || wbc->for_reclaim) return AOP_WRITEPAGE_ACTIVATE; unlock_page(page); return err; -- GitLab From 9731a2dab47eadf85572b0924c072306bb6c3c5d Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 11 Apr 2018 23:09:04 -0700 Subject: [PATCH 178/855] UPSTREAM: f2fs: clear PageError on writepage - part 2 This patch clears PageError in some pages tagged by read path, but when we write the pages with valid contents, writepage should clear the bit likewise ext4. Change-Id: I434b22132f29f7243ab9170296a6e0b52e40701d Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim (cherry picked from commit f453147e9315b3bc1050b590278a63d91fc2a681) --- fs/f2fs/gc.c | 1 + fs/f2fs/inline.c | 1 + fs/f2fs/node.c | 1 + fs/f2fs/segment.c | 1 + 4 files changed, 4 insertions(+) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 604d3fcb8957..66044faf2b71 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -693,6 +693,7 @@ static void move_data_block(struct inode *inode, block_t bidx, dec_page_count(fio.sbi, F2FS_DIRTY_META); set_page_writeback(fio.encrypted_page); + ClearPageError(page); /* allocate block address */ f2fs_wait_on_page_writeback(dn.node_page, NODE, true); diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 26832e778233..156ac4ff491a 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -157,6 +157,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) /* write data page to try to make data consistent */ set_page_writeback(page); + ClearPageError(page); fio.old_blkaddr = dn->data_blkaddr; set_inode_flag(dn->inode, FI_HOT_DATA); write_data_page(dn, &fio); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index ccf410af9192..803a0102a47b 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1398,6 +1398,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted, fio.op_flags |= REQ_PREFLUSH | REQ_FUA; set_page_writeback(page); + ClearPageError(page); fio.old_blkaddr = ni.blk_addr; write_node_page(nid, &fio); set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(page)); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index fc4ee3835f1d..bdf567a7f9b7 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2758,6 +2758,7 @@ void write_meta_page(struct f2fs_sb_info *sbi, struct page *page, fio.op_flags &= ~REQ_META; set_page_writeback(page); + ClearPageError(page); f2fs_submit_page_write(&fio); f2fs_update_iostat(sbi, io_type, F2FS_BLKSIZE); -- GitLab From bf52a75da4a6100fc7ca30ef117dae342ae9f4e8 Mon Sep 17 00:00:00 2001 From: Junzhe Zou Date: Tue, 8 May 2018 17:53:48 -0700 Subject: [PATCH 179/855] msm: camera: lrme: fix return value in error condition Fix the return value if packet validation fails. Change-Id: Id7fed7e37b14fd1aaeaac476dcb123c0559e22cf Signed-off-by: Junzhe Zou --- .../platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index 898997aa173b..a60661e04cd3 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -879,6 +879,7 @@ static int cam_lrme_mgr_hw_prepare_update(void *hw_mgr_priv, if (args->num_in_map_entries == 0 || args->num_out_map_entries == 0) { CAM_ERR(CAM_LRME, "Error in port number in %d, out %d", args->num_in_map_entries, args->num_out_map_entries); + rc = -EINVAL; goto error; } -- GitLab From 0f8a75e90963019cef486565f2b088bb570a7ddb Mon Sep 17 00:00:00 2001 From: Tan Xiaojun Date: Thu, 23 Feb 2017 14:04:39 +0800 Subject: [PATCH 180/855] perf/core: Fix the perf_cpu_time_max_percent check commit 1572e45a924f254d9570093abde46430c3172e3d upstream. Use "proc_dointvec_minmax" instead of "proc_dointvec" to check the input value from user-space. If not, we can set a big value and some vars will overflow like "sysctl_perf_event_sample_rate" which will cause a lot of unexpected problems. Signed-off-by: Tan Xiaojun Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1487829879-56237-1-git-send-email-tanxiaojun@huawei.com Signed-off-by: Ingo Molnar Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- kernel/events/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index b1d6b9888fba..cbc51826cb94 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -453,7 +453,7 @@ int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - int ret = proc_dointvec(table, write, buffer, lenp, ppos); + int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); if (ret || !write) return ret; -- GitLab From 8f54ead2389feeb1c9d4a308af7cb4e8496716ff Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 14 Mar 2018 08:27:26 -0700 Subject: [PATCH 181/855] percpu: include linux/sched.h for cond_resched() commit 71546d100422bcc2c543dadeb9328728997cd23a upstream. microblaze build broke due to missing declaration of the cond_resched() invocation added recently. Let's include linux/sched.h explicitly. Signed-off-by: Tejun Heo Reported-by: kbuild test robot Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- mm/percpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/percpu.c b/mm/percpu.c index f014cebbf405..3794cfc88689 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -70,6 +70,7 @@ #include #include #include +#include #include #include -- GitLab From fcbc8d0e7dbef92a6b611a6d3d1ed8ea228464a0 Mon Sep 17 00:00:00 2001 From: Teng Qin Date: Mon, 24 Apr 2017 19:00:37 -0700 Subject: [PATCH 182/855] bpf: map_get_next_key to return first key on NULL commit 8fe45924387be6b5c1be59a7eb330790c61d5d10 upstream. When iterating through a map, we need to find a key that does not exist in the map so map_get_next_key will give us the first key of the map. This often requires a lot of guessing in production systems. This patch makes map_get_next_key return the first key when the key pointer in the parameter is NULL. Signed-off-by: Teng Qin Signed-off-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Chenbo Feng Cc: Lorenzo Colitti Signed-off-by: Greg Kroah-Hartman --- kernel/bpf/arraymap.c | 2 +- kernel/bpf/hashtab.c | 9 +++++---- kernel/bpf/syscall.c | 20 ++++++++++++-------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index a38119e4a427..eb43f7e219f9 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -190,7 +190,7 @@ int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value) static int array_map_get_next_key(struct bpf_map *map, void *key, void *next_key) { struct bpf_array *array = container_of(map, struct bpf_array, map); - u32 index = *(u32 *)key; + u32 index = key ? *(u32 *)key : U32_MAX; u32 *next = (u32 *)next_key; if (index >= array->map.max_entries) { diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c index ad2f0ed75471..a36a532c056d 100644 --- a/kernel/bpf/hashtab.c +++ b/kernel/bpf/hashtab.c @@ -326,12 +326,15 @@ static int htab_map_get_next_key(struct bpf_map *map, void *key, void *next_key) struct hlist_head *head; struct htab_elem *l, *next_l; u32 hash, key_size; - int i; + int i = 0; WARN_ON_ONCE(!rcu_read_lock_held()); key_size = map->key_size; + if (!key) + goto find_first_elem; + hash = htab_map_hash(key, key_size); head = select_bucket(htab, hash); @@ -339,10 +342,8 @@ static int htab_map_get_next_key(struct bpf_map *map, void *key, void *next_key) /* lookup the key */ l = lookup_elem_raw(head, hash, key, key_size); - if (!l) { - i = 0; + if (!l) goto find_first_elem; - } /* key was found, get next key in the same bucket */ next_l = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(&l->hash_node)), diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index f8b4e3e16cef..ca7e277e8b5f 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -508,14 +508,18 @@ static int map_get_next_key(union bpf_attr *attr) if (IS_ERR(map)) return PTR_ERR(map); - err = -ENOMEM; - key = kmalloc(map->key_size, GFP_USER); - if (!key) - goto err_put; - - err = -EFAULT; - if (copy_from_user(key, ukey, map->key_size) != 0) - goto free_key; + if (ukey) { + err = -ENOMEM; + key = kmalloc(map->key_size, GFP_USER); + if (!key) + goto err_put; + + err = -EFAULT; + if (copy_from_user(key, ukey, map->key_size) != 0) + goto free_key; + } else { + key = NULL; + } err = -ENOMEM; next_key = kmalloc(map->key_size, GFP_USER); -- GitLab From b8beca48a5504a790f3e308adcb965c6d9c657dc Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 21 Jan 2018 16:42:56 +0000 Subject: [PATCH 183/855] arm/arm64: KVM: Add PSCI version selection API commit 85bd0ba1ff9875798fad94218b627ea9f768f3c3 upstream. Although we've implemented PSCI 0.1, 0.2 and 1.0, we expose either 0.1 or 1.0 to a guest, defaulting to the latest version of the PSCI implementation that is compatible with the requested version. This is no different from doing a firmware upgrade on KVM. But in order to give a chance to hypothetical badly implemented guests that would have a fit by discovering something other than PSCI 0.2, let's provide a new API that allows userspace to pick one particular version of the API. This is implemented as a new class of "firmware" registers, where we expose the PSCI version. This allows the PSCI version to be save/restored as part of a guest migration, and also set to any supported version if the guest requires it. Cc: stable@vger.kernel.org #4.16 Reviewed-by: Christoffer Dall Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- Documentation/virtual/kvm/api.txt | 9 +++- Documentation/virtual/kvm/arm/psci.txt | 30 +++++++++++++ arch/arm/include/asm/kvm_host.h | 3 ++ arch/arm/include/uapi/asm/kvm.h | 6 +++ arch/arm/kvm/guest.c | 13 ++++++ arch/arm/kvm/psci.c | 60 ++++++++++++++++++++++++++ arch/arm64/include/asm/kvm_host.h | 3 ++ arch/arm64/include/uapi/asm/kvm.h | 6 +++ arch/arm64/kvm/guest.c | 14 +++++- include/kvm/arm_psci.h | 16 ++++++- 10 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 Documentation/virtual/kvm/arm/psci.txt diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 1f5eab4ef88f..e46c14fac9da 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2118,6 +2118,9 @@ ARM 32-bit VFP control registers have the following id bit patterns: ARM 64-bit FP registers have the following id bit patterns: 0x4030 0000 0012 0 +ARM firmware pseudo-registers have the following bit pattern: + 0x4030 0000 0014 + arm64 registers are mapped using the lower 32 bits. The upper 16 of that is the register group type, or coprocessor number: @@ -2134,6 +2137,9 @@ arm64 CCSIDR registers are demultiplexed by CSSELR value: arm64 system registers have the following id bit patterns: 0x6030 0000 0013 +arm64 firmware pseudo-registers have the following bit pattern: + 0x6030 0000 0014 + MIPS registers are mapped using the lower 32 bits. The upper 16 of that is the register group type: @@ -2656,7 +2662,8 @@ Possible features: and execute guest code when KVM_RUN is called. - KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode. Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only). - - KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 for the CPU. + - KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 (or a future revision + backward compatible with v0.2) for the CPU. Depends on KVM_CAP_ARM_PSCI_0_2. - KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU. Depends on KVM_CAP_ARM_PMU_V3. diff --git a/Documentation/virtual/kvm/arm/psci.txt b/Documentation/virtual/kvm/arm/psci.txt new file mode 100644 index 000000000000..aafdab887b04 --- /dev/null +++ b/Documentation/virtual/kvm/arm/psci.txt @@ -0,0 +1,30 @@ +KVM implements the PSCI (Power State Coordination Interface) +specification in order to provide services such as CPU on/off, reset +and power-off to the guest. + +The PSCI specification is regularly updated to provide new features, +and KVM implements these updates if they make sense from a virtualization +point of view. + +This means that a guest booted on two different versions of KVM can +observe two different "firmware" revisions. This could cause issues if +a given guest is tied to a particular PSCI revision (unlikely), or if +a migration causes a different PSCI version to be exposed out of the +blue to an unsuspecting guest. + +In order to remedy this situation, KVM exposes a set of "firmware +pseudo-registers" that can be manipulated using the GET/SET_ONE_REG +interface. These registers can be saved/restored by userspace, and set +to a convenient value if required. + +The following register is defined: + +* KVM_REG_ARM_PSCI_VERSION: + + - Only valid if the vcpu has the KVM_ARM_VCPU_PSCI_0_2 feature set + (and thus has already been initialized) + - Returns the current PSCI version on GET_ONE_REG (defaulting to the + highest PSCI version implemented by KVM and compatible with v0.2) + - Allows any PSCI version implemented by KVM and compatible with + v0.2 to be set with SET_ONE_REG + - Affects the whole VM (even if the register view is per-vcpu) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 9fe1043e72d2..f4dab20ac9f3 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -78,6 +78,9 @@ struct kvm_arch { /* Interrupt controller */ struct vgic_dist vgic; int max_vcpus; + + /* Mandated version of PSCI */ + u32 psci_version; }; #define KVM_NR_MEM_OBJS 40 diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index b38c10c73579..0b8cf31d8416 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -173,6 +173,12 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_VFP_FPINST 0x1009 #define KVM_REG_ARM_VFP_FPINST2 0x100A +/* KVM-as-firmware specific pseudo-registers */ +#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM | KVM_REG_SIZE_U64 | \ + KVM_REG_ARM_FW | ((r) & 0xffff)) +#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) + /* Device Control API: ARM VGIC */ #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index 9aca92074f85..630117d2e8bd 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -176,6 +177,7 @@ static unsigned long num_core_regs(void) unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) { return num_core_regs() + kvm_arm_num_coproc_regs(vcpu) + + kvm_arm_get_fw_num_regs(vcpu) + NUM_TIMER_REGS; } @@ -196,6 +198,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) uindices++; } + ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices); + if (ret) + return ret; + uindices += kvm_arm_get_fw_num_regs(vcpu); + ret = copy_timer_indices(vcpu, uindices); if (ret) return ret; @@ -214,6 +221,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) return get_core_reg(vcpu, reg); + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW) + return kvm_arm_get_fw_reg(vcpu, reg); + if (is_timer_reg(reg->id)) return get_timer_reg(vcpu, reg); @@ -230,6 +240,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) return set_core_reg(vcpu, reg); + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW) + return kvm_arm_set_fw_reg(vcpu, reg); + if (is_timer_reg(reg->id)) return set_timer_reg(vcpu, reg); diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 3d962257c166..8a9c654f4f87 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -425,3 +426,62 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) smccc_set_retval(vcpu, val, 0, 0, 0); return 1; } + +int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) +{ + return 1; /* PSCI version */ +} + +int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + if (put_user(KVM_REG_ARM_PSCI_VERSION, uindices)) + return -EFAULT; + + return 0; +} + +int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) +{ + if (reg->id == KVM_REG_ARM_PSCI_VERSION) { + void __user *uaddr = (void __user *)(long)reg->addr; + u64 val; + + val = kvm_psci_version(vcpu, vcpu->kvm); + if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + return 0; + } + + return -EINVAL; +} + +int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) +{ + if (reg->id == KVM_REG_ARM_PSCI_VERSION) { + void __user *uaddr = (void __user *)(long)reg->addr; + bool wants_02; + u64 val; + + if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features); + + switch (val) { + case KVM_ARM_PSCI_0_1: + if (wants_02) + return -EINVAL; + vcpu->kvm->arch.psci_version = val; + return 0; + case KVM_ARM_PSCI_0_2: + case KVM_ARM_PSCI_1_0: + if (!wants_02) + return -EINVAL; + vcpu->kvm->arch.psci_version = val; + return 0; + } + } + + return -EINVAL; +} diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 37d56e85036e..0a33ea304e63 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -73,6 +73,9 @@ struct kvm_arch { /* Timer */ struct arch_timer_kvm timer; + + /* Mandated version of PSCI */ + u32 psci_version; }; #define KVM_NR_MEM_OBJS 40 diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 3051f86a9b5f..702de7a2b024 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -195,6 +195,12 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2) #define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2) +/* KVM-as-firmware specific pseudo-registers */ +#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ + KVM_REG_ARM_FW | ((r) & 0xffff)) +#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) + /* Device Control API: ARM VGIC */ #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 3f9e15722473..d3e0a2ffb383 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -205,7 +206,7 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) { return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu) - + NUM_TIMER_REGS; + + kvm_arm_get_fw_num_regs(vcpu) + NUM_TIMER_REGS; } /** @@ -225,6 +226,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) uindices++; } + ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices); + if (ret) + return ret; + uindices += kvm_arm_get_fw_num_regs(vcpu); + ret = copy_timer_indices(vcpu, uindices); if (ret) return ret; @@ -243,6 +249,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) return get_core_reg(vcpu, reg); + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW) + return kvm_arm_get_fw_reg(vcpu, reg); + if (is_timer_reg(reg->id)) return get_timer_reg(vcpu, reg); @@ -259,6 +268,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) return set_core_reg(vcpu, reg); + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW) + return kvm_arm_set_fw_reg(vcpu, reg); + if (is_timer_reg(reg->id)) return set_timer_reg(vcpu, reg); diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h index e518e4e3dfb5..4b1548129fa2 100644 --- a/include/kvm/arm_psci.h +++ b/include/kvm/arm_psci.h @@ -37,10 +37,15 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu, struct kvm *kvm) * Our PSCI implementation stays the same across versions from * v0.2 onward, only adding the few mandatory functions (such * as FEATURES with 1.0) that are required by newer - * revisions. It is thus safe to return the latest. + * revisions. It is thus safe to return the latest, unless + * userspace has instructed us otherwise. */ - if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) + if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) { + if (vcpu->kvm->arch.psci_version) + return vcpu->kvm->arch.psci_version; + return KVM_ARM_PSCI_LATEST; + } return KVM_ARM_PSCI_0_1; } @@ -48,4 +53,11 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu, struct kvm *kvm) int kvm_hvc_call_handler(struct kvm_vcpu *vcpu); +struct kvm_one_reg; + +int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu); +int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices); +int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); +int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); + #endif /* __KVM_ARM_PSCI_H__ */ -- GitLab From 23fb8f797e6bee5c39b43e6f4c6f15203ee8ea14 Mon Sep 17 00:00:00 2001 From: LEROY Christophe Date: Thu, 22 Mar 2018 10:57:01 +0100 Subject: [PATCH 184/855] crypto: talitos - fix IPsec cipher in length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 2b1227301a8e4729409694e323b72c064c47cb6b upstream. For SEC 2.x+, cipher in length must contain only the ciphertext length. In case of using hardware ICV checking, the ICV length is provided via the "extent" field of the descriptor pointer. Cc: # 4.8+ Fixes: 549bd8bc5987 ("crypto: talitos - Implement AEAD for SEC1 using HMAC_SNOOP_NO_AFEU") Reported-by: Horia Geantă Signed-off-by: Christophe Leroy Tested-by: Horia Geantă Signed-off-by: Herbert Xu [backported to 4.9.y, 4.14.y] Signed-off-by: Horia Geantă Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/talitos.c | 41 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 42c060c7ae15..7c71722be395 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -1116,10 +1116,10 @@ static int sg_to_link_tbl_offset(struct scatterlist *sg, int sg_count, return count; } -int talitos_sg_map(struct device *dev, struct scatterlist *src, - unsigned int len, struct talitos_edesc *edesc, - struct talitos_ptr *ptr, - int sg_count, unsigned int offset, int tbl_off) +static int talitos_sg_map_ext(struct device *dev, struct scatterlist *src, + unsigned int len, struct talitos_edesc *edesc, + struct talitos_ptr *ptr, int sg_count, + unsigned int offset, int tbl_off, int elen) { struct talitos_private *priv = dev_get_drvdata(dev); bool is_sec1 = has_ftr_sec1(priv); @@ -1130,7 +1130,7 @@ int talitos_sg_map(struct device *dev, struct scatterlist *src, } to_talitos_ptr_len(ptr, len, is_sec1); - to_talitos_ptr_ext_set(ptr, 0, is_sec1); + to_talitos_ptr_ext_set(ptr, elen, is_sec1); if (sg_count == 1) { to_talitos_ptr(ptr, sg_dma_address(src) + offset, is_sec1); @@ -1140,7 +1140,7 @@ int talitos_sg_map(struct device *dev, struct scatterlist *src, to_talitos_ptr(ptr, edesc->dma_link_tbl + offset, is_sec1); return sg_count; } - sg_count = sg_to_link_tbl_offset(src, sg_count, offset, len, + sg_count = sg_to_link_tbl_offset(src, sg_count, offset, len + elen, &edesc->link_tbl[tbl_off]); if (sg_count == 1) { /* Only one segment now, so no link tbl needed*/ @@ -1154,6 +1154,15 @@ int talitos_sg_map(struct device *dev, struct scatterlist *src, return sg_count; } +static int talitos_sg_map(struct device *dev, struct scatterlist *src, + unsigned int len, struct talitos_edesc *edesc, + struct talitos_ptr *ptr, int sg_count, + unsigned int offset, int tbl_off) +{ + return talitos_sg_map_ext(dev, src, len, edesc, ptr, sg_count, offset, + tbl_off, 0); +} + /* * fill in and submit ipsec_esp descriptor */ @@ -1171,7 +1180,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, unsigned int ivsize = crypto_aead_ivsize(aead); int tbl_off = 0; int sg_count, ret; - int sg_link_tbl_len; + int elen = 0; bool sync_needed = false; struct talitos_private *priv = dev_get_drvdata(dev); bool is_sec1 = has_ftr_sec1(priv); @@ -1225,20 +1234,12 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, * extent is bytes of HMAC postpended to ciphertext, * typically 12 for ipsec */ - to_talitos_ptr_len(&desc->ptr[4], cryptlen, is_sec1); - to_talitos_ptr_ext_set(&desc->ptr[4], 0, is_sec1); - - sg_link_tbl_len = cryptlen; - - if (desc->hdr & DESC_HDR_TYPE_IPSEC_ESP) { - to_talitos_ptr_ext_set(&desc->ptr[4], authsize, is_sec1); - - if (edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV) - sg_link_tbl_len += authsize; - } + if ((desc->hdr & DESC_HDR_TYPE_IPSEC_ESP) && + (desc->hdr & DESC_HDR_MODE1_MDEU_CICV)) + elen = authsize; - ret = talitos_sg_map(dev, areq->src, sg_link_tbl_len, edesc, - &desc->ptr[4], sg_count, areq->assoclen, tbl_off); + ret = talitos_sg_map_ext(dev, areq->src, cryptlen, edesc, &desc->ptr[4], + sg_count, areq->assoclen, tbl_off, elen); if (ret > 1) { tbl_off += ret; -- GitLab From aa6b517e74512ef8373ff66a40f4925f9b6edab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 24 May 2017 21:38:46 +0200 Subject: [PATCH 185/855] serial: imx: ensure UCR3 and UFCR are setup correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6df765dca378bddf994cfd2044acafa501bd800f upstream. Commit e61c38d85b73 ("serial: imx: setup DCEDTE early and ensure DCD and RI irqs to be off") has a flaw: While UCR3 and UFCR were modified using read-modify-write before it switched to write register values independent of the previous state. That's a good idea in principle (and that's why I did it) but needs more care. This patch reinstates read-modify-write for UFCR and for UCR3 ensures that RXDMUXSEL and ADNIMP are set for post imx1. Fixes: e61c38d85b73 ("serial: imx: setup DCEDTE early and ensure DCD and RI irqs to be off") Signed-off-by: Uwe Kleine-König Acked-by: Mika Penttilä Tested-by: Mika Penttilä Acked-by: Steve Twiss Tested-by: Steve Twiss Cc: Chris Ruehl Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index f575a33974fa..ecadc27eea48 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2145,7 +2145,9 @@ static int serial_imx_probe(struct platform_device *pdev) * and DCD (when they are outputs) or enables the respective * irqs. So set this bit early, i.e. before requesting irqs. */ - writel(UFCR_DCEDTE, sport->port.membase + UFCR); + reg = readl(sport->port.membase + UFCR); + if (!(reg & UFCR_DCEDTE)) + writel(reg | UFCR_DCEDTE, sport->port.membase + UFCR); /* * Disable UCR3_RI and UCR3_DCD irqs. They are also not @@ -2156,7 +2158,15 @@ static int serial_imx_probe(struct platform_device *pdev) sport->port.membase + UCR3); } else { - writel(0, sport->port.membase + UFCR); + unsigned long ucr3 = UCR3_DSR; + + reg = readl(sport->port.membase + UFCR); + if (reg & UFCR_DCEDTE) + writel(reg & ~UFCR_DCEDTE, sport->port.membase + UFCR); + + if (!is_imx1_uart(sport)) + ucr3 |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP; + writel(ucr3, sport->port.membase + UCR3); } clk_disable_unprepare(sport->clk_ipg); -- GitLab From 466e8d108d6f9cfacfc347ccc744e8d37a380560 Mon Sep 17 00:00:00 2001 From: Kristian Evensen Date: Thu, 1 Feb 2018 10:32:32 +0100 Subject: [PATCH 186/855] USB: serial: option: Add support for Quectel EP06 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 71a0483d56e784b1e11f38f10d7e22d265dbe244 upstream. The Quectel EP06 is a Cat. 6 LTE modem, and the interface mapping is as follows: 0: Diag 1: NMEA 2: AT 3: Modem Interface 4 is QMI and interface 5 is ADB, so they are blacklisted. This patch should also be considered for -stable. The QMI-patch for this modem is already in the -stable-queue. v1->v2: * Updated commit prefix (thanks Johan Hovold) * Updated commit message slightly. Signed-off-by: Kristian Evensen Acked-by: Johan Hovold Cc: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 1799aa058a5b..a1cb1ea41282 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -244,6 +244,7 @@ static void option_instat_callback(struct urb *urb); #define QUECTEL_PRODUCT_EC21 0x0121 #define QUECTEL_PRODUCT_EC25 0x0125 #define QUECTEL_PRODUCT_BG96 0x0296 +#define QUECTEL_PRODUCT_EP06 0x0306 #define CMOTECH_VENDOR_ID 0x16d8 #define CMOTECH_PRODUCT_6001 0x6001 @@ -692,6 +693,10 @@ static const struct option_blacklist_info yuga_clm920_nc5_blacklist = { .reserved = BIT(1) | BIT(4), }; +static const struct option_blacklist_info quectel_ep06_blacklist = { + .reserved = BIT(4) | BIT(5), +}; + static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -1206,6 +1211,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06), + .driver_info = (kernel_ulong_t)&quectel_ep06_blacklist }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003), -- GitLab From ec2088687413518d1f332848eaa96560dc28356c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 2 May 2018 08:48:46 +0200 Subject: [PATCH 187/855] ALSA: pcm: Check PCM state at xfern compat ioctl commit f13876e2c33a657a71bcbb10f767c0951b165020 upstream. Since snd_pcm_ioctl_xfern_compat() has no PCM state check, it may go further and hit the sanity check pcm_sanity_check() when the ioctl is called right after open. It may eventually spew a kernel warning, as triggered by syzbot, depending on kconfig. The lack of PCM state check there was just an oversight. Although it's no real crash, the spurious kernel warning is annoying, so let's add the proper check. Reported-by: syzbot+1dac3a4f6bc9c1c675d4@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/pcm_compat.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 1f64ab0c2a95..7ae080bae15c 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -426,6 +426,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, return -ENOTTY; if (substream->stream != dir) return -EINVAL; + if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) + return -EBADFD; if ((ch = substream->runtime->channels) > 128) return -EINVAL; -- GitLab From 955185725ba717f7a8f2495089503c05cd231bee Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Apr 2018 09:17:45 +0200 Subject: [PATCH 188/855] ALSA: seq: Fix races at MIDI encoding in snd_virmidi_output_trigger() commit 8f22e52528cc372b218b5f100457469615c733ce upstream. The sequencer virmidi code has an open race at its output trigger callback: namely, virmidi keeps only one event packet for processing while it doesn't protect for concurrent output trigger calls. snd_virmidi_output_trigger() tries to process the previously unfinished event before starting encoding the given MIDI stream, but this is done without any lock. Meanwhile, if another rawmidi stream starts the output trigger, this proceeds further, and overwrites the event package that is being processed in another thread. This eventually corrupts and may lead to the invalid memory access if the event type is like SYSEX. The fix is just to move the spinlock to cover both the pending event and the new stream. The bug was spotted by a new fuzzer, RaceFuzzer. BugLink: http://lkml.kernel.org/r/20180426045223.GA15307@dragonet.kaist.ac.kr Reported-by: DaeRyong Jeong Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/seq_virmidi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 200764948ed1..8bdc4c961f04 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -174,12 +174,12 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, } return; } + spin_lock_irqsave(&substream->runtime->lock, flags); if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) - return; + goto out; vmidi->event.type = SNDRV_SEQ_EVENT_NONE; } - spin_lock_irqsave(&substream->runtime->lock, flags); while (1) { count = __snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); if (count <= 0) -- GitLab From 68f4bc3ab8f13631ad6c144f13c22665382f0387 Mon Sep 17 00:00:00 2001 From: Robert Rosengren Date: Mon, 26 Mar 2018 07:24:49 +0200 Subject: [PATCH 189/855] ALSA: aloop: Mark paused device as inactive commit 306a4f3ca7f3c7dfa473ebd19d66e40e59d99734 upstream. Show paused ALSA aloop device as inactive, i.e. the control "PCM Slave Active" set as false. Notification sent upon state change. This makes it possible for client capturing from aloop device to know if data is expected. Without it the client expects data even if playback is paused. Signed-off-by: Robert Rosengren Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/drivers/aloop.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index dc91002d1e0d..80ec5c69c5df 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -296,6 +296,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) cable->pause |= stream; loopback_timer_stop(dpcm); spin_unlock(&cable->lock); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + loopback_active_notify(dpcm); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: @@ -304,6 +306,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) cable->pause &= ~stream; loopback_timer_start(dpcm); spin_unlock(&cable->lock); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + loopback_active_notify(dpcm); break; default: return -EINVAL; @@ -893,9 +897,11 @@ static int loopback_active_get(struct snd_kcontrol *kcontrol, [kcontrol->id.subdevice][kcontrol->id.device ^ 1]; unsigned int val = 0; - if (cable != NULL) - val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? - 1 : 0; + if (cable != NULL) { + unsigned int running = cable->running ^ cable->pause; + + val = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 1 : 0; + } ucontrol->value.integer.value[0] = val; return 0; } -- GitLab From b6a49cc35cf52ac3835a22a0bbcff59be6d181bd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Apr 2018 10:06:48 +0200 Subject: [PATCH 190/855] ALSA: aloop: Add missing cable lock to ctl API callbacks commit 76b3421b39bd610546931fc923edcf90c18fa395 upstream. Some control API callbacks in aloop driver are too lazy to take the loopback->cable_lock and it results in possible races of cable access while it's being freed. It eventually lead to a UAF, as reported by fuzzer recently. This patch covers such control API callbacks and add the proper mutex locks. Reported-by: DaeRyong Jeong Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/drivers/aloop.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 80ec5c69c5df..847f70348d4d 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -832,9 +832,11 @@ static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol, { struct loopback *loopback = snd_kcontrol_chip(kcontrol); + mutex_lock(&loopback->cable_lock); ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].rate_shift; + mutex_unlock(&loopback->cable_lock); return 0; } @@ -866,9 +868,11 @@ static int loopback_notify_get(struct snd_kcontrol *kcontrol, { struct loopback *loopback = snd_kcontrol_chip(kcontrol); + mutex_lock(&loopback->cable_lock); ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].notify; + mutex_unlock(&loopback->cable_lock); return 0; } @@ -880,12 +884,14 @@ static int loopback_notify_put(struct snd_kcontrol *kcontrol, int change = 0; val = ucontrol->value.integer.value[0] ? 1 : 0; + mutex_lock(&loopback->cable_lock); if (val != loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].notify) { loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].notify = val; change = 1; } + mutex_unlock(&loopback->cable_lock); return change; } @@ -893,15 +899,18 @@ static int loopback_active_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct loopback *loopback = snd_kcontrol_chip(kcontrol); - struct loopback_cable *cable = loopback->cables - [kcontrol->id.subdevice][kcontrol->id.device ^ 1]; + struct loopback_cable *cable; + unsigned int val = 0; + mutex_lock(&loopback->cable_lock); + cable = loopback->cables[kcontrol->id.subdevice][kcontrol->id.device ^ 1]; if (cable != NULL) { unsigned int running = cable->running ^ cable->pause; val = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 1 : 0; } + mutex_unlock(&loopback->cable_lock); ucontrol->value.integer.value[0] = val; return 0; } @@ -944,9 +953,11 @@ static int loopback_rate_get(struct snd_kcontrol *kcontrol, { struct loopback *loopback = snd_kcontrol_chip(kcontrol); + mutex_lock(&loopback->cable_lock); ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].rate; + mutex_unlock(&loopback->cable_lock); return 0; } @@ -966,9 +977,11 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol, { struct loopback *loopback = snd_kcontrol_chip(kcontrol); + mutex_lock(&loopback->cable_lock); ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].channels; + mutex_unlock(&loopback->cable_lock); return 0; } -- GitLab From 0f2c8b315f7b502ec1381c7397332a6157c1345c Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 15 Mar 2018 08:44:24 -0400 Subject: [PATCH 191/855] tracepoint: Do not warn on ENOMEM commit d66a270be3310d7aa132fec0cea77d3d32a0ff75 upstream. Tracepoint should only warn when a kernel API user does not respect the required preconditions (e.g. same tracepoint enabled twice, or called to remove a tracepoint that does not exist). Silence warning in out-of-memory conditions, given that the error is returned to the caller. This ensures that out-of-memory error-injection testing does not trigger warnings in tracepoint.c, which were seen by syzbot. Link: https://lkml.kernel.org/r/001a114465e241a8720567419a72@google.com Link: https://lkml.kernel.org/r/001a1140e0de15fc910567464190@google.com Link: http://lkml.kernel.org/r/20180315124424.32319-1-mathieu.desnoyers@efficios.com CC: Peter Zijlstra CC: Jiri Olsa CC: Arnaldo Carvalho de Melo CC: Alexander Shishkin CC: Namhyung Kim CC: stable@vger.kernel.org Fixes: de7b2973903c6 ("tracepoint: Use struct pointer instead of name hash for reg/unreg tracepoints") Reported-by: syzbot+9c0d616860575a73166a@syzkaller.appspotmail.com Reported-by: syzbot+4e9ae7fa46233396f64d@syzkaller.appspotmail.com Signed-off-by: Mathieu Desnoyers Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/tracepoint.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index d0639d917899..c8e7cc0e6ff6 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -202,7 +202,7 @@ static int tracepoint_add_func(struct tracepoint *tp, lockdep_is_held(&tracepoints_mutex)); old = func_add(&tp_funcs, func, prio); if (IS_ERR(old)) { - WARN_ON_ONCE(1); + WARN_ON_ONCE(PTR_ERR(old) != -ENOMEM); return PTR_ERR(old); } @@ -235,7 +235,7 @@ static int tracepoint_remove_func(struct tracepoint *tp, lockdep_is_held(&tracepoints_mutex)); old = func_remove(&tp_funcs, func); if (IS_ERR(old)) { - WARN_ON_ONCE(1); + WARN_ON_ONCE(PTR_ERR(old) != -ENOMEM); return PTR_ERR(old); } -- GitLab From 4178de2e9e188b2c9839ddf518f0b38de3c9291a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 6 Apr 2018 10:23:05 -0700 Subject: [PATCH 192/855] Input: leds - fix out of bound access commit 6bd6ae639683c0b41f46990d5c64ff9fbfa019dc upstream. UI_SET_LEDBIT ioctl() causes the following KASAN splat when used with led > LED_CHARGING: [ 1274.663418] BUG: KASAN: slab-out-of-bounds in input_leds_connect+0x611/0x730 [input_leds] [ 1274.663426] Write of size 8 at addr ffff88003377b2c0 by task ckb-next-daemon/5128 This happens because we were writing to the led structure before making sure that it exists. Reported-by: Tasos Sahanidis Tested-by: Tasos Sahanidis Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/input-leds.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/input/input-leds.c b/drivers/input/input-leds.c index 766bf2660116..5f04b2d94635 100644 --- a/drivers/input/input-leds.c +++ b/drivers/input/input-leds.c @@ -88,6 +88,7 @@ static int input_leds_connect(struct input_handler *handler, const struct input_device_id *id) { struct input_leds *leds; + struct input_led *led; unsigned int num_leds; unsigned int led_code; int led_no; @@ -119,14 +120,13 @@ static int input_leds_connect(struct input_handler *handler, led_no = 0; for_each_set_bit(led_code, dev->ledbit, LED_CNT) { - struct input_led *led = &leds->leds[led_no]; + if (!input_led_info[led_code].name) + continue; + led = &leds->leds[led_no]; led->handle = &leds->handle; led->code = led_code; - if (!input_led_info[led_code].name) - continue; - led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s", dev_name(&dev->dev), input_led_info[led_code].name); -- GitLab From c0ff32016565d4332e4012b82105918e4c28d4ea Mon Sep 17 00:00:00 2001 From: "Vittorio Gambaletta (VittGam)" Date: Wed, 25 Apr 2018 15:22:13 -0700 Subject: [PATCH 193/855] Input: atmel_mxt_ts - add touchpad button mapping for Samsung Chromebook Pro commit f372b81101e6895252298e563d634d5e44ae81e7 upstream. This patch adds the correct platform data information for the Caroline Chromebook, so that the mouse button does not get stuck in pressed state after the first click. The Samus button keymap and platform data definition are the correct ones for Caroline, so they have been reused here. Signed-off-by: Vittorio Gambaletta Signed-off-by: Salvatore Bellizzi Tested-by: Guenter Roeck Cc: stable@vger.kernel.org [dtor: adjusted vendor spelling to match shipping firmware] Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/touchscreen/atmel_mxt_ts.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index e5d185fe69b9..26132402fdf9 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -3027,6 +3027,15 @@ static const struct dmi_system_id mxt_dmi_table[] = { }, .driver_data = samus_platform_data, }, + { + /* Samsung Chromebook Pro */ + .ident = "Samsung Chromebook Pro", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Caroline"), + }, + .driver_data = samus_platform_data, + }, { /* Other Google Chromebooks */ .ident = "Chromebook", -- GitLab From b13d8f52b8e7f713196e7fc643b44a72ad3da1be Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Mon, 16 Apr 2018 23:07:45 -0700 Subject: [PATCH 194/855] xfs: prevent creating negative-sized file via INSERT_RANGE commit 7d83fb14258b9961920cd86f0b921caaeb3ebe85 upstream. During the "insert range" fallocate operation, i_size grows by the specified 'len' bytes. XFS verifies that i_size + len < s_maxbytes, as it should. But this comparison is done using the signed 'loff_t', and 'i_size + len' can wrap around to a negative value, causing the check to incorrectly pass, resulting in an inode with "negative" i_size. This is possible on 64-bit platforms, where XFS sets s_maxbytes = LLONG_MAX. ext4 and f2fs don't run into this because they set a smaller s_maxbytes. Fix it by using subtraction instead. Reproducer: xfs_io -f file -c "truncate $(((1<<63)-1))" -c "finsert 0 4096" Fixes: a904b1ca5751 ("xfs: Add support FALLOC_FL_INSERT_RANGE for fallocate") Cc: # v4.1+ Originally-From: Eric Biggers Signed-off-by: Eric Biggers Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong [darrick: fix signed integer addition overflow too] Signed-off-by: Darrick J. Wong Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_file.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 362c6b4c1186..1410835eebe2 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -846,22 +846,26 @@ xfs_file_fallocate( if (error) goto out_unlock; } else if (mode & FALLOC_FL_INSERT_RANGE) { - unsigned int blksize_mask = i_blocksize(inode) - 1; + unsigned int blksize_mask = i_blocksize(inode) - 1; + loff_t isize = i_size_read(inode); - new_size = i_size_read(inode) + len; if (offset & blksize_mask || len & blksize_mask) { error = -EINVAL; goto out_unlock; } - /* check the new inode size does not wrap through zero */ - if (new_size > inode->i_sb->s_maxbytes) { + /* + * New inode size must not exceed ->s_maxbytes, accounting for + * possible signed overflow. + */ + if (inode->i_sb->s_maxbytes - isize < len) { error = -EFBIG; goto out_unlock; } + new_size = isize + len; /* Offset should be less than i_size */ - if (offset >= i_size_read(inode)) { + if (offset >= isize) { error = -EINVAL; goto out_unlock; } -- GitLab From 1378078b7a8b1635f1bcd4f5d2843ef9770c61ae Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Mon, 23 Apr 2018 21:42:37 +0530 Subject: [PATCH 195/855] RDMA/cxgb4: release hw resources on device removal commit 26bff1bd74a4f7417509a83295614e9dab995b2a upstream. The c4iw_rdev_close() logic was not releasing all the hw resources (PBL and RQT memory) during the device removal event (driver unload / system reboot). This can cause panic in gen_pool_destroy(). The module remove function will wait for all the hw resources to be released during the device removal event. Fixes c12a67fe(iw_cxgb4: free EQ queue memory on last deref) Signed-off-by: Raju Rangoju Reviewed-by: Steve Wise Cc: stable@vger.kernel.org Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/cxgb4/device.c | 9 ++++++++- drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 4 ++++ drivers/infiniband/hw/cxgb4/resource.c | 26 ++++++++++++++++++++++++-- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index b85a1a983e07..9e0f2ccf1d10 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -856,6 +856,11 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev) rdev->status_page->db_off = 0; + init_completion(&rdev->rqt_compl); + init_completion(&rdev->pbl_compl); + kref_init(&rdev->rqt_kref); + kref_init(&rdev->pbl_kref); + return 0; err_free_status_page: free_page((unsigned long)rdev->status_page); @@ -872,12 +877,14 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev) static void c4iw_rdev_close(struct c4iw_rdev *rdev) { - destroy_workqueue(rdev->free_workq); kfree(rdev->wr_log); free_page((unsigned long)rdev->status_page); c4iw_pblpool_destroy(rdev); c4iw_rqtpool_destroy(rdev); + wait_for_completion(&rdev->pbl_compl); + wait_for_completion(&rdev->rqt_compl); c4iw_destroy_resource(&rdev->resource); + destroy_workqueue(rdev->free_workq); } static void c4iw_dealloc(struct uld_ctx *ctx) diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 7d540667dad2..896dff7a6cee 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -186,6 +186,10 @@ struct c4iw_rdev { struct wr_log_entry *wr_log; int wr_log_size; struct workqueue_struct *free_workq; + struct completion rqt_compl; + struct completion pbl_compl; + struct kref rqt_kref; + struct kref pbl_kref; }; static inline int c4iw_fatal_error(struct c4iw_rdev *rdev) diff --git a/drivers/infiniband/hw/cxgb4/resource.c b/drivers/infiniband/hw/cxgb4/resource.c index 67df71a7012e..803c677e21cd 100644 --- a/drivers/infiniband/hw/cxgb4/resource.c +++ b/drivers/infiniband/hw/cxgb4/resource.c @@ -260,12 +260,22 @@ u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size) rdev->stats.pbl.cur += roundup(size, 1 << MIN_PBL_SHIFT); if (rdev->stats.pbl.cur > rdev->stats.pbl.max) rdev->stats.pbl.max = rdev->stats.pbl.cur; + kref_get(&rdev->pbl_kref); } else rdev->stats.pbl.fail++; mutex_unlock(&rdev->stats.lock); return (u32)addr; } +static void destroy_pblpool(struct kref *kref) +{ + struct c4iw_rdev *rdev; + + rdev = container_of(kref, struct c4iw_rdev, pbl_kref); + gen_pool_destroy(rdev->pbl_pool); + complete(&rdev->pbl_compl); +} + void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size) { PDBG("%s addr 0x%x size %d\n", __func__, addr, size); @@ -273,6 +283,7 @@ void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size) rdev->stats.pbl.cur -= roundup(size, 1 << MIN_PBL_SHIFT); mutex_unlock(&rdev->stats.lock); gen_pool_free(rdev->pbl_pool, (unsigned long)addr, size); + kref_put(&rdev->pbl_kref, destroy_pblpool); } int c4iw_pblpool_create(struct c4iw_rdev *rdev) @@ -312,7 +323,7 @@ int c4iw_pblpool_create(struct c4iw_rdev *rdev) void c4iw_pblpool_destroy(struct c4iw_rdev *rdev) { - gen_pool_destroy(rdev->pbl_pool); + kref_put(&rdev->pbl_kref, destroy_pblpool); } /* @@ -333,12 +344,22 @@ u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size) rdev->stats.rqt.cur += roundup(size << 6, 1 << MIN_RQT_SHIFT); if (rdev->stats.rqt.cur > rdev->stats.rqt.max) rdev->stats.rqt.max = rdev->stats.rqt.cur; + kref_get(&rdev->rqt_kref); } else rdev->stats.rqt.fail++; mutex_unlock(&rdev->stats.lock); return (u32)addr; } +static void destroy_rqtpool(struct kref *kref) +{ + struct c4iw_rdev *rdev; + + rdev = container_of(kref, struct c4iw_rdev, rqt_kref); + gen_pool_destroy(rdev->rqt_pool); + complete(&rdev->rqt_compl); +} + void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size) { PDBG("%s addr 0x%x size %d\n", __func__, addr, size << 6); @@ -346,6 +367,7 @@ void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size) rdev->stats.rqt.cur -= roundup(size << 6, 1 << MIN_RQT_SHIFT); mutex_unlock(&rdev->stats.lock); gen_pool_free(rdev->rqt_pool, (unsigned long)addr, size << 6); + kref_put(&rdev->rqt_kref, destroy_rqtpool); } int c4iw_rqtpool_create(struct c4iw_rdev *rdev) @@ -383,7 +405,7 @@ int c4iw_rqtpool_create(struct c4iw_rdev *rdev) void c4iw_rqtpool_destroy(struct c4iw_rdev *rdev) { - gen_pool_destroy(rdev->rqt_pool); + kref_put(&rdev->rqt_kref, destroy_rqtpool); } /* -- GitLab From aa2fb1f929c5dcfdcafd1456a029874c7a2f75c5 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 19 Apr 2018 08:28:11 -0700 Subject: [PATCH 196/855] RDMA/ucma: Allow resolving address w/o specifying source address commit 09abfe7b5b2f442a85f4c4d59ecf582ad76088d7 upstream. The RDMA CM will select a source device and address by consulting the routing table if no source address is passed into rdma_resolve_address(). Userspace will ask for this by passing an all-zero source address in the RESOLVE_IP command. Unfortunately the new check for non-zero address size rejects this with EINVAL, which breaks valid userspace applications. Fix this by explicitly allowing a zero address family for the source. Fixes: 2975d5de6428 ("RDMA/ucma: Check AF family prior resolving address") Cc: Signed-off-by: Roland Dreier Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index cb79d171d1e4..f2f1c9fec0b1 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -676,7 +676,7 @@ static ssize_t ucma_resolve_ip(struct ucma_file *file, if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - if (!rdma_addr_size_in6(&cmd.src_addr) || + if ((cmd.src_addr.sin6_family && !rdma_addr_size_in6(&cmd.src_addr)) || !rdma_addr_size_in6(&cmd.dst_addr)) return -EINVAL; -- GitLab From a3fe8107c06f153d0eb87b435c7a5be477e986aa Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Mon, 23 Apr 2018 17:01:53 +0300 Subject: [PATCH 197/855] RDMA/mlx5: Protect from shift operand overflow commit 002bf2282b2d7318e444dca9ffcb994afc5d5f15 upstream. Ensure that user didn't supply values too large that can cause overflow. UBSAN: Undefined behaviour in drivers/infiniband/hw/mlx5/qp.c:263:23 shift exponent -2147483648 is negative CPU: 0 PID: 292 Comm: syzkaller612609 Not tainted 4.16.0-rc1+ #131 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.0-0-g63451fca13-prebuilt.qemu-project.org 04/01/2014 Call Trace: dump_stack+0xde/0x164 ubsan_epilogue+0xe/0x81 set_rq_size+0x7c2/0xa90 create_qp_common+0xc18/0x43c0 mlx5_ib_create_qp+0x379/0x1ca0 create_qp.isra.5+0xc94/0x2260 ib_uverbs_create_qp+0x21b/0x2a0 ib_uverbs_write+0xc2c/0x1010 vfs_write+0x1b0/0x550 SyS_write+0xc7/0x1a0 do_syscall_64+0x1aa/0x740 entry_SYSCALL_64_after_hwframe+0x26/0x9b RIP: 0033:0x433569 RSP: 002b:00007ffc6e62f448 EFLAGS: 00000217 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 00000000004002f8 RCX: 0000000000433569 RDX: 0000000000000070 RSI: 00000000200042c0 RDI: 0000000000000003 RBP: 00000000006d5018 R08: 00000000004002f8 R09: 00000000004002f8 R10: 00000000004002f8 R11: 0000000000000217 R12: 0000000000000000 R13: 000000000040c9f0 R14: 000000000040ca80 R15: 0000000000000006 Cc: # 3.10 Fixes: e126ba97dba9 ("mlx5: Add driver for Mellanox Connect-IB adapters") Cc: syzkaller Reported-by: Noa Osherovich Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/qp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 5b8909d1b55e..1d68c538d17e 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -253,7 +253,11 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap, } else { if (ucmd) { qp->rq.wqe_cnt = ucmd->rq_wqe_count; + if (ucmd->rq_wqe_shift > BITS_PER_BYTE * sizeof(ucmd->rq_wqe_shift)) + return -EINVAL; qp->rq.wqe_shift = ucmd->rq_wqe_shift; + if ((1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) < qp->wq_sig) + return -EINVAL; qp->rq.max_gs = (1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) - qp->wq_sig; qp->rq.max_post = qp->rq.wqe_cnt; } else { -- GitLab From f0b2a493973ff8da3a648d6b08bca259e78d6481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZ=20Lin=20=28=E6=9E=97=E4=B8=8A=E6=99=BA=29?= Date: Thu, 26 Apr 2018 14:30:13 +0800 Subject: [PATCH 198/855] NET: usb: qmi_wwan: add support for ublox R410M PID 0x90b2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9306b38e42cb266f98bff6f6f4c1c652aa79ba45 upstream. This patch adds support for PID 0x90b2 of ublox R410M. qmicli -d /dev/cdc-wdm0 --dms-get-manufacturer [/dev/cdc-wdm0] Device manufacturer retrieved: Manufacturer: 'u-blox' qmicli -d /dev/cdc-wdm0 --dms-get-model [/dev/cdc-wdm0] Device model retrieved: Model: 'SARA-R410M-02B' Signed-off-by: SZ Lin (林上智) Cc: stable Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 973e90fb4a24..1029bd234c22 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -803,6 +803,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x05c6, 0x9080, 8)}, {QMI_FIXED_INTF(0x05c6, 0x9083, 3)}, {QMI_FIXED_INTF(0x05c6, 0x9084, 4)}, + {QMI_FIXED_INTF(0x05c6, 0x90b2, 3)}, /* ublox R410M */ {QMI_FIXED_INTF(0x05c6, 0x920d, 0)}, {QMI_FIXED_INTF(0x05c6, 0x920d, 5)}, {QMI_QUIRK_SET_DTR(0x05c6, 0x9625, 4)}, /* YUGA CLM920-NC5 */ -- GitLab From 7508e14f327f002093918800873e723337f0ceb7 Mon Sep 17 00:00:00 2001 From: Danit Goldberg Date: Mon, 23 Apr 2018 17:01:54 +0300 Subject: [PATCH 199/855] IB/mlx5: Use unlimited rate when static rate is not supported commit 4f32ac2e452c2180cd2df581cbadac183e27ecd0 upstream. Before the change, if the user passed a static rate value different than zero and the FW doesn't support static rate, it would end up configuring rate of 2.5 GBps. Fix this by using rate 0; unlimited, in cases where FW doesn't support static rate configuration. Cc: # 3.10 Fixes: e126ba97dba9 ("mlx5: Add driver for Mellanox Connect-IB adapters") Reviewed-by: Majd Dibbiny Signed-off-by: Danit Goldberg Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/qp.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 1d68c538d17e..3cdcbfbd6a79 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -2168,18 +2168,18 @@ enum { static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate) { - if (rate == IB_RATE_PORT_CURRENT) { + if (rate == IB_RATE_PORT_CURRENT) return 0; - } else if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_300_GBPS) { + + if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_300_GBPS) return -EINVAL; - } else { - while (rate != IB_RATE_2_5_GBPS && - !(1 << (rate + MLX5_STAT_RATE_OFFSET) & - MLX5_CAP_GEN(dev->mdev, stat_rate_support))) - --rate; - } - return rate + MLX5_STAT_RATE_OFFSET; + while (rate != IB_RATE_PORT_CURRENT && + !(1 << (rate + MLX5_STAT_RATE_OFFSET) & + MLX5_CAP_GEN(dev->mdev, stat_rate_support))) + --rate; + + return rate ? rate + MLX5_STAT_RATE_OFFSET : rate; } static int modify_raw_packet_eth_prio(struct mlx5_core_dev *dev, -- GitLab From 900ed3ec5634236a48e623ad3272ba59b0b1e842 Mon Sep 17 00:00:00 2001 From: Sebastian Sanchez Date: Tue, 1 May 2018 05:35:58 -0700 Subject: [PATCH 200/855] IB/hfi1: Fix NULL pointer dereference when invalid num_vls is used commit 45d924571a5e1329580811f2419da61b07ac3613 upstream. When an invalid num_vls is used as a module parameter, the code execution follows an exception path where the macro dd_dev_err() expects dd->pcidev->dev not to be NULL in hfi1_init_dd(). This causes a NULL pointer dereference. Fix hfi1_init_dd() by initializing dd->pcidev and dd->pcidev->dev earlier in the code. If a dd exists, then dd->pcidev and dd->pcidev->dev always exists. BUG: unable to handle kernel NULL pointer dereference at 00000000000000f0 IP: __dev_printk+0x15/0x90 Workqueue: events work_for_cpu_fn RIP: 0010:__dev_printk+0x15/0x90 Call Trace: dev_err+0x6c/0x90 ? hfi1_init_pportdata+0x38d/0x3f0 [hfi1] hfi1_init_dd+0xdd/0x2530 [hfi1] ? pci_conf1_read+0xb2/0xf0 ? pci_read_config_word.part.9+0x64/0x80 ? pci_conf1_write+0xb0/0xf0 ? pcie_capability_clear_and_set_word+0x57/0x80 init_one+0x141/0x490 [hfi1] local_pci_probe+0x3f/0xa0 work_for_cpu_fn+0x10/0x20 process_one_work+0x152/0x350 worker_thread+0x1cf/0x3e0 kthread+0xf5/0x130 ? max_active_store+0x80/0x80 ? kthread_bind+0x10/0x10 ? do_syscall_64+0x6e/0x1a0 ? SyS_exit_group+0x10/0x10 ret_from_fork+0x35/0x40 Cc: # 4.9.x Reviewed-by: Mike Marciniszyn Reviewed-by: Michael J. Ruhl Signed-off-by: Sebastian Sanchez Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/hfi1/init.c | 2 ++ drivers/infiniband/hw/hfi1/pcie.c | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index 84a97f3f9299..ae1f90ddd4e8 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -1049,6 +1049,8 @@ struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra) return ERR_PTR(-ENOMEM); dd->num_pports = nports; dd->pport = (struct hfi1_pportdata *)(dd + 1); + dd->pcidev = pdev; + pci_set_drvdata(pdev, dd); INIT_LIST_HEAD(&dd->list); idr_preload(GFP_KERNEL); diff --git a/drivers/infiniband/hw/hfi1/pcie.c b/drivers/infiniband/hw/hfi1/pcie.c index 335613a1a46a..717626046ee5 100644 --- a/drivers/infiniband/hw/hfi1/pcie.c +++ b/drivers/infiniband/hw/hfi1/pcie.c @@ -162,9 +162,6 @@ int hfi1_pcie_ddinit(struct hfi1_devdata *dd, struct pci_dev *pdev) unsigned long len; resource_size_t addr; - dd->pcidev = pdev; - pci_set_drvdata(pdev, dd); - addr = pci_resource_start(pdev, 0); len = pci_resource_len(pdev, 0); -- GitLab From 32c6a543d8a58cb4df06e103dae241d848263938 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 26 Apr 2018 09:59:30 +0200 Subject: [PATCH 201/855] drm/vmwgfx: Fix a buffer object leak commit 13f149d47392782baafd96d54d4e65f3b5ca342f upstream. A buffer object leak was introduced when fixing a premature buffer object release. Fix this. Cc: Fixes: 73a88250b709 ("Fix a destoy-while-held mutex problem.") Signed-off-by: Thomas Hellstrom Reviewed-by: Deepak Rawat Reviewed-by: Sinclair Yeh Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 87086af42114..33ca24ab983e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2014,6 +2014,7 @@ void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx, vmw_kms_helper_buffer_finish(res->dev_priv, NULL, ctx->buf, out_fence, NULL); + vmw_dmabuf_unreference(&ctx->buf); vmw_resource_unreserve(res, false, NULL, 0); mutex_unlock(&res->dev_priv->cmdbuf_mutex); } -- GitLab From ccd174692f70da88ef5dac8292ccd3271b08643a Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Fri, 20 Apr 2018 14:59:59 -0400 Subject: [PATCH 202/855] drm/bridge: vga-dac: Fix edid memory leak commit 49ceda9de2da4d1827941d06701f3017c27c1855 upstream. edid should be freed once it's finished being used. Fixes: 56fe8b6f4991 ("drm/bridge: Add RGB to VGA bridge support") Cc: Rob Herring Cc: Sean Paul Cc: Maxime Ripard Cc: Archit Taneja Cc: Andrzej Hajda Cc: Laurent Pinchart Cc: # v4.9+ Reviewed-by: Maxime Ripard Reviewed-by: Laurent Pinchart Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20180420190007.1572-1-seanpaul@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/bridge/dumb-vga-dac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index afec232185a7..cfd80bc510b6 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -53,7 +53,9 @@ static int dumb_vga_get_modes(struct drm_connector *connector) } drm_mode_connector_update_edid_property(connector, edid); - return drm_add_edid_modes(connector, edid); + ret = drm_add_edid_modes(connector, edid); + kfree(edid); + return ret; fallback: /* -- GitLab From b70f9d27eab5c23e668350927a358621071bc415 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 4 Apr 2018 22:38:49 +0200 Subject: [PATCH 203/855] test_firmware: fix setting old custom fw path back on exit, second try commit e538409257d0217a9bc715686100a5328db75a15 upstream. Commit 65c79230576 tried to clear the custom firmware path on exit by writing a single space to the firmware_class.path parameter. This doesn't work because nothing strips this space from the value stored and fw_get_filesystem_firmware() only ignores zero-length paths. Instead, write a null byte. Fixes: 0a8adf58475 ("test: add firmware_class loader test") Fixes: 65c79230576 ("test_firmware: fix setting old custom fw path back on exit") Signed-off-by: Ben Hutchings Acked-by: Luis R. Rodriguez Cc: stable Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/firmware/fw_filesystem.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh index 17e16fcaa0cc..99d7f13a5637 100755 --- a/tools/testing/selftests/firmware/fw_filesystem.sh +++ b/tools/testing/selftests/firmware/fw_filesystem.sh @@ -29,9 +29,11 @@ test_finish() echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout fi if [ "$OLD_FWPATH" = "" ]; then - OLD_FWPATH=" " + # A zero-length write won't work; write a null byte + printf '\000' >/sys/module/firmware_class/parameters/path + else + echo -n "$OLD_FWPATH" >/sys/module/firmware_class/parameters/path fi - echo -n "$OLD_FWPATH" >/sys/module/firmware_class/parameters/path rm -f "$FW" rmdir "$FWPATH" } -- GitLab From ddb6f5228e6132c706719561cebf4347b930dbb5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 29 Apr 2018 17:41:55 +0200 Subject: [PATCH 204/855] USB: serial: visor: handle potential invalid device configuration commit 4842ed5bfcb9daf6660537d70503c18d38dbdbb8 upstream. If we get an invalid device configuration from a palm 3 type device, we might incorrectly parse things, and we have the potential to crash in "interesting" ways. Fix this up by verifying the size of the configuration passed to us by the device, and only if it is correct, will we handle it. Note that this also fixes an information leak of slab data. Reported-by: Andrey Konovalov Reviewed-by: Andrey Konovalov Signed-off-by: Greg Kroah-Hartman [ johan: add comment about the info leak ] Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/visor.c | 69 +++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 337a0be89fcf..dbc3801b43eb 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -338,47 +338,48 @@ static int palm_os_3_probe(struct usb_serial *serial, goto exit; } - if (retval == sizeof(*connection_info)) { - connection_info = (struct visor_connection_info *) - transfer_buffer; - - num_ports = le16_to_cpu(connection_info->num_ports); - for (i = 0; i < num_ports; ++i) { - switch ( - connection_info->connections[i].port_function_id) { - case VISOR_FUNCTION_GENERIC: - string = "Generic"; - break; - case VISOR_FUNCTION_DEBUGGER: - string = "Debugger"; - break; - case VISOR_FUNCTION_HOTSYNC: - string = "HotSync"; - break; - case VISOR_FUNCTION_CONSOLE: - string = "Console"; - break; - case VISOR_FUNCTION_REMOTE_FILE_SYS: - string = "Remote File System"; - break; - default: - string = "unknown"; - break; - } - dev_info(dev, "%s: port %d, is for %s use\n", - serial->type->description, - connection_info->connections[i].port, string); - } + if (retval != sizeof(*connection_info)) { + dev_err(dev, "Invalid connection information received from device\n"); + retval = -ENODEV; + goto exit; } - /* - * Handle devices that report invalid stuff here. - */ + + connection_info = (struct visor_connection_info *)transfer_buffer; + + num_ports = le16_to_cpu(connection_info->num_ports); + + /* Handle devices that report invalid stuff here. */ if (num_ports == 0 || num_ports > 2) { dev_warn(dev, "%s: No valid connect info available\n", serial->type->description); num_ports = 2; } + for (i = 0; i < num_ports; ++i) { + switch (connection_info->connections[i].port_function_id) { + case VISOR_FUNCTION_GENERIC: + string = "Generic"; + break; + case VISOR_FUNCTION_DEBUGGER: + string = "Debugger"; + break; + case VISOR_FUNCTION_HOTSYNC: + string = "HotSync"; + break; + case VISOR_FUNCTION_CONSOLE: + string = "Console"; + break; + case VISOR_FUNCTION_REMOTE_FILE_SYS: + string = "Remote File System"; + break; + default: + string = "unknown"; + break; + } + dev_info(dev, "%s: port %d, is for %s use\n", + serial->type->description, + connection_info->connections[i].port, string); + } dev_info(dev, "%s: Number of ports: %d\n", serial->type->description, num_ports); -- GitLab From 1fac4fc6708edbad9c1a98d69958f828eb96144c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 3 May 2018 11:04:48 -0400 Subject: [PATCH 205/855] USB: Accept bulk endpoints with 1024-byte maxpacket commit fb5ee84ea72c5f1b6cabdd1c9d6e8648995ca7c6 upstream. Some non-compliant high-speed USB devices have bulk endpoints with a 1024-byte maxpacket size. Although such endpoints don't work with xHCI host controllers, they do work with EHCI controllers. We used to accept these invalid sizes (with a warning), but we no longer do because of an unintentional change introduced by commit aed9d65ac327 ("USB: validate wMaxPacketValue entries in endpoint descriptors"). This patch restores the old behavior, so that people with these peculiar devices can use them without patching their kernels by hand. Signed-off-by: Alan Stern Suggested-by: Elvinas Fixes: aed9d65ac327 ("USB: validate wMaxPacketValue entries in endpoint descriptors") CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 7c54a19b20e0..5e6136d2ed71 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -186,7 +186,9 @@ static const unsigned short full_speed_maxpacket_maxes[4] = { static const unsigned short high_speed_maxpacket_maxes[4] = { [USB_ENDPOINT_XFER_CONTROL] = 64, [USB_ENDPOINT_XFER_ISOC] = 1024, - [USB_ENDPOINT_XFER_BULK] = 512, + + /* Bulk should be 512, but some devices use 1024: we will warn below */ + [USB_ENDPOINT_XFER_BULK] = 1024, [USB_ENDPOINT_XFER_INT] = 1024, }; static const unsigned short super_speed_maxpacket_maxes[4] = { -- GitLab From 12b49756296bec11b319fd0e973036a4c5481dc5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Mar 2018 17:40:48 +0100 Subject: [PATCH 206/855] USB: serial: option: reimplement interface masking commit c3a65808f04a8426481b63a4fbd9392f009f6330 upstream. Reimplement interface masking using device flags stored directly in the device-id table. This will make it easier to add and maintain device-id entries by using a more compact and readable notation compared to the current implementation (which manages pairs of masks in separate blacklist structs). Two convenience macros are used to flag an interface as either reserved or as not supporting modem-control requests: { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), .driver_info = NCTRL(0) | RSVD(3) }, For now, we limit the highest maskable interface number to seven, which allows for (up to 16) additional device flags to be added later should need arise. Note that this will likely need to be backported to stable in order to make future device-id backports more manageable. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 446 ++++++++++++------------------------ 1 file changed, 152 insertions(+), 294 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index a1cb1ea41282..5ea92c9990c5 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -551,151 +551,15 @@ static void option_instat_callback(struct urb *urb); #define WETELECOM_PRODUCT_6802 0x6802 #define WETELECOM_PRODUCT_WMD300 0x6803 -struct option_blacklist_info { - /* bitmask of interface numbers blacklisted for send_setup */ - const unsigned long sendsetup; - /* bitmask of interface numbers that are reserved */ - const unsigned long reserved; -}; -static const struct option_blacklist_info four_g_w14_blacklist = { - .sendsetup = BIT(0) | BIT(1), -}; +/* Device flags */ -static const struct option_blacklist_info four_g_w100_blacklist = { - .sendsetup = BIT(1) | BIT(2), - .reserved = BIT(3), -}; +/* Interface does not support modem-control requests */ +#define NCTRL(ifnum) ((BIT(ifnum) & 0xff) << 8) -static const struct option_blacklist_info alcatel_x200_blacklist = { - .sendsetup = BIT(0) | BIT(1), - .reserved = BIT(4), -}; +/* Interface is reserved */ +#define RSVD(ifnum) ((BIT(ifnum) & 0xff) << 0) -static const struct option_blacklist_info zte_0037_blacklist = { - .sendsetup = BIT(0) | BIT(1), -}; - -static const struct option_blacklist_info zte_k3765_z_blacklist = { - .sendsetup = BIT(0) | BIT(1) | BIT(2), - .reserved = BIT(4), -}; - -static const struct option_blacklist_info zte_ad3812_z_blacklist = { - .sendsetup = BIT(0) | BIT(1) | BIT(2), -}; - -static const struct option_blacklist_info zte_mc2718_z_blacklist = { - .sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4), -}; - -static const struct option_blacklist_info zte_mc2716_z_blacklist = { - .sendsetup = BIT(1) | BIT(2) | BIT(3), -}; - -static const struct option_blacklist_info zte_me3620_mbim_blacklist = { - .reserved = BIT(2) | BIT(3) | BIT(4), -}; - -static const struct option_blacklist_info zte_me3620_xl_blacklist = { - .reserved = BIT(3) | BIT(4) | BIT(5), -}; - -static const struct option_blacklist_info zte_zm8620_x_blacklist = { - .reserved = BIT(3) | BIT(4) | BIT(5), -}; - -static const struct option_blacklist_info huawei_cdc12_blacklist = { - .reserved = BIT(1) | BIT(2), -}; - -static const struct option_blacklist_info net_intf0_blacklist = { - .reserved = BIT(0), -}; - -static const struct option_blacklist_info net_intf1_blacklist = { - .reserved = BIT(1), -}; - -static const struct option_blacklist_info net_intf2_blacklist = { - .reserved = BIT(2), -}; - -static const struct option_blacklist_info net_intf3_blacklist = { - .reserved = BIT(3), -}; - -static const struct option_blacklist_info net_intf4_blacklist = { - .reserved = BIT(4), -}; - -static const struct option_blacklist_info net_intf5_blacklist = { - .reserved = BIT(5), -}; - -static const struct option_blacklist_info net_intf6_blacklist = { - .reserved = BIT(6), -}; - -static const struct option_blacklist_info zte_mf626_blacklist = { - .sendsetup = BIT(0) | BIT(1), - .reserved = BIT(4), -}; - -static const struct option_blacklist_info zte_1255_blacklist = { - .reserved = BIT(3) | BIT(4), -}; - -static const struct option_blacklist_info simcom_sim7100e_blacklist = { - .reserved = BIT(5) | BIT(6), -}; - -static const struct option_blacklist_info telit_me910_blacklist = { - .sendsetup = BIT(0), - .reserved = BIT(1) | BIT(3), -}; - -static const struct option_blacklist_info telit_me910_dual_modem_blacklist = { - .sendsetup = BIT(0), - .reserved = BIT(3), -}; - -static const struct option_blacklist_info telit_le910_blacklist = { - .sendsetup = BIT(0), - .reserved = BIT(1) | BIT(2), -}; - -static const struct option_blacklist_info telit_le920_blacklist = { - .sendsetup = BIT(0), - .reserved = BIT(1) | BIT(5), -}; - -static const struct option_blacklist_info telit_le920a4_blacklist_1 = { - .sendsetup = BIT(0), - .reserved = BIT(1), -}; - -static const struct option_blacklist_info telit_le922_blacklist_usbcfg0 = { - .sendsetup = BIT(2), - .reserved = BIT(0) | BIT(1) | BIT(3), -}; - -static const struct option_blacklist_info telit_le922_blacklist_usbcfg3 = { - .sendsetup = BIT(0), - .reserved = BIT(1) | BIT(2) | BIT(3), -}; - -static const struct option_blacklist_info cinterion_rmnet2_blacklist = { - .reserved = BIT(4) | BIT(5), -}; - -static const struct option_blacklist_info yuga_clm920_nc5_blacklist = { - .reserved = BIT(1) | BIT(4), -}; - -static const struct option_blacklist_info quectel_ep06_blacklist = { - .reserved = BIT(4) | BIT(5), -}; static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, @@ -729,26 +593,26 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) }, { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, { USB_DEVICE(QUANTA_VENDOR_ID, 0xea42), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, USB_CLASS_COMM, 0x02, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c1f, USB_CLASS_COMM, 0x02, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t) &net_intf1_blacklist }, + .driver_info = RSVD(1) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S6, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t) &net_intf1_blacklist }, + .driver_info = RSVD(1) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1750, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t) &net_intf2_blacklist }, + .driver_info = RSVD(2) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1441, USB_CLASS_COMM, 0x02, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1442, USB_CLASS_COMM, 0x02, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, + .driver_info = RSVD(1) | RSVD(2) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, + .driver_info = RSVD(1) | RSVD(2) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x14ac, 0xff, 0xff, 0xff), /* Huawei E1820 */ - .driver_info = (kernel_ulong_t) &net_intf1_blacklist }, + .driver_info = RSVD(1) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, + .driver_info = RSVD(1) | RSVD(2) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0xff, 0xff) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x01) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x02) }, @@ -1193,67 +1057,67 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */ { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, 0x6001, 0xff, 0xff, 0xff), /* 4G LTE usb-modem U901 */ - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + .driver_info = RSVD(3) }, { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ /* Quectel products using Qualcomm vendor ID */ { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)}, { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, /* Yuga products use Qualcomm vendor ID */ { USB_DEVICE(QUALCOMM_VENDOR_ID, YUGA_PRODUCT_CLM920_NC5), - .driver_info = (kernel_ulong_t)&yuga_clm920_nc5_blacklist }, + .driver_info = RSVD(1) | RSVD(4) }, /* Quectel products using Quectel vendor ID */ { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC21), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC25), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06), - .driver_info = (kernel_ulong_t)&quectel_ep06_blacklist }, + .driver_info = RSVD(4) | RSVD(5) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003), - .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + .driver_info = RSVD(0) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6004) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6005) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_628A) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHE_628S), - .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + .driver_info = RSVD(0) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_301), - .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + .driver_info = RSVD(0) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628), - .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + .driver_info = RSVD(0) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628S) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_680) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_685A) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720S), - .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + .driver_info = RSVD(0) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7002), - .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + .driver_info = RSVD(0) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629K), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7004), - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + .driver_info = RSVD(3) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7005) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_629), - .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + .driver_info = RSVD(5) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629S), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720I), - .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + .driver_info = RSVD(0) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7212), - .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + .driver_info = RSVD(0) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7213), - .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, + .driver_info = RSVD(0) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7251), - .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + .driver_info = RSVD(1) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7252), - .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + .driver_info = RSVD(1) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7253), - .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + .driver_info = RSVD(1) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) }, @@ -1261,38 +1125,38 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0), - .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 }, + .driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG1), - .driver_info = (kernel_ulong_t)&telit_le910_blacklist }, + .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG2), - .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 }, + .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG3), - .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 }, + .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff), - .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 }, + .driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910), - .driver_info = (kernel_ulong_t)&telit_me910_blacklist }, + .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), - .driver_info = (kernel_ulong_t)&telit_me910_dual_modem_blacklist }, + .driver_info = NCTRL(0) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), - .driver_info = (kernel_ulong_t)&telit_le910_blacklist }, + .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4), - .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 }, + .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920), - .driver_info = (kernel_ulong_t)&telit_le920_blacklist }, + .driver_info = NCTRL(0) | RSVD(1) | RSVD(5) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1207) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1208), - .driver_info = (kernel_ulong_t)&telit_le920a4_blacklist_1 }, + .driver_info = NCTRL(0) | RSVD(1) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1211), - .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 }, + .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1212), - .driver_info = (kernel_ulong_t)&telit_le920a4_blacklist_1 }, + .driver_info = NCTRL(0) | RSVD(1) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1213, 0xff) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1214), - .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 }, + .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + .driver_info = RSVD(1) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) }, @@ -1308,58 +1172,58 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0010, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0011, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + .driver_info = RSVD(1) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0013, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0016, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + .driver_info = RSVD(3) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + .driver_info = RSVD(3) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0022, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0023, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0024, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + .driver_info = RSVD(1) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0028, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0029, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0030, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff, - 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_mf626_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff, 0xff, 0xff), + .driver_info = NCTRL(0) | NCTRL(1) | RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0032, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0033, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0034, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&zte_0037_blacklist }, + .driver_info = NCTRL(0) | NCTRL(1) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0038, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0039, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0040, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0043, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0044, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0048, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + .driver_info = RSVD(5) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0050, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0051, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0054, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + .driver_info = RSVD(1) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0056, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0057, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0061, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0062, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0064, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0065, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0066, 0xff, 0xff, 0xff) }, @@ -1384,26 +1248,26 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0096, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0097, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0105, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0106, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0108, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + .driver_info = RSVD(5) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0117, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0118, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + .driver_info = RSVD(5) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0121, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + .driver_info = RSVD(5) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0122, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0123, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0124, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + .driver_info = RSVD(5) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0125, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + .driver_info = RSVD(6) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0126, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + .driver_info = RSVD(5) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0128, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0135, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0136, 0xff, 0xff, 0xff) }, @@ -1419,50 +1283,50 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + .driver_info = RSVD(5) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + .driver_info = RSVD(3) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0159, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0164, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0189, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0191, 0xff, 0xff, 0xff), /* ZTE EuFi890 */ - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0196, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0197, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0199, 0xff, 0xff, 0xff), /* ZTE MF820S */ - .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + .driver_info = RSVD(1) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0200, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0201, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0254, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0257, 0xff, 0xff, 0xff), /* ZTE MF821 */ - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + .driver_info = RSVD(3) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff), /* ONDA MT8205 */ - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff), /* ZTE MF880 */ - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0317, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0330, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0395, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0412, 0xff, 0xff, 0xff), /* Telewell TW-LTE 4G */ - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0414, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0417, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1018, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1021, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + .driver_info = RSVD(2) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) }, @@ -1579,23 +1443,23 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1170, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1244, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1245, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1246, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1247, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1248, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1249, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1250, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1251, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1252, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1253, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1254, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1255, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&zte_1255_blacklist }, + .driver_info = RSVD(3) | RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1256, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1257, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1258, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1259, 0xff, 0xff, 0xff) }, @@ -1610,7 +1474,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1268, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1269, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + .driver_info = RSVD(5) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1271, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) }, @@ -1646,17 +1510,17 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1303, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1333, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1401, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + .driver_info = RSVD(2) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + .driver_info = RSVD(2) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1424, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + .driver_info = RSVD(2) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1425, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + .driver_info = RSVD(2) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1426, 0xff, 0xff, 0xff), /* ZTE MF91 */ - .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + .driver_info = RSVD(2) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1428, 0xff, 0xff, 0xff), /* Telewell TW-LTE 4G v2 */ - .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + .driver_info = RSVD(2) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1533, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1534, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1535, 0xff, 0xff, 0xff) }, @@ -1674,8 +1538,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1596, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1598, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1600, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, - 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff), + .driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) | RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */ @@ -1686,20 +1550,20 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0094, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, + .driver_info = RSVD(1) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0133, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + .driver_info = RSVD(3) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + .driver_info = RSVD(5) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0147, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0168, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0170, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0176, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + .driver_info = RSVD(3) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + .driver_info = RSVD(3) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff42, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff43, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff44, 0xff, 0xff, 0xff) }, @@ -1851,19 +1715,19 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&zte_mc2718_z_blacklist }, + .driver_info = NCTRL(1) | NCTRL(2) | NCTRL(3) | NCTRL(4) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AD3812, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist }, + .driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist }, + .driver_info = NCTRL(1) | NCTRL(2) | NCTRL(3) }, { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_L), - .driver_info = (kernel_ulong_t)&zte_me3620_xl_blacklist }, + .driver_info = RSVD(3) | RSVD(4) | RSVD(5) }, { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_MBIM), - .driver_info = (kernel_ulong_t)&zte_me3620_mbim_blacklist }, + .driver_info = RSVD(2) | RSVD(3) | RSVD(4) }, { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_X), - .driver_info = (kernel_ulong_t)&zte_me3620_xl_blacklist }, + .driver_info = RSVD(3) | RSVD(4) | RSVD(5) }, { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ZM8620_X), - .driver_info = (kernel_ulong_t)&zte_zm8620_x_blacklist }, + .driver_info = RSVD(3) | RSVD(4) | RSVD(5) }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) }, @@ -1883,37 +1747,34 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(ALINK_VENDOR_ID, ALINK_PRODUCT_PH300) }, { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, { USB_DEVICE(ALINK_VENDOR_ID, SIMCOM_PRODUCT_SIM7100E), - .driver_info = (kernel_ulong_t)&simcom_sim7100e_blacklist }, + .driver_info = RSVD(5) | RSVD(6) }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200), - .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist - }, + .driver_info = NCTRL(0) | NCTRL(1) | RSVD(4) }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D), - .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + .driver_info = RSVD(6) }, { USB_DEVICE(ALCATEL_VENDOR_ID, 0x0052), - .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + .driver_info = RSVD(6) }, { USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b6), - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + .driver_info = RSVD(3) }, { USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b7), - .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, + .driver_info = RSVD(5) }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L100V), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L800MA), - .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, + .driver_info = RSVD(2) }, { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) }, { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14), - .driver_info = (kernel_ulong_t)&four_g_w14_blacklist - }, + .driver_info = NCTRL(0) | NCTRL(1) }, { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W100), - .driver_info = (kernel_ulong_t)&four_g_w100_blacklist - }, + .driver_info = NCTRL(1) | NCTRL(2) | RSVD(3) }, {USB_DEVICE(LONGCHEER_VENDOR_ID, FUJISOFT_PRODUCT_FS040U), - .driver_info = (kernel_ulong_t)&net_intf3_blacklist}, + .driver_info = RSVD(3)}, { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) }, { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, 0x9801, 0xff), - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + .driver_info = RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, 0x9803, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) }, { USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) }, { USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) }, @@ -1939,14 +1800,14 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX, 0xff) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_2RMNET, 0xff), - .driver_info = (kernel_ulong_t)&cinterion_rmnet2_blacklist }, + .driver_info = RSVD(4) | RSVD(5) }, { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_AUDIO, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_2RMNET, 0xff) }, { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_AUDIO, 0xff) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, @@ -1956,20 +1817,20 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */ { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD120), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD140), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) }, { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD155), - .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + .driver_info = RSVD(6) }, { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200), - .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + .driver_info = RSVD(6) }, { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD160), - .driver_info = (kernel_ulong_t)&net_intf6_blacklist }, + .driver_info = RSVD(6) }, { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD500), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) }, @@ -2046,9 +1907,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600E) }, { USB_DEVICE_AND_INTERFACE_INFO(TPLINK_VENDOR_ID, TPLINK_PRODUCT_LTE, 0xff, 0x00, 0x00) }, /* TP-Link LTE Module */ { USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE(TPLINK_VENDOR_ID, 0x9000), /* TP-Link MA260 */ - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) }, { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x02, 0x01) }, /* D-Link DWM-156 (variant) */ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x00, 0x00) }, /* D-Link DWM-156 (variant) */ @@ -2059,9 +1920,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d04, 0xff) }, /* D-Link DWM-158 */ { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d0e, 0xff) }, /* D-Link DWM-157 C1 */ { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e19, 0xff), /* D-Link DWM-221 B1 */ - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e35, 0xff), /* D-Link DWM-222 */ - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + .driver_info = RSVD(4) }, { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/A3 */ @@ -2121,7 +1982,7 @@ static int option_probe(struct usb_serial *serial, struct usb_interface_descriptor *iface_desc = &serial->interface->cur_altsetting->desc; struct usb_device_descriptor *dev_desc = &serial->dev->descriptor; - const struct option_blacklist_info *blacklist; + unsigned long device_flags = id->driver_info; /* Never bind to the CD-Rom emulation interface */ if (iface_desc->bInterfaceClass == 0x08) @@ -2132,9 +1993,7 @@ static int option_probe(struct usb_serial *serial, * the same class/subclass/protocol as the serial interfaces. Look at * the Windows driver .INF files for reserved interface numbers. */ - blacklist = (void *)id->driver_info; - if (blacklist && test_bit(iface_desc->bInterfaceNumber, - &blacklist->reserved)) + if (device_flags & RSVD(iface_desc->bInterfaceNumber)) return -ENODEV; /* * Don't bind network interface on Samsung GT-B3730, it is handled by @@ -2145,8 +2004,8 @@ static int option_probe(struct usb_serial *serial, iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA) return -ENODEV; - /* Store the blacklist info so we can use it during attach. */ - usb_set_serial_data(serial, (void *)blacklist); + /* Store the device flags so we can use them during attach. */ + usb_set_serial_data(serial, (void *)device_flags); return 0; } @@ -2154,22 +2013,21 @@ static int option_probe(struct usb_serial *serial, static int option_attach(struct usb_serial *serial) { struct usb_interface_descriptor *iface_desc; - const struct option_blacklist_info *blacklist; struct usb_wwan_intf_private *data; + unsigned long device_flags; data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); if (!data) return -ENOMEM; - /* Retrieve blacklist info stored at probe. */ - blacklist = usb_get_serial_data(serial); + /* Retrieve device flags stored at probe. */ + device_flags = (unsigned long)usb_get_serial_data(serial); iface_desc = &serial->interface->cur_altsetting->desc; - if (!blacklist || !test_bit(iface_desc->bInterfaceNumber, - &blacklist->sendsetup)) { + if (!(device_flags & NCTRL(iface_desc->bInterfaceNumber))) data->use_send_setup = 1; - } + spin_lock_init(&data->susp_lock); usb_set_serial_data(serial, data); -- GitLab From 78456009fddfe7c762497aa1370c7fbf32d03e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZ=20Lin=20=28=E6=9E=97=E4=B8=8A=E6=99=BA=29?= Date: Thu, 26 Apr 2018 14:28:31 +0800 Subject: [PATCH 207/855] USB: serial: option: adding support for ublox R410M MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4205cb01f6e9ef2ae6daa7be4e8ac1edeb4c9d64 upstream. This patch adds support for ublox R410M PID 0x90b2 USB modem to option driver, this module supports LTE Cat M1 / NB1. Interface layout: 0: QCDM/DIAG 1: ADB 2: AT 3: RMNET Signed-off-by: SZ Lin (林上智) Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5ea92c9990c5..d982c455e18e 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -236,6 +236,8 @@ static void option_instat_callback(struct urb *urb); /* These Quectel products use Qualcomm's vendor ID */ #define QUECTEL_PRODUCT_UC20 0x9003 #define QUECTEL_PRODUCT_UC15 0x9090 +/* These u-blox products use Qualcomm's vendor ID */ +#define UBLOX_PRODUCT_R410M 0x90b2 /* These Yuga products use Qualcomm's vendor ID */ #define YUGA_PRODUCT_CLM920_NC5 0x9625 @@ -1068,6 +1070,9 @@ static const struct usb_device_id option_ids[] = { /* Yuga products use Qualcomm vendor ID */ { USB_DEVICE(QUALCOMM_VENDOR_ID, YUGA_PRODUCT_CLM920_NC5), .driver_info = RSVD(1) | RSVD(4) }, + /* u-blox products using Qualcomm vendor ID */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, UBLOX_PRODUCT_R410M), + .driver_info = RSVD(1) | RSVD(3) }, /* Quectel products using Quectel vendor ID */ { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC21), .driver_info = RSVD(4) }, -- GitLab From 9f3ac2e8dfc7f2b3eb6103da6711f2b0e6d1d58b Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Mon, 30 Apr 2018 11:20:53 -0500 Subject: [PATCH 208/855] usb: musb: host: fix potential NULL pointer dereference commit 2b63f1329df2cd814c1f8353fae4853ace6521d1 upstream. musb_start_urb() doesn't check the pass-in parameter if it is NULL. But in musb_bulk_nak_timeout() the parameter passed to musb_start_urb() is returned from first_qh(), which could be NULL. So wrap the musb_start_urb() call here with a if condition check to avoid the potential NULL pointer dereference. Fixes: f283862f3b5c ("usb: musb: NAK timeout scheme on bulk TX endpoint") Cc: stable@vger.kernel.org # v3.7+ Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_host.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 43033895e8f6..e2bc91585b4f 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1023,7 +1023,9 @@ static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep, /* set tx_reinit and schedule the next qh */ ep->tx_reinit = 1; } - musb_start_urb(musb, is_in, next_qh); + + if (next_qh) + musb_start_urb(musb, is_in, next_qh); } } -- GitLab From 097100202847a16cefc55675486b14250fbb894b Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Mon, 30 Apr 2018 11:20:54 -0500 Subject: [PATCH 209/855] usb: musb: trace: fix NULL pointer dereference in musb_g_tx() commit 9aea9b6cc78d2b99b23d84fb2e0bc6e464c6569e upstream. The usb_request pointer could be NULL in musb_g_tx(), where the tracepoint call would trigger the NULL pointer dereference failure when parsing the members of the usb_request pointer. Move the tracepoint call to where the usb_request pointer is already checked to solve the issue. Fixes: fc78003e5345 ("usb: musb: gadget: add usb-request tracepoints") Cc: stable@vger.kernel.org # v4.8+ Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_gadget.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index a55173c9e564..f1219f6d58a9 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -442,7 +442,6 @@ void musb_g_tx(struct musb *musb, u8 epnum) req = next_request(musb_ep); request = &req->request; - trace_musb_req_tx(req); csr = musb_readw(epio, MUSB_TXCSR); musb_dbg(musb, "<== %s, txcsr %04x", musb_ep->end_point.name, csr); @@ -481,6 +480,8 @@ void musb_g_tx(struct musb *musb, u8 epnum) u8 is_dma = 0; bool short_packet = false; + trace_musb_req_tx(req); + if (dma && (csr & MUSB_TXCSR_DMAENAB)) { is_dma = 1; csr |= MUSB_TXCSR_P_WZC_BITS; -- GitLab From a801ff4d8e4e84f8922694ece01193b17fe053bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Rechi=20Vita?= Date: Thu, 19 Apr 2018 07:04:34 -0700 Subject: [PATCH 210/855] platform/x86: asus-wireless: Fix NULL pointer dereference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9f0a93de9139c2b0a59299cd36b61564522458f8 upstream. When the module is removed the led workqueue is destroyed in the remove callback, before the led device is unregistered from the led subsystem. This leads to a NULL pointer derefence when the led device is unregistered automatically later as part of the module removal cleanup. Bellow is the backtrace showing the problem. BUG: unable to handle kernel NULL pointer dereference at (null) IP: __queue_work+0x8c/0x410 PGD 0 P4D 0 Oops: 0000 [#1] SMP NOPTI Modules linked in: ccm edac_mce_amd kvm_amd kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcbc aesni_intel aes_x86_64 joydev crypto_simd asus_nb_wmi glue_helper uvcvideo snd_hda_codec_conexant snd_hda_codec_generic snd_hda_codec_hdmi snd_hda_intel asus_wmi snd_hda_codec cryptd snd_hda_core sparse_keymap videobuf2_vmalloc arc4 videobuf2_memops snd_hwdep input_leds videobuf2_v4l2 ath9k psmouse videobuf2_core videodev ath9k_common snd_pcm ath9k_hw media fam15h_power ath k10temp snd_timer mac80211 i2c_piix4 r8169 mii mac_hid cfg80211 asus_wireless(-) snd soundcore wmi shpchp 8250_dw ip_tables x_tables amdkfd amd_iommu_v2 amdgpu radeon chash i2c_algo_bit drm_kms_helper syscopyarea serio_raw sysfillrect sysimgblt fb_sys_fops ahci ttm libahci drm video CPU: 3 PID: 2177 Comm: rmmod Not tainted 4.15.0-5-generic #6+dev94.b4287e5bem1-Endless Hardware name: ASUSTeK COMPUTER INC. X555DG/X555DG, BIOS 5.011 05/05/2015 RIP: 0010:__queue_work+0x8c/0x410 RSP: 0018:ffffbe8cc249fcd8 EFLAGS: 00010086 RAX: ffff992ac6810800 RBX: 0000000000000000 RCX: 0000000000000008 RDX: 0000000000000000 RSI: 0000000000000008 RDI: ffff992ac6400e18 RBP: ffffbe8cc249fd18 R08: ffff992ac6400db0 R09: 0000000000000000 R10: 0000000000000040 R11: ffff992ac6400dd8 R12: 0000000000002000 R13: ffff992abd762e00 R14: ffff992abd763e38 R15: 000000000001ebe0 FS: 00007f318203e700(0000) GS:ffff992aced80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000001c720e000 CR4: 00000000001406e0 Call Trace: queue_work_on+0x38/0x40 led_state_set+0x2c/0x40 [asus_wireless] led_set_brightness_nopm+0x14/0x40 led_set_brightness+0x37/0x60 led_trigger_set+0xfc/0x1d0 led_classdev_unregister+0x32/0xd0 devm_led_classdev_release+0x11/0x20 release_nodes+0x109/0x1f0 devres_release_all+0x3c/0x50 device_release_driver_internal+0x16d/0x220 driver_detach+0x3f/0x80 bus_remove_driver+0x55/0xd0 driver_unregister+0x2c/0x40 acpi_bus_unregister_driver+0x15/0x20 asus_wireless_driver_exit+0x10/0xb7c [asus_wireless] SyS_delete_module+0x1da/0x2b0 entry_SYSCALL_64_fastpath+0x24/0x87 RIP: 0033:0x7f3181b65fd7 RSP: 002b:00007ffe74bcbe18 EFLAGS: 00000206 ORIG_RAX: 00000000000000b0 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f3181b65fd7 RDX: 000000000000000a RSI: 0000000000000800 RDI: 0000555ea2559258 RBP: 0000555ea25591f0 R08: 00007ffe74bcad91 R09: 000000000000000a R10: 0000000000000000 R11: 0000000000000206 R12: 0000000000000003 R13: 00007ffe74bcae00 R14: 0000000000000000 R15: 0000555ea25591f0 Code: 01 00 00 02 0f 85 7d 01 00 00 48 63 45 d4 48 c7 c6 00 f4 fa 87 49 8b 9d 08 01 00 00 48 03 1c c6 4c 89 f7 e8 87 fb ff ff 48 85 c0 <48> 8b 3b 0f 84 c5 01 00 00 48 39 f8 0f 84 bc 01 00 00 48 89 c7 RIP: __queue_work+0x8c/0x410 RSP: ffffbe8cc249fcd8 CR2: 0000000000000000 ---[ end trace 7aa4f4a232e9c39c ]--- Unregistering the led device on the remove callback before destroying the workqueue avoids this problem. https://bugzilla.kernel.org/show_bug.cgi?id=196097 Reported-by: Dun Hum Cc: stable@vger.kernel.org Signed-off-by: João Paulo Rechi Vita Signed-off-by: Darren Hart (VMware) Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/asus-wireless.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c index 18716025b1db..c0983281fca4 100644 --- a/drivers/platform/x86/asus-wireless.c +++ b/drivers/platform/x86/asus-wireless.c @@ -145,8 +145,10 @@ static int asus_wireless_remove(struct acpi_device *adev) { struct asus_wireless_data *data = acpi_driver_data(adev); - if (data->wq) + if (data->wq) { + devm_led_classdev_unregister(&adev->dev, &data->led); destroy_workqueue(data->wq); + } return 0; } -- GitLab From bce133ab7d4c4799949478fc7897cc335f3042e9 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 20 Mar 2017 14:29:50 +0100 Subject: [PATCH 211/855] s390/facilites: use stfle_fac_list array size for MAX_FACILITY_BIT commit 6f5165e864d240d15675cc2fb5a369d57e1f60d0 upstream. Use the actual size of the facility list array within the lowcore structure for the MAX_FACILITY_BIT define instead of a comment which states what this is good for. This makes it a bit harder to break things. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/facility.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h index 7a8a1457dbb8..5811e7849a2e 100644 --- a/arch/s390/include/asm/facility.h +++ b/arch/s390/include/asm/facility.h @@ -15,7 +15,7 @@ #include #include -#define MAX_FACILITY_BIT (256*8) /* stfle_fac_list has 256 bytes */ +#define MAX_FACILITY_BIT (sizeof(((struct lowcore *)0)->stfle_fac_list) * 8) static inline void __set_facility(unsigned long nr, void *facilities) { -- GitLab From 04cd74a759bf381f8f2c12e9ddb5fe8d0651c483 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 9 May 2018 09:50:24 +0200 Subject: [PATCH 212/855] Linux 4.9.99 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 96d770488ae6..d51e99f4a987 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 98 +SUBLEVEL = 99 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 1abe1e07c038d75e9dcaa44ecf2c3cada36f71ed Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Wed, 9 May 2018 16:58:55 +0530 Subject: [PATCH 213/855] scsi: ufs-qcom: Force probe of ufs based on boolean property Force probing the ufs device even if it is not the bootdevice based on device tree property "force-ufshc-probe". This enables the embedded ufs device for other usecases even when board is not using UFS for boot. Change-Id: I8e959fd9bdb810d2dcd6c793a9c7dfbfcd66eaaa Signed-off-by: Veerabhadrarao Badiganti --- Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt | 1 + drivers/scsi/ufs/ufs-qcom.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt index 7f79f4041e4f..f075a2a2ac03 100644 --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt @@ -74,6 +74,7 @@ Optional properties: Defaults to 26 MHz if not specified. - extcon: phandle to external connector (Refer Documentation/devicetree/bindings/extcon/extcon-gpio.txt for more details). - non-removable : defines if the connected ufs device is not removable +- force-ufshc-probe : For force probing UFS device (non removable) even if it is not the boot device. Note: If above properties are not defined it can be assumed that the supply diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 39ab28aa32e9..e84729ef434a 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -2740,7 +2740,7 @@ static int ufs_qcom_probe(struct platform_device *pdev) * the regulators. */ if (of_property_read_bool(np, "non-removable") && - strlen(android_boot_dev) && + !of_property_read_bool(np, "force-ufshc-probe") && strcmp(android_boot_dev, dev_name(dev))) return -ENODEV; -- GitLab From 6de7e0976aec61c607f2d27dd1d9e5915bae2aad Mon Sep 17 00:00:00 2001 From: Ashwanth Goli Date: Wed, 9 May 2018 20:28:24 +0530 Subject: [PATCH 214/855] rmnet_data: Fix use-after-free in rmnet_vnd_create_dev Currently it is possible for rmnet_vnd_create_dev to update features on a free'd device in case of device registraton failure. Fix this issue by updating features only on successful netdevice registration. Change-Id: Idbd50f91377206a73ef4105d35b2f5e8cc065a07 Signed-off-by: Ashwanth Goli --- net/rmnet_data/rmnet_data_vnd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/rmnet_data/rmnet_data_vnd.c b/net/rmnet_data/rmnet_data_vnd.c index c4ef460d7c79..3603c5e32019 100644 --- a/net/rmnet_data/rmnet_data_vnd.c +++ b/net/rmnet_data/rmnet_data_vnd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -578,7 +578,7 @@ int rmnet_vnd_create_dev(int id, struct net_device **new_device, LOGE("Failed to to register netdev [%s]", dev->name); free_netdev(dev); *new_device = 0; - rc = RMNET_CONFIG_UNKNOWN_ERROR; + return RMNET_CONFIG_UNKNOWN_ERROR; } else { rmnet_devices[id] = dev; *new_device = dev; -- GitLab From 5ec274f249c9ea28d517e9d950fe0dac9cef71d0 Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Thu, 3 May 2018 02:18:34 -0700 Subject: [PATCH 215/855] msm: ipa: fix the ipa-hw rules not clean After getting reset ioctl from user-space module, the caches in ipa-driver are clean however ipa-hw still has it. The fix is to commit those caches in ipa-hw. Change-Id: Iee0009b2bf3cdff2979d1fdba629c86a7c5afe21 Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v2/ipa_flt.c | 10 +++++++++- drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c | 9 +++++++++ drivers/platform/msm/ipa/ipa_v2/ipa_rt.c | 9 +++++++++ drivers/platform/msm/ipa/ipa_v3/ipa_flt.c | 10 +++++++++- drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c | 10 +++++++++- drivers/platform/msm/ipa/ipa_v3/ipa_rt.c | 9 +++++++++ 6 files changed, 54 insertions(+), 3 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c index 84dce6fe9bee..50fe2a10c073 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c @@ -1495,8 +1495,16 @@ int ipa2_reset_flt(enum ipa_ip_type ip, bool user_only) } } } - mutex_unlock(&ipa_ctx->lock); + /* commit the change to IPA-HW */ + if (ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v4) || + ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v6)) { + IPAERR_RL("fail to commit flt-rule\n"); + WARN_ON_RATELIMIT_IPA(1); + mutex_unlock(&ipa_ctx->lock); + return -EPERM; + } + mutex_unlock(&ipa_ctx->lock); return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c index 62851306cceb..324125783220 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c @@ -1426,6 +1426,15 @@ int ipa2_reset_hdr(bool user_only) } mutex_unlock(&ipa_ctx->lock); + /* commit the change to IPA-HW */ + if (ipa_ctx->ctrl->ipa_commit_hdr()) { + IPAERR_RL("fail to commit hdr\n"); + WARN_ON_RATELIMIT_IPA(1); + mutex_unlock(&ipa_ctx->lock); + return -EFAULT; + } + + mutex_unlock(&ipa_ctx->lock); return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c index 771027984f0a..073409bf7c7b 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c @@ -1445,6 +1445,15 @@ int ipa2_reset_rt(enum ipa_ip_type ip, bool user_only) } } } + + /* commit the change to IPA-HW */ + if (ipa_ctx->ctrl->ipa_commit_rt(IPA_IP_v4) || + ipa_ctx->ctrl->ipa_commit_rt(IPA_IP_v6)) { + IPAERR("fail to commit rt-rule\n"); + WARN_ON_RATELIMIT_IPA(1); + mutex_unlock(&ipa_ctx->lock); + return -EPERM; + } mutex_unlock(&ipa_ctx->lock); return 0; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c index 29fd54796499..a15c43191872 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c @@ -1445,8 +1445,16 @@ int ipa3_reset_flt(enum ipa_ip_type ip, bool user_only) } } } - mutex_unlock(&ipa3_ctx->lock); + /* commit the change to IPA-HW */ + if (ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v4) || + ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v6)) { + IPAERR("fail to commit flt-rule\n"); + WARN_ON_RATELIMIT_IPA(1); + mutex_unlock(&ipa3_ctx->lock); + return -EPERM; + } + mutex_unlock(&ipa3_ctx->lock); return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c index cecbef08028e..41965398792a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c @@ -1171,8 +1171,16 @@ int ipa3_reset_hdr(bool user_only) ipa3_ctx->hdr_proc_ctx_tbl.end = end; IPADBG("hdr_proc_tbl.end = %d\n", end); } - mutex_unlock(&ipa3_ctx->lock); + /* commit the change to IPA-HW */ + if (ipa3_ctx->ctrl->ipa3_commit_hdr()) { + IPAERR("fail to commit hdr\n"); + WARN_ON_RATELIMIT_IPA(1); + mutex_unlock(&ipa3_ctx->lock); + return -EFAULT; + } + + mutex_unlock(&ipa3_ctx->lock); return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index 786189611fa5..736c0fb1b7f0 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -1577,6 +1577,15 @@ int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only) } } } + + /* commit the change to IPA-HW */ + if (ipa3_ctx->ctrl->ipa3_commit_rt(IPA_IP_v4) || + ipa3_ctx->ctrl->ipa3_commit_rt(IPA_IP_v6)) { + IPAERR("fail to commit rt-rule\n"); + WARN_ON_RATELIMIT_IPA(1); + mutex_unlock(&ipa3_ctx->lock); + return -EPERM; + } mutex_unlock(&ipa3_ctx->lock); return 0; -- GitLab From b7b9533a7d3b05d6c0c851717a2979c9065b099d Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 2 May 2018 15:14:39 -0700 Subject: [PATCH 216/855] msm: camera: cpas: Use device tree entry to set camnoc-min-bw Set the camnoc min axi bw vote to the bus driver by reading this entry from the device tree. If this entry from the device tree is not listed then the pre-defined default value will be used. Change-Id: I2656af75ab6244f534e7c0162d73d240d30d6257 Signed-off-by: Karthik Anantha Ram --- .../bindings/media/video/msm-cam-cpas.txt | 5 +++++ .../msm/camera/cam_cpas/cam_cpas_hw.c | 10 +++------ .../msm/camera/cam_cpas/cam_cpas_hw.h | 5 +++++ .../msm/camera/cam_cpas/cam_cpas_soc.c | 21 +++++++++++++++++++ .../msm/camera/cam_cpas/cam_cpas_soc.h | 2 ++ 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt b/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt index 86d49e382f8d..b89fd85061eb 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt @@ -71,6 +71,11 @@ First Level Node - CAM CPAS device Value type: Definition: CAM HW Version information. +- camnoc-axi-min-ib-bw + Usage: optional + Value type: + Definition: Min camnoc axi bw for the given target. + - regulator-names Usage: required Value type: diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c index 5e4ff0d73f67..665c49b67e7f 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c @@ -22,11 +22,6 @@ #include "cam_cpas_hw_intf.h" #include "cam_cpas_soc.h" -#define CAM_CPAS_AXI_MIN_MNOC_AB_BW (2048 * 1024) -#define CAM_CPAS_AXI_MIN_MNOC_IB_BW (2048 * 1024) -#define CAM_CPAS_AXI_MIN_CAMNOC_AB_BW (2048 * 1024) -#define CAM_CPAS_AXI_MIN_CAMNOC_IB_BW (3000000000L) - static uint cam_min_camnoc_ib_bw; module_param(cam_min_camnoc_ib_bw, uint, 0644); @@ -580,8 +575,9 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( soc_private->camnoc_axi_clk_bw_margin) / 100; if ((required_camnoc_bw > 0) && - (required_camnoc_bw < CAM_CPAS_AXI_MIN_CAMNOC_IB_BW)) - required_camnoc_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW; + (required_camnoc_bw < + soc_private->camnoc_axi_min_ib_bw)) + required_camnoc_bw = soc_private->camnoc_axi_min_ib_bw; clk_rate = required_camnoc_bw / soc_private->camnoc_bus_width; diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h index 2e660b1adb95..5d1243c80064 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h @@ -20,6 +20,11 @@ #define CAM_CPAS_MAX_CLIENTS 30 #define CAM_CPAS_INFLIGHT_WORKS 5 +#define CAM_CPAS_AXI_MIN_MNOC_AB_BW (2048 * 1024) +#define CAM_CPAS_AXI_MIN_MNOC_IB_BW (2048 * 1024) +#define CAM_CPAS_AXI_MIN_CAMNOC_AB_BW (2048 * 1024) +#define CAM_CPAS_AXI_MIN_CAMNOC_IB_BW (3000000000L) + #define CAM_CPAS_GET_CLIENT_IDX(handle) (handle) #define CAM_CPAS_GET_CLIENT_HANDLE(indx) (indx) diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c index 46ee90c5f9c4..3fee45f49ff4 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c @@ -56,6 +56,27 @@ int cam_cpas_get_custom_dt_info(struct platform_device *pdev, CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_private->hw_version); + soc_private->camnoc_axi_min_ib_bw = 0; + rc = of_property_read_u64(of_node, + "camnoc-axi-min-ib-bw", + &soc_private->camnoc_axi_min_ib_bw); + if (rc == -EOVERFLOW) { + soc_private->camnoc_axi_min_ib_bw = 0; + rc = of_property_read_u32(of_node, + "camnoc-axi-min-ib-bw", + (u32 *)&soc_private->camnoc_axi_min_ib_bw); + } + + if (rc) { + CAM_DBG(CAM_CPAS, + "failed to read camnoc-axi-min-ib-bw rc:%d", rc); + soc_private->camnoc_axi_min_ib_bw = + CAM_CPAS_AXI_MIN_CAMNOC_IB_BW; + } + + CAM_DBG(CAM_CPAS, "camnoc-axi-min-ib-bw = %llu", + soc_private->camnoc_axi_min_ib_bw); + soc_private->client_id_based = of_property_read_bool(of_node, "client-id-based"); diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h index 70c49bdd28df..9d8c25d2b624 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h @@ -47,6 +47,7 @@ struct cam_cpas_vdd_ahb_mapping { * @camnoc_bus_width : CAMNOC Bus width * @camnoc_axi_clk_bw_margin : BW Margin in percentage to add while calculating * camnoc axi clock + * @camnoc_axi_min_ib_bw: Min camnoc BW which varies based on target * */ struct cam_cpas_private_soc { @@ -63,6 +64,7 @@ struct cam_cpas_private_soc { bool control_camnoc_axi_clk; uint32_t camnoc_bus_width; uint32_t camnoc_axi_clk_bw_margin; + uint64_t camnoc_axi_min_ib_bw; }; int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info, -- GitLab From 83c0875167327e35fd8ce787defda4bc159faf3f Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 10 May 2018 18:10:48 -0700 Subject: [PATCH 217/855] msm: camera: cpas: Improve logging capability Currently the logs print only the cpas/bus client idx, this change logs the name of the client as well which enhances debugging capabilities. Change-Id: I8c0cb23fc846a5b8f5801c78024d1c76559dc48e Signed-off-by: Karthik Anantha Ram --- .../msm/camera/cam_cpas/cam_cpas_hw.c | 119 ++++++++++++------ .../msm/camera/cam_cpas/cam_cpas_hw.h | 2 + 2 files changed, 80 insertions(+), 41 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c index 5e4ff0d73f67..eabe86dd9cd9 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c @@ -82,8 +82,8 @@ static int cam_cpas_util_vote_bus_client_level( if (level == bus_client->curr_vote_level) return 0; - CAM_DBG(CAM_CPAS, "Bus client[%d] index[%d]", bus_client->client_id, - level); + CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] index[%d]", + bus_client->client_id, bus_client->name, level); msm_bus_scale_client_update_request(bus_client->client_id, level); bus_client->curr_vote_level = level; @@ -152,8 +152,8 @@ static int cam_cpas_util_vote_bus_client_bw( path->vectors[0].ab = ab; path->vectors[0].ib = ib; - CAM_DBG(CAM_CPAS, "Bus client[%d] :ab[%llu] ib[%llu], index[%d]", - bus_client->client_id, ab, ib, idx); + CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] :ab[%llu] ib[%llu], index[%d]", + bus_client->client_id, bus_client->name, ab, ib, idx); msm_bus_scale_client_update_request(bus_client->client_id, idx); return 0; @@ -208,10 +208,12 @@ static int cam_cpas_util_register_bus_client( bus_client->num_paths = pdata->usecase[0].num_paths; bus_client->curr_vote_level = 0; bus_client->valid = true; + bus_client->name = pdata->name; mutex_init(&bus_client->lock); - CAM_DBG(CAM_CPAS, "Bus Client : src=%d, dst=%d, bus_client=%d", - bus_client->src, bus_client->dst, bus_client->client_id); + CAM_DBG(CAM_CPAS, "Bus Client=[%d][%s] : src=%d, dst=%d", + bus_client->client_id, bus_client->name, + bus_client->src, bus_client->dst); return 0; fail_unregister_client: @@ -463,6 +465,7 @@ static int cam_cpas_hw_reg_write(struct cam_hw_info *cpas_hw, { struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_client *cpas_client = NULL; int reg_base_index = cpas_core->regbase_index[reg_base]; uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); int rc = 0; @@ -478,9 +481,12 @@ static int cam_cpas_hw_reg_write(struct cam_hw_info *cpas_hw, return -EINVAL; mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { - CAM_ERR(CAM_CPAS, "client has not started%d", client_indx); + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); rc = -EPERM; goto unlock_client; } @@ -503,6 +509,7 @@ static int cam_cpas_hw_reg_read(struct cam_hw_info *cpas_hw, { struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_client *cpas_client = NULL; int reg_base_index = cpas_core->regbase_index[reg_base]; uint32_t reg_value; uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); @@ -522,9 +529,12 @@ static int cam_cpas_hw_reg_read(struct cam_hw_info *cpas_hw, return -EINVAL; mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { - CAM_ERR(CAM_CPAS, "client has not started%d", client_indx); + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); rc = -EPERM; goto unlock_client; } @@ -695,6 +705,7 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, { struct cam_axi_vote axi_vote; struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_client *cpas_client = NULL; uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); int rc = 0; @@ -719,16 +730,20 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, mutex_lock(&cpas_hw->hw_mutex); mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { - CAM_ERR(CAM_CPAS, "client has not started %d", client_indx); + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); rc = -EPERM; goto unlock_client; } CAM_DBG(CAM_CPAS, - "Client[%d] Requested compressed[%llu], uncompressed[%llu]", - client_indx, axi_vote.compressed_bw, + "Client=[%d][%s][%d] Requested compressed[%llu], uncompressed[%llu]", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, axi_vote.compressed_bw, axi_vote.uncompressed_bw); rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, @@ -809,7 +824,8 @@ static int cam_cpas_util_apply_client_ahb_vote(struct cam_hw_info *cpas_hw, mutex_lock(&ahb_bus_client->lock); cpas_client->ahb_level = required_level; - CAM_DBG(CAM_CPAS, "Clients required level[%d], curr_level[%d]", + CAM_DBG(CAM_CPAS, "Client=[%d][%s] required level[%d], curr_level[%d]", + ahb_bus_client->client_id, ahb_bus_client->name, required_level, ahb_bus_client->curr_vote_level); if (required_level == ahb_bus_client->curr_vote_level) @@ -853,6 +869,7 @@ static int cam_cpas_hw_update_ahb_vote(struct cam_hw_info *cpas_hw, { struct cam_ahb_vote ahb_vote; struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_client *cpas_client = NULL; uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); int rc = 0; @@ -875,17 +892,21 @@ static int cam_cpas_hw_update_ahb_vote(struct cam_hw_info *cpas_hw, mutex_lock(&cpas_hw->hw_mutex); mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { - CAM_ERR(CAM_CPAS, "client has not started %d", client_indx); + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); rc = -EPERM; goto unlock_client; } CAM_DBG(CAM_CPAS, - "client[%d] : type[%d], level[%d], freq[%ld], applied[%d]", - client_indx, ahb_vote.type, ahb_vote.vote.level, - ahb_vote.vote.freq, + "client=[%d][%s][%d] : type[%d], level[%d], freq[%ld], applied[%d]", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, ahb_vote.type, + ahb_vote.vote.level, ahb_vote.vote.freq, cpas_core->cpas_client[client_indx]->ahb_level); rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, @@ -948,32 +969,37 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, mutex_lock(&cpas_hw->hw_mutex); mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; if (!CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) { - CAM_ERR(CAM_CPAS, "client is not registered %d", client_indx); + CAM_ERR(CAM_CPAS, "client=[%d] is not registered", + client_indx); rc = -EPERM; goto done; } if (CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { - CAM_ERR(CAM_CPAS, "Client %d is in start state", client_indx); + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] is in start state", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); rc = -EPERM; goto done; } - cpas_client = cpas_core->cpas_client[client_indx]; - - CAM_DBG(CAM_CPAS, "AHB :client[%d] type[%d], level[%d], applied[%d]", - client_indx, ahb_vote->type, ahb_vote->vote.level, - cpas_client->ahb_level); + CAM_DBG(CAM_CPAS, + "AHB :client=[%d][%s][%d] type[%d], level[%d], applied[%d]", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, + ahb_vote->type, ahb_vote->vote.level, cpas_client->ahb_level); rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, ahb_vote, &applied_level); if (rc) goto done; CAM_DBG(CAM_CPAS, - "AXI client[%d] compressed_bw[%llu], uncompressed_bw[%llu]", - client_indx, axi_vote->compressed_bw, + "AXI client=[%d][%s][%d] compressed_bw[%llu], uncompressed_bw[%llu]", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, axi_vote->compressed_bw, axi_vote->uncompressed_bw); rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, axi_vote); @@ -1010,9 +1036,9 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, cpas_client->started = true; cpas_core->streamon_clients++; - CAM_DBG(CAM_CPAS, "client=%s, streamon_clients=%d", - soc_private->client_name[client_indx], - cpas_core->streamon_clients); + CAM_DBG(CAM_CPAS, "client=[%d][%s][%d] streamon_clients=%d", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, cpas_core->streamon_clients); done: mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); @@ -1062,18 +1088,20 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, mutex_lock(&cpas_hw->hw_mutex); mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; - CAM_DBG(CAM_CPAS, "client=%s, streamon_clients=%d", - soc_private->client_name[client_indx], - cpas_core->streamon_clients); + CAM_DBG(CAM_CPAS, "Client=[%d][%s][%d] streamon_clients=%d", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, cpas_core->streamon_clients); if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { - CAM_ERR(CAM_CPAS, "Client %d is not started", client_indx); + CAM_ERR(CAM_CPAS, "Client=[%d][%s][%d] is not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); rc = -EPERM; goto done; } - cpas_client = cpas_core->cpas_client[client_indx]; cpas_client->started = false; cpas_core->streamon_clients--; @@ -1207,8 +1235,9 @@ static int cam_cpas_hw_register_client(struct cam_hw_info *cpas_hw, cpas_client, client_indx); if (rc) { CAM_ERR(CAM_CPAS, - "axi_port_insert failed client_indx=%d, rc=%d", - client_indx, rc); + "axi_port_insert failed Client=[%d][%s][%d], rc=%d", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, rc); kfree(cpas_client); mutex_unlock(&cpas_hw->hw_mutex); return -EINVAL; @@ -1223,8 +1252,9 @@ static int cam_cpas_hw_register_client(struct cam_hw_info *cpas_hw, mutex_unlock(&cpas_hw->hw_mutex); - CAM_DBG(CAM_CPAS, "client_indx=%d, registered_clients=%d", - client_indx, cpas_core->registered_clients); + CAM_DBG(CAM_CPAS, "client=[%d][%s][%d], registered_clients=%d", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, cpas_core->registered_clients); return 0; } @@ -1233,6 +1263,7 @@ static int cam_cpas_hw_unregister_client(struct cam_hw_info *cpas_hw, uint32_t client_handle) { struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_client *cpas_client = NULL; uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); int rc = 0; @@ -1241,15 +1272,20 @@ static int cam_cpas_hw_unregister_client(struct cam_hw_info *cpas_hw, mutex_lock(&cpas_hw->hw_mutex); mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; if (!CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) { - CAM_ERR(CAM_CPAS, "client not registered %d", client_indx); + CAM_ERR(CAM_CPAS, "Client=[%d][%s][%d] not registered", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); rc = -EPERM; goto done; } if (CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { - CAM_ERR(CAM_CPAS, "Client %d is not stopped", client_indx); + CAM_ERR(CAM_CPAS, "Client=[%d][%s][%d] is not stopped", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); rc = -EPERM; goto done; } @@ -1257,8 +1293,9 @@ static int cam_cpas_hw_unregister_client(struct cam_hw_info *cpas_hw, cam_cpas_util_remove_client_from_axi_port( cpas_core->cpas_client[client_indx]); - CAM_DBG(CAM_CPAS, "client_indx=%d, registered_clients=%d", - client_indx, cpas_core->registered_clients); + CAM_DBG(CAM_CPAS, "client=[%d][%s][%d], registered_clients=%d", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, cpas_core->registered_clients); kfree(cpas_core->cpas_client[client_indx]); cpas_core->cpas_client[client_indx] = NULL; diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h index 2e660b1adb95..a24168461e78 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h @@ -118,6 +118,7 @@ struct cam_cpas_client { * @dyn_vote: Whether dynamic voting enabled * @lock: Mutex lock used while voting on this client * @valid: Whether bus client is valid + * @name: Name of the bus client * */ struct cam_cpas_bus_client { @@ -131,6 +132,7 @@ struct cam_cpas_bus_client { bool dyn_vote; struct mutex lock; bool valid; + const char *name; }; /** -- GitLab From 037371971912613c9089b3e5ee918d870da8028e Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Wed, 9 May 2018 11:16:27 +0530 Subject: [PATCH 218/855] scsi: ufs: delay switching off regulators Don't turn-off regulators immediately in case of errors. If eMMC is not yet probed, turing off regulators without sending a PON to eMMC is not a good idea. Hence, allow upto 10sec for eMMC to be probed. If eMMC is present it'd vote for the regulators and removing UFS vote wouldn't cause it to suddenly turn off. Change-Id: I54f915ef8708919ef1f0a85cc44de42b5df3710a Signed-off-by: Asutosh Das --- drivers/scsi/ufs/ufshcd.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d427fb380840..5ef690a0d63e 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -8093,9 +8093,16 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) /* * If we failed to initialize the device or the device is not * present, turn off the power/clocks etc. + * In cases when there's both ufs and emmc present and regualtors + * are shared b/w the two, this shouldn't turn-off the regulators + * w/o giving emmc a chance to send PON. + * Hence schedule a delayed suspend, thus giving enough time to + * emmc to vote for the shared regulator. */ - if (ret && !ufshcd_eh_in_progress(hba) && !hba->pm_op_in_progress) - pm_runtime_put_sync(hba->dev); + if (ret && !ufshcd_eh_in_progress(hba) && !hba->pm_op_in_progress) { + pm_runtime_put_noidle(hba->dev); + pm_schedule_suspend(hba->dev, MSEC_PER_SEC * 10); + } trace_ufshcd_init(dev_name(hba->dev), ret, ktime_to_us(ktime_sub(ktime_get(), start)), -- GitLab From 5694161e38d4965ec087b0cbe18dfd070a33230b Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 11 May 2018 12:22:11 +0530 Subject: [PATCH 219/855] ARM: dts: msm: Enable system PM to high power saving mode on SDM710 During system suspend, power-down the device and turn-off the link. This will ensure higher power-savings. Change-Id: I68c4c54012b0a7c9343339d8d85c5ac7806021a1 Signed-off-by: Asutosh Das --- arch/arm64/boot/dts/qcom/sdm670.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index 4b39207aae8e..14775a97e103 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -1866,6 +1866,7 @@ ufs-qcom-crypto = <&ufs_ice>; lanes-per-direction = <1>; + spm-level = <5>; dev-ref-clk-freq = <0>; /* 19.2 MHz */ clock-names = -- GitLab From 34f87562d7a3587695dd0bb430699315920003f7 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Fri, 11 May 2018 12:26:16 +0530 Subject: [PATCH 220/855] ARM: dts: msm: Ignore mem timer save/restore for sdm670 Ignore mem timer interrupt while saving/restoring GICD configuration for SDM670. Change-Id: Ief15873cae5d186e3dd25c774b1bf9faf726e274 Signed-off-by: Gaurav Kohli --- arch/arm64/boot/dts/qcom/sdm670.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index 3ca33b2d2583..1cab025dab44 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -730,6 +730,7 @@ <0x17a60000 0x100000>; /* GICR * 8 */ interrupts = <1 9 4>; interrupt-parent = <&intc>; + ignored-save-restore-irqs = <38>; }; pdc: interrupt-controller@b220000{ -- GitLab From c4048b20ffc5e8c35ec1b90032dd6aa35926225a Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 28 Mar 2018 11:14:50 +0200 Subject: [PATCH 221/855] UPSTREAM: ANDROID: binder: prevent transactions into own process. This can't happen with normal nodes (because you can't get a ref to a node you own), but it could happen with the context manager; to make the behavior consistent with regular nodes, reject transactions into the context manager by the process owning it. Reported-by: syzbot+09e05aba06723a94d43d@syzkaller.appspotmail.com Signed-off-by: Martijn Coenen Cc: stable Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 7aa135fcf26377f92dc0680a57566b4c7f3e281b) --- drivers/android/binder.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index e7e4560e4c6e..957eb3cfab79 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3001,6 +3001,14 @@ static void binder_transaction(struct binder_proc *proc, else return_error = BR_DEAD_REPLY; mutex_unlock(&context->context_mgr_node_lock); + if (target_node && target_proc == proc) { + binder_user_error("%d:%d got transaction to context manager from process owning it\n", + proc->pid, thread->pid); + return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; + goto err_invalid_target_handle; + } } if (!target_node) { /* -- GitLab From 60b870a7cbba9157ab67ce5da0f1f040afd28a3b Mon Sep 17 00:00:00 2001 From: Shadab Naseem Date: Fri, 11 May 2018 14:31:03 +0530 Subject: [PATCH 222/855] ARM: dts: msm: Enable support for full modem ramdump for sdm670 Enable support for full modem ramdump for sdm670. On modem ramdump, memory holes were observed when collected for only modem filled regions. This flag will collect the whole carveout of memory allocated for modem to prevent memory holes. Change-Id: I49561c46ade8903a1198dd740c99b5966442616a Signed-off-by: Shadab Naseem --- arch/arm64/boot/dts/qcom/sdm670.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index 4b39207aae8e..8b3d6e687caf 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -2216,6 +2216,7 @@ status = "ok"; memory-region = <&pil_modem_mem>; qcom,mem-protect-id = <0xF>; + qcom,complete-ramdump; /* GPIO inputs from mss */ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>; -- GitLab From c2f9bce9fee8e31e0500c501076f73db7791d8e9 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Thu, 10 May 2018 14:56:41 -0700 Subject: [PATCH 223/855] ANDROID: ftrace: fix function type mismatches This change fixes indirect call mismatches with function and function graph tracing, which trip Control-Flow Integrity (CFI) checking. Bug: 79510107 Bug: 67506682 Change-Id: I5de08c113fb970ffefedce93c58e0161f22c7ca2 Signed-off-by: Sami Tolvanen --- include/linux/ftrace.h | 8 ++++++++ kernel/trace/ftrace.c | 17 +++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index f4c0d36baffb..ab7938a58ca0 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -244,8 +244,16 @@ static inline int ftrace_function_local_disabled(struct ftrace_ops *ops) return *this_cpu_ptr(ops->disabled); } +#ifdef CONFIG_CFI_CLANG +/* Use a C stub with the correct type for CFI */ +static inline void ftrace_stub(unsigned long a0, unsigned long a1, + struct ftrace_ops *op, struct pt_regs *regs) +{ +} +#else extern void ftrace_stub(unsigned long a0, unsigned long a1, struct ftrace_ops *op, struct pt_regs *regs); +#endif #else /* !CONFIG_FUNCTION_TRACER */ /* diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 063dd229bd36..5534be18797e 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -120,8 +120,9 @@ static void ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs); #else /* See comment below, where ftrace_ops_list_func is defined */ -static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip); -#define ftrace_ops_list_func ((ftrace_func_t)ftrace_ops_no_ops) +static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct pt_regs *regs); +#define ftrace_ops_list_func ftrace_ops_no_ops #endif /* @@ -5309,7 +5310,8 @@ static void ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, __ftrace_ops_list_func(ip, parent_ip, NULL, regs); } #else -static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip) +static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct pt_regs *regs) { __ftrace_ops_list_func(ip, parent_ip, NULL, NULL); } @@ -5735,14 +5737,17 @@ void ftrace_graph_graph_time_control(bool enable) fgraph_graph_time = enable; } +void ftrace_graph_return_stub(struct ftrace_graph_ret *trace) +{ +} + int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace) { return 0; } /* The callbacks that hook a function */ -trace_func_graph_ret_t ftrace_graph_return = - (trace_func_graph_ret_t)ftrace_stub; +trace_func_graph_ret_t ftrace_graph_return = ftrace_graph_return_stub; trace_func_graph_ent_t ftrace_graph_entry = ftrace_graph_entry_stub; static trace_func_graph_ent_t __ftrace_graph_entry = ftrace_graph_entry_stub; @@ -5970,7 +5975,7 @@ void unregister_ftrace_graph(void) goto out; ftrace_graph_active--; - ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; + ftrace_graph_return = ftrace_graph_return_stub; ftrace_graph_entry = ftrace_graph_entry_stub; __ftrace_graph_entry = ftrace_graph_entry_stub; ftrace_shutdown(&graph_ops, FTRACE_STOP_FUNC_RET); -- GitLab From d87c67b6354f50547182866f82bc767ff9d6f202 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 3 May 2018 14:36:43 -0700 Subject: [PATCH 224/855] msm: camera: cci: Add support for burst read Configure the read threshold level and implement change to enable burst read. This change also bumps up the max bytes that can be read in a single transaction. Change-Id: I6ab4d5db302ddf49387bf47916e264714ca434e6 Signed-off-by: Karthik Anantha Ram --- .../cam_sensor_module/cam_cci/cam_cci_core.c | 207 +++++++++++++++++- .../cam_sensor_module/cam_cci/cam_cci_dev.c | 62 ++++-- .../cam_sensor_module/cam_cci/cam_cci_dev.h | 10 +- .../cam_sensor_module/cam_cci/cam_cci_hwreg.h | 13 +- .../cam_sensor_module/cam_cci/cam_cci_soc.c | 11 + .../cam_eeprom/cam_eeprom_core.c | 1 + .../cam_sensor_io/cam_sensor_cci_i2c.c | 6 +- .../cam_sensor_io/cam_sensor_i2c.h | 4 +- .../cam_sensor_io/cam_sensor_io.c | 5 +- .../cam_sensor_io/cam_sensor_io.h | 4 +- 10 files changed, 281 insertions(+), 42 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c index fe69fcb27cc4..b47f4f35b108 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c @@ -205,8 +205,6 @@ static void cam_cci_dump_registers(struct cci_device *cci_dev, CAM_INFO(CAM_CCI, "****CCI MASTER %d Registers ****", master); for (i = 0; i < DEBUG_MASTER_REG_COUNT; i++) { - if (i == 6) - continue; reg_offset = DEBUG_MASTER_REG_START + master*0x100 + i * 4; read_val = cam_io_r_mb(base + reg_offset); CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X", @@ -868,6 +866,180 @@ static int32_t cam_cci_data_queue(struct cci_device *cci_dev, return rc; } +static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + uint32_t val = 0, i = 0; + unsigned long rem_jiffies; + int32_t read_words = 0, exp_words = 0; + int32_t index = 0, first_byte = 0, total_read_words = 0; + enum cci_i2c_master_t master; + enum cci_i2c_queue_t queue = QUEUE_1; + struct cci_device *cci_dev = NULL; + struct cam_cci_read_cfg *read_cfg = NULL; + struct cam_hw_soc_info *soc_info = NULL; + void __iomem *base = NULL; + + cci_dev = v4l2_get_subdevdata(sd); + master = c_ctrl->cci_info->cci_i2c_master; + read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; + + if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX + || c_ctrl->cci_info->cci_i2c_master < 0) { + CAM_ERR(CAM_CCI, "Invalid I2C master addr"); + return -EINVAL; + } + + soc_info = &cci_dev->soc_info; + base = soc_info->reg_map[0].mem_base; + mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); + + /* + * Todo: If there is a change in frequency of operation + * Wait for previos transaction to complete + */ + + /* Set the I2C Frequency */ + rc = cam_cci_set_clk_param(cci_dev, c_ctrl); + if (rc < 0) { + CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); + goto rel_mutex; + } + + /* + * Call validate queue to make sure queue is empty before starting. + * If this call fails, don't proceed with i2c_read call. This is to + * avoid overflow / underflow of queue + */ + rc = cam_cci_validate_queue(cci_dev, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1, + master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Initial validataion failed rc %d", rc); + goto rel_mutex; + } + + if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { + CAM_ERR(CAM_CCI, "More than max retries"); + goto rel_mutex; + } + + if (read_cfg->data == NULL) { + CAM_ERR(CAM_CCI, "Data ptr is NULL"); + goto rel_mutex; + } + + if (read_cfg->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_CCI, "failed : Invalid addr type: %u", + read_cfg->addr_type); + rc = -EINVAL; + goto rel_mutex; + } + + CAM_DBG(CAM_CCI, "set param sid 0x%x retries %d id_map %d", + c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, + c_ctrl->cci_info->id_map); + val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | + c_ctrl->cci_info->retries << 16 | + c_ctrl->cci_info->id_map << 18; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex; + } + + val = CCI_I2C_LOCK_CMD; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex; + } + + val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4); + for (i = 0; i < read_cfg->addr_type; i++) { + val |= ((read_cfg->addr >> (i << 3)) & 0xFF) << + ((read_cfg->addr_type - i) << 3); + } + + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex; + } + + val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4); + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex; + } + + val = CCI_I2C_UNLOCK_CMD; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex; + } + + val = cam_io_r_mb(base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + CAM_DBG(CAM_CCI, "cur word cnt 0x%x", val); + cam_io_w_mb(val, base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + + val = 1 << ((master * 2) + queue); + cam_io_w_mb(val, base + CCI_QUEUE_START_ADDR); + exp_words = ((read_cfg->num_byte / 4) + 1); + + while (exp_words != total_read_words) { + rem_jiffies = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].reset_complete, + CCI_TIMEOUT); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + val = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + + master * 0x100); + CAM_ERR(CAM_CCI, + "wait_for_completion_timeout rc = %d FIFO buf_lvl:0x%x", + rc, val); +#ifdef DUMP_CCI_REGISTERS + cam_cci_dump_registers(cci_dev, master, queue); +#endif + cam_cci_flush_queue(cci_dev, master); + goto rel_mutex; + } + + read_words = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); + total_read_words += read_words; + do { + val = cam_io_r_mb(base + + CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); + for (i = 0; (i < 4) && + (index < read_cfg->num_byte); i++) { + CAM_DBG(CAM_CCI, "i:%d index:%d", i, index); + if (!first_byte) { + CAM_DBG(CAM_CCI, "sid 0x%x", + val & 0xFF); + first_byte++; + } else { + read_cfg->data[index] = + (val >> (i * 8)) & 0xFF; + CAM_DBG(CAM_CCI, "data[%d] 0x%x", index, + read_cfg->data[index]); + index++; + } + } + } while (--read_words > 0); + } + +rel_mutex: + mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); + return rc; +} + static int32_t cam_cci_read(struct v4l2_subdev *sd, struct cam_cci_ctrl *c_ctrl) { @@ -1004,7 +1176,11 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, #endif if (rc == 0) rc = -ETIMEDOUT; - CAM_ERR(CAM_CCI, "wait_for_completion_timeout rc = %d", rc); + val = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); + CAM_ERR(CAM_CCI, + "wait_for_completion_timeout rc = %d FIFO buf_lvl: 0x%x", + rc, val); cam_cci_flush_queue(cci_dev, master); goto rel_mutex; } else { @@ -1224,19 +1400,26 @@ static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd, read_bytes = read_cfg->num_byte; do { - if (read_bytes > CCI_READ_MAX) - read_cfg->num_byte = CCI_READ_MAX; + if (read_bytes > CCI_I2C_MAX_BYTE_COUNT) + read_cfg->num_byte = CCI_I2C_MAX_BYTE_COUNT; else read_cfg->num_byte = read_bytes; - rc = cam_cci_read(sd, c_ctrl); - if (rc < 0) { - CAM_ERR(CAM_CCI, "failed rc %d", rc); + + if (read_cfg->num_byte > CCI_READ_MAX) + rc = cam_cci_burst_read(sd, c_ctrl); + else + rc = cam_cci_read(sd, c_ctrl); + + if (!rc) { + CAM_ERR(CAM_CCI, "failed to read rc:%d", rc); goto ERROR; } - if (read_bytes > CCI_READ_MAX) { - read_cfg->addr += CCI_READ_MAX; - read_cfg->data += CCI_READ_MAX; - read_bytes -= CCI_READ_MAX; + + if (read_bytes > CCI_I2C_MAX_BYTE_COUNT) { + read_cfg->addr += (CCI_I2C_MAX_BYTE_COUNT / + read_cfg->data_type); + read_cfg->data += CCI_I2C_MAX_BYTE_COUNT; + read_bytes -= CCI_I2C_MAX_BYTE_COUNT; } else { read_bytes = 0; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c index da08bc7ab037..c8ca85dafdba 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -58,18 +58,23 @@ static long cam_cci_subdev_compat_ioctl(struct v4l2_subdev *sd, irqreturn_t cam_cci_irq(int irq_num, void *data) { - uint32_t irq; + uint32_t irq_status0 = 0; + uint32_t irq_status1 = 0; struct cci_device *cci_dev = data; struct cam_hw_soc_info *soc_info = &cci_dev->soc_info; void __iomem *base = soc_info->reg_map[0].mem_base; unsigned long flags; + bool burst_read_assert = false; - irq = cam_io_r_mb(base + CCI_IRQ_STATUS_0_ADDR); - cam_io_w_mb(irq, base + CCI_IRQ_CLEAR_0_ADDR); + irq_status0 = cam_io_r_mb(base + CCI_IRQ_STATUS_0_ADDR); + irq_status1 = cam_io_r_mb(base + CCI_IRQ_STATUS_1_ADDR); + cam_io_w_mb(irq_status0, base + CCI_IRQ_CLEAR_0_ADDR); + cam_io_w_mb(irq_status1, base + CCI_IRQ_CLEAR_1_ADDR); cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); - if (irq & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { + CAM_DBG(CAM_CCI, "irq0:%x irq1:%x", irq_status0, irq_status1); + if (irq_status0 & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) { cci_dev->cci_master_info[MASTER_0].reset_pending = FALSE; @@ -83,11 +88,24 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) &cci_dev->cci_master_info[MASTER_1].reset_complete); } } - if (irq & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) { + + if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) && + (irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD)) { + cci_dev->cci_master_info[MASTER_0].status = 0; + complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); + burst_read_assert = true; + } + if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) && + (!burst_read_assert)) { + cci_dev->cci_master_info[MASTER_0].status = 0; + complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); + } + if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) && + (!burst_read_assert)) { cci_dev->cci_master_info[MASTER_0].status = 0; complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); } - if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) { + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) { struct cam_cci_master_info *cci_master_info; cci_master_info = &cci_dev->cci_master_info[MASTER_0]; @@ -104,7 +122,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_0], flags); } - if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK) { + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK) { struct cam_cci_master_info *cci_master_info; cci_master_info = &cci_dev->cci_master_info[MASTER_0]; @@ -121,11 +139,23 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_1], flags); } - if (irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) { + if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) && + (irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD)) { + cci_dev->cci_master_info[MASTER_1].status = 0; + complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); + burst_read_assert = true; + } + if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) && + (!burst_read_assert)) { + cci_dev->cci_master_info[MASTER_1].status = 0; + complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); + } + if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) && + (!burst_read_assert)) { cci_dev->cci_master_info[MASTER_1].status = 0; complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); } - if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) { + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) { struct cam_cci_master_info *cci_master_info; cci_master_info = &cci_dev->cci_master_info[MASTER_1]; @@ -142,7 +172,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_0], flags); } - if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK) { + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK) { struct cam_cci_master_info *cci_master_info; cci_master_info = &cci_dev->cci_master_info[MASTER_1]; @@ -159,27 +189,27 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_1], flags); } - if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) { + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) { cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; cam_io_w_mb(CCI_M0_RESET_RMSK, base + CCI_RESET_CMD_ADDR); } - if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) { + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) { cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE; cam_io_w_mb(CCI_M1_RESET_RMSK, base + CCI_RESET_CMD_ADDR); } - if (irq & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_0].status = -EINVAL; cam_io_w_mb(CCI_M0_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); - CAM_DBG(CAM_CCI, "MASTER_0 error 0x%x", irq); + CAM_DBG(CAM_CCI, "MASTER_0 error 0x%x", irq_status0); } - if (irq & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_1].status = -EINVAL; cam_io_w_mb(CCI_M1_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); - CAM_DBG(CAM_CCI, "MASTER_1 error 0x%x", irq); + CAM_DBG(CAM_CCI, "MASTER_1 error 0x%x", irq_status0); } return IRQ_HANDLED; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h index 7cde6190f9db..d48ffd15b4f9 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -65,19 +65,14 @@ #define MAX_LRME_V4l2_EVENTS 30 /* Max bytes that can be read per CCI read transaction */ -#define CCI_READ_MAX 12 +#define CCI_READ_MAX 256 #define CCI_I2C_READ_MAX_RETRIES 3 #define CCI_I2C_MAX_READ 8192 #define CCI_I2C_MAX_WRITE 8192 +#define CCI_I2C_MAX_BYTE_COUNT 65535 #define CAMX_CCI_DEV_NAME "cam-cci-driver" -/* Max bytes that can be read per CCI read transaction */ -#define CCI_READ_MAX 12 -#define CCI_I2C_READ_MAX_RETRIES 3 -#define CCI_I2C_MAX_READ 8192 -#define CCI_I2C_MAX_WRITE 8192 - #define PRIORITY_QUEUE (QUEUE_0) #define SYNC_QUEUE (QUEUE_1) @@ -125,6 +120,7 @@ struct cam_cci_read_cfg { uint16_t addr_type; uint8_t *data; uint16_t num_byte; + uint16_t data_type; }; struct cam_cci_i2c_queue_info { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h index c18593eb5e78..31c8e26f3f90 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h @@ -43,27 +43,36 @@ #define CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x00000310 #define CCI_IRQ_MASK_0_ADDR 0x00000c04 #define CCI_IRQ_MASK_0_RMSK 0x7fff7ff7 +#define CCI_IRQ_MASK_1_ADDR 0x00000c10 +#define CCI_IRQ_MASK_1_RMSK 0x00110000 #define CCI_IRQ_CLEAR_0_ADDR 0x00000c08 +#define CCI_IRQ_CLEAR_1_ADDR 0x00000c14 #define CCI_IRQ_STATUS_0_ADDR 0x00000c0c +#define CCI_IRQ_STATUS_1_ADDR 0x00000c18 #define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK 0x4000000 #define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK 0x2000000 #define CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK 0x1000000 #define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK 0x100000 #define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK 0x10000 #define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK 0x1000 +#define CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD 0x100000 #define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK 0x100 #define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10 #define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6 #define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000 #define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK 0x1 +#define CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD 0x10000 +#define CCI_I2C_M0_RD_THRESHOLD_ADDR 0x00000120 +#define CCI_I2C_M1_RD_THRESHOLD_ADDR 0x00000220 +#define CCI_I2C_RD_THRESHOLD_VALUE 0x38 #define CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x00000c00 #define DEBUG_TOP_REG_START 0x0 #define DEBUG_TOP_REG_COUNT 14 #define DEBUG_MASTER_REG_START 0x100 -#define DEBUG_MASTER_REG_COUNT 8 +#define DEBUG_MASTER_REG_COUNT 9 #define DEBUG_MASTER_QUEUE_REG_START 0x300 -#define DEBUG_MASTER_QUEUE_REG_COUNT 6 +#define DEBUG_MASTER_QUEUE_REG_COUNT 7 #define DEBUG_INTR_REG_START 0xC00 #define DEBUG_INTR_REG_COUNT 7 #endif /* _CAM_CCI_HWREG_ */ diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c index 295259d631a2..e0b27ca1e92a 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -146,6 +146,10 @@ int cam_cci_init(struct v4l2_subdev *sd, base + CCI_IRQ_MASK_0_ADDR); cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_CLEAR_0_ADDR); + cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, + base + CCI_IRQ_MASK_1_ADDR); + cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, + base + CCI_IRQ_CLEAR_1_ADDR); cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); for (i = 0; i < MASTER_MAX; i++) { @@ -157,6 +161,13 @@ int cam_cci_init(struct v4l2_subdev *sd, flush_workqueue(cci_dev->write_wq[i]); } } + + /* Set RD FIFO threshold for M0 & M1 */ + cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, + base + CCI_I2C_M0_RD_THRESHOLD_ADDR); + cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, + base + CCI_I2C_M1_RD_THRESHOLD_ADDR); + cci_dev->cci_state = CCI_STATE_ENABLED; return 0; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 30b9d967c405..6523607f0274 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -109,6 +109,7 @@ static int cam_eeprom_read_memory(struct cam_eeprom_ctrl_t *e_ctrl, rc = camera_io_dev_read_seq(&e_ctrl->io_master_info, emap[j].mem.addr, memptr, emap[j].mem.addr_type, + emap[j].mem.data_type, emap[j].mem.valid_size); if (rc) { CAM_ERR(CAM_EEPROM, "read failed rc %d", diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c index 2c1f5204f4cc..1ec7d9a018c8 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -33,6 +33,7 @@ int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *cci_client, cci_ctrl.cci_info = cci_client; cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = addr_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data_type = data_type; cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = data_type; rc = v4l2_subdev_call(cci_client->cci_subdev, @@ -59,6 +60,7 @@ int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *cci_client, int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *cci_client, uint32_t addr, uint8_t *data, enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, uint32_t num_byte) { int32_t rc = -EFAULT; @@ -67,6 +69,7 @@ int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *cci_client, struct cam_cci_ctrl cci_ctrl; if ((addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + || (data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) || (num_byte > I2C_REG_DATA_MAX)) { CAM_ERR(CAM_SENSOR, "addr_type %d num_byte %d", addr_type, num_byte); @@ -81,6 +84,7 @@ int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *cci_client, cci_ctrl.cci_info = cci_client; cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = addr_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data_type = data_type; cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = num_byte; cci_ctrl.status = -EFAULT; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h index 7cddcf9338b0..e79fffb49d77 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -46,6 +46,7 @@ int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *client, * @addr: I2c address * @data: I2C data * @addr_type: I2c address type + * @data_type: I2c data type * @num_byte: number of bytes * * This API handles CCI sequential read @@ -53,6 +54,7 @@ int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *client, int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *client, uint32_t addr, uint8_t *data, enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, uint32_t num_byte); /** diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c index 89aad4e7aa15..ed490fd579bb 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c @@ -69,11 +69,12 @@ int32_t camera_io_dev_read(struct camera_io_master *io_master_info, int32_t camera_io_dev_read_seq(struct camera_io_master *io_master_info, uint32_t addr, uint8_t *data, - enum camera_sensor_i2c_type addr_type, int32_t num_bytes) + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, int32_t num_bytes) { if (io_master_info->master_type == CCI_MASTER) { return cam_camera_cci_i2c_read_seq(io_master_info->cci_client, - addr, data, addr_type, num_bytes); + addr, data, addr_type, data_type, num_bytes); } else if (io_master_info->master_type == I2C_MASTER) { return cam_qup_i2c_read_seq(io_master_info->client, addr, data, addr_type, num_bytes); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h index ec5ed25c0785..f1143c80dbe0 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -52,6 +52,7 @@ int32_t camera_io_dev_read(struct camera_io_master *io_master_info, * @io_master_info: I2C/SPI master information * @addr: I2C address * @data: I2C data + * @addr_type: I2C addr type * @data_type: I2C data type * @num_bytes: number of bytes * @@ -60,6 +61,7 @@ int32_t camera_io_dev_read(struct camera_io_master *io_master_info, int32_t camera_io_dev_read_seq(struct camera_io_master *io_master_info, uint32_t addr, uint8_t *data, enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, int32_t num_bytes); /** -- GitLab From 78f4711829f1903b9bc3fc25ca6ce25e0e4a4a59 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Mon, 14 May 2018 12:53:32 +0530 Subject: [PATCH 225/855] ARM: dts: msm: Add support for 960MHz for CPU clock on SDM439 Gold cluster cpu clock is required to support 960MHz, so add support for the same. Change-Id: I36ee38c6f73eb863520ba4028fc535fe34b82f1c Signed-off-by: Odelu Kukatla --- arch/arm64/boot/dts/qcom/sdm439.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi index 2df468fdc50d..7c18e7eaf5be 100644 --- a/arch/arm64/boot/dts/qcom/sdm439.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi @@ -278,6 +278,7 @@ qcom,speed0-bin-v0-c1 = < 0 0>, + < 960000000 1>, < 1305600000 1>, < 1497600000 2>, < 1708800000 3>, @@ -298,6 +299,7 @@ qcom,speed1-bin-v0-c1 = < 0 0>, + < 960000000 1>, < 1305600000 1>, < 1497600000 2>, < 1708800000 3>, -- GitLab From 74fa0af47306baf118b32b7acdba4ae98eda7a7d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 28 Jul 2017 22:29:51 +0100 Subject: [PATCH 226/855] BACKPORT: dma-buf/sync_file: Allow multiple sync_files to wrap a single dma-fence Up until recently sync_file were create to export a single dma-fence to userspace, and so we could canabalise a bit insie dma-fence to mark whether or not we had enable polling for the sync_file itself. However, with the advent of syncobj, we do allow userspace to create multiple sync_files for a single dma-fence. (Similarly, that the sw-sync validation framework also started returning multiple sync-files wrapping a single dma-fence for a syncpt also triggering the problem.) This patch reverts my suggestion in commit e24165537312 ("dma-buf/sync_file: only enable fence signalling on poll()") to use a single bit in the shared dma-fence and restores the sync_file->flags for tracking the bits individually. Reported-by: Gustavo Padovan Fixes: f1e8c67123cf ("dma-buf/sw-sync: Use an rbtree to sort fences in the timeline") Fixes: e9083420bbac ("drm: introduce sync objects (v4)") Signed-off-by: Chris Wilson Signed-off-by: Gustavo Padovan Link: http://patchwork.freedesktop.org/patch/msgid/20170728212951.7818-1-chris@chris-wilson.co.uk [astrachan: rediffed against changed context lines in 4.9] Bug: 79383895 Change-Id: If98fa920693045fdab21886960657bbe8ef550c0 Signed-off-by: Alistair Strachan --- drivers/dma-buf/sync_file.c | 5 +++-- include/linux/sync_file.h | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index c835f6216922..e16849fd89aa 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -279,7 +279,7 @@ static void sync_file_free(struct kref *kref) struct sync_file *sync_file = container_of(kref, struct sync_file, kref); - if (test_bit(POLL_ENABLED, &sync_file->fence->flags)) + if (test_bit(POLL_ENABLED, &sync_file->flags)) fence_remove_callback(sync_file->fence, &sync_file->cb); fence_put(sync_file->fence); kfree(sync_file); @@ -299,7 +299,8 @@ static unsigned int sync_file_poll(struct file *file, poll_table *wait) poll_wait(file, &sync_file->wq, wait); - if (!test_and_set_bit(POLL_ENABLED, &sync_file->fence->flags)) { + if (list_empty(&sync_file->cb.node) && + !test_and_set_bit(POLL_ENABLED, &sync_file->flags)) { if (fence_add_callback(sync_file->fence, &sync_file->cb, fence_check_cb_func) < 0) wake_up_all(&sync_file->wq); diff --git a/include/linux/sync_file.h b/include/linux/sync_file.h index aa17ccfc2f57..35ec6c45e190 100644 --- a/include/linux/sync_file.h +++ b/include/linux/sync_file.h @@ -40,12 +40,13 @@ struct sync_file { #endif wait_queue_head_t wq; + unsigned long flags; struct fence *fence; struct fence_cb cb; }; -#define POLL_ENABLED FENCE_FLAG_USER_BITS +#define POLL_ENABLED 0 struct sync_file *sync_file_create(struct fence *fence); struct fence *sync_file_get_fence(int fd); -- GitLab From 7ef5d1244631b75727ae8fdde40cb6160b900b5d Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Fri, 13 Apr 2018 11:26:24 -0700 Subject: [PATCH 227/855] msm: camera: isp: Add support for BUS driver version 175 This change adds new enum, struct and file changes to support the three new FULL/DS4/DS16 display output streams added to IFE in version 175 HW. Change-Id: I01acd4e6bd6fcdc633b24858e48600d63f9e27c3 Signed-off-by: Harsh Shah Signed-off-by: Venkat Chinta Signed-off-by: Vishalsingh Hajeri --- .../bindings/media/video/msm-cam-vfe.txt | 2 +- .../msm/camera/cam_isp/cam_isp_context.h | 4 +- .../cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile | 2 +- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 2 +- .../isp_hw/vfe_hw/{vfe170 => vfe17x}/Makefile | 2 +- .../vfe_hw/{vfe170 => vfe17x}/cam_vfe170.h | 0 .../isp_hw/vfe_hw/vfe17x/cam_vfe175.h | 962 ++++++++++++++++++ .../cam_vfe170.c => vfe17x/cam_vfe17x.c} | 31 +- .../{vfe170 => vfe17x}/cam_vfe_lite170.c | 0 .../{vfe170 => vfe17x}/cam_vfe_lite170.h | 0 .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 60 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h | 7 +- include/uapi/media/cam_isp_ife.h | 6 +- 13 files changed, 1050 insertions(+), 28 deletions(-) rename drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/{vfe170 => vfe17x}/Makefile (94%) rename drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/{vfe170 => vfe17x}/cam_vfe170.h (100%) create mode 100644 drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h rename drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/{vfe170/cam_vfe170.c => vfe17x/cam_vfe17x.c} (54%) rename drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/{vfe170 => vfe17x}/cam_vfe_lite170.c (100%) rename drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/{vfe170 => vfe17x}/cam_vfe_lite170.h (100%) diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt index 99f2c7a0be35..47620bf0cb39 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt @@ -17,7 +17,7 @@ Required properties: Usage: required Value type: Definition: Should specify the compatibility string for matching the - driver. e.g. "qcom,vfe170", "qcom,vfe-lite170". + driver. e.g. "qcom,vfe175", "qcom,vfe170", "qcom,vfe-lite175", "qcom,vfe-lite170". - cell-index Usage: required diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h index a939f2d80b34..79d94807bed5 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h @@ -23,9 +23,9 @@ /* * Maximum hw resource - This number is based on the maximum * output port resource. The current maximum resource number - * is 20. + * is 24. */ -#define CAM_ISP_CTX_RES_MAX 20 +#define CAM_ISP_CTX_RES_MAX 24 /* * Maximum configuration entry size - This is based on the diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile index 5a67efab713e..1fbb236b4b9f 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile @@ -12,4 +12,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_h obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_soc.o cam_vfe_dev.o cam_vfe_core.o -obj-$(CONFIG_SPECTRA_CAMERA) += vfe_bus/ vfe_top/ vfe170/ \ No newline at end of file +obj-$(CONFIG_SPECTRA_CAMERA) += vfe_bus/ vfe_top/ vfe17x/ \ No newline at end of file diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index fd38a964faf6..d25dec8850e2 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -38,7 +38,7 @@ static uint32_t camif_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { static uint32_t camif_irq_err_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { 0x0003FC00, - 0x0FFF7EBC, + 0xEFFF7EBC, }; static uint32_t rdi_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile similarity index 94% rename from drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile rename to drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile index 39a56036d3b6..db41e4d89e47 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile @@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_h ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw -obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe170.o cam_vfe_lite170.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe17x.o cam_vfe_lite170.o diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h similarity index 100% rename from drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h rename to drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h new file mode 100644 index 000000000000..a72a9774863b --- /dev/null +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h @@ -0,0 +1,962 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CAM_VFE175_H_ +#define _CAM_VFE175_H_ + +#include "cam_vfe_camif_ver2.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe175_top_irq_reg_set[2] = { + { + .mask_reg_offset = 0x0000005C, + .clear_reg_offset = 0x00000064, + .status_reg_offset = 0x0000006C, + }, + { + .mask_reg_offset = 0x00000060, + .clear_reg_offset = 0x00000068, + .status_reg_offset = 0x00000070, + }, +}; + +static struct cam_irq_controller_reg_info vfe175_top_irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe175_top_irq_reg_set, + .global_clear_offset = 0x00000058, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_camif_ver2_reg vfe175_camif_reg = { + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_camif_reg_data vfe_175_camif_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0xEFFF7E80, +}; + +static struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_175_reg = { + .reset = 0x0000001C, + .cgc_ovd = 0x0000002C, + .enable = 0x00000040, +}; + +static struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_175_reg = { + .reset = 0x00000020, + .cgc_ovd = 0x00000030, + .enable = 0x00000044, +}; + +static struct cam_vfe_top_ver2_reg_offset_module_ctrl color_175_reg = { + .reset = 0x00000024, + .cgc_ovd = 0x00000034, + .enable = 0x00000048, +}; + +static struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_175_reg = { + .reset = 0x00000028, + .cgc_ovd = 0x00000038, + .enable = 0x0000004C, +}; + +static struct cam_vfe_top_ver2_reg_offset_common vfe175_top_common_reg = { + .hw_version = 0x00000000, + .hw_capability = 0x00000004, + .lens_feature = 0x00000008, + .stats_feature = 0x0000000C, + .color_feature = 0x00000010, + .zoom_feature = 0x00000014, + .global_reset_cmd = 0x00000018, + .module_ctrl = { + &lens_175_reg, + &stats_175_reg, + &color_175_reg, + &zoom_175_reg, + }, + .bus_cgc_ovd = 0x0000003C, + .core_cfg = 0x00000050, + .three_D_cfg = 0x00000054, + .violation_status = 0x0000007C, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_ver2_reg vfe175_rdi_reg = { + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_rdi_0_data = { + .reg_update_cmd_data = 0x2, + .sof_irq_mask = 0x8000000, + .reg_update_irq_mask = 0x20, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_rdi_1_data = { + .reg_update_cmd_data = 0x4, + .sof_irq_mask = 0x10000000, + .reg_update_irq_mask = 0x40, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_rdi_2_data = { + .reg_update_cmd_data = 0x8, + .sof_irq_mask = 0x20000000, + .reg_update_irq_mask = 0x80, +}; + +static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = { + .common_reg = &vfe175_top_common_reg, + .camif_hw_info = { + .common_reg = &vfe175_top_common_reg, + .camif_reg = &vfe175_camif_reg, + .reg_data = &vfe_175_camif_reg_data, + }, + .rdi_hw_info = { + .common_reg = &vfe175_top_common_reg, + .rdi_reg = &vfe175_rdi_reg, + .reg_data = { + &vfe_175_rdi_0_data, + &vfe_175_rdi_1_data, + &vfe_175_rdi_2_data, + NULL, + }, + }, + .mux_type = { + CAM_VFE_CAMIF_VER_2_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe175_bus_irq_reg[3] = { + { + .mask_reg_offset = 0x00002044, + .clear_reg_offset = 0x00002050, + .status_reg_offset = 0x0000205C, + }, + { + .mask_reg_offset = 0x00002048, + .clear_reg_offset = 0x00002054, + .status_reg_offset = 0x00002060, + }, + { + .mask_reg_offset = 0x0000204C, + .clear_reg_offset = 0x00002058, + .status_reg_offset = 0x00002064, + }, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client + vfe175_ubwc_regs_client_3 = { + .tile_cfg = 0x0000252C, + .h_init = 0x00002530, + .v_init = 0x00002534, + .meta_addr = 0x00002538, + .meta_offset = 0x0000253C, + .meta_stride = 0x00002540, + .mode_cfg = 0x00002544, + .bw_limit = 0x000025A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client + vfe175_ubwc_regs_client_4 = { + .tile_cfg = 0x0000262C, + .h_init = 0x00002630, + .v_init = 0x00002634, + .meta_addr = 0x00002638, + .meta_offset = 0x0000263C, + .meta_stride = 0x00002640, + .mode_cfg = 0x00002644, + .bw_limit = 0x000026A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client + vfe175_ubwc_regs_client_20 = { + .tile_cfg = 0x0000362C, + .h_init = 0x00003630, + .v_init = 0x00003634, + .meta_addr = 0x00003638, + .meta_offset = 0x0000363C, + .meta_stride = 0x00003640, + .mode_cfg = 0x00003644, + .bw_limit = 0x000036A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client + vfe175_ubwc_regs_client_21 = { + .tile_cfg = 0x0000372C, + .h_init = 0x00003730, + .v_init = 0x00003734, + .meta_addr = 0x00003738, + .meta_offset = 0x0000373C, + .meta_stride = 0x00003740, + .mode_cfg = 0x00003744, + .bw_limit = 0x000037A0, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe175_bus_hw_info = { + .common_reg = { + .hw_version = 0x00002000, + .hw_capability = 0x00002004, + .sw_reset = 0x00002008, + .cgc_ovd = 0x0000200C, + .pwr_iso_cfg = 0x000020CC, + .dual_master_comp_cfg = 0x00002028, + .irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe175_bus_irq_reg, + .global_clear_offset = 0x00002068, + .global_clear_bitmask = 0x00000001, + }, + .comp_error_status = 0x0000206C, + .comp_ovrwr_status = 0x00002070, + .dual_comp_error_status = 0x00002074, + .dual_comp_ovrwr_status = 0x00002078, + .addr_sync_cfg = 0x0000207C, + .addr_sync_frame_hdr = 0x00002080, + .addr_sync_no_sync = 0x00002084, + }, + .num_client = 24, + .bus_client_reg = { + /* BUS Client 0 */ + { + .status0 = 0x00002200, + .status1 = 0x00002204, + .cfg = 0x00002208, + .header_addr = 0x0000220C, + .header_cfg = 0x00002210, + .image_addr = 0x00002214, + .image_addr_offset = 0x00002218, + .buffer_width_cfg = 0x0000221C, + .buffer_height_cfg = 0x00002220, + .packer_cfg = 0x00002224, + .stride = 0x00002228, + .irq_subsample_period = 0x00002248, + .irq_subsample_pattern = 0x0000224C, + .framedrop_period = 0x00002250, + .framedrop_pattern = 0x00002254, + .frame_inc = 0x00002258, + .burst_limit = 0x0000225C, + .ubwc_regs = NULL, + }, + /* BUS Client 1 */ + { + .status0 = 0x00002300, + .status1 = 0x00002304, + .cfg = 0x00002308, + .header_addr = 0x0000230C, + .header_cfg = 0x00002310, + .image_addr = 0x00002314, + .image_addr_offset = 0x00002318, + .buffer_width_cfg = 0x0000231C, + .buffer_height_cfg = 0x00002320, + .packer_cfg = 0x00002324, + .stride = 0x00002328, + .irq_subsample_period = 0x00002348, + .irq_subsample_pattern = 0x0000234C, + .framedrop_period = 0x00002350, + .framedrop_pattern = 0x00002354, + .frame_inc = 0x00002358, + .burst_limit = 0x0000235C, + .ubwc_regs = NULL, + }, + /* BUS Client 2 */ + { + .status0 = 0x00002400, + .status1 = 0x00002404, + .cfg = 0x00002408, + .header_addr = 0x0000240C, + .header_cfg = 0x00002410, + .image_addr = 0x00002414, + .image_addr_offset = 0x00002418, + .buffer_width_cfg = 0x0000241C, + .buffer_height_cfg = 0x00002420, + .packer_cfg = 0x00002424, + .stride = 0x00002428, + .irq_subsample_period = 0x00002448, + .irq_subsample_pattern = 0x0000244C, + .framedrop_period = 0x00002450, + .framedrop_pattern = 0x00002454, + .frame_inc = 0x00002458, + .burst_limit = 0x0000245C, + .ubwc_regs = NULL, + }, + /* BUS Client 3 */ + { + .status0 = 0x00002500, + .status1 = 0x00002504, + .cfg = 0x00002508, + .header_addr = 0x0000250C, + .header_cfg = 0x00002510, + .image_addr = 0x00002514, + .image_addr_offset = 0x00002518, + .buffer_width_cfg = 0x0000251C, + .buffer_height_cfg = 0x00002520, + .packer_cfg = 0x00002524, + .stride = 0x00002528, + .irq_subsample_period = 0x00002548, + .irq_subsample_pattern = 0x0000254C, + .framedrop_period = 0x00002550, + .framedrop_pattern = 0x00002554, + .frame_inc = 0x00002558, + .burst_limit = 0x0000255C, + .ubwc_regs = &vfe175_ubwc_regs_client_3, + }, + /* BUS Client 4 */ + { + .status0 = 0x00002600, + .status1 = 0x00002604, + .cfg = 0x00002608, + .header_addr = 0x0000260C, + .header_cfg = 0x00002610, + .image_addr = 0x00002614, + .image_addr_offset = 0x00002618, + .buffer_width_cfg = 0x0000261C, + .buffer_height_cfg = 0x00002620, + .packer_cfg = 0x00002624, + .stride = 0x00002628, + .irq_subsample_period = 0x00002648, + .irq_subsample_pattern = 0x0000264C, + .framedrop_period = 0x00002650, + .framedrop_pattern = 0x00002654, + .frame_inc = 0x00002658, + .burst_limit = 0x0000265C, + .ubwc_regs = &vfe175_ubwc_regs_client_4, + }, + /* BUS Client 5 */ + { + .status0 = 0x00002700, + .status1 = 0x00002704, + .cfg = 0x00002708, + .header_addr = 0x0000270C, + .header_cfg = 0x00002710, + .image_addr = 0x00002714, + .image_addr_offset = 0x00002718, + .buffer_width_cfg = 0x0000271C, + .buffer_height_cfg = 0x00002720, + .packer_cfg = 0x00002724, + .stride = 0x00002728, + .irq_subsample_period = 0x00002748, + .irq_subsample_pattern = 0x0000274C, + .framedrop_period = 0x00002750, + .framedrop_pattern = 0x00002754, + .frame_inc = 0x00002758, + .burst_limit = 0x0000275C, + .ubwc_regs = NULL, + }, + /* BUS Client 6 */ + { + .status0 = 0x00002800, + .status1 = 0x00002804, + .cfg = 0x00002808, + .header_addr = 0x0000280C, + .header_cfg = 0x00002810, + .image_addr = 0x00002814, + .image_addr_offset = 0x00002818, + .buffer_width_cfg = 0x0000281C, + .buffer_height_cfg = 0x00002820, + .packer_cfg = 0x00002824, + .stride = 0x00002828, + .irq_subsample_period = 0x00002848, + .irq_subsample_pattern = 0x0000284C, + .framedrop_period = 0x00002850, + .framedrop_pattern = 0x00002854, + .frame_inc = 0x00002858, + .burst_limit = 0x0000285C, + .ubwc_regs = NULL, + }, + /* BUS Client 7 */ + { + .status0 = 0x00002900, + .status1 = 0x00002904, + .cfg = 0x00002908, + .header_addr = 0x0000290C, + .header_cfg = 0x00002910, + .image_addr = 0x00002914, + .image_addr_offset = 0x00002918, + .buffer_width_cfg = 0x0000291C, + .buffer_height_cfg = 0x00002920, + .packer_cfg = 0x00002924, + .stride = 0x00002928, + .irq_subsample_period = 0x00002948, + .irq_subsample_pattern = 0x0000294C, + .framedrop_period = 0x00002950, + .framedrop_pattern = 0x00002954, + .frame_inc = 0x00002958, + .burst_limit = 0x0000295C, + .ubwc_regs = NULL, + }, + /* BUS Client 8 */ + { + .status0 = 0x00002A00, + .status1 = 0x00002A04, + .cfg = 0x00002A08, + .header_addr = 0x00002A0C, + .header_cfg = 0x00002A10, + .image_addr = 0x00002A14, + .image_addr_offset = 0x00002A18, + .buffer_width_cfg = 0x00002A1C, + .buffer_height_cfg = 0x00002A20, + .packer_cfg = 0x00002A24, + .stride = 0x00002A28, + .irq_subsample_period = 0x00002A48, + .irq_subsample_pattern = 0x00002A4C, + .framedrop_period = 0x00002A50, + .framedrop_pattern = 0x00002A54, + .frame_inc = 0x00002A58, + .burst_limit = 0x00002A5C, + .ubwc_regs = NULL, + }, + /* BUS Client 9 */ + { + .status0 = 0x00002B00, + .status1 = 0x00002B04, + .cfg = 0x00002B08, + .header_addr = 0x00002B0C, + .header_cfg = 0x00002B10, + .image_addr = 0x00002B14, + .image_addr_offset = 0x00002B18, + .buffer_width_cfg = 0x00002B1C, + .buffer_height_cfg = 0x00002B20, + .packer_cfg = 0x00002B24, + .stride = 0x00002B28, + .irq_subsample_period = 0x00002B48, + .irq_subsample_pattern = 0x00002B4C, + .framedrop_period = 0x00002B50, + .framedrop_pattern = 0x00002B54, + .frame_inc = 0x00002B58, + .burst_limit = 0x00002B5C, + .ubwc_regs = NULL, + }, + /* BUS Client 10 */ + { + .status0 = 0x00002C00, + .status1 = 0x00002C04, + .cfg = 0x00002C08, + .header_addr = 0x00002C0C, + .header_cfg = 0x00002C10, + .image_addr = 0x00002C14, + .image_addr_offset = 0x00002C18, + .buffer_width_cfg = 0x00002C1C, + .buffer_height_cfg = 0x00002C20, + .packer_cfg = 0x00002C24, + .stride = 0x00002C28, + .irq_subsample_period = 0x00002C48, + .irq_subsample_pattern = 0x00002C4C, + .framedrop_period = 0x00002C50, + .framedrop_pattern = 0x00002C54, + .frame_inc = 0x00002C58, + .burst_limit = 0x00002C5C, + .ubwc_regs = NULL, + }, + /* BUS Client 11 */ + { + .status0 = 0x00002D00, + .status1 = 0x00002D04, + .cfg = 0x00002D08, + .header_addr = 0x00002D0C, + .header_cfg = 0x00002D10, + .image_addr = 0x00002D14, + .image_addr_offset = 0x00002D18, + .buffer_width_cfg = 0x00002D1C, + .buffer_height_cfg = 0x00002D20, + .packer_cfg = 0x00002D24, + .stride = 0x00002D28, + .irq_subsample_period = 0x00002D48, + .irq_subsample_pattern = 0x00002D4C, + .framedrop_period = 0x00002D50, + .framedrop_pattern = 0x00002D54, + .frame_inc = 0x00002D58, + .burst_limit = 0x00002D5C, + .ubwc_regs = NULL, + }, + /* BUS Client 12 */ + { + .status0 = 0x00002E00, + .status1 = 0x00002E04, + .cfg = 0x00002E08, + .header_addr = 0x00002E0C, + .header_cfg = 0x00002E10, + .image_addr = 0x00002E14, + .image_addr_offset = 0x00002E18, + .buffer_width_cfg = 0x00002E1C, + .buffer_height_cfg = 0x00002E20, + .packer_cfg = 0x00002E24, + .stride = 0x00002E28, + .irq_subsample_period = 0x00002E48, + .irq_subsample_pattern = 0x00002E4C, + .framedrop_period = 0x00002E50, + .framedrop_pattern = 0x00002E54, + .frame_inc = 0x00002E58, + .burst_limit = 0x00002E5C, + .ubwc_regs = NULL, + }, + /* BUS Client 13 */ + { + .status0 = 0x00002F00, + .status1 = 0x00002F04, + .cfg = 0x00002F08, + .header_addr = 0x00002F0C, + .header_cfg = 0x00002F10, + .image_addr = 0x00002F14, + .image_addr_offset = 0x00002F18, + .buffer_width_cfg = 0x00002F1C, + .buffer_height_cfg = 0x00002F20, + .packer_cfg = 0x00002F24, + .stride = 0x00002F28, + .irq_subsample_period = 0x00002F48, + .irq_subsample_pattern = 0x00002F4C, + .framedrop_period = 0x00002F50, + .framedrop_pattern = 0x00002F54, + .frame_inc = 0x00002F58, + .burst_limit = 0x00002F5C, + .ubwc_regs = NULL, + }, + /* BUS Client 14 */ + { + .status0 = 0x00003000, + .status1 = 0x00003004, + .cfg = 0x00003008, + .header_addr = 0x0000300C, + .header_cfg = 0x00003010, + .image_addr = 0x00003014, + .image_addr_offset = 0x00003018, + .buffer_width_cfg = 0x0000301C, + .buffer_height_cfg = 0x00003020, + .packer_cfg = 0x00003024, + .stride = 0x00003028, + .irq_subsample_period = 0x00003048, + .irq_subsample_pattern = 0x0000304C, + .framedrop_period = 0x00003050, + .framedrop_pattern = 0x00003054, + .frame_inc = 0x00003058, + .burst_limit = 0x0000305C, + .ubwc_regs = NULL, + }, + /* BUS Client 15 */ + { + .status0 = 0x00003100, + .status1 = 0x00003104, + .cfg = 0x00003108, + .header_addr = 0x0000310C, + .header_cfg = 0x00003110, + .image_addr = 0x00003114, + .image_addr_offset = 0x00003118, + .buffer_width_cfg = 0x0000311C, + .buffer_height_cfg = 0x00003120, + .packer_cfg = 0x00003124, + .stride = 0x00003128, + .irq_subsample_period = 0x00003148, + .irq_subsample_pattern = 0x0000314C, + .framedrop_period = 0x00003150, + .framedrop_pattern = 0x00003154, + .frame_inc = 0x00003158, + .burst_limit = 0x0000315C, + .ubwc_regs = NULL, + }, + /* BUS Client 16 */ + { + .status0 = 0x00003200, + .status1 = 0x00003204, + .cfg = 0x00003208, + .header_addr = 0x0000320C, + .header_cfg = 0x00003210, + .image_addr = 0x00003214, + .image_addr_offset = 0x00003218, + .buffer_width_cfg = 0x0000321C, + .buffer_height_cfg = 0x00003220, + .packer_cfg = 0x00003224, + .stride = 0x00003228, + .irq_subsample_period = 0x00003248, + .irq_subsample_pattern = 0x0000324C, + .framedrop_period = 0x00003250, + .framedrop_pattern = 0x00003254, + .frame_inc = 0x00003258, + .burst_limit = 0x0000325C, + .ubwc_regs = NULL, + }, + /* BUS Client 17 */ + { + .status0 = 0x00003300, + .status1 = 0x00003304, + .cfg = 0x00003308, + .header_addr = 0x0000330C, + .header_cfg = 0x00003310, + .image_addr = 0x00003314, + .image_addr_offset = 0x00003318, + .buffer_width_cfg = 0x0000331C, + .buffer_height_cfg = 0x00003320, + .packer_cfg = 0x00003324, + .stride = 0x00003328, + .irq_subsample_period = 0x00003348, + .irq_subsample_pattern = 0x0000334C, + .framedrop_period = 0x00003350, + .framedrop_pattern = 0x00003354, + .frame_inc = 0x00003358, + .burst_limit = 0x0000335C, + .ubwc_regs = NULL, + }, + /* BUS Client 18 */ + { + .status0 = 0x00003400, + .status1 = 0x00003404, + .cfg = 0x00003408, + .header_addr = 0x0000340C, + .header_cfg = 0x00003410, + .image_addr = 0x00003414, + .image_addr_offset = 0x00003418, + .buffer_width_cfg = 0x0000341C, + .buffer_height_cfg = 0x00003420, + .packer_cfg = 0x00003424, + .stride = 0x00003428, + .irq_subsample_period = 0x00003448, + .irq_subsample_pattern = 0x0000344C, + .framedrop_period = 0x00003450, + .framedrop_pattern = 0x00003454, + .frame_inc = 0x00003458, + .burst_limit = 0x0000345C, + .ubwc_regs = NULL, + }, + /* BUS Client 19 */ + { + .status0 = 0x00003500, + .status1 = 0x00003504, + .cfg = 0x00003508, + .header_addr = 0x0000350C, + .header_cfg = 0x00003510, + .image_addr = 0x00003514, + .image_addr_offset = 0x00003518, + .buffer_width_cfg = 0x0000351C, + .buffer_height_cfg = 0x00003520, + .packer_cfg = 0x00003524, + .stride = 0x00003528, + .irq_subsample_period = 0x00003548, + .irq_subsample_pattern = 0x0000354C, + .framedrop_period = 0x00003550, + .framedrop_pattern = 0x00003554, + .frame_inc = 0x00003558, + .burst_limit = 0x0000355C, + .ubwc_regs = NULL, + }, + /* BUS Client 20 */ + { + .status0 = 0x00003600, + .status1 = 0x00003604, + .cfg = 0x00003608, + .header_addr = 0x0000360C, + .header_cfg = 0x00003610, + .image_addr = 0x00003614, + .image_addr_offset = 0x00003618, + .buffer_width_cfg = 0x0000361C, + .buffer_height_cfg = 0x00003620, + .packer_cfg = 0x00003624, + .stride = 0x00003628, + .irq_subsample_period = 0x00003648, + .irq_subsample_pattern = 0x0000364C, + .framedrop_period = 0x00003650, + .framedrop_pattern = 0x00003654, + .frame_inc = 0x00003658, + .burst_limit = 0x0000365C, + .ubwc_regs = &vfe175_ubwc_regs_client_20, + }, + /* BUS Client 21 */ + { + .status0 = 0x00003700, + .status1 = 0x00003704, + .cfg = 0x00003708, + .header_addr = 0x0000370C, + .header_cfg = 0x00003710, + .image_addr = 0x00003714, + .image_addr_offset = 0x00003718, + .buffer_width_cfg = 0x0000371C, + .buffer_height_cfg = 0x00003720, + .packer_cfg = 0x00003724, + .stride = 0x00003728, + .irq_subsample_period = 0x00003748, + .irq_subsample_pattern = 0x0000374C, + .framedrop_period = 0x00003750, + .framedrop_pattern = 0x00003754, + .frame_inc = 0x00003758, + .burst_limit = 0x0000375C, + .ubwc_regs = &vfe175_ubwc_regs_client_21, + }, + /* BUS Client 22 */ + { + .status0 = 0x00003800, + .status1 = 0x00003804, + .cfg = 0x00003808, + .header_addr = 0x0000380C, + .header_cfg = 0x00003810, + .image_addr = 0x00003814, + .image_addr_offset = 0x00003818, + .buffer_width_cfg = 0x0000381C, + .buffer_height_cfg = 0x00003820, + .packer_cfg = 0x00003824, + .stride = 0x00003828, + .irq_subsample_period = 0x00003848, + .irq_subsample_pattern = 0x0000384C, + .framedrop_period = 0x00003850, + .framedrop_pattern = 0x00003854, + .frame_inc = 0x00003858, + .burst_limit = 0x0000385C, + .ubwc_regs = NULL, + }, + /* BUS Client 23 */ + { + .status0 = 0x00003900, + .status1 = 0x00003904, + .cfg = 0x00003908, + .header_addr = 0x0000390C, + .header_cfg = 0x00003910, + .image_addr = 0x00003914, + .image_addr_offset = 0x00003918, + .buffer_width_cfg = 0x0000391C, + .buffer_height_cfg = 0x00003920, + .packer_cfg = 0x00003924, + .stride = 0x00003928, + .irq_subsample_period = 0x00003948, + .irq_subsample_pattern = 0x0000394C, + .framedrop_period = 0x00003950, + .framedrop_pattern = 0x00003954, + .frame_inc = 0x00003958, + .burst_limit = 0x0000395C, + .ubwc_regs = NULL, + }, + }, + .comp_grp_reg = { + /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ + { + .comp_mask = 0x00002010, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ + { + .comp_mask = 0x00002014, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ + { + .comp_mask = 0x00002018, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ + { + .comp_mask = 0x0000201C, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ + { + .comp_mask = 0x00002020, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ + { + .comp_mask = 0x00002024, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ + { + .comp_mask = 0x0000202C, + .addr_sync_mask = 0x00002088, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ + { + .comp_mask = 0x00002030, + .addr_sync_mask = 0x0000208C, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ + { + .comp_mask = 0x00002034, + .addr_sync_mask = 0x00002090, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ + { + .comp_mask = 0x00002038, + .addr_sync_mask = 0x00002094, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ + { + .comp_mask = 0x0000203C, + .addr_sync_mask = 0x00002098, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ + { + .comp_mask = 0x00002040, + .addr_sync_mask = 0x0000209C, + }, + }, + .num_out = 21, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FD, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_PDAF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, + .max_width = 1920, + .max_height = 1080, + }, + }, +}; + +static struct cam_vfe_hw_info cam_vfe175_hw_info = { + .irq_reg_info = &vfe175_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_2_0, + .bus_hw_info = &vfe175_bus_hw_info, + + .top_version = CAM_VFE_TOP_VER_2_0, + .top_hw_info = &vfe175_top_hw_info, + + .camif_version = CAM_VFE_CAMIF_VER_2_0, + .camif_reg = &vfe175_camif_reg, + +}; + +#endif /* _CAM_VFE175_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c similarity index 54% rename from drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c rename to drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c index 0af32ad5d546..6f0fe47d448a 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,40 +12,45 @@ #include #include "cam_vfe170.h" +#include "cam_vfe175.h" #include "cam_vfe_hw_intf.h" #include "cam_vfe_core.h" #include "cam_vfe_dev.h" -static const struct of_device_id cam_vfe170_dt_match[] = { +static const struct of_device_id cam_vfe_dt_match[] = { { .compatible = "qcom,vfe170", .data = &cam_vfe170_hw_info, }, + { + .compatible = "qcom,vfe175", + .data = &cam_vfe175_hw_info, + }, {} }; -MODULE_DEVICE_TABLE(of, cam_vfe170_dt_match); +MODULE_DEVICE_TABLE(of, cam_vfe_dt_match); -static struct platform_driver cam_vfe170_driver = { +static struct platform_driver cam_vfe_driver = { .probe = cam_vfe_probe, .remove = cam_vfe_remove, .driver = { - .name = "cam_vfe170", + .name = "cam_vfe", .owner = THIS_MODULE, - .of_match_table = cam_vfe170_dt_match, + .of_match_table = cam_vfe_dt_match, }, }; -static int __init cam_vfe170_init_module(void) +static int __init cam_vfe_init_module(void) { - return platform_driver_register(&cam_vfe170_driver); + return platform_driver_register(&cam_vfe_driver); } -static void __exit cam_vfe170_exit_module(void) +static void __exit cam_vfe_exit_module(void) { - platform_driver_unregister(&cam_vfe170_driver); + platform_driver_unregister(&cam_vfe_driver); } -module_init(cam_vfe170_init_module); -module_exit(cam_vfe170_exit_module); -MODULE_DESCRIPTION("CAM VFE170 driver"); +module_init(cam_vfe_init_module); +module_exit(cam_vfe_exit_module); +MODULE_DESCRIPTION("CAM VFE17X driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite170.c similarity index 100% rename from drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c rename to drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite170.c diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite170.h similarity index 100% rename from drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h rename to drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite170.h diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 3c37b83a2256..12e9125d8fa4 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -40,7 +40,8 @@ static const char drv_name[] = "vfe_bus"; #define CAM_VFE_RDI_BUS_DEFAULT_STRIDE 0xFF01 #define CAM_VFE_BUS_INTRA_CLIENT_MASK 0x3 #define CAM_VFE_BUS_ADDR_SYNC_INTRA_CLIENT_SHIFT 8 -#define CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL 0xFFFFF +#define CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL \ + ((1 << CAM_VFE_BUS_VER2_MAX_CLIENTS) - 1) #define ALIGNUP(value, alignment) \ ((value + alignment - 1) / alignment * alignment) @@ -375,6 +376,9 @@ static bool cam_vfe_bus_can_be_secure(uint32_t out_type) case CAM_VFE_BUS_VER2_VFE_OUT_RDI0: case CAM_VFE_BUS_VER2_VFE_OUT_RDI1: case CAM_VFE_BUS_VER2_VFE_OUT_RDI2: + case CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP: + case CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP: + case CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP: return true; case CAM_VFE_BUS_VER2_VFE_OUT_PDAF: @@ -434,6 +438,12 @@ static enum cam_vfe_bus_ver2_vfe_out_type return CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS; case CAM_ISP_IFE_OUT_RES_STATS_IHIST: return CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST; + case CAM_ISP_IFE_OUT_RES_FULL_DISP: + return CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP; + case CAM_ISP_IFE_OUT_RES_DS4_DISP: + return CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP; + case CAM_ISP_IFE_OUT_RES_DS16_DISP: + return CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP; default: return CAM_VFE_BUS_VER2_VFE_OUT_MAX; } @@ -474,6 +484,7 @@ static int cam_vfe_bus_get_num_wm( } break; case CAM_VFE_BUS_VER2_VFE_OUT_FULL: + case CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP: switch (format) { case CAM_FORMAT_NV21: case CAM_FORMAT_NV12: @@ -503,7 +514,9 @@ static int cam_vfe_bus_get_num_wm( } break; case CAM_VFE_BUS_VER2_VFE_OUT_DS4: + case CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP: case CAM_VFE_BUS_VER2_VFE_OUT_DS16: + case CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP: switch (format) { case CAM_FORMAT_PD8: case CAM_FORMAT_PD10: @@ -752,6 +765,37 @@ static int cam_vfe_bus_get_wm_idx( break; } break; + case CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 20; + break; + case PLANE_C: + wm_idx = 21; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 22; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 23; + break; + default: + break; + } + break; + default: break; } @@ -764,7 +808,7 @@ static enum cam_vfe_bus_packer_format { switch (out_fmt) { case CAM_FORMAT_NV21: - if (wm_index == 4 || wm_index == 6) + if ((wm_index == 4) || (wm_index == 6) || (wm_index == 21)) return PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN; case CAM_FORMAT_NV12: case CAM_FORMAT_UBWC_NV12: @@ -895,9 +939,13 @@ static int cam_vfe_bus_acquire_wm( rsrc_data->format); return -EINVAL; } - } else if (rsrc_data->index < 5 || - rsrc_data->index == 7 || rsrc_data->index == 8) { - /* Write master 3, 4 - for Full OUT , 7-8 FD OUT */ + } else if ((rsrc_data->index < 5) || + (rsrc_data->index == 7) || (rsrc_data->index == 8) || + (rsrc_data->index == 20) || (rsrc_data->index == 21)) { + /* + * Write master 3, 4 - for Full OUT , 7-8 FD OUT, + * WM 20-21 = FULL_DISP + */ switch (rsrc_data->format) { case CAM_FORMAT_UBWC_NV12_4R: rsrc_data->en_ubwc = 1; @@ -977,7 +1025,7 @@ static int cam_vfe_bus_acquire_wm( return -EINVAL; } rsrc_data->en_cfg = 0x1; - } else if (rsrc_data->index >= 11) { + } else if ((rsrc_data->index >= 11) && (rsrc_data->index < 20)) { /* Write master 11-19 stats */ rsrc_data->width = 0; rsrc_data->height = 0; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h index 5a12f745e328..c001eef72bc4 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -16,7 +16,7 @@ #include "cam_irq_controller.h" #include "cam_vfe_bus.h" -#define CAM_VFE_BUS_VER2_MAX_CLIENTS 20 +#define CAM_VFE_BUS_VER2_MAX_CLIENTS 24 enum cam_vfe_bus_ver2_vfe_core_id { CAM_VFE_BUS_VER2_VFE_CORE_0, @@ -60,6 +60,9 @@ enum cam_vfe_bus_ver2_vfe_out_type { CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, + CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, + CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, CAM_VFE_BUS_VER2_VFE_OUT_MAX, }; diff --git a/include/uapi/media/cam_isp_ife.h b/include/uapi/media/cam_isp_ife.h index f5e72813fc0d..dd03ecca2884 100644 --- a/include/uapi/media/cam_isp_ife.h +++ b/include/uapi/media/cam_isp_ife.h @@ -23,7 +23,11 @@ #define CAM_ISP_IFE_OUT_RES_STATS_RS (CAM_ISP_IFE_OUT_RES_BASE + 16) #define CAM_ISP_IFE_OUT_RES_STATS_CS (CAM_ISP_IFE_OUT_RES_BASE + 17) #define CAM_ISP_IFE_OUT_RES_STATS_IHIST (CAM_ISP_IFE_OUT_RES_BASE + 18) -#define CAM_ISP_IFE_OUT_RES_MAX (CAM_ISP_IFE_OUT_RES_BASE + 19) +#define CAM_ISP_IFE_OUT_RES_FULL_DISP (CAM_ISP_IFE_OUT_RES_BASE + 19) +#define CAM_ISP_IFE_OUT_RES_DS4_DISP (CAM_ISP_IFE_OUT_RES_BASE + 20) +#define CAM_ISP_IFE_OUT_RES_DS16_DISP (CAM_ISP_IFE_OUT_RES_BASE + 21) + +#define CAM_ISP_IFE_OUT_RES_MAX (CAM_ISP_IFE_OUT_RES_BASE + 22) /* IFE input port resource type (global unique) */ -- GitLab From ec092457a6300f06d826b1fcc2aa26a82c6b3ebc Mon Sep 17 00:00:00 2001 From: Santosh Mardi Date: Tue, 15 May 2018 12:05:04 +0530 Subject: [PATCH 228/855] ARM: dts: msm: add support of 960MHz for sdm439 target Add support for 960MHz clock for the perf cluster on sdm439 target. Change-Id: I9da6db8e3e7af27abb4cefc1257182ffabadbe19 Signed-off-by: Santosh Mardi --- arch/arm64/boot/dts/qcom/sdm439.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi index 2df468fdc50d..15a354214b97 100644 --- a/arch/arm64/boot/dts/qcom/sdm439.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi @@ -49,6 +49,7 @@ qcom,governor-per-policy; qcom,cpufreq-table-0 = + < 960000 >, < 1305600 >, < 1497600 >, < 1708800 >, -- GitLab From 71ac4261d7c1fde8f569ac68c7959c830c07bc4e Mon Sep 17 00:00:00 2001 From: Cullum Baldwin Date: Mon, 7 May 2018 15:58:37 -0700 Subject: [PATCH 229/855] ARM: dts: msm: add camera support for sdm845-svr Add initial device tree support for camera on sdm845-svr Change-Id: Ia63e9cdf4784cbfaa1bf3b04fd62fc34f8137587 Signed-off-by: Cullum Baldwin --- .../dts/qcom/sdm845-camera-sensor-svr.dtsi | 479 ++++++++++++++++++ 1 file changed, 479 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi new file mode 100644 index 000000000000..d387f93cc115 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; + status = "ok"; + }; + + led_flash_rear_aux: qcom,camera-flash@1 { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; + status = "ok"; + }; + + led_flash_front: qcom,camera-flash@2 { + cell-index = <2>; + reg = <0x02 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash2>; + torch-source = <&pmi8998_torch2>; + switch-source = <&pmi8998_switch1>; + status = "ok"; + }; + + led_flash_iris: qcom,camera-flash@3 { + cell-index = <3>; + reg = <0x03 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash2>; + torch-source = <&pmi8998_torch2>; + switch-source = <&pmi8998_switch2>; + status = "ok"; + }; + + actuator_regulator: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "actuator_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <100>; + enable-active-high; + gpio = <&tlmm 27 0>; + vin-supply = <&pmi8998_bob>; + }; + + camera_rear_ldo: gpio-regulator@1 { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "camera_rear_ldo"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&pm8998_gpios 12 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_rear_dvdd_en_default>; + vin-supply = <&pm8998_s3>; + }; + + camera_ldo: gpio-regulator@2 { + compatible = "regulator-fixed"; + reg = <0x02 0x00>; + regulator-name = "camera_ldo"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm8998_gpios 9 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_dvdd_en_default>; + vin-supply = <&pm8998_s3>; + }; +}; + +&cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + shared-gpios = <9>; + pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend"; + pinctrl-0 = <&cam_res_mgr_active>; + pinctrl-1 = <&cam_res_mgr_suspend>; + }; + + actuator_rear: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_rear_aux: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_front: qcom,actuator@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + ois_rear: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + status = "ok"; + }; + + eeprom_rear: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0 2800000>; + rgltr-max-voltage = <0 3600000 1050000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 80 0>, + <&tlmm 79 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VANA0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&camera_ldo>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1050000 0 3312000 0 2800000>; + rgltr-max-voltage = <1050000 0 3600000 0 2800000>; + rgltr-load-current = <105000 0 80000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 9 0>, + <&tlmm 8 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VANA1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0 2800000>; + rgltr-max-voltage = <0 3600000 1050000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 28 0>, + <&tlmm 8 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + ois-src = <&ois_rear>; + eeprom-src = <&eeprom_rear>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&pm8998_l9>; + cam_vio-supply = <&pm8998_l8>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1704000 1200000>; + rgltr-max-voltage = <0 3600000 2928000 1248000>; + rgltr-load-current = <0 80000 105000 1200000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 8 0>, + <&tlmm 115 0>, + <&tlmm 95 0 >, + <&tlmm 97 0>; + gpio-reset = <1>; + gpio-vio = <2>; + gpio-vana = <3>; + gpio-vdig = <4>; + gpio-req-tbl-num = <0 1 2 3 4>; + gpio-req-tbl-flags = <1 0 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VIO", + "CAM_VANA", + "CAM_VDIG"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear_aux>; + led-flash-src = <&led_flash_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; + cam_vdig-supply = <&camera_ldo>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1050000 0 3312000 0>; + rgltr-max-voltage = <1050000 0 3600000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 9 0>, + <&tlmm 8 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VANA1"; + sensor-mode = <0>; + cci-master = <1>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + led-flash-src = <&led_flash_front>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&pm8998_lvs1>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1800000 0>; + rgltr-max-voltage = <0 3600000 1800000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 26 0>, + <&tlmm 132 0>, + <&tlmm 133 0>, + <&tlmm 90 0>, + <&tlmm 40 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vdig = <3>; + gpio-vio = <4>; + gpio-standby = <5>; + gpio-req-tbl-num = <0 1 2 3 4 5>; + gpio-req-tbl-flags = <1 0 0 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET2", + "CAM_VANA2", + "CAM_VDIG2", + "CAM_VIO2", + "CAM_STANDBY2"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + reg = <0x03>; + csiphy-sd-index = <3>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + led-flash-src = <&led_flash_iris>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0>; + rgltr-max-voltage = <0 3600000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_iris_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_iris_suspend>; + gpios = <&tlmm 16 0>, + <&tlmm 9 0>, + <&tlmm 8 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3", + "CAM_VANA1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; -- GitLab From b7edd12f5705e7c890efe7feed7c2eb98923af47 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Fri, 20 Apr 2018 16:17:58 -0700 Subject: [PATCH 230/855] msm: camera: uapi: Adds UBWC blob payload structure This change adds UBWC blob payload structure to enable userspace control over UWBC configuration. This will allow userspace payload and corresponding API to configure UBWC to remain consistent across different UBWC versions. Change-Id: I6f31d7ff9186666703277eb82aefaa8fb48f80e8 Signed-off-by: Venkat Chinta Signed-off-by: Vishalsingh Hajeri --- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 2 +- include/uapi/media/cam_defs.h | 49 +++++++++++++++++++ include/uapi/media/cam_isp.h | 7 +-- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 38a449796a18..4d6b1f467c6b 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -41,7 +41,7 @@ (CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON + 1) #define CAM_ISP_GENERIC_BLOB_TYPE_MAX \ - (CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG + 1) + (CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG + 1) static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = { CAM_ISP_HW_CMD_GET_HFR_UPDATE, diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h index e006463d2aa6..34a65599b558 100644 --- a/include/uapi/media/cam_defs.h +++ b/include/uapi/media/cam_defs.h @@ -43,6 +43,9 @@ #define CAM_CMD_BUF_GENERIC 0x9 #define CAM_CMD_BUF_LEGACY 0xA +/* UBWC API Version */ +#define CAM_UBWC_CFG_VERSION_1 1 + /** * enum flush_type_t - Identifies the various flush types * @@ -235,6 +238,34 @@ struct cam_plane_cfg { uint32_t v_init; }; +/** + * struct cam_ubwc_plane_cfg_v1 - UBWC Plane configuration info + * + * @port_type: Port Type + * @meta_stride: UBWC metadata stride + * @meta_size: UBWC metadata plane size + * @meta_offset: UBWC metadata offset + * @packer_config: UBWC packer config + * @mode_config_0: UBWC mode config 0 + * @mode_config_1: UBWC 3 mode config 1 + * @tile_config: UBWC tile config + * @h_init: UBWC horizontal initial coordinate in pixels + * @v_init: UBWC vertical initial coordinate in lines + * + */ +struct cam_ubwc_plane_cfg_v1 { + uint32_t port_type; + uint32_t meta_stride; + uint32_t meta_size; + uint32_t meta_offset; + uint32_t packer_config; + uint32_t mode_config_0; + uint32_t mode_config_1; + uint32_t tile_config; + uint32_t h_init; + uint32_t v_init; +}; + /** * struct cam_cmd_buf_desc - Command buffer descriptor * @@ -474,4 +505,22 @@ struct cam_flush_dev_cmd { int64_t req_id; }; +/** + * struct cam_ubwc_config - UBWC Configuration Payload + * + * @api_version: UBWC config api version + * @num_ports: Number of ports to be configured + * @ubwc_plane_config: Array of UBWC configurations per port + * Size [CAM_PACKET_MAX_PLANES - 1] per port + * as UBWC is supported on Y & C planes + * and therefore a max size of 2 planes + * + */ +struct cam_ubwc_config { + uint32_t api_version; + uint32_t num_ports; + struct cam_ubwc_plane_cfg_v1 + ubwc_plane_cfg[1][CAM_PACKET_MAX_PLANES - 1]; +}; + #endif /* __UAPI_CAM_DEFS_H__ */ diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index afd109fcb471..0f23e595fb19 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -84,9 +84,10 @@ #define CAM_ISP_DSP_MODE_ROUND 2 /* ISP Generic Cmd Buffer Blob types */ -#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG 0 -#define CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1 -#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG 2 +#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG 0 +#define CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1 +#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG 2 +#define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG 3 /* Query devices */ /** -- GitLab From 776c3918960bb83e8730632ec428995311a4c64c Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Mon, 23 Apr 2018 17:45:59 -0700 Subject: [PATCH 231/855] msm: camera: ife: Add bus write master UBWC config update This change allows handling updates to bus write master UBWC configuration that arrive as blob commands. It also adds compatibility checks to support older hardware. Change-Id: Ie62c8e230b426db06c216ee850bc7ea42abcde39 Signed-off-by: Venkat Chinta --- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 134 ++++ .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 2 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 1 + .../isp_hw/vfe_hw/vfe17x/cam_vfe170.h | 6 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe175.h | 20 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 577 +++++++++++++----- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h | 22 +- 7 files changed, 613 insertions(+), 149 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 4d6b1f467c6b..1e67d9db9cd1 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -47,6 +47,7 @@ static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = { CAM_ISP_HW_CMD_GET_HFR_UPDATE, CAM_ISP_HW_CMD_CLOCK_UPDATE, CAM_ISP_HW_CMD_BW_UPDATE, + CAM_ISP_HW_CMD_UBWC_UPDATE, }; static struct cam_ife_hw_mgr g_ife_hw_mgr; @@ -2238,6 +2239,129 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, return rc; } +static int cam_isp_blob_ubwc_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_ubwc_config *ubwc_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ubwc_plane_cfg_v1 *ubwc_plane_cfg; + struct cam_kmd_buf_info *kmd_buf_info; + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + uint32_t res_id_out, i; + uint32_t total_used_bytes = 0; + uint32_t kmd_buf_remain_size; + uint32_t *cmd_buf_addr; + uint32_t bytes_used = 0; + int num_ent, rc = 0; + + ctx = prepare->ctxt_to_hw_map; + if (!ctx) { + CAM_ERR(CAM_ISP, "Invalid ctx"); + rc = -EINVAL; + goto end; + } + + if ((prepare->num_hw_update_entries + 1) >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d max:%d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + rc = -EINVAL; + goto end; + } + + switch (ubwc_config->api_version) { + case CAM_UBWC_CFG_VERSION_1: + CAM_DBG(CAM_ISP, "num_ports= %d", ubwc_config->num_ports); + + kmd_buf_info = blob_info->kmd_buf_info; + for (i = 0; i < ubwc_config->num_ports; i++) { + ubwc_plane_cfg = &ubwc_config->ubwc_plane_cfg[i][0]; + res_id_out = ubwc_plane_cfg->port_type & 0xFF; + + CAM_DBG(CAM_ISP, "UBWC config idx %d, port_type=%d", i, + ubwc_plane_cfg->port_type); + + if (res_id_out >= CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "Invalid port type:%x", + ubwc_plane_cfg->port_type); + rc = -EINVAL; + goto end; + } + + if ((kmd_buf_info->used_bytes + + total_used_bytes) < kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + total_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base=%d bytes_used=%u buf_size=%u", + blob_info->base_info->idx, bytes_used, + kmd_buf_info->size); + rc = -ENOMEM; + goto end; + } + + cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + total_used_bytes/4; + hw_mgr_res = &ctx->res_list_ife_out[res_id_out]; + + if (!hw_mgr_res) { + CAM_ERR(CAM_ISP, "Invalid hw_mgr_res"); + rc = -EINVAL; + goto end; + } + + rc = cam_isp_add_cmd_buf_update( + hw_mgr_res, blob_type, + blob_type_hw_cmd_map[blob_type], + blob_info->base_info->idx, + (void *)cmd_buf_addr, + kmd_buf_remain_size, + (void *)ubwc_plane_cfg, + &bytes_used); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Failed cmd_update, base_idx=%d, bytes_used=%u, res_id_out=0x%x", + blob_info->base_info->idx, + bytes_used, + res_id_out); + goto end; + } + + total_used_bytes += bytes_used; + } + + if (total_used_bytes) { + /* Update the HW entries */ + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = + total_used_bytes; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + num_ent++; + + kmd_buf_info->used_bytes += total_used_bytes; + kmd_buf_info->offset += total_used_bytes; + prepare->num_hw_update_entries = num_ent; + } + break; + default: + CAM_ERR(CAM_ISP, "Invalid UBWC API Version %d", + ubwc_config->api_version); + rc = -EINVAL; + break; + } +end: + return rc; +} + static int cam_isp_blob_hfr_update( uint32_t blob_type, struct cam_isp_generic_blob_info *blob_info, @@ -2478,6 +2602,16 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, bw_config, sizeof(prepare_hw_data->bw_config[0])); prepare_hw_data->bw_config_valid[bw_config->usage_type] = true; + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG: { + struct cam_ubwc_config *ubwc_config = + (struct cam_ubwc_config *)blob_data; + + rc = cam_isp_blob_ubwc_update(blob_type, blob_info, + ubwc_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "UBWC Update Failed rc: %d", rc); } break; default: diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index c56c49fac5af..51a00e282527 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -95,6 +95,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_BW_CONTROL, CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, CAM_ISP_HW_CMD_GET_REG_DUMP, + CAM_ISP_HW_CMD_UBWC_UPDATE, CAM_ISP_HW_CMD_MAX, }; @@ -201,6 +202,7 @@ struct cam_isp_hw_get_cmd_update { struct cam_isp_port_hfr_config *hfr_update; struct cam_isp_clock_config *clock_update; struct cam_isp_bw_config *bw_update; + struct cam_ubwc_plane_cfg_v1 *ubwc_update; }; }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index d25dec8850e2..bd862512ccc6 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -703,6 +703,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_GET_HFR_UPDATE: case CAM_ISP_HW_CMD_STRIPE_UPDATE: case CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ: + case CAM_ISP_HW_CMD_UBWC_UPDATE: rc = core_info->vfe_bus->hw_ops.process_cmd( core_info->vfe_bus->bus_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h index a4ba2e12bca3..28a632a597e8 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -198,7 +198,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_3 = { .meta_addr = 0x00002538, .meta_offset = 0x0000253C, .meta_stride = 0x00002540, - .mode_cfg = 0x00002544, + .mode_cfg_0 = 0x00002544, .bw_limit = 0x000025A0, }; @@ -209,7 +209,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_4 = { .meta_addr = 0x00002638, .meta_offset = 0x0000263C, .meta_stride = 0x00002640, - .mode_cfg = 0x00002644, + .mode_cfg_0 = 0x00002644, .bw_limit = 0x000026A0, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h index a72a9774863b..a9b0ace03ed3 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h @@ -191,7 +191,7 @@ static struct cam_irq_register_set vfe175_bus_irq_reg[3] = { }, }; -static struct cam_vfe_bus_ver2_reg_offset_ubwc_client +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client vfe175_ubwc_regs_client_3 = { .tile_cfg = 0x0000252C, .h_init = 0x00002530, @@ -199,11 +199,12 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_client .meta_addr = 0x00002538, .meta_offset = 0x0000253C, .meta_stride = 0x00002540, - .mode_cfg = 0x00002544, + .mode_cfg_0 = 0x00002544, + .mode_cfg_1 = 0x000025A4, .bw_limit = 0x000025A0, }; -static struct cam_vfe_bus_ver2_reg_offset_ubwc_client +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client vfe175_ubwc_regs_client_4 = { .tile_cfg = 0x0000262C, .h_init = 0x00002630, @@ -211,11 +212,12 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_client .meta_addr = 0x00002638, .meta_offset = 0x0000263C, .meta_stride = 0x00002640, - .mode_cfg = 0x00002644, + .mode_cfg_0 = 0x00002644, + .mode_cfg_1 = 0x000026A4, .bw_limit = 0x000026A0, }; -static struct cam_vfe_bus_ver2_reg_offset_ubwc_client +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client vfe175_ubwc_regs_client_20 = { .tile_cfg = 0x0000362C, .h_init = 0x00003630, @@ -223,11 +225,12 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_client .meta_addr = 0x00003638, .meta_offset = 0x0000363C, .meta_stride = 0x00003640, - .mode_cfg = 0x00003644, + .mode_cfg_0 = 0x00003644, + .mode_cfg_1 = 0x000036A4, .bw_limit = 0x000036A0, }; -static struct cam_vfe_bus_ver2_reg_offset_ubwc_client +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client vfe175_ubwc_regs_client_21 = { .tile_cfg = 0x0000372C, .h_init = 0x00003730, @@ -235,7 +238,8 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_client .meta_addr = 0x00003738, .meta_offset = 0x0000373C, .meta_stride = 0x00003740, - .mode_cfg = 0x00003744, + .mode_cfg_0 = 0x00003744, + .mode_cfg_1 = 0x000037A4, .bw_limit = 0x000037A0, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 12e9125d8fa4..3dd916e27532 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -54,8 +54,8 @@ static const char drv_name[] = "vfe_bus"; #define CAM_VFE_ADD_REG_VAL_PAIR(buf_array, index, offset, val) \ do { \ - buf_array[index++] = offset; \ - buf_array[index++] = val; \ + buf_array[(index)++] = offset; \ + buf_array[(index)++] = val; \ } while (0) static uint32_t bus_error_irq_mask[3] = { @@ -134,12 +134,14 @@ struct cam_vfe_bus_ver2_wm_resource_data { uint32_t burst_len; uint32_t en_ubwc; + bool ubwc_updated; uint32_t packer_cfg; uint32_t tile_cfg; uint32_t h_init; uint32_t v_init; uint32_t ubwc_meta_stride; - uint32_t ubwc_mode_cfg; + uint32_t ubwc_mode_cfg_0; + uint32_t ubwc_mode_cfg_1; uint32_t ubwc_meta_offset; uint32_t irq_subsample_period; @@ -1086,7 +1088,8 @@ static int cam_vfe_bus_release_wm(void *bus_priv, rsrc_data->h_init = 0; rsrc_data->v_init = 0; rsrc_data->ubwc_meta_stride = 0; - rsrc_data->ubwc_mode_cfg = 0; + rsrc_data->ubwc_mode_cfg_0 = 0; + rsrc_data->ubwc_mode_cfg_1 = 0; rsrc_data->ubwc_meta_offset = 0; rsrc_data->init_cfg_done = false; rsrc_data->hfr_cfg_done = false; @@ -1107,6 +1110,7 @@ static int cam_vfe_bus_start_wm(struct cam_isp_resource_node *wm_res) struct cam_vfe_bus_ver2_common_data *common_data = rsrc_data->common_data; uint32_t bus_irq_reg_mask[CAM_VFE_BUS_IRQ_MAX] = {0}; + uint32_t camera_hw_version; cam_io_w(0xf, common_data->mem_base + rsrc_data->hw_regs->burst_limit); @@ -1142,13 +1146,39 @@ static int cam_vfe_bus_start_wm(struct cam_isp_resource_node *wm_res) /* enable ubwc if needed*/ if (rsrc_data->en_ubwc) { - int val = cam_io_r_mb(common_data->mem_base + - rsrc_data->hw_regs->ubwc_regs->mode_cfg); - CAM_DBG(CAM_ISP, "ubwc reg %d, res id %d", - val, rsrc_data->index); - val |= 0x1; - cam_io_w_mb(val, common_data->mem_base + - rsrc_data->hw_regs->ubwc_regs->mode_cfg); + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version:%d rc:%d", + camera_hw_version, rc); + return rc; + } + if ((camera_hw_version > CAM_CPAS_TITAN_NONE) && + (camera_hw_version < CAM_CPAS_TITAN_175_V100)) { + struct cam_vfe_bus_ver2_reg_offset_ubwc_client + *ubwc_regs; + + ubwc_regs = + (struct + cam_vfe_bus_ver2_reg_offset_ubwc_client *) + rsrc_data->hw_regs->ubwc_regs; + cam_io_w_mb(0x1, common_data->mem_base + + ubwc_regs->mode_cfg_0); + } else if ((camera_hw_version == CAM_CPAS_TITAN_175_V100) || + (camera_hw_version == CAM_CPAS_TITAN_175_V101)) { + struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + *ubwc_regs; + + ubwc_regs = + (struct + cam_vfe_bus_ver2_reg_offset_ubwc_3_client *) + rsrc_data->hw_regs->ubwc_regs; + cam_io_w_mb(0x1, common_data->mem_base + + ubwc_regs->mode_cfg_0); + } else { + CAM_ERR(CAM_ISP, "Invalid HW version: %d", + camera_hw_version); + return -EINVAL; + } } /* Enable WM */ @@ -2326,6 +2356,285 @@ static int cam_vfe_bus_error_irq_top_half(uint32_t evt_id, return -EFAULT; } +static void cam_vfe_bus_update_ubwc_meta_addr( + uint32_t *reg_val_pair, + uint32_t *j, + void *regs, + uint64_t image_buf) +{ + uint32_t camera_hw_version; + struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_regs; + struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *ubwc_3_regs; + int rc = 0; + + if (!regs || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc: %d", rc); + goto end; + } else if ((camera_hw_version < CAM_CPAS_TITAN_170_V100) || + (camera_hw_version > CAM_CPAS_TITAN_175_V101)) { + CAM_ERR(CAM_ISP, "Invalid HW version: %d", + camera_hw_version); + goto end; + } + + switch (camera_hw_version) { + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + ubwc_regs = + (struct cam_vfe_bus_ver2_reg_offset_ubwc_client *)regs; + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_addr, + image_buf); + break; + case CAM_CPAS_TITAN_175_V100: + case CAM_CPAS_TITAN_175_V101: + ubwc_3_regs = + (struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *) + regs; + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_3_regs->meta_addr, + image_buf); + break; + default: + break; + } +end: + return; +} + +static int cam_vfe_bus_update_ubwc_3_regs( + struct cam_vfe_bus_ver2_wm_resource_data *wm_data, + uint32_t *reg_val_pair, uint32_t i, uint32_t *j) +{ + struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *ubwc_regs; + uint32_t ubwc_bw_limit = 0; + int rc = 0; + + if (!wm_data || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + ubwc_regs = (struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *) + wm_data->hw_regs->ubwc_regs; + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + wm_data->hw_regs->packer_cfg, wm_data->packer_cfg); + CAM_DBG(CAM_ISP, "WM %d packer cfg 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + if (wm_data->is_dual) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->tile_cfg, wm_data->tile_cfg); + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->tile_cfg, wm_data->tile_cfg); + CAM_DBG(CAM_ISP, "WM %d tile cfg 0x%x", + wm_data->index, reg_val_pair[*j-1]); + } + + if (wm_data->is_dual) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->h_init, wm_data->offset); + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->h_init, wm_data->h_init); + CAM_DBG(CAM_ISP, "WM %d h_init 0x%x", + wm_data->index, reg_val_pair[*j-1]); + } + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->v_init, wm_data->v_init); + CAM_DBG(CAM_ISP, "WM %d v_init 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_stride, wm_data->ubwc_meta_stride); + CAM_DBG(CAM_ISP, "WM %d meta stride 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->mode_cfg_0, wm_data->ubwc_mode_cfg_0); + CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_0 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->mode_cfg_1, wm_data->ubwc_mode_cfg_1); + CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_1 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_offset, wm_data->ubwc_meta_offset); + CAM_DBG(CAM_ISP, "WM %d ubwc meta offset 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + switch (wm_data->format) { + case CAM_FORMAT_UBWC_TP10: + ubwc_bw_limit = 0x8 | BIT(0); + break; + case CAM_FORMAT_UBWC_NV12_4R: + ubwc_bw_limit = 0xB | BIT(0); + break; + default: + ubwc_bw_limit = 0; + break; + } + + if (ubwc_bw_limit) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->bw_limit, ubwc_bw_limit); + CAM_DBG(CAM_ISP, "WM %d ubwc bw limit 0x%x", + wm_data->index, ubwc_bw_limit); + } + +end: + return rc; +} + +static int cam_vfe_bus_update_ubwc_legacy_regs( + struct cam_vfe_bus_ver2_wm_resource_data *wm_data, + uint32_t camera_hw_version, uint32_t *reg_val_pair, + uint32_t i, uint32_t *j) +{ + struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_regs; + uint32_t ubwc_bw_limit = 0; + int rc = 0; + + if (!wm_data || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + ubwc_regs = (struct cam_vfe_bus_ver2_reg_offset_ubwc_client *) + wm_data->hw_regs->ubwc_regs; + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + wm_data->hw_regs->packer_cfg, wm_data->packer_cfg); + CAM_DBG(CAM_ISP, "WM %d packer cfg 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + if (wm_data->is_dual) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->tile_cfg, wm_data->tile_cfg); + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->tile_cfg, wm_data->tile_cfg); + CAM_DBG(CAM_ISP, "WM %d tile cfg 0x%x", + wm_data->index, reg_val_pair[*j-1]); + } + + if (wm_data->is_dual) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->h_init, wm_data->offset); + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->h_init, wm_data->h_init); + CAM_DBG(CAM_ISP, "WM %d h_init 0x%x", + wm_data->index, reg_val_pair[*j-1]); + } + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->v_init, wm_data->v_init); + CAM_DBG(CAM_ISP, "WM %d v_init 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_stride, wm_data->ubwc_meta_stride); + CAM_DBG(CAM_ISP, "WM %d meta stride 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->mode_cfg_0, wm_data->ubwc_mode_cfg_0); + CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_0 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_offset, wm_data->ubwc_meta_offset); + CAM_DBG(CAM_ISP, "WM %d ubwc meta offset 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + if (camera_hw_version == CAM_CPAS_TITAN_170_V110) { + switch (wm_data->format) { + case CAM_FORMAT_UBWC_TP10: + ubwc_bw_limit = 0x8 | BIT(0); + break; + case CAM_FORMAT_UBWC_NV12_4R: + ubwc_bw_limit = 0xB | BIT(0); + break; + default: + ubwc_bw_limit = 0; + break; + } + } + + if (ubwc_bw_limit) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->bw_limit, ubwc_bw_limit); + CAM_DBG(CAM_ISP, "WM %d ubwc bw limit 0x%x", + wm_data->index, ubwc_bw_limit); + } + +end: + return rc; +} + +static int cam_vfe_bus_update_ubwc_regs( + struct cam_vfe_bus_ver2_wm_resource_data *wm_data, + uint32_t *reg_val_pair, uint32_t i, uint32_t *j) +{ + uint32_t camera_hw_version; + int rc = 0; + + if (!wm_data || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc: %d", rc); + goto end; + } else if ((camera_hw_version <= CAM_CPAS_TITAN_NONE) || + (camera_hw_version >= CAM_CPAS_TITAN_MAX)) { + CAM_ERR(CAM_ISP, "Invalid HW version: %d", + camera_hw_version); + rc = -EINVAL; + goto end; + } + switch (camera_hw_version) { + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + rc = cam_vfe_bus_update_ubwc_legacy_regs( + wm_data, camera_hw_version, reg_val_pair, i, j); + break; + case CAM_CPAS_TITAN_175_V100: + case CAM_CPAS_TITAN_175_V101: + rc = cam_vfe_bus_update_ubwc_3_regs( + wm_data, reg_val_pair, i, j); + break; + default: + break; + } + + if (rc) + CAM_ERR(CAM_ISP, "Failed to update ubwc regs rc:%d", rc); + +end: + return rc; +} + static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, uint32_t arg_size) { @@ -2337,8 +2646,7 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_client = NULL; uint32_t *reg_val_pair; uint32_t i, j, size = 0; - uint32_t frame_inc = 0, ubwc_bw_limit = 0, camera_hw_version, val; - int rc = 0; + uint32_t frame_inc = 0, val; bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; @@ -2405,136 +2713,20 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, "No UBWC register to configure."); return -EINVAL; } - if (wm_data->packer_cfg != - io_cfg->planes[i].packer_config || - !wm_data->init_cfg_done) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->packer_cfg, - io_cfg->planes[i].packer_config); - wm_data->packer_cfg = - io_cfg->planes[i].packer_config; - CAM_DBG(CAM_ISP, "WM %d packer cfg 0x%x", - wm_data->index, reg_val_pair[j-1]); - } - - if (wm_data->is_dual) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->ubwc_regs->tile_cfg, - wm_data->tile_cfg); - } else if ((wm_data->tile_cfg != - io_cfg->planes[i].tile_config) - || !wm_data->init_cfg_done) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->ubwc_regs->tile_cfg, - io_cfg->planes[i].tile_config); - wm_data->tile_cfg = - io_cfg->planes[i].tile_config; - CAM_DBG(CAM_ISP, "WM %d tile cfg 0x%x", - wm_data->index, reg_val_pair[j-1]); - } - - if (wm_data->is_dual) { - if ((wm_data->h_init != wm_data->offset) || - !wm_data->init_cfg_done) { - /* - * For dual ife h init value need to - * take from offset. Striping config - * update offset value. - */ - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, - j, ubwc_client->h_init, - wm_data->offset); - wm_data->h_init = wm_data->offset; - } - } else if (wm_data->h_init != - io_cfg->planes[i].h_init || - !wm_data->init_cfg_done) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->ubwc_regs->h_init, - io_cfg->planes[i].h_init); - wm_data->h_init = io_cfg->planes[i].h_init; - CAM_DBG(CAM_ISP, "WM %d h_init 0x%x", - wm_data->index, reg_val_pair[j-1]); - } - - if (wm_data->v_init != io_cfg->planes[i].v_init || - !wm_data->init_cfg_done) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->ubwc_regs->v_init, - io_cfg->planes[i].v_init); - wm_data->v_init = io_cfg->planes[i].v_init; - CAM_DBG(CAM_ISP, "WM %d v_init 0x%x", - wm_data->index, reg_val_pair[j-1]); - } - - if (wm_data->ubwc_meta_stride != - io_cfg->planes[i].meta_stride || - !wm_data->init_cfg_done) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - ubwc_client->meta_stride, - io_cfg->planes[i].meta_stride); - wm_data->ubwc_meta_stride = - io_cfg->planes[i].meta_stride; - CAM_DBG(CAM_ISP, "WM %d meta stride 0x%x", - wm_data->index, reg_val_pair[j-1]); - } - - if (wm_data->ubwc_mode_cfg != - io_cfg->planes[i].mode_config || - !wm_data->init_cfg_done) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->ubwc_regs->mode_cfg, - io_cfg->planes[i].mode_config); - wm_data->ubwc_mode_cfg = - io_cfg->planes[i].mode_config; - CAM_DBG(CAM_ISP, "WM %d ubwc mode cfg 0x%x", - wm_data->index, reg_val_pair[j-1]); - } - - if (wm_data->ubwc_meta_offset != - io_cfg->planes[i].meta_offset || - !wm_data->init_cfg_done) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - ubwc_client->meta_offset, - io_cfg->planes[i].meta_offset); - wm_data->ubwc_meta_offset = - io_cfg->planes[i].meta_offset; - CAM_DBG(CAM_ISP, "WM %d ubwc meta offset 0x%x", - wm_data->index, reg_val_pair[j-1]); + if (wm_data->ubwc_updated) { + wm_data->ubwc_updated = false; + cam_vfe_bus_update_ubwc_regs( + wm_data, reg_val_pair, i, &j); } /* UBWC meta address */ - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->ubwc_regs->meta_addr, + cam_vfe_bus_update_ubwc_meta_addr( + reg_val_pair, &j, + wm_data->hw_regs->ubwc_regs, update_buf->wm_update->image_buf[i]); CAM_DBG(CAM_ISP, "WM %d ubwc meta addr 0x%llx", wm_data->index, update_buf->wm_update->image_buf[i]); - - /* Enable UBWC bandwidth limit if required */ - rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); - if (camera_hw_version == CAM_CPAS_TITAN_170_V110 - && !rc) { - switch (wm_data->format) { - case CAM_FORMAT_UBWC_TP10: - ubwc_bw_limit = 0x8 | BIT(0); - break; - case CAM_FORMAT_UBWC_NV12_4R: - ubwc_bw_limit = 0xB | BIT(0); - break; - default: - ubwc_bw_limit = 0; - break; - } - } - - if (ubwc_bw_limit) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->ubwc_regs->bw_limit, - ubwc_bw_limit); - CAM_DBG(CAM_ISP, "WM %d ubwc bw limit 0x%x", - wm_data->index, ubwc_bw_limit); - } } /* WM Image address */ @@ -2703,6 +2895,116 @@ static int cam_vfe_bus_update_hfr(void *priv, void *cmd_args, return 0; } +static int cam_vfe_bus_update_ubwc_config(void *cmd_args) +{ + struct cam_isp_hw_get_cmd_update *update_ubwc; + struct cam_vfe_bus_ver2_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + struct cam_ubwc_plane_cfg_v1 *ubwc_plane_cfg = NULL; + uint32_t i; + int rc = 0; + + if (!cmd_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + update_ubwc = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver2_vfe_out_data *) + update_ubwc->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid data"); + rc = -EINVAL; + goto end; + } + + ubwc_plane_cfg = update_ubwc->ubwc_update; + + for (i = 0; i < vfe_out_data->num_wm; i++) { + + wm_data = vfe_out_data->wm_res[i]->res_priv; + if (i > 0) + ubwc_plane_cfg++; + + if (!wm_data->hw_regs->ubwc_regs) { + CAM_ERR(CAM_ISP, + "No UBWC register to configure."); + rc = -EINVAL; + goto end; + } + + if (!wm_data->en_ubwc) { + CAM_ERR(CAM_ISP, "UBWC Disabled"); + rc = -EINVAL; + goto end; + } + + if (wm_data->packer_cfg != + ubwc_plane_cfg->packer_config || + !wm_data->init_cfg_done) { + wm_data->packer_cfg = ubwc_plane_cfg->packer_config; + wm_data->ubwc_updated = true; + } + + if ((!wm_data->is_dual) && ((wm_data->tile_cfg != + ubwc_plane_cfg->tile_config) + || !wm_data->init_cfg_done)) { + wm_data->tile_cfg = ubwc_plane_cfg->tile_config; + wm_data->ubwc_updated = true; + } + + if ((!wm_data->is_dual) && ((wm_data->h_init != + ubwc_plane_cfg->h_init) || + !wm_data->init_cfg_done)) { + wm_data->h_init = ubwc_plane_cfg->h_init; + wm_data->ubwc_updated = true; + } + + if (wm_data->v_init != ubwc_plane_cfg->v_init || + !wm_data->init_cfg_done) { + wm_data->v_init = ubwc_plane_cfg->v_init; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_meta_stride != + ubwc_plane_cfg->meta_stride || + !wm_data->init_cfg_done) { + wm_data->ubwc_meta_stride = ubwc_plane_cfg->meta_stride; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_mode_cfg_0 != + ubwc_plane_cfg->mode_config_0 || + !wm_data->init_cfg_done) { + wm_data->ubwc_mode_cfg_0 = + ubwc_plane_cfg->mode_config_0; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_mode_cfg_1 != + ubwc_plane_cfg->mode_config_1 || + !wm_data->init_cfg_done) { + wm_data->ubwc_mode_cfg_1 = + ubwc_plane_cfg->mode_config_1; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_meta_offset != + ubwc_plane_cfg->meta_offset || + !wm_data->init_cfg_done) { + wm_data->ubwc_meta_offset = ubwc_plane_cfg->meta_offset; + wm_data->ubwc_updated = true; + } + } + +end: + return rc; +} + + static int cam_vfe_bus_update_stripe_cfg(void *priv, void *cmd_args, uint32_t arg_size) { @@ -2902,6 +3204,9 @@ static int cam_vfe_bus_process_cmd( bus_priv->error_irq_handle = 0; } break; + case CAM_ISP_HW_CMD_UBWC_UPDATE: + rc = cam_vfe_bus_update_ubwc_config(cmd_args); + break; default: CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", cmd_type); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h index c001eef72bc4..dee3ecaf1239 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h @@ -100,10 +100,28 @@ struct cam_vfe_bus_ver2_reg_offset_ubwc_client { uint32_t meta_addr; uint32_t meta_offset; uint32_t meta_stride; - uint32_t mode_cfg; + uint32_t mode_cfg_0; uint32_t bw_limit; }; +/* + * struct cam_vfe_bus_ver2_reg_offset_ubwc_client: + * + * @Brief: UBWC register offsets for BUS Clients + */ +struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client { + uint32_t tile_cfg; + uint32_t h_init; + uint32_t v_init; + uint32_t meta_addr; + uint32_t meta_offset; + uint32_t meta_stride; + uint32_t mode_cfg_0; + uint32_t mode_cfg_1; + uint32_t bw_limit; +}; + + /* * struct cam_vfe_bus_ver2_reg_offset_bus_client: * @@ -127,7 +145,7 @@ struct cam_vfe_bus_ver2_reg_offset_bus_client { uint32_t framedrop_pattern; uint32_t frame_inc; uint32_t burst_limit; - struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_regs; + void *ubwc_regs; }; /* -- GitLab From aa05ad02fc46796084d9921910a18eb7441a357a Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Thu, 3 May 2018 17:21:16 -0700 Subject: [PATCH 232/855] msm: camera: isp: Fix the sequence of CSID Master-Slave start This change implements changes to CSID master-slave start that helps to resolve Violation issue in case of Dual IFE. Change-Id: Ie0bcc59d102f6521d06c6dc5621f50454c0168dc Signed-off-by: Harsh Shah --- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 21 +++- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 106 ++++++++++-------- .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 5 + 3 files changed, 82 insertions(+), 50 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 1e67d9db9cd1..f092d5aea193 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -211,7 +211,8 @@ static int cam_ife_hw_mgr_start_hw_res( int rc = -1; struct cam_hw_intf *hw_intf; - for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + /* Start slave (which is right split) first */ + for (i = CAM_ISP_HW_SPLIT_MAX - 1; i >= 0; i--) { if (!isp_hw_res->hw_res[i]) continue; hw_intf = isp_hw_res->hw_res[i]->hw_intf; @@ -960,6 +961,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp( { int rc = -1; int i; + int master_idx = -1; struct cam_ife_hw_mgr *ife_hw_mgr; struct cam_ife_hw_mgr_res *csid_res; @@ -1011,18 +1013,27 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp( if (!cid_res->hw_res[i]) continue; + hw_intf = ife_hw_mgr->csid_devices[ + cid_res->hw_res[i]->hw_intf->hw_idx]; + csid_acquire.node_res = NULL; if (csid_res->is_dual_vfe) { - if (i == CAM_ISP_HW_SPLIT_LEFT) + if (i == CAM_ISP_HW_SPLIT_LEFT) { + master_idx = hw_intf->hw_idx; csid_acquire.sync_mode = CAM_ISP_HW_SYNC_MASTER; - else + } else { + if (master_idx == -1) { + CAM_ERR(CAM_ISP, + "No Master found"); + goto err; + } csid_acquire.sync_mode = CAM_ISP_HW_SYNC_SLAVE; + csid_acquire.master_idx = master_idx; + } } - hw_intf = ife_hw_mgr->csid_devices[ - cid_res->hw_res[i]->hw_intf->hw_idx]; rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &csid_acquire, sizeof(csid_acquire)); if (rc) { diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index d20450c38511..3edae4a53d28 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -851,7 +851,6 @@ static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, path_data->cid = reserve->cid; path_data->in_format = reserve->in_port->format; path_data->out_format = reserve->out_port->format; - path_data->master_idx = reserve->master_idx; path_data->sync_mode = reserve->sync_mode; path_data->height = reserve->in_port->height; path_data->start_line = reserve->in_port->line_start; @@ -877,9 +876,11 @@ static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, goto end; } - CAM_DBG(CAM_ISP, "Res id: %d height:%d line_start %d line_stop %d", + CAM_DBG(CAM_ISP, + "Res id: %d height:%d line_start %d line_stop %d crop_en %d", reserve->res_id, reserve->in_port->height, - reserve->in_port->line_start, reserve->in_port->line_stop); + reserve->in_port->line_start, reserve->in_port->line_stop, + path_data->crop_enable); if (reserve->in_port->res_type == CAM_ISP_IFE_IN_RES_TPG) { path_data->dt = CAM_IFE_CSID_TPG_DT_VAL; @@ -893,20 +894,23 @@ static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, path_data->start_pixel = reserve->in_port->left_start; path_data->end_pixel = reserve->in_port->left_stop; path_data->width = reserve->in_port->left_width; - CAM_DBG(CAM_ISP, "CSID:%dmaster:startpixel 0x%x endpixel:0x%x", + CAM_DBG(CAM_ISP, "CSID:%d master:startpixel 0x%x endpixel:0x%x", csid_hw->hw_intf->hw_idx, path_data->start_pixel, path_data->end_pixel); - CAM_DBG(CAM_ISP, "CSID:%dmaster:line start:0x%x line end:0x%x", + CAM_DBG(CAM_ISP, "CSID:%d master:line start:0x%x line end:0x%x", csid_hw->hw_intf->hw_idx, path_data->start_line, path_data->end_line); } else if (reserve->sync_mode == CAM_ISP_HW_SYNC_SLAVE) { + path_data->master_idx = reserve->master_idx; + CAM_DBG(CAM_ISP, "CSID:%d master_idx=%d", + csid_hw->hw_intf->hw_idx, path_data->master_idx); path_data->start_pixel = reserve->in_port->right_start; path_data->end_pixel = reserve->in_port->right_stop; path_data->width = reserve->in_port->right_width; CAM_DBG(CAM_ISP, "CSID:%d slave:start:0x%x end:0x%x width 0x%x", csid_hw->hw_intf->hw_idx, path_data->start_pixel, path_data->end_pixel, path_data->width); - CAM_DBG(CAM_ISP, "CSID:%dmaster:line start:0x%x line end:0x%x", + CAM_DBG(CAM_ISP, "CSID:%d slave:line start:0x%x line end:0x%x", csid_hw->hw_intf->hw_idx, path_data->start_line, path_data->end_line); } else { @@ -1431,19 +1435,6 @@ static int cam_ife_csid_init_config_ipp_path( cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->ipp_reg->csid_ipp_line_drop_period_addr); - /*Set master or slave IPP */ - if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER) - /*Set halt mode as master */ - val = CSID_HALT_MODE_MASTER << 2; - else if (path_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) - /*Set halt mode as slave and set master idx */ - val = path_data->master_idx << 4 | CSID_HALT_MODE_SLAVE << 2; - else - /* Default is internal halt mode */ - val = 0; - - cam_io_w_mb(val, soc_info->reg_map[0].mem_base + - csid_reg->ipp_reg->csid_ipp_ctrl_addr); /* Enable the IPP path */ val = cam_io_r_mb(soc_info->reg_map[0].mem_base + @@ -1545,19 +1536,31 @@ static int cam_ife_csid_enable_ipp_path( CAM_DBG(CAM_ISP, "Enable IPP path"); - /* Resume at frame boundary */ - if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER) { - val = cam_io_r_mb(soc_info->reg_map[0].mem_base + - csid_reg->ipp_reg->csid_ipp_ctrl_addr); + + /* Set master or slave IPP */ + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER) + /*Set halt mode as master */ + val = CSID_HALT_MODE_MASTER << 2; + else if (path_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + /*Set halt mode as slave and set master idx */ + val = path_data->master_idx << 4 | CSID_HALT_MODE_SLAVE << 2; + else + /* Default is internal halt mode */ + val = 0; + + /* + * Resume at frame boundary if Master or No Sync. + * Slave will get resume command from Master. + */ + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; - cam_io_w_mb(val, soc_info->reg_map[0].mem_base + - csid_reg->ipp_reg->csid_ipp_ctrl_addr); - } else if (path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) { - cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, - soc_info->reg_map[0].mem_base + - csid_reg->ipp_reg->csid_ipp_ctrl_addr); - } - /* for slave mode, not need to resume for slave device */ + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_ctrl_addr); + + CAM_DBG(CAM_ISP, "CSID:%d IPP Ctrl val: 0x%x", + csid_hw->hw_intf->hw_idx, val); /* Enable the required ipp interrupts */ val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; @@ -1569,6 +1572,7 @@ static int cam_ife_csid_enable_ipp_path( cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->ipp_reg->csid_ipp_irq_mask_addr); + CAM_DBG(CAM_ISP, "Enable IPP IRQ mask 0x%x", val); res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; @@ -2618,38 +2622,46 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) { if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED) { - CAM_ERR(CAM_ISP, "CSID:%d PHY_DL0_EOT_CAPTURED", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL0_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); } if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED) { - CAM_ERR(CAM_ISP, "CSID:%d PHY_DL1_EOT_CAPTURED", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL1_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); } if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED) { - CAM_ERR(CAM_ISP, "CSID:%d PHY_DL2_EOT_CAPTURED", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL2_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); } if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED) { - CAM_ERR(CAM_ISP, "CSID:%d PHY_DL3_EOT_CAPTURED", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL3_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); } } if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOT_IRQ) { if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED) { - CAM_ERR(CAM_ISP, "CSID:%d PHY_DL0_SOT_CAPTURED", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL0_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); } if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED) { - CAM_ERR(CAM_ISP, "CSID:%d PHY_DL1_SOT_CAPTURED", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL1_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); } if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED) { - CAM_ERR(CAM_ISP, "CSID:%d PHY_DL2_SOT_CAPTURED", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL2_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); } if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED) { - CAM_ERR(CAM_ISP, "CSID:%d PHY_DL3_SOT_CAPTURED", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL3_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); } } @@ -2709,16 +2721,17 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) if ((irq_status_ipp & CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) - CAM_ERR(CAM_ISP, "CSID:%d IPP SOF received", + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d IPP SOF received", csid_hw->hw_intf->hw_idx); if ((irq_status_ipp & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) - CAM_ERR(CAM_ISP, "CSID:%d IPP EOF received", + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d IPP EOF received", csid_hw->hw_intf->hw_idx); if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) { - CAM_ERR(CAM_ISP, "CSID:%d IPP fifo over flow", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d IPP fifo over flow", csid_hw->hw_intf->hw_idx); /*Stop IPP path immediately */ cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, @@ -2736,14 +2749,17 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) - CAM_ERR(CAM_ISP, "CSID RDI:%d SOF received", i); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID RDI:%d SOF received", i); if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) - CAM_ERR(CAM_ISP, "CSID RDI:%d EOF received", i); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID RDI:%d EOF received", i); if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { - CAM_ERR(CAM_ISP, "CSID:%d RDI fifo over flow", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d RDI fifo over flow", csid_hw->hw_intf->hw_idx); /*Stop RDI path immediately */ cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 734cbdb3d4e5..90c80066b4b1 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -138,6 +138,9 @@ int cam_vfe_camif_ver2_acquire_resource( camif_data->first_line = acquire_data->vfe_in.in_port->line_start; camif_data->last_line = acquire_data->vfe_in.in_port->line_stop; + CAM_DBG(CAM_ISP, "hw id:%d pix_pattern:%d dsp_mode=%d", + camif_res->hw_intf->hw_idx, + camif_data->pix_pattern, camif_data->dsp_mode); return rc; } @@ -249,6 +252,8 @@ static int cam_vfe_camif_resource_start( /* Reg Update */ cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, rsrc_data->mem_base + rsrc_data->camif_reg->reg_update_cmd); + CAM_DBG(CAM_ISP, "hw id:%d RUP val:%d", camif_res->hw_intf->hw_idx, + rsrc_data->reg_data->reg_update_cmd_data); CAM_DBG(CAM_ISP, "Start Camif IFE %d Done", camif_res->hw_intf->hw_idx); return 0; -- GitLab From c8e610fe5495fab84f62f48e6e45949d4a62b703 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Tue, 8 May 2018 17:40:44 -0700 Subject: [PATCH 233/855] msm: camera: isp: Change context lock acquire sequence in flush Move acquiring context lock to functions calling flush to prevent race conditions. Change-Id: Ic30ae8c3d8cd477bf719803c39360e47a0b02811 Signed-off-by: Venkat Chinta --- .../platform/msm/camera/cam_isp/cam_isp_context.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index f9985eb882bc..b618ee526479 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -1325,9 +1325,7 @@ static int __cam_isp_ctx_flush_req(struct cam_context *ctx, struct list_head flush_list; INIT_LIST_HEAD(&flush_list); - spin_lock_bh(&ctx->lock); if (list_empty(req_list)) { - spin_unlock_bh(&ctx->lock); CAM_DBG(CAM_ISP, "request list is empty"); return 0; } @@ -1346,7 +1344,6 @@ static int __cam_isp_ctx_flush_req(struct cam_context *ctx, list_del_init(&req->list); list_add_tail(&req->list, &flush_list); } - spin_unlock_bh(&ctx->lock); list_for_each_entry_safe(req, req_temp, &flush_list, list) { req_isp = (struct cam_isp_ctx_req *) req->req_priv; @@ -1364,9 +1361,7 @@ static int __cam_isp_ctx_flush_req(struct cam_context *ctx, req_isp->fence_map_out[i].sync_id = -1; } } - spin_lock_bh(&ctx->lock); list_add_tail(&req->list, &ctx->free_req_list); - spin_unlock_bh(&ctx->lock); } if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ && @@ -1385,7 +1380,9 @@ static int __cam_isp_ctx_flush_req_in_top_state( int rc = 0; CAM_DBG(CAM_ISP, "try to flush pending list"); + spin_lock_bh(&ctx->lock); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + spin_unlock_bh(&ctx->lock); CAM_DBG(CAM_ISP, "Flush request in top state %d", ctx->state); return rc; @@ -1402,10 +1399,10 @@ static int __cam_isp_ctx_flush_req_in_activated( spin_lock_bh(&ctx->lock); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_FLUSH; ctx_isp->frame_skip_count = 2; - spin_unlock_bh(&ctx->lock); CAM_DBG(CAM_ISP, "Flush request in state %d", ctx->state); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + spin_unlock_bh(&ctx->lock); return rc; } @@ -1416,10 +1413,10 @@ static int __cam_isp_ctx_flush_req_in_ready( int rc = 0; CAM_DBG(CAM_ISP, "try to flush pending list"); + spin_lock_bh(&ctx->lock); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); /* if nothing is in pending req list, change state to acquire*/ - spin_lock_bh(&ctx->lock); if (list_empty(&ctx->pending_req_list)) ctx->state = CAM_CTX_ACQUIRED; spin_unlock_bh(&ctx->lock); @@ -1995,8 +1992,9 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, flush_req.dev_hdl = ctx->dev_hdl; CAM_DBG(CAM_ISP, "try to flush pending list"); + spin_lock_bh(&ctx->lock); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, &flush_req); - + spin_unlock_bh(&ctx->lock); ctx->state = CAM_CTX_AVAILABLE; trace_cam_context_state("ISP", ctx); -- GitLab From 83797a770fe0b4bcbe6f19fa71404d97aaddfda4 Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Sat, 7 Apr 2018 15:50:47 +0300 Subject: [PATCH 234/855] ipvs: fix rtnl_lock lockups caused by start_sync_thread commit 5c64576a77894a50be80be0024bed27171b55989 upstream. syzkaller reports for wrong rtnl_lock usage in sync code [1] and [2] We have 2 problems in start_sync_thread if error path is taken, eg. on memory allocation error or failure to configure sockets for mcast group or addr/port binding: 1. recursive locking: holding rtnl_lock while calling sock_release which in turn calls again rtnl_lock in ip_mc_drop_socket to leave the mcast group, as noticed by Florian Westphal. Additionally, sock_release can not be called while holding sync_mutex (ABBA deadlock). 2. task hung: holding rtnl_lock while calling kthread_stop to stop the running kthreads. As the kthreads do the same to leave the mcast group (sock_release -> ip_mc_drop_socket -> rtnl_lock) they hang. Fix the problems by calling rtnl_unlock early in the error path, now sock_release is called after unlocking both mutexes. Problem 3 (task hung reported by syzkaller [2]) is variant of problem 2: use _trylock to prevent one user to call rtnl_lock and then while waiting for sync_mutex to block kthreads that execute sock_release when they are stopped by stop_sync_thread. [1] IPVS: stopping backup sync thread 4500 ... WARNING: possible recursive locking detected 4.16.0-rc7+ #3 Not tainted -------------------------------------------- syzkaller688027/4497 is trying to acquire lock: (rtnl_mutex){+.+.}, at: [<00000000bb14d7fb>] rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74 but task is already holding lock: IPVS: stopping backup sync thread 4495 ... (rtnl_mutex){+.+.}, at: [<00000000bb14d7fb>] rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(rtnl_mutex); lock(rtnl_mutex); *** DEADLOCK *** May be due to missing lock nesting notation 2 locks held by syzkaller688027/4497: #0: (rtnl_mutex){+.+.}, at: [<00000000bb14d7fb>] rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74 #1: (ipvs->sync_mutex){+.+.}, at: [<00000000703f78e3>] do_ip_vs_set_ctl+0x10f8/0x1cc0 net/netfilter/ipvs/ip_vs_ctl.c:2388 stack backtrace: CPU: 1 PID: 4497 Comm: syzkaller688027 Not tainted 4.16.0-rc7+ #3 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x194/0x24d lib/dump_stack.c:53 print_deadlock_bug kernel/locking/lockdep.c:1761 [inline] check_deadlock kernel/locking/lockdep.c:1805 [inline] validate_chain kernel/locking/lockdep.c:2401 [inline] __lock_acquire+0xe8f/0x3e00 kernel/locking/lockdep.c:3431 lock_acquire+0x1d5/0x580 kernel/locking/lockdep.c:3920 __mutex_lock_common kernel/locking/mutex.c:756 [inline] __mutex_lock+0x16f/0x1a80 kernel/locking/mutex.c:893 mutex_lock_nested+0x16/0x20 kernel/locking/mutex.c:908 rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74 ip_mc_drop_socket+0x88/0x230 net/ipv4/igmp.c:2643 inet_release+0x4e/0x1c0 net/ipv4/af_inet.c:413 sock_release+0x8d/0x1e0 net/socket.c:595 start_sync_thread+0x2213/0x2b70 net/netfilter/ipvs/ip_vs_sync.c:1924 do_ip_vs_set_ctl+0x1139/0x1cc0 net/netfilter/ipvs/ip_vs_ctl.c:2389 nf_sockopt net/netfilter/nf_sockopt.c:106 [inline] nf_setsockopt+0x67/0xc0 net/netfilter/nf_sockopt.c:115 ip_setsockopt+0x97/0xa0 net/ipv4/ip_sockglue.c:1261 udp_setsockopt+0x45/0x80 net/ipv4/udp.c:2406 sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2975 SYSC_setsockopt net/socket.c:1849 [inline] SyS_setsockopt+0x189/0x360 net/socket.c:1828 do_syscall_64+0x281/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x446a69 RSP: 002b:00007fa1c3a64da8 EFLAGS: 00000246 ORIG_RAX: 0000000000000036 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 0000000000446a69 RDX: 000000000000048b RSI: 0000000000000000 RDI: 0000000000000003 RBP: 00000000006e29fc R08: 0000000000000018 R09: 0000000000000000 R10: 00000000200000c0 R11: 0000000000000246 R12: 00000000006e29f8 R13: 00676e697279656b R14: 00007fa1c3a659c0 R15: 00000000006e2b60 [2] IPVS: sync thread started: state = BACKUP, mcast_ifn = syz_tun, syncid = 4, id = 0 IPVS: stopping backup sync thread 25415 ... INFO: task syz-executor7:25421 blocked for more than 120 seconds. Not tainted 4.16.0-rc6+ #284 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. syz-executor7 D23688 25421 4408 0x00000004 Call Trace: context_switch kernel/sched/core.c:2862 [inline] __schedule+0x8fb/0x1ec0 kernel/sched/core.c:3440 schedule+0xf5/0x430 kernel/sched/core.c:3499 schedule_timeout+0x1a3/0x230 kernel/time/timer.c:1777 do_wait_for_common kernel/sched/completion.c:86 [inline] __wait_for_common kernel/sched/completion.c:107 [inline] wait_for_common kernel/sched/completion.c:118 [inline] wait_for_completion+0x415/0x770 kernel/sched/completion.c:139 kthread_stop+0x14a/0x7a0 kernel/kthread.c:530 stop_sync_thread+0x3d9/0x740 net/netfilter/ipvs/ip_vs_sync.c:1996 do_ip_vs_set_ctl+0x2b1/0x1cc0 net/netfilter/ipvs/ip_vs_ctl.c:2394 nf_sockopt net/netfilter/nf_sockopt.c:106 [inline] nf_setsockopt+0x67/0xc0 net/netfilter/nf_sockopt.c:115 ip_setsockopt+0x97/0xa0 net/ipv4/ip_sockglue.c:1253 sctp_setsockopt+0x2ca/0x63e0 net/sctp/socket.c:4154 sock_common_setsockopt+0x95/0xd0 net/core/sock.c:3039 SYSC_setsockopt net/socket.c:1850 [inline] SyS_setsockopt+0x189/0x360 net/socket.c:1829 do_syscall_64+0x281/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x454889 RSP: 002b:00007fc927626c68 EFLAGS: 00000246 ORIG_RAX: 0000000000000036 RAX: ffffffffffffffda RBX: 00007fc9276276d4 RCX: 0000000000454889 RDX: 000000000000048c RSI: 0000000000000000 RDI: 0000000000000017 RBP: 000000000072bf58 R08: 0000000000000018 R09: 0000000000000000 R10: 0000000020000000 R11: 0000000000000246 R12: 00000000ffffffff R13: 000000000000051c R14: 00000000006f9b40 R15: 0000000000000001 Showing all locks held in the system: 2 locks held by khungtaskd/868: #0: (rcu_read_lock){....}, at: [<00000000a1a8f002>] check_hung_uninterruptible_tasks kernel/hung_task.c:175 [inline] #0: (rcu_read_lock){....}, at: [<00000000a1a8f002>] watchdog+0x1c5/0xd60 kernel/hung_task.c:249 #1: (tasklist_lock){.+.+}, at: [<0000000037c2f8f9>] debug_show_all_locks+0xd3/0x3d0 kernel/locking/lockdep.c:4470 1 lock held by rsyslogd/4247: #0: (&f->f_pos_lock){+.+.}, at: [<000000000d8d6983>] __fdget_pos+0x12b/0x190 fs/file.c:765 2 locks held by getty/4338: #0: (&tty->ldisc_sem){++++}, at: [<00000000bee98654>] ldsem_down_read+0x37/0x40 drivers/tty/tty_ldsem.c:365 #1: (&ldata->atomic_read_lock){+.+.}, at: [<00000000c1d180aa>] n_tty_read+0x2ef/0x1a40 drivers/tty/n_tty.c:2131 2 locks held by getty/4339: #0: (&tty->ldisc_sem){++++}, at: [<00000000bee98654>] ldsem_down_read+0x37/0x40 drivers/tty/tty_ldsem.c:365 #1: (&ldata->atomic_read_lock){+.+.}, at: [<00000000c1d180aa>] n_tty_read+0x2ef/0x1a40 drivers/tty/n_tty.c:2131 2 locks held by getty/4340: #0: (&tty->ldisc_sem){++++}, at: [<00000000bee98654>] ldsem_down_read+0x37/0x40 drivers/tty/tty_ldsem.c:365 #1: (&ldata->atomic_read_lock){+.+.}, at: [<00000000c1d180aa>] n_tty_read+0x2ef/0x1a40 drivers/tty/n_tty.c:2131 2 locks held by getty/4341: #0: (&tty->ldisc_sem){++++}, at: [<00000000bee98654>] ldsem_down_read+0x37/0x40 drivers/tty/tty_ldsem.c:365 #1: (&ldata->atomic_read_lock){+.+.}, at: [<00000000c1d180aa>] n_tty_read+0x2ef/0x1a40 drivers/tty/n_tty.c:2131 2 locks held by getty/4342: #0: (&tty->ldisc_sem){++++}, at: [<00000000bee98654>] ldsem_down_read+0x37/0x40 drivers/tty/tty_ldsem.c:365 #1: (&ldata->atomic_read_lock){+.+.}, at: [<00000000c1d180aa>] n_tty_read+0x2ef/0x1a40 drivers/tty/n_tty.c:2131 2 locks held by getty/4343: #0: (&tty->ldisc_sem){++++}, at: [<00000000bee98654>] ldsem_down_read+0x37/0x40 drivers/tty/tty_ldsem.c:365 #1: (&ldata->atomic_read_lock){+.+.}, at: [<00000000c1d180aa>] n_tty_read+0x2ef/0x1a40 drivers/tty/n_tty.c:2131 2 locks held by getty/4344: #0: (&tty->ldisc_sem){++++}, at: [<00000000bee98654>] ldsem_down_read+0x37/0x40 drivers/tty/tty_ldsem.c:365 #1: (&ldata->atomic_read_lock){+.+.}, at: [<00000000c1d180aa>] n_tty_read+0x2ef/0x1a40 drivers/tty/n_tty.c:2131 3 locks held by kworker/0:5/6494: #0: ((wq_completion)"%s"("ipv6_addrconf")){+.+.}, at: [<00000000a062b18e>] work_static include/linux/workqueue.h:198 [inline] #0: ((wq_completion)"%s"("ipv6_addrconf")){+.+.}, at: [<00000000a062b18e>] set_work_data kernel/workqueue.c:619 [inline] #0: ((wq_completion)"%s"("ipv6_addrconf")){+.+.}, at: [<00000000a062b18e>] set_work_pool_and_clear_pending kernel/workqueue.c:646 [inline] #0: ((wq_completion)"%s"("ipv6_addrconf")){+.+.}, at: [<00000000a062b18e>] process_one_work+0xb12/0x1bb0 kernel/workqueue.c:2084 #1: ((addr_chk_work).work){+.+.}, at: [<00000000278427d5>] process_one_work+0xb89/0x1bb0 kernel/workqueue.c:2088 #2: (rtnl_mutex){+.+.}, at: [<00000000066e35ac>] rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74 1 lock held by syz-executor7/25421: #0: (ipvs->sync_mutex){+.+.}, at: [<00000000d414a689>] do_ip_vs_set_ctl+0x277/0x1cc0 net/netfilter/ipvs/ip_vs_ctl.c:2393 2 locks held by syz-executor7/25427: #0: (rtnl_mutex){+.+.}, at: [<00000000066e35ac>] rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74 #1: (ipvs->sync_mutex){+.+.}, at: [<00000000e6d48489>] do_ip_vs_set_ctl+0x10f8/0x1cc0 net/netfilter/ipvs/ip_vs_ctl.c:2388 1 lock held by syz-executor7/25435: #0: (rtnl_mutex){+.+.}, at: [<00000000066e35ac>] rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74 1 lock held by ipvs-b:2:0/25415: #0: (rtnl_mutex){+.+.}, at: [<00000000066e35ac>] rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74 Reported-and-tested-by: syzbot+a46d6abf9d56b1365a72@syzkaller.appspotmail.com Reported-and-tested-by: syzbot+5fe074c01b2032ce9618@syzkaller.appspotmail.com Fixes: e0b26cc997d5 ("ipvs: call rtnl_lock early") Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Pablo Neira Ayuso Cc: Zubin Mithra Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- net/netfilter/ipvs/ip_vs_ctl.c | 8 -- net/netfilter/ipvs/ip_vs_sync.c | 155 ++++++++++++++++---------------- 2 files changed, 80 insertions(+), 83 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 74d119512d96..c5f2350a2b50 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -2393,11 +2393,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) strlcpy(cfg.mcast_ifn, dm->mcast_ifn, sizeof(cfg.mcast_ifn)); cfg.syncid = dm->syncid; - rtnl_lock(); - mutex_lock(&ipvs->sync_mutex); ret = start_sync_thread(ipvs, &cfg, dm->state); - mutex_unlock(&ipvs->sync_mutex); - rtnl_unlock(); } else { mutex_lock(&ipvs->sync_mutex); ret = stop_sync_thread(ipvs, dm->state); @@ -3495,12 +3491,8 @@ static int ip_vs_genl_new_daemon(struct netns_ipvs *ipvs, struct nlattr **attrs) if (ipvs->mixed_address_family_dests > 0) return -EINVAL; - rtnl_lock(); - mutex_lock(&ipvs->sync_mutex); ret = start_sync_thread(ipvs, &c, nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE])); - mutex_unlock(&ipvs->sync_mutex); - rtnl_unlock(); return ret; } diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 9350530c16c1..5fbf4b232592 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -48,6 +48,7 @@ #include #include #include +#include #include /* Used for ntoh_seq and hton_seq */ @@ -1359,15 +1360,9 @@ static void set_mcast_pmtudisc(struct sock *sk, int val) /* * Specifiy default interface for outgoing multicasts */ -static int set_mcast_if(struct sock *sk, char *ifname) +static int set_mcast_if(struct sock *sk, struct net_device *dev) { - struct net_device *dev; struct inet_sock *inet = inet_sk(sk); - struct net *net = sock_net(sk); - - dev = __dev_get_by_name(net, ifname); - if (!dev) - return -ENODEV; if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) return -EINVAL; @@ -1395,19 +1390,14 @@ static int set_mcast_if(struct sock *sk, char *ifname) * in the in_addr structure passed in as a parameter. */ static int -join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname) +join_mcast_group(struct sock *sk, struct in_addr *addr, struct net_device *dev) { - struct net *net = sock_net(sk); struct ip_mreqn mreq; - struct net_device *dev; int ret; memset(&mreq, 0, sizeof(mreq)); memcpy(&mreq.imr_multiaddr, addr, sizeof(struct in_addr)); - dev = __dev_get_by_name(net, ifname); - if (!dev) - return -ENODEV; if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) return -EINVAL; @@ -1422,15 +1412,10 @@ join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname) #ifdef CONFIG_IP_VS_IPV6 static int join_mcast_group6(struct sock *sk, struct in6_addr *addr, - char *ifname) + struct net_device *dev) { - struct net *net = sock_net(sk); - struct net_device *dev; int ret; - dev = __dev_get_by_name(net, ifname); - if (!dev) - return -ENODEV; if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) return -EINVAL; @@ -1442,24 +1427,18 @@ static int join_mcast_group6(struct sock *sk, struct in6_addr *addr, } #endif -static int bind_mcastif_addr(struct socket *sock, char *ifname) +static int bind_mcastif_addr(struct socket *sock, struct net_device *dev) { - struct net *net = sock_net(sock->sk); - struct net_device *dev; __be32 addr; struct sockaddr_in sin; - dev = __dev_get_by_name(net, ifname); - if (!dev) - return -ENODEV; - addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); if (!addr) pr_err("You probably need to specify IP address on " "multicast interface.\n"); IP_VS_DBG(7, "binding socket with (%s) %pI4\n", - ifname, &addr); + dev->name, &addr); /* Now bind the socket with the address of multicast interface */ sin.sin_family = AF_INET; @@ -1492,7 +1471,8 @@ static void get_mcast_sockaddr(union ipvs_sockaddr *sa, int *salen, /* * Set up sending multicast socket over UDP */ -static struct socket *make_send_sock(struct netns_ipvs *ipvs, int id) +static int make_send_sock(struct netns_ipvs *ipvs, int id, + struct net_device *dev, struct socket **sock_ret) { /* multicast addr */ union ipvs_sockaddr mcast_addr; @@ -1504,9 +1484,10 @@ static struct socket *make_send_sock(struct netns_ipvs *ipvs, int id) IPPROTO_UDP, &sock); if (result < 0) { pr_err("Error during creation of socket; terminating\n"); - return ERR_PTR(result); + goto error; } - result = set_mcast_if(sock->sk, ipvs->mcfg.mcast_ifn); + *sock_ret = sock; + result = set_mcast_if(sock->sk, dev); if (result < 0) { pr_err("Error setting outbound mcast interface\n"); goto error; @@ -1521,7 +1502,7 @@ static struct socket *make_send_sock(struct netns_ipvs *ipvs, int id) set_sock_size(sock->sk, 1, result); if (AF_INET == ipvs->mcfg.mcast_af) - result = bind_mcastif_addr(sock, ipvs->mcfg.mcast_ifn); + result = bind_mcastif_addr(sock, dev); else result = 0; if (result < 0) { @@ -1537,19 +1518,18 @@ static struct socket *make_send_sock(struct netns_ipvs *ipvs, int id) goto error; } - return sock; + return 0; error: - sock_release(sock); - return ERR_PTR(result); + return result; } /* * Set up receiving multicast socket over UDP */ -static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id, - int ifindex) +static int make_receive_sock(struct netns_ipvs *ipvs, int id, + struct net_device *dev, struct socket **sock_ret) { /* multicast addr */ union ipvs_sockaddr mcast_addr; @@ -1561,8 +1541,9 @@ static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id, IPPROTO_UDP, &sock); if (result < 0) { pr_err("Error during creation of socket; terminating\n"); - return ERR_PTR(result); + goto error; } + *sock_ret = sock; /* it is equivalent to the REUSEADDR option in user-space */ sock->sk->sk_reuse = SK_CAN_REUSE; result = sysctl_sync_sock_size(ipvs); @@ -1570,7 +1551,7 @@ static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id, set_sock_size(sock->sk, 0, result); get_mcast_sockaddr(&mcast_addr, &salen, &ipvs->bcfg, id); - sock->sk->sk_bound_dev_if = ifindex; + sock->sk->sk_bound_dev_if = dev->ifindex; result = sock->ops->bind(sock, (struct sockaddr *)&mcast_addr, salen); if (result < 0) { pr_err("Error binding to the multicast addr\n"); @@ -1581,21 +1562,20 @@ static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id, #ifdef CONFIG_IP_VS_IPV6 if (ipvs->bcfg.mcast_af == AF_INET6) result = join_mcast_group6(sock->sk, &mcast_addr.in6.sin6_addr, - ipvs->bcfg.mcast_ifn); + dev); else #endif result = join_mcast_group(sock->sk, &mcast_addr.in.sin_addr, - ipvs->bcfg.mcast_ifn); + dev); if (result < 0) { pr_err("Error joining to the multicast group\n"); goto error; } - return sock; + return 0; error: - sock_release(sock); - return ERR_PTR(result); + return result; } @@ -1780,13 +1760,12 @@ static int sync_thread_backup(void *data) int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, int state) { - struct ip_vs_sync_thread_data *tinfo; + struct ip_vs_sync_thread_data *tinfo = NULL; struct task_struct **array = NULL, *task; - struct socket *sock; struct net_device *dev; char *name; int (*threadfn)(void *data); - int id, count, hlen; + int id = 0, count, hlen; int result = -ENOMEM; u16 mtu, min_mtu; @@ -1794,6 +1773,18 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %Zd bytes\n", sizeof(struct ip_vs_sync_conn_v0)); + /* Do not hold one mutex and then to block on another */ + for (;;) { + rtnl_lock(); + if (mutex_trylock(&ipvs->sync_mutex)) + break; + rtnl_unlock(); + mutex_lock(&ipvs->sync_mutex); + if (rtnl_trylock()) + break; + mutex_unlock(&ipvs->sync_mutex); + } + if (!ipvs->sync_state) { count = clamp(sysctl_sync_ports(ipvs), 1, IPVS_SYNC_PORTS_MAX); ipvs->threads_mask = count - 1; @@ -1812,7 +1803,8 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, dev = __dev_get_by_name(ipvs->net, c->mcast_ifn); if (!dev) { pr_err("Unknown mcast interface: %s\n", c->mcast_ifn); - return -ENODEV; + result = -ENODEV; + goto out_early; } hlen = (AF_INET6 == c->mcast_af) ? sizeof(struct ipv6hdr) + sizeof(struct udphdr) : @@ -1829,26 +1821,30 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, c->sync_maxlen = mtu - hlen; if (state == IP_VS_STATE_MASTER) { + result = -EEXIST; if (ipvs->ms) - return -EEXIST; + goto out_early; ipvs->mcfg = *c; name = "ipvs-m:%d:%d"; threadfn = sync_thread_master; } else if (state == IP_VS_STATE_BACKUP) { + result = -EEXIST; if (ipvs->backup_threads) - return -EEXIST; + goto out_early; ipvs->bcfg = *c; name = "ipvs-b:%d:%d"; threadfn = sync_thread_backup; } else { - return -EINVAL; + result = -EINVAL; + goto out_early; } if (state == IP_VS_STATE_MASTER) { struct ipvs_master_sync_state *ms; + result = -ENOMEM; ipvs->ms = kzalloc(count * sizeof(ipvs->ms[0]), GFP_KERNEL); if (!ipvs->ms) goto out; @@ -1864,39 +1860,38 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, } else { array = kzalloc(count * sizeof(struct task_struct *), GFP_KERNEL); + result = -ENOMEM; if (!array) goto out; } - tinfo = NULL; for (id = 0; id < count; id++) { - if (state == IP_VS_STATE_MASTER) - sock = make_send_sock(ipvs, id); - else - sock = make_receive_sock(ipvs, id, dev->ifindex); - if (IS_ERR(sock)) { - result = PTR_ERR(sock); - goto outtinfo; - } + result = -ENOMEM; tinfo = kmalloc(sizeof(*tinfo), GFP_KERNEL); if (!tinfo) - goto outsocket; + goto out; tinfo->ipvs = ipvs; - tinfo->sock = sock; + tinfo->sock = NULL; if (state == IP_VS_STATE_BACKUP) { tinfo->buf = kmalloc(ipvs->bcfg.sync_maxlen, GFP_KERNEL); if (!tinfo->buf) - goto outtinfo; + goto out; } else { tinfo->buf = NULL; } tinfo->id = id; + if (state == IP_VS_STATE_MASTER) + result = make_send_sock(ipvs, id, dev, &tinfo->sock); + else + result = make_receive_sock(ipvs, id, dev, &tinfo->sock); + if (result < 0) + goto out; task = kthread_run(threadfn, tinfo, name, ipvs->gen, id); if (IS_ERR(task)) { result = PTR_ERR(task); - goto outtinfo; + goto out; } tinfo = NULL; if (state == IP_VS_STATE_MASTER) @@ -1913,20 +1908,20 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, ipvs->sync_state |= state; spin_unlock_bh(&ipvs->sync_buff_lock); + mutex_unlock(&ipvs->sync_mutex); + rtnl_unlock(); + /* increase the module use count */ ip_vs_use_count_inc(); return 0; -outsocket: - sock_release(sock); - -outtinfo: - if (tinfo) { - sock_release(tinfo->sock); - kfree(tinfo->buf); - kfree(tinfo); - } +out: + /* We do not need RTNL lock anymore, release it here so that + * sock_release below and in the kthreads can use rtnl_lock + * to leave the mcast group. + */ + rtnl_unlock(); count = id; while (count-- > 0) { if (state == IP_VS_STATE_MASTER) @@ -1934,13 +1929,23 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, else kthread_stop(array[count]); } - kfree(array); - -out: if (!(ipvs->sync_state & IP_VS_STATE_MASTER)) { kfree(ipvs->ms); ipvs->ms = NULL; } + mutex_unlock(&ipvs->sync_mutex); + if (tinfo) { + if (tinfo->sock) + sock_release(tinfo->sock); + kfree(tinfo->buf); + kfree(tinfo); + } + kfree(array); + return result; + +out_early: + mutex_unlock(&ipvs->sync_mutex); + rtnl_unlock(); return result; } -- GitLab From 1899f679355d34d18447e76fa76eae16299fddda Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 8 Mar 2017 22:03:17 +0200 Subject: [PATCH 235/855] IB/device: Convert ib-comp-wq to be CPU-bound commit b7363e67b23e04c23c2a99437feefac7292a88bc upstream. This workqueue is used by our storage target mode ULPs via the new CQ API. Recent observations when working with very high-end flash storage devices reveal that UNBOUND workqueue threads can migrate between cpu cores and even numa nodes (although some numa locality is accounted for). While this attribute can be useful in some workloads, it does not fit in very nicely with the normal run-to-completion model we usually use in our target-mode ULPs and the block-mq irq<->cpu affinity facilities. The whole block-mq concept is that the completion will land on the same cpu where the submission was performed. The fact that our submitter thread is migrating cpus can break this locality. We assume that as a target mode ULP, we will serve multiple initiators/clients and we can spread the load enough without having to use unbound kworkers. Also, while we're at it, expose this workqueue via sysfs which is harmless and can be useful for debug. Signed-off-by: Sagi Grimberg Reviewed-by: Bart Van Assche -- Signed-off-by: Doug Ledford Cc: Raju Rangoju Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/device.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 760ef603a468..15f4bdf89fe1 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -999,8 +999,7 @@ static int __init ib_core_init(void) return -ENOMEM; ib_comp_wq = alloc_workqueue("ib-comp-wq", - WQ_UNBOUND | WQ_HIGHPRI | WQ_MEM_RECLAIM, - WQ_UNBOUND_MAX_ACTIVE); + WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_SYSFS, 0); if (!ib_comp_wq) { ret = -ENOMEM; goto err; -- GitLab From 383250363daf01eb7aa3728c09ef8a4f6d8a3252 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Wed, 14 Feb 2018 09:22:42 -0800 Subject: [PATCH 236/855] kcm: Call strp_stop before strp_done in kcm_attach commit dff8baa261174de689a44572d0ea182d7aa70598 upstream. In kcm_attach strp_done is called when sk_user_data is already set to fail the attach. strp_done needs the strp to be stopped and warns if it isn't. Call strp_stop in this case to eliminate the warning message. Reported-by: syzbot+88dfb55e4c8b770d86e3@syzkaller.appspotmail.com Fixes: e5571240236c5652f ("kcm: Check if sk_user_data already set in kcm_attach" Signed-off-by: Tom Herbert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/kcm/kcmsock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 63e6d08388ab..cc306defcc19 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -1424,6 +1424,7 @@ static int kcm_attach(struct socket *sock, struct socket *csock, */ if (csk->sk_user_data) { write_unlock_bh(&csk->sk_callback_lock); + strp_stop(&psock->strp); strp_done(&psock->strp); kmem_cache_free(kcm_psockp, psock); err = -EALREADY; -- GitLab From 7b38b6dd316e5359c70fc11df7eb27825d4f3f15 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 7 Apr 2018 13:42:36 -0700 Subject: [PATCH 237/855] crypto: af_alg - fix possible uninit-value in alg_bind() commit a466856e0b7ab269cdf9461886d007e88ff575b0 upstream. syzbot reported : BUG: KMSAN: uninit-value in alg_bind+0xe3/0xd90 crypto/af_alg.c:162 We need to check addr_len before dereferencing sa (or uaddr) Fixes: bb30b8848c85 ("crypto: af_alg - whitelist mask and type") Signed-off-by: Eric Dumazet Reported-by: syzbot Cc: Stephan Mueller Cc: Herbert Xu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- crypto/af_alg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index ca50eeb13097..b5953f1d1a18 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -157,16 +157,16 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) void *private; int err; - /* If caller uses non-allowed flag, return error. */ - if ((sa->salg_feat & ~allowed) || (sa->salg_mask & ~allowed)) - return -EINVAL; - if (sock->state == SS_CONNECTED) return -EINVAL; if (addr_len != sizeof(*sa)) return -EINVAL; + /* If caller uses non-allowed flag, return error. */ + if ((sa->salg_feat & ~allowed) || (sa->salg_mask & ~allowed)) + return -EINVAL; + sa->salg_type[sizeof(sa->salg_type) - 1] = 0; sa->salg_name[sizeof(sa->salg_name) - 1] = 0; -- GitLab From 473ac55c5e036a73455bfbf5bf7b7bffeac4fa3d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 7 Apr 2018 13:42:37 -0700 Subject: [PATCH 238/855] netlink: fix uninit-value in netlink_sendmsg commit 6091f09c2f79730d895149bcfe3d66140288cd0e upstream. syzbot reported : BUG: KMSAN: uninit-value in ffs arch/x86/include/asm/bitops.h:432 [inline] BUG: KMSAN: uninit-value in netlink_sendmsg+0xb26/0x1310 net/netlink/af_netlink.c:1851 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/netlink/af_netlink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 1e97b8d9a159..15e6e7b9fd2b 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1795,6 +1795,8 @@ static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) if (msg->msg_namelen) { err = -EINVAL; + if (msg->msg_namelen < sizeof(struct sockaddr_nl)) + goto out; if (addr->nl_family != AF_NETLINK) goto out; dst_portid = addr->nl_pid; -- GitLab From a3cac7e26bbd944cc8bfc96c81d6784fbde594ec Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 7 Apr 2018 13:42:38 -0700 Subject: [PATCH 239/855] net: fix rtnh_ok() commit b1993a2de12c9e75c35729e2ffbc3a92d50c0d31 upstream. syzbot reported : BUG: KMSAN: uninit-value in rtnh_ok include/net/nexthop.h:11 [inline] BUG: KMSAN: uninit-value in fib_count_nexthops net/ipv4/fib_semantics.c:469 [inline] BUG: KMSAN: uninit-value in fib_create_info+0x554/0x8d20 net/ipv4/fib_semantics.c:1091 @remaining is an integer, coming from user space. If it is negative we want rtnh_ok() to return false. Fixes: 4e902c57417c ("[IPv4]: FIB configuration using struct fib_config") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/nexthop.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/nexthop.h b/include/net/nexthop.h index 3334dbfa5aa4..7fc78663ec9d 100644 --- a/include/net/nexthop.h +++ b/include/net/nexthop.h @@ -6,7 +6,7 @@ static inline int rtnh_ok(const struct rtnexthop *rtnh, int remaining) { - return remaining >= sizeof(*rtnh) && + return remaining >= (int)sizeof(*rtnh) && rtnh->rtnh_len >= sizeof(*rtnh) && rtnh->rtnh_len <= remaining; } -- GitLab From ec98618c20d0ba798798ec93fb366681f18347de Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 7 Apr 2018 13:42:39 -0700 Subject: [PATCH 240/855] net: initialize skb->peeked when cloning commit b13dda9f9aa7caceeee61c080c2e544d5f5d85e5 upstream. syzbot reported __skb_try_recv_from_queue() was using skb->peeked while it was potentially unitialized. We need to clear it in __skb_clone() Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/skbuff.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index fb422dfec848..a40ccc184b83 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -903,6 +903,7 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len; n->cloned = 1; n->nohdr = 0; + n->peeked = 0; n->destructor = NULL; C(tail); C(end); -- GitLab From 45227db4a6c2174b8aaf55c4a607aa55b134a74e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 7 Apr 2018 13:42:40 -0700 Subject: [PATCH 241/855] net: fix uninit-value in __hw_addr_add_ex() commit 77d36398d99f2565c0a8d43a86fd520a82e64bb8 upstream. syzbot complained : BUG: KMSAN: uninit-value in memcmp+0x119/0x180 lib/string.c:861 CPU: 0 PID: 3 Comm: kworker/0:0 Not tainted 4.16.0+ #82 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Workqueue: ipv6_addrconf addrconf_dad_work Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 memcmp+0x119/0x180 lib/string.c:861 __hw_addr_add_ex net/core/dev_addr_lists.c:60 [inline] __dev_mc_add+0x1c2/0x8e0 net/core/dev_addr_lists.c:670 dev_mc_add+0x6d/0x80 net/core/dev_addr_lists.c:687 igmp6_group_added+0x2db/0xa00 net/ipv6/mcast.c:662 ipv6_dev_mc_inc+0xe9e/0x1130 net/ipv6/mcast.c:914 addrconf_join_solict net/ipv6/addrconf.c:2078 [inline] addrconf_dad_begin net/ipv6/addrconf.c:3828 [inline] addrconf_dad_work+0x427/0x2150 net/ipv6/addrconf.c:3954 process_one_work+0x12c6/0x1f60 kernel/workqueue.c:2113 worker_thread+0x113c/0x24f0 kernel/workqueue.c:2247 kthread+0x539/0x720 kernel/kthread.c:239 Fixes: f001fde5eadd ("net: introduce a list of device addresses dev_addr_list (v6)") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev_addr_lists.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c index c0548d268e1a..e3e6a3e2ca22 100644 --- a/net/core/dev_addr_lists.c +++ b/net/core/dev_addr_lists.c @@ -57,8 +57,8 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list, return -EINVAL; list_for_each_entry(ha, &list->list, list) { - if (!memcmp(ha->addr, addr, addr_len) && - ha->type == addr_type) { + if (ha->type == addr_type && + !memcmp(ha->addr, addr, addr_len)) { if (global) { /* check if addr is already used as global */ if (ha->global_use) -- GitLab From 543cb05defa68c8020fefb04d09420fc13d6b626 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 7 Apr 2018 13:42:41 -0700 Subject: [PATCH 242/855] dccp: initialize ireq->ir_mark commit b855ff827476adbdc2259e9895681d82b7b26065 upstream. syzbot reported an uninit-value read of skb->mark in iptable_mangle_hook() Thanks to the nice report, I tracked the problem to dccp not caring of ireq->ir_mark for passive sessions. BUG: KMSAN: uninit-value in ipt_mangle_out net/ipv4/netfilter/iptable_mangle.c:66 [inline] BUG: KMSAN: uninit-value in iptable_mangle_hook+0x5e5/0x720 net/ipv4/netfilter/iptable_mangle.c:84 CPU: 0 PID: 5300 Comm: syz-executor3 Not tainted 4.16.0+ #81 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 ipt_mangle_out net/ipv4/netfilter/iptable_mangle.c:66 [inline] iptable_mangle_hook+0x5e5/0x720 net/ipv4/netfilter/iptable_mangle.c:84 nf_hook_entry_hookfn include/linux/netfilter.h:120 [inline] nf_hook_slow+0x158/0x3d0 net/netfilter/core.c:483 nf_hook include/linux/netfilter.h:243 [inline] __ip_local_out net/ipv4/ip_output.c:113 [inline] ip_local_out net/ipv4/ip_output.c:122 [inline] ip_queue_xmit+0x1d21/0x21c0 net/ipv4/ip_output.c:504 dccp_transmit_skb+0x15eb/0x1900 net/dccp/output.c:142 dccp_xmit_packet+0x814/0x9e0 net/dccp/output.c:281 dccp_write_xmit+0x20f/0x480 net/dccp/output.c:363 dccp_sendmsg+0x12ca/0x12d0 net/dccp/proto.c:818 inet_sendmsg+0x48d/0x740 net/ipv4/af_inet.c:764 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2046 __sys_sendmsg net/socket.c:2080 [inline] SYSC_sendmsg+0x2a3/0x3d0 net/socket.c:2091 SyS_sendmsg+0x54/0x80 net/socket.c:2087 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x455259 RSP: 002b:00007f1a4473dc68 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007f1a4473e6d4 RCX: 0000000000455259 RDX: 0000000000000000 RSI: 0000000020b76fc8 RDI: 0000000000000015 RBP: 000000000072bea0 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00000000ffffffff R13: 00000000000004f0 R14: 00000000006fa720 R15: 0000000000000000 Uninit was stored to memory at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_save_stack mm/kmsan/kmsan.c:293 [inline] kmsan_internal_chain_origin+0x12b/0x210 mm/kmsan/kmsan.c:684 __msan_chain_origin+0x69/0xc0 mm/kmsan/kmsan_instr.c:521 ip_queue_xmit+0x1e35/0x21c0 net/ipv4/ip_output.c:502 dccp_transmit_skb+0x15eb/0x1900 net/dccp/output.c:142 dccp_xmit_packet+0x814/0x9e0 net/dccp/output.c:281 dccp_write_xmit+0x20f/0x480 net/dccp/output.c:363 dccp_sendmsg+0x12ca/0x12d0 net/dccp/proto.c:818 inet_sendmsg+0x48d/0x740 net/ipv4/af_inet.c:764 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2046 __sys_sendmsg net/socket.c:2080 [inline] SYSC_sendmsg+0x2a3/0x3d0 net/socket.c:2091 SyS_sendmsg+0x54/0x80 net/socket.c:2087 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Uninit was stored to memory at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_save_stack mm/kmsan/kmsan.c:293 [inline] kmsan_internal_chain_origin+0x12b/0x210 mm/kmsan/kmsan.c:684 __msan_chain_origin+0x69/0xc0 mm/kmsan/kmsan_instr.c:521 inet_csk_clone_lock+0x503/0x580 net/ipv4/inet_connection_sock.c:797 dccp_create_openreq_child+0x7f/0x890 net/dccp/minisocks.c:92 dccp_v4_request_recv_sock+0x22c/0xe90 net/dccp/ipv4.c:408 dccp_v6_request_recv_sock+0x290/0x2000 net/dccp/ipv6.c:414 dccp_check_req+0x7b9/0x8f0 net/dccp/minisocks.c:197 dccp_v4_rcv+0x12e4/0x2630 net/dccp/ipv4.c:840 ip_local_deliver_finish+0x6ed/0xd40 net/ipv4/ip_input.c:216 NF_HOOK include/linux/netfilter.h:288 [inline] ip_local_deliver+0x43c/0x4e0 net/ipv4/ip_input.c:257 dst_input include/net/dst.h:449 [inline] ip_rcv_finish+0x1253/0x16d0 net/ipv4/ip_input.c:397 NF_HOOK include/linux/netfilter.h:288 [inline] ip_rcv+0x119d/0x16f0 net/ipv4/ip_input.c:493 __netif_receive_skb_core+0x47cf/0x4a80 net/core/dev.c:4562 __netif_receive_skb net/core/dev.c:4627 [inline] process_backlog+0x62d/0xe20 net/core/dev.c:5307 napi_poll net/core/dev.c:5705 [inline] net_rx_action+0x7c1/0x1a70 net/core/dev.c:5771 __do_softirq+0x56d/0x93d kernel/softirq.c:285 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:188 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:314 kmem_cache_alloc+0xaab/0xb90 mm/slub.c:2756 reqsk_alloc include/net/request_sock.h:88 [inline] inet_reqsk_alloc+0xc4/0x7f0 net/ipv4/tcp_input.c:6145 dccp_v4_conn_request+0x5cc/0x1770 net/dccp/ipv4.c:600 dccp_v6_conn_request+0x299/0x1880 net/dccp/ipv6.c:317 dccp_rcv_state_process+0x2ea/0x2410 net/dccp/input.c:612 dccp_v4_do_rcv+0x229/0x340 net/dccp/ipv4.c:682 dccp_v6_do_rcv+0x16d/0x1220 net/dccp/ipv6.c:578 sk_backlog_rcv include/net/sock.h:908 [inline] __sk_receive_skb+0x60e/0xf20 net/core/sock.c:513 dccp_v4_rcv+0x24d4/0x2630 net/dccp/ipv4.c:874 ip_local_deliver_finish+0x6ed/0xd40 net/ipv4/ip_input.c:216 NF_HOOK include/linux/netfilter.h:288 [inline] ip_local_deliver+0x43c/0x4e0 net/ipv4/ip_input.c:257 dst_input include/net/dst.h:449 [inline] ip_rcv_finish+0x1253/0x16d0 net/ipv4/ip_input.c:397 NF_HOOK include/linux/netfilter.h:288 [inline] ip_rcv+0x119d/0x16f0 net/ipv4/ip_input.c:493 __netif_receive_skb_core+0x47cf/0x4a80 net/core/dev.c:4562 __netif_receive_skb net/core/dev.c:4627 [inline] process_backlog+0x62d/0xe20 net/core/dev.c:5307 napi_poll net/core/dev.c:5705 [inline] net_rx_action+0x7c1/0x1a70 net/core/dev.c:5771 __do_softirq+0x56d/0x93d kernel/softirq.c:285 Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dccp/ipv4.c | 1 + net/dccp/ipv6.c | 1 + 2 files changed, 2 insertions(+) diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 8c7799cdd3cf..6697b180e122 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -620,6 +620,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) ireq = inet_rsk(req); sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr); sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr); + ireq->ir_mark = inet_request_mark(sk, skb); ireq->ireq_family = AF_INET; ireq->ir_iif = sk->sk_bound_dev_if; diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 28e8252cc5ea..6cbcf399d22b 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -349,6 +349,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; ireq->ireq_family = AF_INET6; + ireq->ir_mark = inet_request_mark(sk, skb); if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) || np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || -- GitLab From e68fb96236f46032def5d2eee26875b4d1eb0f4c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 7 Apr 2018 13:42:43 -0700 Subject: [PATCH 243/855] soreuseport: initialise timewait reuseport field commit 3099a52918937ab86ec47038ad80d377ba16c531 upstream. syzbot reported an uninit-value in inet_csk_bind_conflict() [1] It turns out we never propagated sk->sk_reuseport into timewait socket. [1] BUG: KMSAN: uninit-value in inet_csk_bind_conflict+0x5f9/0x990 net/ipv4/inet_connection_sock.c:151 CPU: 1 PID: 3589 Comm: syzkaller008242 Not tainted 4.16.0+ #82 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 inet_csk_bind_conflict+0x5f9/0x990 net/ipv4/inet_connection_sock.c:151 inet_csk_get_port+0x1d28/0x1e40 net/ipv4/inet_connection_sock.c:320 inet6_bind+0x121c/0x1820 net/ipv6/af_inet6.c:399 SYSC_bind+0x3f2/0x4b0 net/socket.c:1474 SyS_bind+0x54/0x80 net/socket.c:1460 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x4416e9 RSP: 002b:00007ffce6d15c88 EFLAGS: 00000217 ORIG_RAX: 0000000000000031 RAX: ffffffffffffffda RBX: 0100000000000000 RCX: 00000000004416e9 RDX: 000000000000001c RSI: 0000000020402000 RDI: 0000000000000004 RBP: 0000000000000000 R08: 00000000e6d15e08 R09: 00000000e6d15e08 R10: 0000000000000004 R11: 0000000000000217 R12: 0000000000009478 R13: 00000000006cd448 R14: 0000000000000000 R15: 0000000000000000 Uninit was stored to memory at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_save_stack mm/kmsan/kmsan.c:293 [inline] kmsan_internal_chain_origin+0x12b/0x210 mm/kmsan/kmsan.c:684 __msan_chain_origin+0x69/0xc0 mm/kmsan/kmsan_instr.c:521 tcp_time_wait+0xf17/0xf50 net/ipv4/tcp_minisocks.c:283 tcp_rcv_state_process+0xebe/0x6490 net/ipv4/tcp_input.c:6003 tcp_v6_do_rcv+0x11dd/0x1d90 net/ipv6/tcp_ipv6.c:1331 sk_backlog_rcv include/net/sock.h:908 [inline] __release_sock+0x2d6/0x680 net/core/sock.c:2271 release_sock+0x97/0x2a0 net/core/sock.c:2786 tcp_close+0x277/0x18f0 net/ipv4/tcp.c:2269 inet_release+0x240/0x2a0 net/ipv4/af_inet.c:427 inet6_release+0xaf/0x100 net/ipv6/af_inet6.c:435 sock_release net/socket.c:595 [inline] sock_close+0xe0/0x300 net/socket.c:1149 __fput+0x49e/0xa10 fs/file_table.c:209 ____fput+0x37/0x40 fs/file_table.c:243 task_work_run+0x243/0x2c0 kernel/task_work.c:113 exit_task_work include/linux/task_work.h:22 [inline] do_exit+0x10e1/0x38d0 kernel/exit.c:867 do_group_exit+0x1a0/0x360 kernel/exit.c:970 SYSC_exit_group+0x21/0x30 kernel/exit.c:981 SyS_exit_group+0x25/0x30 kernel/exit.c:979 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Uninit was stored to memory at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_save_stack mm/kmsan/kmsan.c:293 [inline] kmsan_internal_chain_origin+0x12b/0x210 mm/kmsan/kmsan.c:684 __msan_chain_origin+0x69/0xc0 mm/kmsan/kmsan_instr.c:521 inet_twsk_alloc+0xaef/0xc00 net/ipv4/inet_timewait_sock.c:182 tcp_time_wait+0xd9/0xf50 net/ipv4/tcp_minisocks.c:258 tcp_rcv_state_process+0xebe/0x6490 net/ipv4/tcp_input.c:6003 tcp_v6_do_rcv+0x11dd/0x1d90 net/ipv6/tcp_ipv6.c:1331 sk_backlog_rcv include/net/sock.h:908 [inline] __release_sock+0x2d6/0x680 net/core/sock.c:2271 release_sock+0x97/0x2a0 net/core/sock.c:2786 tcp_close+0x277/0x18f0 net/ipv4/tcp.c:2269 inet_release+0x240/0x2a0 net/ipv4/af_inet.c:427 inet6_release+0xaf/0x100 net/ipv6/af_inet6.c:435 sock_release net/socket.c:595 [inline] sock_close+0xe0/0x300 net/socket.c:1149 __fput+0x49e/0xa10 fs/file_table.c:209 ____fput+0x37/0x40 fs/file_table.c:243 task_work_run+0x243/0x2c0 kernel/task_work.c:113 exit_task_work include/linux/task_work.h:22 [inline] do_exit+0x10e1/0x38d0 kernel/exit.c:867 do_group_exit+0x1a0/0x360 kernel/exit.c:970 SYSC_exit_group+0x21/0x30 kernel/exit.c:981 SyS_exit_group+0x25/0x30 kernel/exit.c:979 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:188 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:314 kmem_cache_alloc+0xaab/0xb90 mm/slub.c:2756 inet_twsk_alloc+0x13b/0xc00 net/ipv4/inet_timewait_sock.c:163 tcp_time_wait+0xd9/0xf50 net/ipv4/tcp_minisocks.c:258 tcp_rcv_state_process+0xebe/0x6490 net/ipv4/tcp_input.c:6003 tcp_v6_do_rcv+0x11dd/0x1d90 net/ipv6/tcp_ipv6.c:1331 sk_backlog_rcv include/net/sock.h:908 [inline] __release_sock+0x2d6/0x680 net/core/sock.c:2271 release_sock+0x97/0x2a0 net/core/sock.c:2786 tcp_close+0x277/0x18f0 net/ipv4/tcp.c:2269 inet_release+0x240/0x2a0 net/ipv4/af_inet.c:427 inet6_release+0xaf/0x100 net/ipv6/af_inet6.c:435 sock_release net/socket.c:595 [inline] sock_close+0xe0/0x300 net/socket.c:1149 __fput+0x49e/0xa10 fs/file_table.c:209 ____fput+0x37/0x40 fs/file_table.c:243 task_work_run+0x243/0x2c0 kernel/task_work.c:113 exit_task_work include/linux/task_work.h:22 [inline] do_exit+0x10e1/0x38d0 kernel/exit.c:867 do_group_exit+0x1a0/0x360 kernel/exit.c:970 SYSC_exit_group+0x21/0x30 kernel/exit.c:981 SyS_exit_group+0x25/0x30 kernel/exit.c:979 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Fixes: da5e36308d9f ("soreuseport: TCP/IPv4 implementation") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/inet_timewait_sock.h | 1 + net/ipv4/inet_timewait_sock.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index c9b3eb70f340..567017b5fc9e 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -55,6 +55,7 @@ struct inet_timewait_sock { #define tw_family __tw_common.skc_family #define tw_state __tw_common.skc_state #define tw_reuse __tw_common.skc_reuse +#define tw_reuseport __tw_common.skc_reuseport #define tw_ipv6only __tw_common.skc_ipv6only #define tw_bound_dev_if __tw_common.skc_bound_dev_if #define tw_node __tw_common.skc_nulls_node diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index ddcd56c08d14..a6b34ac3139e 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -182,6 +182,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, tw->tw_dport = inet->inet_dport; tw->tw_family = sk->sk_family; tw->tw_reuse = sk->sk_reuse; + tw->tw_reuseport = sk->sk_reuseport; tw->tw_hash = sk->sk_hash; tw->tw_ipv6only = 0; tw->tw_transparent = inet->transparent; -- GitLab From 68447d694fd41d8381090ea012185fddc8df25c5 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 15 Apr 2018 11:23:52 +0200 Subject: [PATCH 244/855] perf: Remove superfluous allocation error check commit bfb3d7b8b906b66551424d7636182126e1d134c8 upstream. If the get_callchain_buffers fails to allocate the buffer it will decrease the nr_callchain_events right away. There's no point of checking the allocation error for nr_callchain_events > 1. Removing that check. Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: H. Peter Anvin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: syzkaller-bugs@googlegroups.com Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20180415092352.12403-3-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- kernel/events/callchain.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c index 04988d6466bf..c265f1c3ae50 100644 --- a/kernel/events/callchain.c +++ b/kernel/events/callchain.c @@ -129,14 +129,8 @@ int get_callchain_buffers(int event_max_stack) goto exit; } - if (count > 1) { - /* If the allocation failed, give up */ - if (!callchain_cpus_entries) - err = -ENOMEM; - goto exit; - } - - err = alloc_callchain_buffers(); + if (count == 1) + err = alloc_callchain_buffers(); exit: if (err) atomic_dec(&nr_callchain_events); -- GitLab From 869f538101abb7d394a9bfdc49e0874a7a07b308 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 29 Apr 2018 18:55:20 -0700 Subject: [PATCH 245/855] tcp: fix TCP_REPAIR_QUEUE bound checking commit bf2acc943a45d2b2e8a9f1a5ddff6b6e43cc69d9 upstream. syzbot is able to produce a nasty WARN_ON() in tcp_verify_left_out() with following C-repro : socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3 setsockopt(3, SOL_TCP, TCP_REPAIR, [1], 4) = 0 setsockopt(3, SOL_TCP, TCP_REPAIR_QUEUE, [-1], 4) = 0 bind(3, {sa_family=AF_INET, sin_port=htons(20002), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 sendto(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1242, MSG_FASTOPEN, {sa_family=AF_INET, sin_port=htons(20002), sin_addr=inet_addr("127.0.0.1")}, 16) = 1242 setsockopt(3, SOL_TCP, TCP_REPAIR_WINDOW, "\4\0\0@+\205\0\0\377\377\0\0\377\377\377\177\0\0\0\0", 20) = 0 writev(3, [{"\270", 1}], 1) = 1 setsockopt(3, SOL_TCP, TCP_REPAIR_OPTIONS, "\10\0\0\0\0\0\0\0\0\0\0\0|\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 386) = 0 writev(3, [{"\210v\r[\226\320t\231qwQ\204\264l\254\t\1\20\245\214p\350H\223\254;\\\37\345\307p$"..., 3144}], 1) = 3144 The 3rd system call looks odd : setsockopt(3, SOL_TCP, TCP_REPAIR_QUEUE, [-1], 4) = 0 This patch makes sure bound checking is using an unsigned compare. Fixes: ee9952831cfd ("tcp: Initial repair mode") Signed-off-by: Eric Dumazet Reported-by: syzbot Cc: Pavel Emelyanov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 0fc5dad02fe8..6f501c9deaae 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2523,7 +2523,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, case TCP_REPAIR_QUEUE: if (!tp->repair) err = -EPERM; - else if (val < TCP_QUEUES_NR) + else if ((unsigned int)val < TCP_QUEUES_NR) tp->repair_queue = val; else err = -EINVAL; -- GitLab From 57d641003679cf452f995b6f034b567d5d4e3be3 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 3 May 2018 18:26:26 +0200 Subject: [PATCH 246/855] bdi: Fix oops in wb_workfn() commit b8b784958eccbf8f51ebeee65282ca3fd59ea391 upstream. Syzbot has reported that it can hit a NULL pointer dereference in wb_workfn() due to wb->bdi->dev being NULL. This indicates that wb_workfn() was called for an already unregistered bdi which should not happen as wb_shutdown() called from bdi_unregister() should make sure all pending writeback works are completed before bdi is unregistered. Except that wb_workfn() itself can requeue the work with: mod_delayed_work(bdi_wq, &wb->dwork, 0); and if this happens while wb_shutdown() is waiting in: flush_delayed_work(&wb->dwork); the dwork can get executed after wb_shutdown() has finished and bdi_unregister() has cleared wb->bdi->dev. Make wb_workfn() use wakeup_wb() for requeueing the work which takes all the necessary precautions against racing with bdi unregistration. CC: Tetsuo Handa CC: Tejun Heo Fixes: 839a8e8660b6777e7fe4e80af1a048aebe2b5977 Reported-by: syzbot Reviewed-by: Dave Chinner Signed-off-by: Jan Kara Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- fs/fs-writeback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 3d8b35f28a9b..f3aea1b8702c 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1942,7 +1942,7 @@ void wb_workfn(struct work_struct *work) } if (!list_empty(&wb->work_list)) - mod_delayed_work(bdi_wq, &wb->dwork, 0); + wb_wakeup(wb); else if (wb_has_dirty_io(wb) && dirty_writeback_interval) wb_wakeup_delayed(wb); -- GitLab From b87943f388ab24f66b4db380d47fe691a67dc44d Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 7 Mar 2018 22:17:20 +1100 Subject: [PATCH 247/855] KVM: PPC: Book3S HV: Fix trap number return from __kvmppc_vcore_entry commit a8b48a4dccea77e29462e59f1dbf0d5aa1ff167c upstream. This fixes a bug where the trap number that is returned by __kvmppc_vcore_entry gets corrupted. The effect of the corruption is that IPIs get ignored on POWER9 systems when the IPI is sent via a doorbell interrupt to a CPU which is executing in a KVM guest. The effect of the IPI being ignored is often that another CPU locks up inside smp_call_function_many() (and if that CPU is holding a spinlock, other CPUs then lock up inside raw_spin_lock()). The trap number is currently held in register r12 for most of the assembly-language part of the guest exit path. In that path, we call kvmppc_subcore_exit_guest(), which is a C function, without restoring r12 afterwards. Depending on the kernel config and the compiler, it may modify r12 or it may not, so some config/compiler combinations see the bug and others don't. To fix this, we arrange for the trap number to be stored on the stack from the 'guest_bypass:' label until the end of the function, then the trap number is loaded and returned in r12 as before. Cc: stable@vger.kernel.org # v4.8+ Fixes: fd7bacbca47a ("KVM: PPC: Book3S HV: Fix TB corruption in guest exit path on HMI interrupt") Signed-off-by: Paul Mackerras Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 55fbc0c78721..79a180cf4c94 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -299,7 +299,6 @@ kvm_novcpu_exit: stw r12, STACK_SLOT_TRAP(r1) bl kvmhv_commence_exit nop - lwz r12, STACK_SLOT_TRAP(r1) b kvmhv_switch_to_host /* @@ -1023,6 +1022,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) secondary_too_late: li r12, 0 + stw r12, STACK_SLOT_TRAP(r1) cmpdi r4, 0 beq 11f stw r12, VCPU_TRAP(r4) @@ -1266,12 +1266,12 @@ mc_cont: bl kvmhv_accumulate_time #endif + stw r12, STACK_SLOT_TRAP(r1) mr r3, r12 /* Increment exit count, poke other threads to exit */ bl kvmhv_commence_exit nop ld r9, HSTATE_KVM_VCPU(r13) - lwz r12, VCPU_TRAP(r9) /* Stop others sending VCPU interrupts to this physical CPU */ li r0, -1 @@ -1549,6 +1549,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) * POWER7/POWER8 guest -> host partition switch code. * We don't have to lock against tlbies but we do * have to coordinate the hardware threads. + * Here STACK_SLOT_TRAP(r1) contains the trap number. */ kvmhv_switch_to_host: /* Secondary threads wait for primary to do partition switch */ @@ -1599,11 +1600,11 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) /* If HMI, call kvmppc_realmode_hmi_handler() */ + lwz r12, STACK_SLOT_TRAP(r1) cmpwi r12, BOOK3S_INTERRUPT_HMI bne 27f bl kvmppc_realmode_hmi_handler nop - li r12, BOOK3S_INTERRUPT_HMI /* * At this point kvmppc_realmode_hmi_handler would have resync-ed * the TB. Hence it is not required to subtract guest timebase @@ -1678,6 +1679,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) li r0, KVM_GUEST_MODE_NONE stb r0, HSTATE_IN_GUEST(r13) + lwz r12, STACK_SLOT_TRAP(r1) /* return trap # in r12 */ ld r0, SFS+PPC_LR_STKOFF(r1) addi r1, r1, SFS mtlr r0 -- GitLab From b8bf4b886b82585202ab4ee169718656661cb89e Mon Sep 17 00:00:00 2001 From: Wei Fang Date: Sun, 22 Jan 2017 12:21:02 +0800 Subject: [PATCH 248/855] f2fs: fix a dead loop in f2fs_fiemap() commit b86e33075ed1909d8002745b56ecf73b833db143 upstream. A dead loop can be triggered in f2fs_fiemap() using the test case as below: ... fd = open(); fallocate(fd, 0, 0, 4294967296); ioctl(fd, FS_IOC_FIEMAP, fiemap_buf); ... It's caused by an overflow in __get_data_block(): ... bh->b_size = map.m_len << inode->i_blkbits; ... map.m_len is an unsigned int, and bh->b_size is a size_t which is 64 bits on 64 bits archtecture, type conversion from an unsigned int to a size_t will result in an overflow. In the above-mentioned case, bh->b_size will be zero, and f2fs_fiemap() will call get_data_block() at block 0 again an again. Fix this by adding a force conversion before left shift. Signed-off-by: Wei Fang Acked-by: Chao Yu Signed-off-by: Jaegeuk Kim Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 99432b59c5cb..ae354ac67da1 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -844,7 +844,7 @@ static int __get_data_block(struct inode *inode, sector_t iblock, if (!ret) { map_bh(bh, inode->i_sb, map.m_pblk); bh->b_state = (bh->b_state & ~F2FS_MAP_FLAGS) | map.m_flags; - bh->b_size = map.m_len << inode->i_blkbits; + bh->b_size = (u64)map.m_len << inode->i_blkbits; } return ret; } -- GitLab From b8c320884eff003581ee61c5970a2e83f513eff1 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Mon, 26 Mar 2018 15:12:49 +0100 Subject: [PATCH 249/855] arm64: Add work around for Arm Cortex-A55 Erratum 1024718 commit ece1397cbc89c51914fae1aec729539cfd8bd62b upstream. Some variants of the Arm Cortex-55 cores (r0p0, r0p1, r1p0) suffer from an erratum 1024718, which causes incorrect updates when DBM/AP bits in a page table entry is modified without a break-before-make sequence. The work around is to skip enabling the hardware DBM feature on the affected cores. The hardware Access Flag management features is not affected. There are some other cores suffering from this errata, which could be added to the midr_list to trigger the work around. Cc: Catalin Marinas Cc: ckadabi@codeaurora.org Reviewed-by: Dave Martin Signed-off-by: Suzuki K Poulose Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- Documentation/arm64/silicon-errata.txt | 1 + arch/arm64/Kconfig | 14 +++++++++ arch/arm64/include/asm/assembler.h | 40 ++++++++++++++++++++++++++ arch/arm64/include/asm/cputype.h | 5 ++++ arch/arm64/mm/proc.S | 5 ++++ 5 files changed, 65 insertions(+) diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt index d11af52427b4..ac9489fad31b 100644 --- a/Documentation/arm64/silicon-errata.txt +++ b/Documentation/arm64/silicon-errata.txt @@ -54,6 +54,7 @@ stable kernels. | ARM | Cortex-A57 | #852523 | N/A | | ARM | Cortex-A57 | #834220 | ARM64_ERRATUM_834220 | | ARM | Cortex-A72 | #853709 | N/A | +| ARM | Cortex-A55 | #1024718 | ARM64_ERRATUM_1024718 | | ARM | MMU-500 | #841119,#826419 | N/A | | | | | | | Cavium | ThunderX ITS | #22375, #24313 | CAVIUM_ERRATUM_22375 | diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 90e58bbbd858..d0df3611d1e2 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -427,6 +427,20 @@ config ARM64_ERRATUM_843419 If unsure, say Y. +config ARM64_ERRATUM_1024718 + bool "Cortex-A55: 1024718: Update of DBM/AP bits without break before make might result in incorrect update" + default y + help + This option adds work around for Arm Cortex-A55 Erratum 1024718. + + Affected Cortex-A55 cores (r0p0, r0p1, r1p0) could cause incorrect + update of the hardware dirty bit when the DBM/AP bits are updated + without a break-before-make. The work around is to disable the usage + of hardware DBM locally on the affected cores. CPUs not affected by + erratum will continue to use the feature. + + If unsure, say Y. + config CAVIUM_ERRATUM_22375 bool "Cavium erratum 22375, 24313" default y diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index e60375ce0dd2..bfcfec3590f6 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -435,4 +436,43 @@ alternative_endif and \phys, \pte, #(((1 << (48 - PAGE_SHIFT)) - 1) << PAGE_SHIFT) .endm +/* + * Check the MIDR_EL1 of the current CPU for a given model and a range of + * variant/revision. See asm/cputype.h for the macros used below. + * + * model: MIDR_CPU_MODEL of CPU + * rv_min: Minimum of MIDR_CPU_VAR_REV() + * rv_max: Maximum of MIDR_CPU_VAR_REV() + * res: Result register. + * tmp1, tmp2, tmp3: Temporary registers + * + * Corrupts: res, tmp1, tmp2, tmp3 + * Returns: 0, if the CPU id doesn't match. Non-zero otherwise + */ + .macro cpu_midr_match model, rv_min, rv_max, res, tmp1, tmp2, tmp3 + mrs \res, midr_el1 + mov_q \tmp1, (MIDR_REVISION_MASK | MIDR_VARIANT_MASK) + mov_q \tmp2, MIDR_CPU_MODEL_MASK + and \tmp3, \res, \tmp2 // Extract model + and \tmp1, \res, \tmp1 // rev & variant + mov_q \tmp2, \model + cmp \tmp3, \tmp2 + cset \res, eq + cbz \res, .Ldone\@ // Model matches ? + + .if (\rv_min != 0) // Skip min check if rv_min == 0 + mov_q \tmp3, \rv_min + cmp \tmp1, \tmp3 + cset \res, ge + .endif // \rv_min != 0 + /* Skip rv_max check if rv_min == rv_max && rv_min != 0 */ + .if ((\rv_min != \rv_max) || \rv_min == 0) + mov_q \tmp2, \rv_max + cmp \tmp1, \tmp2 + cset \tmp2, le + and \res, \res, \tmp2 + .endif +.Ldone\@: + .endm + #endif /* __ASM_ASSEMBLER_H */ diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 9ee3038a6b98..39d1db68748d 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -56,6 +56,9 @@ (0xf << MIDR_ARCHITECTURE_SHIFT) | \ ((partnum) << MIDR_PARTNUM_SHIFT)) +#define MIDR_CPU_VAR_REV(var, rev) \ + (((var) << MIDR_VARIANT_SHIFT) | (rev)) + #define MIDR_CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \ MIDR_ARCHITECTURE_MASK) @@ -74,6 +77,7 @@ #define ARM_CPU_PART_AEM_V8 0xD0F #define ARM_CPU_PART_FOUNDATION 0xD00 +#define ARM_CPU_PART_CORTEX_A55 0xD05 #define ARM_CPU_PART_CORTEX_A57 0xD07 #define ARM_CPU_PART_CORTEX_A72 0xD08 #define ARM_CPU_PART_CORTEX_A53 0xD03 @@ -89,6 +93,7 @@ #define BRCM_CPU_PART_VULCAN 0x516 #define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) +#define MIDR_CORTEX_A55 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A55) #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) #define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) #define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73) diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 619da1cbd32b..66cce2138f95 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -425,6 +425,11 @@ ENTRY(__cpu_setup) cbz x9, 2f cmp x9, #2 b.lt 1f +#ifdef CONFIG_ARM64_ERRATUM_1024718 + /* Disable hardware DBM on Cortex-A55 r0p0, r0p1 & r1p0 */ + cpu_midr_match MIDR_CORTEX_A55, MIDR_CPU_VAR_REV(0, 0), MIDR_CPU_VAR_REV(1, 0), x1, x2, x3, x4 + cbnz x1, 1f +#endif orr x10, x10, #TCR_HD // hardware Dirty flag update 1: orr x10, x10, #TCR_HA // hardware Access flag update 2: -- GitLab From 31d04ca1eb232077e7d8032bc845bba6e6465d22 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Thu, 29 Mar 2018 13:29:12 -0500 Subject: [PATCH 250/855] gpioib: do not free unrequested descriptors commit ab3dbcf78f60f46d6a0ad63b1f4b690b7a427140 upstream. If the main loop in linehandle_create() encounters an error, it unwinds completely by freeing all previously requested GPIO descriptors. However, if the error occurs in the beginning of the loop before that GPIO is requested, then the exit code attempts to free a null descriptor. If extrachecks is enabled, gpiod_free() triggers a WARN_ON. Instead, keep a separate count of legitimate GPIOs so that only those are freed. Cc: stable@vger.kernel.org Fixes: d7c51b47ac11 ("gpio: userspace ABI for reading/writing GPIO lines") Reviewed-by: Bjorn Andersson Signed-off-by: Timur Tabi Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpiolib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 4f54ff45e09e..68102e262922 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -425,7 +425,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) struct gpiohandle_request handlereq; struct linehandle_state *lh; struct file *file; - int fd, i, ret; + int fd, i, count = 0, ret; if (copy_from_user(&handlereq, ip, sizeof(handlereq))) return -EFAULT; @@ -471,6 +471,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) if (ret) goto out_free_descs; lh->descs[i] = desc; + count = i; if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW) set_bit(FLAG_ACTIVE_LOW, &desc->flags); @@ -537,7 +538,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) out_put_unused_fd: put_unused_fd(fd); out_free_descs: - for (; i >= 0; i--) + for (i = 0; i < count; i++) gpiod_free(lh->descs[i]); kfree(lh->label); out_free_lh: -- GitLab From 2b0e672598f9ae572b69898cb235fbeffc3e2f8e Mon Sep 17 00:00:00 2001 From: Govert Overgaauw Date: Fri, 6 Apr 2018 14:41:35 +0200 Subject: [PATCH 251/855] gpio: fix aspeed_gpio unmask irq commit f241632fd087d3d9fbd5450f4d8c8604badd8348 upstream. The unmask function disables all interrupts in a bank when unmasking an interrupt. Only disable the given interrupt. Cc: stable@vger.kernel.org Signed-off-by: Govert Overgaauw Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-aspeed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 03a5925a423c..a9daf7121e6e 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -256,7 +256,7 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) if (set) reg |= bit; else - reg &= bit; + reg &= ~bit; iowrite32(reg, addr); spin_unlock_irqrestore(&gpio->lock, flags); -- GitLab From 63e2ae9d75d4c348f47600dcef0f3d90eef7f34e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 16 Apr 2018 13:17:53 +0200 Subject: [PATCH 252/855] gpio: fix error path in lineevent_create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f001cc351ad3309ec8736c374e90e5a4bc472d41 upstream. If gpiod_request() fails the cleanup must not call gpiod_free(). Cc: stable@vger.kernel.org Fixes: 61f922db7221 ("gpio: userspace ABI for reading GPIO line events") Signed-off-by: Uwe Kleine-König Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 68102e262922..56b24198741c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -795,7 +795,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) desc = &gdev->descs[offset]; ret = gpiod_request(desc, le->label); if (ret) - goto out_free_desc; + goto out_free_label; le->desc = desc; le->eflags = eflags; -- GitLab From dd4e7140c4dec8ce0bacb0d0ff152653e0b85660 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 26 Apr 2018 09:31:52 +0200 Subject: [PATCH 253/855] rfkill: gpio: fix memory leak in probe error path commit 4bf01ca21e2e0e4561d1a03c48c3d740418702db upstream. Make sure to free the rfkill device in case registration fails during probe. Fixes: 5e7ca3937fbe ("net: rfkill: gpio: convert to resource managed allocation") Cc: stable # 3.13 Cc: Heikki Krogerus Signed-off-by: Johan Hovold Reviewed-by: Heikki Krogerus Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/rfkill/rfkill-gpio.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c index 76c01cbd56e3..d6d8b34c5f22 100644 --- a/net/rfkill/rfkill-gpio.c +++ b/net/rfkill/rfkill-gpio.c @@ -138,13 +138,18 @@ static int rfkill_gpio_probe(struct platform_device *pdev) ret = rfkill_register(rfkill->rfkill_dev); if (ret < 0) - return ret; + goto err_destroy; platform_set_drvdata(pdev, rfkill); dev_info(&pdev->dev, "%s device registered.\n", rfkill->name); return 0; + +err_destroy: + rfkill_destroy(rfkill->rfkill_dev); + + return ret; } static int rfkill_gpio_remove(struct platform_device *pdev) -- GitLab From b2692091a9f418ed918ed00e97f31eeb11860f27 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 26 Apr 2018 22:32:21 +0200 Subject: [PATCH 254/855] libata: Apply NOLPM quirk for SanDisk SD7UB3Q*G1001 SSDs commit 184add2ca23ce5edcac0ab9c3b9be13f91e7b567 upstream. Richard Jones has reported that using med_power_with_dipm on a T450s with a Sandisk SD7UB3Q256G1001 SSD (firmware version X2180501) is causing the machine to hang. Switching the LPM to max_performance fixes this, so it seems that this Sandisk SSD does not handle LPM well. Note in the past there have been bug-reports about the following Sandisk models not working with min_power, so we may need to extend the quirk list in the future: name - firmware Sandisk SD6SB2M512G1022I - X210400 Sandisk SD6PP4M-256G-1006 - A200906 Cc: stable@vger.kernel.org Cc: Richard W.M. Jones Reported-and-tested-by: Richard W.M. Jones Signed-off-by: Hans de Goede Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index e08c09fa5da0..4fe3ec122bf0 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4422,6 +4422,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ATA_HORKAGE_ZERO_AFTER_TRIM | ATA_HORKAGE_NOLPM, }, + /* Sandisk devices which are known to not handle LPM well */ + { "SanDisk SD7UB3Q*G1001", NULL, ATA_HORKAGE_NOLPM, }, + /* devices that don't properly handle queued TRIM commands */ { "Micron_M500_*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, -- GitLab From f94eef3a4c9c4c17e910c1f35f79d4bcb580b73b Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 9 May 2018 11:59:32 -0400 Subject: [PATCH 255/855] tracing: Fix regex_match_front() to not over compare the test string commit dc432c3d7f9bceb3de6f5b44fb9c657c9810ed6d upstream. The regex match function regex_match_front() in the tracing filter logic, was fixed to test just the pattern length from testing the entire test string. That is, it went from strncmp(str, r->pattern, len) to strcmp(str, r->pattern, r->len). The issue is that str is not guaranteed to be nul terminated, and if r->len is greater than the length of str, it can access more memory than is allocated. The solution is to add a simple test if (len < r->len) return 0. Cc: stable@vger.kernel.org Fixes: 285caad415f45 ("tracing/filters: Fix MATCH_FRONT_ONLY filter matching") Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_events_filter.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 0193f58c45f0..e35a411bea4b 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -322,6 +322,9 @@ static int regex_match_full(char *str, struct regex *r, int len) static int regex_match_front(char *str, struct regex *r, int len) { + if (len < r->len) + return 0; + if (strncmp(str, r->pattern, r->len) == 0) return 1; return 0; -- GitLab From 0e79ef256d4634699b2ed3b872176ceffd904be5 Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Fri, 20 Apr 2018 14:38:46 +0200 Subject: [PATCH 256/855] can: kvaser_usb: Increase correct stats counter in kvaser_usb_rx_can_msg() commit 6ee00865ffe4e8c8ba4a68d26db53c7ec09bbb89 upstream. Increase rx_dropped, if alloc_can_skb() fails, not tx_dropped. Signed-off-by: Jimmy Assarsson Cc: linux-stable Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/usb/kvaser_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index c9d61a6dfb7a..3a75352f632b 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -1179,7 +1179,7 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, skb = alloc_can_skb(priv->netdev, &cf); if (!skb) { - stats->tx_dropped++; + stats->rx_dropped++; return; } -- GitLab From 87994a2165ec29dbef64029b26315b1a1debf7b9 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 7 May 2018 14:13:03 +0200 Subject: [PATCH 257/855] drm/vc4: Fix scaling of uni-planar formats commit 9a0e9802217291e54c4dd1fc5462f189a4be14ec upstream. When using uni-planar formats (like RGB), the scaling parameters are stored in plane 0, not plane 1. Fixes: fc04023fafec ("drm/vc4: Add support for YUV planes.") Cc: stable@vger.kernel.org Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20180507121303.5610-1-boris.brezillon@bootlin.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vc4/vc4_plane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 881bf489478b..75056553b06c 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -533,7 +533,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, * the scl fields here. */ if (num_planes == 1) { - scl0 = vc4_get_scl_field(state, 1); + scl0 = vc4_get_scl_field(state, 0); scl1 = scl0; } else { scl0 = vc4_get_scl_field(state, 1); -- GitLab From 28d832be7e9fbf6f18e2d931db116980eee5eeff Mon Sep 17 00:00:00 2001 From: Florent Flament Date: Thu, 19 Apr 2018 19:07:00 +0300 Subject: [PATCH 258/855] drm/i915: Fix drm:intel_enable_lvds ERROR message in kernel log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e8f48f96db7e482995743f461b3e8a5c1a102533 upstream. Fix `[drm:intel_enable_lvds] *ERROR* timed out waiting for panel to power on` in kernel log at boot time. Toshiba Satellite Z930 laptops needs between 1 and 2 seconds to power on its screen during Intel i915 DRM initialization. This currently results in a `[drm:intel_enable_lvds] *ERROR* timed out waiting for panel to power on` message appearing in the kernel log during boot time and when stopping the machine. This change increases the timeout of the `intel_enable_lvds` function from 1 to 5 seconds, letting enough time for the Satellite 930 LCD screen to power on, and suppressing the error message from the kernel log. This patch has been successfully tested on Linux 4.14 running on a Toshiba Satellite Z930. [vsyrjala: bump the timeout from 2 to 5 seconds to match the DP code and properly cover the max hw timeout of ~4 seconds, and drop the comment about the specific machine since this is not a particulary surprising issue, nor specific to that one machine] Signed-off-by: Florent Flament Cc: stable@vger.kernel.org Cc: Pavel Petrovic Cc: Sérgio M. Basto Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103414 References: https://bugzilla.kernel.org/show_bug.cgi?id=57591 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180419160700.19828-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula (cherry picked from commit 280b54ade5914d3b4abe4f0ebe083ddbd4603246) Signed-off-by: Joonas Lahtinen Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_lvds.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index e1d47d51ea47..3517c0ed984a 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -321,7 +321,8 @@ static void intel_enable_lvds(struct intel_encoder *encoder, I915_WRITE(PP_CONTROL(0), I915_READ(PP_CONTROL(0)) | PANEL_POWER_ON); POSTING_READ(lvds_encoder->reg); - if (intel_wait_for_register(dev_priv, PP_STATUS(0), PP_ON, PP_ON, 1000)) + + if (intel_wait_for_register(dev_priv, PP_STATUS(0), PP_ON, PP_ON, 5000)) DRM_ERROR("timed out waiting for panel to power on\n"); intel_panel_enable_backlight(intel_connector); -- GitLab From 81b8eb6b9a3531b769357f8ae468c7eacffa7cd6 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 3 May 2018 13:45:58 -0500 Subject: [PATCH 259/855] net: atm: Fix potential Spectre v1 commit acf784bd0ce257fe43da7ca266f7a10b837479d2 upstream. ioc_data.dev_num can be controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability. This issue was detected with the help of Smatch: net/atm/lec.c:702 lec_vcc_attach() warn: potential spectre issue 'dev_lec' Fix this by sanitizing ioc_data.dev_num before using it to index dev_lec. Also, notice that there is another instance in which array dev_lec is being indexed using ioc_data.dev_num at line 705: lec_vcc_added(netdev_priv(dev_lec[ioc_data.dev_num]), Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1]. [1] https://marc.info/?l=linux-kernel&m=152449131114778&w=2 Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/atm/lec.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/atm/lec.c b/net/atm/lec.c index 5d2693826afb..1e84c5226c84 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -41,6 +41,9 @@ static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 }; #include #include +/* Hardening for Spectre-v1 */ +#include + #include "lec.h" #include "lec_arpc.h" #include "resources.h" @@ -697,8 +700,10 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg) bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc)); if (bytes_left != 0) pr_info("copy from user failed for %d bytes\n", bytes_left); - if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF || - !dev_lec[ioc_data.dev_num]) + if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF) + return -EINVAL; + ioc_data.dev_num = array_index_nospec(ioc_data.dev_num, MAX_LEC_ITF); + if (!dev_lec[ioc_data.dev_num]) return -EINVAL; vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL); if (!vpriv) -- GitLab From ad43aede80e2faf876d6f0c4d27e462f8e0380dd Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 3 May 2018 13:17:12 -0500 Subject: [PATCH 260/855] atm: zatm: Fix potential Spectre v1 commit 2be147f7459db5bbf292e0a6f135037b55e20b39 upstream. pool can be indirectly controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability. This issue was detected with the help of Smatch: drivers/atm/zatm.c:1462 zatm_ioctl() warn: potential spectre issue 'zatm_dev->pool_info' (local cap) Fix this by sanitizing pool before using it to index zatm_dev->pool_info Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1]. [1] https://marc.info/?l=linux-kernel&m=152449131114778&w=2 Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/atm/zatm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index d3dc95484161..81bfeec67b77 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -1458,6 +1459,8 @@ static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) return -EFAULT; if (pool < 0 || pool > ZATM_LAST_POOL) return -EINVAL; + pool = array_index_nospec(pool, + ZATM_LAST_POOL + 1); spin_lock_irqsave(&zatm_dev->lock, flags); info = zatm_dev->pool_info[pool]; if (cmd == ZATM_GETPOOLZ) { -- GitLab From c7a2c159d6beff177aa9df5037b30a5a9ec08d1b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 26 Apr 2018 14:18:19 +0200 Subject: [PATCH 261/855] Revert "Bluetooth: btusb: Fix quirk for Atheros 1525/QCA6174" commit 544a591668813583021474fa5c7ff4942244d654 upstream. Commit f44cb4b19ed4 ("Bluetooth: btusb: Fix quirk for Atheros 1525/QCA6174") is causing bluetooth to no longer work for several people, see: https://bugzilla.redhat.com/show_bug.cgi?id=1568911 So lets revert it for now and try to find another solution for devices which need the modified quirk. Cc: stable@vger.kernel.org Cc: Takashi Iwai Signed-off-by: Hans de Goede Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index f8ba5c714df5..3257647d4f74 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -217,6 +217,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 }, @@ -249,7 +250,6 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, /* QCA ROME chipset */ - { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME }, -- GitLab From 3cc96a4acf139c30ff5b4d0312fddaab082db699 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 16 Apr 2018 12:11:52 +0200 Subject: [PATCH 262/855] thermal: exynos: Reading temperature makes sense only when TMU is turned on commit 88fc6f73fddf64eb507b04f7b2bd01d7291db514 upstream. When thermal sensor is not yet enabled, reading temperature might return random value. This might even result in stopping system booting when such temperature is higher than the critical value. Fix this by checking if TMU has been actually enabled before reading the temperature. This change fixes booting of Exynos4210-based board with TMU enabled (for example Samsung Trats board), which was broken since v4.4 kernel release. Signed-off-by: Marek Szyprowski Fixes: 9e4249b40340 ("thermal: exynos: Fix first temperature read after registering sensor") CC: stable@vger.kernel.org # v4.6+ Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Eduardo Valentin Signed-off-by: Greg Kroah-Hartman --- drivers/thermal/samsung/exynos_tmu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index ad1186dd6132..0689da4c869e 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -185,6 +185,7 @@ * @regulator: pointer to the TMU regulator structure. * @reg_conf: pointer to structure to register with core thermal. * @ntrip: number of supported trip points. + * @enabled: current status of TMU device * @tmu_initialize: SoC specific TMU initialization method * @tmu_control: SoC specific TMU control method * @tmu_read: SoC specific TMU temperature read method @@ -205,6 +206,7 @@ struct exynos_tmu_data { struct regulator *regulator; struct thermal_zone_device *tzd; unsigned int ntrip; + bool enabled; int (*tmu_initialize)(struct platform_device *pdev); void (*tmu_control)(struct platform_device *pdev, bool on); @@ -398,6 +400,7 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on) mutex_lock(&data->lock); clk_enable(data->clk); data->tmu_control(pdev, on); + data->enabled = on; clk_disable(data->clk); mutex_unlock(&data->lock); } @@ -890,7 +893,7 @@ static int exynos_get_temp(void *p, int *temp) { struct exynos_tmu_data *data = p; - if (!data || !data->tmu_read) + if (!data || !data->tmu_read || !data->enabled) return -EINVAL; mutex_lock(&data->lock); -- GitLab From 5d1639dae65f6c8b1a71a84e11d29696b7915d34 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 16 Apr 2018 12:11:53 +0200 Subject: [PATCH 263/855] thermal: exynos: Propagate error value from tmu_read() commit c8da6cdef57b459ac0fd5d9d348f8460a575ae90 upstream. tmu_read() in case of Exynos4210 might return error for out of bound values. Current code ignores such value, what leads to reporting critical temperature value. Add proper error code propagation to exynos_get_temp() function. Signed-off-by: Marek Szyprowski CC: stable@vger.kernel.org # v4.6+ Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Eduardo Valentin Signed-off-by: Greg Kroah-Hartman --- drivers/thermal/samsung/exynos_tmu.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 0689da4c869e..a45810b43f70 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -892,6 +892,7 @@ static void exynos7_tmu_control(struct platform_device *pdev, bool on) static int exynos_get_temp(void *p, int *temp) { struct exynos_tmu_data *data = p; + int value, ret = 0; if (!data || !data->tmu_read || !data->enabled) return -EINVAL; @@ -899,12 +900,16 @@ static int exynos_get_temp(void *p, int *temp) mutex_lock(&data->lock); clk_enable(data->clk); - *temp = code_to_temp(data, data->tmu_read(data)) * MCELSIUS; + value = data->tmu_read(data); + if (value < 0) + ret = value; + else + *temp = code_to_temp(data, value) * MCELSIUS; clk_disable(data->clk); mutex_unlock(&data->lock); - return 0; + return ret; } #ifdef CONFIG_THERMAL_EMULATION -- GitLab From fba70eb3ecbcdc0d177ae904a21beeb7b0595612 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 10 Apr 2018 21:20:08 +0900 Subject: [PATCH 264/855] tracing/uprobe_event: Fix strncpy corner case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 50268a3d266ecfdd6c5873d62b2758d9732fc598 upstream. Fix string fetch function to terminate with NUL. It is OK to drop the rest of string. Signed-off-by: Masami Hiramatsu Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Song Liu Cc: Thomas Gleixner Cc: security@kernel.org Cc: 范龙飞 Fixes: 5baaa59ef09e ("tracing/probes: Implement 'memory' fetch method for uprobes") Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_uprobe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 0913693caf6e..788262984818 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -149,6 +149,8 @@ static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, return; ret = strncpy_from_user(dst, src, maxlen); + if (ret == maxlen) + dst[--ret] = '\0'; if (ret < 0) { /* Failed to fetch string */ ((u8 *)get_rloc_data(dest))[0] = '\0'; -- GitLab From 662218f1216ddb3755e79120767462eeaab5e12a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 20 Apr 2018 14:06:29 +0200 Subject: [PATCH 265/855] perf/x86: Fix possible Spectre-v1 indexing for hw_perf_event cache_* commit ef9ee4ad38445a30909c48998624861716f2a994 upstream. > arch/x86/events/core.c:319 set_ext_hw_attr() warn: potential spectre issue 'hw_cache_event_ids[cache_type]' (local cap) > arch/x86/events/core.c:319 set_ext_hw_attr() warn: potential spectre issue 'hw_cache_event_ids' (local cap) > arch/x86/events/core.c:328 set_ext_hw_attr() warn: potential spectre issue 'hw_cache_extra_regs[cache_type]' (local cap) > arch/x86/events/core.c:328 set_ext_hw_attr() warn: potential spectre issue 'hw_cache_extra_regs' (local cap) Userspace controls @config which contains 3 (byte) fields used for a 3 dimensional array deref. Reported-by: Dan Carpenter Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index f73796db8758..61d9e8a72637 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -303,17 +303,20 @@ set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event *event) config = attr->config; - cache_type = (config >> 0) & 0xff; + cache_type = (config >> 0) & 0xff; if (cache_type >= PERF_COUNT_HW_CACHE_MAX) return -EINVAL; + cache_type = array_index_nospec(cache_type, PERF_COUNT_HW_CACHE_MAX); cache_op = (config >> 8) & 0xff; if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX) return -EINVAL; + cache_op = array_index_nospec(cache_op, PERF_COUNT_HW_CACHE_OP_MAX); cache_result = (config >> 16) & 0xff; if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) return -EINVAL; + cache_result = array_index_nospec(cache_result, PERF_COUNT_HW_CACHE_RESULT_MAX); val = hw_cache_event_ids[cache_type][cache_op][cache_result]; -- GitLab From 688d5d9189ce0132564be4f4642ae5f4087a3c7c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 20 Apr 2018 14:25:48 +0200 Subject: [PATCH 266/855] perf/x86/cstate: Fix possible Spectre-v1 indexing for pkg_msr commit a5f81290ce475489fa2551c01a07470c1a4c932e upstream. > arch/x86/events/intel/cstate.c:307 cstate_pmu_event_init() warn: potential spectre issue 'pkg_msr' (local cap) Userspace controls @attr, sanitize cfg (attr->config) before using it to index an array. Reported-by: Dan Carpenter Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/intel/cstate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c index 1076c9a77292..47d526c700a1 100644 --- a/arch/x86/events/intel/cstate.c +++ b/arch/x86/events/intel/cstate.c @@ -90,6 +90,7 @@ #include #include #include +#include #include #include #include "../perf_event.h" @@ -300,6 +301,7 @@ static int cstate_pmu_event_init(struct perf_event *event) } else if (event->pmu == &cstate_pkg_pmu) { if (cfg >= PERF_CSTATE_PKG_EVENT_MAX) return -EINVAL; + cfg = array_index_nospec((unsigned long)cfg, PERF_CSTATE_PKG_EVENT_MAX); if (!pkg_msr[cfg].attr) return -EINVAL; event->hw.event_base = pkg_msr[cfg].msr; -- GitLab From 5edbd2d8db426d49bc570a3a019720b5e810d951 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 20 Apr 2018 14:23:36 +0200 Subject: [PATCH 267/855] perf/x86/msr: Fix possible Spectre-v1 indexing in the MSR driver commit 06ce6e9b6d6c09d4129c6e24a1314a395d816c10 upstream. > arch/x86/events/msr.c:178 msr_event_init() warn: potential spectre issue 'msr' (local cap) Userspace controls @attr, sanitize cfg (attr->config) before using it to index an array. Reported-by: Dan Carpenter Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/msr.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/x86/events/msr.c b/arch/x86/events/msr.c index 4bb3ec69e8ea..be0b1968d60a 100644 --- a/arch/x86/events/msr.c +++ b/arch/x86/events/msr.c @@ -1,4 +1,5 @@ #include +#include #include enum perf_msr_id { @@ -136,9 +137,6 @@ static int msr_event_init(struct perf_event *event) if (event->attr.type != event->pmu->type) return -ENOENT; - if (cfg >= PERF_MSR_EVENT_MAX) - return -EINVAL; - /* unsupported modes and filters */ if (event->attr.exclude_user || event->attr.exclude_kernel || @@ -149,6 +147,11 @@ static int msr_event_init(struct perf_event *event) event->attr.sample_period) /* no sampling */ return -EINVAL; + if (cfg >= PERF_MSR_EVENT_MAX) + return -EINVAL; + + cfg = array_index_nospec((unsigned long)cfg, PERF_MSR_EVENT_MAX); + if (!msr[cfg].attr) return -EINVAL; -- GitLab From c64ca00ec73546a6079621d90b9cce7ed25b0885 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 20 Apr 2018 14:03:18 +0200 Subject: [PATCH 268/855] perf/core: Fix possible Spectre-v1 indexing for ->aux_pages[] commit 4411ec1d1993e8dbff2898390e3fed280d88e446 upstream. > kernel/events/ring_buffer.c:871 perf_mmap_to_page() warn: potential spectre issue 'rb->aux_pages' Userspace controls @pgoff through the fault address. Sanitize the array index before doing the array dereference. Reported-by: Dan Carpenter Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/events/ring_buffer.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c index 257fa460b846..017f7933a37d 100644 --- a/kernel/events/ring_buffer.c +++ b/kernel/events/ring_buffer.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "internal.h" @@ -844,8 +845,10 @@ perf_mmap_to_page(struct ring_buffer *rb, unsigned long pgoff) return NULL; /* AUX space */ - if (pgoff >= rb->aux_pgoff) - return virt_to_page(rb->aux_pages[pgoff - rb->aux_pgoff]); + if (pgoff >= rb->aux_pgoff) { + int aux_pgoff = array_index_nospec(pgoff - rb->aux_pgoff, rb->aux_nr_pages); + return virt_to_page(rb->aux_pages[aux_pgoff]); + } } return __perf_mmap_to_page(rb, pgoff); -- GitLab From 70e65f281a5671c1a6de239bdd5a331046b077f6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 20 Apr 2018 14:08:58 +0200 Subject: [PATCH 269/855] perf/x86: Fix possible Spectre-v1 indexing for x86_pmu::event_map() commit 46b1b577229a091b137831becaa0fae8690ee15a upstream. > arch/x86/events/intel/cstate.c:307 cstate_pmu_event_init() warn: potential spectre issue 'pkg_msr' (local cap) > arch/x86/events/intel/core.c:337 intel_pmu_event_map() warn: potential spectre issue 'intel_perfmon_event_map' > arch/x86/events/intel/knc.c:122 knc_pmu_event_map() warn: potential spectre issue 'knc_perfmon_event_map' > arch/x86/events/intel/p4.c:722 p4_pmu_event_map() warn: potential spectre issue 'p4_general_events' > arch/x86/events/intel/p6.c:116 p6_pmu_event_map() warn: potential spectre issue 'p6_perfmon_event_map' > arch/x86/events/amd/core.c:132 amd_pmu_event_map() warn: potential spectre issue 'amd_perfmon_event_map' Userspace controls @attr, sanitize @attr->config before passing it on to x86_pmu::event_map(). Reported-by: Dan Carpenter Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 61d9e8a72637..02e547f9ca3f 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -423,6 +424,8 @@ int x86_setup_perfctr(struct perf_event *event) if (attr->config >= x86_pmu.max_events) return -EINVAL; + attr->config = array_index_nospec((unsigned long)attr->config, x86_pmu.max_events); + /* * The generic map: */ -- GitLab From 872e1aead3efecaa6e4113c1c218059e9412beb7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 16 May 2018 10:08:45 +0200 Subject: [PATCH 270/855] Linux 4.9.100 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d51e99f4a987..52a41396680c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 99 +SUBLEVEL = 100 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 53ba6ff9f968e0330426a93f1c7b38cff2cf9b04 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Wed, 9 May 2018 18:07:15 -0700 Subject: [PATCH 271/855] msm: camera: Fix the activated state to be flush state If request is found in pending queue, move the activated substate to flush state. Change-Id: Icf96bc8cd7d821c03e7ea83ebac02cc4c8c0c665 Signed-off-by: Vishalsingh Hajeri --- .../msm/camera/cam_isp/cam_isp_context.c | 18 ++++++++++++------ .../msm/camera/cam_req_mgr/cam_req_mgr_core.c | 2 ++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index b618ee526479..d484890958e6 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -1365,10 +1365,12 @@ static int __cam_isp_ctx_flush_req(struct cam_context *ctx, } if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ && - !cancel_req_id_found) - CAM_DBG(CAM_ISP, + !cancel_req_id_found) { + CAM_INFO(CAM_ISP, "Flush request id:%lld is not found in the list", flush_req->req_id); + return -EINVAL; + } return 0; } @@ -1396,13 +1398,17 @@ static int __cam_isp_ctx_flush_req_in_activated( struct cam_isp_context *ctx_isp; ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; - spin_lock_bh(&ctx->lock); - ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_FLUSH; - ctx_isp->frame_skip_count = 2; CAM_DBG(CAM_ISP, "Flush request in state %d", ctx->state); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); - spin_unlock_bh(&ctx->lock); + + /* only if request is found in pending queue, move to flush state*/ + if (!rc) { + spin_lock_bh(&ctx->lock); + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_FLUSH; + ctx_isp->frame_skip_count = 2; + spin_unlock_bh(&ctx->lock); + } return rc; } diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index adfac57d3678..ff18fa741ade 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c @@ -1447,6 +1447,8 @@ int cam_req_mgr_process_flush_req(void *priv, void *data) if (idx < 0) { CAM_ERR(CAM_CRM, "req_id %lld not found in input queue", flush_info->req_id); + mutex_unlock(&link->req.lock); + return -EINVAL; } else { CAM_DBG(CAM_CRM, "req_id %lld found at idx %d", flush_info->req_id, idx); -- GitLab From 039656e9cc621502bf6eedc592e834c29aca4cd5 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 26 Apr 2018 12:18:35 +0200 Subject: [PATCH 272/855] FROMLIST: brcmfmac: reports boottime_ns while informing bss Provides a timestamp in bss information so user space can see when the bss info was updated. Since tsf is not available from the dongle events boottime is reported instead. Reported-by: Dmitry Shmidt Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo (cherry picked from commit 7742fce4c007141617dab9bcb90034b3c0fe2347) Change-Id: I72e275babbca6e19b05ce73b125767a43ec6ff98 --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index f507d821aba8..36fb18c20963 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -2774,7 +2774,6 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, struct brcmf_bss_info_le *bi) { struct wiphy *wiphy = cfg_to_wiphy(cfg); - struct ieee80211_channel *notify_channel; struct cfg80211_bss *bss; struct ieee80211_supported_band *band; struct brcmu_chan ch; @@ -2784,7 +2783,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, u16 notify_interval; u8 *notify_ie; size_t notify_ielen; - s32 notify_signal; + struct cfg80211_inform_bss bss_data = { 0 }; if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) { brcmf_err("Bss info is larger than buffer. Discarding\n"); @@ -2804,27 +2803,28 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, band = wiphy->bands[NL80211_BAND_5GHZ]; freq = ieee80211_channel_to_frequency(channel, band->band); - notify_channel = ieee80211_get_channel(wiphy, freq); + bss_data.chan = ieee80211_get_channel(wiphy, freq); + bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20; + bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime()); notify_capability = le16_to_cpu(bi->capability); notify_interval = le16_to_cpu(bi->beacon_period); notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); notify_ielen = le32_to_cpu(bi->ie_length); - notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; + bss_data.signal = (s16)le16_to_cpu(bi->RSSI) * 100; brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID); brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq); brcmf_dbg(CONN, "Capability: %X\n", notify_capability); brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval); - brcmf_dbg(CONN, "Signal: %d\n", notify_signal); - - bss = cfg80211_inform_bss(wiphy, notify_channel, - CFG80211_BSS_FTYPE_UNKNOWN, - (const u8 *)bi->BSSID, - 0, notify_capability, - notify_interval, notify_ie, - notify_ielen, notify_signal, - GFP_KERNEL); + brcmf_dbg(CONN, "Signal: %d\n", bss_data.signal); + + bss = cfg80211_inform_bss_data(wiphy, &bss_data, + CFG80211_BSS_FTYPE_UNKNOWN, + (const u8 *)bi->BSSID, + 0, notify_capability, + notify_interval, notify_ie, + notify_ielen, GFP_KERNEL); if (!bss) return -ENOMEM; -- GitLab From 73fdfa38c59d197fe6ce1d3a356685c96e8c829b Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Tue, 15 May 2018 11:14:44 +0200 Subject: [PATCH 273/855] FROMLIST: brcmfmac: fix initialization of struct cfg80211_inform_bss variable This patch fixes a sparse warning "Using plain integer as NULL pointer" about cfg80211_inform_bss structure initialization. Reported-by: kbuild test robot Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo (cherry picked from commit 763ece85f45a6b93268e25a0abf02922f911dab4) Change-Id: If5a64df0fcaeb56435678a142b71a33e4f3e45b2 --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 36fb18c20963..6aacd471fd5b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -2783,7 +2783,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, u16 notify_interval; u8 *notify_ie; size_t notify_ielen; - struct cfg80211_inform_bss bss_data = { 0 }; + struct cfg80211_inform_bss bss_data = {}; if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) { brcmf_err("Bss info is larger than buffer. Discarding\n"); -- GitLab From b2e0469420ec0c6ebd04a95d8c546c39d671e929 Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Wed, 9 May 2018 15:41:07 -0700 Subject: [PATCH 274/855] msm: camera: isp: Fix rdi buf done for early pcr Currently there is no callback defined to handle buf done for early PCR, this change ensures rdi buf done is acknowledged. Change-Id: Ib001ed841f812ced50c8afa79edfe634580ab0bd Signed-off-by: Harsh Shah Signed-off-by: Karthik Anantha Ram --- .../media/platform/msm/camera/cam_isp/cam_isp_context.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index b618ee526479..08d012df89ab 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -2379,7 +2379,9 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; ctx_isp->substate_activated = ctx_isp->rdi_only_context ? - CAM_ISP_CTX_ACTIVATED_APPLIED : CAM_ISP_CTX_ACTIVATED_SOF; + CAM_ISP_CTX_ACTIVATED_APPLIED : + (req_isp->num_fence_map_out) ? CAM_ISP_CTX_ACTIVATED_EPOCH : + CAM_ISP_CTX_ACTIVATED_SOF; /* * Only place to change state before calling the hw due to @@ -2397,6 +2399,11 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, goto end; } CAM_DBG(CAM_ISP, "start device success"); + + if (req_isp->num_fence_map_out) { + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->active_req_list); + } end: return rc; } -- GitLab From 8714e647c61c5141ef2b6b8fb9e780b24177b66e Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Thu, 17 May 2018 15:21:08 +0530 Subject: [PATCH 275/855] msm: adsprpc: destroy mutex before file free Destroy mutex before file free, to avoid use after free of mutex. Change-Id: I4ff73dc17b15043eacbb299219a379bfd1a8efa6 Acked-by: Himateja Reddy Signed-off-by: Tharun Kumar Merugu --- drivers/char/adsprpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 4d734bfe2018..683c19bcc090 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -2764,6 +2764,7 @@ static int fastrpc_file_free(struct fastrpc_file *fl) mutex_unlock(&fl->perf_mutex); mutex_destroy(&fl->perf_mutex); mutex_destroy(&fl->fl_map_mutex); + mutex_destroy(&fl->map_mutex); kfree(fl); return 0; } @@ -2777,7 +2778,6 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) pm_qos_remove_request(&fl->pm_qos_req); if (fl->debugfs_file != NULL) debugfs_remove(fl->debugfs_file); - mutex_destroy(&fl->map_mutex); fastrpc_file_free(fl); file->private_data = NULL; } -- GitLab From 51c726790b5250c2052caebecedf7ffc11a335f3 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Thu, 17 May 2018 12:58:32 +0530 Subject: [PATCH 276/855] ARM: dts: msm: add support for FHD+ panel to sdm670 This change adds the hx8399 FHD+ panel node to sdm670 CDP and MTP platform. Change-Id: Ib09a41131802cd9f9fd571e6c5131ec8b5cf69a0 Signed-off-by: Sandeep Panda --- arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi | 11 +++++++++++ arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi | 11 +++++++++++ arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi index da4d27da8d66..00a1498f9374 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi @@ -296,6 +296,17 @@ qcom,platform-te-gpio = <&tlmm 10 0>; }; +&dsi_hx8399_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; +}; + &dsi_dual_nt35597_truly_video_display { qcom,dsi-display-active; }; diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi index 7764837cb7db..63941e450571 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi @@ -355,6 +355,17 @@ qcom,platform-te-gpio = <&tlmm 10 0>; }; +&dsi_hx8399_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; +}; + &dsi_dual_nt35597_truly_video_display { qcom,dsi-display-active; }; diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi index 48deca6aecc5..dc55e620e2cd 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi @@ -468,7 +468,7 @@ dsi_hx8399_truly_cmd_display: qcom,dsi-display@16 { compatible = "qcom,dsi-display"; - label = "dsi_hx8399_truly_cmd_display"; + label = "dsi_hx8399_truly_fhd_video_display"; qcom,display-type = "primary"; qcom,dsi-ctrl = <&mdss_dsi0>; -- GitLab From 1074e5274ec14513c1f6170464ca9c613b2a3c87 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Thu, 17 May 2018 11:48:40 -0700 Subject: [PATCH 277/855] Revert "msm: camera: ife: Add bus write master UBWC config update" This reverts commit 776c3918960bb83e8730632ec428995311a4c64c. The change being reverted was made to add support for UBWC 3.0 config on newer hardware. UBWC 3.0 is not supported by SDM845 target and older hardware and therefore that change is not needed on 4.9 branch. Change-Id: I8fa1747c253e5753733fbd4994dad261304f9959 Signed-off-by: Vishalsingh Hajeri --- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 134 ---- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 2 - .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 1 - .../isp_hw/vfe_hw/vfe17x/cam_vfe170.h | 4 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe175.h | 20 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 577 +++++------------- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h | 22 +- 7 files changed, 148 insertions(+), 612 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index f092d5aea193..3e099e245feb 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -47,7 +47,6 @@ static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = { CAM_ISP_HW_CMD_GET_HFR_UPDATE, CAM_ISP_HW_CMD_CLOCK_UPDATE, CAM_ISP_HW_CMD_BW_UPDATE, - CAM_ISP_HW_CMD_UBWC_UPDATE, }; static struct cam_ife_hw_mgr g_ife_hw_mgr; @@ -2250,129 +2249,6 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, return rc; } -static int cam_isp_blob_ubwc_update( - uint32_t blob_type, - struct cam_isp_generic_blob_info *blob_info, - struct cam_ubwc_config *ubwc_config, - struct cam_hw_prepare_update_args *prepare) -{ - struct cam_ubwc_plane_cfg_v1 *ubwc_plane_cfg; - struct cam_kmd_buf_info *kmd_buf_info; - struct cam_ife_hw_mgr_ctx *ctx = NULL; - struct cam_ife_hw_mgr_res *hw_mgr_res; - uint32_t res_id_out, i; - uint32_t total_used_bytes = 0; - uint32_t kmd_buf_remain_size; - uint32_t *cmd_buf_addr; - uint32_t bytes_used = 0; - int num_ent, rc = 0; - - ctx = prepare->ctxt_to_hw_map; - if (!ctx) { - CAM_ERR(CAM_ISP, "Invalid ctx"); - rc = -EINVAL; - goto end; - } - - if ((prepare->num_hw_update_entries + 1) >= - prepare->max_hw_update_entries) { - CAM_ERR(CAM_ISP, "Insufficient HW entries :%d max:%d", - prepare->num_hw_update_entries, - prepare->max_hw_update_entries); - rc = -EINVAL; - goto end; - } - - switch (ubwc_config->api_version) { - case CAM_UBWC_CFG_VERSION_1: - CAM_DBG(CAM_ISP, "num_ports= %d", ubwc_config->num_ports); - - kmd_buf_info = blob_info->kmd_buf_info; - for (i = 0; i < ubwc_config->num_ports; i++) { - ubwc_plane_cfg = &ubwc_config->ubwc_plane_cfg[i][0]; - res_id_out = ubwc_plane_cfg->port_type & 0xFF; - - CAM_DBG(CAM_ISP, "UBWC config idx %d, port_type=%d", i, - ubwc_plane_cfg->port_type); - - if (res_id_out >= CAM_IFE_HW_OUT_RES_MAX) { - CAM_ERR(CAM_ISP, "Invalid port type:%x", - ubwc_plane_cfg->port_type); - rc = -EINVAL; - goto end; - } - - if ((kmd_buf_info->used_bytes - + total_used_bytes) < kmd_buf_info->size) { - kmd_buf_remain_size = kmd_buf_info->size - - (kmd_buf_info->used_bytes - + total_used_bytes); - } else { - CAM_ERR(CAM_ISP, - "no free kmd memory for base=%d bytes_used=%u buf_size=%u", - blob_info->base_info->idx, bytes_used, - kmd_buf_info->size); - rc = -ENOMEM; - goto end; - } - - cmd_buf_addr = kmd_buf_info->cpu_addr + - kmd_buf_info->used_bytes/4 + - total_used_bytes/4; - hw_mgr_res = &ctx->res_list_ife_out[res_id_out]; - - if (!hw_mgr_res) { - CAM_ERR(CAM_ISP, "Invalid hw_mgr_res"); - rc = -EINVAL; - goto end; - } - - rc = cam_isp_add_cmd_buf_update( - hw_mgr_res, blob_type, - blob_type_hw_cmd_map[blob_type], - blob_info->base_info->idx, - (void *)cmd_buf_addr, - kmd_buf_remain_size, - (void *)ubwc_plane_cfg, - &bytes_used); - if (rc < 0) { - CAM_ERR(CAM_ISP, - "Failed cmd_update, base_idx=%d, bytes_used=%u, res_id_out=0x%x", - blob_info->base_info->idx, - bytes_used, - res_id_out); - goto end; - } - - total_used_bytes += bytes_used; - } - - if (total_used_bytes) { - /* Update the HW entries */ - num_ent = prepare->num_hw_update_entries; - prepare->hw_update_entries[num_ent].handle = - kmd_buf_info->handle; - prepare->hw_update_entries[num_ent].len = - total_used_bytes; - prepare->hw_update_entries[num_ent].offset = - kmd_buf_info->offset; - num_ent++; - - kmd_buf_info->used_bytes += total_used_bytes; - kmd_buf_info->offset += total_used_bytes; - prepare->num_hw_update_entries = num_ent; - } - break; - default: - CAM_ERR(CAM_ISP, "Invalid UBWC API Version %d", - ubwc_config->api_version); - rc = -EINVAL; - break; - } -end: - return rc; -} - static int cam_isp_blob_hfr_update( uint32_t blob_type, struct cam_isp_generic_blob_info *blob_info, @@ -2613,16 +2489,6 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, bw_config, sizeof(prepare_hw_data->bw_config[0])); prepare_hw_data->bw_config_valid[bw_config->usage_type] = true; - } - break; - case CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG: { - struct cam_ubwc_config *ubwc_config = - (struct cam_ubwc_config *)blob_data; - - rc = cam_isp_blob_ubwc_update(blob_type, blob_info, - ubwc_config, prepare); - if (rc) - CAM_ERR(CAM_ISP, "UBWC Update Failed rc: %d", rc); } break; default: diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 51a00e282527..c56c49fac5af 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -95,7 +95,6 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_BW_CONTROL, CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, CAM_ISP_HW_CMD_GET_REG_DUMP, - CAM_ISP_HW_CMD_UBWC_UPDATE, CAM_ISP_HW_CMD_MAX, }; @@ -202,7 +201,6 @@ struct cam_isp_hw_get_cmd_update { struct cam_isp_port_hfr_config *hfr_update; struct cam_isp_clock_config *clock_update; struct cam_isp_bw_config *bw_update; - struct cam_ubwc_plane_cfg_v1 *ubwc_update; }; }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index bd862512ccc6..d25dec8850e2 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -703,7 +703,6 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_GET_HFR_UPDATE: case CAM_ISP_HW_CMD_STRIPE_UPDATE: case CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ: - case CAM_ISP_HW_CMD_UBWC_UPDATE: rc = core_info->vfe_bus->hw_ops.process_cmd( core_info->vfe_bus->bus_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h index 28a632a597e8..984adf7eda8a 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h @@ -198,7 +198,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_3 = { .meta_addr = 0x00002538, .meta_offset = 0x0000253C, .meta_stride = 0x00002540, - .mode_cfg_0 = 0x00002544, + .mode_cfg = 0x00002544, .bw_limit = 0x000025A0, }; @@ -209,7 +209,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_4 = { .meta_addr = 0x00002638, .meta_offset = 0x0000263C, .meta_stride = 0x00002640, - .mode_cfg_0 = 0x00002644, + .mode_cfg = 0x00002644, .bw_limit = 0x000026A0, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h index a9b0ace03ed3..a72a9774863b 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h @@ -191,7 +191,7 @@ static struct cam_irq_register_set vfe175_bus_irq_reg[3] = { }, }; -static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client vfe175_ubwc_regs_client_3 = { .tile_cfg = 0x0000252C, .h_init = 0x00002530, @@ -199,12 +199,11 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client .meta_addr = 0x00002538, .meta_offset = 0x0000253C, .meta_stride = 0x00002540, - .mode_cfg_0 = 0x00002544, - .mode_cfg_1 = 0x000025A4, + .mode_cfg = 0x00002544, .bw_limit = 0x000025A0, }; -static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client vfe175_ubwc_regs_client_4 = { .tile_cfg = 0x0000262C, .h_init = 0x00002630, @@ -212,12 +211,11 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client .meta_addr = 0x00002638, .meta_offset = 0x0000263C, .meta_stride = 0x00002640, - .mode_cfg_0 = 0x00002644, - .mode_cfg_1 = 0x000026A4, + .mode_cfg = 0x00002644, .bw_limit = 0x000026A0, }; -static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client vfe175_ubwc_regs_client_20 = { .tile_cfg = 0x0000362C, .h_init = 0x00003630, @@ -225,12 +223,11 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client .meta_addr = 0x00003638, .meta_offset = 0x0000363C, .meta_stride = 0x00003640, - .mode_cfg_0 = 0x00003644, - .mode_cfg_1 = 0x000036A4, + .mode_cfg = 0x00003644, .bw_limit = 0x000036A0, }; -static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client vfe175_ubwc_regs_client_21 = { .tile_cfg = 0x0000372C, .h_init = 0x00003730, @@ -238,8 +235,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client .meta_addr = 0x00003738, .meta_offset = 0x0000373C, .meta_stride = 0x00003740, - .mode_cfg_0 = 0x00003744, - .mode_cfg_1 = 0x000037A4, + .mode_cfg = 0x00003744, .bw_limit = 0x000037A0, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 3dd916e27532..12e9125d8fa4 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -54,8 +54,8 @@ static const char drv_name[] = "vfe_bus"; #define CAM_VFE_ADD_REG_VAL_PAIR(buf_array, index, offset, val) \ do { \ - buf_array[(index)++] = offset; \ - buf_array[(index)++] = val; \ + buf_array[index++] = offset; \ + buf_array[index++] = val; \ } while (0) static uint32_t bus_error_irq_mask[3] = { @@ -134,14 +134,12 @@ struct cam_vfe_bus_ver2_wm_resource_data { uint32_t burst_len; uint32_t en_ubwc; - bool ubwc_updated; uint32_t packer_cfg; uint32_t tile_cfg; uint32_t h_init; uint32_t v_init; uint32_t ubwc_meta_stride; - uint32_t ubwc_mode_cfg_0; - uint32_t ubwc_mode_cfg_1; + uint32_t ubwc_mode_cfg; uint32_t ubwc_meta_offset; uint32_t irq_subsample_period; @@ -1088,8 +1086,7 @@ static int cam_vfe_bus_release_wm(void *bus_priv, rsrc_data->h_init = 0; rsrc_data->v_init = 0; rsrc_data->ubwc_meta_stride = 0; - rsrc_data->ubwc_mode_cfg_0 = 0; - rsrc_data->ubwc_mode_cfg_1 = 0; + rsrc_data->ubwc_mode_cfg = 0; rsrc_data->ubwc_meta_offset = 0; rsrc_data->init_cfg_done = false; rsrc_data->hfr_cfg_done = false; @@ -1110,7 +1107,6 @@ static int cam_vfe_bus_start_wm(struct cam_isp_resource_node *wm_res) struct cam_vfe_bus_ver2_common_data *common_data = rsrc_data->common_data; uint32_t bus_irq_reg_mask[CAM_VFE_BUS_IRQ_MAX] = {0}; - uint32_t camera_hw_version; cam_io_w(0xf, common_data->mem_base + rsrc_data->hw_regs->burst_limit); @@ -1146,39 +1142,13 @@ static int cam_vfe_bus_start_wm(struct cam_isp_resource_node *wm_res) /* enable ubwc if needed*/ if (rsrc_data->en_ubwc) { - rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); - if (rc) { - CAM_ERR(CAM_ISP, "Failed to get HW version:%d rc:%d", - camera_hw_version, rc); - return rc; - } - if ((camera_hw_version > CAM_CPAS_TITAN_NONE) && - (camera_hw_version < CAM_CPAS_TITAN_175_V100)) { - struct cam_vfe_bus_ver2_reg_offset_ubwc_client - *ubwc_regs; - - ubwc_regs = - (struct - cam_vfe_bus_ver2_reg_offset_ubwc_client *) - rsrc_data->hw_regs->ubwc_regs; - cam_io_w_mb(0x1, common_data->mem_base + - ubwc_regs->mode_cfg_0); - } else if ((camera_hw_version == CAM_CPAS_TITAN_175_V100) || - (camera_hw_version == CAM_CPAS_TITAN_175_V101)) { - struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client - *ubwc_regs; - - ubwc_regs = - (struct - cam_vfe_bus_ver2_reg_offset_ubwc_3_client *) - rsrc_data->hw_regs->ubwc_regs; - cam_io_w_mb(0x1, common_data->mem_base + - ubwc_regs->mode_cfg_0); - } else { - CAM_ERR(CAM_ISP, "Invalid HW version: %d", - camera_hw_version); - return -EINVAL; - } + int val = cam_io_r_mb(common_data->mem_base + + rsrc_data->hw_regs->ubwc_regs->mode_cfg); + CAM_DBG(CAM_ISP, "ubwc reg %d, res id %d", + val, rsrc_data->index); + val |= 0x1; + cam_io_w_mb(val, common_data->mem_base + + rsrc_data->hw_regs->ubwc_regs->mode_cfg); } /* Enable WM */ @@ -2356,285 +2326,6 @@ static int cam_vfe_bus_error_irq_top_half(uint32_t evt_id, return -EFAULT; } -static void cam_vfe_bus_update_ubwc_meta_addr( - uint32_t *reg_val_pair, - uint32_t *j, - void *regs, - uint64_t image_buf) -{ - uint32_t camera_hw_version; - struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_regs; - struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *ubwc_3_regs; - int rc = 0; - - if (!regs || !reg_val_pair || !j) { - CAM_ERR(CAM_ISP, "Invalid args"); - rc = -EINVAL; - goto end; - } - - rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); - if (rc) { - CAM_ERR(CAM_ISP, "Failed to get HW version rc: %d", rc); - goto end; - } else if ((camera_hw_version < CAM_CPAS_TITAN_170_V100) || - (camera_hw_version > CAM_CPAS_TITAN_175_V101)) { - CAM_ERR(CAM_ISP, "Invalid HW version: %d", - camera_hw_version); - goto end; - } - - switch (camera_hw_version) { - case CAM_CPAS_TITAN_170_V100: - case CAM_CPAS_TITAN_170_V110: - case CAM_CPAS_TITAN_170_V120: - ubwc_regs = - (struct cam_vfe_bus_ver2_reg_offset_ubwc_client *)regs; - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->meta_addr, - image_buf); - break; - case CAM_CPAS_TITAN_175_V100: - case CAM_CPAS_TITAN_175_V101: - ubwc_3_regs = - (struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *) - regs; - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_3_regs->meta_addr, - image_buf); - break; - default: - break; - } -end: - return; -} - -static int cam_vfe_bus_update_ubwc_3_regs( - struct cam_vfe_bus_ver2_wm_resource_data *wm_data, - uint32_t *reg_val_pair, uint32_t i, uint32_t *j) -{ - struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *ubwc_regs; - uint32_t ubwc_bw_limit = 0; - int rc = 0; - - if (!wm_data || !reg_val_pair || !j) { - CAM_ERR(CAM_ISP, "Invalid args"); - rc = -EINVAL; - goto end; - } - - ubwc_regs = (struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *) - wm_data->hw_regs->ubwc_regs; - - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - wm_data->hw_regs->packer_cfg, wm_data->packer_cfg); - CAM_DBG(CAM_ISP, "WM %d packer cfg 0x%x", - wm_data->index, reg_val_pair[*j-1]); - - if (wm_data->is_dual) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->tile_cfg, wm_data->tile_cfg); - } else { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->tile_cfg, wm_data->tile_cfg); - CAM_DBG(CAM_ISP, "WM %d tile cfg 0x%x", - wm_data->index, reg_val_pair[*j-1]); - } - - if (wm_data->is_dual) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->h_init, wm_data->offset); - } else { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->h_init, wm_data->h_init); - CAM_DBG(CAM_ISP, "WM %d h_init 0x%x", - wm_data->index, reg_val_pair[*j-1]); - } - - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->v_init, wm_data->v_init); - CAM_DBG(CAM_ISP, "WM %d v_init 0x%x", - wm_data->index, reg_val_pair[*j-1]); - - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->meta_stride, wm_data->ubwc_meta_stride); - CAM_DBG(CAM_ISP, "WM %d meta stride 0x%x", - wm_data->index, reg_val_pair[*j-1]); - - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->mode_cfg_0, wm_data->ubwc_mode_cfg_0); - CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_0 0x%x", - wm_data->index, reg_val_pair[*j-1]); - - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->mode_cfg_1, wm_data->ubwc_mode_cfg_1); - CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_1 0x%x", - wm_data->index, reg_val_pair[*j-1]); - - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->meta_offset, wm_data->ubwc_meta_offset); - CAM_DBG(CAM_ISP, "WM %d ubwc meta offset 0x%x", - wm_data->index, reg_val_pair[*j-1]); - - switch (wm_data->format) { - case CAM_FORMAT_UBWC_TP10: - ubwc_bw_limit = 0x8 | BIT(0); - break; - case CAM_FORMAT_UBWC_NV12_4R: - ubwc_bw_limit = 0xB | BIT(0); - break; - default: - ubwc_bw_limit = 0; - break; - } - - if (ubwc_bw_limit) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->bw_limit, ubwc_bw_limit); - CAM_DBG(CAM_ISP, "WM %d ubwc bw limit 0x%x", - wm_data->index, ubwc_bw_limit); - } - -end: - return rc; -} - -static int cam_vfe_bus_update_ubwc_legacy_regs( - struct cam_vfe_bus_ver2_wm_resource_data *wm_data, - uint32_t camera_hw_version, uint32_t *reg_val_pair, - uint32_t i, uint32_t *j) -{ - struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_regs; - uint32_t ubwc_bw_limit = 0; - int rc = 0; - - if (!wm_data || !reg_val_pair || !j) { - CAM_ERR(CAM_ISP, "Invalid args"); - rc = -EINVAL; - goto end; - } - - ubwc_regs = (struct cam_vfe_bus_ver2_reg_offset_ubwc_client *) - wm_data->hw_regs->ubwc_regs; - - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - wm_data->hw_regs->packer_cfg, wm_data->packer_cfg); - CAM_DBG(CAM_ISP, "WM %d packer cfg 0x%x", - wm_data->index, reg_val_pair[*j-1]); - - if (wm_data->is_dual) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->tile_cfg, wm_data->tile_cfg); - } else { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->tile_cfg, wm_data->tile_cfg); - CAM_DBG(CAM_ISP, "WM %d tile cfg 0x%x", - wm_data->index, reg_val_pair[*j-1]); - } - - if (wm_data->is_dual) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->h_init, wm_data->offset); - } else { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->h_init, wm_data->h_init); - CAM_DBG(CAM_ISP, "WM %d h_init 0x%x", - wm_data->index, reg_val_pair[*j-1]); - } - - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->v_init, wm_data->v_init); - CAM_DBG(CAM_ISP, "WM %d v_init 0x%x", - wm_data->index, reg_val_pair[*j-1]); - - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->meta_stride, wm_data->ubwc_meta_stride); - CAM_DBG(CAM_ISP, "WM %d meta stride 0x%x", - wm_data->index, reg_val_pair[*j-1]); - - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->mode_cfg_0, wm_data->ubwc_mode_cfg_0); - CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_0 0x%x", - wm_data->index, reg_val_pair[*j-1]); - - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->meta_offset, wm_data->ubwc_meta_offset); - CAM_DBG(CAM_ISP, "WM %d ubwc meta offset 0x%x", - wm_data->index, reg_val_pair[*j-1]); - - if (camera_hw_version == CAM_CPAS_TITAN_170_V110) { - switch (wm_data->format) { - case CAM_FORMAT_UBWC_TP10: - ubwc_bw_limit = 0x8 | BIT(0); - break; - case CAM_FORMAT_UBWC_NV12_4R: - ubwc_bw_limit = 0xB | BIT(0); - break; - default: - ubwc_bw_limit = 0; - break; - } - } - - if (ubwc_bw_limit) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, - ubwc_regs->bw_limit, ubwc_bw_limit); - CAM_DBG(CAM_ISP, "WM %d ubwc bw limit 0x%x", - wm_data->index, ubwc_bw_limit); - } - -end: - return rc; -} - -static int cam_vfe_bus_update_ubwc_regs( - struct cam_vfe_bus_ver2_wm_resource_data *wm_data, - uint32_t *reg_val_pair, uint32_t i, uint32_t *j) -{ - uint32_t camera_hw_version; - int rc = 0; - - if (!wm_data || !reg_val_pair || !j) { - CAM_ERR(CAM_ISP, "Invalid args"); - rc = -EINVAL; - goto end; - } - - rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); - if (rc) { - CAM_ERR(CAM_ISP, "Failed to get HW version rc: %d", rc); - goto end; - } else if ((camera_hw_version <= CAM_CPAS_TITAN_NONE) || - (camera_hw_version >= CAM_CPAS_TITAN_MAX)) { - CAM_ERR(CAM_ISP, "Invalid HW version: %d", - camera_hw_version); - rc = -EINVAL; - goto end; - } - switch (camera_hw_version) { - case CAM_CPAS_TITAN_170_V100: - case CAM_CPAS_TITAN_170_V110: - case CAM_CPAS_TITAN_170_V120: - rc = cam_vfe_bus_update_ubwc_legacy_regs( - wm_data, camera_hw_version, reg_val_pair, i, j); - break; - case CAM_CPAS_TITAN_175_V100: - case CAM_CPAS_TITAN_175_V101: - rc = cam_vfe_bus_update_ubwc_3_regs( - wm_data, reg_val_pair, i, j); - break; - default: - break; - } - - if (rc) - CAM_ERR(CAM_ISP, "Failed to update ubwc regs rc:%d", rc); - -end: - return rc; -} - static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, uint32_t arg_size) { @@ -2646,7 +2337,8 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_client = NULL; uint32_t *reg_val_pair; uint32_t i, j, size = 0; - uint32_t frame_inc = 0, val; + uint32_t frame_inc = 0, ubwc_bw_limit = 0, camera_hw_version, val; + int rc = 0; bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; @@ -2713,20 +2405,136 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, "No UBWC register to configure."); return -EINVAL; } - if (wm_data->ubwc_updated) { - wm_data->ubwc_updated = false; - cam_vfe_bus_update_ubwc_regs( - wm_data, reg_val_pair, i, &j); + if (wm_data->packer_cfg != + io_cfg->planes[i].packer_config || + !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->packer_cfg, + io_cfg->planes[i].packer_config); + wm_data->packer_cfg = + io_cfg->planes[i].packer_config; + CAM_DBG(CAM_ISP, "WM %d packer cfg 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->is_dual) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs->tile_cfg, + wm_data->tile_cfg); + } else if ((wm_data->tile_cfg != + io_cfg->planes[i].tile_config) + || !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs->tile_cfg, + io_cfg->planes[i].tile_config); + wm_data->tile_cfg = + io_cfg->planes[i].tile_config; + CAM_DBG(CAM_ISP, "WM %d tile cfg 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->is_dual) { + if ((wm_data->h_init != wm_data->offset) || + !wm_data->init_cfg_done) { + /* + * For dual ife h init value need to + * take from offset. Striping config + * update offset value. + */ + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, + j, ubwc_client->h_init, + wm_data->offset); + wm_data->h_init = wm_data->offset; + } + } else if (wm_data->h_init != + io_cfg->planes[i].h_init || + !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs->h_init, + io_cfg->planes[i].h_init); + wm_data->h_init = io_cfg->planes[i].h_init; + CAM_DBG(CAM_ISP, "WM %d h_init 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->v_init != io_cfg->planes[i].v_init || + !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs->v_init, + io_cfg->planes[i].v_init); + wm_data->v_init = io_cfg->planes[i].v_init; + CAM_DBG(CAM_ISP, "WM %d v_init 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->ubwc_meta_stride != + io_cfg->planes[i].meta_stride || + !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + ubwc_client->meta_stride, + io_cfg->planes[i].meta_stride); + wm_data->ubwc_meta_stride = + io_cfg->planes[i].meta_stride; + CAM_DBG(CAM_ISP, "WM %d meta stride 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->ubwc_mode_cfg != + io_cfg->planes[i].mode_config || + !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs->mode_cfg, + io_cfg->planes[i].mode_config); + wm_data->ubwc_mode_cfg = + io_cfg->planes[i].mode_config; + CAM_DBG(CAM_ISP, "WM %d ubwc mode cfg 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->ubwc_meta_offset != + io_cfg->planes[i].meta_offset || + !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + ubwc_client->meta_offset, + io_cfg->planes[i].meta_offset); + wm_data->ubwc_meta_offset = + io_cfg->planes[i].meta_offset; + CAM_DBG(CAM_ISP, "WM %d ubwc meta offset 0x%x", + wm_data->index, reg_val_pair[j-1]); } /* UBWC meta address */ - cam_vfe_bus_update_ubwc_meta_addr( - reg_val_pair, &j, - wm_data->hw_regs->ubwc_regs, + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs->meta_addr, update_buf->wm_update->image_buf[i]); CAM_DBG(CAM_ISP, "WM %d ubwc meta addr 0x%llx", wm_data->index, update_buf->wm_update->image_buf[i]); + + /* Enable UBWC bandwidth limit if required */ + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (camera_hw_version == CAM_CPAS_TITAN_170_V110 + && !rc) { + switch (wm_data->format) { + case CAM_FORMAT_UBWC_TP10: + ubwc_bw_limit = 0x8 | BIT(0); + break; + case CAM_FORMAT_UBWC_NV12_4R: + ubwc_bw_limit = 0xB | BIT(0); + break; + default: + ubwc_bw_limit = 0; + break; + } + } + + if (ubwc_bw_limit) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs->bw_limit, + ubwc_bw_limit); + CAM_DBG(CAM_ISP, "WM %d ubwc bw limit 0x%x", + wm_data->index, ubwc_bw_limit); + } } /* WM Image address */ @@ -2895,116 +2703,6 @@ static int cam_vfe_bus_update_hfr(void *priv, void *cmd_args, return 0; } -static int cam_vfe_bus_update_ubwc_config(void *cmd_args) -{ - struct cam_isp_hw_get_cmd_update *update_ubwc; - struct cam_vfe_bus_ver2_vfe_out_data *vfe_out_data = NULL; - struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; - struct cam_ubwc_plane_cfg_v1 *ubwc_plane_cfg = NULL; - uint32_t i; - int rc = 0; - - if (!cmd_args) { - CAM_ERR(CAM_ISP, "Invalid args"); - rc = -EINVAL; - goto end; - } - - update_ubwc = (struct cam_isp_hw_get_cmd_update *) cmd_args; - - vfe_out_data = (struct cam_vfe_bus_ver2_vfe_out_data *) - update_ubwc->res->res_priv; - - if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { - CAM_ERR(CAM_ISP, "Invalid data"); - rc = -EINVAL; - goto end; - } - - ubwc_plane_cfg = update_ubwc->ubwc_update; - - for (i = 0; i < vfe_out_data->num_wm; i++) { - - wm_data = vfe_out_data->wm_res[i]->res_priv; - if (i > 0) - ubwc_plane_cfg++; - - if (!wm_data->hw_regs->ubwc_regs) { - CAM_ERR(CAM_ISP, - "No UBWC register to configure."); - rc = -EINVAL; - goto end; - } - - if (!wm_data->en_ubwc) { - CAM_ERR(CAM_ISP, "UBWC Disabled"); - rc = -EINVAL; - goto end; - } - - if (wm_data->packer_cfg != - ubwc_plane_cfg->packer_config || - !wm_data->init_cfg_done) { - wm_data->packer_cfg = ubwc_plane_cfg->packer_config; - wm_data->ubwc_updated = true; - } - - if ((!wm_data->is_dual) && ((wm_data->tile_cfg != - ubwc_plane_cfg->tile_config) - || !wm_data->init_cfg_done)) { - wm_data->tile_cfg = ubwc_plane_cfg->tile_config; - wm_data->ubwc_updated = true; - } - - if ((!wm_data->is_dual) && ((wm_data->h_init != - ubwc_plane_cfg->h_init) || - !wm_data->init_cfg_done)) { - wm_data->h_init = ubwc_plane_cfg->h_init; - wm_data->ubwc_updated = true; - } - - if (wm_data->v_init != ubwc_plane_cfg->v_init || - !wm_data->init_cfg_done) { - wm_data->v_init = ubwc_plane_cfg->v_init; - wm_data->ubwc_updated = true; - } - - if (wm_data->ubwc_meta_stride != - ubwc_plane_cfg->meta_stride || - !wm_data->init_cfg_done) { - wm_data->ubwc_meta_stride = ubwc_plane_cfg->meta_stride; - wm_data->ubwc_updated = true; - } - - if (wm_data->ubwc_mode_cfg_0 != - ubwc_plane_cfg->mode_config_0 || - !wm_data->init_cfg_done) { - wm_data->ubwc_mode_cfg_0 = - ubwc_plane_cfg->mode_config_0; - wm_data->ubwc_updated = true; - } - - if (wm_data->ubwc_mode_cfg_1 != - ubwc_plane_cfg->mode_config_1 || - !wm_data->init_cfg_done) { - wm_data->ubwc_mode_cfg_1 = - ubwc_plane_cfg->mode_config_1; - wm_data->ubwc_updated = true; - } - - if (wm_data->ubwc_meta_offset != - ubwc_plane_cfg->meta_offset || - !wm_data->init_cfg_done) { - wm_data->ubwc_meta_offset = ubwc_plane_cfg->meta_offset; - wm_data->ubwc_updated = true; - } - } - -end: - return rc; -} - - static int cam_vfe_bus_update_stripe_cfg(void *priv, void *cmd_args, uint32_t arg_size) { @@ -3204,9 +2902,6 @@ static int cam_vfe_bus_process_cmd( bus_priv->error_irq_handle = 0; } break; - case CAM_ISP_HW_CMD_UBWC_UPDATE: - rc = cam_vfe_bus_update_ubwc_config(cmd_args); - break; default: CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", cmd_type); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h index dee3ecaf1239..c001eef72bc4 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h @@ -100,28 +100,10 @@ struct cam_vfe_bus_ver2_reg_offset_ubwc_client { uint32_t meta_addr; uint32_t meta_offset; uint32_t meta_stride; - uint32_t mode_cfg_0; + uint32_t mode_cfg; uint32_t bw_limit; }; -/* - * struct cam_vfe_bus_ver2_reg_offset_ubwc_client: - * - * @Brief: UBWC register offsets for BUS Clients - */ -struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client { - uint32_t tile_cfg; - uint32_t h_init; - uint32_t v_init; - uint32_t meta_addr; - uint32_t meta_offset; - uint32_t meta_stride; - uint32_t mode_cfg_0; - uint32_t mode_cfg_1; - uint32_t bw_limit; -}; - - /* * struct cam_vfe_bus_ver2_reg_offset_bus_client: * @@ -145,7 +127,7 @@ struct cam_vfe_bus_ver2_reg_offset_bus_client { uint32_t framedrop_pattern; uint32_t frame_inc; uint32_t burst_limit; - void *ubwc_regs; + struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_regs; }; /* -- GitLab From f5f9793064057420d32b360129e993d49ba7e817 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Thu, 17 May 2018 12:18:07 -0700 Subject: [PATCH 278/855] Revert "msm: camera: uapi: Adds UBWC blob payload structure" This reverts commit b7edd12f5705e7c890efe7feed7c2eb98923af47. UBWC blob payload structure was added to support UBWC 3.0 and its corresponding driver changes. It is not required on 4.9 branch as SDM845 and older targets do not support UBWC 3.0. Change-Id: I15c192abf985659def4596b39355a6423513709e Signed-off-by: Vishalsingh Hajeri --- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 2 +- include/uapi/media/cam_defs.h | 49 ------------------- include/uapi/media/cam_isp.h | 7 ++- 3 files changed, 4 insertions(+), 54 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 3e099e245feb..12c37863a3a5 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -41,7 +41,7 @@ (CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON + 1) #define CAM_ISP_GENERIC_BLOB_TYPE_MAX \ - (CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG + 1) + (CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG + 1) static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = { CAM_ISP_HW_CMD_GET_HFR_UPDATE, diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h index 34a65599b558..e006463d2aa6 100644 --- a/include/uapi/media/cam_defs.h +++ b/include/uapi/media/cam_defs.h @@ -43,9 +43,6 @@ #define CAM_CMD_BUF_GENERIC 0x9 #define CAM_CMD_BUF_LEGACY 0xA -/* UBWC API Version */ -#define CAM_UBWC_CFG_VERSION_1 1 - /** * enum flush_type_t - Identifies the various flush types * @@ -238,34 +235,6 @@ struct cam_plane_cfg { uint32_t v_init; }; -/** - * struct cam_ubwc_plane_cfg_v1 - UBWC Plane configuration info - * - * @port_type: Port Type - * @meta_stride: UBWC metadata stride - * @meta_size: UBWC metadata plane size - * @meta_offset: UBWC metadata offset - * @packer_config: UBWC packer config - * @mode_config_0: UBWC mode config 0 - * @mode_config_1: UBWC 3 mode config 1 - * @tile_config: UBWC tile config - * @h_init: UBWC horizontal initial coordinate in pixels - * @v_init: UBWC vertical initial coordinate in lines - * - */ -struct cam_ubwc_plane_cfg_v1 { - uint32_t port_type; - uint32_t meta_stride; - uint32_t meta_size; - uint32_t meta_offset; - uint32_t packer_config; - uint32_t mode_config_0; - uint32_t mode_config_1; - uint32_t tile_config; - uint32_t h_init; - uint32_t v_init; -}; - /** * struct cam_cmd_buf_desc - Command buffer descriptor * @@ -505,22 +474,4 @@ struct cam_flush_dev_cmd { int64_t req_id; }; -/** - * struct cam_ubwc_config - UBWC Configuration Payload - * - * @api_version: UBWC config api version - * @num_ports: Number of ports to be configured - * @ubwc_plane_config: Array of UBWC configurations per port - * Size [CAM_PACKET_MAX_PLANES - 1] per port - * as UBWC is supported on Y & C planes - * and therefore a max size of 2 planes - * - */ -struct cam_ubwc_config { - uint32_t api_version; - uint32_t num_ports; - struct cam_ubwc_plane_cfg_v1 - ubwc_plane_cfg[1][CAM_PACKET_MAX_PLANES - 1]; -}; - #endif /* __UAPI_CAM_DEFS_H__ */ diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index 0f23e595fb19..afd109fcb471 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -84,10 +84,9 @@ #define CAM_ISP_DSP_MODE_ROUND 2 /* ISP Generic Cmd Buffer Blob types */ -#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG 0 -#define CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1 -#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG 2 -#define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG 3 +#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG 0 +#define CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1 +#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG 2 /* Query devices */ /** -- GitLab From 6e0508b397c36a1adc68cec845bc270edb183815 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 15 May 2018 13:34:59 -0700 Subject: [PATCH 279/855] msm: camera: reqmgr: Validate inject delay for all pd devices There is a possibilty that a packet is not available for a higher pd device and a lower pd device at the same instance is introducing inject delay, this change compensates this delay for a given frame. Change-Id: I2dc24028834cc257df1ba16429c397bed3d09671 Signed-off-by: Karthik Anantha Ram --- .../msm/camera/cam_req_mgr/cam_req_mgr_core.c | 48 +++++++++++++++---- .../msm/camera/cam_req_mgr/cam_req_mgr_core.h | 22 +++++---- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index ff18fa741ade..4602d6c135a5 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c @@ -162,6 +162,34 @@ static void __cam_req_mgr_dec_idx(int32_t *val, int32_t step, int32_t max_val) *val = max_val + (*val); } +/** + * __cam_req_mgr_validate_inject_delay() + * + * @brief : Check if any pd device is introducing inject delay + * @tbl : cam_req_mgr_req_tbl + * @curr_idx : slot idx + * + * @return : 0 for success, negative for failure + */ +static int __cam_req_mgr_validate_inject_delay( + struct cam_req_mgr_req_tbl *tbl, + int32_t curr_idx) +{ + struct cam_req_mgr_tbl_slot *slot = NULL; + + while (tbl) { + slot = &tbl->slot[curr_idx]; + if (slot->inject_delay > 0) { + slot->inject_delay--; + return -EAGAIN; + } + __cam_req_mgr_dec_idx(&curr_idx, tbl->pd_delta, + tbl->num_slots); + tbl = tbl->next; + } + return 0; +} + /** * __cam_req_mgr_traverse() * @@ -201,14 +229,17 @@ static int __cam_req_mgr_traverse(struct cam_req_mgr_traverse *traverse_data) tbl->skip_traverse, traverse_data->in_q->slot[curr_idx].status, traverse_data->in_q->slot[curr_idx].skip_idx); - if ((slot->inject_delay > 0) && - (traverse_data->self_link == true)) { - CAM_DBG(CAM_CRM, "Injecting Delay of one frame"); - apply_data[tbl->pd].req_id = -1; - slot->inject_delay--; - /* This pd table is not ready to proceed with asked idx */ - SET_FAILURE_BIT(traverse_data->result, tbl->pd); - return -EAGAIN; + if ((traverse_data->self_link == true) && + (!traverse_data->inject_delay_chk)) { + rc = __cam_req_mgr_validate_inject_delay(tbl, curr_idx); + if (rc) { + CAM_DBG(CAM_CRM, "Injecting Delay of one frame"); + apply_data[tbl->pd].req_id = -1; + /* This pd tbl not ready to proceed with asked idx */ + SET_FAILURE_BIT(traverse_data->result, tbl->pd); + return -EAGAIN; + } + traverse_data->inject_delay_chk = true; } /* Check if req is ready or in skip mode or pd tbl is in skip mode */ @@ -520,6 +551,7 @@ static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link, traverse_data.result = 0; traverse_data.validate_only = validate_only; traverse_data.self_link = self_link; + traverse_data.inject_delay_chk = false; traverse_data.open_req_cnt = link->open_req_cnt; /* * Traverse through all pd tables, if result is success, diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h index 73ffb81dd953..025c16aacfdf 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h @@ -126,15 +126,16 @@ enum cam_req_mgr_link_state { /** * struct cam_req_mgr_traverse - * @idx : slot index - * @result : contains which all tables were able to apply successfully - * @tbl : pointer of pipeline delay based request table - * @apply_data : pointer which various tables will update during traverse - * @in_q : input request queue pointer - * @validate_only : Whether to validate only and/or update settings - * @self_link : To indicate whether the check is for the given link or the - * other sync link - * @open_req_cnt : Count of open requests yet to be serviced in the kernel. + * @idx : slot index + * @result : contains which all tables were able to apply successfully + * @tbl : pointer of pipeline delay based request table + * @apply_data : pointer which various tables will update during traverse + * @in_q : input request queue pointer + * @validate_only : Whether to validate only and/or update settings + * @self_link : To indicate whether the check is for the given link or + * the other sync link + * @inject_delay_chk : if inject delay has been validated for all pd devices + * @open_req_cnt : Count of open requests yet to be serviced in the kernel. */ struct cam_req_mgr_traverse { int32_t idx; @@ -144,7 +145,8 @@ struct cam_req_mgr_traverse { struct cam_req_mgr_req_queue *in_q; bool validate_only; bool self_link; - int32_t open_req_cnt; + bool inject_delay_chk; + int32_t open_req_cnt; }; /** -- GitLab From 8f6e1ddfa1266b7f8efad3d24406874dc4187081 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Thu, 17 May 2018 12:19:39 -0700 Subject: [PATCH 280/855] Revert "msm: camera: isp: Add support for BUS driver version 175" This reverts commit 7ef5d1244631b75727ae8fdde40cb6160b900b5d. The change being reverted was made to add support for new DISP ports on newer targets. These ports are not present on sdm845 and older targets. Therefore that change is not needed on 4.9 branch. Change-Id: I766feded6e4d30227a0bad572d5133899d3abc55 Signed-off-by: Vishalsingh Hajeri --- .../bindings/media/video/msm-cam-vfe.txt | 2 +- .../msm/camera/cam_isp/cam_isp_context.h | 4 +- .../cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile | 2 +- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 2 +- .../isp_hw/vfe_hw/{vfe17x => vfe170}/Makefile | 2 +- .../cam_vfe17x.c => vfe170/cam_vfe170.c} | 31 +- .../vfe_hw/{vfe17x => vfe170}/cam_vfe170.h | 0 .../{vfe17x => vfe170}/cam_vfe_lite170.c | 0 .../{vfe17x => vfe170}/cam_vfe_lite170.h | 0 .../isp_hw/vfe_hw/vfe17x/cam_vfe175.h | 962 ------------------ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 60 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h | 7 +- include/uapi/media/cam_isp_ife.h | 6 +- 13 files changed, 28 insertions(+), 1050 deletions(-) rename drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/{vfe17x => vfe170}/Makefile (94%) rename drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/{vfe17x/cam_vfe17x.c => vfe170/cam_vfe170.c} (54%) rename drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/{vfe17x => vfe170}/cam_vfe170.h (100%) rename drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/{vfe17x => vfe170}/cam_vfe_lite170.c (100%) rename drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/{vfe17x => vfe170}/cam_vfe_lite170.h (100%) delete mode 100644 drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt index 47620bf0cb39..99f2c7a0be35 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt @@ -17,7 +17,7 @@ Required properties: Usage: required Value type: Definition: Should specify the compatibility string for matching the - driver. e.g. "qcom,vfe175", "qcom,vfe170", "qcom,vfe-lite175", "qcom,vfe-lite170". + driver. e.g. "qcom,vfe170", "qcom,vfe-lite170". - cell-index Usage: required diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h index 79d94807bed5..a939f2d80b34 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h @@ -23,9 +23,9 @@ /* * Maximum hw resource - This number is based on the maximum * output port resource. The current maximum resource number - * is 24. + * is 20. */ -#define CAM_ISP_CTX_RES_MAX 24 +#define CAM_ISP_CTX_RES_MAX 20 /* * Maximum configuration entry size - This is based on the diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile index 1fbb236b4b9f..5a67efab713e 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile @@ -12,4 +12,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_h obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_soc.o cam_vfe_dev.o cam_vfe_core.o -obj-$(CONFIG_SPECTRA_CAMERA) += vfe_bus/ vfe_top/ vfe17x/ \ No newline at end of file +obj-$(CONFIG_SPECTRA_CAMERA) += vfe_bus/ vfe_top/ vfe170/ \ No newline at end of file diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index d25dec8850e2..fd38a964faf6 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -38,7 +38,7 @@ static uint32_t camif_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { static uint32_t camif_irq_err_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { 0x0003FC00, - 0xEFFF7EBC, + 0x0FFF7EBC, }; static uint32_t rdi_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile similarity index 94% rename from drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile rename to drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile index db41e4d89e47..39a56036d3b6 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile @@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_h ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw -obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe17x.o cam_vfe_lite170.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe170.o cam_vfe_lite170.o diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c similarity index 54% rename from drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c rename to drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c index 6f0fe47d448a..0af32ad5d546 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,45 +12,40 @@ #include #include "cam_vfe170.h" -#include "cam_vfe175.h" #include "cam_vfe_hw_intf.h" #include "cam_vfe_core.h" #include "cam_vfe_dev.h" -static const struct of_device_id cam_vfe_dt_match[] = { +static const struct of_device_id cam_vfe170_dt_match[] = { { .compatible = "qcom,vfe170", .data = &cam_vfe170_hw_info, }, - { - .compatible = "qcom,vfe175", - .data = &cam_vfe175_hw_info, - }, {} }; -MODULE_DEVICE_TABLE(of, cam_vfe_dt_match); +MODULE_DEVICE_TABLE(of, cam_vfe170_dt_match); -static struct platform_driver cam_vfe_driver = { +static struct platform_driver cam_vfe170_driver = { .probe = cam_vfe_probe, .remove = cam_vfe_remove, .driver = { - .name = "cam_vfe", + .name = "cam_vfe170", .owner = THIS_MODULE, - .of_match_table = cam_vfe_dt_match, + .of_match_table = cam_vfe170_dt_match, }, }; -static int __init cam_vfe_init_module(void) +static int __init cam_vfe170_init_module(void) { - return platform_driver_register(&cam_vfe_driver); + return platform_driver_register(&cam_vfe170_driver); } -static void __exit cam_vfe_exit_module(void) +static void __exit cam_vfe170_exit_module(void) { - platform_driver_unregister(&cam_vfe_driver); + platform_driver_unregister(&cam_vfe170_driver); } -module_init(cam_vfe_init_module); -module_exit(cam_vfe_exit_module); -MODULE_DESCRIPTION("CAM VFE17X driver"); +module_init(cam_vfe170_init_module); +module_exit(cam_vfe170_exit_module); +MODULE_DESCRIPTION("CAM VFE170 driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h similarity index 100% rename from drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h rename to drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite170.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c similarity index 100% rename from drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite170.c rename to drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite170.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h similarity index 100% rename from drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite170.h rename to drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h deleted file mode 100644 index a72a9774863b..000000000000 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h +++ /dev/null @@ -1,962 +0,0 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _CAM_VFE175_H_ -#define _CAM_VFE175_H_ - -#include "cam_vfe_camif_ver2.h" -#include "cam_vfe_bus_ver2.h" -#include "cam_irq_controller.h" -#include "cam_vfe_top_ver2.h" -#include "cam_vfe_core.h" - -static struct cam_irq_register_set vfe175_top_irq_reg_set[2] = { - { - .mask_reg_offset = 0x0000005C, - .clear_reg_offset = 0x00000064, - .status_reg_offset = 0x0000006C, - }, - { - .mask_reg_offset = 0x00000060, - .clear_reg_offset = 0x00000068, - .status_reg_offset = 0x00000070, - }, -}; - -static struct cam_irq_controller_reg_info vfe175_top_irq_reg_info = { - .num_registers = 2, - .irq_reg_set = vfe175_top_irq_reg_set, - .global_clear_offset = 0x00000058, - .global_clear_bitmask = 0x00000001, -}; - -static struct cam_vfe_camif_ver2_reg vfe175_camif_reg = { - .camif_cmd = 0x00000478, - .camif_config = 0x0000047C, - .line_skip_pattern = 0x00000488, - .pixel_skip_pattern = 0x0000048C, - .skip_period = 0x00000490, - .irq_subsample_pattern = 0x0000049C, - .epoch_irq = 0x000004A0, - .raw_crop_width_cfg = 0x00000CE4, - .raw_crop_height_cfg = 0x00000CE8, - .reg_update_cmd = 0x000004AC, -}; - -static struct cam_vfe_camif_reg_data vfe_175_camif_reg_data = { - .raw_crop_first_pixel_shift = 16, - .raw_crop_first_pixel_mask = 0xFFFF, - .raw_crop_last_pixel_shift = 0x0, - .raw_crop_last_pixel_mask = 0x3FFF, - .raw_crop_first_line_shift = 16, - .raw_crop_first_line_mask = 0xFFFF, - .raw_crop_last_line_shift = 0, - .raw_crop_last_line_mask = 0x3FFF, - .input_mux_sel_shift = 5, - .input_mux_sel_mask = 0x3, - .extern_reg_update_shift = 4, - .extern_reg_update_mask = 1, - .pixel_pattern_shift = 0, - .pixel_pattern_mask = 0x7, - .dsp_mode_shift = 23, - .dsp_mode_mask = 0x1, - .dsp_en_shift = 3, - .dsp_en_mask = 0x1, - .reg_update_cmd_data = 0x1, - .epoch_line_cfg = 0x00140014, - .sof_irq_mask = 0x00000001, - .epoch0_irq_mask = 0x00000004, - .reg_update_irq_mask = 0x00000010, - .eof_irq_mask = 0x00000002, - .error_irq_mask0 = 0x0003FC00, - .error_irq_mask1 = 0xEFFF7E80, -}; - -static struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_175_reg = { - .reset = 0x0000001C, - .cgc_ovd = 0x0000002C, - .enable = 0x00000040, -}; - -static struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_175_reg = { - .reset = 0x00000020, - .cgc_ovd = 0x00000030, - .enable = 0x00000044, -}; - -static struct cam_vfe_top_ver2_reg_offset_module_ctrl color_175_reg = { - .reset = 0x00000024, - .cgc_ovd = 0x00000034, - .enable = 0x00000048, -}; - -static struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_175_reg = { - .reset = 0x00000028, - .cgc_ovd = 0x00000038, - .enable = 0x0000004C, -}; - -static struct cam_vfe_top_ver2_reg_offset_common vfe175_top_common_reg = { - .hw_version = 0x00000000, - .hw_capability = 0x00000004, - .lens_feature = 0x00000008, - .stats_feature = 0x0000000C, - .color_feature = 0x00000010, - .zoom_feature = 0x00000014, - .global_reset_cmd = 0x00000018, - .module_ctrl = { - &lens_175_reg, - &stats_175_reg, - &color_175_reg, - &zoom_175_reg, - }, - .bus_cgc_ovd = 0x0000003C, - .core_cfg = 0x00000050, - .three_D_cfg = 0x00000054, - .violation_status = 0x0000007C, - .reg_update_cmd = 0x000004AC, -}; - -static struct cam_vfe_rdi_ver2_reg vfe175_rdi_reg = { - .reg_update_cmd = 0x000004AC, -}; - -static struct cam_vfe_rdi_reg_data vfe_175_rdi_0_data = { - .reg_update_cmd_data = 0x2, - .sof_irq_mask = 0x8000000, - .reg_update_irq_mask = 0x20, -}; - -static struct cam_vfe_rdi_reg_data vfe_175_rdi_1_data = { - .reg_update_cmd_data = 0x4, - .sof_irq_mask = 0x10000000, - .reg_update_irq_mask = 0x40, -}; - -static struct cam_vfe_rdi_reg_data vfe_175_rdi_2_data = { - .reg_update_cmd_data = 0x8, - .sof_irq_mask = 0x20000000, - .reg_update_irq_mask = 0x80, -}; - -static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = { - .common_reg = &vfe175_top_common_reg, - .camif_hw_info = { - .common_reg = &vfe175_top_common_reg, - .camif_reg = &vfe175_camif_reg, - .reg_data = &vfe_175_camif_reg_data, - }, - .rdi_hw_info = { - .common_reg = &vfe175_top_common_reg, - .rdi_reg = &vfe175_rdi_reg, - .reg_data = { - &vfe_175_rdi_0_data, - &vfe_175_rdi_1_data, - &vfe_175_rdi_2_data, - NULL, - }, - }, - .mux_type = { - CAM_VFE_CAMIF_VER_2_0, - CAM_VFE_RDI_VER_1_0, - CAM_VFE_RDI_VER_1_0, - CAM_VFE_RDI_VER_1_0, - }, -}; - -static struct cam_irq_register_set vfe175_bus_irq_reg[3] = { - { - .mask_reg_offset = 0x00002044, - .clear_reg_offset = 0x00002050, - .status_reg_offset = 0x0000205C, - }, - { - .mask_reg_offset = 0x00002048, - .clear_reg_offset = 0x00002054, - .status_reg_offset = 0x00002060, - }, - { - .mask_reg_offset = 0x0000204C, - .clear_reg_offset = 0x00002058, - .status_reg_offset = 0x00002064, - }, -}; - -static struct cam_vfe_bus_ver2_reg_offset_ubwc_client - vfe175_ubwc_regs_client_3 = { - .tile_cfg = 0x0000252C, - .h_init = 0x00002530, - .v_init = 0x00002534, - .meta_addr = 0x00002538, - .meta_offset = 0x0000253C, - .meta_stride = 0x00002540, - .mode_cfg = 0x00002544, - .bw_limit = 0x000025A0, -}; - -static struct cam_vfe_bus_ver2_reg_offset_ubwc_client - vfe175_ubwc_regs_client_4 = { - .tile_cfg = 0x0000262C, - .h_init = 0x00002630, - .v_init = 0x00002634, - .meta_addr = 0x00002638, - .meta_offset = 0x0000263C, - .meta_stride = 0x00002640, - .mode_cfg = 0x00002644, - .bw_limit = 0x000026A0, -}; - -static struct cam_vfe_bus_ver2_reg_offset_ubwc_client - vfe175_ubwc_regs_client_20 = { - .tile_cfg = 0x0000362C, - .h_init = 0x00003630, - .v_init = 0x00003634, - .meta_addr = 0x00003638, - .meta_offset = 0x0000363C, - .meta_stride = 0x00003640, - .mode_cfg = 0x00003644, - .bw_limit = 0x000036A0, -}; - -static struct cam_vfe_bus_ver2_reg_offset_ubwc_client - vfe175_ubwc_regs_client_21 = { - .tile_cfg = 0x0000372C, - .h_init = 0x00003730, - .v_init = 0x00003734, - .meta_addr = 0x00003738, - .meta_offset = 0x0000373C, - .meta_stride = 0x00003740, - .mode_cfg = 0x00003744, - .bw_limit = 0x000037A0, -}; - -static struct cam_vfe_bus_ver2_hw_info vfe175_bus_hw_info = { - .common_reg = { - .hw_version = 0x00002000, - .hw_capability = 0x00002004, - .sw_reset = 0x00002008, - .cgc_ovd = 0x0000200C, - .pwr_iso_cfg = 0x000020CC, - .dual_master_comp_cfg = 0x00002028, - .irq_reg_info = { - .num_registers = 3, - .irq_reg_set = vfe175_bus_irq_reg, - .global_clear_offset = 0x00002068, - .global_clear_bitmask = 0x00000001, - }, - .comp_error_status = 0x0000206C, - .comp_ovrwr_status = 0x00002070, - .dual_comp_error_status = 0x00002074, - .dual_comp_ovrwr_status = 0x00002078, - .addr_sync_cfg = 0x0000207C, - .addr_sync_frame_hdr = 0x00002080, - .addr_sync_no_sync = 0x00002084, - }, - .num_client = 24, - .bus_client_reg = { - /* BUS Client 0 */ - { - .status0 = 0x00002200, - .status1 = 0x00002204, - .cfg = 0x00002208, - .header_addr = 0x0000220C, - .header_cfg = 0x00002210, - .image_addr = 0x00002214, - .image_addr_offset = 0x00002218, - .buffer_width_cfg = 0x0000221C, - .buffer_height_cfg = 0x00002220, - .packer_cfg = 0x00002224, - .stride = 0x00002228, - .irq_subsample_period = 0x00002248, - .irq_subsample_pattern = 0x0000224C, - .framedrop_period = 0x00002250, - .framedrop_pattern = 0x00002254, - .frame_inc = 0x00002258, - .burst_limit = 0x0000225C, - .ubwc_regs = NULL, - }, - /* BUS Client 1 */ - { - .status0 = 0x00002300, - .status1 = 0x00002304, - .cfg = 0x00002308, - .header_addr = 0x0000230C, - .header_cfg = 0x00002310, - .image_addr = 0x00002314, - .image_addr_offset = 0x00002318, - .buffer_width_cfg = 0x0000231C, - .buffer_height_cfg = 0x00002320, - .packer_cfg = 0x00002324, - .stride = 0x00002328, - .irq_subsample_period = 0x00002348, - .irq_subsample_pattern = 0x0000234C, - .framedrop_period = 0x00002350, - .framedrop_pattern = 0x00002354, - .frame_inc = 0x00002358, - .burst_limit = 0x0000235C, - .ubwc_regs = NULL, - }, - /* BUS Client 2 */ - { - .status0 = 0x00002400, - .status1 = 0x00002404, - .cfg = 0x00002408, - .header_addr = 0x0000240C, - .header_cfg = 0x00002410, - .image_addr = 0x00002414, - .image_addr_offset = 0x00002418, - .buffer_width_cfg = 0x0000241C, - .buffer_height_cfg = 0x00002420, - .packer_cfg = 0x00002424, - .stride = 0x00002428, - .irq_subsample_period = 0x00002448, - .irq_subsample_pattern = 0x0000244C, - .framedrop_period = 0x00002450, - .framedrop_pattern = 0x00002454, - .frame_inc = 0x00002458, - .burst_limit = 0x0000245C, - .ubwc_regs = NULL, - }, - /* BUS Client 3 */ - { - .status0 = 0x00002500, - .status1 = 0x00002504, - .cfg = 0x00002508, - .header_addr = 0x0000250C, - .header_cfg = 0x00002510, - .image_addr = 0x00002514, - .image_addr_offset = 0x00002518, - .buffer_width_cfg = 0x0000251C, - .buffer_height_cfg = 0x00002520, - .packer_cfg = 0x00002524, - .stride = 0x00002528, - .irq_subsample_period = 0x00002548, - .irq_subsample_pattern = 0x0000254C, - .framedrop_period = 0x00002550, - .framedrop_pattern = 0x00002554, - .frame_inc = 0x00002558, - .burst_limit = 0x0000255C, - .ubwc_regs = &vfe175_ubwc_regs_client_3, - }, - /* BUS Client 4 */ - { - .status0 = 0x00002600, - .status1 = 0x00002604, - .cfg = 0x00002608, - .header_addr = 0x0000260C, - .header_cfg = 0x00002610, - .image_addr = 0x00002614, - .image_addr_offset = 0x00002618, - .buffer_width_cfg = 0x0000261C, - .buffer_height_cfg = 0x00002620, - .packer_cfg = 0x00002624, - .stride = 0x00002628, - .irq_subsample_period = 0x00002648, - .irq_subsample_pattern = 0x0000264C, - .framedrop_period = 0x00002650, - .framedrop_pattern = 0x00002654, - .frame_inc = 0x00002658, - .burst_limit = 0x0000265C, - .ubwc_regs = &vfe175_ubwc_regs_client_4, - }, - /* BUS Client 5 */ - { - .status0 = 0x00002700, - .status1 = 0x00002704, - .cfg = 0x00002708, - .header_addr = 0x0000270C, - .header_cfg = 0x00002710, - .image_addr = 0x00002714, - .image_addr_offset = 0x00002718, - .buffer_width_cfg = 0x0000271C, - .buffer_height_cfg = 0x00002720, - .packer_cfg = 0x00002724, - .stride = 0x00002728, - .irq_subsample_period = 0x00002748, - .irq_subsample_pattern = 0x0000274C, - .framedrop_period = 0x00002750, - .framedrop_pattern = 0x00002754, - .frame_inc = 0x00002758, - .burst_limit = 0x0000275C, - .ubwc_regs = NULL, - }, - /* BUS Client 6 */ - { - .status0 = 0x00002800, - .status1 = 0x00002804, - .cfg = 0x00002808, - .header_addr = 0x0000280C, - .header_cfg = 0x00002810, - .image_addr = 0x00002814, - .image_addr_offset = 0x00002818, - .buffer_width_cfg = 0x0000281C, - .buffer_height_cfg = 0x00002820, - .packer_cfg = 0x00002824, - .stride = 0x00002828, - .irq_subsample_period = 0x00002848, - .irq_subsample_pattern = 0x0000284C, - .framedrop_period = 0x00002850, - .framedrop_pattern = 0x00002854, - .frame_inc = 0x00002858, - .burst_limit = 0x0000285C, - .ubwc_regs = NULL, - }, - /* BUS Client 7 */ - { - .status0 = 0x00002900, - .status1 = 0x00002904, - .cfg = 0x00002908, - .header_addr = 0x0000290C, - .header_cfg = 0x00002910, - .image_addr = 0x00002914, - .image_addr_offset = 0x00002918, - .buffer_width_cfg = 0x0000291C, - .buffer_height_cfg = 0x00002920, - .packer_cfg = 0x00002924, - .stride = 0x00002928, - .irq_subsample_period = 0x00002948, - .irq_subsample_pattern = 0x0000294C, - .framedrop_period = 0x00002950, - .framedrop_pattern = 0x00002954, - .frame_inc = 0x00002958, - .burst_limit = 0x0000295C, - .ubwc_regs = NULL, - }, - /* BUS Client 8 */ - { - .status0 = 0x00002A00, - .status1 = 0x00002A04, - .cfg = 0x00002A08, - .header_addr = 0x00002A0C, - .header_cfg = 0x00002A10, - .image_addr = 0x00002A14, - .image_addr_offset = 0x00002A18, - .buffer_width_cfg = 0x00002A1C, - .buffer_height_cfg = 0x00002A20, - .packer_cfg = 0x00002A24, - .stride = 0x00002A28, - .irq_subsample_period = 0x00002A48, - .irq_subsample_pattern = 0x00002A4C, - .framedrop_period = 0x00002A50, - .framedrop_pattern = 0x00002A54, - .frame_inc = 0x00002A58, - .burst_limit = 0x00002A5C, - .ubwc_regs = NULL, - }, - /* BUS Client 9 */ - { - .status0 = 0x00002B00, - .status1 = 0x00002B04, - .cfg = 0x00002B08, - .header_addr = 0x00002B0C, - .header_cfg = 0x00002B10, - .image_addr = 0x00002B14, - .image_addr_offset = 0x00002B18, - .buffer_width_cfg = 0x00002B1C, - .buffer_height_cfg = 0x00002B20, - .packer_cfg = 0x00002B24, - .stride = 0x00002B28, - .irq_subsample_period = 0x00002B48, - .irq_subsample_pattern = 0x00002B4C, - .framedrop_period = 0x00002B50, - .framedrop_pattern = 0x00002B54, - .frame_inc = 0x00002B58, - .burst_limit = 0x00002B5C, - .ubwc_regs = NULL, - }, - /* BUS Client 10 */ - { - .status0 = 0x00002C00, - .status1 = 0x00002C04, - .cfg = 0x00002C08, - .header_addr = 0x00002C0C, - .header_cfg = 0x00002C10, - .image_addr = 0x00002C14, - .image_addr_offset = 0x00002C18, - .buffer_width_cfg = 0x00002C1C, - .buffer_height_cfg = 0x00002C20, - .packer_cfg = 0x00002C24, - .stride = 0x00002C28, - .irq_subsample_period = 0x00002C48, - .irq_subsample_pattern = 0x00002C4C, - .framedrop_period = 0x00002C50, - .framedrop_pattern = 0x00002C54, - .frame_inc = 0x00002C58, - .burst_limit = 0x00002C5C, - .ubwc_regs = NULL, - }, - /* BUS Client 11 */ - { - .status0 = 0x00002D00, - .status1 = 0x00002D04, - .cfg = 0x00002D08, - .header_addr = 0x00002D0C, - .header_cfg = 0x00002D10, - .image_addr = 0x00002D14, - .image_addr_offset = 0x00002D18, - .buffer_width_cfg = 0x00002D1C, - .buffer_height_cfg = 0x00002D20, - .packer_cfg = 0x00002D24, - .stride = 0x00002D28, - .irq_subsample_period = 0x00002D48, - .irq_subsample_pattern = 0x00002D4C, - .framedrop_period = 0x00002D50, - .framedrop_pattern = 0x00002D54, - .frame_inc = 0x00002D58, - .burst_limit = 0x00002D5C, - .ubwc_regs = NULL, - }, - /* BUS Client 12 */ - { - .status0 = 0x00002E00, - .status1 = 0x00002E04, - .cfg = 0x00002E08, - .header_addr = 0x00002E0C, - .header_cfg = 0x00002E10, - .image_addr = 0x00002E14, - .image_addr_offset = 0x00002E18, - .buffer_width_cfg = 0x00002E1C, - .buffer_height_cfg = 0x00002E20, - .packer_cfg = 0x00002E24, - .stride = 0x00002E28, - .irq_subsample_period = 0x00002E48, - .irq_subsample_pattern = 0x00002E4C, - .framedrop_period = 0x00002E50, - .framedrop_pattern = 0x00002E54, - .frame_inc = 0x00002E58, - .burst_limit = 0x00002E5C, - .ubwc_regs = NULL, - }, - /* BUS Client 13 */ - { - .status0 = 0x00002F00, - .status1 = 0x00002F04, - .cfg = 0x00002F08, - .header_addr = 0x00002F0C, - .header_cfg = 0x00002F10, - .image_addr = 0x00002F14, - .image_addr_offset = 0x00002F18, - .buffer_width_cfg = 0x00002F1C, - .buffer_height_cfg = 0x00002F20, - .packer_cfg = 0x00002F24, - .stride = 0x00002F28, - .irq_subsample_period = 0x00002F48, - .irq_subsample_pattern = 0x00002F4C, - .framedrop_period = 0x00002F50, - .framedrop_pattern = 0x00002F54, - .frame_inc = 0x00002F58, - .burst_limit = 0x00002F5C, - .ubwc_regs = NULL, - }, - /* BUS Client 14 */ - { - .status0 = 0x00003000, - .status1 = 0x00003004, - .cfg = 0x00003008, - .header_addr = 0x0000300C, - .header_cfg = 0x00003010, - .image_addr = 0x00003014, - .image_addr_offset = 0x00003018, - .buffer_width_cfg = 0x0000301C, - .buffer_height_cfg = 0x00003020, - .packer_cfg = 0x00003024, - .stride = 0x00003028, - .irq_subsample_period = 0x00003048, - .irq_subsample_pattern = 0x0000304C, - .framedrop_period = 0x00003050, - .framedrop_pattern = 0x00003054, - .frame_inc = 0x00003058, - .burst_limit = 0x0000305C, - .ubwc_regs = NULL, - }, - /* BUS Client 15 */ - { - .status0 = 0x00003100, - .status1 = 0x00003104, - .cfg = 0x00003108, - .header_addr = 0x0000310C, - .header_cfg = 0x00003110, - .image_addr = 0x00003114, - .image_addr_offset = 0x00003118, - .buffer_width_cfg = 0x0000311C, - .buffer_height_cfg = 0x00003120, - .packer_cfg = 0x00003124, - .stride = 0x00003128, - .irq_subsample_period = 0x00003148, - .irq_subsample_pattern = 0x0000314C, - .framedrop_period = 0x00003150, - .framedrop_pattern = 0x00003154, - .frame_inc = 0x00003158, - .burst_limit = 0x0000315C, - .ubwc_regs = NULL, - }, - /* BUS Client 16 */ - { - .status0 = 0x00003200, - .status1 = 0x00003204, - .cfg = 0x00003208, - .header_addr = 0x0000320C, - .header_cfg = 0x00003210, - .image_addr = 0x00003214, - .image_addr_offset = 0x00003218, - .buffer_width_cfg = 0x0000321C, - .buffer_height_cfg = 0x00003220, - .packer_cfg = 0x00003224, - .stride = 0x00003228, - .irq_subsample_period = 0x00003248, - .irq_subsample_pattern = 0x0000324C, - .framedrop_period = 0x00003250, - .framedrop_pattern = 0x00003254, - .frame_inc = 0x00003258, - .burst_limit = 0x0000325C, - .ubwc_regs = NULL, - }, - /* BUS Client 17 */ - { - .status0 = 0x00003300, - .status1 = 0x00003304, - .cfg = 0x00003308, - .header_addr = 0x0000330C, - .header_cfg = 0x00003310, - .image_addr = 0x00003314, - .image_addr_offset = 0x00003318, - .buffer_width_cfg = 0x0000331C, - .buffer_height_cfg = 0x00003320, - .packer_cfg = 0x00003324, - .stride = 0x00003328, - .irq_subsample_period = 0x00003348, - .irq_subsample_pattern = 0x0000334C, - .framedrop_period = 0x00003350, - .framedrop_pattern = 0x00003354, - .frame_inc = 0x00003358, - .burst_limit = 0x0000335C, - .ubwc_regs = NULL, - }, - /* BUS Client 18 */ - { - .status0 = 0x00003400, - .status1 = 0x00003404, - .cfg = 0x00003408, - .header_addr = 0x0000340C, - .header_cfg = 0x00003410, - .image_addr = 0x00003414, - .image_addr_offset = 0x00003418, - .buffer_width_cfg = 0x0000341C, - .buffer_height_cfg = 0x00003420, - .packer_cfg = 0x00003424, - .stride = 0x00003428, - .irq_subsample_period = 0x00003448, - .irq_subsample_pattern = 0x0000344C, - .framedrop_period = 0x00003450, - .framedrop_pattern = 0x00003454, - .frame_inc = 0x00003458, - .burst_limit = 0x0000345C, - .ubwc_regs = NULL, - }, - /* BUS Client 19 */ - { - .status0 = 0x00003500, - .status1 = 0x00003504, - .cfg = 0x00003508, - .header_addr = 0x0000350C, - .header_cfg = 0x00003510, - .image_addr = 0x00003514, - .image_addr_offset = 0x00003518, - .buffer_width_cfg = 0x0000351C, - .buffer_height_cfg = 0x00003520, - .packer_cfg = 0x00003524, - .stride = 0x00003528, - .irq_subsample_period = 0x00003548, - .irq_subsample_pattern = 0x0000354C, - .framedrop_period = 0x00003550, - .framedrop_pattern = 0x00003554, - .frame_inc = 0x00003558, - .burst_limit = 0x0000355C, - .ubwc_regs = NULL, - }, - /* BUS Client 20 */ - { - .status0 = 0x00003600, - .status1 = 0x00003604, - .cfg = 0x00003608, - .header_addr = 0x0000360C, - .header_cfg = 0x00003610, - .image_addr = 0x00003614, - .image_addr_offset = 0x00003618, - .buffer_width_cfg = 0x0000361C, - .buffer_height_cfg = 0x00003620, - .packer_cfg = 0x00003624, - .stride = 0x00003628, - .irq_subsample_period = 0x00003648, - .irq_subsample_pattern = 0x0000364C, - .framedrop_period = 0x00003650, - .framedrop_pattern = 0x00003654, - .frame_inc = 0x00003658, - .burst_limit = 0x0000365C, - .ubwc_regs = &vfe175_ubwc_regs_client_20, - }, - /* BUS Client 21 */ - { - .status0 = 0x00003700, - .status1 = 0x00003704, - .cfg = 0x00003708, - .header_addr = 0x0000370C, - .header_cfg = 0x00003710, - .image_addr = 0x00003714, - .image_addr_offset = 0x00003718, - .buffer_width_cfg = 0x0000371C, - .buffer_height_cfg = 0x00003720, - .packer_cfg = 0x00003724, - .stride = 0x00003728, - .irq_subsample_period = 0x00003748, - .irq_subsample_pattern = 0x0000374C, - .framedrop_period = 0x00003750, - .framedrop_pattern = 0x00003754, - .frame_inc = 0x00003758, - .burst_limit = 0x0000375C, - .ubwc_regs = &vfe175_ubwc_regs_client_21, - }, - /* BUS Client 22 */ - { - .status0 = 0x00003800, - .status1 = 0x00003804, - .cfg = 0x00003808, - .header_addr = 0x0000380C, - .header_cfg = 0x00003810, - .image_addr = 0x00003814, - .image_addr_offset = 0x00003818, - .buffer_width_cfg = 0x0000381C, - .buffer_height_cfg = 0x00003820, - .packer_cfg = 0x00003824, - .stride = 0x00003828, - .irq_subsample_period = 0x00003848, - .irq_subsample_pattern = 0x0000384C, - .framedrop_period = 0x00003850, - .framedrop_pattern = 0x00003854, - .frame_inc = 0x00003858, - .burst_limit = 0x0000385C, - .ubwc_regs = NULL, - }, - /* BUS Client 23 */ - { - .status0 = 0x00003900, - .status1 = 0x00003904, - .cfg = 0x00003908, - .header_addr = 0x0000390C, - .header_cfg = 0x00003910, - .image_addr = 0x00003914, - .image_addr_offset = 0x00003918, - .buffer_width_cfg = 0x0000391C, - .buffer_height_cfg = 0x00003920, - .packer_cfg = 0x00003924, - .stride = 0x00003928, - .irq_subsample_period = 0x00003948, - .irq_subsample_pattern = 0x0000394C, - .framedrop_period = 0x00003950, - .framedrop_pattern = 0x00003954, - .frame_inc = 0x00003958, - .burst_limit = 0x0000395C, - .ubwc_regs = NULL, - }, - }, - .comp_grp_reg = { - /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ - { - .comp_mask = 0x00002010, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ - { - .comp_mask = 0x00002014, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ - { - .comp_mask = 0x00002018, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ - { - .comp_mask = 0x0000201C, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ - { - .comp_mask = 0x00002020, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ - { - .comp_mask = 0x00002024, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ - { - .comp_mask = 0x0000202C, - .addr_sync_mask = 0x00002088, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ - { - .comp_mask = 0x00002030, - .addr_sync_mask = 0x0000208C, - - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ - { - .comp_mask = 0x00002034, - .addr_sync_mask = 0x00002090, - - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ - { - .comp_mask = 0x00002038, - .addr_sync_mask = 0x00002094, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ - { - .comp_mask = 0x0000203C, - .addr_sync_mask = 0x00002098, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ - { - .comp_mask = 0x00002040, - .addr_sync_mask = 0x0000209C, - }, - }, - .num_out = 21, - .vfe_out_hw_info = { - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL, - .max_width = 4096, - .max_height = 4096, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4, - .max_width = 1920, - .max_height = 1080, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16, - .max_width = 1920, - .max_height = 1080, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FD, - .max_width = 1920, - .max_height = 1080, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_PDAF, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = - CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = - CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, - .max_width = 1920, - .max_height = 1080, - }, - { - .vfe_out_type = - CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = - CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = - CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = - CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = - CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = - CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = - CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, - .max_width = 4096, - .max_height = 4096, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, - .max_width = 1920, - .max_height = 1080, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, - .max_width = 1920, - .max_height = 1080, - }, - }, -}; - -static struct cam_vfe_hw_info cam_vfe175_hw_info = { - .irq_reg_info = &vfe175_top_irq_reg_info, - - .bus_version = CAM_VFE_BUS_VER_2_0, - .bus_hw_info = &vfe175_bus_hw_info, - - .top_version = CAM_VFE_TOP_VER_2_0, - .top_hw_info = &vfe175_top_hw_info, - - .camif_version = CAM_VFE_CAMIF_VER_2_0, - .camif_reg = &vfe175_camif_reg, - -}; - -#endif /* _CAM_VFE175_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 12e9125d8fa4..3c37b83a2256 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -40,8 +40,7 @@ static const char drv_name[] = "vfe_bus"; #define CAM_VFE_RDI_BUS_DEFAULT_STRIDE 0xFF01 #define CAM_VFE_BUS_INTRA_CLIENT_MASK 0x3 #define CAM_VFE_BUS_ADDR_SYNC_INTRA_CLIENT_SHIFT 8 -#define CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL \ - ((1 << CAM_VFE_BUS_VER2_MAX_CLIENTS) - 1) +#define CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL 0xFFFFF #define ALIGNUP(value, alignment) \ ((value + alignment - 1) / alignment * alignment) @@ -376,9 +375,6 @@ static bool cam_vfe_bus_can_be_secure(uint32_t out_type) case CAM_VFE_BUS_VER2_VFE_OUT_RDI0: case CAM_VFE_BUS_VER2_VFE_OUT_RDI1: case CAM_VFE_BUS_VER2_VFE_OUT_RDI2: - case CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP: - case CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP: - case CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP: return true; case CAM_VFE_BUS_VER2_VFE_OUT_PDAF: @@ -438,12 +434,6 @@ static enum cam_vfe_bus_ver2_vfe_out_type return CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS; case CAM_ISP_IFE_OUT_RES_STATS_IHIST: return CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST; - case CAM_ISP_IFE_OUT_RES_FULL_DISP: - return CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP; - case CAM_ISP_IFE_OUT_RES_DS4_DISP: - return CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP; - case CAM_ISP_IFE_OUT_RES_DS16_DISP: - return CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP; default: return CAM_VFE_BUS_VER2_VFE_OUT_MAX; } @@ -484,7 +474,6 @@ static int cam_vfe_bus_get_num_wm( } break; case CAM_VFE_BUS_VER2_VFE_OUT_FULL: - case CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP: switch (format) { case CAM_FORMAT_NV21: case CAM_FORMAT_NV12: @@ -514,9 +503,7 @@ static int cam_vfe_bus_get_num_wm( } break; case CAM_VFE_BUS_VER2_VFE_OUT_DS4: - case CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP: case CAM_VFE_BUS_VER2_VFE_OUT_DS16: - case CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP: switch (format) { case CAM_FORMAT_PD8: case CAM_FORMAT_PD10: @@ -765,37 +752,6 @@ static int cam_vfe_bus_get_wm_idx( break; } break; - case CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP: - switch (plane) { - case PLANE_Y: - wm_idx = 20; - break; - case PLANE_C: - wm_idx = 21; - break; - default: - break; - } - break; - case CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP: - switch (plane) { - case PLANE_Y: - wm_idx = 22; - break; - default: - break; - } - break; - case CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP: - switch (plane) { - case PLANE_Y: - wm_idx = 23; - break; - default: - break; - } - break; - default: break; } @@ -808,7 +764,7 @@ static enum cam_vfe_bus_packer_format { switch (out_fmt) { case CAM_FORMAT_NV21: - if ((wm_index == 4) || (wm_index == 6) || (wm_index == 21)) + if (wm_index == 4 || wm_index == 6) return PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN; case CAM_FORMAT_NV12: case CAM_FORMAT_UBWC_NV12: @@ -939,13 +895,9 @@ static int cam_vfe_bus_acquire_wm( rsrc_data->format); return -EINVAL; } - } else if ((rsrc_data->index < 5) || - (rsrc_data->index == 7) || (rsrc_data->index == 8) || - (rsrc_data->index == 20) || (rsrc_data->index == 21)) { - /* - * Write master 3, 4 - for Full OUT , 7-8 FD OUT, - * WM 20-21 = FULL_DISP - */ + } else if (rsrc_data->index < 5 || + rsrc_data->index == 7 || rsrc_data->index == 8) { + /* Write master 3, 4 - for Full OUT , 7-8 FD OUT */ switch (rsrc_data->format) { case CAM_FORMAT_UBWC_NV12_4R: rsrc_data->en_ubwc = 1; @@ -1025,7 +977,7 @@ static int cam_vfe_bus_acquire_wm( return -EINVAL; } rsrc_data->en_cfg = 0x1; - } else if ((rsrc_data->index >= 11) && (rsrc_data->index < 20)) { + } else if (rsrc_data->index >= 11) { /* Write master 11-19 stats */ rsrc_data->width = 0; rsrc_data->height = 0; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h index c001eef72bc4..5a12f745e328 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -16,7 +16,7 @@ #include "cam_irq_controller.h" #include "cam_vfe_bus.h" -#define CAM_VFE_BUS_VER2_MAX_CLIENTS 24 +#define CAM_VFE_BUS_VER2_MAX_CLIENTS 20 enum cam_vfe_bus_ver2_vfe_core_id { CAM_VFE_BUS_VER2_VFE_CORE_0, @@ -60,9 +60,6 @@ enum cam_vfe_bus_ver2_vfe_out_type { CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, - CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, - CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, - CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, CAM_VFE_BUS_VER2_VFE_OUT_MAX, }; diff --git a/include/uapi/media/cam_isp_ife.h b/include/uapi/media/cam_isp_ife.h index dd03ecca2884..f5e72813fc0d 100644 --- a/include/uapi/media/cam_isp_ife.h +++ b/include/uapi/media/cam_isp_ife.h @@ -23,11 +23,7 @@ #define CAM_ISP_IFE_OUT_RES_STATS_RS (CAM_ISP_IFE_OUT_RES_BASE + 16) #define CAM_ISP_IFE_OUT_RES_STATS_CS (CAM_ISP_IFE_OUT_RES_BASE + 17) #define CAM_ISP_IFE_OUT_RES_STATS_IHIST (CAM_ISP_IFE_OUT_RES_BASE + 18) -#define CAM_ISP_IFE_OUT_RES_FULL_DISP (CAM_ISP_IFE_OUT_RES_BASE + 19) -#define CAM_ISP_IFE_OUT_RES_DS4_DISP (CAM_ISP_IFE_OUT_RES_BASE + 20) -#define CAM_ISP_IFE_OUT_RES_DS16_DISP (CAM_ISP_IFE_OUT_RES_BASE + 21) - -#define CAM_ISP_IFE_OUT_RES_MAX (CAM_ISP_IFE_OUT_RES_BASE + 22) +#define CAM_ISP_IFE_OUT_RES_MAX (CAM_ISP_IFE_OUT_RES_BASE + 19) /* IFE input port resource type (global unique) */ -- GitLab From e14d1a35ebd9ac3c4bbc76021310178213cceb61 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 24 Apr 2018 18:06:56 -0700 Subject: [PATCH 281/855] ANDROID: sdcardfs: Don't d_drop in d_revalidate After d_revalidate returns 0, the vfs will call d_invalidate, which will call d_drop itself, along with other cleanup. Bug: 78262592 Change-Id: Idbb30e008c05d62edf2217679cb6a5517d8d1a2c Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/dentry.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index 166f14b2400b..776d549b397b 100644 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -51,7 +51,6 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) * whether the base obbpath has been changed or not */ if (is_obbpath_invalid(dentry)) { - d_drop(dentry); return 0; } @@ -65,7 +64,6 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) if ((lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) { err = lower_dentry->d_op->d_revalidate(lower_dentry, flags); if (err == 0) { - d_drop(dentry); goto out; } } @@ -73,14 +71,12 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) spin_lock(&lower_dentry->d_lock); if (d_unhashed(lower_dentry)) { spin_unlock(&lower_dentry->d_lock); - d_drop(dentry); err = 0; goto out; } spin_unlock(&lower_dentry->d_lock); if (parent_lower_dentry != lower_cur_parent_dentry) { - d_drop(dentry); err = 0; goto out; } @@ -94,7 +90,6 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) } if (!qstr_case_eq(&dentry->d_name, &lower_dentry->d_name)) { - __d_drop(dentry); err = 0; } @@ -113,7 +108,6 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) if (inode) { data = top_data_get(SDCARDFS_I(inode)); if (!data || data->abandoned) { - d_drop(dentry); err = 0; } if (data) -- GitLab From ee617c500fd7db0629bfcf2440d090f3c4e91d07 Mon Sep 17 00:00:00 2001 From: Rajesh Bharathwaj Date: Mon, 14 May 2018 17:41:21 -0700 Subject: [PATCH 282/855] ARM: dts: msm: Add pinctrl overrides for SDA845 SVR platform Added pinctrl, regulator voltages and drive strength overrides for SDA845 SVR platform. Change-Id: I1e47f5479f3725c981ced896eeb9f7fabd0836e6 Signed-off-by: Rajesh Bharathwaj --- .../dts/qcom/sda845-svr-pinctrl-overlay.dtsi | 156 ++++++++++++++++-- arch/arm64/boot/dts/qcom/sda845-svr.dtsi | 18 ++ .../dts/qcom/sdm845-camera-sensor-svr.dtsi | 36 ++-- 3 files changed, 179 insertions(+), 31 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi b/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi index c76ef2b9a0cf..19d1370df6a3 100644 --- a/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi @@ -10,7 +10,7 @@ * GNU General Public License for more details. */ -&cam_sensor_mclk0_active{ +&cam_sensor_mclk0_active { /* MCLK0 */ mux { pins = "gpio13"; @@ -20,7 +20,7 @@ config { pins = "gpio13"; bias-disable; /* No PULL */ - drive-strength = <8>; /* 2 MA */ + drive-strength = <8>; /* 8 MA */ }; }; @@ -34,19 +34,75 @@ config { pins = "gpio13"; bias-pull-down; /* PULL DOWN */ - drive-strength = <8>; /* 2 MA */ + drive-strength = <8>; /* 8 MA */ + }; +}; + +&cam_sensor_mclk1_active { + /* MCLK1 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-disable; /* No PULL */ + drive-strength = <8>; /* 8 MA */ + }; +}; + +&cam_sensor_mclk1_suspend { + /* MCLK1 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <8>; /* 8 MA */ + }; +}; + +&cam_sensor_mclk2_active { + /* MCLK2 */ + mux { + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-disable; /* No PULL */ + drive-strength = <8>; /* 8 MA */ + }; +}; + +&cam_sensor_mclk2_suspend { + /* MCLK2 */ + mux { + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <8>; /* 8 MA */ }; }; &cam_sensor_rear_active { /* RESET, AVDD LDO */ mux { - pins = "gpio8","gpio79"; + pins = "gpio8", "gpio29"; function = "gpio"; }; config { - pins = "gpio8","gpio79"; + pins = "gpio8", "gpio29"; bias-disable; /* No PULL */ drive-strength = <2>; /* 2 MA */ }; @@ -55,43 +111,115 @@ &cam_sensor_rear_suspend { /* RESET, AVDD LDO */ mux { - pins = "gpio8","gpio79"; + pins = "gpio8", "gpio29"; function = "gpio"; }; config { - pins = "gpio8","gpio79"; + pins = "gpio8", "gpio29"; bias-pull-down; /* PULL DOWN */ drive-strength = <2>; /* 2 MA */ output-low; }; }; -&cam_sensor_front_active{ - /* RESET AVDD_LDO*/ +&cam_sensor_front_active { + /* RESET AVDD_LDO */ mux { - pins = "gpio26", "gpio8"; + pins = "gpio26", "gpio12"; function = "gpio"; }; config { - pins = "gpio26", "gpio8"; + pins = "gpio26", "gpio12"; bias-disable; /* No PULL */ drive-strength = <2>; /* 2 MA */ }; }; -&cam_sensor_front_suspend{ +&cam_sensor_front_suspend { /* RESET */ mux { - pins = "gpio26", "gpio8"; + pins = "gpio26", "gpio12"; function = "gpio"; }; config { - pins = "gpio26", "gpio8"; + pins = "gpio26", "gpio12"; bias-pull-down; /* PULL DOWN */ drive-strength = <2>; /* 2 MA */ output-low; }; }; + +&cam_sensor_iris_active { + /* RESET AVDD_LDO */ + mux { + pins = "gpio21", "gpio122"; + function = "gpio"; + }; + + config { + pins = "gpio21", "gpio122"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +&cam_sensor_iris_suspend { + /* RESET AVDD_LDO */ + mux { + pins = "gpio21", "gpio122"; + function = "gpio"; + }; + + config { + pins = "gpio21", "gpio122"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +&cam_sensor_rear_vana { + /* AVDD_LDO */ + mux { + pins = "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio7"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +&cam_res_mgr_active { + /* AVDD_LDO */ + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +&cam_res_mgr_suspend { + /* AVDD_LDO */ + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-svr.dtsi b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi index ce62781fdf42..6ab754ea2a1d 100644 --- a/arch/arm64/boot/dts/qcom/sda845-svr.dtsi +++ b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi @@ -249,6 +249,24 @@ #cooling-cells = <2>; }; +&pm8998_l10 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; +}; + +&pm8998_l15 { + regulator-min-microvolt = <1504000>; + regulator-max-microvolt = <1504000>; + qcom,init-voltage = <1504000>; +}; + +&pm8998_l16 { + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3312000>; + qcom,init-voltage = <3312000>; +}; + &ufsphy_mem { compatible = "qcom,ufs-phy-qmp-v3"; diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi index d387f93cc115..aa068e542903 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi @@ -220,7 +220,7 @@ &cam_sensor_rear2_suspend>; gpios = <&tlmm 15 0>, <&tlmm 9 0>, - <&tlmm 8 0>; + <&tlmm 7 0>; gpio-reset = <1>; gpio-vana = <2>; gpio-req-tbl-num = <0 1 2>; @@ -261,7 +261,7 @@ &cam_sensor_front_suspend>; gpios = <&tlmm 14 0>, <&tlmm 28 0>, - <&tlmm 8 0>; + <&tlmm 7 0>; gpio-reset = <1>; gpio-vana = <2>; gpio-req-tbl-num = <0 1 2>; @@ -441,37 +441,39 @@ sensor-position-roll = <270>; sensor-position-pitch = <0>; sensor-position-yaw = <0>; - led-flash-src = <&led_flash_iris>; - cam_vio-supply = <&pm8998_lvs1>; - cam_vana-supply = <&pmi8998_bob>; - cam_vdig-supply = <&camera_ldo>; + cam_vio-supply = <&pm8998_l9>; + cam_vana-supply = <&pm8998_l16>; + cam_vdig-supply = <&pm8998_l10>; cam_clk-supply = <&titan_top_gdsc>; regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk"; rgltr-cntrl-support; - rgltr-min-voltage = <0 3312000 1050000 0>; - rgltr-max-voltage = <0 3600000 1050000 0>; + rgltr-min-voltage = <1800000 3312000 1800000 0>; + rgltr-max-voltage = <1800000 3312000 1800000 0>; rgltr-load-current = <0 80000 105000 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk3_active + pinctrl-0 = <&cam_sensor_mclk2_active &cam_sensor_iris_active>; - pinctrl-1 = <&cam_sensor_mclk3_suspend + pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_iris_suspend>; - gpios = <&tlmm 16 0>, - <&tlmm 9 0>, - <&tlmm 8 0>; + gpios = <&tlmm 15 0>, + <&tlmm 21 0>, + <&tlmm 122 0>, + <&tlmm 59 0>; gpio-reset = <1>; gpio-vana = <2>; - gpio-req-tbl-num = <0 1 2>; - gpio-req-tbl-flags = <1 0 0>; + gpio-vdig = <3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; gpio-req-tbl-label = "CAMIF_MCLK3", "CAM_RESET3", - "CAM_VANA1"; + "CAM_VANA3", + "CAM_VDIG3"; sensor-mode = <0>; cci-master = <1>; status = "ok"; - clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; clock-names = "cam_clk"; clock-cntl-level = "turbo"; clock-rates = <24000000>; -- GitLab From 50dae7add22bf6648fe386cc72d75463fde4e9da Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Fri, 18 May 2018 15:34:19 -0700 Subject: [PATCH 283/855] leds: qpnp-wled: Do not configure DTEST for PMI8998 v2.0 In PMI8998 v2.0, DTEST line is configured internally by the hardware. Do not configure it explicitly in software. CRs-Fixed: 2244974 Change-Id: I2b8150b5a97fd1851069ee0f1bbb45dd3d8cc048 Signed-off-by: Subbaraman Narayanamurthy --- drivers/leds/leds-qpnp-wled.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c index d2e576d2bba0..861d9876cf0b 100644 --- a/drivers/leds/leds-qpnp-wled.c +++ b/drivers/leds/leds-qpnp-wled.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2215,12 +2215,16 @@ static int qpnp_wled_config(struct qpnp_wled *wled) return rc; if (wled->en_ext_pfet_sc_pro) { - reg = QPNP_WLED_EXT_FET_DTEST2; - rc = qpnp_wled_sec_write_reg(wled, + if (!(wled->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE + && wled->pmic_rev_id->rev4 == + PMI8998_V2P0_REV4)) { + reg = QPNP_WLED_EXT_FET_DTEST2; + rc = qpnp_wled_sec_write_reg(wled, QPNP_WLED_TEST1_REG(wled->ctrl_base), reg); - if (rc) - return rc; + if (rc) + return rc; + } } } else { rc = qpnp_wled_read_reg(wled, -- GitLab From 205cd52bbee7fe6452912fe01ceade970bccc926 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 2 May 2018 13:30:57 +0200 Subject: [PATCH 284/855] 8139too: Use disable_irq_nosync() in rtl8139_poll_controller() [ Upstream commit af3e0fcf78879f718c5f73df0814951bd7057d34 ] Use disable_irq_nosync() instead of disable_irq() as this might be called in atomic context with netpoll. Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/8139too.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c index da4c2d8a4173..1420dfb56bac 100644 --- a/drivers/net/ethernet/realtek/8139too.c +++ b/drivers/net/ethernet/realtek/8139too.c @@ -2233,7 +2233,7 @@ static void rtl8139_poll_controller(struct net_device *dev) struct rtl8139_private *tp = netdev_priv(dev); const int irq = tp->pci_dev->irq; - disable_irq(irq); + disable_irq_nosync(irq); rtl8139_interrupt(irq, dev); enable_irq(irq); } -- GitLab From 0c2133c8b38c6c6ddfd2340c1aefa4844afd0e94 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 27 Apr 2018 20:59:24 +0800 Subject: [PATCH 285/855] bridge: check iface upper dev when setting master via ioctl [ Upstream commit e8238fc2bd7b4c3c7554fa2df067e796610212fc ] When we set a bond slave's master to bridge via ioctl, we only check the IFF_BRIDGE_PORT flag. Although we will find the slave's real master at netdev_master_upper_dev_link() later, it already does some settings and allocates some resources. It would be better to return as early as possible. v1 -> v2: use netdev_master_upper_dev_get() instead of netdev_has_any_upper_dev() to check if we have a master, because not all upper devs are masters, e.g. vlan device. Reported-by: syzbot+de73361ee4971b6e6f75@syzkaller.appspotmail.com Signed-off-by: Hangbin Liu Acked-by: Nikolay Aleksandrov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bridge/br_if.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index ed0dd3340084..8e173324693d 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -504,8 +504,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit) return -ELOOP; - /* Device is already being bridged */ - if (br_port_exists(dev)) + /* Device has master upper dev */ + if (netdev_master_upper_dev_get(dev)) return -EBUSY; /* No bridging devices that dislike that (e.g. wireless) */ -- GitLab From aef419ef7754d22ea647d8a71825c9db0f5c4591 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 3 May 2018 09:39:20 -0700 Subject: [PATCH 286/855] dccp: fix tasklet usage [ Upstream commit a8d7aa17bbc970971ccdf71988ea19230ab368b1 ] syzbot reported a crash in tasklet_action_common() caused by dccp. dccp needs to make sure socket wont disappear before tasklet handler has completed. This patch takes a reference on the socket when arming the tasklet, and moves the sock_put() from dccp_write_xmit_timer() to dccp_write_xmitlet() kernel BUG at kernel/softirq.c:514! invalid opcode: 0000 [#1] SMP KASAN Dumping ftrace buffer: (ftrace buffer empty) Modules linked in: CPU: 1 PID: 17 Comm: ksoftirqd/1 Not tainted 4.17.0-rc3+ #30 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:tasklet_action_common.isra.19+0x6db/0x700 kernel/softirq.c:515 RSP: 0018:ffff8801d9b3faf8 EFLAGS: 00010246 dccp_close: ABORT with 65423 bytes unread RAX: 1ffff1003b367f6b RBX: ffff8801daf1f3f0 RCX: 0000000000000000 RDX: ffff8801cf895498 RSI: 0000000000000004 RDI: 0000000000000000 RBP: ffff8801d9b3fc40 R08: ffffed0039f12a95 R09: ffffed0039f12a94 dccp_close: ABORT with 65423 bytes unread R10: ffffed0039f12a94 R11: ffff8801cf8954a3 R12: 0000000000000000 R13: ffff8801d9b3fc18 R14: dffffc0000000000 R15: ffff8801cf895490 FS: 0000000000000000(0000) GS:ffff8801daf00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000001b2bc28000 CR3: 00000001a08a9000 CR4: 00000000001406e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: tasklet_action+0x1d/0x20 kernel/softirq.c:533 __do_softirq+0x2e0/0xaf5 kernel/softirq.c:285 dccp_close: ABORT with 65423 bytes unread run_ksoftirqd+0x86/0x100 kernel/softirq.c:646 smpboot_thread_fn+0x417/0x870 kernel/smpboot.c:164 kthread+0x345/0x410 kernel/kthread.c:238 ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:412 Code: 48 8b 85 e8 fe ff ff 48 8b 95 f0 fe ff ff e9 94 fb ff ff 48 89 95 f0 fe ff ff e8 81 53 6e 00 48 8b 95 f0 fe ff ff e9 62 fb ff ff <0f> 0b 48 89 cf 48 89 8d e8 fe ff ff e8 64 53 6e 00 48 8b 8d e8 RIP: tasklet_action_common.isra.19+0x6db/0x700 kernel/softirq.c:515 RSP: ffff8801d9b3faf8 Fixes: dc841e30eaea ("dccp: Extend CCID packet dequeueing interface") Signed-off-by: Eric Dumazet Reported-by: syzbot Cc: Gerrit Renker Cc: dccp@vger.kernel.org Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dccp/ccids/ccid2.c | 14 ++++++++++++-- net/dccp/timer.c | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 7753681195c1..86a2ed0fb219 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -126,6 +126,16 @@ static void ccid2_change_l_seq_window(struct sock *sk, u64 val) DCCPF_SEQ_WMAX)); } +static void dccp_tasklet_schedule(struct sock *sk) +{ + struct tasklet_struct *t = &dccp_sk(sk)->dccps_xmitlet; + + if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) { + sock_hold(sk); + __tasklet_schedule(t); + } +} + static void ccid2_hc_tx_rto_expire(unsigned long data) { struct sock *sk = (struct sock *)data; @@ -166,7 +176,7 @@ static void ccid2_hc_tx_rto_expire(unsigned long data) /* if we were blocked before, we may now send cwnd=1 packet */ if (sender_was_blocked) - tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet); + dccp_tasklet_schedule(sk); /* restart backed-off timer */ sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); out: @@ -706,7 +716,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) done: /* check if incoming Acks allow pending packets to be sent */ if (sender_was_blocked && !ccid2_cwnd_network_limited(hc)) - tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet); + dccp_tasklet_schedule(sk); dccp_ackvec_parsed_cleanup(&hc->tx_av_chunks); } diff --git a/net/dccp/timer.c b/net/dccp/timer.c index 3a2c34027758..2a952cbd6efa 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c @@ -230,12 +230,12 @@ static void dccp_write_xmitlet(unsigned long data) else dccp_write_xmit(sk); bh_unlock_sock(sk); + sock_put(sk); } static void dccp_write_xmit_timer(unsigned long data) { dccp_write_xmitlet(data); - sock_put((struct sock *)data); } void dccp_init_xmit_timers(struct sock *sk) -- GitLab From d664986f9290792c6a564a046ed08fcc483a0eec Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Thu, 10 May 2018 10:59:34 -0700 Subject: [PATCH 287/855] ipv4: fix memory leaks in udp_sendmsg, ping_v4_sendmsg [ Upstream commit 1b97013bfb11d66f041de691de6f0fec748ce016 ] Fix more memory leaks in ip_cmsg_send() callers. Part of them were fixed earlier in 919483096bfe. * udp_sendmsg one was there since the beginning when linux sources were first added to git; * ping_v4_sendmsg one was copy/pasted in c319b4d76b9e. Whenever return happens in udp_sendmsg() or ping_v4_sendmsg() IP options have to be freed if they were allocated previously. Add label so that future callers (if any) can use it instead of kfree() before return that is easy to forget. Fixes: c319b4d76b9e (net: ipv4: add IPPROTO_ICMP socket kind) Signed-off-by: Andrey Ignatov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ping.c | 7 +++++-- net/ipv4/udp.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index e612991c9185..9adcd4b1b3fd 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -775,8 +775,10 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ipc.addr = faddr = daddr; if (ipc.opt && ipc.opt->opt.srr) { - if (!daddr) - return -EINVAL; + if (!daddr) { + err = -EINVAL; + goto out_free; + } faddr = ipc.opt->opt.faddr; } tos = get_rttos(&ipc, inet); @@ -841,6 +843,7 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) out: ip_rt_put(rt); +out_free: if (free) kfree(ipc.opt); if (!err) { diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 4cd943096afa..aa2a20e918fd 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -982,8 +982,10 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) sock_tx_timestamp(sk, ipc.sockc.tsflags, &ipc.tx_flags); if (ipc.opt && ipc.opt->opt.srr) { - if (!daddr) - return -EINVAL; + if (!daddr) { + err = -EINVAL; + goto out_free; + } faddr = ipc.opt->opt.faddr; connected = 0; } @@ -1090,6 +1092,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) out: ip_rt_put(rt); +out_free: if (free) kfree(ipc.opt); if (!err) -- GitLab From cf7ef0af1a6a08e3ee3de640968768ed0a47e49c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 7 May 2018 09:02:25 -0700 Subject: [PATCH 288/855] llc: better deal with too small mtu [ Upstream commit 2c5d5b13c6eb79f5677e206b8aad59b3a2097f60 ] syzbot loves to set very small mtu on devices, since it brings joy. We must make llc_ui_sendmsg() fool proof. usercopy: Kernel memory overwrite attempt detected to wrapped address (offset 0, size 18446612139802320068)! kernel BUG at mm/usercopy.c:100! invalid opcode: 0000 [#1] SMP KASAN Dumping ftrace buffer: (ftrace buffer empty) Modules linked in: CPU: 0 PID: 17464 Comm: syz-executor1 Not tainted 4.17.0-rc3+ #36 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:usercopy_abort+0xbb/0xbd mm/usercopy.c:88 RSP: 0018:ffff8801868bf800 EFLAGS: 00010282 RAX: 000000000000006c RBX: ffffffff87d2fb00 RCX: 0000000000000000 RDX: 000000000000006c RSI: ffffffff81610731 RDI: ffffed0030d17ef6 RBP: ffff8801868bf858 R08: ffff88018daa4200 R09: ffffed003b5c4fb0 R10: ffffed003b5c4fb0 R11: ffff8801dae27d87 R12: ffffffff87d2f8e0 R13: ffffffff87d2f7a0 R14: ffffffff87d2f7a0 R15: ffffffff87d2f7a0 FS: 00007f56a14ac700(0000) GS:ffff8801dae00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000001b2bc21000 CR3: 00000001abeb1000 CR4: 00000000001426f0 DR0: 0000000020000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000030602 Call Trace: check_bogus_address mm/usercopy.c:153 [inline] __check_object_size+0x5d9/0x5d9 mm/usercopy.c:256 check_object_size include/linux/thread_info.h:108 [inline] check_copy_size include/linux/thread_info.h:139 [inline] copy_from_iter_full include/linux/uio.h:121 [inline] memcpy_from_msg include/linux/skbuff.h:3305 [inline] llc_ui_sendmsg+0x4b1/0x1530 net/llc/af_llc.c:941 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg+0xd5/0x120 net/socket.c:639 __sys_sendto+0x3d7/0x670 net/socket.c:1789 __do_sys_sendto net/socket.c:1801 [inline] __se_sys_sendto net/socket.c:1797 [inline] __x64_sys_sendto+0xe1/0x1a0 net/socket.c:1797 do_syscall_64+0x1b1/0x800 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x455979 RSP: 002b:00007f56a14abc68 EFLAGS: 00000246 ORIG_RAX: 000000000000002c RAX: ffffffffffffffda RBX: 00007f56a14ac6d4 RCX: 0000000000455979 RDX: 0000000000000000 RSI: 0000000020000000 RDI: 0000000000000018 RBP: 000000000072bea0 R08: 00000000200012c0 R09: 0000000000000010 R10: 0000000000000000 R11: 0000000000000246 R12: 00000000ffffffff R13: 0000000000000548 R14: 00000000006fbf60 R15: 0000000000000000 Code: 55 c0 e8 c0 55 bb ff ff 75 c8 48 8b 55 c0 4d 89 f9 ff 75 d0 4d 89 e8 48 89 d9 4c 89 e6 41 56 48 c7 c7 80 fa d2 87 e8 a0 0b a3 ff <0f> 0b e8 95 55 bb ff e8 c0 a8 f7 ff 8b 95 14 ff ff ff 4d 89 e8 RIP: usercopy_abort+0xbb/0xbd mm/usercopy.c:88 RSP: ffff8801868bf800 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/llc/af_llc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index d6bc5f2a1175..85aae8c84aeb 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -926,6 +926,9 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) if (size > llc->dev->mtu) size = llc->dev->mtu; copied = size - hdrlen; + rc = -EINVAL; + if (copied < 0) + goto release; release_sock(sk); skb = sock_alloc_send_skb(sk, size, noblock, &rc); lock_sock(sk); -- GitLab From 1ed74a5b26c9d5f6e2754008d12a5117f0ac1fc2 Mon Sep 17 00:00:00 2001 From: Rob Taglang Date: Thu, 3 May 2018 17:13:06 -0400 Subject: [PATCH 289/855] net: ethernet: sun: niu set correct packet size in skb [ Upstream commit 14224923c3600bae2ac4dcae3bf0c3d4dc2812be ] Currently, skb->len and skb->data_len are set to the page size, not the packet size. This causes the frame check sequence to not be located at the "end" of the packet resulting in ethernet frame check errors. The driver does work currently, but stricter kernel facing networking solutions like OpenVSwitch will drop these packets as invalid. These changes set the packet size correctly so that these errors no longer occur. The length does not include the frame check sequence, so that subtraction was removed. Tested on Oracle/SUN Multithreaded 10-Gigabit Ethernet Network Controller [108e:abcd] and validated in wireshark. Signed-off-by: Rob Taglang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/sun/niu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c index a2371aa14a49..e45e2f14fb94 100644 --- a/drivers/net/ethernet/sun/niu.c +++ b/drivers/net/ethernet/sun/niu.c @@ -3442,7 +3442,7 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np, len = (val & RCR_ENTRY_L2_LEN) >> RCR_ENTRY_L2_LEN_SHIFT; - len -= ETH_FCS_LEN; + append_size = len + ETH_HLEN + ETH_FCS_LEN; addr = (val & RCR_ENTRY_PKT_BUF_ADDR) << RCR_ENTRY_PKT_BUF_ADDR_SHIFT; @@ -3452,7 +3452,6 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np, RCR_ENTRY_PKTBUFSZ_SHIFT]; off = addr & ~PAGE_MASK; - append_size = rcr_size; if (num_rcr == 1) { int ptype; @@ -3465,7 +3464,7 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np, else skb_checksum_none_assert(skb); } else if (!(val & RCR_ENTRY_MULTI)) - append_size = len - skb->len; + append_size = append_size - skb->len; niu_rx_skb_append(skb, page, off, append_size, rcr_size); if ((page->index + rp->rbr_block_size) - rcr_size == addr) { -- GitLab From b26c7becd7f0c4ac7c45e0ae69cbce3e7f7bf0a7 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Tue, 1 May 2018 12:41:22 -0500 Subject: [PATCH 290/855] net: ethernet: ti: cpsw: fix packet leaking in dual_mac mode [ Upstream commit 5e5add172ea81152d518b161ec5706503ad3d799 ] In dual_mac mode packets arrived on one port should not be forwarded by switch hw to another port. Only Linux Host can forward packets between ports. The below test case (reported in [1]) shows that packet arrived on one port can be leaked to anoter (reproducible with dual port evms): - connect port 1 (eth0) to linux Host 0 and run tcpdump or Wireshark - connect port 2 (eth1) to linux Host 1 with vlan 1 configured - ping from Host 1 through vlan 1 interface. ARP packets will be seen on Host 0. Issue happens because dual_mac mode is implemnted using two vlans: 1 (Port 1+Port 0) and 2 (Port 2+Port 0), so there are vlan records created for for each vlan. By default, the ALE will find valid vlan record in its table when vlan 1 tagged packet arrived on Port 2 and so forwards packet to all ports which are vlan 1 members (like Port. To avoid such behaviorr the ALE VLAN ID Ingress Check need to be enabled for each external CPSW port (ALE_PORTCTLn.VID_INGRESS_CHECK) so ALE will drop ingress packets if Rx port is not VLAN member. Signed-off-by: Grygorii Strashko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/ti/cpsw.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index de336897a28a..d7cb205fe7e2 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1141,6 +1141,8 @@ static inline void cpsw_add_dual_emac_def_ale_entries( cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr, HOST_PORT_NUM, ALE_VLAN | ALE_SECURE, slave->port_vlan); + cpsw_ale_control_set(cpsw->ale, slave_port, + ALE_PORT_DROP_UNKNOWN_VLAN, 1); } static void soft_reset_slave(struct cpsw_slave *slave) -- GitLab From a73d97e2ab241a867cbab2c511fb41163d1fef67 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Wed, 9 May 2018 18:35:13 +0300 Subject: [PATCH 291/855] net/mlx4_en: Verify coalescing parameters are in range [ Upstream commit 6ad4e91c6d796b38a7f0e724db1de28eeb122bad ] Add check of coalescing parameters received through ethtool are within range of values supported by the HW. Driver gets the coalescing rx/tx-usecs and rx/tx-frames as set by the users through ethtool. The ethtool support up to 32 bit value for each. However, mlx4 modify cq limits the coalescing time parameter and coalescing frames parameters to 16 bits. Return out of range error if user tries to set these parameters to higher values. Change type of sample-interval and adaptive_rx_coal parameters in mlx4 driver to u32 as the ethtool holds them as u32 and these parameters are not limited due to mlx4 HW. Fixes: c27a02cd94d6 ('mlx4_en: Add driver for Mellanox ConnectX 10GbE NIC') Signed-off-by: Moshe Shemesh Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 16 ++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 7 +++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 24977cc881d2..9a4c4f8281bd 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -970,6 +970,22 @@ static int mlx4_en_set_coalesce(struct net_device *dev, if (!coal->tx_max_coalesced_frames_irq) return -EINVAL; + if (coal->tx_coalesce_usecs > MLX4_EN_MAX_COAL_TIME || + coal->rx_coalesce_usecs > MLX4_EN_MAX_COAL_TIME || + coal->rx_coalesce_usecs_low > MLX4_EN_MAX_COAL_TIME || + coal->rx_coalesce_usecs_high > MLX4_EN_MAX_COAL_TIME) { + netdev_info(dev, "%s: maximum coalesce time supported is %d usecs\n", + __func__, MLX4_EN_MAX_COAL_TIME); + return -ERANGE; + } + + if (coal->tx_max_coalesced_frames > MLX4_EN_MAX_COAL_PKTS || + coal->rx_max_coalesced_frames > MLX4_EN_MAX_COAL_PKTS) { + netdev_info(dev, "%s: maximum coalesced frames supported is %d\n", + __func__, MLX4_EN_MAX_COAL_PKTS); + return -ERANGE; + } + priv->rx_frames = (coal->rx_max_coalesced_frames == MLX4_EN_AUTO_CONF) ? MLX4_EN_RX_COAL_TARGET : diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 18f221d8a04d..247d340be743 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -141,6 +141,9 @@ enum { #define MLX4_EN_TX_COAL_PKTS 16 #define MLX4_EN_TX_COAL_TIME 0x10 +#define MLX4_EN_MAX_COAL_PKTS U16_MAX +#define MLX4_EN_MAX_COAL_TIME U16_MAX + #define MLX4_EN_RX_RATE_LOW 400000 #define MLX4_EN_RX_COAL_TIME_LOW 0 #define MLX4_EN_RX_RATE_HIGH 450000 @@ -543,8 +546,8 @@ struct mlx4_en_priv { u16 rx_usecs_low; u32 pkt_rate_high; u16 rx_usecs_high; - u16 sample_interval; - u16 adaptive_rx_coal; + u32 sample_interval; + u32 adaptive_rx_coal; u32 msg_enable; u32 loopback_ok; u32 validate_loopback; -- GitLab From a541ccf5688da9312f690d988db14f598a4e6b71 Mon Sep 17 00:00:00 2001 From: Adi Nissim Date: Wed, 25 Apr 2018 11:21:32 +0300 Subject: [PATCH 292/855] net/mlx5: E-Switch, Include VF RDMA stats in vport statistics [ Upstream commit 88d725bbb43cd63a40c8ef70dd373f1d38ead2e3 ] The host side reporting of VF vport statistics didn't include the VF RDMA traffic. Fixes: 3b751a2a418a ("net/mlx5: E-Switch, Introduce get vf statistics") Signed-off-by: Adi Nissim Reported-by: Ariel Almog Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index a8966e6dbe1b..5d6eab19a9d8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1924,26 +1924,35 @@ int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw, memset(vf_stats, 0, sizeof(*vf_stats)); vf_stats->rx_packets = MLX5_GET_CTR(out, received_eth_unicast.packets) + + MLX5_GET_CTR(out, received_ib_unicast.packets) + MLX5_GET_CTR(out, received_eth_multicast.packets) + + MLX5_GET_CTR(out, received_ib_multicast.packets) + MLX5_GET_CTR(out, received_eth_broadcast.packets); vf_stats->rx_bytes = MLX5_GET_CTR(out, received_eth_unicast.octets) + + MLX5_GET_CTR(out, received_ib_unicast.octets) + MLX5_GET_CTR(out, received_eth_multicast.octets) + + MLX5_GET_CTR(out, received_ib_multicast.octets) + MLX5_GET_CTR(out, received_eth_broadcast.octets); vf_stats->tx_packets = MLX5_GET_CTR(out, transmitted_eth_unicast.packets) + + MLX5_GET_CTR(out, transmitted_ib_unicast.packets) + MLX5_GET_CTR(out, transmitted_eth_multicast.packets) + + MLX5_GET_CTR(out, transmitted_ib_multicast.packets) + MLX5_GET_CTR(out, transmitted_eth_broadcast.packets); vf_stats->tx_bytes = MLX5_GET_CTR(out, transmitted_eth_unicast.octets) + + MLX5_GET_CTR(out, transmitted_ib_unicast.octets) + MLX5_GET_CTR(out, transmitted_eth_multicast.octets) + + MLX5_GET_CTR(out, transmitted_ib_multicast.octets) + MLX5_GET_CTR(out, transmitted_eth_broadcast.octets); vf_stats->multicast = - MLX5_GET_CTR(out, received_eth_multicast.packets); + MLX5_GET_CTR(out, received_eth_multicast.packets) + + MLX5_GET_CTR(out, received_ib_multicast.packets); vf_stats->broadcast = MLX5_GET_CTR(out, received_eth_broadcast.packets); -- GitLab From c8b54621de5c0b50b4b8bef90901b645f7f92e01 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 May 2018 10:03:30 -0700 Subject: [PATCH 293/855] net_sched: fq: take care of throttled flows before reuse [ Upstream commit 7df40c2673a1307c3260aab6f9d4b9bf97ca8fd7 ] Normally, a socket can not be freed/reused unless all its TX packets left qdisc and were TX-completed. However connect(AF_UNSPEC) allows this to happen. With commit fc59d5bdf1e3 ("pkt_sched: fq: clear time_next_packet for reused flows") we cleared f->time_next_packet but took no special action if the flow was still in the throttled rb-tree. Since f->time_next_packet is the key used in the rb-tree searches, blindly clearing it might break rb-tree integrity. We need to make sure the flow is no longer in the rb-tree to avoid this problem. Fixes: fc59d5bdf1e3 ("pkt_sched: fq: clear time_next_packet for reused flows") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_fq.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 18e752439f6f..b57b4de73038 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -128,6 +128,28 @@ static bool fq_flow_is_detached(const struct fq_flow *f) return f->next == &detached; } +static bool fq_flow_is_throttled(const struct fq_flow *f) +{ + return f->next == &throttled; +} + +static void fq_flow_add_tail(struct fq_flow_head *head, struct fq_flow *flow) +{ + if (head->first) + head->last->next = flow; + else + head->first = flow; + head->last = flow; + flow->next = NULL; +} + +static void fq_flow_unset_throttled(struct fq_sched_data *q, struct fq_flow *f) +{ + rb_erase(&f->rate_node, &q->delayed); + q->throttled_flows--; + fq_flow_add_tail(&q->old_flows, f); +} + static void fq_flow_set_throttled(struct fq_sched_data *q, struct fq_flow *f) { struct rb_node **p = &q->delayed.rb_node, *parent = NULL; @@ -155,15 +177,6 @@ static void fq_flow_set_throttled(struct fq_sched_data *q, struct fq_flow *f) static struct kmem_cache *fq_flow_cachep __read_mostly; -static void fq_flow_add_tail(struct fq_flow_head *head, struct fq_flow *flow) -{ - if (head->first) - head->last->next = flow; - else - head->first = flow; - head->last = flow; - flow->next = NULL; -} /* limit number of collected flows per round */ #define FQ_GC_MAX 8 @@ -267,6 +280,8 @@ static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q) f->socket_hash != sk->sk_hash)) { f->credit = q->initial_quantum; f->socket_hash = sk->sk_hash; + if (fq_flow_is_throttled(f)) + fq_flow_unset_throttled(q, f); f->time_next_packet = 0ULL; } return f; @@ -430,9 +445,7 @@ static void fq_check_throttled(struct fq_sched_data *q, u64 now) q->time_next_delayed_flow = f->time_next_packet; break; } - rb_erase(p, &q->delayed); - q->throttled_flows--; - fq_flow_add_tail(&q->old_flows, f); + fq_flow_unset_throttled(q, f); } } -- GitLab From 51d2a5e792863b77a077d8ca68b456a7406e8889 Mon Sep 17 00:00:00 2001 From: Lance Richardson Date: Wed, 25 Apr 2018 10:21:54 -0400 Subject: [PATCH 294/855] net: support compat 64-bit time in {s,g}etsockopt [ Upstream commit 988bf7243e03ef69238381594e0334a79cef74a6 ] For the x32 ABI, struct timeval has two 64-bit fields. However the kernel currently interprets the user-space values used for the SO_RCVTIMEO and SO_SNDTIMEO socket options as having a pair of 32-bit fields. When the seconds portion of the requested timeout is less than 2**32, the seconds portion of the effective timeout is correct but the microseconds portion is zero. When the seconds portion of the requested timeout is zero and the microseconds portion is non-zero, the kernel interprets the timeout as zero (never timeout). Fix by using 64-bit time for SO_RCVTIMEO/SO_SNDTIMEO as required for the ABI. The code included below demonstrates the problem. Results before patch: $ gcc -m64 -Wall -O2 -o socktmo socktmo.c && ./socktmo recv time: 2.008181 seconds send time: 2.015985 seconds $ gcc -m32 -Wall -O2 -o socktmo socktmo.c && ./socktmo recv time: 2.016763 seconds send time: 2.016062 seconds $ gcc -mx32 -Wall -O2 -o socktmo socktmo.c && ./socktmo recv time: 1.007239 seconds send time: 1.023890 seconds Results after patch: $ gcc -m64 -O2 -Wall -o socktmo socktmo.c && ./socktmo recv time: 2.010062 seconds send time: 2.015836 seconds $ gcc -m32 -O2 -Wall -o socktmo socktmo.c && ./socktmo recv time: 2.013974 seconds send time: 2.015981 seconds $ gcc -mx32 -O2 -Wall -o socktmo socktmo.c && ./socktmo recv time: 2.030257 seconds send time: 2.013383 seconds #include #include #include #include #include void checkrc(char *str, int rc) { if (rc >= 0) return; perror(str); exit(1); } static char buf[1024]; int main(int argc, char **argv) { int rc; int socks[2]; struct timeval tv; struct timeval start, end, delta; rc = socketpair(AF_UNIX, SOCK_STREAM, 0, socks); checkrc("socketpair", rc); /* set timeout to 1.999999 seconds */ tv.tv_sec = 1; tv.tv_usec = 999999; rc = setsockopt(socks[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); rc = setsockopt(socks[0], SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv); checkrc("setsockopt", rc); /* measure actual receive timeout */ gettimeofday(&start, NULL); rc = recv(socks[0], buf, sizeof buf, 0); gettimeofday(&end, NULL); timersub(&end, &start, &delta); printf("recv time: %ld.%06ld seconds\n", (long)delta.tv_sec, (long)delta.tv_usec); /* fill send buffer */ do { rc = send(socks[0], buf, sizeof buf, 0); } while (rc > 0); /* measure actual send timeout */ gettimeofday(&start, NULL); rc = send(socks[0], buf, sizeof buf, 0); gettimeofday(&end, NULL); timersub(&end, &start, &delta); printf("send time: %ld.%06ld seconds\n", (long)delta.tv_sec, (long)delta.tv_usec); exit(0); } Fixes: 515c7af85ed9 ("x32: Use compat shims for {g,s}etsockopt") Reported-by: Gopal RajagopalSai Signed-off-by: Lance Richardson Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/compat.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/compat.c b/net/compat.c index a96fd2f3507b..73671e6ec6eb 100644 --- a/net/compat.c +++ b/net/compat.c @@ -372,7 +372,8 @@ static int compat_sock_setsockopt(struct socket *sock, int level, int optname, optname == SO_ATTACH_REUSEPORT_CBPF) return do_set_attach_filter(sock, level, optname, optval, optlen); - if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) + if (!COMPAT_USE_64BIT_TIME && + (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) return do_set_sock_timeout(sock, level, optname, optval, optlen); return sock_setsockopt(sock, level, optname, optval, optlen); @@ -437,7 +438,8 @@ static int do_get_sock_timeout(struct socket *sock, int level, int optname, static int compat_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { - if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) + if (!COMPAT_USE_64BIT_TIME && + (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) return do_get_sock_timeout(sock, level, optname, optval, optlen); return sock_getsockopt(sock, level, optname, optval, optlen); } -- GitLab From 32a42d5fa1f0cd342009bd852088a67e1d7daf6d Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Thu, 3 May 2018 18:13:25 +0200 Subject: [PATCH 295/855] openvswitch: Don't swap table in nlattr_set() after OVS_ATTR_NESTED is found [ Upstream commit 72f17baf2352ded6a1d3f4bb2d15da8c678cd2cb ] If an OVS_ATTR_NESTED attribute type is found while walking through netlink attributes, we call nlattr_set() recursively passing the length table for the following nested attributes, if different from the current one. However, once we're done with those sub-nested attributes, we should continue walking through attributes using the current table, instead of using the one related to the sub-nested attributes. For example, given this sequence: 1 OVS_KEY_ATTR_PRIORITY 2 OVS_KEY_ATTR_TUNNEL 3 OVS_TUNNEL_KEY_ATTR_ID 4 OVS_TUNNEL_KEY_ATTR_IPV4_SRC 5 OVS_TUNNEL_KEY_ATTR_IPV4_DST 6 OVS_TUNNEL_KEY_ATTR_TTL 7 OVS_TUNNEL_KEY_ATTR_TP_SRC 8 OVS_TUNNEL_KEY_ATTR_TP_DST 9 OVS_KEY_ATTR_IN_PORT 10 OVS_KEY_ATTR_SKB_MARK 11 OVS_KEY_ATTR_MPLS we switch to the 'ovs_tunnel_key_lens' table on attribute #3, and we don't switch back to 'ovs_key_lens' while setting attributes #9 to #11 in the sequence. As OVS_KEY_ATTR_MPLS evaluates to 21, and the array size of 'ovs_tunnel_key_lens' is 15, we also get this kind of KASan splat while accessing the wrong table: [ 7654.586496] ================================================================== [ 7654.594573] BUG: KASAN: global-out-of-bounds in nlattr_set+0x164/0xde9 [openvswitch] [ 7654.603214] Read of size 4 at addr ffffffffc169ecf0 by task handler29/87430 [ 7654.610983] [ 7654.612644] CPU: 21 PID: 87430 Comm: handler29 Kdump: loaded Not tainted 3.10.0-866.el7.test.x86_64 #1 [ 7654.623030] Hardware name: Dell Inc. PowerEdge R730/072T6D, BIOS 2.1.7 06/16/2016 [ 7654.631379] Call Trace: [ 7654.634108] [] dump_stack+0x19/0x1b [ 7654.639843] [] print_address_description+0x33/0x290 [ 7654.647129] [] ? nlattr_set+0x164/0xde9 [openvswitch] [ 7654.654607] [] kasan_report.part.3+0x242/0x330 [ 7654.661406] [] __asan_report_load4_noabort+0x34/0x40 [ 7654.668789] [] nlattr_set+0x164/0xde9 [openvswitch] [ 7654.676076] [] ovs_nla_get_match+0x10c8/0x1900 [openvswitch] [ 7654.684234] [] ? genl_rcv+0x28/0x40 [ 7654.689968] [] ? netlink_unicast+0x3f3/0x590 [ 7654.696574] [] ? ovs_nla_put_tunnel_info+0xb0/0xb0 [openvswitch] [ 7654.705122] [] ? unwind_get_return_address+0xb0/0xb0 [ 7654.712503] [] ? system_call_fastpath+0x1c/0x21 [ 7654.719401] [] ? update_stack_state+0x229/0x370 [ 7654.726298] [] ? update_stack_state+0x229/0x370 [ 7654.733195] [] ? kasan_unpoison_shadow+0x35/0x50 [ 7654.740187] [] ? kasan_kmalloc+0xaa/0xe0 [ 7654.746406] [] ? kasan_slab_alloc+0x12/0x20 [ 7654.752914] [] ? memset+0x31/0x40 [ 7654.758456] [] ovs_flow_cmd_new+0x2b2/0xf00 [openvswitch] [snip] [ 7655.132484] The buggy address belongs to the variable: [ 7655.138226] ovs_tunnel_key_lens+0xf0/0xffffffffffffd400 [openvswitch] [ 7655.145507] [ 7655.147166] Memory state around the buggy address: [ 7655.152514] ffffffffc169eb80: 00 00 00 00 00 00 00 00 00 00 fa fa fa fa fa fa [ 7655.160585] ffffffffc169ec00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 7655.168644] >ffffffffc169ec80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa fa [ 7655.176701] ^ [ 7655.184372] ffffffffc169ed00: fa fa fa fa 00 00 00 00 fa fa fa fa 00 00 00 05 [ 7655.192431] ffffffffc169ed80: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00 [ 7655.200490] ================================================================== Reported-by: Hangbin Liu Fixes: 982b52700482 ("openvswitch: Fix mask generation for nested attributes.") Signed-off-by: Stefano Brivio Reviewed-by: Sabrina Dubroca Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/openvswitch/flow_netlink.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 1668916bdbde..326945d9be5f 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -1296,13 +1296,10 @@ static void nlattr_set(struct nlattr *attr, u8 val, /* The nlattr stream should already have been validated */ nla_for_each_nested(nla, attr, rem) { - if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED) { - if (tbl[nla_type(nla)].next) - tbl = tbl[nla_type(nla)].next; - nlattr_set(nla, val, tbl); - } else { + if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED) + nlattr_set(nla, val, tbl[nla_type(nla)].next ? : tbl); + else memset(nla_data(nla), val, nla_len(nla)); - } if (nla_type(nla) == OVS_KEY_ATTR_CT_STATE) *(u32 *)nla_data(nla) &= CT_SUPPORTED_MASK; -- GitLab From 7b863f6bd3c29a3d6b6a0eb766f915d32a2104c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 2 May 2018 22:22:54 +0200 Subject: [PATCH 296/855] qmi_wwan: do not steal interfaces from class drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 5697db4a696c41601a1d15c1922150b4dbf5726c ] The USB_DEVICE_INTERFACE_NUMBER matching macro assumes that the { vendorid, productid, interfacenumber } set uniquely identifies one specific function. This has proven to fail for some configurable devices. One example is the Quectel EM06/EP06 where the same interface number can be either QMI or MBIM, without the device ID changing either. Fix by requiring the vendor-specific class for interface number based matching. Functions of other classes can and should use class based matching instead. Fixes: 03304bcb5ec4 ("net: qmi_wwan: use fixed interface number matching") Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 1029bd234c22..3e893fe890a0 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1039,6 +1039,18 @@ static int qmi_wwan_probe(struct usb_interface *intf, id->driver_info = (unsigned long)&qmi_wwan_info; } + /* There are devices where the same interface number can be + * configured as different functions. We should only bind to + * vendor specific functions when matching on interface number + */ + if (id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER && + desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) { + dev_dbg(&intf->dev, + "Rejecting interface number match for class %02x\n", + desc->bInterfaceClass); + return -ENODEV; + } + /* Quectel EC20 quirk where we've QMI on interface 4 instead of 0 */ if (quectel_ec20_detected(intf) && desc->bInterfaceNumber == 0) { dev_dbg(&intf->dev, "Quectel EC20 quirk, skipping interface 0\n"); -- GitLab From 4a5de2f99caf699145691a0d55a8812c52a7c8df Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 7 May 2018 21:11:21 +0200 Subject: [PATCH 297/855] r8169: fix powering up RTL8168h [ Upstream commit 3148dedfe79e422f448a10250d3e2cdf8b7ee617 ] Since commit a92a08499b1f "r8169: improve runtime pm in general and suspend unused ports" interfaces w/o link are runtime-suspended after 10s. On systems where drivers take longer to load this can lead to the situation that the interface is runtime-suspended already when it's initially brought up. This shouldn't be a problem because rtl_open() resumes MAC/PHY. However with at least one chip version the interface doesn't properly come up, as reported here: https://bugzilla.kernel.org/show_bug.cgi?id=199549 The vendor driver uses a delay to give certain chip versions some time to resume before starting the PHY configuration. So let's do the same. I don't know which chip versions may be affected, therefore apply this delay always. This patch was reported to fix the issue for RTL8168h. I was able to reproduce the issue on an Asus H310I-Plus which also uses a RTL8168h. Also in my case the patch fixed the issue. Reported-by: Slava Kardakov Tested-by: Slava Kardakov Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/r8169.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index dbb63640bc6e..59b932db0d42 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -4861,6 +4861,9 @@ static void rtl_pll_power_down(struct rtl8169_private *tp) static void rtl_pll_power_up(struct rtl8169_private *tp) { rtl_generic_op(tp, tp->pll_power_ops.up); + + /* give MAC/PHY some time to resume */ + msleep(20); } static void rtl_init_pll_power_ops(struct rtl8169_private *tp) -- GitLab From f9a670e10d274274fda7fd74220dfd1048dd332e Mon Sep 17 00:00:00 2001 From: Xin Long Date: Thu, 26 Apr 2018 14:13:57 +0800 Subject: [PATCH 298/855] sctp: handle two v4 addrs comparison in sctp_inet6_cmp_addr [ Upstream commit d625329b06e46bd20baf9ee40847d11982569204 ] Since sctp ipv6 socket also supports v4 addrs, it's possible to compare two v4 addrs in pf v6 .cmp_addr, sctp_inet6_cmp_addr. However after Commit 1071ec9d453a ("sctp: do not check port in sctp_inet6_cmp_addr"), it no longer calls af1->cmp_addr, which in this case is sctp_v4_cmp_addr, but calls __sctp_v6_cmp_addr where it handles them as two v6 addrs. It would cause a out of bounds crash. syzbot found this crash when trying to bind two v4 addrs to a v6 socket. This patch fixes it by adding the process for two v4 addrs in sctp_inet6_cmp_addr. Fixes: 1071ec9d453a ("sctp: do not check port in sctp_inet6_cmp_addr") Reported-by: syzbot+cd494c1dd681d4d93ebb@syzkaller.appspotmail.com Signed-off-by: Xin Long Acked-by: Neil Horman Acked-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/ipv6.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index e031797ad311..f4d5efb1d231 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -864,6 +864,9 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1, if (sctp_is_any(sk, addr1) || sctp_is_any(sk, addr2)) return 1; + if (addr1->sa.sa_family == AF_INET && addr2->sa.sa_family == AF_INET) + return addr1->v4.sin_addr.s_addr == addr2->v4.sin_addr.s_addr; + return __sctp_v6_cmp_addr(addr1, addr2); } -- GitLab From 1f2b77e868d9ff002a312fd93ee20e636f80614d Mon Sep 17 00:00:00 2001 From: Xin Long Date: Thu, 10 May 2018 17:34:13 +0800 Subject: [PATCH 299/855] sctp: remove sctp_chunk_put from fail_mark err path in sctp_ulpevent_make_rcvmsg [ Upstream commit 6910e25de2257e2c82c7a2d126e3463cd8e50810 ] In Commit 1f45f78f8e51 ("sctp: allow GSO frags to access the chunk too"), it held the chunk in sctp_ulpevent_make_rcvmsg to access it safely later in recvmsg. However, it also added sctp_chunk_put in fail_mark err path, which is only triggered before holding the chunk. syzbot reported a use-after-free crash happened on this err path, where it shouldn't call sctp_chunk_put. This patch simply removes this call. Fixes: 1f45f78f8e51 ("sctp: allow GSO frags to access the chunk too") Reported-by: syzbot+141d898c5f24489db4aa@syzkaller.appspotmail.com Signed-off-by: Xin Long Acked-by: Neil Horman Acked-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/ulpevent.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index bea00058ce35..6825e05a68b2 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -723,7 +723,6 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, return event; fail_mark: - sctp_chunk_put(chunk); kfree_skb(skb); fail: return NULL; -- GitLab From c832ac459e2dbce204e6a5e072f821eadc49d4f7 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Wed, 2 May 2018 13:39:46 +0800 Subject: [PATCH 300/855] sctp: use the old asoc when making the cookie-ack chunk in dupcook_d [ Upstream commit 46e16d4b956867013e0bbd7f2bad206f4aa55752 ] When processing a duplicate cookie-echo chunk, for case 'D', sctp will not process the param from this chunk. It means old asoc has nothing to be updated, and the new temp asoc doesn't have the complete info. So there's no reason to use the new asoc when creating the cookie-ack chunk. Otherwise, like when auth is enabled for cookie-ack, the chunk can not be set with auth, and it will definitely be dropped by peer. This issue is there since very beginning, and we fix it by using the old asoc instead. Signed-off-by: Xin Long Acked-by: Neil Horman Acked-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/sm_statefuns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 8ec20a64a3f8..07f8b53c3bf1 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -1959,7 +1959,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(struct net *net, } } - repl = sctp_make_cookie_ack(new_asoc, chunk); + repl = sctp_make_cookie_ack(asoc, chunk); if (!repl) goto nomem; -- GitLab From a9d361cfe203e283a8745d36f9ccde5895237b28 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Tue, 1 May 2018 21:45:41 -0400 Subject: [PATCH 301/855] tcp_bbr: fix to zero idle_restart only upon S/ACKed data [ Upstream commit e6e6a278b1eaffa19d42186bfacd1ffc15a50b3f ] Previously the bbr->idle_restart tracking was zeroing out the bbr->idle_restart bit upon ACKs that did not SACK or ACK anything, e.g. receiving incoming data or receiver window updates. In such situations BBR would forget that this was a restart-from-idle situation, and if the min_rtt had expired it would unnecessarily enter PROBE_RTT (even though we were actually restarting from idle but had merely forgotten that fact). The fix is simple: we need to remember we are restarting from idle until we receive a S/ACK for some data (a S/ACK for the first flight of data we send as we are restarting). This commit is a stable candidate for kernels back as far as 4.9. Fixes: 0f8782ea1497 ("tcp_bbr: add BBR congestion control") Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Signed-off-by: Soheil Hassas Yeganeh Signed-off-by: Priyaranjan Jha Signed-off-by: Yousuk Seung Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_bbr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c index 8ec60532be2b..9169859506b7 100644 --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c @@ -773,7 +773,9 @@ static void bbr_update_min_rtt(struct sock *sk, const struct rate_sample *rs) } } } - bbr->idle_restart = 0; + /* Restart after idle ends only once we process a new S/ACK for data */ + if (rs->delivered > 0) + bbr->idle_restart = 0; } static void bbr_update_model(struct sock *sk, const struct rate_sample *rs) -- GitLab From d979320029f97adc7c2112d85fc626a71fe2366a Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 3 May 2018 20:04:27 -0400 Subject: [PATCH 302/855] tg3: Fix vunmap() BUG_ON() triggered from tg3_free_consistent(). [ Upstream commit d89a2adb8bfe6f8949ff389acdb9fa298b6e8e12 ] tg3_free_consistent() calls dma_free_coherent() to free tp->hw_stats under spinlock and can trigger BUG_ON() in vunmap() because vunmap() may sleep. Fix it by removing the spinlock and relying on the TG3_FLAG_INIT_COMPLETE flag to prevent race conditions between tg3_get_stats64() and tg3_free_consistent(). TG3_FLAG_INIT_COMPLETE is always cleared under tp->lock before tg3_free_consistent() and therefore tg3_get_stats64() can safely access tp->hw_stats under tp->lock if TG3_FLAG_INIT_COMPLETE is set. Fixes: f5992b72ebe0 ("tg3: Fix race condition in tg3_get_stats64().") Reported-by: Zumeng Chen Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/tg3.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 795a133fb074..4ffbe850d746 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -8720,14 +8720,15 @@ static void tg3_free_consistent(struct tg3 *tp) tg3_mem_rx_release(tp); tg3_mem_tx_release(tp); - /* Protect tg3_get_stats64() from reading freed tp->hw_stats. */ - tg3_full_lock(tp, 0); + /* tp->hw_stats can be referenced safely: + * 1. under rtnl_lock + * 2. or under tp->lock if TG3_FLAG_INIT_COMPLETE is set. + */ if (tp->hw_stats) { dma_free_coherent(&tp->pdev->dev, sizeof(struct tg3_hw_stats), tp->hw_stats, tp->stats_mapping); tp->hw_stats = NULL; } - tg3_full_unlock(tp); } /* @@ -14161,7 +14162,7 @@ static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev, struct tg3 *tp = netdev_priv(dev); spin_lock_bh(&tp->lock); - if (!tp->hw_stats) { + if (!tp->hw_stats || !tg3_flag(tp, INIT_COMPLETE)) { *stats = tp->net_stats_prev; spin_unlock_bh(&tp->lock); return stats; -- GitLab From 89f502a4c07ed6b9a69b6c81146f4db331224086 Mon Sep 17 00:00:00 2001 From: Debabrata Banerjee Date: Wed, 9 May 2018 19:32:10 -0400 Subject: [PATCH 303/855] bonding: do not allow rlb updates to invalid mac [ Upstream commit 4fa8667ca3989ce14cf66301fa251544fbddbdd0 ] Make sure multicast, broadcast, and zero mac's cannot be the output of rlb updates, which should all be directed arps. Receive load balancing will be collapsed if any of these happen, as the switch will broadcast. Signed-off-by: Debabrata Banerjee Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_alb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 551f0f8dead3..7b85c508c273 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -450,7 +450,7 @@ static void rlb_update_client(struct rlb_client_info *client_info) { int i; - if (!client_info->slave) + if (!client_info->slave || !is_valid_ether_addr(client_info->mac_dst)) return; for (i = 0; i < RLB_ARP_BURST_SIZE; i++) { -- GitLab From 8274cb813b5dcb27de72bf7abf0a2ebad4cf95dd Mon Sep 17 00:00:00 2001 From: Talat Batheesh Date: Sun, 15 Apr 2018 11:26:19 +0300 Subject: [PATCH 304/855] net/mlx5: Avoid cleaning flow steering table twice during error flow [ Upstream commit 9c26f5f89d01ca21560c6b8a8e4054c271cc3a9c ] When we fail to initialize the RX root namespace, we need to clean only that and not the entire flow steering. Currently the code may try to clean the flow steering twice on error witch leads to null pointer deference. Make sure we clean correctly. Fixes: fba53f7b5719 ("net/mlx5: Introduce mlx5_flow_steering structure") Signed-off-by: Talat Batheesh Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- .../net/ethernet/mellanox/mlx5/core/fs_core.c | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 331a6ca4856d..5f3402ba9916 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -153,6 +153,7 @@ static void del_rule(struct fs_node *node); static void del_flow_table(struct fs_node *node); static void del_flow_group(struct fs_node *node); static void del_fte(struct fs_node *node); +static void cleanup_root_ns(struct mlx5_flow_root_namespace *root_ns); static void tree_init_node(struct fs_node *node, unsigned int refcount, @@ -1690,24 +1691,28 @@ static int create_anchor_flow_table(struct mlx5_flow_steering *steering) static int init_root_ns(struct mlx5_flow_steering *steering) { + int err; steering->root_ns = create_root_ns(steering, FS_FT_NIC_RX); if (!steering->root_ns) - goto cleanup; + return -ENOMEM; - if (init_root_tree(steering, &root_fs, &steering->root_ns->ns.node)) - goto cleanup; + err = init_root_tree(steering, &root_fs, &steering->root_ns->ns.node); + if (err) + goto out_err; set_prio_attrs(steering->root_ns); - if (create_anchor_flow_table(steering)) - goto cleanup; + err = create_anchor_flow_table(steering); + if (err) + goto out_err; return 0; -cleanup: - mlx5_cleanup_fs(steering->dev); - return -ENOMEM; +out_err: + cleanup_root_ns(steering->root_ns); + steering->root_ns = NULL; + return err; } static void clean_tree(struct fs_node *node) -- GitLab From d7bfa99fcc7fdc5a6669ef63c60dc4c3dacb7020 Mon Sep 17 00:00:00 2001 From: Debabrata Banerjee Date: Wed, 9 May 2018 19:32:11 -0400 Subject: [PATCH 305/855] bonding: send learning packets for vlans on slave [ Upstream commit 21706ee8a47d3ede7fdae0be6d7c0a0e31a83229 ] There was a regression at some point from the intended functionality of commit f60c3704e87d ("bonding: Fix alb mode to only use first level vlans.") Given the return value vlan_get_encap_level() we need to store the nest level of the bond device, and then compare the vlan's encap level to this. Without this, this check always fails and learning packets are never sent. In addition, this same commit caused a regression in the behavior of balance_alb, which requires learning packets be sent for all interfaces using the slave's mac in order to load balance properly. For vlan's that have not set a user mac, we can send after checking one bit. Otherwise we need send the set mac, albeit defeating rx load balancing for that vlan. Signed-off-by: Debabrata Banerjee Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_alb.c | 13 ++++++++----- drivers/net/bonding/bond_main.c | 2 ++ include/net/bonding.h | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 7b85c508c273..91d8a48e53c3 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -944,6 +944,10 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[], skb->priority = TC_PRIO_CONTROL; skb->dev = slave->dev; + netdev_dbg(slave->bond->dev, + "Send learning packet: dev %s mac %pM vlan %d\n", + slave->dev->name, mac_addr, vid); + if (vid) __vlan_hwaccel_put_tag(skb, vlan_proto, vid); @@ -966,14 +970,13 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[], */ rcu_read_lock(); netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) { - if (is_vlan_dev(upper) && vlan_get_encap_level(upper) == 0) { - if (strict_match && - ether_addr_equal_64bits(mac_addr, - upper->dev_addr)) { + if (is_vlan_dev(upper) && + bond->nest_level == vlan_get_encap_level(upper) - 1) { + if (upper->addr_assign_type == NET_ADDR_STOLEN) { alb_send_lp_vid(slave, mac_addr, vlan_dev_vlan_proto(upper), vlan_dev_vlan_id(upper)); - } else if (!strict_match) { + } else { alb_send_lp_vid(slave, upper->dev_addr, vlan_dev_vlan_proto(upper), vlan_dev_vlan_id(upper)); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 13a015b8052b..1a139d0f2232 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1732,6 +1732,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (bond_mode_uses_xmit_hash(bond)) bond_update_slave_arr(bond, NULL); + bond->nest_level = dev_get_nest_level(bond_dev); + netdev_info(bond_dev, "Enslaving %s as %s interface with %s link\n", slave_dev->name, bond_is_active_slave(new_slave) ? "an active" : "a backup", diff --git a/include/net/bonding.h b/include/net/bonding.h index f32f7ef8a23a..7734cc9c7d29 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -197,6 +197,7 @@ struct bonding { struct slave __rcu *primary_slave; struct bond_up_slave __rcu *slave_arr; /* Array of usable slaves */ bool force_primary; + u32 nest_level; s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ int (*recv_probe)(const struct sk_buff *, struct bonding *, struct slave *); -- GitLab From 832978fced8c531ac2366c04a7d5a1124a631b0d Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 25 Apr 2018 11:33:08 -0700 Subject: [PATCH 306/855] tcp: ignore Fast Open on repair mode [ Upstream commit 16ae6aa1705299789f71fdea59bfb119c1fbd9c0 ] The TCP repair sequence of operation is to first set the socket in repair mode, then inject the TCP stats into the socket with repair socket options, then call connect() to re-activate the socket. The connect syscall simply returns and set state to ESTABLISHED mode. As a result Fast Open is meaningless for TCP repair. However allowing sendto() system call with MSG_FASTOPEN flag half-way during the repair operation could unexpectedly cause data to be sent, before the operation finishes changing the internal TCP stats (e.g. MSS). This in turn triggers TCP warnings on inconsistent packet accounting. The fix is to simply disallow Fast Open operation once the socket is in the repair mode. Reported-by: syzbot Signed-off-by: Yuchung Cheng Reviewed-by: Neal Cardwell Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 6f501c9deaae..84ffebf0192d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1118,7 +1118,7 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) lock_sock(sk); flags = msg->msg_flags; - if (flags & MSG_FASTOPEN) { + if ((flags & MSG_FASTOPEN) && !tp->repair) { err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size); if (err == -EINPROGRESS && copied_syn > 0) goto out; -- GitLab From db869e7dd670f2991030b226d44e5de3a82987b1 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Wed, 2 May 2018 13:45:12 +0800 Subject: [PATCH 307/855] sctp: fix the issue that the cookie-ack with auth can't get processed [ Upstream commit ce402f044e4e432c296f90eaabb8dbe8f3624391 ] When auth is enabled for cookie-ack chunk, in sctp_inq_pop, sctp processes auth chunk first, then continues to the next chunk in this packet if chunk_end + chunk_hdr size < skb_tail_pointer(). Otherwise, it will go to the next packet or discard this chunk. However, it missed the fact that cookie-ack chunk's size is equal to chunk_hdr size, which couldn't match that check, and thus this chunk would not get processed. This patch fixes it by changing the check to chunk_end + chunk_hdr size <= skb_tail_pointer(). Fixes: 26b87c788100 ("net: sctp: fix remote memory pressure from excessive queueing") Signed-off-by: Xin Long Acked-by: Neil Horman Acked-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/inqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index f731de3e8428..e06083c53f57 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -217,7 +217,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); chunk->subh.v = NULL; /* Subheader is no longer valid. */ - if (chunk->chunk_end + sizeof(sctp_chunkhdr_t) < + if (chunk->chunk_end + sizeof(sctp_chunkhdr_t) <= skb_tail_pointer(chunk->skb)) { /* This is not a singleton */ chunk->singleton = 0; -- GitLab From 0e67ad52f9d181411918546f64f2c694dca53bbf Mon Sep 17 00:00:00 2001 From: Xin Long Date: Sat, 5 May 2018 14:59:47 +0800 Subject: [PATCH 308/855] sctp: delay the authentication for the duplicated cookie-echo chunk [ Upstream commit 59d8d4434f429b4fa8a346fd889058bda427a837 ] Now sctp only delays the authentication for the normal cookie-echo chunk by setting chunk->auth_chunk in sctp_endpoint_bh_rcv(). But for the duplicated one with auth, in sctp_assoc_bh_rcv(), it does authentication first based on the old asoc, which will definitely fail due to the different auth info in the old asoc. The duplicated cookie-echo chunk will create a new asoc with the auth info from this chunk, and the authentication should also be done with the new asoc's auth info for all of the collision 'A', 'B' and 'D'. Otherwise, the duplicated cookie-echo chunk with auth will never pass the authentication and create the new connection. This issue exists since very beginning, and this fix is to make sctp_assoc_bh_rcv() follow the way sctp_endpoint_bh_rcv() does for the normal cookie-echo chunk to delay the authentication. While at it, remove the unused params from sctp_sf_authenticate() and define sctp_auth_chunk_verify() used for all the places that do the delayed authentication. v1->v2: fix the typo in changelog as Marcelo noticed. Acked-by: Marcelo Ricardo Leitner Signed-off-by: Xin Long Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/associola.c | 30 +++++++++++++- net/sctp/sm_statefuns.c | 87 +++++++++++++++++++++++------------------ 2 files changed, 77 insertions(+), 40 deletions(-) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index f10d3397f917..738c55e994c4 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1006,9 +1006,10 @@ static void sctp_assoc_bh_rcv(struct work_struct *work) struct sctp_endpoint *ep; struct sctp_chunk *chunk; struct sctp_inq *inqueue; - int state; sctp_subtype_t subtype; + int first_time = 1; /* is this the first time through the loop */ int error = 0; + int state; /* The association should be held so we should be safe. */ ep = asoc->ep; @@ -1019,6 +1020,30 @@ static void sctp_assoc_bh_rcv(struct work_struct *work) state = asoc->state; subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); + /* If the first chunk in the packet is AUTH, do special + * processing specified in Section 6.3 of SCTP-AUTH spec + */ + if (first_time && subtype.chunk == SCTP_CID_AUTH) { + struct sctp_chunkhdr *next_hdr; + + next_hdr = sctp_inq_peek(inqueue); + if (!next_hdr) + goto normal; + + /* If the next chunk is COOKIE-ECHO, skip the AUTH + * chunk while saving a pointer to it so we can do + * Authentication later (during cookie-echo + * processing). + */ + if (next_hdr->type == SCTP_CID_COOKIE_ECHO) { + chunk->auth_chunk = skb_clone(chunk->skb, + GFP_ATOMIC); + chunk->auth = 1; + continue; + } + } + +normal: /* SCTP-AUTH, Section 6.3: * The receiver has a list of chunk types which it expects * to be received only after an AUTH-chunk. This list has @@ -1057,6 +1082,9 @@ static void sctp_assoc_bh_rcv(struct work_struct *work) /* If there is an error on chunk, discard this packet. */ if (error && chunk) chunk->pdiscard = 1; + + if (first_time) + first_time = 0; } sctp_association_put(asoc); } diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 07f8b53c3bf1..bfd068679710 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -144,10 +144,8 @@ static sctp_disposition_t sctp_sf_violation_chunk( void *arg, sctp_cmd_seq_t *commands); -static sctp_ierror_t sctp_sf_authenticate(struct net *net, - const struct sctp_endpoint *ep, +static sctp_ierror_t sctp_sf_authenticate( const struct sctp_association *asoc, - const sctp_subtype_t type, struct sctp_chunk *chunk); static sctp_disposition_t __sctp_sf_do_9_1_abort(struct net *net, @@ -615,6 +613,38 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(struct net *net, return SCTP_DISPOSITION_CONSUME; } +static bool sctp_auth_chunk_verify(struct net *net, struct sctp_chunk *chunk, + const struct sctp_association *asoc) +{ + struct sctp_chunk auth; + + if (!chunk->auth_chunk) + return true; + + /* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo + * is supposed to be authenticated and we have to do delayed + * authentication. We've just recreated the association using + * the information in the cookie and now it's much easier to + * do the authentication. + */ + + /* Make sure that we and the peer are AUTH capable */ + if (!net->sctp.auth_enable || !asoc->peer.auth_capable) + return false; + + /* set-up our fake chunk so that we can process it */ + auth.skb = chunk->auth_chunk; + auth.asoc = chunk->asoc; + auth.sctp_hdr = chunk->sctp_hdr; + auth.chunk_hdr = (struct sctp_chunkhdr *) + skb_push(chunk->auth_chunk, + sizeof(struct sctp_chunkhdr)); + skb_pull(chunk->auth_chunk, sizeof(struct sctp_chunkhdr)); + auth.transport = chunk->transport; + + return sctp_sf_authenticate(asoc, &auth) == SCTP_IERROR_NO_ERROR; +} + /* * Respond to a normal COOKIE ECHO chunk. * We are the side that is being asked for an association. @@ -751,36 +781,9 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net, if (error) goto nomem_init; - /* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo - * is supposed to be authenticated and we have to do delayed - * authentication. We've just recreated the association using - * the information in the cookie and now it's much easier to - * do the authentication. - */ - if (chunk->auth_chunk) { - struct sctp_chunk auth; - sctp_ierror_t ret; - - /* Make sure that we and the peer are AUTH capable */ - if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) { - sctp_association_free(new_asoc); - return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); - } - - /* set-up our fake chunk so that we can process it */ - auth.skb = chunk->auth_chunk; - auth.asoc = chunk->asoc; - auth.sctp_hdr = chunk->sctp_hdr; - auth.chunk_hdr = (sctp_chunkhdr_t *)skb_push(chunk->auth_chunk, - sizeof(sctp_chunkhdr_t)); - skb_pull(chunk->auth_chunk, sizeof(sctp_chunkhdr_t)); - auth.transport = chunk->transport; - - ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth); - if (ret != SCTP_IERROR_NO_ERROR) { - sctp_association_free(new_asoc); - return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); - } + if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) { + sctp_association_free(new_asoc); + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); } repl = sctp_make_cookie_ack(new_asoc, chunk); @@ -1717,13 +1720,15 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(struct net *net, GFP_ATOMIC)) goto nomem; + if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) + return SCTP_DISPOSITION_DISCARD; + /* Make sure no new addresses are being added during the * restart. Though this is a pretty complicated attack * since you'd have to get inside the cookie. */ - if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) { + if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) return SCTP_DISPOSITION_CONSUME; - } /* If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes * the peer has restarted (Action A), it MUST NOT setup a new @@ -1828,6 +1833,9 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(struct net *net, GFP_ATOMIC)) goto nomem; + if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) + return SCTP_DISPOSITION_DISCARD; + /* Update the content of current association. */ sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, @@ -1920,6 +1928,9 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(struct net *net, * a COOKIE ACK. */ + if (!sctp_auth_chunk_verify(net, chunk, asoc)) + return SCTP_DISPOSITION_DISCARD; + /* Don't accidentally move back into established state. */ if (asoc->state < SCTP_STATE_ESTABLISHED) { sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, @@ -3981,10 +3992,8 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast( * * The return value is the disposition of the chunk. */ -static sctp_ierror_t sctp_sf_authenticate(struct net *net, - const struct sctp_endpoint *ep, +static sctp_ierror_t sctp_sf_authenticate( const struct sctp_association *asoc, - const sctp_subtype_t type, struct sctp_chunk *chunk) { struct sctp_authhdr *auth_hdr; @@ -4083,7 +4092,7 @@ sctp_disposition_t sctp_sf_eat_auth(struct net *net, commands); auth_hdr = (struct sctp_authhdr *)chunk->skb->data; - error = sctp_sf_authenticate(net, ep, asoc, type, chunk); + error = sctp_sf_authenticate(asoc, chunk); switch (error) { case SCTP_IERROR_AUTH_BAD_HMAC: /* Generate the ERROR chunk and discard the rest -- GitLab From 8c5e7b071be1b530fc9ce574c4ccd310387ad034 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 2 Sep 2017 23:13:55 +0300 Subject: [PATCH 309/855] serial: sccnxp: Fix error handling in sccnxp_probe() commit c91261437985d481c472639d4397931d77f5d4e9 upstream. sccnxp_probe() returns result of regulator_disable() that may lead to returning zero, while device is not properly initialized. Also the driver enables clocks, but it does not disable it. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sccnxp.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index cdd2f942317c..b9c7a904c1ea 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -889,7 +889,16 @@ static int sccnxp_probe(struct platform_device *pdev) goto err_out; uartclk = 0; } else { - clk_prepare_enable(clk); + ret = clk_prepare_enable(clk); + if (ret) + goto err_out; + + ret = devm_add_action_or_reset(&pdev->dev, + (void(*)(void *))clk_disable_unprepare, + clk); + if (ret) + goto err_out; + uartclk = clk_get_rate(clk); } @@ -988,7 +997,7 @@ static int sccnxp_probe(struct platform_device *pdev) uart_unregister_driver(&s->uart); err_out: if (!IS_ERR(s->regulator)) - return regulator_disable(s->regulator); + regulator_disable(s->regulator); return ret; } -- GitLab From 81da9f87ad9d5b77014f0d11946ffbc887bdec70 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 24 Aug 2017 09:31:05 +0200 Subject: [PATCH 310/855] futex: Remove duplicated code and fix undefined behaviour commit 30d6e0a4190d37740e9447e4e4815f06992dd8c3 upstream. There is code duplicated over all architecture's headers for futex_atomic_op_inuser. Namely op decoding, access_ok check for uaddr, and comparison of the result. Remove this duplication and leave up to the arches only the needed assembly which is now in arch_futex_atomic_op_inuser. This effectively distributes the Will Deacon's arm64 fix for undefined behaviour reported by UBSAN to all architectures. The fix was done in commit 5f16a046f8e1 (arm64: futex: Fix undefined behaviour with FUTEX_OP_OPARG_SHIFT usage). Look there for an example dump. And as suggested by Thomas, check for negative oparg too, because it was also reported to cause undefined behaviour report. Note that s390 removed access_ok check in d12a29703 ("s390/uaccess: remove pointless access_ok() checks") as access_ok there returns true. We introduce it back to the helper for the sake of simplicity (it gets optimized away anyway). Signed-off-by: Jiri Slaby Signed-off-by: Thomas Gleixner Acked-by: Russell King Acked-by: Michael Ellerman (powerpc) Acked-by: Heiko Carstens [s390] Acked-by: Chris Metcalf [for tile] Reviewed-by: Darren Hart (VMware) Reviewed-by: Will Deacon [core/arm64] Cc: linux-mips@linux-mips.org Cc: Rich Felker Cc: linux-ia64@vger.kernel.org Cc: linux-sh@vger.kernel.org Cc: peterz@infradead.org Cc: Benjamin Herrenschmidt Cc: Max Filippov Cc: Paul Mackerras Cc: sparclinux@vger.kernel.org Cc: Jonas Bonn Cc: linux-s390@vger.kernel.org Cc: linux-arch@vger.kernel.org Cc: Yoshinori Sato Cc: linux-hexagon@vger.kernel.org Cc: Helge Deller Cc: "James E.J. Bottomley" Cc: Catalin Marinas Cc: Matt Turner Cc: linux-snps-arc@lists.infradead.org Cc: Fenghua Yu Cc: Arnd Bergmann Cc: linux-xtensa@linux-xtensa.org Cc: Stefan Kristiansson Cc: openrisc@lists.librecores.org Cc: Ivan Kokshaysky Cc: Stafford Horne Cc: linux-arm-kernel@lists.infradead.org Cc: Richard Henderson Cc: Chris Zankel Cc: Michal Simek Cc: Tony Luck Cc: linux-parisc@vger.kernel.org Cc: Vineet Gupta Cc: Ralf Baechle Cc: Richard Kuo Cc: linux-alpha@vger.kernel.org Cc: Martin Schwidefsky Cc: linuxppc-dev@lists.ozlabs.org Cc: "David S. Miller" Link: http://lkml.kernel.org/r/20170824073105.3901-1-jslaby@suse.cz Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/alpha/include/asm/futex.h | 26 +++------------ arch/arc/include/asm/futex.h | 40 +++-------------------- arch/arm/include/asm/futex.h | 26 +++------------ arch/arm64/include/asm/futex.h | 27 +++------------- arch/frv/include/asm/futex.h | 3 +- arch/frv/kernel/futex.c | 27 +++------------- arch/hexagon/include/asm/futex.h | 38 +++------------------- arch/ia64/include/asm/futex.h | 25 +++------------ arch/microblaze/include/asm/futex.h | 38 +++------------------- arch/mips/include/asm/futex.h | 25 +++------------ arch/parisc/include/asm/futex.h | 26 +++------------ arch/powerpc/include/asm/futex.h | 26 +++------------ arch/s390/include/asm/futex.h | 23 +++---------- arch/sh/include/asm/futex.h | 26 +++------------ arch/sparc/include/asm/futex_64.h | 26 +++------------ arch/tile/include/asm/futex.h | 40 +++-------------------- arch/x86/include/asm/futex.h | 40 +++-------------------- arch/xtensa/include/asm/futex.h | 27 +++------------- include/asm-generic/futex.h | 50 ++++++----------------------- kernel/futex.c | 39 ++++++++++++++++++++++ 20 files changed, 126 insertions(+), 472 deletions(-) diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h index f939794363ac..56474690e685 100644 --- a/arch/alpha/include/asm/futex.h +++ b/arch/alpha/include/asm/futex.h @@ -29,18 +29,10 @@ : "r" (uaddr), "r"(oparg) \ : "memory") -static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, + u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; pagefault_disable(); @@ -66,17 +58,9 @@ static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/arch/arc/include/asm/futex.h b/arch/arc/include/asm/futex.h index 11e1b1f3acda..eb887dd13e74 100644 --- a/arch/arc/include/asm/futex.h +++ b/arch/arc/include/asm/futex.h @@ -73,20 +73,11 @@ #endif -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, + u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - #ifndef CONFIG_ARC_HAS_LLSC preempt_disable(); /* to guarantee atomic r-m-w of futex op */ #endif @@ -118,30 +109,9 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) preempt_enable(); #endif - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: - ret = (oldval == cmparg); - break; - case FUTEX_OP_CMP_NE: - ret = (oldval != cmparg); - break; - case FUTEX_OP_CMP_LT: - ret = (oldval < cmparg); - break; - case FUTEX_OP_CMP_GE: - ret = (oldval >= cmparg); - break; - case FUTEX_OP_CMP_LE: - ret = (oldval <= cmparg); - break; - case FUTEX_OP_CMP_GT: - ret = (oldval > cmparg); - break; - default: - ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h index 6795368ad023..cc414382dab4 100644 --- a/arch/arm/include/asm/futex.h +++ b/arch/arm/include/asm/futex.h @@ -128,20 +128,10 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, #endif /* !SMP */ static inline int -futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret, tmp; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; - #ifndef CONFIG_SMP preempt_disable(); #endif @@ -172,17 +162,9 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) preempt_enable(); #endif - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index 4e5f36a804b4..2a5090fb9113 100644 --- a/arch/arm64/include/asm/futex.h +++ b/arch/arm64/include/asm/futex.h @@ -51,20 +51,9 @@ : "memory") static inline int -futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *_uaddr) +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (int)(encoded_op << 8) >> 20; - int cmparg = (int)(encoded_op << 20) >> 20; int oldval = 0, ret, tmp; - u32 __user *uaddr = __uaccess_mask_ptr(_uaddr); - - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1U << (oparg & 0x1f); - - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; pagefault_disable(); @@ -95,17 +84,9 @@ futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *_uaddr) pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/arch/frv/include/asm/futex.h b/arch/frv/include/asm/futex.h index 4bea27f50a7a..2702bd802d44 100644 --- a/arch/frv/include/asm/futex.h +++ b/arch/frv/include/asm/futex.h @@ -7,7 +7,8 @@ #include #include -extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr); +extern int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, + u32 __user *uaddr); static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, diff --git a/arch/frv/kernel/futex.c b/arch/frv/kernel/futex.c index d155ca9e5098..37f7b2bf7f73 100644 --- a/arch/frv/kernel/futex.c +++ b/arch/frv/kernel/futex.c @@ -186,20 +186,10 @@ static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr, int *_o /* * do the futex operations */ -int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) +int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; - pagefault_disable(); switch (op) { @@ -225,18 +215,9 @@ int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; break; - } - } + if (!ret) + *oval = oldval; return ret; -} /* end futex_atomic_op_inuser() */ +} /* end arch_futex_atomic_op_inuser() */ diff --git a/arch/hexagon/include/asm/futex.h b/arch/hexagon/include/asm/futex.h index 7e597f8434da..c607b77c8215 100644 --- a/arch/hexagon/include/asm/futex.h +++ b/arch/hexagon/include/asm/futex.h @@ -31,18 +31,9 @@ static inline int -futex_atomic_op_inuser(int encoded_op, int __user *uaddr) +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; pagefault_disable(); @@ -72,30 +63,9 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr) pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: - ret = (oldval == cmparg); - break; - case FUTEX_OP_CMP_NE: - ret = (oldval != cmparg); - break; - case FUTEX_OP_CMP_LT: - ret = (oldval < cmparg); - break; - case FUTEX_OP_CMP_GE: - ret = (oldval >= cmparg); - break; - case FUTEX_OP_CMP_LE: - ret = (oldval <= cmparg); - break; - case FUTEX_OP_CMP_GT: - ret = (oldval > cmparg); - break; - default: - ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/arch/ia64/include/asm/futex.h b/arch/ia64/include/asm/futex.h index 76acbcd5c060..6d67dc1eaf2b 100644 --- a/arch/ia64/include/asm/futex.h +++ b/arch/ia64/include/asm/futex.h @@ -45,18 +45,9 @@ do { \ } while (0) static inline int -futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; pagefault_disable(); @@ -84,17 +75,9 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/arch/microblaze/include/asm/futex.h b/arch/microblaze/include/asm/futex.h index 01848f056f43..a9dad9e5e132 100644 --- a/arch/microblaze/include/asm/futex.h +++ b/arch/microblaze/include/asm/futex.h @@ -29,18 +29,9 @@ }) static inline int -futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; pagefault_disable(); @@ -66,30 +57,9 @@ futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: - ret = (oldval == cmparg); - break; - case FUTEX_OP_CMP_NE: - ret = (oldval != cmparg); - break; - case FUTEX_OP_CMP_LT: - ret = (oldval < cmparg); - break; - case FUTEX_OP_CMP_GE: - ret = (oldval >= cmparg); - break; - case FUTEX_OP_CMP_LE: - ret = (oldval <= cmparg); - break; - case FUTEX_OP_CMP_GT: - ret = (oldval > cmparg); - break; - default: - ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h index 1de190bdfb9c..a9e61ea54ca9 100644 --- a/arch/mips/include/asm/futex.h +++ b/arch/mips/include/asm/futex.h @@ -83,18 +83,9 @@ } static inline int -futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; pagefault_disable(); @@ -125,17 +116,9 @@ futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h index ac8bd586ace8..06a1a883c72f 100644 --- a/arch/parisc/include/asm/futex.h +++ b/arch/parisc/include/asm/futex.h @@ -32,22 +32,12 @@ _futex_spin_unlock_irqrestore(u32 __user *uaddr, unsigned long int *flags) } static inline int -futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) { unsigned long int flags; - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval, ret; u32 tmp; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(*uaddr))) - return -EFAULT; - _futex_spin_lock_irqsave(uaddr, &flags); pagefault_disable(); @@ -85,17 +75,9 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) pagefault_enable(); _futex_spin_unlock_irqrestore(uaddr, &flags); - if (ret == 0) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h index 2a9cf845473b..f4c7467f7465 100644 --- a/arch/powerpc/include/asm/futex.h +++ b/arch/powerpc/include/asm/futex.h @@ -31,18 +31,10 @@ : "b" (uaddr), "i" (-EFAULT), "r" (oparg) \ : "cr0", "memory") -static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, + u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; pagefault_disable(); @@ -68,17 +60,9 @@ static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h index a4811aa0304d..8f8eec9e1198 100644 --- a/arch/s390/include/asm/futex.h +++ b/arch/s390/include/asm/futex.h @@ -21,17 +21,12 @@ : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \ "m" (*uaddr) : "cc"); -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, + u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, newval, ret; load_kernel_asce(); - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; pagefault_disable(); switch (op) { @@ -60,17 +55,9 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) } pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h index d0078747d308..8f8cf941a8cd 100644 --- a/arch/sh/include/asm/futex.h +++ b/arch/sh/include/asm/futex.h @@ -27,21 +27,12 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval); } -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) +static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, + u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - u32 oparg = (encoded_op << 8) >> 20; - u32 cmparg = (encoded_op << 20) >> 20; u32 oldval, newval, prev; int ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; - pagefault_disable(); do { @@ -80,17 +71,8 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = ((int)oldval < (int)cmparg); break; - case FUTEX_OP_CMP_GE: ret = ((int)oldval >= (int)cmparg); break; - case FUTEX_OP_CMP_LE: ret = ((int)oldval <= (int)cmparg); break; - case FUTEX_OP_CMP_GT: ret = ((int)oldval > (int)cmparg); break; - default: ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; return ret; } diff --git a/arch/sparc/include/asm/futex_64.h b/arch/sparc/include/asm/futex_64.h index 4e899b0dabf7..1cfd89d92208 100644 --- a/arch/sparc/include/asm/futex_64.h +++ b/arch/sparc/include/asm/futex_64.h @@ -29,22 +29,14 @@ : "r" (uaddr), "r" (oparg), "i" (-EFAULT) \ : "memory") -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, + u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret, tem; - if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))) - return -EFAULT; if (unlikely((((unsigned long) uaddr) & 0x3UL))) return -EINVAL; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - pagefault_disable(); switch (op) { @@ -69,17 +61,9 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h index e64a1b75fc38..83c1e639b411 100644 --- a/arch/tile/include/asm/futex.h +++ b/arch/tile/include/asm/futex.h @@ -106,12 +106,9 @@ lock = __atomic_hashed_lock((int __force *)uaddr) #endif -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) +static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, + u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int uninitialized_var(val), ret; __futex_prolog(); @@ -119,12 +116,6 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) /* The 32-bit futex code makes this assumption, so validate it here. */ BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int)); - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; - pagefault_disable(); switch (op) { case FUTEX_OP_SET: @@ -148,30 +139,9 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) } pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: - ret = (val == cmparg); - break; - case FUTEX_OP_CMP_NE: - ret = (val != cmparg); - break; - case FUTEX_OP_CMP_LT: - ret = (val < cmparg); - break; - case FUTEX_OP_CMP_GE: - ret = (val >= cmparg); - break; - case FUTEX_OP_CMP_LE: - ret = (val <= cmparg); - break; - case FUTEX_OP_CMP_GT: - ret = (val > cmparg); - break; - default: - ret = -ENOSYS; - } - } + if (!ret) + *oval = val; + return ret; } diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h index b4c1f5453436..f4dc9b63bdda 100644 --- a/arch/x86/include/asm/futex.h +++ b/arch/x86/include/asm/futex.h @@ -41,20 +41,11 @@ "+m" (*uaddr), "=&r" (tem) \ : "r" (oparg), "i" (-EFAULT), "1" (0)) -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, + u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret, tem; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; - pagefault_disable(); switch (op) { @@ -80,30 +71,9 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: - ret = (oldval == cmparg); - break; - case FUTEX_OP_CMP_NE: - ret = (oldval != cmparg); - break; - case FUTEX_OP_CMP_LT: - ret = (oldval < cmparg); - break; - case FUTEX_OP_CMP_GE: - ret = (oldval >= cmparg); - break; - case FUTEX_OP_CMP_LE: - ret = (oldval <= cmparg); - break; - case FUTEX_OP_CMP_GT: - ret = (oldval > cmparg); - break; - default: - ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h index 72bfc1cbc2b5..5bfbc1c401d4 100644 --- a/arch/xtensa/include/asm/futex.h +++ b/arch/xtensa/include/asm/futex.h @@ -44,18 +44,10 @@ : "r" (uaddr), "I" (-EFAULT), "r" (oparg) \ : "memory") -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, + u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; #if !XCHAL_HAVE_S32C1I return -ENOSYS; @@ -89,19 +81,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) pagefault_enable(); - if (ret) - return ret; + if (!ret) + *oval = oldval; - switch (cmp) { - case FUTEX_OP_CMP_EQ: return (oldval == cmparg); - case FUTEX_OP_CMP_NE: return (oldval != cmparg); - case FUTEX_OP_CMP_LT: return (oldval < cmparg); - case FUTEX_OP_CMP_GE: return (oldval >= cmparg); - case FUTEX_OP_CMP_LE: return (oldval <= cmparg); - case FUTEX_OP_CMP_GT: return (oldval > cmparg); - } - - return -ENOSYS; + return ret; } static inline int diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h index bf2d34c9d804..f0d8b1c51343 100644 --- a/include/asm-generic/futex.h +++ b/include/asm-generic/futex.h @@ -13,7 +13,7 @@ */ /** - * futex_atomic_op_inuser() - Atomic arithmetic operation with constant + * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant * argument and comparison of the previous * futex value with another constant. * @@ -25,18 +25,11 @@ * <0 - On error */ static inline int -futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) +arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval, ret; u32 tmp; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - preempt_disable(); pagefault_disable(); @@ -74,17 +67,9 @@ futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) pagefault_enable(); preempt_enable(); - if (ret == 0) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } + if (ret == 0) + *oval = oldval; + return ret; } @@ -126,18 +111,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, #else static inline int -futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) +arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) { - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; pagefault_disable(); @@ -153,17 +129,9 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) pagefault_enable(); - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } + if (!ret) + *oval = oldval; + return ret; } diff --git a/kernel/futex.c b/kernel/futex.c index bb2265ae5cbc..401d99a4e3cb 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1458,6 +1458,45 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset) return ret; } +static int futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr) +{ + unsigned int op = (encoded_op & 0x70000000) >> 28; + unsigned int cmp = (encoded_op & 0x0f000000) >> 24; + int oparg = sign_extend32((encoded_op & 0x00fff000) >> 12, 12); + int cmparg = sign_extend32(encoded_op & 0x00000fff, 12); + int oldval, ret; + + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) { + if (oparg < 0 || oparg > 31) + return -EINVAL; + oparg = 1 << oparg; + } + + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) + return -EFAULT; + + ret = arch_futex_atomic_op_inuser(op, oparg, &oldval, uaddr); + if (ret) + return ret; + + switch (cmp) { + case FUTEX_OP_CMP_EQ: + return oldval == cmparg; + case FUTEX_OP_CMP_NE: + return oldval != cmparg; + case FUTEX_OP_CMP_LT: + return oldval < cmparg; + case FUTEX_OP_CMP_GE: + return oldval >= cmparg; + case FUTEX_OP_CMP_LE: + return oldval <= cmparg; + case FUTEX_OP_CMP_GT: + return oldval > cmparg; + default: + return -ENOSYS; + } +} + /* * Wake up all waiters hashed on the physical page that is mapped * to this virtual address: -- GitLab From 3e54e1c3beecce02cf1256eabb8f71f1414be3aa Mon Sep 17 00:00:00 2001 From: Antony Antony Date: Thu, 7 Dec 2017 21:54:27 +0100 Subject: [PATCH 311/855] xfrm: fix xfrm_do_migrate() with AEAD e.g(AES-GCM) commit 75bf50f4aaa1c78d769d854ab3d975884909e4fb upstream. copy geniv when cloning the xfrm state. x->geniv was not copied to the new state and migration would fail. xfrm_do_migrate .. xfrm_state_clone() .. .. esp_init_aead() crypto_alloc_aead() crypto_alloc_tfm() crypto_find_alg() return EAGAIN and failed Signed-off-by: Antony Antony Signed-off-by: Steffen Klassert Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_state.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 6f5635770d6a..71a94e549301 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1197,6 +1197,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig) if (orig->aead) { x->aead = xfrm_algo_aead_clone(orig->aead); + x->geniv = orig->geniv; if (!x->aead) goto error; } -- GitLab From 117dd2165ee791b5df888445d94b75c76923b44b Mon Sep 17 00:00:00 2001 From: Vasily Averin Date: Thu, 2 Nov 2017 13:03:42 +0300 Subject: [PATCH 312/855] lockd: lost rollback of set_grace_period() in lockd_down_net() commit 3a2b19d1ee5633f76ae8a88da7bc039a5d1732aa upstream. Commit efda760fe95ea ("lockd: fix lockd shutdown race") is incorrect, it removes lockd_manager and disarm grace_period_end for init_net only. If nfsd was started from another net namespace lockd_up_net() calls set_grace_period() that adds lockd_manager into per-netns list and queues grace_period_end delayed work. These action should be reverted in lockd_down_net(). Otherwise it can lead to double list_add on after restart nfsd in netns, and to use-after-free if non-disarmed delayed work will be executed after netns destroy. Fixes: efda760fe95e ("lockd: fix lockd shutdown race") Cc: stable@vger.kernel.org Signed-off-by: Vasily Averin Signed-off-by: J. Bruce Fields Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- fs/lockd/svc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 85135df0eb34..c19123dcd1a4 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -274,6 +274,8 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net) if (ln->nlmsvc_users) { if (--ln->nlmsvc_users == 0) { nlm_shutdown_hosts_net(net); + cancel_delayed_work_sync(&ln->grace_period_end); + locks_end_grace(&ln->lockd_manager); svc_shutdown_net(serv, net); dprintk("lockd_down_net: per-net data destroyed; net=%p\n", net); } -- GitLab From eddf1b6325fee140bbe472f0a0c916053bec7090 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 17 May 2018 11:47:39 +0200 Subject: [PATCH 313/855] Revert "ARM: dts: imx6qdl-wandboard: Fix audio channel swap" This reverts commit c53c4ad96242e868da492f424535bf4b45f80503 which was commit 79935915300c5eb88a0e94fa9148a7505c14a02a upstream. As Ben points out: This depends on: commit 570c70a60f53ca737ead4e5966c446bf0d39fac9 Author: Fabio Estevam Date: Wed Apr 5 11:32:34 2017 -0300 ASoC: sgtl5000: Allow LRCLK pad drive strength to be changed which did not show up until 4.13, so this makes no sense to have in this stable branch. Reported-by: Ben Hutchings Cc: Fabio Estevam Cc: Shawn Guo Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/imx6qdl-wandboard.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi index 47c955458a77..2b9c2be436f9 100644 --- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi +++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi @@ -88,7 +88,6 @@ clocks = <&clks IMX6QDL_CLK_CKO>; VDDA-supply = <®_2p5v>; VDDIO-supply = <®_3p3v>; - lrclk-strength = <3>; }; }; -- GitLab From f21ad10b235b4d4399c5b3653ffbf9a33c69647d Mon Sep 17 00:00:00 2001 From: James Chapman Date: Wed, 3 Jan 2018 22:48:05 +0000 Subject: [PATCH 314/855] l2tp: revert "l2tp: fix missing print session offset info" commit de3b58bc359a861d5132300f53f95e83f71954b3 upstream. Revert commit 820da5357572 ("l2tp: fix missing print session offset info"). The peer_offset parameter is removed. Signed-off-by: James Chapman Signed-off-by: David S. Miller Cc: Guillaume Nault Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_netlink.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index ce1238492c0f..ee03bc866d1b 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -750,8 +750,6 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl if ((session->ifname[0] && nla_put_string(skb, L2TP_ATTR_IFNAME, session->ifname)) || - (session->offset && - nla_put_u16(skb, L2TP_ATTR_OFFSET, session->offset)) || (session->cookie_len && nla_put(skb, L2TP_ATTR_COOKIE, session->cookie_len, &session->cookie[0])) || -- GitLab From 61e8f6676e598f173a540a27ce8ca09675a68535 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 23 Aug 2017 14:41:50 -0700 Subject: [PATCH 315/855] nfp: TX time stamp packets before HW doorbell is rung commit 46f1c52e66dbc0d7a99f7c2a3c9debb497fe7b7b upstream. TX completion may happen any time after HW queue was kicked. We can't access the skb afterwards. Move the time stamping before ringing the doorbell. Fixes: 4c3523623dc0 ("net: add driver for Netronome NFP4000/NFP6000 NIC VFs") Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller Cc: Willy Tarreau Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 4ca82bd8c4f0..eee6e59e6cf3 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -854,6 +854,8 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) netdev_tx_sent_queue(nd_q, txbuf->real_len); + skb_tx_timestamp(skb); + tx_ring->wr_p += nr_frags + 1; if (nfp_net_tx_ring_should_stop(tx_ring)) nfp_net_tx_ring_stop(nd_q, tx_ring); @@ -866,8 +868,6 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) tx_ring->wr_ptr_add = 0; } - skb_tx_timestamp(skb); - return NETDEV_TX_OK; err_unmap: -- GitLab From 6f1abf8628b750905606996fd5ff5ea22d149238 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 11 May 2018 08:11:44 +0200 Subject: [PATCH 316/855] proc: do not access cmdline nor environ from file-backed areas commit 7f7ccc2ccc2e70c6054685f5e3522efa81556830 upstream. proc_pid_cmdline_read() and environ_read() directly access the target process' VM to retrieve the command line and environment. If this process remaps these areas onto a file via mmap(), the requesting process may experience various issues such as extra delays if the underlying device is slow to respond. Let's simply refuse to access file-backed areas in these functions. For this we add a new FOLL_ANON gup flag that is passed to all calls to access_remote_vm(). The code already takes care of such failures (including unmapped areas). Accesses via /proc/pid/mem were not changed though. This was assigned CVE-2018-1120. Note for stable backports: the patch may apply to kernels prior to 4.11 but silently miss one location; it must be checked that no call to access_remote_vm() keeps zero as the last argument. Reported-by: Qualys Security Advisory Cc: Linus Torvalds Cc: Andy Lutomirski Cc: Oleg Nesterov Cc: stable@vger.kernel.org Signed-off-by: Willy Tarreau Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/base.c | 10 +++++----- include/linux/mm.h | 1 + mm/gup.c | 3 +++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index e67fec3c9856..3fec83ba75fa 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -252,7 +252,7 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, * Inherently racy -- command line shares address space * with code and data. */ - rv = access_remote_vm(mm, arg_end - 1, &c, 1, 0); + rv = access_remote_vm(mm, arg_end - 1, &c, 1, FOLL_ANON); if (rv <= 0) goto out_free_page; @@ -270,7 +270,7 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, int nr_read; _count = min3(count, len, PAGE_SIZE); - nr_read = access_remote_vm(mm, p, page, _count, 0); + nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON); if (nr_read < 0) rv = nr_read; if (nr_read <= 0) @@ -305,7 +305,7 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, bool final; _count = min3(count, len, PAGE_SIZE); - nr_read = access_remote_vm(mm, p, page, _count, 0); + nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON); if (nr_read < 0) rv = nr_read; if (nr_read <= 0) @@ -354,7 +354,7 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, bool final; _count = min3(count, len, PAGE_SIZE); - nr_read = access_remote_vm(mm, p, page, _count, 0); + nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON); if (nr_read < 0) rv = nr_read; if (nr_read <= 0) @@ -970,7 +970,7 @@ static ssize_t environ_read(struct file *file, char __user *buf, max_len = min_t(size_t, PAGE_SIZE, count); this_len = min(max_len, this_len); - retval = access_remote_vm(mm, (env_start + src), page, this_len, 0); + retval = access_remote_vm(mm, (env_start + src), page, this_len, FOLL_ANON); if (retval <= 0) { ret = retval; diff --git a/include/linux/mm.h b/include/linux/mm.h index 4a07ff4f38e1..493d07931ea5 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2246,6 +2246,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma, #define FOLL_MLOCK 0x1000 /* lock present pages */ #define FOLL_REMOTE 0x2000 /* we are working on non-current tsk/mm */ #define FOLL_COW 0x4000 /* internal GUP flag */ +#define FOLL_ANON 0x8000 /* don't do file mappings */ typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr, void *data); diff --git a/mm/gup.c b/mm/gup.c index 6c3b4e822946..be4ccddac26f 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -430,6 +430,9 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags) if (vm_flags & (VM_IO | VM_PFNMAP)) return -EFAULT; + if (gup_flags & FOLL_ANON && !vma_is_anonymous(vma)) + return -EFAULT; + if (write) { if (!(vm_flags & VM_WRITE)) { if (!(gup_flags & FOLL_FORCE)) -- GitLab From a164009f480ecc0666bba193bdef0cea2c2a5546 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 30 Nov 2017 15:35:44 +0100 Subject: [PATCH 317/855] futex: futex_wake_op, fix sign_extend32 sign bits commit d70ef22892ed6c066e51e118b225923c9b74af34 upstream. sign_extend32 counts the sign bit parameter from 0, not from 1. So we have to use "11" for 12th bit, not "12". This mistake means we have not allowed negative op and cmp args since commit 30d6e0a4190d ("futex: Remove duplicated code and fix undefined behaviour") till now. Fixes: 30d6e0a4190d ("futex: Remove duplicated code and fix undefined behaviour") Signed-off-by: Jiri Slaby Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Darren Hart Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/futex.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index 401d99a4e3cb..c3ea6f2a6997 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1462,8 +1462,8 @@ static int futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr) { unsigned int op = (encoded_op & 0x70000000) >> 28; unsigned int cmp = (encoded_op & 0x0f000000) >> 24; - int oparg = sign_extend32((encoded_op & 0x00fff000) >> 12, 12); - int cmparg = sign_extend32(encoded_op & 0x00000fff, 12); + int oparg = sign_extend32((encoded_op & 0x00fff000) >> 12, 11); + int cmparg = sign_extend32(encoded_op & 0x00000fff, 11); int oldval, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) { -- GitLab From 04103c29b6cc1ffcf9efe167a07e882be68f8367 Mon Sep 17 00:00:00 2001 From: zhongjiang Date: Mon, 10 Jul 2017 15:53:01 -0700 Subject: [PATCH 318/855] kernel/exit.c: avoid undefined behaviour when calling wait4() commit dd83c161fbcc5d8be637ab159c0de015cbff5ba4 upstream. wait4(-2147483648, 0x20, 0, 0xdd0000) triggers: UBSAN: Undefined behaviour in kernel/exit.c:1651:9 The related calltrace is as follows: negation of -2147483648 cannot be represented in type 'int': CPU: 9 PID: 16482 Comm: zj Tainted: G B ---- ------- 3.10.0-327.53.58.71.x86_64+ #66 Hardware name: Huawei Technologies Co., Ltd. Tecal RH2285 /BC11BTSA , BIOS CTSAV036 04/27/2011 Call Trace: dump_stack+0x19/0x1b ubsan_epilogue+0xd/0x50 __ubsan_handle_negate_overflow+0x109/0x14e SyS_wait4+0x1cb/0x1e0 system_call_fastpath+0x16/0x1b Exclude the overflow to avoid the UBSAN warning. Link: http://lkml.kernel.org/r/1497264618-20212-1-git-send-email-zhongjiang@huawei.com Signed-off-by: zhongjiang Cc: Oleg Nesterov Cc: David Rientjes Cc: Aneesh Kumar K.V Cc: Kirill A. Shutemov Cc: Xishi Qiu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/exit.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/exit.c b/kernel/exit.c index 3076f3089919..6dd7ff4b337a 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1662,6 +1662,10 @@ SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr, __WNOTHREAD|__WCLONE|__WALL)) return -EINVAL; + /* -INT_MIN is not defined */ + if (upid == INT_MIN) + return -ESRCH; + if (upid == -1) type = PIDTYPE_MAX; else if (upid < 0) { -- GitLab From 6ba89b52ba6916bc7a3d390d70951e992c0ca39e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 19 May 2018 10:27:01 +0200 Subject: [PATCH 319/855] Linux 4.9.101 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 52a41396680c..7d7bda23db8f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 100 +SUBLEVEL = 101 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 46a34ac2d9f3ad9026103a17a584d5fb2720aeed Mon Sep 17 00:00:00 2001 From: Vijay Viswanath Date: Fri, 11 May 2018 18:21:16 +0530 Subject: [PATCH 320/855] mmc: core: rescan for card if deferred resume fails SD card can be removed when system is under suspend and mmc driver will not get cd-gpio irq. And because of deferred_resume feature, we will do nothing during system resume and hence cannot detect card removal event. So when we do deferred_resume (when a request is issued to mmc driver), schedule a rescan if: - Deferred_resume fails AND - Card is removable and polling is not enabled Change-Id: I8048027ad3900c1be72b65dfb4ec535780351488 Signed-off-by: Vijay Viswanath --- drivers/mmc/core/core.c | 17 ++++++++++++++++- drivers/mmc/core/sd.c | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 8700e72b3bb8..60f8a6d62d0b 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -3393,7 +3393,22 @@ int mmc_resume_bus(struct mmc_host *host) if (host->bus_ops && !host->bus_dead && host->card) { mmc_power_up(host, host->card->ocr); BUG_ON(!host->bus_ops->resume); - host->bus_ops->resume(host); + err = host->bus_ops->resume(host); + if (err) { + pr_err("%s: %s: resume failed: %d\n", + mmc_hostname(host), __func__, err); + /* + * If we have cd-gpio based detection mechanism and + * deferred resume is supported, we will not detect + * card removal event when system is suspended. So if + * resume fails after a system suspend/resume, + * schedule the work to detect card presence. + */ + if (mmc_card_is_removable(host) && + !(host->caps & MMC_CAP_NEEDS_POLL)) { + mmc_detect_change(host, 0); + } + } if (mmc_card_cmdq(host->card)) { err = mmc_cmdq_halt(host, false); if (err) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 965d1f06e231..245493ef3723 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1329,6 +1329,8 @@ static int _mmc_sd_resume(struct mmc_host *host) mmc_hostname(host), __func__, err); mmc_card_set_removed(host->card); mmc_detect_change(host, msecs_to_jiffies(200)); + } else if (err) { + goto out; } mmc_card_clr_suspended(host->card); -- GitLab From cc9091dc176692ef6fda913794ca305f0e603d36 Mon Sep 17 00:00:00 2001 From: Shubhashree Dhar Date: Thu, 10 May 2018 15:56:42 +0530 Subject: [PATCH 321/855] drm/msm: Add pointer check before dereference Add pointer check, print error message and return error value in case the pointer is NULL. Change-Id: I9b776bfce771148606548a41cab6a695fc2adfa7 Signed-off-by: Shubhashree Dhar --- drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c | 12 +++++++++- drivers/gpu/drm/msm/sde/sde_kms.c | 27 +++++++++++----------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index 32bc3eb5b655..dd917995a3e9 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -1338,10 +1338,20 @@ static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl, u32 current_read_len = 0, total_bytes_read = 0; bool short_resp = false; bool read_done = false; - u32 dlen, diff, rlen = msg->rx_len; + u32 dlen, diff, rlen; unsigned char *buff; char cmd; + struct dsi_cmd_desc *of_cmd; + if (!msg) { + pr_err("Invalid msg\n"); + rc = -EINVAL; + goto error; + } + + of_cmd = container_of(msg, struct dsi_cmd_desc, msg); + + rlen = msg->rx_len; if (msg->rx_len <= 2) { short_resp = true; rd_pkt_size = msg->rx_len; diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index b0a52a705cb5..69fd4b07dbe4 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -2664,21 +2664,22 @@ static int sde_kms_cont_splash_config(struct msm_kms *kms) mutex_lock(&dev->mode_config.mutex); connector_list = &dev->mode_config.connector_list; - list_for_each_entry(conn_iter, connector_list, head) { - /** - * SDE_KMS doesn't attach more than one encoder to - * a DSI connector. So it is safe to check only with the - * first encoder entry. Revisit this logic if we ever have - * to support continuous splash for external displays in MST - * configuration. - */ - if (conn_iter && - (conn_iter->encoder_ids[0] == encoder->base.id)) { - connector = conn_iter; - break; + if (connector_list) { + list_for_each_entry(conn_iter, connector_list, head) { + /** + * SDE_KMS doesn't attach more than one encoder to + * a DSI connector. So it is safe to check only with + * the first encoder entry. Revisit this logic if we + * ever have to support continuous splash for + * external displays in MST configuration. + */ + if (conn_iter && + (conn_iter->encoder_ids[0] == encoder->base.id)) { + connector = conn_iter; + break; + } } } - if (!connector) { SDE_ERROR("connector not initialized\n"); mutex_unlock(&dev->mode_config.mutex); -- GitLab From 058e5b531787c89ab04bbb86763ad4b1a7da8692 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Mon, 12 Mar 2018 19:07:23 +0530 Subject: [PATCH 322/855] ARM: dts: msm: Add 725MHz GPU clock support for SDM632 SDM632 can support maximum GPU clock of 725MHz. Add support for this new GPU level. Change-Id: Id33133f84bdb9e05bbb62e8709b0b7409ea717c9 Signed-off-by: Sunil Khatri --- arch/arm64/boot/dts/qcom/sdm632.dtsi | 94 ++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi index 67efe0f85d96..cc6b1a359a4b 100644 --- a/arch/arm64/boot/dts/qcom/sdm632.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi @@ -1005,3 +1005,97 @@ }; #include "sdm632-coresight.dtsi" + +/* GPU Overrides*/ +&msm_gpu { + + qcom,ca-target-pwrlevel = <4>; + qcom,initial-pwrlevel = <5>; + /delete-node/qcom,gpu-pwrlevels; + + /* Power levels */ + qcom,gpu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,gpu-pwrlevels"; + /* TURBO LD0 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <725000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <10>; + qcom,bus-max = <10>; + }; + + /* TURBO */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <10>; + qcom,bus-max = <10>; + }; + + /* NOM+ */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <560000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <510000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <6>; + qcom,bus-max = <10>; + }; + + /* SVS+ */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <320000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <2>; + qcom,bus-max = <6>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <216000000>; + qcom,bus-freq = <1>; + qcom,bus-min = <1>; + qcom,bus-max = <4>; + }; + + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <133300000>; + qcom,bus-freq = <1>; + qcom,bus-min = <1>; + qcom,bus-max = <4>; + }; + /* XO */ + qcom,gpu-pwrlevel@8 { + reg = <8>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; +}; -- GitLab From 153260777fde1020d211e82db952ae323d5109a8 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 18 May 2018 14:47:00 -0700 Subject: [PATCH 323/855] msm: camera: isp: Define new callback for early PCR Add reg_update callback to handle irq in the event that early PCR is enabled. This callback will be invoked only for the first frame after streamon. Change-Id: I007e5d6380c624910685d4f1ae5669b3458d0b1f Signed-off-by: Karthik Anantha Ram --- .../platform/msm/camera/cam_isp/cam_isp_context.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index 50cdc7d69ea6..7b02aac2ad0a 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -504,6 +504,18 @@ static void __cam_isp_ctx_send_sof_timestamp( } +static int __cam_isp_ctx_reg_upd_in_epoch_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + if (ctx_isp->frame_id == 1) + CAM_DBG(CAM_ISP, "Reg update for early PCR"); + else + CAM_WARN(CAM_ISP, + "Unexpected reg update in activated substate:%d for frame_id:%lld", + ctx_isp->substate_activated, ctx_isp->frame_id); + return 0; +} + static int __cam_isp_ctx_reg_upd_in_activated_state( struct cam_isp_context *ctx_isp, void *evt_data) { @@ -1119,7 +1131,7 @@ static struct cam_isp_ctx_irq_ops .irq_ops = { __cam_isp_ctx_handle_error, __cam_isp_ctx_sof_in_epoch, - NULL, + __cam_isp_ctx_reg_upd_in_epoch_state, __cam_isp_ctx_notify_sof_in_actived_state, __cam_isp_ctx_notify_eof_in_actived_state, __cam_isp_ctx_buf_done_in_epoch, -- GitLab From 00ddfc6e23927cc088ef6f92c9721307e4c44ebe Mon Sep 17 00:00:00 2001 From: Abhilash Kumar Date: Tue, 27 Mar 2018 15:09:13 +0530 Subject: [PATCH 324/855] msm: camera: crm: Access the task list of workqueue with locks Add locks at proper place while acquiring, enqueuing and executing a task from the list and while accessing the elements of workq. Also the change ensures that the workq is destroyed safely. Change-Id: I01bf2032133cc1a5269d699b94770141347d3cd0 Signed-off-by: Abhilash Kumar Signed-off-by: Karthik Anantha Ram --- .../camera/cam_req_mgr/cam_req_mgr_workq.c | 51 +++++++------------ 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c index 966b573b5493..066efd6fa3e7 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c @@ -59,11 +59,11 @@ static void cam_req_mgr_workq_put_task(struct crm_workq_task *task) (struct cam_req_mgr_core_workq *)task->parent; unsigned long flags = 0; - WORKQ_ACQUIRE_LOCK(workq, flags); list_del_init(&task->entry); task->cancel = 0; task->process_cb = NULL; task->priv = NULL; + WORKQ_ACQUIRE_LOCK(workq, flags); list_add_tail(&task->entry, &workq->task.empty_head); atomic_add(1, &workq->task.free_cnt); @@ -127,28 +127,6 @@ static void cam_req_mgr_process_workq(struct work_struct *w) } } -void crm_workq_clear_q(struct cam_req_mgr_core_workq *workq) -{ - int32_t i = CRM_TASK_PRIORITY_0; - struct crm_workq_task *task, *task_save; - - CAM_DBG(CAM_CRM, "pending_cnt %d", - atomic_read(&workq->task.pending_cnt)); - - while (i < CRM_TASK_PRIORITY_MAX) { - if (!list_empty(&workq->task.process_head[i])) { - list_for_each_entry_safe(task, task_save, - &workq->task.process_head[i], entry) { - cam_req_mgr_workq_put_task(task); - CAM_WARN(CAM_CRM, "flush task %pK, %d, cnt %d", - task, i, atomic_read( - &workq->task.free_cnt)); - } - } - i++; - } -} - int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task, void *priv, int32_t prio) { @@ -167,10 +145,6 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task, rc = -EINVAL; goto end; } - if (!workq->job) { - rc = -EINVAL; - goto end; - } if (task->cancel == 1) { cam_req_mgr_workq_put_task(task); @@ -184,16 +158,21 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task, ? prio : CRM_TASK_PRIORITY_0; WORKQ_ACQUIRE_LOCK(workq, flags); + if (!workq->job) { + rc = -EINVAL; + WORKQ_RELEASE_LOCK(workq, flags); + goto end; + } + list_add_tail(&task->entry, &workq->task.process_head[task->priority]); - WORKQ_RELEASE_LOCK(workq, flags); atomic_add(1, &workq->task.pending_cnt); CAM_DBG(CAM_CRM, "enq task %pK pending_cnt %d", task, atomic_read(&workq->task.pending_cnt)); queue_work(workq->job, &workq->work); - + WORKQ_RELEASE_LOCK(workq, flags); end: return rc; } @@ -252,8 +231,7 @@ int cam_req_mgr_workq_create(char *name, int32_t num_tasks, task = &crm_workq->task.pool[i]; task->parent = (void *)crm_workq; /* Put all tasks in free pool */ - list_add_tail(&task->entry, - &crm_workq->task.process_head[CRM_TASK_PRIORITY_0]); + INIT_LIST_HEAD(&task->entry); cam_req_mgr_workq_put_task(task); } *workq = crm_workq; @@ -266,13 +244,18 @@ int cam_req_mgr_workq_create(char *name, int32_t num_tasks, void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **crm_workq) { + unsigned long flags = 0; + struct workqueue_struct *job; CAM_DBG(CAM_CRM, "destroy workque %pK", crm_workq); if (*crm_workq) { - crm_workq_clear_q(*crm_workq); + WORKQ_ACQUIRE_LOCK(*crm_workq, flags); if ((*crm_workq)->job) { - destroy_workqueue((*crm_workq)->job); + job = (*crm_workq)->job; (*crm_workq)->job = NULL; - } + WORKQ_RELEASE_LOCK(*crm_workq, flags); + destroy_workqueue(job); + } else + WORKQ_RELEASE_LOCK(*crm_workq, flags); kfree((*crm_workq)->task.pool); kfree(*crm_workq); *crm_workq = NULL; -- GitLab From d4e8148e26acff8d59e83d5f7fa9a469122b2e40 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 17 Nov 2016 11:24:20 -0800 Subject: [PATCH 325/855] UPSTREAM: dm bufio: avoid sleeping while holding the dm_bufio lock We've seen in-field reports showing _lots_ (18 in one case, 41 in another) of tasks all sitting there blocked on: mutex_lock+0x4c/0x68 dm_bufio_shrink_count+0x38/0x78 shrink_slab.part.54.constprop.65+0x100/0x464 shrink_zone+0xa8/0x198 In the two cases analyzed, we see one task that looks like this: Workqueue: kverityd verity_prefetch_io __switch_to+0x9c/0xa8 __schedule+0x440/0x6d8 schedule+0x94/0xb4 schedule_timeout+0x204/0x27c schedule_timeout_uninterruptible+0x44/0x50 wait_iff_congested+0x9c/0x1f0 shrink_inactive_list+0x3a0/0x4cc shrink_lruvec+0x418/0x5cc shrink_zone+0x88/0x198 try_to_free_pages+0x51c/0x588 __alloc_pages_nodemask+0x648/0xa88 __get_free_pages+0x34/0x7c alloc_buffer+0xa4/0x144 __bufio_new+0x84/0x278 dm_bufio_prefetch+0x9c/0x154 verity_prefetch_io+0xe8/0x10c process_one_work+0x240/0x424 worker_thread+0x2fc/0x424 kthread+0x10c/0x114 ...and that looks to be the one holding the mutex. The problem has been reproduced on fairly easily: 0. Be running Chrome OS w/ verity enabled on the root filesystem 1. Pick test patch: http://crosreview.com/412360 2. Install launchBalloons.sh and balloon.arm from http://crbug.com/468342 ...that's just a memory stress test app. 3. On a 4GB rk3399 machine, run nice ./launchBalloons.sh 4 900 100000 ...that tries to eat 4 * 900 MB of memory and keep accessing. 4. Login to the Chrome web browser and restore many tabs With that, I've seen printouts like: DOUG: long bufio 90758 ms ...and stack trace always show's we're in dm_bufio_prefetch(). The problem is that we try to allocate memory with GFP_NOIO while we're holding the dm_bufio lock. Instead we should be using GFP_NOWAIT. Using GFP_NOIO can cause us to sleep while holding the lock and that causes the above problems. The current behavior explained by David Rientjes: It will still try reclaim initially because __GFP_WAIT (or __GFP_KSWAPD_RECLAIM) is set by GFP_NOIO. This is the cause of contention on dm_bufio_lock() that the thread holds. You want to pass GFP_NOWAIT instead of GFP_NOIO to alloc_buffer() when holding a mutex that can be contended by a concurrent slab shrinker (if count_objects didn't use a trylock, this pattern would trivially deadlock). This change significantly increases responsiveness of the system while in this state. It makes a real difference because it unblocks kswapd. In the bug report analyzed, kswapd was hung: kswapd0 D ffffffc000204fd8 0 72 2 0x00000000 Call trace: [] __switch_to+0x9c/0xa8 [] __schedule+0x440/0x6d8 [] schedule+0x94/0xb4 [] schedule_preempt_disabled+0x28/0x44 [] __mutex_lock_slowpath+0x120/0x1ac [] mutex_lock+0x4c/0x68 [] dm_bufio_shrink_count+0x38/0x78 [] shrink_slab.part.54.constprop.65+0x100/0x464 [] shrink_zone+0xa8/0x198 [] balance_pgdat+0x328/0x508 [] kswapd+0x424/0x51c [] kthread+0x10c/0x114 [] ret_from_fork+0x10/0x40 By unblocking kswapd memory pressure should be reduced. Change-Id: I947d980c1cd67d16fd069fe26f060f16c844beb8 Suggested-by: David Rientjes Reviewed-by: Guenter Roeck Signed-off-by: Douglas Anderson Signed-off-by: Mike Snitzer (cherry picked from commit 9ea61cac0b1ad0c09022f39fd97e9b99a2cfc2dc) Signed-off-by: Minchan Kim --- drivers/md/dm-bufio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 3ec647e8b9c6..809a4dfc6338 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -827,7 +827,8 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client * dm-bufio is resistant to allocation failures (it just keeps * one buffer reserved in cases all the allocations fail). * So set flags to not try too hard: - * GFP_NOIO: don't recurse into the I/O layer + * GFP_NOWAIT: don't wait; if we need to sleep we'll release our + * mutex and wait ourselves. * __GFP_NORETRY: don't retry and rather return failure * __GFP_NOMEMALLOC: don't use emergency reserves * __GFP_NOWARN: don't print a warning in case of failure @@ -837,7 +838,7 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client */ while (1) { if (dm_bufio_cache_size_latch != 1) { - b = alloc_buffer(c, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); + b = alloc_buffer(c, GFP_NOWAIT | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); if (b) return b; } -- GitLab From 6dfa32a3faae71b8660be26b5ad0b7369e4a638e Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Thu, 17 May 2018 14:59:04 +0530 Subject: [PATCH 326/855] ARM: dts: msm: Align venus virtual address pool size to 128MB for msm8x53 Updating the virtual memory pool address range to 128MB aligned. Change-Id: I207c7807f225df9a4d34725a18638d9b2a327f7b Signed-off-by: Mansur Alisha Shaik --- arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi b/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi index cb8cdf210850..1558010f4c0e 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi @@ -88,8 +88,8 @@ <&apps_iommu 0x82c 0x01>, <&apps_iommu 0x821 0x10>; buffer-types = <0xfff>; - virtual-addr-pool = <0x5dc00000 0x7f000000 - 0xdcc00000 0x1000000>; + virtual-addr-pool = <0x79000000 0x28000000 + 0xa1000000 0xc9000000>; }; secure_bitstream_cb { @@ -102,7 +102,7 @@ <&apps_iommu 0x926 0x0>, <&apps_iommu 0x929 0x2>; buffer-types = <0x241>; - virtual-addr-pool = <0x4b000000 0x12c00000>; + virtual-addr-pool = <0x51000000 0x28000000>; qcom,secure-context-bank; }; @@ -113,7 +113,7 @@ <&apps_iommu 0x910 0x0>, <&apps_iommu 0x92c 0x0>; buffer-types = <0x106>; - virtual-addr-pool = <0x25800000 0x25800000>; + virtual-addr-pool = <0x29000000 0x28000000>; qcom,secure-context-bank; }; @@ -125,7 +125,7 @@ <&apps_iommu 0x925 0x8>, <&apps_iommu 0x928 0x0>; buffer-types = <0x480>; - virtual-addr-pool = <0x1000000 0x24800000>; + virtual-addr-pool = <0x1000000 0x28000000>; qcom,secure-context-bank; }; -- GitLab From f73c68b7166bdbb404a93c7753bf7ef877943fd8 Mon Sep 17 00:00:00 2001 From: Tejaswi Tanikella Date: Tue, 22 May 2018 11:43:40 +0530 Subject: [PATCH 327/855] defconfig: sdm670: Enable INET_UDP_DIAG Enable config to enable UDP stats collection by ss tool. "ss -uneiopan" should work now. Change-Id: I6535055c12646826e6f96e8cb17dc8bf5e02f37e Signed-off-by: Tejaswi Tanikella --- arch/arm64/configs/sdm670-perf_defconfig | 1 + arch/arm64/configs/sdm670_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig index 8e7c3699c80d..7b99783e032b 100644 --- a/arch/arm64/configs/sdm670-perf_defconfig +++ b/arch/arm64/configs/sdm670-perf_defconfig @@ -106,6 +106,7 @@ CONFIG_IP_PNP_DHCP=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig index 5fb8fdb4c8e5..0c01944b6a35 100644 --- a/arch/arm64/configs/sdm670_defconfig +++ b/arch/arm64/configs/sdm670_defconfig @@ -111,6 +111,7 @@ CONFIG_IP_PNP_DHCP=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y -- GitLab From 862a74ad31a5608052c2673f4612a3aced2c369c Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Tue, 22 May 2018 11:55:13 +0530 Subject: [PATCH 328/855] scsi: ufs: Dont send abort command to w-luns As per spec, w-luns can only handle certain set of commands. Table 10-58 lists down the commands that can be handled by each of the w-luns and abort is not one of them. Hence do not send abort to a w-lun. CRs-fixed: 2234578 Change-Id: I523d2bc8860ac1d9decff82e66a1ffe97a198e52 Signed-off-by: Asutosh Das --- drivers/scsi/ufs/ufshcd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d427fb380840..b72e2eac9fb7 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -7090,7 +7090,10 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) * To avoid these unnecessary/illegal step we skip to the last error * handling stage: reset and restore. */ - if (lrbp->lun == UFS_UPIU_UFS_DEVICE_WLUN) + if ((lrbp->lun == UFS_UPIU_UFS_DEVICE_WLUN) || + (lrbp->lun == UFS_UPIU_REPORT_LUNS_WLUN) || + (lrbp->lun == UFS_UPIU_BOOT_WLUN) || + (lrbp->lun == UFS_UPIU_RPMB_WLUN)) return ufshcd_eh_host_reset_handler(cmd); ufshcd_hold_all(hba); -- GitLab From c692cb96096def8727ae342ea0926c651f2eeed7 Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Wed, 18 Apr 2018 17:20:22 +0530 Subject: [PATCH 329/855] Resolve merge conflict and enable HW FBE for ext4 fs HW File Based Encryption (FBE) uses Crypto Engine to encrypt the user data with unique key for each file. File name and data both are encrypted with this feature. - security/pfk: New module to support per file encryption using CE. - fs/ext4: changes made to support using crypto engine to encyrpt the data. Other changes made to provide support framework for per file encryption. Change-Id: I82b05a73b10ad8c26b0e400cdf246c67a8060f0e Signed-off-by: Neeraj Soni --- block/bio.c | 2 +- block/blk-merge.c | 11 +- drivers/crypto/msm/ice.c | 8 +- drivers/scsi/ufs/ufs-qcom-ice.c | 44 +- drivers/scsi/ufs/ufs-qcom.h | 1 + fs/crypto/Makefile | 1 + fs/crypto/bio.c | 16 +- fs/crypto/fscrypt_private.h | 8 + fs/crypto/keyinfo.c | 144 +++-- fs/direct-io.c | 13 + fs/ext4/Kconfig | 10 +- fs/ext4/Makefile | 2 + fs/ext4/ext4_ice.c | 109 ++++ fs/ext4/ext4_ice.h | 108 ++++ fs/ext4/inode.c | 13 +- fs/ext4/ioctl.c | 4 +- fs/ext4/page-io.c | 2 + fs/namei.c | 12 + include/linux/blk_types.h | 6 + include/linux/fs.h | 2 + include/linux/fscrypt_supp.h | 4 + include/linux/lsm_hooks.h | 3 + include/linux/pfk.h | 57 ++ include/linux/security.h | 11 + include/uapi/linux/fs.h | 1 + security/Kconfig | 5 + security/Makefile | 2 + security/pfe/Kconfig | 28 + security/pfe/Makefile | 10 + security/pfe/pfk.c | 483 +++++++++++++++ security/pfe/pfk_ext4.c | 211 +++++++ security/pfe/pfk_ext4.h | 37 ++ security/pfe/pfk_ice.c | 189 ++++++ security/pfe/pfk_ice.h | 33 + security/pfe/pfk_internal.h | 34 ++ security/pfe/pfk_kc.c | 905 ++++++++++++++++++++++++++++ security/pfe/pfk_kc.h | 33 + security/security.c | 10 + security/selinux/include/objsec.h | 7 +- security/selinux/include/security.h | 1 - 40 files changed, 2491 insertions(+), 89 deletions(-) create mode 100644 fs/ext4/ext4_ice.c create mode 100644 fs/ext4/ext4_ice.h create mode 100644 include/linux/pfk.h create mode 100644 security/pfe/Kconfig create mode 100644 security/pfe/Makefile create mode 100644 security/pfe/pfk.c create mode 100644 security/pfe/pfk_ext4.c create mode 100644 security/pfe/pfk_ext4.h create mode 100644 security/pfe/pfk_ice.c create mode 100644 security/pfe/pfk_ice.h create mode 100644 security/pfe/pfk_internal.h create mode 100644 security/pfe/pfk_kc.c create mode 100644 security/pfe/pfk_kc.h diff --git a/block/bio.c b/block/bio.c index 4f93345c6a82..4d938110a518 100644 --- a/block/bio.c +++ b/block/bio.c @@ -589,7 +589,7 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src) bio->bi_opf = bio_src->bi_opf; bio->bi_iter = bio_src->bi_iter; bio->bi_io_vec = bio_src->bi_io_vec; - + bio->bi_dio_inode = bio_src->bi_dio_inode; bio_clone_blkcg_association(bio, bio_src); } EXPORT_SYMBOL(__bio_clone_fast); diff --git a/block/blk-merge.c b/block/blk-merge.c index abde3707438d..0272face5199 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -6,7 +6,7 @@ #include #include #include - +#include #include #include "blk.h" @@ -725,6 +725,11 @@ static void blk_account_io_merge(struct request *req) } } +static bool crypto_not_mergeable(const struct bio *bio, const struct bio *nxt) +{ + return (!pfk_allow_merge_bio(bio, nxt)); +} + /* * Has to be called with the request spinlock acquired */ @@ -752,6 +757,8 @@ static int attempt_merge(struct request_queue *q, struct request *req, !blk_write_same_mergeable(req->bio, next->bio)) return 0; + if (crypto_not_mergeable(req->bio, next->bio)) + return 0; /* * If we are allowed to merge, then append bio list * from next to rq and release next. merge_requests_fn @@ -862,6 +869,8 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) !blk_write_same_mergeable(rq->bio, bio)) return false; + if (crypto_not_mergeable(rq->bio, bio)) + return false; return true; } diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index 3aa75aa03044..f15267eb69b8 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -152,6 +152,9 @@ static int qti_ice_setting_config(struct request *req, return -EPERM; } + if (!setting) + return -EINVAL; + if ((short)(crypto_data->key_index) >= 0) { memcpy(&setting->crypto_data, crypto_data, @@ -1488,7 +1491,7 @@ static int qcom_ice_config_start(struct platform_device *pdev, bool is_pfe = false; sector_t data_size; - if (!pdev || !req || !setting) { + if (!pdev || !req) { pr_err("%s: Invalid params passed\n", __func__); return -EINVAL; } @@ -1507,6 +1510,7 @@ static int qcom_ice_config_start(struct platform_device *pdev, /* It is not an error to have a request with no bio */ return 0; } + //pr_err("%s bio is %pK\n", __func__, req->bio); ret = pfk_load_key_start(req->bio, &pfk_crypto_data, &is_pfe, async); if (is_pfe) { @@ -1664,7 +1668,7 @@ static struct ice_device *get_ice_device_from_storage_type list_for_each_entry(ice_dev, &ice_devices, list) { if (!strcmp(ice_dev->ice_instance_type, storage_type)) { - pr_info("%s: found ice device %p\n", __func__, ice_dev); + pr_debug("%s: ice device %pK\n", __func__, ice_dev); return ice_dev; } } diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index b1c86d42148a..d4fe6eede3b4 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -172,17 +172,15 @@ int ufs_qcom_ice_get_dev(struct ufs_qcom_host *qcom_host) static void ufs_qcom_ice_cfg_work(struct work_struct *work) { unsigned long flags; - struct ice_data_setting ice_set; struct ufs_qcom_host *qcom_host = container_of(work, struct ufs_qcom_host, ice_cfg_work); - struct request *req_pending = NULL; if (!qcom_host->ice.vops->config_start) return; spin_lock_irqsave(&qcom_host->ice_work_lock, flags); - req_pending = qcom_host->req_pending; - if (!req_pending) { + if (!qcom_host->req_pending) { + qcom_host->work_pending = false; spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); return; } @@ -191,24 +189,15 @@ static void ufs_qcom_ice_cfg_work(struct work_struct *work) /* * config_start is called again as previous attempt returned -EAGAIN, * this call shall now take care of the necessary key setup. - * 'ice_set' will not actually be used, instead the next call to - * config_start() for this request, in the normal call flow, will - * succeed as the key has now been setup. */ qcom_host->ice.vops->config_start(qcom_host->ice.pdev, - qcom_host->req_pending, &ice_set, false); + qcom_host->req_pending, NULL, false); spin_lock_irqsave(&qcom_host->ice_work_lock, flags); qcom_host->req_pending = NULL; + qcom_host->work_pending = false; spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); - /* - * Resume with requests processing. We assume config_start has been - * successful, but even if it wasn't we still must resume in order to - * allow for the request to be retried. - */ - ufshcd_scsi_unblock_requests(qcom_host->hba); - } /** @@ -294,18 +283,14 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, * requires a non-atomic context, this means we should * call the function again from the worker thread to do * the configuration. For this request the error will - * propagate so it will be re-queued and until the - * configuration is is completed we block further - * request processing. + * propagate so it will be re-queued. */ if (err == -EAGAIN) { dev_dbg(qcom_host->hba->dev, "%s: scheduling task for ice setup\n", __func__); - if (!qcom_host->req_pending) { - ufshcd_scsi_block_requests( - qcom_host->hba); + if (!qcom_host->work_pending) { qcom_host->req_pending = cmd->request; if (!queue_work(ice_workqueue, @@ -316,10 +301,9 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, &qcom_host->ice_work_lock, flags); - ufshcd_scsi_unblock_requests( - qcom_host->hba); return err; } + qcom_host->work_pending = true; } } else { @@ -418,9 +402,7 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, * requires a non-atomic context, this means we should * call the function again from the worker thread to do * the configuration. For this request the error will - * propagate so it will be re-queued and until the - * configuration is is completed we block further - * request processing. + * propagate so it will be re-queued. */ if (err == -EAGAIN) { @@ -428,9 +410,8 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, "%s: scheduling task for ice setup\n", __func__); - if (!qcom_host->req_pending) { - ufshcd_scsi_block_requests( - qcom_host->hba); + if (!qcom_host->work_pending) { + qcom_host->req_pending = cmd->request; if (!queue_work(ice_workqueue, &qcom_host->ice_cfg_work)) { @@ -440,10 +421,9 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, &qcom_host->ice_work_lock, flags); - ufshcd_scsi_unblock_requests( - qcom_host->hba); return err; } + qcom_host->work_pending = true; } } else { diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index a03ecb0dc1f7..27f6a05af547 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -375,6 +375,7 @@ struct ufs_qcom_host { struct work_struct ice_cfg_work; struct request *req_pending; struct ufs_vreg *vddp_ref_clk; + bool work_pending; }; static inline u32 diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile index cb496989a6b6..a35f058cd6f5 100644 --- a/fs/crypto/Makefile +++ b/fs/crypto/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o +ccflags-y += -Ifs/ext4 fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o fscrypto-$(CONFIG_BLOCK) += bio.o diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index d7b4c480e39e..205e92806876 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -32,14 +32,18 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done) bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; - int ret = fscrypt_decrypt_page(page->mapping->host, page, - PAGE_SIZE, 0, page->index); - if (ret) { - WARN_ON_ONCE(1); - SetPageError(page); - } else if (done) { + if (fs_is_ice_enabled()) { SetPageUptodate(page); + } else { + int ret = fscrypt_decrypt_page(page->mapping->host, + page, PAGE_SIZE, 0, page->index); + if (ret) { + WARN_ON_ONCE(1); + SetPageError(page); + } else if (done) { + SetPageUptodate(page); + } } if (done) unlock_page(page); diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index d36a648cb2bb..3e72d65e8a80 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -69,6 +69,7 @@ struct fscrypt_info { struct crypto_skcipher *ci_ctfm; struct crypto_cipher *ci_essiv_tfm; u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE]; + u8 ci_raw_key[FS_MAX_KEY_SIZE]; }; typedef enum { @@ -90,6 +91,9 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode, filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS) return true; + if (contents_mode == FS_ENCRYPTION_MODE_PRIVATE) + return true; + return false; } @@ -112,6 +116,10 @@ extern bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, u32 max_len, u32 *encrypted_len_ret); +static inline int fs_is_ice_enabled(void) +{ + return 1; +} /* keyinfo.c */ extern void __exit fscrypt_essiv_cleanup(void); diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index aae68c0924f1..dcd00d5fe62c 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -134,10 +134,12 @@ static const struct { FS_AES_128_CBC_KEY_SIZE }, [FS_ENCRYPTION_MODE_AES_128_CTS] = { "cts(cbc(aes))", FS_AES_128_CTS_KEY_SIZE }, + [FS_ENCRYPTION_MODE_PRIVATE] = { "bugon", + FS_AES_256_XTS_KEY_SIZE }, }; static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode, - const char **cipher_str_ret, int *keysize_ret) + const char **cipher_str_ret, int *keysize_ret, int *fname) { u32 mode; @@ -152,6 +154,7 @@ static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode, mode = ci->ci_data_mode; } else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { mode = ci->ci_filename_mode; + *fname = 1; } else { WARN_ONCE(1, "fscrypt: filesystem tried to load encryption info for inode %lu, which is not encryptable (file type %d)\n", inode->i_ino, (inode->i_mode & S_IFMT)); @@ -170,6 +173,7 @@ static void put_crypt_info(struct fscrypt_info *ci) crypto_free_skcipher(ci->ci_ctfm); crypto_free_cipher(ci->ci_essiv_tfm); + memzero_explicit(ci->ci_raw_key, sizeof(ci->ci_raw_key)); kmem_cache_free(fscrypt_info_cachep, ci); } @@ -239,6 +243,21 @@ void __exit fscrypt_essiv_cleanup(void) crypto_free_shash(essiv_hash_tfm); } +static int fs_data_encryption_mode(void) +{ + return fs_is_ice_enabled() ? FS_ENCRYPTION_MODE_PRIVATE : + FS_ENCRYPTION_MODE_AES_256_XTS; +} + +int fs_using_hardware_encryption(struct inode *inode) +{ + struct fscrypt_info *ci = inode->i_crypt_info; + + return S_ISREG(inode->i_mode) && ci && + ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; +} +EXPORT_SYMBOL(fs_using_hardware_encryption); + int fscrypt_get_encryption_info(struct inode *inode) { struct fscrypt_info *crypt_info; @@ -246,8 +265,8 @@ int fscrypt_get_encryption_info(struct inode *inode) struct crypto_skcipher *ctfm; const char *cipher_str; int keysize; - u8 *raw_key = NULL; int res; + int fname = 0; if (inode->i_crypt_info) return 0; @@ -264,7 +283,7 @@ int fscrypt_get_encryption_info(struct inode *inode) /* Fake up a context for an unencrypted directory */ memset(&ctx, 0, sizeof(ctx)); ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; - ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS; + ctx.contents_encryption_mode = fs_data_encryption_mode(); ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE); } else if (res != sizeof(ctx)) { @@ -289,7 +308,8 @@ int fscrypt_get_encryption_info(struct inode *inode) memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor, sizeof(crypt_info->ci_master_key)); - res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize); + res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize, + &fname); if (res) goto out; @@ -298,16 +318,13 @@ int fscrypt_get_encryption_info(struct inode *inode) * crypto API as part of key derivation. */ res = -ENOMEM; - raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS); - if (!raw_key) - goto out; - res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX, - keysize); + res = validate_user_key(crypt_info, &ctx, crypt_info->ci_raw_key, + FS_KEY_DESC_PREFIX, keysize); if (res && inode->i_sb->s_cop->key_prefix) { - int res2 = validate_user_key(crypt_info, &ctx, raw_key, - inode->i_sb->s_cop->key_prefix, - keysize); + int res2 = validate_user_key(crypt_info, &ctx, + crypt_info->ci_raw_key, + inode->i_sb->s_cop->key_prefix, keysize); if (res2) { if (res2 == -ENOKEY) res = -ENOKEY; @@ -316,32 +333,40 @@ int fscrypt_get_encryption_info(struct inode *inode) } else if (res) { goto out; } - ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); - if (!ctfm || IS_ERR(ctfm)) { - res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; - pr_debug("%s: error %d (inode %lu) allocating crypto tfm\n", - __func__, res, inode->i_ino); - goto out; - } - crypt_info->ci_ctfm = ctfm; - crypto_skcipher_clear_flags(ctfm, ~0); - crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); - /* - * if the provided key is longer than keysize, we use the first - * keysize bytes of the derived key only - */ - res = crypto_skcipher_setkey(ctfm, raw_key, keysize); - if (res) - goto out; - - if (S_ISREG(inode->i_mode) && - crypt_info->ci_data_mode == FS_ENCRYPTION_MODE_AES_128_CBC) { - res = init_essiv_generator(crypt_info, raw_key, keysize); - if (res) { - pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n", + if (crypt_info->ci_data_mode != FS_ENCRYPTION_MODE_PRIVATE || fname) { + ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); + if (!ctfm || IS_ERR(ctfm)) { + res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; + pr_debug("%s: error %d (inode %lu) allocating crypto tfm\n", __func__, res, inode->i_ino); goto out; } + crypt_info->ci_ctfm = ctfm; + crypto_skcipher_clear_flags(ctfm, ~0); + crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); + /* + * if the provided key is longer than keysize, we use the first + * keysize bytes of the derived key only + */ + res = crypto_skcipher_setkey(ctfm, + crypt_info->ci_raw_key, keysize); + if (res) + goto out; + + if (S_ISREG(inode->i_mode) && crypt_info->ci_data_mode == + FS_ENCRYPTION_MODE_AES_128_CBC) { + res = init_essiv_generator(crypt_info, + crypt_info->ci_raw_key, keysize); + if (res) { + pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n", + __func__, res, inode->i_ino); + goto out; + } + } + } else if (!fs_is_ice_enabled()) { + pr_warn("%s: ICE support not available\n", __func__); + res = -EINVAL; + goto out; } if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL) crypt_info = NULL; @@ -349,7 +374,6 @@ int fscrypt_get_encryption_info(struct inode *inode) if (res == -ENOKEY) res = 0; put_crypt_info(crypt_info); - kzfree(raw_key); return res; } EXPORT_SYMBOL(fscrypt_get_encryption_info); @@ -360,3 +384,51 @@ void fscrypt_put_encryption_info(struct inode *inode) inode->i_crypt_info = NULL; } EXPORT_SYMBOL(fscrypt_put_encryption_info); + +char *fscrypt_get_ice_encryption_key(const struct inode *inode) +{ + struct fscrypt_info *ci; + + if (!inode) + return NULL; + + ci = inode->i_crypt_info; + if (!ci) + return NULL; + + return &(ci->ci_raw_key[0]); +} +EXPORT_SYMBOL(fscrypt_get_ice_encryption_key); + +/* + * Retrieves encryption salt from the inode + */ +char *fscrypt_get_ice_encryption_salt(const struct inode *inode) +{ + struct fscrypt_info *ci; + + if (!inode) + return NULL; + + ci = inode->i_crypt_info; + if (!ci) + return NULL; + + return &(ci->ci_raw_key[FS_AES_256_XTS_KEY_SIZE / 2]); +} +EXPORT_SYMBOL(fscrypt_get_ice_encryption_salt); + +/* + * returns true if the cipher mode in inode is AES XTS + */ +int fscrypt_is_aes_xts_cipher(const struct inode *inode) +{ + struct fscrypt_info *ci; + + ci = inode->i_crypt_info; + if (!ci) + return 0; + + return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE); +} +EXPORT_SYMBOL(fscrypt_is_aes_xts_cipher); diff --git a/fs/direct-io.c b/fs/direct-io.c index c6220a2daefd..bf03a92d109a 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -411,6 +411,7 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio) if (dio->is_async && dio->op == REQ_OP_READ && dio->should_dirty) bio_set_pages_dirty(bio); + bio->bi_dio_inode = dio->inode; dio->bio_bdev = bio->bi_bdev; if (sdio->submit_io) { @@ -424,6 +425,18 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio) sdio->logical_offset_in_bio = 0; } +struct inode *dio_bio_get_inode(struct bio *bio) +{ + struct inode *inode = NULL; + + if (bio == NULL) + return NULL; + + inode = bio->bi_dio_inode; + + return inode; +} +EXPORT_SYMBOL(dio_bio_get_inode); /* * Release any resources in case of a failure */ diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig index e38039fd96ff..e9232a09af5d 100644 --- a/fs/ext4/Kconfig +++ b/fs/ext4/Kconfig @@ -109,10 +109,16 @@ config EXT4_ENCRYPTION decrypted pages in the page cache. config EXT4_FS_ENCRYPTION - bool - default y + bool "Ext4 FS Encryption" + default n depends on EXT4_ENCRYPTION +config EXT4_FS_ICE_ENCRYPTION + bool "Ext4 Encryption with ICE support" + default n + depends on EXT4_FS_ENCRYPTION + depends on PFK + config EXT4_DEBUG bool "EXT4 debugging support" depends on EXT4_FS diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 354103f3490c..d9e563a914ad 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -1,6 +1,7 @@ # # Makefile for the linux ext4-filesystem routines. # +ccflags-y += -Ifs/crypto obj-$(CONFIG_EXT4_FS) += ext4.o @@ -12,3 +13,4 @@ ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \ ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o +ext4-$(CONFIG_EXT4_FS_ICE_ENCRYPTION) += ext4_ice.o diff --git a/fs/ext4/ext4_ice.c b/fs/ext4/ext4_ice.c new file mode 100644 index 000000000000..802df3699810 --- /dev/null +++ b/fs/ext4/ext4_ice.c @@ -0,0 +1,109 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "ext4_ice.h" +#include + +/* + * Retrieves encryption key from the inode + */ +char *ext4_get_ice_encryption_key(const struct inode *inode) +{ + /* + * struct fscrypt_info *ci; + * if (!inode) + * return NULL; + * ci = inode->i_crypt_info; + * if (!ci) + * return NULL; + * return &(ci->ci_raw_key[0]); + */ + return fscrypt_get_ice_encryption_key(inode); +} + +/* + * Retrieves encryption salt from the inode + */ +char *ext4_get_ice_encryption_salt(const struct inode *inode) +{ + /* + * struct fscrypt_info *ci; + * if (!inode) + * return NULL; + * ci = inode->i_crypt_info; + * if (!ci) + * return NULL; + * return &(ci->ci_raw_key[ext4_get_ice_encryption_key_size(inode)]); + */ + return fscrypt_get_ice_encryption_salt(inode); +} + +/* + * returns true if the cipher mode in inode is AES XTS + */ +int ext4_is_aes_xts_cipher(const struct inode *inode) +{ + /* + * struct fscrypt_info *ci; + * ci = inode->i_crypt_info; + * if (!ci) + * return 0; + * return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE); + */ + return fscrypt_is_aes_xts_cipher(inode); +} + +/* + * returns true if encryption info in both inodes is equal + */ +int ext4_is_ice_encryption_info_equal(const struct inode *inode1, + const struct inode *inode2) +{ + char *key1 = NULL; + char *key2 = NULL; + char *salt1 = NULL; + char *salt2 = NULL; + + if (!inode1 || !inode2) + return 0; + + if (inode1 == inode2) + return 1; + + /* both do not belong to ice, so we don't care, they are equal for us */ + if (!ext4_should_be_processed_by_ice(inode1) && + !ext4_should_be_processed_by_ice(inode2)) + return 1; + + /* one belongs to ice, the other does not -> not equal */ + if (ext4_should_be_processed_by_ice(inode1) ^ + ext4_should_be_processed_by_ice(inode2)) + return 0; + + key1 = ext4_get_ice_encryption_key(inode1); + key2 = ext4_get_ice_encryption_key(inode2); + salt1 = ext4_get_ice_encryption_salt(inode1); + salt2 = ext4_get_ice_encryption_salt(inode2); + + /* key and salt should not be null by this point */ + if (!key1 || !key2 || !salt1 || !salt2 || + (ext4_get_ice_encryption_key_size(inode1) != + ext4_get_ice_encryption_key_size(inode2)) || + (ext4_get_ice_encryption_salt_size(inode1) != + ext4_get_ice_encryption_salt_size(inode2))) + return 0; + + return ((memcmp(key1, key2, + ext4_get_ice_encryption_key_size(inode1)) == 0) && + (memcmp(salt1, salt2, + ext4_get_ice_encryption_salt_size(inode1)) == 0)); +} diff --git a/fs/ext4/ext4_ice.h b/fs/ext4/ext4_ice.h new file mode 100644 index 000000000000..8cf4d2e607c9 --- /dev/null +++ b/fs/ext4/ext4_ice.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _EXT4_ICE_H +#define _EXT4_ICE_H + +#include "ext4.h" +#define EXT4_256_XTS_KEY_SIZE 64 + +#ifdef CONFIG_EXT4_FS_ICE_ENCRYPTION +static inline int ext4_should_be_processed_by_ice(const struct inode *inode) +{ + if (!ext4_encrypted_inode((struct inode *)inode)) + return 0; + + return fs_using_hardware_encryption((struct inode *)inode); +} + +static inline int ext4_is_ice_enabled(void) +{ + return 1; +} + +int ext4_is_aes_xts_cipher(const struct inode *inode); + +char *ext4_get_ice_encryption_key(const struct inode *inode); +char *ext4_get_ice_encryption_salt(const struct inode *inode); + +int ext4_is_ice_encryption_info_equal(const struct inode *inode1, + const struct inode *inode2); + +static inline size_t ext4_get_ice_encryption_key_size( + const struct inode *inode) +{ + return EXT4_256_XTS_KEY_SIZE / 2; +} + +static inline size_t ext4_get_ice_encryption_salt_size( + const struct inode *inode) +{ + return EXT4_256_XTS_KEY_SIZE / 2; +} + +#else +static inline int ext4_should_be_processed_by_ice(const struct inode *inode) +{ + return 0; +} +static inline int ext4_is_ice_enabled(void) +{ + return 0; +} + +static inline char *ext4_get_ice_encryption_key(const struct inode *inode) +{ + return NULL; +} + +static inline char *ext4_get_ice_encryption_salt(const struct inode *inode) +{ + return NULL; +} + +static inline size_t ext4_get_ice_encryption_key_size( + const struct inode *inode) +{ + return 0; +} + +static inline size_t ext4_get_ice_encryption_salt_size( + const struct inode *inode) +{ + return 0; +} + +static inline int ext4_is_xts_cipher(const struct inode *inode) +{ + return 0; +} + +static inline int ext4_is_ice_encryption_info_equal( + const struct inode *inode1, + const struct inode *inode2) +{ + return 0; +} + +static inline int ext4_is_aes_xts_cipher(const struct inode *inode) +{ + return 0; +} + +static int fs_using_hardware_encryption(struct inode *inode) +{ + return -EOPNOTSUPP; +} +#endif + +#endif /* _EXT4_ICE_H */ diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 2bf83d0cb363..3d89b98c8b37 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -42,6 +42,7 @@ #include "xattr.h" #include "acl.h" #include "truncate.h" +#include "ext4_ice.h" #include #include @@ -1152,7 +1153,8 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, ll_rw_block(REQ_OP_READ, 0, 1, &bh); *wait_bh++ = bh; decrypt = ext4_encrypted_inode(inode) && - S_ISREG(inode->i_mode); + S_ISREG(inode->i_mode) && + !ext4_is_ice_enabled(); } } /* @@ -3509,7 +3511,8 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) get_block_func = ext4_dio_get_block_unwritten_async; dio_flags = DIO_LOCKING; } -#ifdef CONFIG_EXT4_FS_ENCRYPTION +#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \ +!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION) BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)); #endif if (IS_DAX(inode)) { @@ -3631,7 +3634,8 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ssize_t ret; int rw = iov_iter_rw(iter); -#ifdef CONFIG_EXT4_FS_ENCRYPTION +#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \ +!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION) if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) return 0; #endif @@ -3828,7 +3832,8 @@ static int __ext4_block_zero_page_range(handle_t *handle, if (!buffer_uptodate(bh)) goto unlock; if (S_ISREG(inode->i_mode) && - ext4_encrypted_inode(inode)) { + ext4_encrypted_inode(inode) && + !fs_using_hardware_encryption(inode)) { /* We expect the key to be set. */ BUG_ON(!fscrypt_has_encryption_key(inode)); BUG_ON(blocksize != PAGE_SIZE); diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 15ca15cb9f28..3585e26c0964 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -774,8 +774,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return ext4_ext_precache(inode); case EXT4_IOC_SET_ENCRYPTION_POLICY: - if (!ext4_has_feature_encrypt(sb)) - return -EOPNOTSUPP; +// if (!ext4_has_feature_encrypt(sb)) +// return -EOPNOTSUPP; return fscrypt_ioctl_set_policy(filp, (const void __user *)arg); case EXT4_IOC_GET_ENCRYPTION_PWSALT: { diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 0718a8667f0c..a9dc6723b9db 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -28,6 +28,7 @@ #include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" +#include "ext4_ice.h" static struct kmem_cache *io_end_cachep; @@ -469,6 +470,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io, gfp_t gfp_flags = GFP_NOFS; retry_encrypt: + if (!fs_using_hardware_encryption(inode)) data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, 0, page->index, gfp_flags); if (IS_ERR(data_page)) { diff --git a/fs/namei.c b/fs/namei.c index a5a05d3faa63..c138ab184a2e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2905,6 +2905,11 @@ int vfs_create2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, if (error) return error; error = dir->i_op->create(dir, dentry, mode, want_excl); + if (error) + return error; + error = security_inode_post_create(dir, dentry, mode); + if (error) + return error; if (!error) fsnotify_create(dir, dentry); return error; @@ -3720,6 +3725,13 @@ int vfs_mknod2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, u return error; error = dir->i_op->mknod(dir, dentry, mode, dev); + if (error) + return error; + + error = security_inode_post_create(dir, dentry, mode); + if (error) + return error; + if (!error) fsnotify_create(dir, dentry); return error; diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index e4d84d327a4b..4115fa430be3 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -81,6 +81,12 @@ struct bio { struct bio_set *bi_pool; + /* + * When using dircet-io (O_DIRECT), we can't get the inode from a bio + * by walking bio->bi_io_vec->bv_page->mapping->host + * since the page is anon. + */ + struct inode *bi_dio_inode; /* * We can inline a number of vecs at the end of the bio, to avoid * double allocations for a small number of bio_vecs. This member diff --git a/include/linux/fs.h b/include/linux/fs.h index 8a3bdadd0ca7..1c4da438fdc5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2948,6 +2948,8 @@ static inline void inode_dio_end(struct inode *inode) wake_up_bit(&inode->i_state, __I_DIO_WAKEUP); } +struct inode *dio_bio_get_inode(struct bio *bio); + extern void inode_set_flags(struct inode *inode, unsigned int flags, unsigned int mask); diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index 1ed79eeb2438..401584753746 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -97,6 +97,10 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *, /* keyinfo.c */ extern int fscrypt_get_encryption_info(struct inode *); extern void fscrypt_put_encryption_info(struct inode *); +extern int fs_using_hardware_encryption(struct inode *inode); +extern char *fscrypt_get_ice_encryption_key(const struct inode *inode); +extern char *fscrypt_get_ice_encryption_salt(const struct inode *inode); +extern int fscrypt_is_aes_xts_cipher(const struct inode *inode); /* fname.c */ extern int fscrypt_setup_filename(struct inode *, const struct qstr *, diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index be65c03cfcdc..f510c681378c 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1452,6 +1452,8 @@ union security_list_options { size_t *len); int (*inode_create)(struct inode *dir, struct dentry *dentry, umode_t mode); + int (*inode_post_create)(struct inode *dir, struct dentry *dentry, + umode_t mode); int (*inode_link)(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry); int (*inode_unlink)(struct inode *dir, struct dentry *dentry); @@ -1750,6 +1752,7 @@ struct security_hook_heads { struct list_head inode_free_security; struct list_head inode_init_security; struct list_head inode_create; + struct list_head inode_post_create; struct list_head inode_link; struct list_head inode_unlink; struct list_head inode_symlink; diff --git a/include/linux/pfk.h b/include/linux/pfk.h new file mode 100644 index 000000000000..3c7a389fd4d4 --- /dev/null +++ b/include/linux/pfk.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef PFK_H_ +#define PFK_H_ + +#include + +struct ice_crypto_setting; + +#ifdef CONFIG_PFK + +int pfk_load_key_start(const struct bio *bio, + struct ice_crypto_setting *ice_setting, bool *is_pfe, bool); +int pfk_load_key_end(const struct bio *bio, bool *is_pfe); +int pfk_remove_key(const unsigned char *key, size_t key_size); +bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2); +void pfk_clear_on_reset(void); + +#else +static inline int pfk_load_key_start(const struct bio *bio, + struct ice_crypto_setting *ice_setting, bool *is_pfe, bool async) +{ + return -ENODEV; +} + +static inline int pfk_load_key_end(const struct bio *bio, bool *is_pfe) +{ + return -ENODEV; +} + +static inline int pfk_remove_key(const unsigned char *key, size_t key_size) +{ + return -ENODEV; +} + +static inline bool pfk_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2) +{ + return true; +} + +static inline void pfk_clear_on_reset(void) +{} + +#endif /* CONFIG_PFK */ + +#endif /* PFK_H */ diff --git a/include/linux/security.h b/include/linux/security.h index 363242871b66..bfb1b749da64 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -30,6 +30,7 @@ #include #include #include +#include struct linux_binprm; struct cred; @@ -256,6 +257,8 @@ int security_old_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, const char **name, void **value, size_t *len); int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode); +int security_inode_post_create(struct inode *dir, struct dentry *dentry, + umode_t mode); int security_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry); int security_inode_unlink(struct inode *dir, struct dentry *dentry); @@ -304,6 +307,7 @@ int security_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int sig); int security_file_receive(struct file *file); int security_file_open(struct file *file, const struct cred *cred); + int security_task_create(unsigned long clone_flags); void security_task_free(struct task_struct *task); int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); @@ -637,6 +641,13 @@ static inline int security_inode_create(struct inode *dir, return 0; } +static inline int security_inode_post_create(struct inode *dir, + struct dentry *dentry, + umode_t mode) +{ + return 0; +} + static inline int security_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index 12263e4b8b08..dfcf37128ecb 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -273,6 +273,7 @@ struct fsxattr { #define FS_ENCRYPTION_MODE_AES_256_CTS 4 #define FS_ENCRYPTION_MODE_AES_128_CBC 5 #define FS_ENCRYPTION_MODE_AES_128_CTS 6 +#define FS_ENCRYPTION_MODE_PRIVATE 127 struct fscrypt_policy { __u8 version; diff --git a/security/Kconfig b/security/Kconfig index 2e68fa436974..638afc868ba2 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -6,6 +6,11 @@ menu "Security options" source security/keys/Kconfig +if ARCH_QCOM +source security/pfe/Kconfig +endif + + config SECURITY_DMESG_RESTRICT bool "Restrict unprivileged access to the kernel syslog" default n diff --git a/security/Makefile b/security/Makefile index f2d71cdb8e19..79166bad11d0 100644 --- a/security/Makefile +++ b/security/Makefile @@ -9,6 +9,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor subdir-$(CONFIG_SECURITY_YAMA) += yama subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin +subdir-$(CONFIG_ARCH_QCOM) += pfe # always enable default capabilities obj-y += commoncap.o @@ -24,6 +25,7 @@ obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ obj-$(CONFIG_SECURITY_YAMA) += yama/ obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ +obj-$(CONFIG_ARCH_QCOM) += pfe/ obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o # Object integrity file lists diff --git a/security/pfe/Kconfig b/security/pfe/Kconfig new file mode 100644 index 000000000000..0cd9e81a4952 --- /dev/null +++ b/security/pfe/Kconfig @@ -0,0 +1,28 @@ +menu "Qualcomm Technologies, Inc Per File Encryption security device drivers" + depends on ARCH_QCOM + +config PFT + bool "Per-File-Tagger driver" + depends on SECURITY + default n + help + This driver is used for tagging enterprise files. + It is part of the Per-File-Encryption (PFE) feature. + The driver is tagging files when created by + registered application. + Tagged files are encrypted using the dm-req-crypt driver. + +config PFK + bool "Per-File-Key driver" + depends on SECURITY + depends on SECURITY_SELINUX + default n + help + This driver is used for storing eCryptfs information + in file node. + This is part of eCryptfs hardware enhanced solution + provided by Qualcomm Technologies, Inc. + Information is used when file is encrypted later using + ICE or dm crypto engine + +endmenu diff --git a/security/pfe/Makefile b/security/pfe/Makefile new file mode 100644 index 000000000000..242a2165fccb --- /dev/null +++ b/security/pfe/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the MSM specific security device drivers. +# + +ccflags-y += -Isecurity/selinux -Isecurity/selinux/include +ccflags-y += -Ifs/ext4 +ccflags-y += -Ifs/crypto + +obj-$(CONFIG_PFT) += pft.o +obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o diff --git a/security/pfe/pfk.c b/security/pfe/pfk.c new file mode 100644 index 000000000000..cd282a09c7d5 --- /dev/null +++ b/security/pfe/pfk.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Per-File-Key (PFK). + * + * This driver is responsible for overall management of various + * Per File Encryption variants that work on top of or as part of different + * file systems. + * + * The driver has the following purpose : + * 1) Define priorities between PFE's if more than one is enabled + * 2) Extract key information from inode + * 3) Load and manage various keys in ICE HW engine + * 4) It should be invoked from various layers in FS/BLOCK/STORAGE DRIVER + * that need to take decision on HW encryption management of the data + * Some examples: + * BLOCK LAYER: when it takes decision on whether 2 chunks can be united + * to one encryption / decryption request sent to the HW + * + * UFS DRIVER: when it need to configure ICE HW with a particular key slot + * to be used for encryption / decryption + * + * PFE variants can differ on particular way of storing the cryptographic info + * inside inode, actions to be taken upon file operations, etc., but the common + * properties are described above + * + */ + + +/* Uncomment the line below to enable debug messages */ +/* #define DEBUG 1 */ +#define pr_fmt(fmt) "pfk [%s]: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pfk_kc.h" +#include "objsec.h" +#include "pfk_ice.h" +#include "pfk_ext4.h" +#include "pfk_internal.h" +#include "ext4.h" + +static bool pfk_ready; + + +/* might be replaced by a table when more than one cipher is supported */ +#define PFK_SUPPORTED_KEY_SIZE 32 +#define PFK_SUPPORTED_SALT_SIZE 32 + +/* Various PFE types and function tables to support each one of them */ +enum pfe_type {EXT4_CRYPT_PFE, INVALID_PFE}; + +typedef int (*pfk_parse_inode_type)(const struct bio *bio, + const struct inode *inode, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo, + bool *is_pfe); + +typedef bool (*pfk_allow_merge_bio_type)(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2); + +static const pfk_parse_inode_type pfk_parse_inode_ftable[] = { + /* EXT4_CRYPT_PFE */ &pfk_ext4_parse_inode, +}; + +static const pfk_allow_merge_bio_type pfk_allow_merge_bio_ftable[] = { + /* EXT4_CRYPT_PFE */ &pfk_ext4_allow_merge_bio, +}; + +static void __exit pfk_exit(void) +{ + pfk_ready = false; + pfk_ext4_deinit(); + pfk_kc_deinit(); +} + +static int __init pfk_init(void) +{ + + int ret = 0; + + ret = pfk_ext4_init(); + if (ret != 0) + goto fail; + + ret = pfk_kc_init(); + if (ret != 0) { + pr_err("could init pfk key cache, error %d\n", ret); + pfk_ext4_deinit(); + goto fail; + } + + pfk_ready = true; + pr_info("Driver initialized successfully\n"); + + return 0; + +fail: + pr_err("Failed to init driver\n"); + return -ENODEV; +} + +/* + * If more than one type is supported simultaneously, this function will also + * set the priority between them + */ +static enum pfe_type pfk_get_pfe_type(const struct inode *inode) +{ + if (!inode) + return INVALID_PFE; + + if (pfk_is_ext4_type(inode)) + return EXT4_CRYPT_PFE; + + return INVALID_PFE; +} + +/** + * inode_to_filename() - get the filename from inode pointer. + * @inode: inode pointer + * + * it is used for debug prints. + * + * Return: filename string or "unknown". + */ +char *inode_to_filename(const struct inode *inode) +{ + struct dentry *dentry = NULL; + char *filename = NULL; + + if (hlist_empty(&inode->i_dentry)) + return "unknown"; + + dentry = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); + filename = dentry->d_iname; + + return filename; +} + +/** + * pfk_is_ready() - driver is initialized and ready. + * + * Return: true if the driver is ready. + */ +static inline bool pfk_is_ready(void) +{ + return pfk_ready; +} + +/** + * pfk_bio_get_inode() - get the inode from a bio. + * @bio: Pointer to BIO structure. + * + * Walk the bio struct links to get the inode. + * Please note, that in general bio may consist of several pages from + * several files, but in our case we always assume that all pages come + * from the same file, since our logic ensures it. That is why we only + * walk through the first page to look for inode. + * + * Return: pointer to the inode struct if successful, or NULL otherwise. + * + */ +static struct inode *pfk_bio_get_inode(const struct bio *bio) +{ + struct address_space *mapping; + + if (!bio) + return NULL; + if (!bio->bi_io_vec) + return NULL; + if (!bio->bi_io_vec->bv_page) + return NULL; + if (!bio_has_data((struct bio *)bio)) + return NULL; + + if (PageAnon(bio->bi_io_vec->bv_page)) { + struct inode *inode; + + //Using direct-io (O_DIRECT) without page cache + inode = dio_bio_get_inode((struct bio *)bio); + pr_debug("inode on direct-io, inode = 0x%pK.\n", inode); + + return inode; + } + + mapping = page_mapping(bio->bi_io_vec->bv_page); + if (!mapping) + return NULL; + + if (!mapping->host) + return NULL; + + return bio->bi_io_vec->bv_page->mapping->host; +} + +/** + * pfk_key_size_to_key_type() - translate key size to key size enum + * @key_size: key size in bytes + * @key_size_type: pointer to store the output enum (can be null) + * + * return 0 in case of success, error otherwise (i.e not supported key size) + */ +int pfk_key_size_to_key_type(size_t key_size, + enum ice_crpto_key_size *key_size_type) +{ + /* + * currently only 32 bit key size is supported + * in the future, table with supported key sizes might + * be introduced + */ + + if (key_size != PFK_SUPPORTED_KEY_SIZE) { + pr_err("not supported key size %zu\n", key_size); + return -EINVAL; + } + + if (key_size_type) + *key_size_type = ICE_CRYPTO_KEY_SIZE_256; + + return 0; +} + +/* + * Retrieves filesystem type from inode's superblock + */ +bool pfe_is_inode_filesystem_type(const struct inode *inode, + const char *fs_type) +{ + if (!inode || !fs_type) + return false; + + if (!inode->i_sb) + return false; + + if (!inode->i_sb->s_type) + return false; + + return (strcmp(inode->i_sb->s_type->name, fs_type) == 0); +} + + +/** + * pfk_load_key_start() - loads PFE encryption key to the ICE + * Can also be invoked from non + * PFE context, in this case it + * is not relevant and is_pfe + * flag is set to false + * + * @bio: Pointer to the BIO structure + * @ice_setting: Pointer to ice setting structure that will be filled with + * ice configuration values, including the index to which the key was loaded + * @is_pfe: will be false if inode is not relevant to PFE, in such a case + * it should be treated as non PFE by the block layer + * + * Returns the index where the key is stored in encryption hw and additional + * information that will be used later for configuration of the encryption hw. + * + * Must be followed by pfk_load_key_end when key is no longer used by ice + * + */ +int pfk_load_key_start(const struct bio *bio, + struct ice_crypto_setting *ice_setting, bool *is_pfe, + bool async) +{ + int ret = 0; + struct pfk_key_info key_info = {NULL, NULL, 0, 0}; + enum ice_cryto_algo_mode algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS; + enum ice_crpto_key_size key_size_type = 0; + u32 key_index = 0; + struct inode *inode = NULL; + enum pfe_type which_pfe = INVALID_PFE; + + if (!is_pfe) { + pr_err("is_pfe is NULL\n"); + return -EINVAL; + } + + /* + * only a few errors below can indicate that + * this function was not invoked within PFE context, + * otherwise we will consider it PFE + */ + *is_pfe = true; + + if (!pfk_is_ready()) + return -ENODEV; + + if (!ice_setting) { + pr_err("ice setting is NULL\n"); + return -EINVAL; + } + + inode = pfk_bio_get_inode(bio); + if (!inode) { + *is_pfe = false; + return -EINVAL; + } + + which_pfe = pfk_get_pfe_type(inode); + if (which_pfe == INVALID_PFE) { + *is_pfe = false; + return -EPERM; + } + + pr_debug("parsing file %s with PFE %d\n", + inode_to_filename(inode), which_pfe); + + ret = (*(pfk_parse_inode_ftable[which_pfe])) + (bio, inode, &key_info, &algo_mode, is_pfe); + if (ret != 0) + return ret; + + ret = pfk_key_size_to_key_type(key_info.key_size, &key_size_type); + if (ret != 0) + return ret; + + ret = pfk_kc_load_key_start(key_info.key, key_info.key_size, + key_info.salt, key_info.salt_size, &key_index, async); + if (ret) { + if (ret != -EBUSY && ret != -EAGAIN) + pr_err("start: could not load key into pfk key cache, error %d\n", + ret); + + return ret; + } + + ice_setting->key_size = key_size_type; + ice_setting->algo_mode = algo_mode; + /* hardcoded for now */ + ice_setting->key_mode = ICE_CRYPTO_USE_LUT_SW_KEY; + ice_setting->key_index = key_index; + + pr_debug("loaded key for file %s key_index %d\n", + inode_to_filename(inode), key_index); + + return 0; +} + +/** + * pfk_load_key_end() - marks the PFE key as no longer used by ICE + * Can also be invoked from non + * PFE context, in this case it is not + * relevant and is_pfe flag is + * set to false + * + * @bio: Pointer to the BIO structure + * @is_pfe: Pointer to is_pfe flag, which will be true if function was invoked + * from PFE context + */ +int pfk_load_key_end(const struct bio *bio, bool *is_pfe) +{ + int ret = 0; + struct pfk_key_info key_info = {NULL, NULL, 0, 0}; + enum pfe_type which_pfe = INVALID_PFE; + struct inode *inode = NULL; + + if (!is_pfe) { + pr_err("is_pfe is NULL\n"); + return -EINVAL; + } + + /* only a few errors below can indicate that + * this function was not invoked within PFE context, + * otherwise we will consider it PFE + */ + *is_pfe = true; + + if (!pfk_is_ready()) + return -ENODEV; + + inode = pfk_bio_get_inode(bio); + if (!inode) { + *is_pfe = false; + return -EINVAL; + } + + which_pfe = pfk_get_pfe_type(inode); + if (which_pfe == INVALID_PFE) { + *is_pfe = false; + return -EPERM; + } + + ret = (*(pfk_parse_inode_ftable[which_pfe])) + (bio, inode, &key_info, NULL, is_pfe); + if (ret != 0) + return ret; + + pfk_kc_load_key_end(key_info.key, key_info.key_size, + key_info.salt, key_info.salt_size); + + pr_debug("finished using key for file %s\n", + inode_to_filename(inode)); + + return 0; +} + +/** + * pfk_allow_merge_bio() - Check if 2 BIOs can be merged. + * @bio1: Pointer to first BIO structure. + * @bio2: Pointer to second BIO structure. + * + * Prevent merging of BIOs from encrypted and non-encrypted + * files, or files encrypted with different key. + * Also prevent non encrypted and encrypted data from the same file + * to be merged (ecryptfs header if stored inside file should be non + * encrypted) + * This API is called by the file system block layer. + * + * Return: true if the BIOs allowed to be merged, false + * otherwise. + */ +bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2) +{ + struct inode *inode1 = NULL; + struct inode *inode2 = NULL; + enum pfe_type which_pfe1 = INVALID_PFE; + enum pfe_type which_pfe2 = INVALID_PFE; + + if (!pfk_is_ready()) + return false; + + if (!bio1 || !bio2) + return false; + + if (bio1 == bio2) + return true; + + inode1 = pfk_bio_get_inode(bio1); + inode2 = pfk_bio_get_inode(bio2); + + + which_pfe1 = pfk_get_pfe_type(inode1); + which_pfe2 = pfk_get_pfe_type(inode2); + + /* nodes with different encryption, do not merge */ + if (which_pfe1 != which_pfe2) + return false; + + /* both nodes do not have encryption, allow merge */ + if (which_pfe1 == INVALID_PFE) + return true; + + return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2, + inode1, inode2); +} +/** + * Flush key table on storage core reset. During core reset key configuration + * is lost in ICE. We need to flash the cache, so that the keys will be + * reconfigured again for every subsequent transaction + */ +void pfk_clear_on_reset(void) +{ + if (!pfk_is_ready()) + return; + + pfk_kc_clear_on_reset(); +} + +module_init(pfk_init); +module_exit(pfk_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Per-File-Key driver"); diff --git a/security/pfe/pfk_ext4.c b/security/pfe/pfk_ext4.c new file mode 100644 index 000000000000..c8a527e4a671 --- /dev/null +++ b/security/pfe/pfk_ext4.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Per-File-Key (PFK) - EXT4 + * + * This driver is used for working with EXT4 crypt extension + * + * The key information is stored in node by EXT4 when file is first opened + * and will be later accessed by Block Device Driver to actually load the key + * to encryption hw. + * + * PFK exposes API's for loading and removing keys from encryption hw + * and also API to determine whether 2 adjacent blocks can be agregated by + * Block Layer in one request to encryption hw. + * + */ + + +/* Uncomment the line below to enable debug messages */ +/* #define DEBUG 1 */ +#define pr_fmt(fmt) "pfk_ext4 [%s]: " fmt, __func__ + +#include +#include +#include +#include + +#include "ext4_ice.h" +#include "pfk_ext4.h" + +static bool pfk_ext4_ready; + +/* + * pfk_ext4_deinit() - Deinit function, should be invoked by upper PFK layer + */ +void pfk_ext4_deinit(void) +{ + pfk_ext4_ready = false; +} + +/* + * pfk_ecryptfs_init() - Init function, should be invoked by upper PFK layer + */ +int __init pfk_ext4_init(void) +{ + pfk_ext4_ready = true; + pr_info("PFK EXT4 inited successfully\n"); + + return 0; +} + +/** + * pfk_ecryptfs_is_ready() - driver is initialized and ready. + * + * Return: true if the driver is ready. + */ +static inline bool pfk_ext4_is_ready(void) +{ + return pfk_ext4_ready; +} + +/** + * pfk_ext4_dump_inode() - dumps all interesting info about inode to the screen + * + * + */ +/* + * static void pfk_ext4_dump_inode(const struct inode* inode) + * { + * struct ext4_crypt_info *ci = ext4_encryption_info((struct inode*)inode); + * + * pr_debug("dumping inode with address 0x%p\n", inode); + * pr_debug("S_ISREG is %d\n", S_ISREG(inode->i_mode)); + * pr_debug("EXT4_INODE_ENCRYPT flag is %d\n", + * ext4_test_inode_flag((struct inode*)inode, EXT4_INODE_ENCRYPT)); + * if (ci) { + * pr_debug("crypt_info address 0x%p\n", ci); + * pr_debug("ci->ci_data_mode %d\n", ci->ci_data_mode); + * } else { + * pr_debug("crypt_info is NULL\n"); + * } + * } + */ + +/** + * pfk_is_ext4_type() - return true if inode belongs to ICE EXT4 PFE + * @inode: inode pointer + */ +bool pfk_is_ext4_type(const struct inode *inode) +{ + if (!pfe_is_inode_filesystem_type(inode, "ext4")) + return false; + + return ext4_should_be_processed_by_ice(inode); +} + +/** + * pfk_ext4_parse_cipher() - parse cipher from inode to enum + * @inode: inode + * @algo: pointer to store the output enum (can be null) + * + * return 0 in case of success, error otherwise (i.e not supported cipher) + */ +static int pfk_ext4_parse_cipher(const struct inode *inode, + enum ice_cryto_algo_mode *algo) +{ + /* + * currently only AES XTS algo is supported + * in the future, table with supported ciphers might + * be introduced + */ + + if (!inode) + return -EINVAL; + + if (!ext4_is_aes_xts_cipher(inode)) { + pr_err("ext4 alghoritm is not supported by pfk\n"); + return -EINVAL; + } + + if (algo) + *algo = ICE_CRYPTO_ALGO_MODE_AES_XTS; + + return 0; +} + + +int pfk_ext4_parse_inode(const struct bio *bio, + const struct inode *inode, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo, + bool *is_pfe) +{ + int ret = 0; + + if (!is_pfe) + return -EINVAL; + + /* + * only a few errors below can indicate that + * this function was not invoked within PFE context, + * otherwise we will consider it PFE + */ + *is_pfe = true; + + if (!pfk_ext4_is_ready()) + return -ENODEV; + + if (!inode) + return -EINVAL; + + if (!key_info) + return -EINVAL; + + key_info->key = ext4_get_ice_encryption_key(inode); + if (!key_info->key) { + pr_err("could not parse key from ext4\n"); + return -EINVAL; + } + + key_info->key_size = ext4_get_ice_encryption_key_size(inode); + if (!key_info->key_size) { + pr_err("could not parse key size from ext4\n"); + return -EINVAL; + } + + key_info->salt = ext4_get_ice_encryption_salt(inode); + if (!key_info->salt) { + pr_err("could not parse salt from ext4\n"); + return -EINVAL; + } + + key_info->salt_size = ext4_get_ice_encryption_salt_size(inode); + if (!key_info->salt_size) { + pr_err("could not parse salt size from ext4\n"); + return -EINVAL; + } + + ret = pfk_ext4_parse_cipher(inode, algo); + if (ret != 0) { + pr_err("not supported cipher\n"); + return ret; + } + + return 0; +} + +bool pfk_ext4_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2) +{ + /* if there is no ext4 pfk, don't disallow merging blocks */ + if (!pfk_ext4_is_ready()) + return true; + + if (!inode1 || !inode2) + return false; + + return ext4_is_ice_encryption_info_equal(inode1, inode2); +} diff --git a/security/pfe/pfk_ext4.h b/security/pfe/pfk_ext4.h new file mode 100644 index 000000000000..c33232f35a14 --- /dev/null +++ b/security/pfe/pfk_ext4.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _PFK_EXT4_H_ +#define _PFK_EXT4_H_ + +#include +#include +#include +#include "pfk_internal.h" + +bool pfk_is_ext4_type(const struct inode *inode); + +int pfk_ext4_parse_inode(const struct bio *bio, + const struct inode *inode, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo, + bool *is_pfe); + +bool pfk_ext4_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2); + +int __init pfk_ext4_init(void); + +void pfk_ext4_deinit(void); + +#endif /* _PFK_EXT4_H_ */ diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c new file mode 100644 index 000000000000..16ed5162665d --- /dev/null +++ b/security/pfe/pfk_ice.c @@ -0,0 +1,189 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pfk_ice.h" + + +/**********************************/ +/** global definitions **/ +/**********************************/ + +#define TZ_ES_SET_ICE_KEY 0x2 +#define TZ_ES_INVALIDATE_ICE_KEY 0x3 + +/* index 0 and 1 is reserved for FDE */ +#define MIN_ICE_KEY_INDEX 2 + +#define MAX_ICE_KEY_INDEX 31 + + +#define TZ_ES_SET_ICE_KEY_ID \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, TZ_SVC_ES, TZ_ES_SET_ICE_KEY) + + +#define TZ_ES_INVALIDATE_ICE_KEY_ID \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, \ + TZ_SVC_ES, TZ_ES_INVALIDATE_ICE_KEY) + + +#define TZ_ES_SET_ICE_KEY_PARAM_ID \ + TZ_SYSCALL_CREATE_PARAM_ID_5( \ + TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL) + +#define TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID \ + TZ_SYSCALL_CREATE_PARAM_ID_1( \ + TZ_SYSCALL_PARAM_TYPE_VAL) + +#define ICE_KEY_SIZE 32 +#define ICE_SALT_SIZE 32 + +static uint8_t ice_key[ICE_KEY_SIZE]; +static uint8_t ice_salt[ICE_KEY_SIZE]; + +int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, + char *storage_type) +{ + struct scm_desc desc = {0}; + int ret, ret1; + char *tzbuf_key = (char *)ice_key; + char *tzbuf_salt = (char *)ice_salt; + char *s_type = storage_type; + + uint32_t smc_id = 0; + u32 tzbuflen_key = sizeof(ice_key); + u32 tzbuflen_salt = sizeof(ice_salt); + + if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { + pr_err("%s Invalid index %d\n", __func__, index); + return -EINVAL; + } + if (!key || !salt) { + pr_err("%s Invalid key/salt\n", __func__); + return -EINVAL; + } + + if (!tzbuf_key || !tzbuf_salt) { + pr_err("%s No Memory\n", __func__); + return -ENOMEM; + } + + if (s_type == NULL) { + pr_err("%s Invalid Storage type\n", __func__); + return -EINVAL; + } + + memset(tzbuf_key, 0, tzbuflen_key); + memset(tzbuf_salt, 0, tzbuflen_salt); + + memcpy(ice_key, key, tzbuflen_key); + memcpy(ice_salt, salt, tzbuflen_salt); + + dmac_flush_range(tzbuf_key, tzbuf_key + tzbuflen_key); + dmac_flush_range(tzbuf_salt, tzbuf_salt + tzbuflen_salt); + + smc_id = TZ_ES_SET_ICE_KEY_ID; + + desc.arginfo = TZ_ES_SET_ICE_KEY_PARAM_ID; + desc.args[0] = index; + desc.args[1] = virt_to_phys(tzbuf_key); + desc.args[2] = tzbuflen_key; + desc.args[3] = virt_to_phys(tzbuf_salt); + desc.args[4] = tzbuflen_salt; + + ret = qcom_ice_setup_ice_hw((const char *)s_type, true); + + if (ret) { + pr_err("%s: could not enable clocks: %d\n", __func__, ret); + goto out; + } + + ret = scm_call2(smc_id, &desc); + + if (ret) { + pr_err("%s: Set Key Error: %d\n", __func__, ret); + if (ret == -EBUSY) { + if (qcom_ice_setup_ice_hw((const char *)s_type, false)) + pr_err("%s: clock disable failed\n", __func__); + goto out; + } + /*Try to invalidate the key to keep ICE in proper state*/ + smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; + desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; + desc.args[0] = index; + ret1 = scm_call2(smc_id, &desc); + if (ret1) + pr_err("%s: Invalidate Key Error: %d\n", __func__, + ret1); + goto out; + } + ret = qcom_ice_setup_ice_hw((const char *)s_type, false); + +out: + return ret; +} + +int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) +{ + struct scm_desc desc = {0}; + int ret; + + uint32_t smc_id = 0; + + if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { + pr_err("%s Invalid index %d\n", __func__, index); + return -EINVAL; + } + + if (storage_type == NULL) { + pr_err("%s Invalid Storage type\n", __func__); + return -EINVAL; + } + + smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; + + desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; + desc.args[0] = index; + + ret = qcom_ice_setup_ice_hw((const char *)storage_type, true); + + if (ret) { + pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret); + return ret; + } + + ret = scm_call2(smc_id, &desc); + + if (ret) { + pr_err("%s: Error: 0x%x\n", __func__, ret); + if (qcom_ice_setup_ice_hw((const char *)storage_type, false)) + pr_err("%s: could not disable clocks\n", __func__); + } else { + ret = qcom_ice_setup_ice_hw((const char *)storage_type, false); + } + + return ret; +} diff --git a/security/pfe/pfk_ice.h b/security/pfe/pfk_ice.h new file mode 100644 index 000000000000..31772e798636 --- /dev/null +++ b/security/pfe/pfk_ice.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef PFK_ICE_H_ +#define PFK_ICE_H_ + +/* + * PFK ICE + * + * ICE keys configuration through scm calls. + * + */ + +#include + +int pfk_ice_init(void); +int pfk_ice_deinit(void); + +int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, + char *storage_type); +int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type); + + +#endif /* PFK_ICE_H_ */ diff --git a/security/pfe/pfk_internal.h b/security/pfe/pfk_internal.h new file mode 100644 index 000000000000..3214327b8bcd --- /dev/null +++ b/security/pfe/pfk_internal.h @@ -0,0 +1,34 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _PFK_INTERNAL_H_ +#define _PFK_INTERNAL_H_ + +#include +#include + +struct pfk_key_info { + const unsigned char *key; + const unsigned char *salt; + size_t key_size; + size_t salt_size; +}; + +int pfk_key_size_to_key_type(size_t key_size, + enum ice_crpto_key_size *key_size_type); + +bool pfe_is_inode_filesystem_type(const struct inode *inode, + const char *fs_type); + +char *inode_to_filename(const struct inode *inode); + +#endif /* _PFK_INTERNAL_H_ */ diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c new file mode 100644 index 000000000000..a405d05ccbfb --- /dev/null +++ b/security/pfe/pfk_kc.c @@ -0,0 +1,905 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * PFK Key Cache + * + * Key Cache used internally in PFK. + * The purpose of the cache is to save access time to QSEE when loading keys. + * Currently the cache is the same size as the total number of keys that can + * be loaded to ICE. Since this number is relatively small, the algorithms for + * cache eviction are simple, linear and based on last usage timestamp, i.e + * the node that will be evicted is the one with the oldest timestamp. + * Empty entries always have the oldest timestamp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pfk_kc.h" +#include "pfk_ice.h" + + +/** the first available index in ice engine */ +#define PFK_KC_STARTING_INDEX 2 + +/** currently the only supported key and salt sizes */ +#define PFK_KC_KEY_SIZE 32 +#define PFK_KC_SALT_SIZE 32 + +/** Table size */ +/* TODO replace by some constant from ice.h */ +#define PFK_KC_TABLE_SIZE ((32) - (PFK_KC_STARTING_INDEX)) + +/** The maximum key and salt size */ +#define PFK_MAX_KEY_SIZE PFK_KC_KEY_SIZE +#define PFK_MAX_SALT_SIZE PFK_KC_SALT_SIZE +#define PFK_UFS "ufs" + +static DEFINE_SPINLOCK(kc_lock); +static unsigned long flags; +static bool kc_ready; +static char *s_type = "sdcc"; + +/** + * enum pfk_kc_entry_state - state of the entry inside kc table + * + * @FREE: entry is free + * @ACTIVE_ICE_PRELOAD: entry is actively used by ICE engine + and cannot be used by others. SCM call + to load key to ICE is pending to be performed + * @ACTIVE_ICE_LOADED: entry is actively used by ICE engine and + cannot be used by others. SCM call to load the + key to ICE was successfully executed and key is + now loaded + * @INACTIVE_INVALIDATING: entry is being invalidated during file close + and cannot be used by others until invalidation + is complete + * @INACTIVE: entry's key is already loaded, but is not + currently being used. It can be re-used for + optimization and to avoid SCM call cost or + it can be taken by another key if there are + no FREE entries + * @SCM_ERROR: error occurred while scm call was performed to + load the key to ICE + */ +enum pfk_kc_entry_state { + FREE, + ACTIVE_ICE_PRELOAD, + ACTIVE_ICE_LOADED, + INACTIVE_INVALIDATING, + INACTIVE, + SCM_ERROR +}; + +struct kc_entry { + unsigned char key[PFK_MAX_KEY_SIZE]; + size_t key_size; + + unsigned char salt[PFK_MAX_SALT_SIZE]; + size_t salt_size; + + u64 time_stamp; + u32 key_index; + + struct task_struct *thread_pending; + + enum pfk_kc_entry_state state; + + /* ref count for the number of requests in the HW queue for this key */ + int loaded_ref_cnt; + int scm_error; +}; + +static struct kc_entry kc_table[PFK_KC_TABLE_SIZE]; + +/** + * kc_is_ready() - driver is initialized and ready. + * + * Return: true if the key cache is ready. + */ +static inline bool kc_is_ready(void) +{ + return kc_ready; +} + +static inline void kc_spin_lock(void) +{ + spin_lock_irqsave(&kc_lock, flags); +} + +static inline void kc_spin_unlock(void) +{ + spin_unlock_irqrestore(&kc_lock, flags); +} + +/** + * kc_entry_is_available() - checks whether the entry is available + * + * Return true if it is , false otherwise or if invalid + * Should be invoked under spinlock + */ +static bool kc_entry_is_available(const struct kc_entry *entry) +{ + if (!entry) + return false; + + return (entry->state == FREE || entry->state == INACTIVE); +} + +/** + * kc_entry_wait_till_available() - waits till entry is available + * + * Returns 0 in case of success or -ERESTARTSYS if the wait was interrupted + * by signal + * + * Should be invoked under spinlock + */ +static int kc_entry_wait_till_available(struct kc_entry *entry) +{ + int res = 0; + + while (!kc_entry_is_available(entry)) { + set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { + res = -ERESTARTSYS; + break; + } + /* assuming only one thread can try to invalidate + * the same entry + */ + entry->thread_pending = current; + kc_spin_unlock(); + schedule(); + kc_spin_lock(); + } + set_current_state(TASK_RUNNING); + + return res; +} + +/** + * kc_entry_start_invalidating() - moves entry to state + * INACTIVE_INVALIDATING + * If entry is in use, waits till + * it gets available + * @entry: pointer to entry + * + * Return 0 in case of success, otherwise error + * Should be invoked under spinlock + */ +static int kc_entry_start_invalidating(struct kc_entry *entry) +{ + int res; + + res = kc_entry_wait_till_available(entry); + if (res) + return res; + + entry->state = INACTIVE_INVALIDATING; + + return 0; +} + +/** + * kc_entry_finish_invalidating() - moves entry to state FREE + * wakes up all the tasks waiting + * on it + * + * @entry: pointer to entry + * + * Return 0 in case of success, otherwise error + * Should be invoked under spinlock + */ +static void kc_entry_finish_invalidating(struct kc_entry *entry) +{ + if (!entry) + return; + + if (entry->state != INACTIVE_INVALIDATING) + return; + + entry->state = FREE; +} + +/** + * kc_min_entry() - compare two entries to find one with minimal time + * @a: ptr to the first entry. If NULL the other entry will be returned + * @b: pointer to the second entry + * + * Return the entry which timestamp is the minimal, or b if a is NULL + */ +static inline struct kc_entry *kc_min_entry(struct kc_entry *a, + struct kc_entry *b) +{ + if (!a) + return b; + + if (time_before64(b->time_stamp, a->time_stamp)) + return b; + + return a; +} + +/** + * kc_entry_at_index() - return entry at specific index + * @index: index of entry to be accessed + * + * Return entry + * Should be invoked under spinlock + */ +static struct kc_entry *kc_entry_at_index(int index) +{ + return &(kc_table[index]); +} + +/** + * kc_find_key_at_index() - find kc entry starting at specific index + * @key: key to look for + * @key_size: the key size + * @salt: salt to look for + * @salt_size: the salt size + * @sarting_index: index to start search with, if entry found, updated with + * index of that entry + * + * Return entry or NULL in case of error + * Should be invoked under spinlock + */ +static struct kc_entry *kc_find_key_at_index(const unsigned char *key, + size_t key_size, const unsigned char *salt, size_t salt_size, + int *starting_index) +{ + struct kc_entry *entry = NULL; + int i = 0; + + for (i = *starting_index; i < PFK_KC_TABLE_SIZE; i++) { + entry = kc_entry_at_index(i); + + if (salt != NULL) { + if (entry->salt_size != salt_size) + continue; + + if (memcmp(entry->salt, salt, salt_size) != 0) + continue; + } + + if (entry->key_size != key_size) + continue; + + if (memcmp(entry->key, key, key_size) == 0) { + *starting_index = i; + return entry; + } + } + + return NULL; +} + +/** + * kc_find_key() - find kc entry + * @key: key to look for + * @key_size: the key size + * @salt: salt to look for + * @salt_size: the salt size + * + * Return entry or NULL in case of error + * Should be invoked under spinlock + */ +static struct kc_entry *kc_find_key(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size) +{ + int index = 0; + + return kc_find_key_at_index(key, key_size, salt, salt_size, &index); +} + +/** + * kc_find_oldest_entry_non_locked() - finds the entry with minimal timestamp + * that is not locked + * + * Returns entry with minimal timestamp. Empty entries have timestamp + * of 0, therefore they are returned first. + * If all the entries are locked, will return NULL + * Should be invoked under spin lock + */ +static struct kc_entry *kc_find_oldest_entry_non_locked(void) +{ + struct kc_entry *curr_min_entry = NULL; + struct kc_entry *entry = NULL; + int i = 0; + + for (i = 0; i < PFK_KC_TABLE_SIZE; i++) { + entry = kc_entry_at_index(i); + + if (entry->state == FREE) + return entry; + + if (entry->state == INACTIVE) + curr_min_entry = kc_min_entry(curr_min_entry, entry); + } + + return curr_min_entry; +} + +/** + * kc_update_timestamp() - updates timestamp of entry to current + * + * @entry: entry to update + * + */ +static void kc_update_timestamp(struct kc_entry *entry) +{ + if (!entry) + return; + + entry->time_stamp = get_jiffies_64(); +} + +/** + * kc_clear_entry() - clear the key from entry and mark entry not in use + * + * @entry: pointer to entry + * + * Should be invoked under spinlock + */ +static void kc_clear_entry(struct kc_entry *entry) +{ + if (!entry) + return; + + memset(entry->key, 0, entry->key_size); + memset(entry->salt, 0, entry->salt_size); + + entry->key_size = 0; + entry->salt_size = 0; + + entry->time_stamp = 0; + entry->scm_error = 0; + + entry->state = FREE; + + entry->loaded_ref_cnt = 0; + entry->thread_pending = NULL; +} + +/** + * kc_update_entry() - replaces the key in given entry and + * loads the new key to ICE + * + * @entry: entry to replace key in + * @key: key + * @key_size: key_size + * @salt: salt + * @salt_size: salt_size + * + * The previous key is securely released and wiped, the new one is loaded + * to ICE. + * Should be invoked under spinlock + */ +static int kc_update_entry(struct kc_entry *entry, const unsigned char *key, + size_t key_size, const unsigned char *salt, size_t salt_size) +{ + int ret; + + kc_clear_entry(entry); + + memcpy(entry->key, key, key_size); + entry->key_size = key_size; + + memcpy(entry->salt, salt, salt_size); + entry->salt_size = salt_size; + + /* Mark entry as no longer free before releasing the lock */ + entry->state = ACTIVE_ICE_PRELOAD; + kc_spin_unlock(); + + ret = qti_pfk_ice_set_key(entry->key_index, entry->key, + entry->salt, s_type); + + kc_spin_lock(); + return ret; +} + +/** + * pfk_kc_init() - init function + * + * Return 0 in case of success, error otherwise + */ +int pfk_kc_init(void) +{ + int i = 0; + struct kc_entry *entry = NULL; + + kc_spin_lock(); + for (i = 0; i < PFK_KC_TABLE_SIZE; i++) { + entry = kc_entry_at_index(i); + entry->key_index = PFK_KC_STARTING_INDEX + i; + } + kc_ready = true; + kc_spin_unlock(); + return 0; +} + +/** + * pfk_kc_denit() - deinit function + * + * Return 0 in case of success, error otherwise + */ +int pfk_kc_deinit(void) +{ + int res = pfk_kc_clear(); + + kc_ready = false; + return res; +} + +/** + * pfk_kc_load_key_start() - retrieve the key from cache or add it if + * it's not there and return the ICE hw key index in @key_index. + * @key: pointer to the key + * @key_size: the size of the key + * @salt: pointer to the salt + * @salt_size: the size of the salt + * @key_index: the pointer to key_index where the output will be stored + * @async: whether scm calls are allowed in the caller context + * + * If key is present in cache, than the key_index will be retrieved from cache. + * If it is not present, the oldest entry from kc table will be evicted, + * the key will be loaded to ICE via QSEE to the index that is the evicted + * entry number and stored in cache. + * Entry that is going to be used is marked as being used, it will mark + * as not being used when ICE finishes using it and pfk_kc_load_key_end + * will be invoked. + * As QSEE calls can only be done from a non-atomic context, when @async flag + * is set to 'false', it specifies that it is ok to make the calls in the + * current context. Otherwise, when @async is set, the caller should retry the + * call again from a different context, and -EAGAIN error will be returned. + * + * Return 0 in case of success, error otherwise + */ +int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size, u32 *key_index, + bool async) +{ + int ret = 0; + struct kc_entry *entry = NULL; + bool entry_exists = false; + + if (!kc_is_ready()) + return -ENODEV; + + if (!key || !salt || !key_index) { + pr_err("%s key/salt/key_index NULL\n", __func__); + return -EINVAL; + } + + if (key_size != PFK_KC_KEY_SIZE) { + pr_err("unsupported key size %zu\n", key_size); + return -EINVAL; + } + + if (salt_size != PFK_KC_SALT_SIZE) { + pr_err("unsupported salt size %zu\n", salt_size); + return -EINVAL; + } + + kc_spin_lock(); + + entry = kc_find_key(key, key_size, salt, salt_size); + if (!entry) { + if (async) { + pr_debug("%s task will populate entry\n", __func__); + kc_spin_unlock(); + return -EAGAIN; + } + + entry = kc_find_oldest_entry_non_locked(); + if (!entry) { + /* could not find a single non locked entry, + * return EBUSY to upper layers so that the + * request will be rescheduled + */ + kc_spin_unlock(); + return -EBUSY; + } + } else { + entry_exists = true; + } + + pr_debug("entry with index %d is in state %d\n", + entry->key_index, entry->state); + + switch (entry->state) { + case (INACTIVE): + if (entry_exists) { + kc_update_timestamp(entry); + entry->state = ACTIVE_ICE_LOADED; + + if (!strcmp(s_type, (char *)PFK_UFS)) { + if (async) + entry->loaded_ref_cnt++; + } else { + entry->loaded_ref_cnt++; + } + break; + } + case (FREE): + ret = kc_update_entry(entry, key, key_size, salt, salt_size); + if (ret) { + entry->state = SCM_ERROR; + entry->scm_error = ret; + pr_err("%s: key load error (%d)\n", __func__, ret); + } else { + kc_update_timestamp(entry); + entry->state = ACTIVE_ICE_LOADED; + + /* + * In case of UFS only increase ref cnt for async calls, + * sync calls from within work thread do not pass + * requests further to HW + */ + if (!strcmp(s_type, (char *)PFK_UFS)) { + if (async) + entry->loaded_ref_cnt++; + } else { + entry->loaded_ref_cnt++; + } + } + break; + case (ACTIVE_ICE_PRELOAD): + case (INACTIVE_INVALIDATING): + ret = -EAGAIN; + break; + case (ACTIVE_ICE_LOADED): + kc_update_timestamp(entry); + + if (!strcmp(s_type, (char *)PFK_UFS)) { + if (async) + entry->loaded_ref_cnt++; + } else { + entry->loaded_ref_cnt++; + } + break; + case(SCM_ERROR): + ret = entry->scm_error; + kc_clear_entry(entry); + entry->state = FREE; + break; + default: + pr_err("invalid state %d for entry with key index %d\n", + entry->state, entry->key_index); + ret = -EINVAL; + } + + *key_index = entry->key_index; + kc_spin_unlock(); + + return ret; +} + +/** + * pfk_kc_load_key_end() - finish the process of key loading that was started + * by pfk_kc_load_key_start + * by marking the entry as not + * being in use + * @key: pointer to the key + * @key_size: the size of the key + * @salt: pointer to the salt + * @salt_size: the size of the salt + * + */ +void pfk_kc_load_key_end(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size) +{ + struct kc_entry *entry = NULL; + struct task_struct *tmp_pending = NULL; + int ref_cnt = 0; + + if (!kc_is_ready()) + return; + + if (!key || !salt) + return; + + if (key_size != PFK_KC_KEY_SIZE) + return; + + if (salt_size != PFK_KC_SALT_SIZE) + return; + + kc_spin_lock(); + + entry = kc_find_key(key, key_size, salt, salt_size); + if (!entry) { + kc_spin_unlock(); + pr_err("internal error, there should an entry to unlock\n"); + + return; + } + ref_cnt = --entry->loaded_ref_cnt; + + if (ref_cnt < 0) + pr_err("internal error, ref count should never be negative\n"); + + if (!ref_cnt) { + entry->state = INACTIVE; + /* + * wake-up invalidation if it's waiting + * for the entry to be released + */ + if (entry->thread_pending) { + tmp_pending = entry->thread_pending; + entry->thread_pending = NULL; + + kc_spin_unlock(); + wake_up_process(tmp_pending); + return; + } + } + + kc_spin_unlock(); +} + +/** + * pfk_kc_remove_key() - remove the key from cache and from ICE engine + * @key: pointer to the key + * @key_size: the size of the key + * @salt: pointer to the key + * @salt_size: the size of the key + * + * Return 0 in case of success, error otherwise (also in case of non + * (existing key) + */ +int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size) +{ + struct kc_entry *entry = NULL; + int res = 0; + + if (!kc_is_ready()) + return -ENODEV; + + if (!key) + return -EINVAL; + + if (!salt) + return -EINVAL; + + if (key_size != PFK_KC_KEY_SIZE) + return -EINVAL; + + if (salt_size != PFK_KC_SALT_SIZE) + return -EINVAL; + + kc_spin_lock(); + + entry = kc_find_key(key, key_size, salt, salt_size); + if (!entry) { + pr_debug("%s: key does not exist\n", __func__); + kc_spin_unlock(); + return -EINVAL; + } + + res = kc_entry_start_invalidating(entry); + if (res != 0) { + kc_spin_unlock(); + return res; + } + kc_clear_entry(entry); + + kc_spin_unlock(); + + qti_pfk_ice_invalidate_key(entry->key_index, s_type); + + kc_spin_lock(); + kc_entry_finish_invalidating(entry); + kc_spin_unlock(); + + return 0; +} + +/** + * pfk_kc_remove_key() - remove the key from cache and from ICE engine + * when no salt is available. Will only search key part, if there are several, + * all will be removed + * + * @key: pointer to the key + * @key_size: the size of the key + * + * Return 0 in case of success, error otherwise (also for non-existing key) + */ +int pfk_kc_remove_key(const unsigned char *key, size_t key_size) +{ + struct kc_entry *entry = NULL; + int index = 0; + int temp_indexes[PFK_KC_TABLE_SIZE] = {0}; + int temp_indexes_size = 0; + int i = 0; + int res = 0; + + if (!kc_is_ready()) + return -ENODEV; + + if (!key) + return -EINVAL; + + if (key_size != PFK_KC_KEY_SIZE) + return -EINVAL; + + memset(temp_indexes, -1, sizeof(temp_indexes)); + + kc_spin_lock(); + + entry = kc_find_key_at_index(key, key_size, NULL, 0, &index); + if (!entry) { + pr_err("%s: key does not exist\n", __func__); + kc_spin_unlock(); + return -EINVAL; + } + + res = kc_entry_start_invalidating(entry); + if (res != 0) { + kc_spin_unlock(); + return res; + } + + temp_indexes[temp_indexes_size++] = index; + kc_clear_entry(entry); + + /* let's clean additional entries with the same key if there are any */ + do { + index++; + entry = kc_find_key_at_index(key, key_size, NULL, 0, &index); + if (!entry) + break; + + res = kc_entry_start_invalidating(entry); + if (res != 0) { + kc_spin_unlock(); + goto out; + } + + temp_indexes[temp_indexes_size++] = index; + + kc_clear_entry(entry); + + + } while (true); + + kc_spin_unlock(); + + temp_indexes_size--; + for (i = temp_indexes_size; i >= 0 ; i--) + qti_pfk_ice_invalidate_key( + kc_entry_at_index(temp_indexes[i])->key_index, + s_type); + + /* fall through */ + res = 0; + +out: + kc_spin_lock(); + for (i = temp_indexes_size; i >= 0 ; i--) + kc_entry_finish_invalidating( + kc_entry_at_index(temp_indexes[i])); + kc_spin_unlock(); + + return res; +} + +/** + * pfk_kc_clear() - clear the table and remove all keys from ICE + * + * Return 0 on success, error otherwise + * + */ +int pfk_kc_clear(void) +{ + struct kc_entry *entry = NULL; + int i = 0; + int res = 0; + + if (!kc_is_ready()) + return -ENODEV; + + kc_spin_lock(); + for (i = 0; i < PFK_KC_TABLE_SIZE; i++) { + entry = kc_entry_at_index(i); + res = kc_entry_start_invalidating(entry); + if (res != 0) { + kc_spin_unlock(); + goto out; + } + kc_clear_entry(entry); + } + kc_spin_unlock(); + + for (i = 0; i < PFK_KC_TABLE_SIZE; i++) + qti_pfk_ice_invalidate_key(kc_entry_at_index(i)->key_index, + s_type); + + /* fall through */ + res = 0; +out: + kc_spin_lock(); + for (i = 0; i < PFK_KC_TABLE_SIZE; i++) + kc_entry_finish_invalidating(kc_entry_at_index(i)); + kc_spin_unlock(); + + return res; +} + +/** + * pfk_kc_clear_on_reset() - clear the table and remove all keys from ICE + * The assumption is that at this point we don't have any pending transactions + * Also, there is no need to clear keys from ICE + * + * Return 0 on success, error otherwise + * + */ +void pfk_kc_clear_on_reset(void) +{ + struct kc_entry *entry = NULL; + int i = 0; + + if (!kc_is_ready()) + return; + + kc_spin_lock(); + for (i = 0; i < PFK_KC_TABLE_SIZE; i++) { + entry = kc_entry_at_index(i); + kc_clear_entry(entry); + } + kc_spin_unlock(); +} + +static int pfk_kc_find_storage_type(char **device) +{ + char boot[20] = {'\0'}; + char *match = (char *)strnstr(saved_command_line, + "androidboot.bootdevice=", + strlen(saved_command_line)); + if (match) { + memcpy(boot, (match + strlen("androidboot.bootdevice=")), + sizeof(boot) - 1); + if (strnstr(boot, PFK_UFS, strlen(boot))) + *device = PFK_UFS; + + return 0; + } + return -EINVAL; +} + +static int __init pfk_kc_pre_init(void) +{ + return pfk_kc_find_storage_type(&s_type); +} + +static void __exit pfk_kc_exit(void) +{ + s_type = NULL; +} + +module_init(pfk_kc_pre_init); +module_exit(pfk_kc_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Per-File-Key-KC driver"); diff --git a/security/pfe/pfk_kc.h b/security/pfe/pfk_kc.h new file mode 100644 index 000000000000..6adeee2259cd --- /dev/null +++ b/security/pfe/pfk_kc.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef PFK_KC_H_ +#define PFK_KC_H_ + +#include + +int pfk_kc_init(void); +int pfk_kc_deinit(void); +int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size, u32 *key_index, + bool async); +void pfk_kc_load_key_end(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size); +int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size); +int pfk_kc_remove_key(const unsigned char *key, size_t key_size); +int pfk_kc_clear(void); +void pfk_kc_clear_on_reset(void); +extern char *saved_command_line; + + +#endif /* PFK_KC_H_ */ diff --git a/security/security.c b/security/security.c index e43c50cbdcbf..35c8dcec61f3 100644 --- a/security/security.c +++ b/security/security.c @@ -525,6 +525,14 @@ int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode } EXPORT_SYMBOL_GPL(security_inode_create); +int security_inode_post_create(struct inode *dir, struct dentry *dentry, + umode_t mode) +{ + if (unlikely(IS_PRIVATE(dir))) + return 0; + return call_int_hook(inode_post_create, 0, dir, dentry, mode); +} + int security_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { @@ -1700,6 +1708,8 @@ struct security_hook_heads security_hook_heads __lsm_ro_after_init = { .inode_init_security = LIST_HEAD_INIT(security_hook_heads.inode_init_security), .inode_create = LIST_HEAD_INIT(security_hook_heads.inode_create), + .inode_post_create = + LIST_HEAD_INIT(security_hook_heads.inode_post_create), .inode_link = LIST_HEAD_INIT(security_hook_heads.inode_link), .inode_unlink = LIST_HEAD_INIT(security_hook_heads.inode_unlink), .inode_symlink = diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 43535cdd4c37..60cdcf44da18 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -25,8 +25,9 @@ #include #include #include -#include "flask.h" -#include "avc.h" +//#include "flask.h" +//#include "avc.h" +#include "security.h" struct task_security_struct { u32 osid; /* SID prior to last execve */ @@ -52,6 +53,8 @@ struct inode_security_struct { u32 sid; /* SID of this object */ u16 sclass; /* security class of this object */ unsigned char initialized; /* initialization flag */ + u32 tag; /* Per-File-Encryption tag */ + void *pfk_data; /* Per-File-Key data from ecryptfs */ struct mutex lock; }; diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 308a286c6cbe..b8e98c111b2f 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -12,7 +12,6 @@ #include #include #include -#include "flask.h" #define SECSID_NULL 0x00000000 /* unspecified SID */ #define SECSID_WILD 0xffffffff /* wildcard SID */ -- GitLab From d4ec6dfb83359d6b7da116035cc70314a694c10f Mon Sep 17 00:00:00 2001 From: Narender Ankam Date: Mon, 21 May 2018 19:00:21 +0530 Subject: [PATCH 330/855] ARM: dts: msm: update panel status command properties Update DSI panel status command properties for truly-1080p panel on msm8953 platform. Change-Id: I4c00daa91805a8e3e41ef97f21d9871514587faf Signed-off-by: Narender Ankam --- .../arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi index f7671dcff4ad..7ee30f6c5b4f 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi @@ -75,7 +75,13 @@ 23 1e 08 09 05 03 04 a0 23 1a 08 09 05 03 04 a0]; qcom,esd-check-enabled; - qcom,mdss-dsi-panel-status-check-mode = "bta_check"; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-panel-on-check-value = <0x1c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-max-error-count = <3>; }; @@ -86,7 +92,13 @@ 23 1e 08 09 05 03 04 a0 23 1a 08 09 05 03 04 a0]; qcom,esd-check-enabled; - qcom,mdss-dsi-panel-status-check-mode = "bta_check"; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-panel-on-check-value = <0x1c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-max-error-count = <3>; }; &dsi_r69006_1080p_video { -- GitLab From e4578769c0c3ecf752dbacfb2690a6e81a12ff76 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Thu, 5 Apr 2018 16:44:40 +0530 Subject: [PATCH 331/855] ARM: dts: msm: Use bw_vbif as GPU governor on MSM8909 Use bw_vbif as governor on MSM8909 instead of bw_hwmon for GPU and also remove unused bandwidth voting levels for bw_tbl. Change-Id: Ic6df6e8ef867965281ef083f7d81ad62bdb3e7c0 Signed-off-by: Deepak Kumar Signed-off-by: Archana Sriram --- arch/arm64/boot/dts/qcom/msm8909-gpu.dtsi | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8909-gpu.dtsi b/arch/arm64/boot/dts/qcom/msm8909-gpu.dtsi index dc95570da9b5..180d6c3385d0 100644 --- a/arch/arm64/boot/dts/qcom/msm8909-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909-gpu.dtsi @@ -19,26 +19,15 @@ /* To use BIMC based bus governor */ gpubw: qcom,gpubw { compatible = "qcom,devbw"; - governor = "bw_hwmon"; + governor = "bw_vbif"; qcom,src-dst-ports = <26 512>; qcom,bw-tbl = < 0 >, /* 9.6 MHz */ - < 381 >, /* 50.0 MHz */ - < 762 >, /* 100.0 MHz */ < 1525 >, /* 200.0 MHz */ < 3051 >, /* 400.0 MHz */ < 4066 >; /* 533.0 MHz */ }; - qcom,gpu-bwmon@410000 { - compatible = "qcom,bimc-bwmon2"; - reg = <0x00410000 0x300>, <0x00401000 0x200>; - reg-names = "base", "global_base"; - interrupts = <0 183 4>; - qcom,mport = <2>; - qcom,target-dev = <&gpubw>; - }; - msm_gpu: qcom,kgsl-3d0@01c00000 { label = "kgsl-3d0"; compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; @@ -103,24 +92,32 @@ reg = <0>; qcom,gpu-freq = <456000000>; qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <3>; }; qcom,gpu-pwrlevel@1 { reg = <1>; qcom,gpu-freq = <307200000>; qcom,bus-freq = <2>; + qcom,bus-min = <2>; + qcom,bus-max = <3>; }; qcom,gpu-pwrlevel@2 { reg = <2>; qcom,gpu-freq = <200000000>; - qcom,bus-freq = <1>; + qcom,bus-freq = <2>; + qcom,bus-min = <1>; + qcom,bus-max = <2>; }; qcom,gpu-pwrlevel@3 { reg = <3>; qcom,gpu-freq = <19200000>; qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; }; }; -- GitLab From 4b2ba2eab07ccf78417641382c4b811a8120490e Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Wed, 2 May 2018 16:02:13 +0530 Subject: [PATCH 332/855] defconfig: sdm845: Enable FBE config flag for ext4 FS Enable corresponding flags for HW based file encryption. Change-Id: I994dfed3b2e4256dab1ef339ebcb808f4c293f9e Signed-off-by: Neeraj Soni --- arch/arm64/configs/sdm845-perf_defconfig | 3 +++ arch/arm64/configs/sdm845_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig index fe5b5b565f8e..a29cfa70f228 100644 --- a/arch/arm64/configs/sdm845-perf_defconfig +++ b/arch/arm64/configs/sdm845-perf_defconfig @@ -572,6 +572,8 @@ CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_QUOTA=y @@ -605,6 +607,7 @@ CONFIG_CORESIGHT_CTI=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y +CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig index 666f350b632f..d20d9edbebe7 100644 --- a/arch/arm64/configs/sdm845_defconfig +++ b/arch/arm64/configs/sdm845_defconfig @@ -593,6 +593,8 @@ CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_QUOTA=y @@ -670,6 +672,7 @@ CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y +CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y -- GitLab From 04989891ff5d0d59f9a84f629c1fd7b638ab3b98 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Thu, 3 May 2018 10:50:33 +0530 Subject: [PATCH 333/855] ARM: dts: msm: Add thermal zone configuration for SDM439 Add usr thermal zone configurations for adc_tm channels pa_therm0 and quiet_therm in SDM439. Change-Id: I44053bb228056921d65085b34523d059cad99398 Signed-off-by: Jishnu Prakash --- arch/arm64/boot/dts/qcom/sdm439-pm8953.dtsi | 15 +++++++++++++++ arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm439-pm8953.dtsi b/arch/arm64/boot/dts/qcom/sdm439-pm8953.dtsi index d34c34a8b120..615489eb92a0 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-pm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-pm8953.dtsi @@ -271,6 +271,21 @@ }; }; }; + + pa-therm0 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8953_adc_tm 0x36>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; }; &pm8953_vadc { diff --git a/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi b/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi index bc2ba9f04d17..b306bc0a05d4 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi @@ -184,4 +184,19 @@ }; }; }; + + quiet-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmi632_adc_tm 0x53>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; }; -- GitLab From 53209d2c5710ec4052050898b8d833330e4f8e9a Mon Sep 17 00:00:00 2001 From: Vijay kumar Tumati Date: Mon, 21 May 2018 11:44:41 +0530 Subject: [PATCH 334/855] msm: camera: sensor: Correct custom voltage on MSM8953 Change the voltage to match the other voting on same regulator. Change-Id: Ic97345d44c85c7c6baaaffd8803e4963a07c39e8 Signed-off-by: Vijay kumar Tumati --- arch/arm64/boot/dts/qcom/msm8953-camera-sensor-cdp.dtsi | 4 ++-- arch/arm64/boot/dts/qcom/msm8953-camera-sensor-mtp.dtsi | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-cdp.dtsi index 6e961b117953..d47dd7500f5b 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-cdp.dtsi @@ -207,8 +207,8 @@ cam_v_custom1-supply = <&pm8953_l23>; qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf", "cam_vana", "cam_v_custom1"; - qcom,cam-vreg-min-voltage = <0 1200000 2850000 2800000 1220000>; - qcom,cam-vreg-max-voltage = <0 1200000 2850000 2800000 1220000>; + qcom,cam-vreg-min-voltage = <0 1200000 2850000 2800000 1200000>; + qcom,cam-vreg-max-voltage = <0 1200000 2850000 2800000 1200000>; qcom,cam-vreg-op-mode = <0 105000 100000 80000 105000>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_default diff --git a/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-mtp.dtsi index 6e961b117953..d47dd7500f5b 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-camera-sensor-mtp.dtsi @@ -207,8 +207,8 @@ cam_v_custom1-supply = <&pm8953_l23>; qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vaf", "cam_vana", "cam_v_custom1"; - qcom,cam-vreg-min-voltage = <0 1200000 2850000 2800000 1220000>; - qcom,cam-vreg-max-voltage = <0 1200000 2850000 2800000 1220000>; + qcom,cam-vreg-min-voltage = <0 1200000 2850000 2800000 1200000>; + qcom,cam-vreg-max-voltage = <0 1200000 2850000 2800000 1200000>; qcom,cam-vreg-op-mode = <0 105000 100000 80000 105000>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_default -- GitLab From 3de06402a3a7fa8036a186852adb864048e5bf16 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Tue, 22 May 2018 17:31:53 +0530 Subject: [PATCH 335/855] ARM: dts: msm: Disable SPDM governor on SDM632 CPU performance is impacted due to SPDM governor, disable it for now and will be enabled back if required. Change-Id: I269810ce0def21aea13c8cc11367817c4da01757 Signed-off-by: Odelu Kukatla --- arch/arm64/boot/dts/qcom/sdm632.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi index 67efe0f85d96..5c68dec33557 100644 --- a/arch/arm64/boot/dts/qcom/sdm632.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi @@ -38,6 +38,16 @@ compatible = "qcom,cc-debug-sdm632"; }; +&soc { + devfreq_spdm_cpu { + status = "disabled"; + }; + + devfreq_spdm_gov { + status = "disabled"; + }; +}; + &clock_gcc_gfx { compatible = "qcom,gcc-gfx-sdm632"; qcom,gfxfreq-corner = -- GitLab From 9bb3107789cdec635dada00749a932714bfc669d Mon Sep 17 00:00:00 2001 From: Vishnuvardhan Prodduturi Date: Tue, 22 May 2018 17:59:36 +0530 Subject: [PATCH 336/855] msm: mdss: Remove explicit call to disable esd thread Esd thread will automatically be disabled using fb notifier when display is off. So, remove explicit call to disable esd in display off sequence to avoid mutex deadlock. Change-Id: Ifc7f7f32e0881fa49ea816150f2b55f41a5ff9a3 Signed-off-by: Vishnuvardhan Prodduturi --- drivers/video/fbdev/msm/mdss_dsi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index d3e52698d372..816eed022994 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -2751,7 +2751,6 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, break; case MDSS_EVENT_PANEL_OFF: power_state = (int) (unsigned long) arg; - disable_esd_thread(); ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE; if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_blank(pdata, power_state); -- GitLab From dbab65be6bdea68b6a201d03334b44a02860dd2c Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 11 Apr 2018 18:13:30 -0600 Subject: [PATCH 337/855] usbip: usbip_host: refine probe and disconnect debug msgs to be useful commit 28b68acc4a88dcf91fd1dcf2577371dc9bf574cc upstream. Refine probe and disconnect debug msgs to be useful and say what is in progress. Signed-off-by: Shuah Khan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/stub_dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c index 3550224f4d69..70973ca36a4d 100644 --- a/drivers/usb/usbip/stub_dev.c +++ b/drivers/usb/usbip/stub_dev.c @@ -316,7 +316,7 @@ static int stub_probe(struct usb_device *udev) struct bus_id_priv *busid_priv; int rc; - dev_dbg(&udev->dev, "Enter\n"); + dev_dbg(&udev->dev, "Enter probe\n"); /* check we should claim or not by busid_table */ busid_priv = get_busid_priv(udev_busid); @@ -418,7 +418,7 @@ static void stub_disconnect(struct usb_device *udev) struct bus_id_priv *busid_priv; int rc; - dev_dbg(&udev->dev, "Enter\n"); + dev_dbg(&udev->dev, "Enter disconnect\n"); busid_priv = get_busid_priv(udev_busid); if (!busid_priv) { -- GitLab From 58c9c70cb7e10599f44a996cc4b481fc5c02ea4f Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Mon, 30 Apr 2018 16:17:19 -0600 Subject: [PATCH 338/855] usbip: usbip_host: delete device from busid_table after rebind commit 1e180f167d4e413afccbbb4a421b48b2de832549 upstream. Device is left in the busid_table after unbind and rebind. Rebind initiates usb bus scan and the original driver claims the device. After rescan the device should be deleted from the busid_table as it no longer belongs to usbip_host. Fix it to delete the device after device_attach() succeeds. Signed-off-by: Shuah Khan (Samsung OSG) Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/stub_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index f761e02e75c9..c289f0593bb8 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -201,6 +201,9 @@ static ssize_t rebind_store(struct device_driver *dev, const char *buf, if (!bid) return -ENODEV; + /* mark the device for deletion so probe ignores it during rescan */ + bid->status = STUB_BUSID_OTHER; + /* device_attach() callers should hold parent lock for USB */ if (bid->udev->dev.parent) device_lock(bid->udev->dev.parent); @@ -212,6 +215,9 @@ static ssize_t rebind_store(struct device_driver *dev, const char *buf, return ret; } + /* delete device from busid_table */ + del_match_busid((char *) buf); + return count; } -- GitLab From 59ad4f5342dadadbcf9fd67f29fd6a8ed70ab125 Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Mon, 30 Apr 2018 16:17:20 -0600 Subject: [PATCH 339/855] usbip: usbip_host: run rebind from exit when module is removed commit 7510df3f29d44685bab7b1918b61a8ccd57126a9 upstream. After removing usbip_host module, devices it releases are left without a driver. For example, when a keyboard or a mass storage device are bound to usbip_host when it is removed, these devices are no longer bound to any driver. Fix it to run device_attach() from the module exit routine to restore the devices to their original drivers. This includes cleanup changes and moving device_attach() code to a common routine to be called from rebind_store() and usbip_host_exit(). Signed-off-by: Shuah Khan (Samsung OSG) Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/stub_dev.c | 6 +--- drivers/usb/usbip/stub_main.c | 60 +++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c index 70973ca36a4d..12d6d95a142b 100644 --- a/drivers/usb/usbip/stub_dev.c +++ b/drivers/usb/usbip/stub_dev.c @@ -462,12 +462,8 @@ static void stub_disconnect(struct usb_device *udev) busid_priv->sdev = NULL; stub_device_free(sdev); - if (busid_priv->status == STUB_BUSID_ALLOC) { + if (busid_priv->status == STUB_BUSID_ALLOC) busid_priv->status = STUB_BUSID_ADDED; - } else { - busid_priv->status = STUB_BUSID_OTHER; - del_match_busid((char *)udev_busid); - } } #ifdef CONFIG_PM diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index c289f0593bb8..5a4f5d9d3ea1 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -28,6 +28,7 @@ #define DRIVER_DESC "USB/IP Host Driver" struct kmem_cache *stub_priv_cache; + /* * busid_tables defines matching busids that usbip can grab. A user can change * dynamically what device is locally used and what device is exported to a @@ -184,6 +185,51 @@ static ssize_t store_match_busid(struct device_driver *dev, const char *buf, static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid, store_match_busid); +static int do_rebind(char *busid, struct bus_id_priv *busid_priv) +{ + int ret; + + /* device_attach() callers should hold parent lock for USB */ + if (busid_priv->udev->dev.parent) + device_lock(busid_priv->udev->dev.parent); + ret = device_attach(&busid_priv->udev->dev); + if (busid_priv->udev->dev.parent) + device_unlock(busid_priv->udev->dev.parent); + if (ret < 0) { + dev_err(&busid_priv->udev->dev, "rebind failed\n"); + return ret; + } + return 0; +} + +static void stub_device_rebind(void) +{ +#if IS_MODULE(CONFIG_USBIP_HOST) + struct bus_id_priv *busid_priv; + int i; + + /* update status to STUB_BUSID_OTHER so probe ignores the device */ + spin_lock(&busid_table_lock); + for (i = 0; i < MAX_BUSID; i++) { + if (busid_table[i].name[0] && + busid_table[i].shutdown_busid) { + busid_priv = &(busid_table[i]); + busid_priv->status = STUB_BUSID_OTHER; + } + } + spin_unlock(&busid_table_lock); + + /* now run rebind */ + for (i = 0; i < MAX_BUSID; i++) { + if (busid_table[i].name[0] && + busid_table[i].shutdown_busid) { + busid_priv = &(busid_table[i]); + do_rebind(busid_table[i].name, busid_priv); + } + } +#endif +} + static ssize_t rebind_store(struct device_driver *dev, const char *buf, size_t count) { @@ -204,16 +250,9 @@ static ssize_t rebind_store(struct device_driver *dev, const char *buf, /* mark the device for deletion so probe ignores it during rescan */ bid->status = STUB_BUSID_OTHER; - /* device_attach() callers should hold parent lock for USB */ - if (bid->udev->dev.parent) - device_lock(bid->udev->dev.parent); - ret = device_attach(&bid->udev->dev); - if (bid->udev->dev.parent) - device_unlock(bid->udev->dev.parent); - if (ret < 0) { - dev_err(&bid->udev->dev, "rebind failed\n"); + ret = do_rebind((char *) buf, bid); + if (ret < 0) return ret; - } /* delete device from busid_table */ del_match_busid((char *) buf); @@ -339,6 +378,9 @@ static void __exit usbip_host_exit(void) */ usb_deregister_device_driver(&stub_driver); + /* initiate scan to attach devices */ + stub_device_rebind(); + kmem_cache_destroy(stub_priv_cache); } -- GitLab From f2a6d5f19450086e5cbdac7168d3fc75af32becf Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Mon, 14 May 2018 20:49:58 -0600 Subject: [PATCH 340/855] usbip: usbip_host: fix NULL-ptr deref and use-after-free errors commit 22076557b07c12086eeb16b8ce2b0b735f7a27e7 upstream. usbip_host updates device status without holding lock from stub probe, disconnect and rebind code paths. When multiple requests to import a device are received, these unprotected code paths step all over each other and drive fails with NULL-ptr deref and use-after-free errors. The driver uses a table lock to protect the busid array for adding and deleting busids to the table. However, the probe, disconnect and rebind paths get the busid table entry and update the status without holding the busid table lock. Add a new finer grain lock to protect the busid entry. This new lock will be held to search and update the busid entry fields from get_busid_idx(), add_match_busid() and del_match_busid(). match_busid_show() does the same to access the busid entry fields. get_busid_priv() changed to return the pointer to the busid entry holding the busid lock. stub_probe(), stub_disconnect() and stub_device_rebind() call put_busid_priv() to release the busid lock before returning. This changes fixes the unprotected code paths eliminating the race conditions in updating the busid entries. Reported-by: Jakub Jirasek Signed-off-by: Shuah Khan (Samsung OSG) Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/stub.h | 2 ++ drivers/usb/usbip/stub_dev.c | 33 ++++++++++++++++++++--------- drivers/usb/usbip/stub_main.c | 40 ++++++++++++++++++++++++++++++----- 3 files changed, 60 insertions(+), 15 deletions(-) diff --git a/drivers/usb/usbip/stub.h b/drivers/usb/usbip/stub.h index 910f027773aa..84c0599b45b7 100644 --- a/drivers/usb/usbip/stub.h +++ b/drivers/usb/usbip/stub.h @@ -87,6 +87,7 @@ struct bus_id_priv { struct stub_device *sdev; struct usb_device *udev; char shutdown_busid; + spinlock_t busid_lock; }; /* stub_priv is allocated from stub_priv_cache */ @@ -97,6 +98,7 @@ extern struct usb_device_driver stub_driver; /* stub_main.c */ struct bus_id_priv *get_busid_priv(const char *busid); +void put_busid_priv(struct bus_id_priv *bid); int del_match_busid(char *busid); void stub_device_cleanup_urbs(struct stub_device *sdev); diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c index 12d6d95a142b..8e629b6a6f3f 100644 --- a/drivers/usb/usbip/stub_dev.c +++ b/drivers/usb/usbip/stub_dev.c @@ -314,7 +314,7 @@ static int stub_probe(struct usb_device *udev) struct stub_device *sdev = NULL; const char *udev_busid = dev_name(&udev->dev); struct bus_id_priv *busid_priv; - int rc; + int rc = 0; dev_dbg(&udev->dev, "Enter probe\n"); @@ -331,13 +331,15 @@ static int stub_probe(struct usb_device *udev) * other matched drivers by the driver core. * See driver_probe_device() in driver/base/dd.c */ - return -ENODEV; + rc = -ENODEV; + goto call_put_busid_priv; } if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) { dev_dbg(&udev->dev, "%s is a usb hub device... skip!\n", udev_busid); - return -ENODEV; + rc = -ENODEV; + goto call_put_busid_priv; } if (!strcmp(udev->bus->bus_name, "vhci_hcd")) { @@ -345,13 +347,16 @@ static int stub_probe(struct usb_device *udev) "%s is attached on vhci_hcd... skip!\n", udev_busid); - return -ENODEV; + rc = -ENODEV; + goto call_put_busid_priv; } /* ok, this is my device */ sdev = stub_device_alloc(udev); - if (!sdev) - return -ENOMEM; + if (!sdev) { + rc = -ENOMEM; + goto call_put_busid_priv; + } dev_info(&udev->dev, "usbip-host: register new device (bus %u dev %u)\n", @@ -383,7 +388,9 @@ static int stub_probe(struct usb_device *udev) } busid_priv->status = STUB_BUSID_ALLOC; - return 0; + rc = 0; + goto call_put_busid_priv; + err_files: usb_hub_release_port(udev->parent, udev->portnum, (struct usb_dev_state *) udev); @@ -393,6 +400,9 @@ static int stub_probe(struct usb_device *udev) busid_priv->sdev = NULL; stub_device_free(sdev); + +call_put_busid_priv: + put_busid_priv(busid_priv); return rc; } @@ -431,7 +441,7 @@ static void stub_disconnect(struct usb_device *udev) /* get stub_device */ if (!sdev) { dev_err(&udev->dev, "could not get device"); - return; + goto call_put_busid_priv; } dev_set_drvdata(&udev->dev, NULL); @@ -446,12 +456,12 @@ static void stub_disconnect(struct usb_device *udev) (struct usb_dev_state *) udev); if (rc) { dev_dbg(&udev->dev, "unable to release port\n"); - return; + goto call_put_busid_priv; } /* If usb reset is called from event handler */ if (usbip_in_eh(current)) - return; + goto call_put_busid_priv; /* shutdown the current connection */ shutdown_busid(busid_priv); @@ -464,6 +474,9 @@ static void stub_disconnect(struct usb_device *udev) if (busid_priv->status == STUB_BUSID_ALLOC) busid_priv->status = STUB_BUSID_ADDED; + +call_put_busid_priv: + put_busid_priv(busid_priv); } #ifdef CONFIG_PM diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index 5a4f5d9d3ea1..82df6ea4d1a6 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -40,6 +40,8 @@ static spinlock_t busid_table_lock; static void init_busid_table(void) { + int i; + /* * This also sets the bus_table[i].status to * STUB_BUSID_OTHER, which is 0. @@ -47,6 +49,9 @@ static void init_busid_table(void) memset(busid_table, 0, sizeof(busid_table)); spin_lock_init(&busid_table_lock); + + for (i = 0; i < MAX_BUSID; i++) + spin_lock_init(&busid_table[i].busid_lock); } /* @@ -58,15 +63,20 @@ static int get_busid_idx(const char *busid) int i; int idx = -1; - for (i = 0; i < MAX_BUSID; i++) + for (i = 0; i < MAX_BUSID; i++) { + spin_lock(&busid_table[i].busid_lock); if (busid_table[i].name[0]) if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) { idx = i; + spin_unlock(&busid_table[i].busid_lock); break; } + spin_unlock(&busid_table[i].busid_lock); + } return idx; } +/* Returns holding busid_lock. Should call put_busid_priv() to unlock */ struct bus_id_priv *get_busid_priv(const char *busid) { int idx; @@ -74,13 +84,21 @@ struct bus_id_priv *get_busid_priv(const char *busid) spin_lock(&busid_table_lock); idx = get_busid_idx(busid); - if (idx >= 0) + if (idx >= 0) { bid = &(busid_table[idx]); + /* get busid_lock before returning */ + spin_lock(&bid->busid_lock); + } spin_unlock(&busid_table_lock); return bid; } +void put_busid_priv(struct bus_id_priv *bid) +{ + spin_unlock(&bid->busid_lock); +} + static int add_match_busid(char *busid) { int i; @@ -93,15 +111,19 @@ static int add_match_busid(char *busid) goto out; } - for (i = 0; i < MAX_BUSID; i++) + for (i = 0; i < MAX_BUSID; i++) { + spin_lock(&busid_table[i].busid_lock); if (!busid_table[i].name[0]) { strlcpy(busid_table[i].name, busid, BUSID_SIZE); if ((busid_table[i].status != STUB_BUSID_ALLOC) && (busid_table[i].status != STUB_BUSID_REMOV)) busid_table[i].status = STUB_BUSID_ADDED; ret = 0; + spin_unlock(&busid_table[i].busid_lock); break; } + spin_unlock(&busid_table[i].busid_lock); + } out: spin_unlock(&busid_table_lock); @@ -122,6 +144,8 @@ int del_match_busid(char *busid) /* found */ ret = 0; + spin_lock(&busid_table[idx].busid_lock); + if (busid_table[idx].status == STUB_BUSID_OTHER) memset(busid_table[idx].name, 0, BUSID_SIZE); @@ -129,6 +153,7 @@ int del_match_busid(char *busid) (busid_table[idx].status != STUB_BUSID_ADDED)) busid_table[idx].status = STUB_BUSID_REMOV; + spin_unlock(&busid_table[idx].busid_lock); out: spin_unlock(&busid_table_lock); @@ -141,9 +166,12 @@ static ssize_t show_match_busid(struct device_driver *drv, char *buf) char *out = buf; spin_lock(&busid_table_lock); - for (i = 0; i < MAX_BUSID; i++) + for (i = 0; i < MAX_BUSID; i++) { + spin_lock(&busid_table[i].busid_lock); if (busid_table[i].name[0]) out += sprintf(out, "%s ", busid_table[i].name); + spin_unlock(&busid_table[i].busid_lock); + } spin_unlock(&busid_table_lock); out += sprintf(out, "\n"); @@ -219,7 +247,7 @@ static void stub_device_rebind(void) } spin_unlock(&busid_table_lock); - /* now run rebind */ + /* now run rebind - no need to hold locks. driver files are removed */ for (i = 0; i < MAX_BUSID; i++) { if (busid_table[i].name[0] && busid_table[i].shutdown_busid) { @@ -249,6 +277,8 @@ static ssize_t rebind_store(struct device_driver *dev, const char *buf, /* mark the device for deletion so probe ignores it during rescan */ bid->status = STUB_BUSID_OTHER; + /* release the busid lock */ + put_busid_priv(bid); ret = do_rebind((char *) buf, bid); if (ret < 0) -- GitLab From 0471d407998b58d1f1cbb4f594fc63f9bf0ec7bb Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Tue, 15 May 2018 17:57:23 -0600 Subject: [PATCH 341/855] usbip: usbip_host: fix bad unlock balance during stub_probe() commit c171654caa875919be3c533d3518da8be5be966e upstream. stub_probe() calls put_busid_priv() in an error path when device isn't found in the busid_table. Fix it by making put_busid_priv() safe to be called with null struct bus_id_priv pointer. This problem happens when "usbip bind" is run without loading usbip_host driver and then running modprobe. The first failed bind attempt unbinds the device from the original driver and when usbip_host is modprobed, stub_probe() runs and doesn't find the device in its busid table and calls put_busid_priv(0 with null bus_id_priv pointer. usbip-host 3-10.2: 3-10.2 is not in match_busid table... skip! [ 367.359679] ===================================== [ 367.359681] WARNING: bad unlock balance detected! [ 367.359683] 4.17.0-rc4+ #5 Not tainted [ 367.359685] ------------------------------------- [ 367.359688] modprobe/2768 is trying to release lock ( [ 367.359689] ================================================================== [ 367.359696] BUG: KASAN: null-ptr-deref in print_unlock_imbalance_bug+0x99/0x110 [ 367.359699] Read of size 8 at addr 0000000000000058 by task modprobe/2768 [ 367.359705] CPU: 4 PID: 2768 Comm: modprobe Not tainted 4.17.0-rc4+ #5 Fixes: 22076557b07c ("usbip: usbip_host: fix NULL-ptr deref and use-after-free errors") in usb-linus Signed-off-by: Shuah Khan (Samsung OSG) Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/stub_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index 82df6ea4d1a6..fa90496ca7a8 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -96,7 +96,8 @@ struct bus_id_priv *get_busid_priv(const char *busid) void put_busid_priv(struct bus_id_priv *bid) { - spin_unlock(&bid->busid_lock); + if (bid) + spin_unlock(&bid->busid_lock); } static int add_match_busid(char *busid) -- GitLab From 639a74bf5f4da1c64884ff157ec62fed2798d5d0 Mon Sep 17 00:00:00 2001 From: Federico Cuello Date: Wed, 9 May 2018 00:13:38 +0200 Subject: [PATCH 342/855] ALSA: usb: mixer: volume quirk for CM102-A+/102S+ commit 21493316a3c4598f308d5a9fa31cc74639c4caff upstream. Currently it's not possible to set volume lower than 26% (it just mutes). Also fixes this warning: Warning! Unlikely big volume range (=9472), cval->res is probably wrong. [13] FU [PCM Playback Volume] ch = 2, val = -9473/-1/1 , and volume works fine for full range. Signed-off-by: Federico Cuello Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/mixer.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index dedf8eb4570e..db8404e31fae 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -905,6 +905,14 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, } break; + case USB_ID(0x0d8c, 0x0103): + if (!strcmp(kctl->id.name, "PCM Playback Volume")) { + usb_audio_info(chip, + "set volume quirk for CM102-A+/102S+\n"); + cval->min = -256; + } + break; + case USB_ID(0x0471, 0x0101): case USB_ID(0x0471, 0x0104): case USB_ID(0x0471, 0x0105): -- GitLab From e303276bbd9e2c603eee7a5ca14362493728d589 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 8 May 2018 09:27:46 +0200 Subject: [PATCH 343/855] ALSA: hda: Add Lenovo C50 All in one to the power_save blacklist commit c8beccc19b92f5172994c0732db689c08f4f98e5 upstream. Power-saving is causing loud plops on the Lenovo C50 All in one, add it to the blacklist. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1572975 Signed-off-by: Hans de Goede Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_intel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 7d3f88d90eec..4e9112001306 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2061,6 +2061,8 @@ static struct snd_pci_quirk power_save_blacklist[] = { SND_PCI_QUIRK(0x1849, 0x0c0c, "Asrock B85M-ITX", 0), /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ SND_PCI_QUIRK(0x1043, 0x8733, "Asus Prime X370-Pro", 0), + /* https://bugzilla.redhat.com/show_bug.cgi?id=1572975 */ + SND_PCI_QUIRK(0x17aa, 0x36a7, "Lenovo C50 All in one", 0), /* https://bugzilla.kernel.org/show_bug.cgi?id=198611 */ SND_PCI_QUIRK(0x17aa, 0x2227, "Lenovo X1 Carbon 3rd Gen", 0), {} -- GitLab From c5d8237ef6067635ed5cb6b787540c52afe6bc8f Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Sat, 5 May 2018 13:38:03 -0500 Subject: [PATCH 344/855] ALSA: control: fix a redundant-copy issue commit 3f12888dfae2a48741c4caa9214885b3aaf350f9 upstream. In snd_ctl_elem_add_compat(), the fields of the struct 'data' need to be copied from the corresponding fields of the struct 'data32' in userspace. This is achieved by invoking copy_from_user() and get_user() functions. The problem here is that the 'type' field is copied twice. One is by copy_from_user() and one is by get_user(). Given that the 'type' field is not used between the two copies, the second copy is *completely* redundant and should be removed for better performance and cleanup. Also, these two copies can cause inconsistent data: as the struct 'data32' resides in userspace and a malicious userspace process can race to change the 'type' field between the two copies to cause inconsistent data. Depending on how the data is used in the future, such an inconsistency may cause potential security risks. For above reasons, we should take out the second copy. Signed-off-by: Wenwen Wang Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/control_compat.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 1fa70766ffab..84ee29c3b1a0 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -400,8 +400,7 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) || copy_from_user(&data->type, &data32->type, 3 * sizeof(u32))) goto error; - if (get_user(data->owner, &data32->owner) || - get_user(data->type, &data32->type)) + if (get_user(data->owner, &data32->owner)) goto error; switch (data->type) { case SNDRV_CTL_ELEM_TYPE_BOOLEAN: -- GitLab From a436539bc16fdc6cb69cfa069ca0388df8d53d4b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 19 Apr 2018 19:53:32 +0300 Subject: [PATCH 345/855] spi: pxa2xx: Allow 64-bit DMA commit efc4a13724b852ddaa3358402a8dec024ffbcb17 upstream. Currently the 32-bit device address only is supported for DMA. However, starting from Intel Sunrisepoint PCH the DMA address of the device FIFO can be 64-bit. Change the respective variable to be compatible with DMA engine expectations, i.e. to phys_addr_t. Fixes: 34cadd9c1bcb ("spi: pxa2xx: Add support for Intel Sunrisepoint") Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-pxa2xx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index ce31b8199bb3..b8e004d1467b 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -38,7 +38,7 @@ struct driver_data { /* SSP register addresses */ void __iomem *ioaddr; - u32 ssdr_physical; + phys_addr_t ssdr_physical; /* SSP masks*/ u32 dma_cr1; -- GitLab From 1c384327383de13223186ec138c57cb49fa1efea Mon Sep 17 00:00:00 2001 From: Kamal Dasu Date: Thu, 26 Apr 2018 14:48:00 -0400 Subject: [PATCH 346/855] spi: bcm-qspi: Avoid setting MSPI_CDRAM_PCS for spi-nor master commit 5eb9a07a4ae1008b67d8bcd47bddb3dae97456b7 upstream. Added fix for probing of spi-nor device non-zero chip selects. Set MSPI_CDRAM_PCS (peripheral chip select) with spi master for MSPI controller and not for MSPI/BSPI spi-nor master controller. Ensure setting of cs bit in chip select register on chip select change. Fixes: fa236a7ef24048 ("spi: bcm-qspi: Add Broadcom MSPI driver") Signed-off-by: Kamal Dasu Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-bcm-qspi.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 7d629b4e1ecc..77966e291ae6 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -543,16 +543,19 @@ static void bcm_qspi_disable_bspi(struct bcm_qspi *qspi) static void bcm_qspi_chip_select(struct bcm_qspi *qspi, int cs) { - u32 data = 0; + u32 rd = 0; + u32 wr = 0; - if (qspi->curr_cs == cs) - return; if (qspi->base[CHIP_SELECT]) { - data = bcm_qspi_read(qspi, CHIP_SELECT, 0); - data = (data & ~0xff) | (1 << cs); - bcm_qspi_write(qspi, CHIP_SELECT, 0, data); + rd = bcm_qspi_read(qspi, CHIP_SELECT, 0); + wr = (rd & ~0xff) | (1 << cs); + if (rd == wr) + return; + bcm_qspi_write(qspi, CHIP_SELECT, 0, wr); usleep_range(10, 20); } + + dev_dbg(&qspi->pdev->dev, "using cs:%d\n", cs); qspi->curr_cs = cs; } @@ -770,8 +773,13 @@ static int write_to_hw(struct bcm_qspi *qspi, struct spi_device *spi) dev_dbg(&qspi->pdev->dev, "WR %04x\n", val); } mspi_cdram = MSPI_CDRAM_CONT_BIT; - mspi_cdram |= (~(1 << spi->chip_select) & - MSPI_CDRAM_PCS); + + if (has_bspi(qspi)) + mspi_cdram &= ~1; + else + mspi_cdram |= (~(1 << spi->chip_select) & + MSPI_CDRAM_PCS); + mspi_cdram |= ((tp.trans->bits_per_word <= 8) ? 0 : MSPI_CDRAM_BITSE_BIT); -- GitLab From ad04996f0bb0a2bfc8468c04dacc40aed76de8ae Mon Sep 17 00:00:00 2001 From: Kamal Dasu Date: Thu, 26 Apr 2018 14:48:01 -0400 Subject: [PATCH 347/855] spi: bcm-qspi: Always read and set BSPI_MAST_N_BOOT_CTRL commit 602805fb618b018b7a41fbb3f93c1992b078b1ae upstream. Always confirm the BSPI_MAST_N_BOOT_CTRL bit when enabling or disabling BSPI transfers. Fixes: 4e3b2d236fe00 ("spi: bcm-qspi: Add BSPI spi-nor flash controller driver") Signed-off-by: Kamal Dasu Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-bcm-qspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 77966e291ae6..adc3f56d4773 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -514,7 +514,7 @@ static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi, static void bcm_qspi_enable_bspi(struct bcm_qspi *qspi) { - if (!has_bspi(qspi) || (qspi->bspi_enabled)) + if (!has_bspi(qspi)) return; qspi->bspi_enabled = 1; @@ -529,7 +529,7 @@ static void bcm_qspi_enable_bspi(struct bcm_qspi *qspi) static void bcm_qspi_disable_bspi(struct bcm_qspi *qspi) { - if (!has_bspi(qspi) || (!qspi->bspi_enabled)) + if (!has_bspi(qspi)) return; qspi->bspi_enabled = 0; -- GitLab From 9488d11728a6d945ce589cac6b6760cdb361e9c6 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 11 May 2018 15:20:14 +0100 Subject: [PATCH 348/855] KVM: arm/arm64: VGIC/ITS: protect kvm_read_guest() calls with SRCU lock commit bf308242ab98b5d1648c3663e753556bef9bec01 upstream. kvm_read_guest() will eventually look up in kvm_memslots(), which requires either to hold the kvm->slots_lock or to be inside a kvm->srcu critical section. In contrast to x86 and s390 we don't take the SRCU lock on every guest exit, so we have to do it individually for each kvm_read_guest() call. Provide a wrapper which does that and use that everywhere. Note that ending the SRCU critical section before returning from the kvm_read_guest() wrapper is safe, because the data has been *copied*, so we don't need to rely on valid references to the memslot anymore. Cc: Stable # 4.8+ Reported-by: Jan Glauber Signed-off-by: Andre Przywara Acked-by: Christoffer Dall Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/kvm_mmu.h | 16 ++++++++++++++++ arch/arm64/include/asm/kvm_mmu.h | 16 ++++++++++++++++ virt/kvm/arm/vgic/vgic-its.c | 15 ++++++++------- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index d10e36235438..7f66b1b3aca1 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -223,6 +223,22 @@ static inline unsigned int kvm_get_vmid_bits(void) return 8; } +/* + * We are not in the kvm->srcu critical section most of the time, so we take + * the SRCU read lock here. Since we copy the data from the user page, we + * can immediately drop the lock again. + */ +static inline int kvm_read_guest_lock(struct kvm *kvm, + gpa_t gpa, void *data, unsigned long len) +{ + int srcu_idx = srcu_read_lock(&kvm->srcu); + int ret = kvm_read_guest(kvm, gpa, data, len); + + srcu_read_unlock(&kvm->srcu, srcu_idx); + + return ret; +} + static inline void *kvm_get_hyp_vector(void) { return kvm_ksym_ref(__kvm_hyp_vector); diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index 80bf33715ecb..eac73a640ea7 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -313,6 +313,22 @@ static inline unsigned int kvm_get_vmid_bits(void) return (cpuid_feature_extract_unsigned_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT) == 2) ? 16 : 8; } +/* + * We are not in the kvm->srcu critical section most of the time, so we take + * the SRCU read lock here. Since we copy the data from the user page, we + * can immediately drop the lock again. + */ +static inline int kvm_read_guest_lock(struct kvm *kvm, + gpa_t gpa, void *data, unsigned long len) +{ + int srcu_idx = srcu_read_lock(&kvm->srcu); + int ret = kvm_read_guest(kvm, gpa, data, len); + + srcu_read_unlock(&kvm->srcu, srcu_idx); + + return ret; +} + #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR #include diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c index 31f562507915..1ebbf233de9a 100644 --- a/virt/kvm/arm/vgic/vgic-its.c +++ b/virt/kvm/arm/vgic/vgic-its.c @@ -208,8 +208,8 @@ static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq, u8 prop; int ret; - ret = kvm_read_guest(kvm, propbase + irq->intid - GIC_LPI_OFFSET, - &prop, 1); + ret = kvm_read_guest_lock(kvm, propbase + irq->intid - GIC_LPI_OFFSET, + &prop, 1); if (ret) return ret; @@ -339,8 +339,9 @@ static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu) * this very same byte in the last iteration. Reuse that. */ if (byte_offset != last_byte_offset) { - ret = kvm_read_guest(vcpu->kvm, pendbase + byte_offset, - &pendmask, 1); + ret = kvm_read_guest_lock(vcpu->kvm, + pendbase + byte_offset, + &pendmask, 1); if (ret) { kfree(intids); return ret; @@ -628,7 +629,7 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, int id) return false; /* Each 1st level entry is represented by a 64-bit value. */ - if (kvm_read_guest(its->dev->kvm, + if (kvm_read_guest_lock(its->dev->kvm, BASER_ADDRESS(baser) + index * sizeof(indirect_ptr), &indirect_ptr, sizeof(indirect_ptr))) return false; @@ -1152,8 +1153,8 @@ static void vgic_its_process_commands(struct kvm *kvm, struct vgic_its *its) cbaser = CBASER_ADDRESS(its->cbaser); while (its->cwriter != its->creadr) { - int ret = kvm_read_guest(kvm, cbaser + its->creadr, - cmd_buf, ITS_CMD_SIZE); + int ret = kvm_read_guest_lock(kvm, cbaser + its->creadr, + cmd_buf, ITS_CMD_SIZE); /* * If kvm_read_guest() fails, this could be due to the guest * programming a bogus value in CBASER or something else going -- GitLab From 0c8b8d37c85805ebc47a3e6a5f799bad4de8328e Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 10 Jan 2018 17:10:12 +1100 Subject: [PATCH 349/855] powerpc: Don't preempt_disable() in show_cpuinfo() commit 349524bc0da698ec77f2057cf4a4948eb6349265 upstream. This causes warnings from cpufreq mutex code. This is also rather unnecessary and ineffective. If we really want to prevent concurrent unplug, we could take the unplug read lock but I don't see this being critical. Fixes: cd77b5ce208c ("powerpc/powernv/cpufreq: Fix the frequency read by /proc/cpuinfo") Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Acked-by: Michal Suchanek Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/setup-common.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index f516ac508ae3..bf0f712ac0e0 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -228,14 +228,6 @@ static int show_cpuinfo(struct seq_file *m, void *v) unsigned short maj; unsigned short min; - /* We only show online cpus: disable preempt (overzealous, I - * knew) to prevent cpu going down. */ - preempt_disable(); - if (!cpu_online(cpu_id)) { - preempt_enable(); - return 0; - } - #ifdef CONFIG_SMP pvr = per_cpu(cpu_pvr, cpu_id); #else @@ -340,9 +332,6 @@ static int show_cpuinfo(struct seq_file *m, void *v) #ifdef CONFIG_SMP seq_printf(m, "\n"); #endif - - preempt_enable(); - /* If this is the last cpu, print the summary */ if (cpumask_next(cpu_id, cpu_online_mask) >= nr_cpu_ids) show_cpuinfo_summary(m); -- GitLab From 20a30619b3315c1f11565cfbc0dbe2ea92a8a003 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Wed, 14 Dec 2016 15:04:10 -0800 Subject: [PATCH 350/855] signals: avoid unnecessary taking of sighand->siglock commit c7be96af89d4b53211862d8599b2430e8900ed92 upstream. When running certain database workload on a high-end system with many CPUs, it was found that spinlock contention in the sigprocmask syscalls became a significant portion of the overall CPU cycles as shown below. 9.30% 9.30% 905387 dataserver /proc/kcore 0x7fff8163f4d2 [k] _raw_spin_lock_irq | ---_raw_spin_lock_irq | |--99.34%-- __set_current_blocked | sigprocmask | sys_rt_sigprocmask | system_call_fastpath | | | |--50.63%-- __swapcontext | | | | | |--99.91%-- upsleepgeneric | | | |--49.36%-- __setcontext | | ktskRun Looking further into the swapcontext function in glibc, it was found that the function always call sigprocmask() without checking if there are changes in the signal mask. A check was added to the __set_current_blocked() function to avoid taking the sighand->siglock spinlock if there is no change in the signal mask. This will prevent unneeded spinlock contention when many threads are trying to call sigprocmask(). With this patch applied, the spinlock contention in sigprocmask() was gone. Link: http://lkml.kernel.org/r/1474979209-11867-1-git-send-email-Waiman.Long@hpe.com Signed-off-by: Waiman Long Acked-by: Oleg Nesterov Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Stas Sergeev Cc: Scott J Norton Cc: Douglas Hatch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Mel Gorman Signed-off-by: Greg Kroah-Hartman --- include/linux/signal.h | 17 +++++++++++++++++ kernel/signal.c | 7 +++++++ 2 files changed, 24 insertions(+) diff --git a/include/linux/signal.h b/include/linux/signal.h index b63f63eaa39c..5308304993be 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -97,6 +97,23 @@ static inline int sigisemptyset(sigset_t *set) } } +static inline int sigequalsets(const sigset_t *set1, const sigset_t *set2) +{ + switch (_NSIG_WORDS) { + case 4: + return (set1->sig[3] == set2->sig[3]) && + (set1->sig[2] == set2->sig[2]) && + (set1->sig[1] == set2->sig[1]) && + (set1->sig[0] == set2->sig[0]); + case 2: + return (set1->sig[1] == set2->sig[1]) && + (set1->sig[0] == set2->sig[0]); + case 1: + return set1->sig[0] == set2->sig[0]; + } + return 0; +} + #define sigmask(sig) (1UL << ((sig) - 1)) #ifndef __HAVE_ARCH_SIG_SETOPS diff --git a/kernel/signal.c b/kernel/signal.c index 7ebe236a5364..17428fec19b0 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2495,6 +2495,13 @@ void __set_current_blocked(const sigset_t *newset) { struct task_struct *tsk = current; + /* + * In case the signal mask hasn't changed, there is nothing we need + * to do. The current->blocked shouldn't be modified by other task. + */ + if (sigequalsets(&tsk->blocked, newset)) + return; + spin_lock_irq(&tsk->sighand->siglock); __set_task_blocked(tsk, newset); spin_unlock_irq(&tsk->sighand->siglock); -- GitLab From 1af681da78b748eba17ad244d08e8bbe1980bf5c Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 9 May 2018 14:36:09 -0400 Subject: [PATCH 351/855] tracing/x86/xen: Remove zero data size trace events trace_xen_mmu_flush_tlb{_all} commit 45dd9b0666a162f8e4be76096716670cf1741f0e upstream. Doing an audit of trace events, I discovered two trace events in the xen subsystem that use a hack to create zero data size trace events. This is not what trace events are for. Trace events add memory footprint overhead, and if all you need to do is see if a function is hit or not, simply make that function noinline and use function tracer filtering. Worse yet, the hack used was: __array(char, x, 0) Which creates a static string of zero in length. There's assumptions about such constructs in ftrace that this is a dynamic string that is nul terminated. This is not the case with these tracepoints and can cause problems in various parts of ftrace. Nuke the trace events! Link: http://lkml.kernel.org/r/20180509144605.5a220327@gandalf.local.home Cc: stable@vger.kernel.org Fixes: 95a7d76897c1e ("xen/mmu: Use Xen specific TLB flush instead of the generic one.") Reviewed-by: Juergen Gross Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/mmu.c | 4 ---- include/trace/events/xen.h | 16 ---------------- 2 files changed, 20 deletions(-) diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 418f1b8576cf..c92f75f7ae33 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1317,8 +1317,6 @@ void xen_flush_tlb_all(void) struct mmuext_op *op; struct multicall_space mcs; - trace_xen_mmu_flush_tlb_all(0); - preempt_disable(); mcs = xen_mc_entry(sizeof(*op)); @@ -1336,8 +1334,6 @@ static void xen_flush_tlb(void) struct mmuext_op *op; struct multicall_space mcs; - trace_xen_mmu_flush_tlb(0); - preempt_disable(); mcs = xen_mc_entry(sizeof(*op)); diff --git a/include/trace/events/xen.h b/include/trace/events/xen.h index bce990f5a35d..d6be935caa50 100644 --- a/include/trace/events/xen.h +++ b/include/trace/events/xen.h @@ -377,22 +377,6 @@ DECLARE_EVENT_CLASS(xen_mmu_pgd, DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_pin); DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_unpin); -TRACE_EVENT(xen_mmu_flush_tlb_all, - TP_PROTO(int x), - TP_ARGS(x), - TP_STRUCT__entry(__array(char, x, 0)), - TP_fast_assign((void)x), - TP_printk("%s", "") - ); - -TRACE_EVENT(xen_mmu_flush_tlb, - TP_PROTO(int x), - TP_ARGS(x), - TP_STRUCT__entry(__array(char, x, 0)), - TP_fast_assign((void)x), - TP_printk("%s", "") - ); - TRACE_EVENT(xen_mmu_flush_tlb_single, TP_PROTO(unsigned long addr), TP_ARGS(addr), -- GitLab From f32bb2aad27e5dac434a8fa1e12b1d6c25fe49f8 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 10 Apr 2018 09:30:27 +0200 Subject: [PATCH 352/855] netfilter: nf_tables: can't fail after linking rule into active rule list commit 569ccae68b38654f04b6842b034aa33857f605fe upstream. rules in nftables a free'd using kfree, but protected by rcu, i.e. we must wait for a grace period to elapse. Normal removal patch does this, but nf_tables_newrule() doesn't obey this rule during error handling. It calls nft_trans_rule_add() *after* linking rule, and, if that fails to allocate memory, it unlinks the rule and then kfree() it -- this is unsafe. Switch order -- first add rule to transaction list, THEN link it to public list. Note: nft_trans_rule_add() uses GFP_KERNEL; it will not fail so this is not a problem in practice (spotted only during code review). Fixes: 0628b123c96d12 ("netfilter: nfnetlink: add batch support and use it from nf_tables") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nf_tables_api.c | 59 +++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index fa3ef25441e5..762f31fb5b67 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -2200,41 +2200,46 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk, } if (nlh->nlmsg_flags & NLM_F_REPLACE) { - if (nft_is_active_next(net, old_rule)) { - trans = nft_trans_rule_add(&ctx, NFT_MSG_DELRULE, - old_rule); - if (trans == NULL) { - err = -ENOMEM; - goto err2; - } - nft_deactivate_next(net, old_rule); - chain->use--; - list_add_tail_rcu(&rule->list, &old_rule->list); - } else { + if (!nft_is_active_next(net, old_rule)) { err = -ENOENT; goto err2; } - } else if (nlh->nlmsg_flags & NLM_F_APPEND) - if (old_rule) - list_add_rcu(&rule->list, &old_rule->list); - else - list_add_tail_rcu(&rule->list, &chain->rules); - else { - if (old_rule) - list_add_tail_rcu(&rule->list, &old_rule->list); - else - list_add_rcu(&rule->list, &chain->rules); - } + trans = nft_trans_rule_add(&ctx, NFT_MSG_DELRULE, + old_rule); + if (trans == NULL) { + err = -ENOMEM; + goto err2; + } + nft_deactivate_next(net, old_rule); + chain->use--; - if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) { - err = -ENOMEM; - goto err3; + if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) { + err = -ENOMEM; + goto err2; + } + + list_add_tail_rcu(&rule->list, &old_rule->list); + } else { + if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) { + err = -ENOMEM; + goto err2; + } + + if (nlh->nlmsg_flags & NLM_F_APPEND) { + if (old_rule) + list_add_rcu(&rule->list, &old_rule->list); + else + list_add_tail_rcu(&rule->list, &chain->rules); + } else { + if (old_rule) + list_add_tail_rcu(&rule->list, &old_rule->list); + else + list_add_rcu(&rule->list, &chain->rules); + } } chain->use++; return 0; -err3: - list_del_rcu(&rule->list); err2: nf_tables_rule_destroy(&ctx, rule); err1: -- GitLab From 895c53e10b91432d0e9a9662448f0c7fc40f79e1 Mon Sep 17 00:00:00 2001 From: Alexander Monakov Date: Sat, 28 Apr 2018 16:56:06 +0300 Subject: [PATCH 353/855] i2c: designware: fix poll-after-enable regression commit 06cb616b1bca7080824acfedb3d4c898e7a64836 upstream. Not all revisions of DW I2C controller implement the enable status register. On platforms where that's the case (e.g. BG2CD and SPEAr ARM SoCs), waiting for enable will time out as reading the unimplemented register yields zero. It was observed that reading the IC_ENABLE_STATUS register once suffices to avoid getting it stuck on Bay Trail hardware, so replace polling with one dummy read of the register. Fixes: fba4adbbf670 ("i2c: designware: must wait for enable") Signed-off-by: Alexander Monakov Tested-by: Ben Gardner Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-designware-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 340e037b3224..884c1ec61ac9 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -507,7 +507,10 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) i2c_dw_disable_int(dev); /* Enable the adapter */ - __i2c_dw_enable_and_wait(dev, true); + __i2c_dw_enable(dev, true); + + /* Dummy read to avoid the register getting stuck on Bay Trail */ + dw_readl(dev, DW_IC_ENABLE_STATUS); /* Clear and enable interrupts */ dw_readl(dev, DW_IC_CLR_INTR); -- GitLab From 96c83fb2de4d45a9da51668e4a2f9aa0ac2c74ba Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 15 May 2018 01:59:47 +1000 Subject: [PATCH 354/855] powerpc/powernv: Fix NVRAM sleep in invalid context when crashing commit c1d2a31397ec51f0370f6bd17b19b39152c263cb upstream. Similarly to opal_event_shutdown, opal_nvram_write can be called in the crash path with irqs disabled. Special case the delay to avoid sleeping in invalid context. Fixes: 3b8070335f75 ("powerpc/powernv: Fix OPAL NVRAM driver OPAL_BUSY loops") Cc: stable@vger.kernel.org # v3.2 Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/opal-nvram.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/powernv/opal-nvram.c b/arch/powerpc/platforms/powernv/opal-nvram.c index 1bceb95f422d..5584247f5029 100644 --- a/arch/powerpc/platforms/powernv/opal-nvram.c +++ b/arch/powerpc/platforms/powernv/opal-nvram.c @@ -44,6 +44,10 @@ static ssize_t opal_nvram_read(char *buf, size_t count, loff_t *index) return count; } +/* + * This can be called in the panic path with interrupts off, so use + * mdelay in that case. + */ static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index) { s64 rc = OPAL_BUSY; @@ -58,10 +62,16 @@ static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index) while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { rc = opal_write_nvram(__pa(buf), count, off); if (rc == OPAL_BUSY_EVENT) { - msleep(OPAL_BUSY_DELAY_MS); + if (in_interrupt() || irqs_disabled()) + mdelay(OPAL_BUSY_DELAY_MS); + else + msleep(OPAL_BUSY_DELAY_MS); opal_poll_events(NULL); } else if (rc == OPAL_BUSY) { - msleep(OPAL_BUSY_DELAY_MS); + if (in_interrupt() || irqs_disabled()) + mdelay(OPAL_BUSY_DELAY_MS); + else + msleep(OPAL_BUSY_DELAY_MS); } } -- GitLab From 270693b978f345c34509676c0729d72c19b6d87e Mon Sep 17 00:00:00 2001 From: Pavel Tatashin Date: Fri, 18 May 2018 16:09:13 -0700 Subject: [PATCH 355/855] mm: don't allow deferred pages with NEED_PER_CPU_KM commit ab1e8d8960b68f54af42b6484b5950bd13a4054b upstream. It is unsafe to do virtual to physical translations before mm_init() is called if struct page is needed in order to determine the memory section number (see SECTION_IN_PAGE_FLAGS). This is because only in mm_init() we initialize struct pages for all the allocated memory when deferred struct pages are used. My recent fix in commit c9e97a1997 ("mm: initialize pages on demand during boot") exposed this problem, because it greatly reduced number of pages that are initialized before mm_init(), but the problem existed even before my fix, as Fengguang Wu found. Below is a more detailed explanation of the problem. We initialize struct pages in four places: 1. Early in boot a small set of struct pages is initialized to fill the first section, and lower zones. 2. During mm_init() we initialize "struct pages" for all the memory that is allocated, i.e reserved in memblock. 3. Using on-demand logic when pages are allocated after mm_init call (when memblock is finished) 4. After smp_init() when the rest free deferred pages are initialized. The problem occurs if we try to do va to phys translation of a memory between steps 1 and 2. Because we have not yet initialized struct pages for all the reserved pages, it is inherently unsafe to do va to phys if the translation itself requires access of "struct page" as in case of this combination: CONFIG_SPARSE && !CONFIG_SPARSE_VMEMMAP The following path exposes the problem: start_kernel() trap_init() setup_cpu_entry_areas() setup_cpu_entry_area(cpu) get_cpu_gdt_paddr(cpu) per_cpu_ptr_to_phys(addr) pcpu_addr_to_page(addr) virt_to_page(addr) pfn_to_page(__pa(addr) >> PAGE_SHIFT) We disable this path by not allowing NEED_PER_CPU_KM with deferred struct pages feature. The problems are discussed in these threads: http://lkml.kernel.org/r/20180418135300.inazvpxjxowogyge@wfg-t540p.sh.intel.com http://lkml.kernel.org/r/20180419013128.iurzouiqxvcnpbvz@wfg-t540p.sh.intel.com http://lkml.kernel.org/r/20180426202619.2768-1-pasha.tatashin@oracle.com Link: http://lkml.kernel.org/r/20180515175124.1770-1-pasha.tatashin@oracle.com Fixes: 3a80a7fa7989 ("mm: meminit: initialise a subset of struct pages if CONFIG_DEFERRED_STRUCT_PAGE_INIT is set") Signed-off-by: Pavel Tatashin Acked-by: Michal Hocko Reviewed-by: Andrew Morton Cc: Steven Sistare Cc: Daniel Jordan Cc: Mel Gorman Cc: Fengguang Wu Cc: Dennis Zhou Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/Kconfig b/mm/Kconfig index 86e3e0e74d20..ea074a9d4958 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -666,6 +666,7 @@ config DEFERRED_STRUCT_PAGE_INIT depends on ARCH_SUPPORTS_DEFERRED_STRUCT_PAGE_INIT depends on NO_BOOTMEM && MEMORY_HOTPLUG depends on !FLATMEM + depends on !NEED_PER_CPU_KM help Ordinarily all struct pages are initialised during early boot in a single thread. On very large machines this can take a considerable -- GitLab From 252bbeb9688a3c6ede9ea997e93ecb5d05e60209 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 2 May 2018 08:48:43 +0200 Subject: [PATCH 356/855] s390/qdio: fix access to uninitialized qdio_q fields commit e521813468f786271a87e78e8644243bead48fad upstream. Ever since CQ/QAOB support was added, calling qdio_free() straight after qdio_alloc() results in qdio_release_memory() accessing uninitialized memory (ie. q->u.out.use_cq and q->u.out.aobs). Followed by a kmem_cache_free() on the random AOB addresses. For older kernels that don't have 6e30c549f6ca, the same applies if qdio_establish() fails in the DEV_STATE_ONLINE check. While initializing q->u.out.use_cq would be enough to fix this particular bug, the more future-proof change is to just zero-alloc the whole struct. Fixes: 104ea556ee7f ("qdio: support asynchronous delivery of storage blocks") Cc: #v3.2+ Signed-off-by: Julian Wiedmann Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/qdio_setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 48b3866a9ded..3da5f3f3cf8b 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -140,7 +140,7 @@ static int __qdio_allocate_qs(struct qdio_q **irq_ptr_qs, int nr_queues) int i; for (i = 0; i < nr_queues; i++) { - q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL); + q = kmem_cache_zalloc(qdio_q_cache, GFP_KERNEL); if (!q) return -ENOMEM; -- GitLab From a03e14f09b40a1a10ce464d906814bb85ecd71ab Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Thu, 3 May 2018 15:56:15 +0200 Subject: [PATCH 357/855] s390/cpum_sf: ensure sample frequency of perf event attributes is non-zero commit 4bbaf2584b86b0772413edeac22ff448f36351b1 upstream. Correct a trinity finding for the perf_event_open() system call with a perf event attribute structure that uses a frequency but has the sampling frequency set to zero. This causes a FP divide exception during the sample rate initialization for the hardware sampling facility. Fixes: 8c069ff4bd606 ("s390/perf: add support for the CPU-Measurement Sampling Facility") Cc: stable@vger.kernel.org # 3.14+ Reviewed-by: Heiko Carstens Signed-off-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/perf_cpum_sf.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index fcc634c1479a..96e4fcad57bf 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c @@ -739,6 +739,10 @@ static int __hw_perf_event_init(struct perf_event *event) */ rate = 0; if (attr->freq) { + if (!attr->sample_freq) { + err = -EINVAL; + goto out; + } rate = freq_to_sample_rate(&si, attr->sample_freq); rate = hw_limit_rate(&si, rate); attr->freq = 0; -- GitLab From c79b01b8d4cb7c37c5da2299152c2ca9f22acc76 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 2 May 2018 08:28:34 +0200 Subject: [PATCH 358/855] s390/qdio: don't release memory in qdio_setup_irq() commit 2e68adcd2fb21b7188ba449f0fab3bee2910e500 upstream. Calling qdio_release_memory() on error is just plain wrong. It frees the main qdio_irq struct, when following code still uses it. Also, no other error path in qdio_establish() does this. So trust callers to clean up via qdio_free() if some step of the QDIO initialization fails. Fixes: 779e6e1c724d ("[S390] qdio: new qdio driver.") Cc: #v2.6.27+ Signed-off-by: Julian Wiedmann Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/qdio_setup.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 3da5f3f3cf8b..35286907c636 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -456,7 +456,6 @@ int qdio_setup_irq(struct qdio_initialize *init_data) { struct ciw *ciw; struct qdio_irq *irq_ptr = init_data->cdev->private->qdio_data; - int rc; memset(&irq_ptr->qib, 0, sizeof(irq_ptr->qib)); memset(&irq_ptr->siga_flag, 0, sizeof(irq_ptr->siga_flag)); @@ -493,16 +492,14 @@ int qdio_setup_irq(struct qdio_initialize *init_data) ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_EQUEUE); if (!ciw) { DBF_ERROR("%4x NO EQ", irq_ptr->schid.sch_no); - rc = -EINVAL; - goto out_err; + return -EINVAL; } irq_ptr->equeue = *ciw; ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_AQUEUE); if (!ciw) { DBF_ERROR("%4x NO AQ", irq_ptr->schid.sch_no); - rc = -EINVAL; - goto out_err; + return -EINVAL; } irq_ptr->aqueue = *ciw; @@ -510,9 +507,6 @@ int qdio_setup_irq(struct qdio_initialize *init_data) irq_ptr->orig_handler = init_data->cdev->handler; init_data->cdev->handler = qdio_int_handler; return 0; -out_err: - qdio_release_memory(irq_ptr); - return rc; } void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, -- GitLab From 633b4eb03bab15247214eae6a544dabf01688511 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 24 Apr 2018 11:18:49 +0200 Subject: [PATCH 359/855] s390: remove indirect branch from do_softirq_own_stack commit 9f18fff63cfd6f559daa1eaae60640372c65f84b upstream. The inline assembly to call __do_softirq on the irq stack uses an indirect branch. This can be replaced with a normal relative branch. Cc: stable@vger.kernel.org # 4.16 Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches") Reviewed-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/irq.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 285d6561076d..7ff976737bb1 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -173,10 +173,9 @@ void do_softirq_own_stack(void) new -= STACK_FRAME_OVERHEAD; ((struct stack_frame *) new)->back_chain = old; asm volatile(" la 15,0(%0)\n" - " basr 14,%2\n" + " brasl 14,__do_softirq\n" " la 15,0(%1)\n" - : : "a" (new), "a" (old), - "a" (__do_softirq) + : : "a" (new), "a" (old) : "0", "1", "2", "3", "4", "5", "14", "cc", "memory" ); } else { -- GitLab From a8330db3fb9b434471b861927e8e965835005929 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 9 May 2018 10:13:51 -0700 Subject: [PATCH 360/855] x86/pkeys: Override pkey when moving away from PROT_EXEC commit 0a0b152083cfc44ec1bb599b57b7aab41327f998 upstream. I got a bug report that the following code (roughly) was causing a SIGSEGV: mprotect(ptr, size, PROT_EXEC); mprotect(ptr, size, PROT_NONE); mprotect(ptr, size, PROT_READ); *ptr = 100; The problem is hit when the mprotect(PROT_EXEC) is implicitly assigned a protection key to the VMA, and made that key ACCESS_DENY|WRITE_DENY. The PROT_NONE mprotect() failed to remove the protection key, and the PROT_NONE-> PROT_READ left the PTE usable, but the pkey still in place and left the memory inaccessible. To fix this, we ensure that we always "override" the pkee at mprotect() if the VMA does not have execute-only permissions, but the VMA has the execute-only pkey. We had a check for PROT_READ/WRITE, but it did not work for PROT_NONE. This entirely removes the PROT_* checks, which ensures that PROT_NONE now works. Reported-by: Shakeel Butt Signed-off-by: Dave Hansen Cc: Andrew Morton Cc: Dave Hansen Cc: Linus Torvalds Cc: Michael Ellermen Cc: Peter Zijlstra Cc: Ram Pai Cc: Shuah Khan Cc: Thomas Gleixner Cc: linux-mm@kvack.org Cc: stable@vger.kernel.org Fixes: 62b5f7d013f ("mm/core, x86/mm/pkeys: Add execute-only protection keys support") Link: http://lkml.kernel.org/r/20180509171351.084C5A71@viggo.jf.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/pkeys.h | 12 +++++++++++- arch/x86/mm/pkeys.c | 21 +++++++++++---------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/arch/x86/include/asm/pkeys.h b/arch/x86/include/asm/pkeys.h index b3b09b98896d..bcb5745f927d 100644 --- a/arch/x86/include/asm/pkeys.h +++ b/arch/x86/include/asm/pkeys.h @@ -1,6 +1,8 @@ #ifndef _ASM_X86_PKEYS_H #define _ASM_X86_PKEYS_H +#define ARCH_DEFAULT_PKEY 0 + #define arch_max_pkey() (boot_cpu_has(X86_FEATURE_OSPKE) ? 16 : 1) extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, @@ -14,7 +16,7 @@ extern int __execute_only_pkey(struct mm_struct *mm); static inline int execute_only_pkey(struct mm_struct *mm) { if (!boot_cpu_has(X86_FEATURE_OSPKE)) - return 0; + return ARCH_DEFAULT_PKEY; return __execute_only_pkey(mm); } @@ -55,6 +57,14 @@ bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey) return false; if (pkey >= arch_max_pkey()) return false; + /* + * The exec-only pkey is set in the allocation map, but + * is not available to any of the user interfaces like + * mprotect_pkey(). + */ + if (pkey == mm->context.execute_only_pkey) + return false; + return mm_pkey_allocation_map(mm) & (1U << pkey); } diff --git a/arch/x86/mm/pkeys.c b/arch/x86/mm/pkeys.c index f88ce0e5efd9..0bbec041c003 100644 --- a/arch/x86/mm/pkeys.c +++ b/arch/x86/mm/pkeys.c @@ -95,26 +95,27 @@ int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, int pkey */ if (pkey != -1) return pkey; - /* - * Look for a protection-key-drive execute-only mapping - * which is now being given permissions that are not - * execute-only. Move it back to the default pkey. - */ - if (vma_is_pkey_exec_only(vma) && - (prot & (PROT_READ|PROT_WRITE))) { - return 0; - } + /* * The mapping is execute-only. Go try to get the * execute-only protection key. If we fail to do that, * fall through as if we do not have execute-only - * support. + * support in this mm. */ if (prot == PROT_EXEC) { pkey = execute_only_pkey(vma->vm_mm); if (pkey > 0) return pkey; + } else if (vma_is_pkey_exec_only(vma)) { + /* + * Protections are *not* PROT_EXEC, but the mapping + * is using the exec-only pkey. This mapping was + * PROT_EXEC and will no longer be. Move back to + * the default pkey. + */ + return ARCH_DEFAULT_PKEY; } + /* * This is a vanilla, non-pkey mprotect (or we failed to * setup execute-only), inherit the pkey from the VMA we -- GitLab From 7925d9da8d189025b190ad43ff476cba240144f2 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 9 May 2018 10:13:58 -0700 Subject: [PATCH 361/855] x86/pkeys: Do not special case protection key 0 commit 2fa9d1cfaf0e02f8abef0757002bff12dfcfa4e6 upstream. mm_pkey_is_allocated() treats pkey 0 as unallocated. That is inconsistent with the manpages, and also inconsistent with mm->context.pkey_allocation_map. Stop special casing it and only disallow values that are actually bad (< 0). The end-user visible effect of this is that you can now use mprotect_pkey() to set pkey=0. This is a bit nicer than what Ram proposed[1] because it is simpler and removes special-casing for pkey 0. On the other hand, it does allow applications to pkey_free() pkey-0, but that's just a silly thing to do, so we are not going to protect against it. The scenario that could happen is similar to what happens if you free any other pkey that is in use: it might get reallocated later and used to protect some other data. The most likely scenario is that pkey-0 comes back from pkey_alloc(), an access-disable or write-disable bit is set in PKRU for it, and the next stack access will SIGSEGV. It's not horribly different from if you mprotect()'d your stack or heap to be unreadable or unwritable, which is generally very foolish, but also not explicitly prevented by the kernel. 1. http://lkml.kernel.org/r/1522112702-27853-1-git-send-email-linuxram@us.ibm.com Signed-off-by: Dave Hansen Cc: Andrew Morton p Cc: Dave Hansen Cc: Linus Torvalds Cc: Michael Ellermen Cc: Peter Zijlstra Cc: Ram Pai Cc: Shuah Khan Cc: Thomas Gleixner Cc: linux-mm@kvack.org Cc: stable@vger.kernel.org Fixes: 58ab9a088dda ("x86/pkeys: Check against max pkey to avoid overflows") Link: http://lkml.kernel.org/r/20180509171358.47FD785E@viggo.jf.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/mmu_context.h | 2 +- arch/x86/include/asm/pkeys.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h index 5a295bb97103..733650874b30 100644 --- a/arch/x86/include/asm/mmu_context.h +++ b/arch/x86/include/asm/mmu_context.h @@ -113,7 +113,7 @@ static inline int init_new_context(struct task_struct *tsk, #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS if (cpu_feature_enabled(X86_FEATURE_OSPKE)) { - /* pkey 0 is the default and always allocated */ + /* pkey 0 is the default and allocated implicitly */ mm->context.pkey_allocation_map = 0x1; /* -1 means unallocated or invalid */ mm->context.execute_only_pkey = -1; diff --git a/arch/x86/include/asm/pkeys.h b/arch/x86/include/asm/pkeys.h index bcb5745f927d..c50d6dcf4a22 100644 --- a/arch/x86/include/asm/pkeys.h +++ b/arch/x86/include/asm/pkeys.h @@ -50,10 +50,10 @@ bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey) { /* * "Allocated" pkeys are those that have been returned - * from pkey_alloc(). pkey 0 is special, and never - * returned from pkey_alloc(). + * from pkey_alloc() or pkey 0 which is allocated + * implicitly when the mm is created. */ - if (pkey <= 0) + if (pkey < 0) return false; if (pkey >= arch_max_pkey()) return false; -- GitLab From dc7de9b203e844ecb143b32cc86a54bb528b8c5d Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 4 May 2018 07:59:58 +0200 Subject: [PATCH 362/855] efi: Avoid potential crashes, fix the 'struct efi_pci_io_protocol_32' definition for mixed mode commit 0b3225ab9407f557a8e20f23f37aa7236c10a9b1 upstream. Mixed mode allows a kernel built for x86_64 to interact with 32-bit EFI firmware, but requires us to define all struct definitions carefully when it comes to pointer sizes. 'struct efi_pci_io_protocol_32' currently uses a 'void *' for the 'romimage' field, which will be interpreted as a 64-bit field on such kernels, potentially resulting in bogus memory references and subsequent crashes. Tested-by: Hans de Goede Signed-off-by: Ard Biesheuvel Cc: Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/20180504060003.19618-13-ard.biesheuvel@linaro.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/boot/compressed/eboot.c | 6 ++++-- include/linux/efi.h | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index cc69e37548db..c0ad1bb27fa2 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -330,7 +330,8 @@ __setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) goto free_struct; - memcpy(rom->romdata, pci->romimage, pci->romsize); + memcpy(rom->romdata, (void *)(unsigned long)pci->romimage, + pci->romsize); return status; free_struct: @@ -436,7 +437,8 @@ __setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) goto free_struct; - memcpy(rom->romdata, pci->romimage, pci->romsize); + memcpy(rom->romdata, (void *)(unsigned long)pci->romimage, + pci->romsize); return status; free_struct: diff --git a/include/linux/efi.h b/include/linux/efi.h index cba7177cbec7..80b1b8faf503 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -380,8 +380,8 @@ typedef struct { u32 attributes; u32 get_bar_attributes; u32 set_bar_attributes; - uint64_t romsize; - void *romimage; + u64 romsize; + u32 romimage; } efi_pci_io_protocol_32; typedef struct { @@ -400,8 +400,8 @@ typedef struct { u64 attributes; u64 get_bar_attributes; u64 set_bar_attributes; - uint64_t romsize; - void *romimage; + u64 romsize; + u64 romimage; } efi_pci_io_protocol_64; typedef struct { -- GitLab From 10b408d6324b60fe2a949c2bac63fe9d5bd00851 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sun, 13 May 2018 05:04:16 +0100 Subject: [PATCH 363/855] ARM: 8771/1: kprobes: Prohibit kprobes on do_undefinstr commit eb0146daefdde65665b7f076fbff7b49dade95b9 upstream. Prohibit kprobes on do_undefinstr because kprobes on arm is implemented by undefined instruction. This means if we probe do_undefinstr(), it can cause infinit recursive exception. Fixes: 24ba613c9d6c ("ARM kprobes: core code") Signed-off-by: Masami Hiramatsu Cc: stable@vger.kernel.org Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/traps.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 1b304897aa12..aa316a7562b1 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -415,7 +416,8 @@ void unregister_undef_hook(struct undef_hook *hook) raw_spin_unlock_irqrestore(&undef_lock, flags); } -static int call_undef_hook(struct pt_regs *regs, unsigned int instr) +static nokprobe_inline +int call_undef_hook(struct pt_regs *regs, unsigned int instr) { struct undef_hook *hook; unsigned long flags; @@ -488,6 +490,7 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6); } +NOKPROBE_SYMBOL(do_undefinstr) /* * Handle FIQ similarly to NMI on x86 systems. -- GitLab From f58b66165d556abcf7eb0375bcc85e9fec2de614 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Tue, 15 May 2018 19:52:50 +0000 Subject: [PATCH 364/855] tick/broadcast: Use for_each_cpu() specially on UP kernels commit 5596fe34495cf0f645f417eb928ef224df3e3cb4 upstream. for_each_cpu() unintuitively reports CPU0 as set independent of the actual cpumask content on UP kernels. This causes an unexpected PIT interrupt storm on a UP kernel running in an SMP virtual machine on Hyper-V, and as a result, the virtual machine can suffer from a strange random delay of 1~20 minutes during boot-up, and sometimes it can hang forever. Protect if by checking whether the cpumask is empty before entering the for_each_cpu() loop. [ tglx: Use !IS_ENABLED(CONFIG_SMP) instead of #ifdeffery ] Signed-off-by: Dexuan Cui Signed-off-by: Thomas Gleixner Cc: Josh Poulson Cc: "Michael Kelley (EOSG)" Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: stable@vger.kernel.org Cc: Rakib Mullick Cc: Jork Loeser Cc: Greg Kroah-Hartman Cc: Andrew Morton Cc: KY Srinivasan Cc: Linus Torvalds Cc: Alexey Dobriyan Cc: Dmitry Vyukov Link: https://lkml.kernel.org/r/KL1P15301MB000678289FE55BA365B3279ABF990@KL1P15301MB0006.APCP153.PROD.OUTLOOK.COM Link: https://lkml.kernel.org/r/KL1P15301MB0006FA63BC22BEB64902EAA0BF930@KL1P15301MB0006.APCP153.PROD.OUTLOOK.COM Signed-off-by: Greg Kroah-Hartman --- kernel/time/tick-broadcast.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index d2a20e83ebae..22d7454b387b 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -610,6 +610,14 @@ static void tick_handle_oneshot_broadcast(struct clock_event_device *dev) now = ktime_get(); /* Find all expired events */ for_each_cpu(cpu, tick_broadcast_oneshot_mask) { + /* + * Required for !SMP because for_each_cpu() reports + * unconditionally CPU0 as set on UP kernels. + */ + if (!IS_ENABLED(CONFIG_SMP) && + cpumask_empty(tick_broadcast_oneshot_mask)) + break; + td = &per_cpu(tick_cpu_device, cpu); if (td->evtdev->next_event.tv64 <= now.tv64) { cpumask_set_cpu(cpu, tmpmask); -- GitLab From 70b4b1451086218a32122cf9fc7f92ccfb9ae4dc Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sun, 13 May 2018 05:03:54 +0100 Subject: [PATCH 365/855] ARM: 8769/1: kprobes: Fix to use get_kprobe_ctlblk after irq-disabed commit 69af7e23a6870df2ea6fa79ca16493d59b3eebeb upstream. Since get_kprobe_ctlblk() uses smp_processor_id() to access per-cpu variable, it hits smp_processor_id sanity check as below. [ 7.006928] BUG: using smp_processor_id() in preemptible [00000000] code: swapper/0/1 [ 7.007859] caller is debug_smp_processor_id+0x20/0x24 [ 7.008438] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.16.0-rc1-00192-g4eb17253e4b5 #1 [ 7.008890] Hardware name: Generic DT based system [ 7.009917] [] (unwind_backtrace) from [] (show_stack+0x20/0x24) [ 7.010473] [] (show_stack) from [] (dump_stack+0x84/0x98) [ 7.010990] [] (dump_stack) from [] (check_preemption_disabled+0x138/0x13c) [ 7.011592] [] (check_preemption_disabled) from [] (debug_smp_processor_id+0x20/0x24) [ 7.012214] [] (debug_smp_processor_id) from [] (optimized_callback+0x2c/0xe4) [ 7.013077] [] (optimized_callback) from [] (0xbf0021b0) To fix this issue, call get_kprobe_ctlblk() right after irq-disabled since that disables preemption. Fixes: 0dc016dbd820 ("ARM: kprobes: enable OPTPROBES for ARM 32") Signed-off-by: Masami Hiramatsu Cc: stable@vger.kernel.org Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/probes/kprobes/opt-arm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/probes/kprobes/opt-arm.c b/arch/arm/probes/kprobes/opt-arm.c index bcdecc25461b..ddc5a82eb10d 100644 --- a/arch/arm/probes/kprobes/opt-arm.c +++ b/arch/arm/probes/kprobes/opt-arm.c @@ -165,13 +165,14 @@ optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs) { unsigned long flags; struct kprobe *p = &op->kp; - struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + struct kprobe_ctlblk *kcb; /* Save skipped registers */ regs->ARM_pc = (unsigned long)op->kp.addr; regs->ARM_ORIG_r0 = ~0UL; local_irq_save(flags); + kcb = get_kprobe_ctlblk(); if (kprobe_running()) { kprobes_inc_nmissed_count(&op->kp); -- GitLab From b1690451d93fcd8af8edfa3b7fc6b966d330b0a8 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sun, 13 May 2018 05:04:10 +0100 Subject: [PATCH 366/855] ARM: 8770/1: kprobes: Prohibit probing on optimized_callback commit 70948c05fdde0aac32f9667856a88725c192fa40 upstream. Prohibit probing on optimized_callback() because it is called from kprobes itself. If we put a kprobes on it, that will cause a recursive call loop. Mark it NOKPROBE_SYMBOL. Fixes: 0dc016dbd820 ("ARM: kprobes: enable OPTPROBES for ARM 32") Signed-off-by: Masami Hiramatsu Cc: stable@vger.kernel.org Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/probes/kprobes/opt-arm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/probes/kprobes/opt-arm.c b/arch/arm/probes/kprobes/opt-arm.c index ddc5a82eb10d..b2aa9b32bff2 100644 --- a/arch/arm/probes/kprobes/opt-arm.c +++ b/arch/arm/probes/kprobes/opt-arm.c @@ -192,6 +192,7 @@ optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs) local_irq_restore(flags); } +NOKPROBE_SYMBOL(optimized_callback) int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *orig) { -- GitLab From 21cc684a31ef5f9290aaef48b1c9146b019d987d Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sun, 13 May 2018 05:04:29 +0100 Subject: [PATCH 367/855] ARM: 8772/1: kprobes: Prohibit kprobes on get_user functions commit 0d73c3f8e7f6ee2aab1bb350f60c180f5ae21a2c upstream. Since do_undefinstr() uses get_user to get the undefined instruction, it can be called before kprobes processes recursive check. This can cause an infinit recursive exception. Prohibit probing on get_user functions. Fixes: 24ba613c9d6c ("ARM kprobes: core code") Signed-off-by: Masami Hiramatsu Cc: stable@vger.kernel.org Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/assembler.h | 10 ++++++++++ arch/arm/lib/getuser.S | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 12f99fd2e3b2..3aed4492c9a7 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -534,4 +534,14 @@ THUMB( orr \reg , \reg , #PSR_T_BIT ) #endif .endm +#ifdef CONFIG_KPROBES +#define _ASM_NOKPROBE(entry) \ + .pushsection "_kprobe_blacklist", "aw" ; \ + .balign 4 ; \ + .long entry; \ + .popsection +#else +#define _ASM_NOKPROBE(entry) +#endif + #endif /* __ASM_ASSEMBLER_H__ */ diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S index df73914e81c8..746e7801dcdf 100644 --- a/arch/arm/lib/getuser.S +++ b/arch/arm/lib/getuser.S @@ -38,6 +38,7 @@ ENTRY(__get_user_1) mov r0, #0 ret lr ENDPROC(__get_user_1) +_ASM_NOKPROBE(__get_user_1) ENTRY(__get_user_2) check_uaccess r0, 2, r1, r2, __get_user_bad @@ -58,6 +59,7 @@ rb .req r0 mov r0, #0 ret lr ENDPROC(__get_user_2) +_ASM_NOKPROBE(__get_user_2) ENTRY(__get_user_4) check_uaccess r0, 4, r1, r2, __get_user_bad @@ -65,6 +67,7 @@ ENTRY(__get_user_4) mov r0, #0 ret lr ENDPROC(__get_user_4) +_ASM_NOKPROBE(__get_user_4) ENTRY(__get_user_8) check_uaccess r0, 8, r1, r2, __get_user_bad8 @@ -78,6 +81,7 @@ ENTRY(__get_user_8) mov r0, #0 ret lr ENDPROC(__get_user_8) +_ASM_NOKPROBE(__get_user_8) #ifdef __ARMEB__ ENTRY(__get_user_32t_8) @@ -91,6 +95,7 @@ ENTRY(__get_user_32t_8) mov r0, #0 ret lr ENDPROC(__get_user_32t_8) +_ASM_NOKPROBE(__get_user_32t_8) ENTRY(__get_user_64t_1) check_uaccess r0, 1, r1, r2, __get_user_bad8 @@ -98,6 +103,7 @@ ENTRY(__get_user_64t_1) mov r0, #0 ret lr ENDPROC(__get_user_64t_1) +_ASM_NOKPROBE(__get_user_64t_1) ENTRY(__get_user_64t_2) check_uaccess r0, 2, r1, r2, __get_user_bad8 @@ -114,6 +120,7 @@ rb .req r0 mov r0, #0 ret lr ENDPROC(__get_user_64t_2) +_ASM_NOKPROBE(__get_user_64t_2) ENTRY(__get_user_64t_4) check_uaccess r0, 4, r1, r2, __get_user_bad8 @@ -121,6 +128,7 @@ ENTRY(__get_user_64t_4) mov r0, #0 ret lr ENDPROC(__get_user_64t_4) +_ASM_NOKPROBE(__get_user_64t_4) #endif __get_user_bad8: @@ -131,6 +139,8 @@ __get_user_bad: ret lr ENDPROC(__get_user_bad) ENDPROC(__get_user_bad8) +_ASM_NOKPROBE(__get_user_bad) +_ASM_NOKPROBE(__get_user_bad8) .pushsection __ex_table, "a" .long 1b, __get_user_bad -- GitLab From 92291247b6069bce1c9c695b0f3496be4303b9fc Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Fri, 11 May 2018 16:42:42 +0100 Subject: [PATCH 368/855] Btrfs: fix xattr loss after power failure commit 9a8fca62aacc1599fea8e813d01e1955513e4fad upstream. If a file has xattrs, we fsync it, to ensure we clear the flags BTRFS_INODE_NEEDS_FULL_SYNC and BTRFS_INODE_COPY_EVERYTHING from its inode, the current transaction commits and then we fsync it (without either of those bits being set in its inode), we end up not logging all its xattrs. This results in deleting all xattrs when replying the log after a power failure. Trivial reproducer $ mkfs.btrfs -f /dev/sdb $ mount /dev/sdb /mnt $ touch /mnt/foobar $ setfattr -n user.xa -v qwerty /mnt/foobar $ xfs_io -c "fsync" /mnt/foobar $ sync $ xfs_io -c "pwrite -S 0xab 0 64K" /mnt/foobar $ xfs_io -c "fsync" /mnt/foobar $ mount /dev/sdb /mnt $ getfattr --absolute-names --dump /mnt/foobar $ So fix this by making sure all xattrs are logged if we log a file's inode item and neither the flags BTRFS_INODE_NEEDS_FULL_SYNC nor BTRFS_INODE_COPY_EVERYTHING were set in the inode. Fixes: 36283bf777d9 ("Btrfs: fix fsync xattr loss in the fast fsync path") Cc: # 4.2+ Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/tree-log.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 52401732cddc..c65350e5119c 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -4614,6 +4614,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; u64 logged_isize = 0; bool need_log_inode_item = true; + bool xattrs_logged = false; path = btrfs_alloc_path(); if (!path) @@ -4918,6 +4919,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, err = btrfs_log_all_xattrs(trans, root, inode, path, dst_path); if (err) goto out_unlock; + xattrs_logged = true; if (max_key.type >= BTRFS_EXTENT_DATA_KEY && !fast_search) { btrfs_release_path(path); btrfs_release_path(dst_path); @@ -4930,6 +4932,11 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, btrfs_release_path(dst_path); if (need_log_inode_item) { err = log_inode_item(trans, log, dst_path, inode); + if (!err && !xattrs_logged) { + err = btrfs_log_all_xattrs(trans, root, inode, path, + dst_path); + btrfs_release_path(path); + } if (err) goto out_unlock; } -- GitLab From b2d748b3a8d4e936a7e6e5fc9f04e2f9696efcc5 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Thu, 17 May 2018 15:16:51 +0800 Subject: [PATCH 369/855] btrfs: fix crash when trying to resume balance without the resume flag commit 02ee654d3a04563c67bfe658a05384548b9bb105 upstream. We set the BTRFS_BALANCE_RESUME flag in the btrfs_recover_balance() only, which isn't called during the remount. So when resuming from the paused balance we hit the bug: kernel: kernel BUG at fs/btrfs/volumes.c:3890! :: kernel: balance_kthread+0x51/0x60 [btrfs] kernel: kthread+0x111/0x130 :: kernel: RIP: btrfs_balance+0x12e1/0x1570 [btrfs] RSP: ffffba7d0090bde8 Reproducer: On a mounted filesystem: btrfs balance start --full-balance /btrfs btrfs balance pause /btrfs mount -o remount,ro /dev/sdb /btrfs mount -o remount,rw /dev/sdb /btrfs To fix this set the BTRFS_BALANCE_RESUME flag in btrfs_resume_balance_async(). CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Anand Jain Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/volumes.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 4730ba2cc049..c2495cde26f6 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3966,6 +3966,15 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info) return 0; } + /* + * A ro->rw remount sequence should continue with the paused balance + * regardless of who pauses it, system or the user as of now, so set + * the resume flag. + */ + spin_lock(&fs_info->balance_lock); + fs_info->balance_ctl->flags |= BTRFS_BALANCE_RESUME; + spin_unlock(&fs_info->balance_lock); + tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance"); return PTR_ERR_OR_ZERO(tsk); } -- GitLab From 944e0fc51a89c9827b98813d65dc083274777c7f Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 20 May 2018 20:51:10 +0100 Subject: [PATCH 370/855] x86/amd: don't set X86_BUG_SYSRET_SS_ATTRS when running under Xen commit def9331a12977770cc6132d79f8e6565871e8e38 upstream When running as Xen pv guest X86_BUG_SYSRET_SS_ATTRS must not be set on AMD cpus. This bug/feature bit is kind of special as it will be used very early when switching threads. Setting the bit and clearing it a little bit later leaves a critical window where things can go wrong. This time window has enlarged a little bit by using setup_clear_cpu_cap() instead of the hypervisor's set_cpu_features callback. It seems this larger window now makes it rather easy to hit the problem. The proper solution is to never set the bit in case of Xen. Signed-off-by: Juergen Gross Reviewed-by: Boris Ostrovsky Acked-by: Thomas Gleixner Signed-off-by: Juergen Gross Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/amd.c | 5 +++-- arch/x86/xen/enlighten.c | 4 +--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index c375bc672f82..747f8a20b629 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -824,8 +824,9 @@ static void init_amd(struct cpuinfo_x86 *c) if (cpu_has(c, X86_FEATURE_3DNOW) || cpu_has(c, X86_FEATURE_LM)) set_cpu_cap(c, X86_FEATURE_3DNOWPREFETCH); - /* AMD CPUs don't reset SS attributes on SYSRET */ - set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); + /* AMD CPUs don't reset SS attributes on SYSRET, Xen does. */ + if (!cpu_has(c, X86_FEATURE_XENPV)) + set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); } #ifdef CONFIG_X86_32 diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 2bea87cc0ff2..081437b5f381 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1977,10 +1977,8 @@ EXPORT_SYMBOL_GPL(xen_hvm_need_lapic); static void xen_set_cpu_features(struct cpuinfo_x86 *c) { - if (xen_pv_domain()) { - clear_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); + if (xen_pv_domain()) set_cpu_cap(c, X86_FEATURE_XENPV); - } } static void xen_pin_vcpu(int cpu) -- GitLab From 298d5db170f7d8430498417fa96e7472b620dcea Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 16 May 2018 01:37:36 +0800 Subject: [PATCH 371/855] btrfs: fix reading stale metadata blocks after degraded raid1 mounts commit 02a3307aa9c20b4f6626255b028f07f6cfa16feb upstream. If a btree block, aka. extent buffer, is not available in the extent buffer cache, it'll be read out from the disk instead, i.e. btrfs_search_slot() read_block_for_search() # hold parent and its lock, go to read child btrfs_release_path() read_tree_block() # read child Unfortunately, the parent lock got released before reading child, so commit 5bdd3536cbbe ("Btrfs: Fix block generation verification race") had used 0 as parent transid to read the child block. It forces read_tree_block() not to check if parent transid is different with the generation id of the child that it reads out from disk. A simple PoC is included in btrfs/124, 0. A two-disk raid1 btrfs, 1. Right after mkfs.btrfs, block A is allocated to be device tree's root. 2. Mount this filesystem and put it in use, after a while, device tree's root got COW but block A hasn't been allocated/overwritten yet. 3. Umount it and reload the btrfs module to remove both disks from the global @fs_devices list. 4. mount -odegraded dev1 and write some data, so now block A is allocated to be a leaf in checksum tree. Note that only dev1 has the latest metadata of this filesystem. 5. Umount it and mount it again normally (with both disks), since raid1 can pick up one disk by the writer task's pid, if btrfs_search_slot() needs to read block A, dev2 which does NOT have the latest metadata might be read for block A, then we got a stale block A. 6. As parent transid is not checked, block A is marked as uptodate and put into the extent buffer cache, so the future search won't bother to read disk again, which means it'll make changes on this stale one and make it dirty and flush it onto disk. To avoid the problem, parent transid needs to be passed to read_tree_block(). In order to get a valid parent transid, we need to hold the parent's lock until finishing reading child. This patch needs to be slightly adapted for stable kernels, the &first_key parameter added to read_tree_block() is from 4.16+ (581c1760415c4). The fix is to replace 0 by 'gen'. Fixes: 5bdd3536cbbe ("Btrfs: Fix block generation verification race") CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Liu Bo Reviewed-by: Filipe Manana Reviewed-by: Qu Wenruo [ update changelog ] Signed-off-by: David Sterba Signed-off-by: Nikolay Borisov Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/ctree.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index f6ba165d3f81..409b12392474 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -2486,10 +2486,8 @@ read_block_for_search(struct btrfs_trans_handle *trans, if (p->reada != READA_NONE) reada_for_search(root, p, level, slot, key->objectid); - btrfs_release_path(p); - ret = -EAGAIN; - tmp = read_tree_block(root, blocknr, 0); + tmp = read_tree_block(root, blocknr, gen); if (!IS_ERR(tmp)) { /* * If the read above didn't mark this buffer up to date, @@ -2503,6 +2501,8 @@ read_block_for_search(struct btrfs_trans_handle *trans, } else { ret = PTR_ERR(tmp); } + + btrfs_release_path(p); return ret; } -- GitLab From 741c026d1a0c594f7ad509f44488ef29582fed74 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 1 May 2018 15:55:51 +0200 Subject: [PATCH 372/855] x86/nospec: Simplify alternative_msr_write() commit 1aa7a5735a41418d8e01fa7c9565eb2657e2ea3f upstream The macro is not type safe and I did look for why that "g" constraint for the asm doesn't work: it's because the asm is more fundamentally wrong. It does movl %[val], %%eax but "val" isn't a 32-bit value, so then gcc will pass it in a register, and generate code like movl %rsi, %eax and gas will complain about a nonsensical 'mov' instruction (it's moving a 64-bit register to a 32-bit one). Passing it through memory will just hide the real bug - gcc still thinks the memory location is 64-bit, but the "movl" will only load the first 32 bits and it all happens to work because x86 is little-endian. Convert it to a type safe inline function with a little trick which hands the feature into the ALTERNATIVE macro. Signed-off-by: Linus Torvalds Signed-off-by: Thomas Gleixner Reviewed-by: Ingo Molnar Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/nospec-branch.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index f928ad9b143f..870acfc2fd34 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -241,15 +241,16 @@ static inline void vmexit_fill_RSB(void) #endif } -#define alternative_msr_write(_msr, _val, _feature) \ - asm volatile(ALTERNATIVE("", \ - "movl %[msr], %%ecx\n\t" \ - "movl %[val], %%eax\n\t" \ - "movl $0, %%edx\n\t" \ - "wrmsr", \ - _feature) \ - : : [msr] "i" (_msr), [val] "i" (_val) \ - : "eax", "ecx", "edx", "memory") +static __always_inline +void alternative_msr_write(unsigned int msr, u64 val, unsigned int feature) +{ + asm volatile(ALTERNATIVE("", "wrmsr", %c[feature]) + : : "c" (msr), + "a" (val), + "d" (val >> 32), + [feature] "i" (feature) + : "memory"); +} static inline void indirect_branch_prediction_barrier(void) { -- GitLab From 88659d5fd9bea7f6afb227c6d404de750b368b45 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 25 Apr 2018 22:04:16 -0400 Subject: [PATCH 373/855] x86/bugs: Concentrate bug detection into a separate function commit 4a28bfe3267b68e22c663ac26185aa16c9b879ef upstream Combine the various logic which goes through all those x86_cpu_id matching structures in one function. Suggested-by: Borislav Petkov Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Ingo Molnar Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/common.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 301bbd1f2373..357c589c7ce6 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -879,21 +879,27 @@ static const __initconst struct x86_cpu_id cpu_no_meltdown[] = { {} }; -static bool __init cpu_vulnerable_to_meltdown(struct cpuinfo_x86 *c) +static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) { u64 ia32_cap = 0; + if (x86_match_cpu(cpu_no_speculation)) + return; + + setup_force_cpu_bug(X86_BUG_SPECTRE_V1); + setup_force_cpu_bug(X86_BUG_SPECTRE_V2); + if (x86_match_cpu(cpu_no_meltdown)) - return false; + return; if (cpu_has(c, X86_FEATURE_ARCH_CAPABILITIES)) rdmsrl(MSR_IA32_ARCH_CAPABILITIES, ia32_cap); /* Rogue Data Cache Load? No! */ if (ia32_cap & ARCH_CAP_RDCL_NO) - return false; + return; - return true; + setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN); } /* @@ -942,12 +948,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) setup_force_cpu_cap(X86_FEATURE_ALWAYS); - if (!x86_match_cpu(cpu_no_speculation)) { - if (cpu_vulnerable_to_meltdown(c)) - setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN); - setup_force_cpu_bug(X86_BUG_SPECTRE_V1); - setup_force_cpu_bug(X86_BUG_SPECTRE_V2); - } + cpu_set_bug_bits(c); fpu__init_system(c); -- GitLab From 3effee64a9993dc5587fb39f0da4455769e53d26 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 25 Apr 2018 22:04:17 -0400 Subject: [PATCH 374/855] x86/bugs: Concentrate bug reporting into a separate function commit d1059518b4789cabe34bb4b714d07e6089c82ca1 upstream Those SysFS functions have a similar preamble, as such make common code to handle them. Suggested-by: Borislav Petkov Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Ingo Molnar Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/bugs.c | 46 ++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index b8b0b6e78371..4d9c5fed56b2 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -313,30 +313,48 @@ static void __init spectre_v2_select_mitigation(void) #undef pr_fmt #ifdef CONFIG_SYSFS -ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) + +ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr, + char *buf, unsigned int bug) { - if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) + if (!boot_cpu_has_bug(bug)) return sprintf(buf, "Not affected\n"); - if (boot_cpu_has(X86_FEATURE_KAISER)) - return sprintf(buf, "Mitigation: PTI\n"); + + switch (bug) { + case X86_BUG_CPU_MELTDOWN: + if (boot_cpu_has(X86_FEATURE_KAISER)) + return sprintf(buf, "Mitigation: PTI\n"); + + break; + + case X86_BUG_SPECTRE_V1: + return sprintf(buf, "Mitigation: __user pointer sanitization\n"); + + case X86_BUG_SPECTRE_V2: + return sprintf(buf, "%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled], + boot_cpu_has(X86_FEATURE_USE_IBPB) ? ", IBPB" : "", + boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "", + spectre_v2_module_string()); + + default: + break; + } + return sprintf(buf, "Vulnerable\n"); } +ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) +{ + return cpu_show_common(dev, attr, buf, X86_BUG_CPU_MELTDOWN); +} + ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) { - if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1)) - return sprintf(buf, "Not affected\n"); - return sprintf(buf, "Mitigation: __user pointer sanitization\n"); + return cpu_show_common(dev, attr, buf, X86_BUG_SPECTRE_V1); } ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) { - if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) - return sprintf(buf, "Not affected\n"); - - return sprintf(buf, "%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled], - boot_cpu_has(X86_FEATURE_USE_IBPB) ? ", IBPB" : "", - boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "", - spectre_v2_module_string()); + return cpu_show_common(dev, attr, buf, X86_BUG_SPECTRE_V2); } #endif -- GitLab From 0f5dd651397b264903e8becc511af6cf384c273e Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 25 Apr 2018 22:04:18 -0400 Subject: [PATCH 375/855] x86/bugs: Read SPEC_CTRL MSR during boot and re-use reserved bits commit 1b86883ccb8d5d9506529d42dbe1a5257cb30b18 upstream The 336996-Speculative-Execution-Side-Channel-Mitigations.pdf refers to all the other bits as reserved. The Intel SDM glossary defines reserved as implementation specific - aka unknown. As such at bootup this must be taken it into account and proper masking for the bits in use applied. A copy of this document is available at https://bugzilla.kernel.org/show_bug.cgi?id=199511 [ tglx: Made x86_spec_ctrl_base __ro_after_init ] Suggested-by: Jon Masters Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Ingo Molnar Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/nospec-branch.h | 24 ++++++++++++++++++++---- arch/x86/kernel/cpu/bugs.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 870acfc2fd34..9ec3d4d448cd 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -217,6 +217,17 @@ enum spectre_v2_mitigation { SPECTRE_V2_IBRS, }; +/* + * The Intel specification for the SPEC_CTRL MSR requires that we + * preserve any already set reserved bits at boot time (e.g. for + * future additions that this kernel is not currently aware of). + * We then set any additional mitigation bits that we want + * ourselves and always use this as the base for SPEC_CTRL. + * We also use this when handling guest entry/exit as below. + */ +extern void x86_spec_ctrl_set(u64); +extern u64 x86_spec_ctrl_get_default(void); + extern char __indirect_thunk_start[]; extern char __indirect_thunk_end[]; @@ -254,8 +265,9 @@ void alternative_msr_write(unsigned int msr, u64 val, unsigned int feature) static inline void indirect_branch_prediction_barrier(void) { - alternative_msr_write(MSR_IA32_PRED_CMD, PRED_CMD_IBPB, - X86_FEATURE_USE_IBPB); + u64 val = PRED_CMD_IBPB; + + alternative_msr_write(MSR_IA32_PRED_CMD, val, X86_FEATURE_USE_IBPB); } /* @@ -266,14 +278,18 @@ static inline void indirect_branch_prediction_barrier(void) */ #define firmware_restrict_branch_speculation_start() \ do { \ + u64 val = x86_spec_ctrl_get_default() | SPEC_CTRL_IBRS; \ + \ preempt_disable(); \ - alternative_msr_write(MSR_IA32_SPEC_CTRL, SPEC_CTRL_IBRS, \ + alternative_msr_write(MSR_IA32_SPEC_CTRL, val, \ X86_FEATURE_USE_IBRS_FW); \ } while (0) #define firmware_restrict_branch_speculation_end() \ do { \ - alternative_msr_write(MSR_IA32_SPEC_CTRL, 0, \ + u64 val = x86_spec_ctrl_get_default(); \ + \ + alternative_msr_write(MSR_IA32_SPEC_CTRL, val, \ X86_FEATURE_USE_IBRS_FW); \ preempt_enable(); \ } while (0) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 4d9c5fed56b2..6ff972aa7307 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -27,6 +27,12 @@ static void __init spectre_v2_select_mitigation(void); +/* + * Our boot-time value of the SPEC_CTRL MSR. We read it once so that any + * writes to SPEC_CTRL contain whatever reserved bits have been set. + */ +static u64 __ro_after_init x86_spec_ctrl_base; + void __init check_bugs(void) { identify_boot_cpu(); @@ -36,6 +42,13 @@ void __init check_bugs(void) print_cpu_info(&boot_cpu_data); } + /* + * Read the SPEC_CTRL MSR to account for reserved bits which may + * have unknown values. + */ + if (boot_cpu_has(X86_FEATURE_IBRS)) + rdmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base); + /* Select the proper spectre mitigation before patching alternatives */ spectre_v2_select_mitigation(); @@ -94,6 +107,21 @@ static const char *spectre_v2_strings[] = { static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE; +void x86_spec_ctrl_set(u64 val) +{ + if (val & ~SPEC_CTRL_IBRS) + WARN_ONCE(1, "SPEC_CTRL MSR value 0x%16llx is unknown.\n", val); + else + wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base | val); +} +EXPORT_SYMBOL_GPL(x86_spec_ctrl_set); + +u64 x86_spec_ctrl_get_default(void) +{ + return x86_spec_ctrl_base; +} +EXPORT_SYMBOL_GPL(x86_spec_ctrl_get_default); + #ifdef RETPOLINE static bool spectre_v2_bad_module; -- GitLab From cf21f58ae6f264e0a10d9736be97342627cf9837 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 25 Apr 2018 22:04:19 -0400 Subject: [PATCH 376/855] x86/bugs, KVM: Support the combination of guest and host IBRS commit 5cf687548705412da47c9cec342fd952d71ed3d5 upstream A guest may modify the SPEC_CTRL MSR from the value used by the kernel. Since the kernel doesn't use IBRS, this means a value of zero is what is needed in the host. But the 336996-Speculative-Execution-Side-Channel-Mitigations.pdf refers to the other bits as reserved so the kernel should respect the boot time SPEC_CTRL value and use that. This allows to deal with future extensions to the SPEC_CTRL interface if any at all. Note: This uses wrmsrl() instead of native_wrmsl(). I does not make any difference as paravirt will over-write the callq *0xfff.. with the wrmsrl assembler code. Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Ingo Molnar Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/nospec-branch.h | 10 ++++++++++ arch/x86/kernel/cpu/bugs.c | 18 ++++++++++++++++++ arch/x86/kvm/svm.c | 6 ++---- arch/x86/kvm/vmx.c | 6 ++---- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 9ec3d4d448cd..d1c2630922da 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -228,6 +228,16 @@ enum spectre_v2_mitigation { extern void x86_spec_ctrl_set(u64); extern u64 x86_spec_ctrl_get_default(void); +/* + * On VMENTER we must preserve whatever view of the SPEC_CTRL MSR + * the guest has, while on VMEXIT we restore the host view. This + * would be easier if SPEC_CTRL were architecturally maskable or + * shadowable for guests but this is not (currently) the case. + * Takes the guest view of SPEC_CTRL MSR as a parameter. + */ +extern void x86_spec_ctrl_set_guest(u64); +extern void x86_spec_ctrl_restore_host(u64); + extern char __indirect_thunk_start[]; extern char __indirect_thunk_end[]; diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 6ff972aa7307..f5cad2f9af44 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -122,6 +122,24 @@ u64 x86_spec_ctrl_get_default(void) } EXPORT_SYMBOL_GPL(x86_spec_ctrl_get_default); +void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl) +{ + if (!boot_cpu_has(X86_FEATURE_IBRS)) + return; + if (x86_spec_ctrl_base != guest_spec_ctrl) + wrmsrl(MSR_IA32_SPEC_CTRL, guest_spec_ctrl); +} +EXPORT_SYMBOL_GPL(x86_spec_ctrl_set_guest); + +void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl) +{ + if (!boot_cpu_has(X86_FEATURE_IBRS)) + return; + if (x86_spec_ctrl_base != guest_spec_ctrl) + wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base); +} +EXPORT_SYMBOL_GPL(x86_spec_ctrl_restore_host); + #ifdef RETPOLINE static bool spectre_v2_bad_module; diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index aaa93b4b0380..eeb8cd3193ea 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -4917,8 +4917,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) * is no need to worry about the conditional branch over the wrmsr * being speculatively taken. */ - if (svm->spec_ctrl) - native_wrmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl); + x86_spec_ctrl_set_guest(svm->spec_ctrl); asm volatile ( "push %%" _ASM_BP "; \n\t" @@ -5030,8 +5029,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))) svm->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL); - if (svm->spec_ctrl) - native_wrmsrl(MSR_IA32_SPEC_CTRL, 0); + x86_spec_ctrl_restore_host(svm->spec_ctrl); /* Eliminate branch target predictions from guest mode */ vmexit_fill_RSB(); diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index b978aeccda78..266db0b2e138 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -8916,8 +8916,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) * is no need to worry about the conditional branch over the wrmsr * being speculatively taken. */ - if (vmx->spec_ctrl) - native_wrmsrl(MSR_IA32_SPEC_CTRL, vmx->spec_ctrl); + x86_spec_ctrl_set_guest(vmx->spec_ctrl); vmx->__launched = vmx->loaded_vmcs->launched; asm( @@ -9055,8 +9054,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))) vmx->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL); - if (vmx->spec_ctrl) - native_wrmsrl(MSR_IA32_SPEC_CTRL, 0); + x86_spec_ctrl_restore_host(vmx->spec_ctrl); /* Eliminate branch target predictions from guest mode */ vmexit_fill_RSB(); -- GitLab From 24e4dd97af40afa4d45e85a32d9c2cc81425a62e Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 25 Apr 2018 22:04:20 -0400 Subject: [PATCH 377/855] x86/bugs: Expose /sys/../spec_store_bypass commit c456442cd3a59eeb1d60293c26cbe2ff2c4e42cf upstream Add the sysfs file for the new vulerability. It does not do much except show the words 'Vulnerable' for recent x86 cores. Intel cores prior to family 6 are known not to be vulnerable, and so are some Atoms and some Xeon Phi. It assumes that older Cyrix, Centaur, etc. cores are immune. Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Ingo Molnar Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- .../ABI/testing/sysfs-devices-system-cpu | 1 + arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/kernel/cpu/bugs.c | 5 ++++ arch/x86/kernel/cpu/common.c | 23 +++++++++++++++++++ drivers/base/cpu.c | 8 +++++++ include/linux/cpu.h | 2 ++ 6 files changed, 40 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index dfd56ec7a850..6d75a9c00e8a 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -355,6 +355,7 @@ What: /sys/devices/system/cpu/vulnerabilities /sys/devices/system/cpu/vulnerabilities/meltdown /sys/devices/system/cpu/vulnerabilities/spectre_v1 /sys/devices/system/cpu/vulnerabilities/spectre_v2 + /sys/devices/system/cpu/vulnerabilities/spec_store_bypass Date: January 2018 Contact: Linux kernel mailing list Description: Information about CPU vulnerabilities diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index a2485311164b..a688adbc427c 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -335,5 +335,6 @@ #define X86_BUG_CPU_MELTDOWN X86_BUG(14) /* CPU is affected by meltdown attack and needs kernel page table isolation */ #define X86_BUG_SPECTRE_V1 X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */ #define X86_BUG_SPECTRE_V2 X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */ +#define X86_BUG_SPEC_STORE_BYPASS X86_BUG(17) /* CPU is affected by speculative store bypass attack */ #endif /* _ASM_X86_CPUFEATURES_H */ diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index f5cad2f9af44..64e17a962bb6 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -403,4 +403,9 @@ ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, c { return cpu_show_common(dev, attr, buf, X86_BUG_SPECTRE_V2); } + +ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) +{ + return cpu_show_common(dev, attr, buf, X86_BUG_SPEC_STORE_BYPASS); +} #endif diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 357c589c7ce6..4f1050aedc26 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -879,10 +879,33 @@ static const __initconst struct x86_cpu_id cpu_no_meltdown[] = { {} }; +static const __initconst struct x86_cpu_id cpu_no_spec_store_bypass[] = { + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_PINEVIEW }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_LINCROFT }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_PENWELL }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_CLOVERVIEW }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_CEDARVIEW }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1 }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT2 }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_MERRIFIELD }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_CORE_YONAH }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_XEON_PHI_KNL }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_XEON_PHI_KNM }, + { X86_VENDOR_CENTAUR, 5, }, + { X86_VENDOR_INTEL, 5, }, + { X86_VENDOR_NSC, 5, }, + { X86_VENDOR_ANY, 4, }, + {} +}; + static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) { u64 ia32_cap = 0; + if (!x86_match_cpu(cpu_no_spec_store_bypass)) + setup_force_cpu_bug(X86_BUG_SPEC_STORE_BYPASS); + if (x86_match_cpu(cpu_no_speculation)) return; diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 56b6c8508a89..cbb1cc6bbdb4 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -519,14 +519,22 @@ ssize_t __weak cpu_show_spectre_v2(struct device *dev, return sprintf(buf, "Not affected\n"); } +ssize_t __weak cpu_show_spec_store_bypass(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL); +static DEVICE_ATTR(spec_store_bypass, 0444, cpu_show_spec_store_bypass, NULL); static struct attribute *cpu_root_vulnerabilities_attrs[] = { &dev_attr_meltdown.attr, &dev_attr_spectre_v1.attr, &dev_attr_spectre_v2.attr, + &dev_attr_spec_store_bypass.attr, NULL }; diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 2f475ad89a0d..917829b27350 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -50,6 +50,8 @@ extern ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf); extern ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf); +extern ssize_t cpu_show_spec_store_bypass(struct device *dev, + struct device_attribute *attr, char *buf); extern __printf(4, 5) struct device *cpu_device_create(struct device *parent, void *drvdata, -- GitLab From a80714172abca6413d2d6505be64723ae73a903b Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Sat, 28 Apr 2018 22:34:17 +0200 Subject: [PATCH 378/855] x86/cpufeatures: Add X86_FEATURE_RDS commit 0cc5fa00b0a88dad140b4e5c2cead9951ad36822 upstream Add the CPU feature bit CPUID.7.0.EDX[31] which indicates whether the CPU supports Reduced Data Speculation. [ tglx: Split it out from a later patch ] Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Reviewed-by: Ingo Molnar Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/cpufeatures.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index a688adbc427c..0c05c6cf5a12 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -306,6 +306,7 @@ #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ +#define X86_FEATURE_RDS (18*32+31) /* Reduced Data Speculation */ /* * BUG word(s) -- GitLab From 6f70a553666dd8c4fa370eaaa41380eec593229c Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 25 Apr 2018 22:04:21 -0400 Subject: [PATCH 379/855] x86/bugs: Provide boot parameters for the spec_store_bypass_disable mitigation commit 24f7fc83b9204d20f878c57cb77d261ae825e033 upstream Contemporary high performance processors use a common industry-wide optimization known as "Speculative Store Bypass" in which loads from addresses to which a recent store has occurred may (speculatively) see an older value. Intel refers to this feature as "Memory Disambiguation" which is part of their "Smart Memory Access" capability. Memory Disambiguation can expose a cache side-channel attack against such speculatively read values. An attacker can create exploit code that allows them to read memory outside of a sandbox environment (for example, malicious JavaScript in a web page), or to perform more complex attacks against code running within the same privilege level, e.g. via the stack. As a first step to mitigate against such attacks, provide two boot command line control knobs: nospec_store_bypass_disable spec_store_bypass_disable=[off,auto,on] By default affected x86 processors will power on with Speculative Store Bypass enabled. Hence the provided kernel parameters are written from the point of view of whether to enable a mitigation or not. The parameters are as follows: - auto - Kernel detects whether your CPU model contains an implementation of Speculative Store Bypass and picks the most appropriate mitigation. - on - disable Speculative Store Bypass - off - enable Speculative Store Bypass [ tglx: Reordered the checks so that the whole evaluation is not done when the CPU does not support RDS ] Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Ingo Molnar Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 33 +++++++++ arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/nospec-branch.h | 6 ++ arch/x86/kernel/cpu/bugs.c | 103 +++++++++++++++++++++++++++ 4 files changed, 143 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 5f9e51436a99..792ac917411a 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2699,6 +2699,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. allow data leaks with this option, which is equivalent to spectre_v2=off. + nospec_store_bypass_disable + [HW] Disable all mitigations for the Speculative Store Bypass vulnerability + noxsave [BUGS=X86] Disables x86 extended register state save and restore using xsave. The kernel will fallback to enabling legacy floating-point and sse state. @@ -3973,6 +3976,36 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Not specifying this option is equivalent to spectre_v2=auto. + spec_store_bypass_disable= + [HW] Control Speculative Store Bypass (SSB) Disable mitigation + (Speculative Store Bypass vulnerability) + + Certain CPUs are vulnerable to an exploit against a + a common industry wide performance optimization known + as "Speculative Store Bypass" in which recent stores + to the same memory location may not be observed by + later loads during speculative execution. The idea + is that such stores are unlikely and that they can + be detected prior to instruction retirement at the + end of a particular speculation execution window. + + In vulnerable processors, the speculatively forwarded + store can be used in a cache side channel attack, for + example to read memory to which the attacker does not + directly have access (e.g. inside sandboxed code). + + This parameter controls whether the Speculative Store + Bypass optimization is used. + + on - Unconditionally disable Speculative Store Bypass + off - Unconditionally enable Speculative Store Bypass + auto - Kernel detects whether the CPU model contains an + implementation of Speculative Store Bypass and + picks the most appropriate mitigation + + Not specifying this option is equivalent to + spec_store_bypass_disable=auto. + spia_io_base= [HW,MTD] spia_fio_base= spia_pedr= diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 0c05c6cf5a12..013f3defc6fa 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -204,6 +204,7 @@ #define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ #define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ +#define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* "" Disable Speculative Store Bypass. */ /* Virtualization flags: Linux defined, word 8 */ #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index d1c2630922da..7b9eacfc03f3 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -238,6 +238,12 @@ extern u64 x86_spec_ctrl_get_default(void); extern void x86_spec_ctrl_set_guest(u64); extern void x86_spec_ctrl_restore_host(u64); +/* The Speculative Store Bypass disable variants */ +enum ssb_mitigation { + SPEC_STORE_BYPASS_NONE, + SPEC_STORE_BYPASS_DISABLE, +}; + extern char __indirect_thunk_start[]; extern char __indirect_thunk_end[]; diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 64e17a962bb6..75146d99b3e1 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -26,6 +26,7 @@ #include static void __init spectre_v2_select_mitigation(void); +static void __init ssb_select_mitigation(void); /* * Our boot-time value of the SPEC_CTRL MSR. We read it once so that any @@ -52,6 +53,12 @@ void __init check_bugs(void) /* Select the proper spectre mitigation before patching alternatives */ spectre_v2_select_mitigation(); + /* + * Select proper mitigation for any exposure to the Speculative Store + * Bypass vulnerability. + */ + ssb_select_mitigation(); + #ifdef CONFIG_X86_32 /* * Check whether we are able to run this kernel safely on SMP. @@ -356,6 +363,99 @@ static void __init spectre_v2_select_mitigation(void) } } +#undef pr_fmt +#define pr_fmt(fmt) "Speculative Store Bypass: " fmt + +static enum ssb_mitigation ssb_mode = SPEC_STORE_BYPASS_NONE; + +/* The kernel command line selection */ +enum ssb_mitigation_cmd { + SPEC_STORE_BYPASS_CMD_NONE, + SPEC_STORE_BYPASS_CMD_AUTO, + SPEC_STORE_BYPASS_CMD_ON, +}; + +static const char *ssb_strings[] = { + [SPEC_STORE_BYPASS_NONE] = "Vulnerable", + [SPEC_STORE_BYPASS_DISABLE] = "Mitigation: Speculative Store Bypass disabled" +}; + +static const struct { + const char *option; + enum ssb_mitigation_cmd cmd; +} ssb_mitigation_options[] = { + { "auto", SPEC_STORE_BYPASS_CMD_AUTO }, /* Platform decides */ + { "on", SPEC_STORE_BYPASS_CMD_ON }, /* Disable Speculative Store Bypass */ + { "off", SPEC_STORE_BYPASS_CMD_NONE }, /* Don't touch Speculative Store Bypass */ +}; + +static enum ssb_mitigation_cmd __init ssb_parse_cmdline(void) +{ + enum ssb_mitigation_cmd cmd = SPEC_STORE_BYPASS_CMD_AUTO; + char arg[20]; + int ret, i; + + if (cmdline_find_option_bool(boot_command_line, "nospec_store_bypass_disable")) { + return SPEC_STORE_BYPASS_CMD_NONE; + } else { + ret = cmdline_find_option(boot_command_line, "spec_store_bypass_disable", + arg, sizeof(arg)); + if (ret < 0) + return SPEC_STORE_BYPASS_CMD_AUTO; + + for (i = 0; i < ARRAY_SIZE(ssb_mitigation_options); i++) { + if (!match_option(arg, ret, ssb_mitigation_options[i].option)) + continue; + + cmd = ssb_mitigation_options[i].cmd; + break; + } + + if (i >= ARRAY_SIZE(ssb_mitigation_options)) { + pr_err("unknown option (%s). Switching to AUTO select\n", arg); + return SPEC_STORE_BYPASS_CMD_AUTO; + } + } + + return cmd; +} + +static enum ssb_mitigation_cmd __init __ssb_select_mitigation(void) +{ + enum ssb_mitigation mode = SPEC_STORE_BYPASS_NONE; + enum ssb_mitigation_cmd cmd; + + if (!boot_cpu_has(X86_FEATURE_RDS)) + return mode; + + cmd = ssb_parse_cmdline(); + if (!boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS) && + (cmd == SPEC_STORE_BYPASS_CMD_NONE || + cmd == SPEC_STORE_BYPASS_CMD_AUTO)) + return mode; + + switch (cmd) { + case SPEC_STORE_BYPASS_CMD_AUTO: + case SPEC_STORE_BYPASS_CMD_ON: + mode = SPEC_STORE_BYPASS_DISABLE; + break; + case SPEC_STORE_BYPASS_CMD_NONE: + break; + } + + if (mode != SPEC_STORE_BYPASS_NONE) + setup_force_cpu_cap(X86_FEATURE_SPEC_STORE_BYPASS_DISABLE); + return mode; +} + +static void ssb_select_mitigation() +{ + ssb_mode = __ssb_select_mitigation(); + + if (boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS)) + pr_info("%s\n", ssb_strings[ssb_mode]); +} + #undef pr_fmt #ifdef CONFIG_SYSFS @@ -382,6 +482,9 @@ ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr, boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "", spectre_v2_module_string()); + case X86_BUG_SPEC_STORE_BYPASS: + return sprintf(buf, "%s\n", ssb_strings[ssb_mode]); + default: break; } -- GitLab From 19e3a2bec95e966921689ae39117f9dbbaffd99b Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 25 Apr 2018 22:04:22 -0400 Subject: [PATCH 380/855] x86/bugs/intel: Set proper CPU features and setup RDS commit 772439717dbf703b39990be58d8d4e3e4ad0598a upstream Intel CPUs expose methods to: - Detect whether RDS capability is available via CPUID.7.0.EDX[31], - The SPEC_CTRL MSR(0x48), bit 2 set to enable RDS. - MSR_IA32_ARCH_CAPABILITIES, Bit(4) no need to enable RRS. With that in mind if spec_store_bypass_disable=[auto,on] is selected set at boot-time the SPEC_CTRL MSR to enable RDS if the platform requires it. Note that this does not fix the KVM case where the SPEC_CTRL is exposed to guests which can muck with it, see patch titled : KVM/SVM/VMX/x86/spectre_v2: Support the combination of guest and host IBRS. And for the firmware (IBRS to be set), see patch titled: x86/spectre_v2: Read SPEC_CTRL MSR during boot and re-use reserved bits [ tglx: Distangled it from the intel implementation and kept the call order ] Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Ingo Molnar Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/msr-index.h | 6 ++++++ arch/x86/kernel/cpu/bugs.c | 30 ++++++++++++++++++++++++++++-- arch/x86/kernel/cpu/common.c | 10 ++++++---- arch/x86/kernel/cpu/cpu.h | 3 +++ arch/x86/kernel/cpu/intel.c | 1 + 5 files changed, 44 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index c768bc1550a1..87103e8f4785 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -40,6 +40,7 @@ #define MSR_IA32_SPEC_CTRL 0x00000048 /* Speculation Control */ #define SPEC_CTRL_IBRS (1 << 0) /* Indirect Branch Restricted Speculation */ #define SPEC_CTRL_STIBP (1 << 1) /* Single Thread Indirect Branch Predictors */ +#define SPEC_CTRL_RDS (1 << 2) /* Reduced Data Speculation */ #define MSR_IA32_PRED_CMD 0x00000049 /* Prediction Command */ #define PRED_CMD_IBPB (1 << 0) /* Indirect Branch Prediction Barrier */ @@ -61,6 +62,11 @@ #define MSR_IA32_ARCH_CAPABILITIES 0x0000010a #define ARCH_CAP_RDCL_NO (1 << 0) /* Not susceptible to Meltdown */ #define ARCH_CAP_IBRS_ALL (1 << 1) /* Enhanced IBRS support */ +#define ARCH_CAP_RDS_NO (1 << 4) /* + * Not susceptible to Speculative Store Bypass + * attack, so no Reduced Data Speculation control + * required. + */ #define MSR_IA32_BBL_CR_CTL 0x00000119 #define MSR_IA32_BBL_CR_CTL3 0x0000011e diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 75146d99b3e1..7dd16f4ec3c4 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -116,7 +116,7 @@ static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE; void x86_spec_ctrl_set(u64 val) { - if (val & ~SPEC_CTRL_IBRS) + if (val & ~(SPEC_CTRL_IBRS | SPEC_CTRL_RDS)) WARN_ONCE(1, "SPEC_CTRL MSR value 0x%16llx is unknown.\n", val); else wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base | val); @@ -443,8 +443,28 @@ static enum ssb_mitigation_cmd __init __ssb_select_mitigation(void) break; } - if (mode != SPEC_STORE_BYPASS_NONE) + /* + * We have three CPU feature flags that are in play here: + * - X86_BUG_SPEC_STORE_BYPASS - CPU is susceptible. + * - X86_FEATURE_RDS - CPU is able to turn off speculative store bypass + * - X86_FEATURE_SPEC_STORE_BYPASS_DISABLE - engage the mitigation + */ + if (mode != SPEC_STORE_BYPASS_NONE) { setup_force_cpu_cap(X86_FEATURE_SPEC_STORE_BYPASS_DISABLE); + /* + * Intel uses the SPEC CTRL MSR Bit(2) for this, while AMD uses + * a completely different MSR and bit dependent on family. + */ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_INTEL: + x86_spec_ctrl_base |= SPEC_CTRL_RDS; + x86_spec_ctrl_set(SPEC_CTRL_RDS); + break; + case X86_VENDOR_AMD: + break; + } + } + return mode; } @@ -458,6 +478,12 @@ static void ssb_select_mitigation() #undef pr_fmt +void x86_spec_ctrl_setup_ap(void) +{ + if (boot_cpu_has(X86_FEATURE_IBRS)) + x86_spec_ctrl_set(x86_spec_ctrl_base & (SPEC_CTRL_IBRS | SPEC_CTRL_RDS)); +} + #ifdef CONFIG_SYSFS ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr, diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 4f1050aedc26..ab6b3adaa3d7 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -903,7 +903,11 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) { u64 ia32_cap = 0; - if (!x86_match_cpu(cpu_no_spec_store_bypass)) + if (cpu_has(c, X86_FEATURE_ARCH_CAPABILITIES)) + rdmsrl(MSR_IA32_ARCH_CAPABILITIES, ia32_cap); + + if (!x86_match_cpu(cpu_no_spec_store_bypass) && + !(ia32_cap & ARCH_CAP_RDS_NO)) setup_force_cpu_bug(X86_BUG_SPEC_STORE_BYPASS); if (x86_match_cpu(cpu_no_speculation)) @@ -915,9 +919,6 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) if (x86_match_cpu(cpu_no_meltdown)) return; - if (cpu_has(c, X86_FEATURE_ARCH_CAPABILITIES)) - rdmsrl(MSR_IA32_ARCH_CAPABILITIES, ia32_cap); - /* Rogue Data Cache Load? No! */ if (ia32_cap & ARCH_CAP_RDCL_NO) return; @@ -1339,6 +1340,7 @@ void identify_secondary_cpu(struct cpuinfo_x86 *c) #endif mtrr_ap_init(); validate_apic_and_package_id(c); + x86_spec_ctrl_setup_ap(); } struct msr_range { diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h index 2584265d4745..3b19d82f7932 100644 --- a/arch/x86/kernel/cpu/cpu.h +++ b/arch/x86/kernel/cpu/cpu.h @@ -46,4 +46,7 @@ extern const struct cpu_dev *const __x86_cpu_dev_start[], extern void get_cpu_cap(struct cpuinfo_x86 *c); extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c); + +extern void x86_spec_ctrl_setup_ap(void); + #endif /* ARCH_X86_CPU_H */ diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 8fb1d6522f8e..f15aea653e8a 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -154,6 +154,7 @@ static void early_init_intel(struct cpuinfo_x86 *c) setup_clear_cpu_cap(X86_FEATURE_STIBP); setup_clear_cpu_cap(X86_FEATURE_SPEC_CTRL); setup_clear_cpu_cap(X86_FEATURE_INTEL_STIBP); + setup_clear_cpu_cap(X86_FEATURE_RDS); } /* -- GitLab From 99b13116965f16b2e608e7796cd59198eee5bf06 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 25 Apr 2018 22:04:23 -0400 Subject: [PATCH 381/855] x86/bugs: Whitelist allowed SPEC_CTRL MSR values commit 1115a859f33276fe8afb31c60cf9d8e657872558 upstream Intel and AMD SPEC_CTRL (0x48) MSR semantics may differ in the future (or in fact use different MSRs for the same functionality). As such a run-time mechanism is required to whitelist the appropriate MSR values. [ tglx: Made the variable __ro_after_init ] Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Reviewed-by: Ingo Molnar Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/bugs.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 7dd16f4ec3c4..b92c4699f2ea 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -34,6 +34,12 @@ static void __init ssb_select_mitigation(void); */ static u64 __ro_after_init x86_spec_ctrl_base; +/* + * The vendor and possibly platform specific bits which can be modified in + * x86_spec_ctrl_base. + */ +static u64 __ro_after_init x86_spec_ctrl_mask = ~SPEC_CTRL_IBRS; + void __init check_bugs(void) { identify_boot_cpu(); @@ -116,7 +122,7 @@ static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE; void x86_spec_ctrl_set(u64 val) { - if (val & ~(SPEC_CTRL_IBRS | SPEC_CTRL_RDS)) + if (val & x86_spec_ctrl_mask) WARN_ONCE(1, "SPEC_CTRL MSR value 0x%16llx is unknown.\n", val); else wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base | val); @@ -458,6 +464,7 @@ static enum ssb_mitigation_cmd __init __ssb_select_mitigation(void) switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_INTEL: x86_spec_ctrl_base |= SPEC_CTRL_RDS; + x86_spec_ctrl_mask &= ~SPEC_CTRL_RDS; x86_spec_ctrl_set(SPEC_CTRL_RDS); break; case X86_VENDOR_AMD: @@ -481,7 +488,7 @@ static void ssb_select_mitigation() void x86_spec_ctrl_setup_ap(void) { if (boot_cpu_has(X86_FEATURE_IBRS)) - x86_spec_ctrl_set(x86_spec_ctrl_base & (SPEC_CTRL_IBRS | SPEC_CTRL_RDS)); + x86_spec_ctrl_set(x86_spec_ctrl_base & ~x86_spec_ctrl_mask); } #ifdef CONFIG_SYSFS -- GitLab From f854434b37bbf8953900226acd6139081f60d3da Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 20 May 2018 20:52:05 +0100 Subject: [PATCH 382/855] x86/bugs/AMD: Add support to disable RDS on Fam[15,16,17]h if requested commit 764f3c21588a059cd783c6ba0734d4db2d72822d upstream AMD does not need the Speculative Store Bypass mitigation to be enabled. The parameters for this are already available and can be done via MSR C001_1020. Each family uses a different bit in that MSR for this. [ tglx: Expose the bit mask via a variable and move the actual MSR fiddling into the bugs code as that's the right thing to do and also required to prepare for dynamic enable/disable ] Suggested-by: Borislav Petkov Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Reviewed-by: Ingo Molnar Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/nospec-branch.h | 4 ++++ arch/x86/kernel/cpu/amd.c | 26 ++++++++++++++++++++++++++ arch/x86/kernel/cpu/bugs.c | 27 ++++++++++++++++++++++++++- arch/x86/kernel/cpu/common.c | 4 ++++ 5 files changed, 61 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 013f3defc6fa..87970694cac1 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -205,6 +205,7 @@ #define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ #define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ #define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* "" Disable Speculative Store Bypass. */ +#define X86_FEATURE_AMD_RDS (7*32+24) /* "" AMD RDS implementation */ /* Virtualization flags: Linux defined, word 8 */ #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 7b9eacfc03f3..3a1541cf32de 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -244,6 +244,10 @@ enum ssb_mitigation { SPEC_STORE_BYPASS_DISABLE, }; +/* AMD specific Speculative Store Bypass MSR data */ +extern u64 x86_amd_ls_cfg_base; +extern u64 x86_amd_ls_cfg_rds_mask; + extern char __indirect_thunk_start[]; extern char __indirect_thunk_end[]; diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 747f8a20b629..7551d9ad243a 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -542,6 +543,26 @@ static void bsp_init_amd(struct cpuinfo_x86 *c) rdmsrl(MSR_FAM10H_NODE_ID, value); nodes_per_socket = ((value >> 3) & 7) + 1; } + + if (c->x86 >= 0x15 && c->x86 <= 0x17) { + unsigned int bit; + + switch (c->x86) { + case 0x15: bit = 54; break; + case 0x16: bit = 33; break; + case 0x17: bit = 10; break; + default: return; + } + /* + * Try to cache the base value so further operations can + * avoid RMW. If that faults, do not enable RDS. + */ + if (!rdmsrl_safe(MSR_AMD64_LS_CFG, &x86_amd_ls_cfg_base)) { + setup_force_cpu_cap(X86_FEATURE_RDS); + setup_force_cpu_cap(X86_FEATURE_AMD_RDS); + x86_amd_ls_cfg_rds_mask = 1ULL << bit; + } + } } static void early_init_amd(struct cpuinfo_x86 *c) @@ -827,6 +848,11 @@ static void init_amd(struct cpuinfo_x86 *c) /* AMD CPUs don't reset SS attributes on SYSRET, Xen does. */ if (!cpu_has(c, X86_FEATURE_XENPV)) set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); + + if (boot_cpu_has(X86_FEATURE_AMD_RDS)) { + set_cpu_cap(c, X86_FEATURE_RDS); + set_cpu_cap(c, X86_FEATURE_AMD_RDS); + } } #ifdef CONFIG_X86_32 diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index b92c4699f2ea..b3696cc48fd6 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -40,6 +40,13 @@ static u64 __ro_after_init x86_spec_ctrl_base; */ static u64 __ro_after_init x86_spec_ctrl_mask = ~SPEC_CTRL_IBRS; +/* + * AMD specific MSR info for Speculative Store Bypass control. + * x86_amd_ls_cfg_rds_mask is initialized in identify_boot_cpu(). + */ +u64 __ro_after_init x86_amd_ls_cfg_base; +u64 __ro_after_init x86_amd_ls_cfg_rds_mask; + void __init check_bugs(void) { identify_boot_cpu(); @@ -51,7 +58,8 @@ void __init check_bugs(void) /* * Read the SPEC_CTRL MSR to account for reserved bits which may - * have unknown values. + * have unknown values. AMD64_LS_CFG MSR is cached in the early AMD + * init code as it is not enumerated and depends on the family. */ if (boot_cpu_has(X86_FEATURE_IBRS)) rdmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base); @@ -153,6 +161,14 @@ void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl) } EXPORT_SYMBOL_GPL(x86_spec_ctrl_restore_host); +static void x86_amd_rds_enable(void) +{ + u64 msrval = x86_amd_ls_cfg_base | x86_amd_ls_cfg_rds_mask; + + if (boot_cpu_has(X86_FEATURE_AMD_RDS)) + wrmsrl(MSR_AMD64_LS_CFG, msrval); +} + #ifdef RETPOLINE static bool spectre_v2_bad_module; @@ -442,6 +458,11 @@ static enum ssb_mitigation_cmd __init __ssb_select_mitigation(void) switch (cmd) { case SPEC_STORE_BYPASS_CMD_AUTO: + /* + * AMD platforms by default don't need SSB mitigation. + */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + break; case SPEC_STORE_BYPASS_CMD_ON: mode = SPEC_STORE_BYPASS_DISABLE; break; @@ -468,6 +489,7 @@ static enum ssb_mitigation_cmd __init __ssb_select_mitigation(void) x86_spec_ctrl_set(SPEC_CTRL_RDS); break; case X86_VENDOR_AMD: + x86_amd_rds_enable(); break; } } @@ -489,6 +511,9 @@ void x86_spec_ctrl_setup_ap(void) { if (boot_cpu_has(X86_FEATURE_IBRS)) x86_spec_ctrl_set(x86_spec_ctrl_base & ~x86_spec_ctrl_mask); + + if (ssb_mode == SPEC_STORE_BYPASS_DISABLE) + x86_amd_rds_enable(); } #ifdef CONFIG_SYSFS diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index ab6b3adaa3d7..beb1da89ea7d 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -895,6 +895,10 @@ static const __initconst struct x86_cpu_id cpu_no_spec_store_bypass[] = { { X86_VENDOR_CENTAUR, 5, }, { X86_VENDOR_INTEL, 5, }, { X86_VENDOR_NSC, 5, }, + { X86_VENDOR_AMD, 0x12, }, + { X86_VENDOR_AMD, 0x11, }, + { X86_VENDOR_AMD, 0x10, }, + { X86_VENDOR_AMD, 0xf, }, { X86_VENDOR_ANY, 4, }, {} }; -- GitLab From 99318eca2c7ab3250b9614043b9ac6077ff2cb46 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 25 Apr 2018 22:04:25 -0400 Subject: [PATCH 383/855] x86/KVM/VMX: Expose SPEC_CTRL Bit(2) to the guest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit da39556f66f5cfe8f9c989206974f1cb16ca5d7c upstream Expose the CPUID.7.EDX[31] bit to the guest, and also guard against various combinations of SPEC_CTRL MSR values. The handling of the MSR (to take into account the host value of SPEC_CTRL Bit(2)) is taken care of in patch: KVM/SVM/VMX/x86/spectre_v2: Support the combination of guest and host IBRS Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Reviewed-by: Ingo Molnar [dwmw2: Handle 4.9 guest CPUID differences, rename guest_cpu_has_ibrs() → guest_cpu_has_spec_ctrl()] Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/cpuid.c | 2 +- arch/x86/kvm/cpuid.h | 4 ++-- arch/x86/kvm/svm.c | 4 ++-- arch/x86/kvm/vmx.c | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 93f924de06cf..a9409f06ddc9 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -382,7 +382,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, /* cpuid 7.0.edx*/ const u32 kvm_cpuid_7_0_edx_x86_features = - F(SPEC_CTRL) | F(ARCH_CAPABILITIES); + F(SPEC_CTRL) | F(RDS) | F(ARCH_CAPABILITIES); /* all calls to cpuid_count() should be made on the same cpu */ get_cpu(); diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index d1beb7156704..24187d07c2cf 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -171,7 +171,7 @@ static inline bool guest_cpuid_has_ibpb(struct kvm_vcpu *vcpu) return best && (best->edx & bit(X86_FEATURE_SPEC_CTRL)); } -static inline bool guest_cpuid_has_ibrs(struct kvm_vcpu *vcpu) +static inline bool guest_cpuid_has_spec_ctrl(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; @@ -179,7 +179,7 @@ static inline bool guest_cpuid_has_ibrs(struct kvm_vcpu *vcpu) if (best && (best->ebx & bit(X86_FEATURE_IBRS))) return true; best = kvm_find_cpuid_entry(vcpu, 7, 0); - return best && (best->edx & bit(X86_FEATURE_SPEC_CTRL)); + return best && (best->edx & (bit(X86_FEATURE_SPEC_CTRL) | bit(X86_FEATURE_RDS))); } static inline bool guest_cpuid_has_arch_capabilities(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index eeb8cd3193ea..57b886bf5ac5 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -3545,7 +3545,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; case MSR_IA32_SPEC_CTRL: if (!msr_info->host_initiated && - !guest_cpuid_has_ibrs(vcpu)) + !guest_cpuid_has_spec_ctrl(vcpu)) return 1; msr_info->data = svm->spec_ctrl; @@ -3643,7 +3643,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) break; case MSR_IA32_SPEC_CTRL: if (!msr->host_initiated && - !guest_cpuid_has_ibrs(vcpu)) + !guest_cpuid_has_spec_ctrl(vcpu)) return 1; /* The STIBP bit doesn't fault even if it's not advertised */ diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 266db0b2e138..67ed4e9f9e5b 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -3020,7 +3020,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; case MSR_IA32_SPEC_CTRL: if (!msr_info->host_initiated && - !guest_cpuid_has_ibrs(vcpu)) + !guest_cpuid_has_spec_ctrl(vcpu)) return 1; msr_info->data = to_vmx(vcpu)->spec_ctrl; @@ -3137,11 +3137,11 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; case MSR_IA32_SPEC_CTRL: if (!msr_info->host_initiated && - !guest_cpuid_has_ibrs(vcpu)) + !guest_cpuid_has_spec_ctrl(vcpu)) return 1; /* The STIBP bit doesn't fault even if it's not advertised */ - if (data & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP)) + if (data & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP | SPEC_CTRL_RDS)) return 1; vmx->spec_ctrl = data; -- GitLab From 7a2d2358ba9b6de29be0a98c8290479df32604b6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 29 Apr 2018 15:01:37 +0200 Subject: [PATCH 384/855] x86/speculation: Create spec-ctrl.h to avoid include hell commit 28a2775217b17208811fa43a9e96bd1fdf417b86 upstream Having everything in nospec-branch.h creates a hell of dependencies when adding the prctl based switching mechanism. Move everything which is not required in nospec-branch.h to spec-ctrl.h and fix up the includes in the relevant files. Signed-off-by: Thomas Gleixner Reviewed-by: Konrad Rzeszutek Wilk Reviewed-by: Ingo Molnar Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/nospec-branch.h | 14 -------------- arch/x86/include/asm/spec-ctrl.h | 21 +++++++++++++++++++++ arch/x86/kernel/cpu/amd.c | 2 +- arch/x86/kernel/cpu/bugs.c | 2 +- arch/x86/kvm/svm.c | 2 +- arch/x86/kvm/vmx.c | 2 +- 6 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 arch/x86/include/asm/spec-ctrl.h diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 3a1541cf32de..1119f14bc883 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -228,26 +228,12 @@ enum spectre_v2_mitigation { extern void x86_spec_ctrl_set(u64); extern u64 x86_spec_ctrl_get_default(void); -/* - * On VMENTER we must preserve whatever view of the SPEC_CTRL MSR - * the guest has, while on VMEXIT we restore the host view. This - * would be easier if SPEC_CTRL were architecturally maskable or - * shadowable for guests but this is not (currently) the case. - * Takes the guest view of SPEC_CTRL MSR as a parameter. - */ -extern void x86_spec_ctrl_set_guest(u64); -extern void x86_spec_ctrl_restore_host(u64); - /* The Speculative Store Bypass disable variants */ enum ssb_mitigation { SPEC_STORE_BYPASS_NONE, SPEC_STORE_BYPASS_DISABLE, }; -/* AMD specific Speculative Store Bypass MSR data */ -extern u64 x86_amd_ls_cfg_base; -extern u64 x86_amd_ls_cfg_rds_mask; - extern char __indirect_thunk_start[]; extern char __indirect_thunk_end[]; diff --git a/arch/x86/include/asm/spec-ctrl.h b/arch/x86/include/asm/spec-ctrl.h new file mode 100644 index 000000000000..3ad64420a06e --- /dev/null +++ b/arch/x86/include/asm/spec-ctrl.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_SPECCTRL_H_ +#define _ASM_X86_SPECCTRL_H_ + +#include + +/* + * On VMENTER we must preserve whatever view of the SPEC_CTRL MSR + * the guest has, while on VMEXIT we restore the host view. This + * would be easier if SPEC_CTRL were architecturally maskable or + * shadowable for guests but this is not (currently) the case. + * Takes the guest view of SPEC_CTRL MSR as a parameter. + */ +extern void x86_spec_ctrl_set_guest(u64); +extern void x86_spec_ctrl_restore_host(u64); + +/* AMD specific Speculative Store Bypass MSR data */ +extern u64 x86_amd_ls_cfg_base; +extern u64 x86_amd_ls_cfg_rds_mask; + +#endif diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 7551d9ad243a..a176c81a74b2 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index b3696cc48fd6..46d01fd4c3c8 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 57b886bf5ac5..516ddfff8c8b 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include "trace.h" diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 67ed4e9f9e5b..0eb3863d3159 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include "trace.h" #include "pmu.h" -- GitLab From 4812ffbbfcac35270b82292e84e8e7187088c8b8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 29 Apr 2018 15:20:11 +0200 Subject: [PATCH 385/855] prctl: Add speculation control prctls commit b617cfc858161140d69cc0b5cc211996b557a1c7 upstream Add two new prctls to control aspects of speculation related vulnerabilites and their mitigations to provide finer grained control over performance impacting mitigations. PR_GET_SPECULATION_CTRL returns the state of the speculation misfeature which is selected with arg2 of prctl(2). The return value uses bit 0-2 with the following meaning: Bit Define Description 0 PR_SPEC_PRCTL Mitigation can be controlled per task by PR_SET_SPECULATION_CTRL 1 PR_SPEC_ENABLE The speculation feature is enabled, mitigation is disabled 2 PR_SPEC_DISABLE The speculation feature is disabled, mitigation is enabled If all bits are 0 the CPU is not affected by the speculation misfeature. If PR_SPEC_PRCTL is set, then the per task control of the mitigation is available. If not set, prctl(PR_SET_SPECULATION_CTRL) for the speculation misfeature will fail. PR_SET_SPECULATION_CTRL allows to control the speculation misfeature, which is selected by arg2 of prctl(2) per task. arg3 is used to hand in the control value, i.e. either PR_SPEC_ENABLE or PR_SPEC_DISABLE. The common return values are: EINVAL prctl is not implemented by the architecture or the unused prctl() arguments are not 0 ENODEV arg2 is selecting a not supported speculation misfeature PR_SET_SPECULATION_CTRL has these additional return values: ERANGE arg3 is incorrect, i.e. it's not either PR_SPEC_ENABLE or PR_SPEC_DISABLE ENXIO prctl control of the selected speculation misfeature is disabled The first supported controlable speculation misfeature is PR_SPEC_STORE_BYPASS. Add the define so this can be shared between architectures. Based on an initial patch from Tim Chen and mostly rewritten. Signed-off-by: Thomas Gleixner Reviewed-by: Ingo Molnar Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- Documentation/spec_ctrl.txt | 86 +++++++++++++++++++++++++++++++++++++ include/linux/nospec.h | 5 +++ include/uapi/linux/prctl.h | 11 +++++ kernel/sys.c | 22 ++++++++++ 4 files changed, 124 insertions(+) create mode 100644 Documentation/spec_ctrl.txt diff --git a/Documentation/spec_ctrl.txt b/Documentation/spec_ctrl.txt new file mode 100644 index 000000000000..ddbebcd01208 --- /dev/null +++ b/Documentation/spec_ctrl.txt @@ -0,0 +1,86 @@ +=================== +Speculation Control +=================== + +Quite some CPUs have speculation related misfeatures which are in fact +vulnerabilites causing data leaks in various forms even accross privilege +domains. + +The kernel provides mitigation for such vulnerabilities in various +forms. Some of these mitigations are compile time configurable and some on +the kernel command line. + +There is also a class of mitigations which are very expensive, but they can +be restricted to a certain set of processes or tasks in controlled +environments. The mechanism to control these mitigations is via +:manpage:`prctl(2)`. + +There are two prctl options which are related to this: + + * PR_GET_SPECULATION_CTRL + + * PR_SET_SPECULATION_CTRL + +PR_GET_SPECULATION_CTRL +----------------------- + +PR_GET_SPECULATION_CTRL returns the state of the speculation misfeature +which is selected with arg2 of prctl(2). The return value uses bits 0-2 with +the following meaning: + +==== ================ =================================================== +Bit Define Description +==== ================ =================================================== +0 PR_SPEC_PRCTL Mitigation can be controlled per task by + PR_SET_SPECULATION_CTRL +1 PR_SPEC_ENABLE The speculation feature is enabled, mitigation is + disabled +2 PR_SPEC_DISABLE The speculation feature is disabled, mitigation is + enabled +==== ================ =================================================== + +If all bits are 0 the CPU is not affected by the speculation misfeature. + +If PR_SPEC_PRCTL is set, then the per task control of the mitigation is +available. If not set, prctl(PR_SET_SPECULATION_CTRL) for the speculation +misfeature will fail. + +PR_SET_SPECULATION_CTRL +----------------------- +PR_SET_SPECULATION_CTRL allows to control the speculation misfeature, which +is selected by arg2 of :manpage:`prctl(2)` per task. arg3 is used to hand +in the control value, i.e. either PR_SPEC_ENABLE or PR_SPEC_DISABLE. + +Common error codes +------------------ +======= ================================================================= +Value Meaning +======= ================================================================= +EINVAL The prctl is not implemented by the architecture or unused + prctl(2) arguments are not 0 + +ENODEV arg2 is selecting a not supported speculation misfeature +======= ================================================================= + +PR_SET_SPECULATION_CTRL error codes +----------------------------------- +======= ================================================================= +Value Meaning +======= ================================================================= +0 Success + +ERANGE arg3 is incorrect, i.e. it's neither PR_SPEC_ENABLE nor + PR_SPEC_DISABLE + +ENXIO Control of the selected speculation misfeature is not possible. + See PR_GET_SPECULATION_CTRL. +======= ================================================================= + +Speculation misfeature controls +------------------------------- +- PR_SPEC_STORE_BYPASS: Speculative Store Bypass + + Invocations: + * prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, 0, 0, 0); + * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_ENABLE, 0, 0); + * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_DISABLE, 0, 0); diff --git a/include/linux/nospec.h b/include/linux/nospec.h index e791ebc65c9c..700bb8a4e4ea 100644 --- a/include/linux/nospec.h +++ b/include/linux/nospec.h @@ -55,4 +55,9 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, \ (typeof(_i)) (_i & _mask); \ }) + +/* Speculation control prctl */ +int arch_prctl_spec_ctrl_get(unsigned long which); +int arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl); + #endif /* _LINUX_NOSPEC_H */ diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index a8d0759a9e40..3b316be71c56 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -197,4 +197,15 @@ struct prctl_mm_map { # define PR_CAP_AMBIENT_LOWER 3 # define PR_CAP_AMBIENT_CLEAR_ALL 4 +/* Per task speculation control */ +#define PR_GET_SPECULATION_CTRL 52 +#define PR_SET_SPECULATION_CTRL 53 +/* Speculation control variants */ +# define PR_SPEC_STORE_BYPASS 0 +/* Return and control values for PR_SET/GET_SPECULATION_CTRL */ +# define PR_SPEC_NOT_AFFECTED 0 +# define PR_SPEC_PRCTL (1UL << 0) +# define PR_SPEC_ENABLE (1UL << 1) +# define PR_SPEC_DISABLE (1UL << 2) + #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/sys.c b/kernel/sys.c index 89d5be418157..312c985c4643 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -53,6 +53,8 @@ #include #include +#include + #include /* Move somewhere else to avoid recompiling? */ #include @@ -2072,6 +2074,16 @@ static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr) } #endif +int __weak arch_prctl_spec_ctrl_get(unsigned long which) +{ + return -EINVAL; +} + +int __weak arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl) +{ + return -EINVAL; +} + SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, unsigned long, arg4, unsigned long, arg5) { @@ -2270,6 +2282,16 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, case PR_GET_FP_MODE: error = GET_FP_MODE(me); break; + case PR_GET_SPECULATION_CTRL: + if (arg3 || arg4 || arg5) + return -EINVAL; + error = arch_prctl_spec_ctrl_get(arg2); + break; + case PR_SET_SPECULATION_CTRL: + if (arg4 || arg5) + return -EINVAL; + error = arch_prctl_spec_ctrl_set(arg2, arg3); + break; default: error = -EINVAL; break; -- GitLab From fd01e82efa269b7e295533ec7b2d93aa8adf670a Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Tue, 14 Feb 2017 00:11:02 -0800 Subject: [PATCH 386/855] x86/process: Optimize TIF checks in __switch_to_xtra() commit af8b3cd3934ec60f4c2a420d19a9d416554f140b upstream Help the compiler to avoid reevaluating the thread flags for each checked bit by reordering the bit checks and providing an explicit xor for evaluation. With default defconfigs for each arch, x86_64: arch/x86/kernel/process.o text data bss dec hex 3056 8577 16 11649 2d81 Before 3024 8577 16 11617 2d61 After i386: arch/x86/kernel/process.o text data bss dec hex 2957 8673 8 11638 2d76 Before 2925 8673 8 11606 2d56 After Originally-by: Thomas Gleixner Signed-off-by: Kyle Huey Cc: Peter Zijlstra Cc: Andy Lutomirski Link: http://lkml.kernel.org/r/20170214081104.9244-2-khuey@kylehuey.com Signed-off-by: Thomas Gleixner [dwmw2: backported to make TIF_RDS handling simpler. No deferred TR reload.] Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/process.c | 54 ++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index a55b32007785..0e1999e99470 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -192,48 +192,56 @@ int set_tsc_mode(unsigned int val) return 0; } +static inline void switch_to_bitmap(struct tss_struct *tss, + struct thread_struct *prev, + struct thread_struct *next, + unsigned long tifp, unsigned long tifn) +{ + if (tifn & _TIF_IO_BITMAP) { + /* + * Copy the relevant range of the IO bitmap. + * Normally this is 128 bytes or less: + */ + memcpy(tss->io_bitmap, next->io_bitmap_ptr, + max(prev->io_bitmap_max, next->io_bitmap_max)); + } else if (tifp & _TIF_IO_BITMAP) { + /* + * Clear any possible leftover bits: + */ + memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); + } +} + void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, struct tss_struct *tss) { struct thread_struct *prev, *next; + unsigned long tifp, tifn; prev = &prev_p->thread; next = &next_p->thread; - if (test_tsk_thread_flag(prev_p, TIF_BLOCKSTEP) ^ - test_tsk_thread_flag(next_p, TIF_BLOCKSTEP)) { + tifn = READ_ONCE(task_thread_info(next_p)->flags); + tifp = READ_ONCE(task_thread_info(prev_p)->flags); + switch_to_bitmap(tss, prev, next, tifp, tifn); + + propagate_user_return_notify(prev_p, next_p); + + if ((tifp ^ tifn) & _TIF_BLOCKSTEP) { unsigned long debugctl = get_debugctlmsr(); debugctl &= ~DEBUGCTLMSR_BTF; - if (test_tsk_thread_flag(next_p, TIF_BLOCKSTEP)) + if (tifn & _TIF_BLOCKSTEP) debugctl |= DEBUGCTLMSR_BTF; - update_debugctlmsr(debugctl); } - if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^ - test_tsk_thread_flag(next_p, TIF_NOTSC)) { - /* prev and next are different */ - if (test_tsk_thread_flag(next_p, TIF_NOTSC)) + if ((tifp ^ tifn) & _TIF_NOTSC) { + if (tifn & _TIF_NOTSC) hard_disable_TSC(); else hard_enable_TSC(); } - - if (test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { - /* - * Copy the relevant range of the IO bitmap. - * Normally this is 128 bytes or less: - */ - memcpy(tss->io_bitmap, next->io_bitmap_ptr, - max(prev->io_bitmap_max, next->io_bitmap_max)); - } else if (test_tsk_thread_flag(prev_p, TIF_IO_BITMAP)) { - /* - * Clear any possible leftover bits: - */ - memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); - } - propagate_user_return_notify(prev_p, next_p); } /* -- GitLab From 439f2ef884306976f22b42f709c1ccdf04278987 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Tue, 14 Feb 2017 00:11:03 -0800 Subject: [PATCH 387/855] x86/process: Correct and optimize TIF_BLOCKSTEP switch commit b9894a2f5bd18b1691cb6872c9afe32b148d0132 upstream The debug control MSR is "highly magical" as the blockstep bit can be cleared by hardware under not well documented circumstances. So a task switch relying on the bit set by the previous task (according to the previous tasks thread flags) can trip over this and not update the flag for the next task. To fix this its required to handle DEBUGCTLMSR_BTF when either the previous or the next or both tasks have the TIF_BLOCKSTEP flag set. While at it avoid branching within the TIF_BLOCKSTEP case and evaluating boot_cpu_data twice in kernels without CONFIG_X86_DEBUGCTLMSR. x86_64: arch/x86/kernel/process.o text data bss dec hex 3024 8577 16 11617 2d61 Before 3008 8577 16 11601 2d51 After i386: No change [ tglx: Made the shift value explicit, use a local variable to make the code readable and massaged changelog] Originally-by: Thomas Gleixner Signed-off-by: Kyle Huey Cc: Peter Zijlstra Cc: Andy Lutomirski Link: http://lkml.kernel.org/r/20170214081104.9244-3-khuey@kylehuey.com Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/msr-index.h | 1 + arch/x86/kernel/process.c | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 87103e8f4785..076e86838245 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -141,6 +141,7 @@ /* DEBUGCTLMSR bits (others vary by model): */ #define DEBUGCTLMSR_LBR (1UL << 0) /* last branch recording */ +#define DEBUGCTLMSR_BTF_SHIFT 1 #define DEBUGCTLMSR_BTF (1UL << 1) /* single-step on branches */ #define DEBUGCTLMSR_TR (1UL << 6) #define DEBUGCTLMSR_BTS (1UL << 7) diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 0e1999e99470..496eef653d23 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -227,13 +227,15 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, propagate_user_return_notify(prev_p, next_p); - if ((tifp ^ tifn) & _TIF_BLOCKSTEP) { - unsigned long debugctl = get_debugctlmsr(); + if ((tifp & _TIF_BLOCKSTEP || tifn & _TIF_BLOCKSTEP) && + arch_has_block_step()) { + unsigned long debugctl, msk; + rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); debugctl &= ~DEBUGCTLMSR_BTF; - if (tifn & _TIF_BLOCKSTEP) - debugctl |= DEBUGCTLMSR_BTF; - update_debugctlmsr(debugctl); + msk = tifn & _TIF_BLOCKSTEP; + debugctl |= (msk >> TIF_BLOCKSTEP) << DEBUGCTLMSR_BTF_SHIFT; + wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); } if ((tifp ^ tifn) & _TIF_NOTSC) { -- GitLab From 5ed7788df973455378e987fe221bef0661fbe03a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 14 Feb 2017 00:11:04 -0800 Subject: [PATCH 388/855] x86/process: Optimize TIF_NOTSC switch commit 5a920155e388ec22a22e0532fb695b9215c9b34d upstream Provide and use a toggle helper instead of doing it with a branch. x86_64: arch/x86/kernel/process.o text data bss dec hex 3008 8577 16 11601 2d51 Before 2976 8577 16 11569 2d31 After i386: arch/x86/kernel/process.o text data bss dec hex 2925 8673 8 11606 2d56 Before 2893 8673 8 11574 2d36 After Signed-off-by: Thomas Gleixner Cc: Peter Zijlstra Cc: Andy Lutomirski Link: http://lkml.kernel.org/r/20170214081104.9244-4-khuey@kylehuey.com Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/tlbflush.h | 10 ++++++++++ arch/x86/kernel/process.c | 22 ++++------------------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index 99185a064978..686a58d793e5 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -111,6 +111,16 @@ static inline void cr4_clear_bits(unsigned long mask) } } +static inline void cr4_toggle_bits(unsigned long mask) +{ + unsigned long cr4; + + cr4 = this_cpu_read(cpu_tlbstate.cr4); + cr4 ^= mask; + this_cpu_write(cpu_tlbstate.cr4, cr4); + __write_cr4(cr4); +} + /* Read the CR4 shadow. */ static inline unsigned long cr4_read_shadow(void) { diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 496eef653d23..b7e3822238ad 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -134,11 +134,6 @@ void flush_thread(void) fpu__clear(&tsk->thread.fpu); } -static void hard_disable_TSC(void) -{ - cr4_set_bits(X86_CR4_TSD); -} - void disable_TSC(void) { preempt_disable(); @@ -147,15 +142,10 @@ void disable_TSC(void) * Must flip the CPU state synchronously with * TIF_NOTSC in the current running context. */ - hard_disable_TSC(); + cr4_set_bits(X86_CR4_TSD); preempt_enable(); } -static void hard_enable_TSC(void) -{ - cr4_clear_bits(X86_CR4_TSD); -} - static void enable_TSC(void) { preempt_disable(); @@ -164,7 +154,7 @@ static void enable_TSC(void) * Must flip the CPU state synchronously with * TIF_NOTSC in the current running context. */ - hard_enable_TSC(); + cr4_clear_bits(X86_CR4_TSD); preempt_enable(); } @@ -238,12 +228,8 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); } - if ((tifp ^ tifn) & _TIF_NOTSC) { - if (tifn & _TIF_NOTSC) - hard_disable_TSC(); - else - hard_enable_TSC(); - } + if ((tifp ^ tifn) & _TIF_NOTSC) + cr4_toggle_bits(X86_CR4_TSD); } /* -- GitLab From 89c6e9b599c573802de1b2fff6a9ccd99c3c4e57 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 29 Apr 2018 15:21:42 +0200 Subject: [PATCH 389/855] x86/process: Allow runtime control of Speculative Store Bypass commit 885f82bfbc6fefb6664ea27965c3ab9ac4194b8c upstream The Speculative Store Bypass vulnerability can be mitigated with the Reduced Data Speculation (RDS) feature. To allow finer grained control of this eventually expensive mitigation a per task mitigation control is required. Add a new TIF_RDS flag and put it into the group of TIF flags which are evaluated for mismatch in switch_to(). If these bits differ in the previous and the next task, then the slow path function __switch_to_xtra() is invoked. Implement the TIF_RDS dependent mitigation control in the slow path. If the prctl for controlling Speculative Store Bypass is disabled or no task uses the prctl then there is no overhead in the switch_to() fast path. Update the KVM related speculation control functions to take TID_RDS into account as well. Based on a patch from Tim Chen. Completely rewritten. Signed-off-by: Thomas Gleixner Reviewed-by: Ingo Molnar Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/msr-index.h | 3 ++- arch/x86/include/asm/spec-ctrl.h | 17 +++++++++++++++++ arch/x86/include/asm/thread_info.h | 6 ++++-- arch/x86/kernel/cpu/bugs.c | 26 +++++++++++++++++++++----- arch/x86/kernel/process.c | 22 ++++++++++++++++++++++ 5 files changed, 66 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 076e86838245..5dd28d0e9f0e 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -40,7 +40,8 @@ #define MSR_IA32_SPEC_CTRL 0x00000048 /* Speculation Control */ #define SPEC_CTRL_IBRS (1 << 0) /* Indirect Branch Restricted Speculation */ #define SPEC_CTRL_STIBP (1 << 1) /* Single Thread Indirect Branch Predictors */ -#define SPEC_CTRL_RDS (1 << 2) /* Reduced Data Speculation */ +#define SPEC_CTRL_RDS_SHIFT 2 /* Reduced Data Speculation bit */ +#define SPEC_CTRL_RDS (1 << SPEC_CTRL_RDS_SHIFT) /* Reduced Data Speculation */ #define MSR_IA32_PRED_CMD 0x00000049 /* Prediction Command */ #define PRED_CMD_IBPB (1 << 0) /* Indirect Branch Prediction Barrier */ diff --git a/arch/x86/include/asm/spec-ctrl.h b/arch/x86/include/asm/spec-ctrl.h index 3ad64420a06e..45ef00ad5105 100644 --- a/arch/x86/include/asm/spec-ctrl.h +++ b/arch/x86/include/asm/spec-ctrl.h @@ -2,6 +2,7 @@ #ifndef _ASM_X86_SPECCTRL_H_ #define _ASM_X86_SPECCTRL_H_ +#include #include /* @@ -18,4 +19,20 @@ extern void x86_spec_ctrl_restore_host(u64); extern u64 x86_amd_ls_cfg_base; extern u64 x86_amd_ls_cfg_rds_mask; +/* The Intel SPEC CTRL MSR base value cache */ +extern u64 x86_spec_ctrl_base; + +static inline u64 rds_tif_to_spec_ctrl(u64 tifn) +{ + BUILD_BUG_ON(TIF_RDS < SPEC_CTRL_RDS_SHIFT); + return (tifn & _TIF_RDS) >> (TIF_RDS - SPEC_CTRL_RDS_SHIFT); +} + +static inline u64 rds_tif_to_amd_ls_cfg(u64 tifn) +{ + return (tifn & _TIF_RDS) ? x86_amd_ls_cfg_rds_mask : 0ULL; +} + +extern void speculative_store_bypass_update(void); + #endif diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 89978b9c667a..661afac34502 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -83,6 +83,7 @@ struct thread_info { #define TIF_SIGPENDING 2 /* signal pending */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/ +#define TIF_RDS 5 /* Reduced data speculation */ #define TIF_SYSCALL_EMU 6 /* syscall emulation active */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_SECCOMP 8 /* secure computing */ @@ -104,8 +105,9 @@ struct thread_info { #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) -#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) +#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) +#define _TIF_RDS (1 << TIF_RDS) #define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SECCOMP (1 << TIF_SECCOMP) @@ -139,7 +141,7 @@ struct thread_info { /* flags to check in __switch_to() */ #define _TIF_WORK_CTXSW \ - (_TIF_IO_BITMAP|_TIF_NOTSC|_TIF_BLOCKSTEP) + (_TIF_IO_BITMAP|_TIF_NOTSC|_TIF_BLOCKSTEP|_TIF_RDS) #define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY) #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 46d01fd4c3c8..4f0957600076 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -32,7 +32,7 @@ static void __init ssb_select_mitigation(void); * Our boot-time value of the SPEC_CTRL MSR. We read it once so that any * writes to SPEC_CTRL contain whatever reserved bits have been set. */ -static u64 __ro_after_init x86_spec_ctrl_base; +u64 __ro_after_init x86_spec_ctrl_base; /* * The vendor and possibly platform specific bits which can be modified in @@ -139,25 +139,41 @@ EXPORT_SYMBOL_GPL(x86_spec_ctrl_set); u64 x86_spec_ctrl_get_default(void) { - return x86_spec_ctrl_base; + u64 msrval = x86_spec_ctrl_base; + + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + msrval |= rds_tif_to_spec_ctrl(current_thread_info()->flags); + return msrval; } EXPORT_SYMBOL_GPL(x86_spec_ctrl_get_default); void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl) { + u64 host = x86_spec_ctrl_base; + if (!boot_cpu_has(X86_FEATURE_IBRS)) return; - if (x86_spec_ctrl_base != guest_spec_ctrl) + + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + host |= rds_tif_to_spec_ctrl(current_thread_info()->flags); + + if (host != guest_spec_ctrl) wrmsrl(MSR_IA32_SPEC_CTRL, guest_spec_ctrl); } EXPORT_SYMBOL_GPL(x86_spec_ctrl_set_guest); void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl) { + u64 host = x86_spec_ctrl_base; + if (!boot_cpu_has(X86_FEATURE_IBRS)) return; - if (x86_spec_ctrl_base != guest_spec_ctrl) - wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base); + + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + host |= rds_tif_to_spec_ctrl(current_thread_info()->flags); + + if (host != guest_spec_ctrl) + wrmsrl(MSR_IA32_SPEC_CTRL, host); } EXPORT_SYMBOL_GPL(x86_spec_ctrl_restore_host); diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index b7e3822238ad..9c48e18d4aeb 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -33,6 +33,7 @@ #include #include #include +#include /* * per-CPU TSS segments. Threads are completely 'soft' on Linux, @@ -202,6 +203,24 @@ static inline void switch_to_bitmap(struct tss_struct *tss, } } +static __always_inline void __speculative_store_bypass_update(unsigned long tifn) +{ + u64 msr; + + if (static_cpu_has(X86_FEATURE_AMD_RDS)) { + msr = x86_amd_ls_cfg_base | rds_tif_to_amd_ls_cfg(tifn); + wrmsrl(MSR_AMD64_LS_CFG, msr); + } else { + msr = x86_spec_ctrl_base | rds_tif_to_spec_ctrl(tifn); + wrmsrl(MSR_IA32_SPEC_CTRL, msr); + } +} + +void speculative_store_bypass_update(void) +{ + __speculative_store_bypass_update(current_thread_info()->flags); +} + void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, struct tss_struct *tss) { @@ -230,6 +249,9 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, if ((tifp ^ tifn) & _TIF_NOTSC) cr4_toggle_bits(X86_CR4_TSD); + + if ((tifp ^ tifn) & _TIF_RDS) + __speculative_store_bypass_update(tifn); } /* -- GitLab From a078e3e81964c31079627dd32c3ea714d5b1531e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 29 Apr 2018 15:26:40 +0200 Subject: [PATCH 390/855] x86/speculation: Add prctl for Speculative Store Bypass mitigation commit a73ec77ee17ec556fe7f165d00314cb7c047b1ac upstream Add prctl based control for Speculative Store Bypass mitigation and make it the default mitigation for Intel and AMD. Andi Kleen provided the following rationale (slightly redacted): There are multiple levels of impact of Speculative Store Bypass: 1) JITed sandbox. It cannot invoke system calls, but can do PRIME+PROBE and may have call interfaces to other code 2) Native code process. No protection inside the process at this level. 3) Kernel. 4) Between processes. The prctl tries to protect against case (1) doing attacks. If the untrusted code can do random system calls then control is already lost in a much worse way. So there needs to be system call protection in some way (using a JIT not allowing them or seccomp). Or rather if the process can subvert its environment somehow to do the prctl it can already execute arbitrary code, which is much worse than SSB. To put it differently, the point of the prctl is to not allow JITed code to read data it shouldn't read from its JITed sandbox. If it already has escaped its sandbox then it can already read everything it wants in its address space, and do much worse. The ability to control Speculative Store Bypass allows to enable the protection selectively without affecting overall system performance. Based on an initial patch from Tim Chen. Completely rewritten. Signed-off-by: Thomas Gleixner Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 6 +- arch/x86/include/asm/nospec-branch.h | 1 + arch/x86/kernel/cpu/bugs.c | 83 ++++++++++++++++++++++++---- 3 files changed, 79 insertions(+), 11 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 792ac917411a..543923b35260 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -4001,7 +4001,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. off - Unconditionally enable Speculative Store Bypass auto - Kernel detects whether the CPU model contains an implementation of Speculative Store Bypass and - picks the most appropriate mitigation + picks the most appropriate mitigation. + prctl - Control Speculative Store Bypass per thread + via prctl. Speculative Store Bypass is enabled + for a process by default. The state of the control + is inherited on fork. Not specifying this option is equivalent to spec_store_bypass_disable=auto. diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 1119f14bc883..71ad01422655 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -232,6 +232,7 @@ extern u64 x86_spec_ctrl_get_default(void); enum ssb_mitigation { SPEC_STORE_BYPASS_NONE, SPEC_STORE_BYPASS_DISABLE, + SPEC_STORE_BYPASS_PRCTL, }; extern char __indirect_thunk_start[]; diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 4f0957600076..b7d9adf22585 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -411,20 +413,23 @@ enum ssb_mitigation_cmd { SPEC_STORE_BYPASS_CMD_NONE, SPEC_STORE_BYPASS_CMD_AUTO, SPEC_STORE_BYPASS_CMD_ON, + SPEC_STORE_BYPASS_CMD_PRCTL, }; static const char *ssb_strings[] = { [SPEC_STORE_BYPASS_NONE] = "Vulnerable", - [SPEC_STORE_BYPASS_DISABLE] = "Mitigation: Speculative Store Bypass disabled" + [SPEC_STORE_BYPASS_DISABLE] = "Mitigation: Speculative Store Bypass disabled", + [SPEC_STORE_BYPASS_PRCTL] = "Mitigation: Speculative Store Bypass disabled via prctl" }; static const struct { const char *option; enum ssb_mitigation_cmd cmd; } ssb_mitigation_options[] = { - { "auto", SPEC_STORE_BYPASS_CMD_AUTO }, /* Platform decides */ - { "on", SPEC_STORE_BYPASS_CMD_ON }, /* Disable Speculative Store Bypass */ - { "off", SPEC_STORE_BYPASS_CMD_NONE }, /* Don't touch Speculative Store Bypass */ + { "auto", SPEC_STORE_BYPASS_CMD_AUTO }, /* Platform decides */ + { "on", SPEC_STORE_BYPASS_CMD_ON }, /* Disable Speculative Store Bypass */ + { "off", SPEC_STORE_BYPASS_CMD_NONE }, /* Don't touch Speculative Store Bypass */ + { "prctl", SPEC_STORE_BYPASS_CMD_PRCTL }, /* Disable Speculative Store Bypass via prctl */ }; static enum ssb_mitigation_cmd __init ssb_parse_cmdline(void) @@ -474,14 +479,15 @@ static enum ssb_mitigation_cmd __init __ssb_select_mitigation(void) switch (cmd) { case SPEC_STORE_BYPASS_CMD_AUTO: - /* - * AMD platforms by default don't need SSB mitigation. - */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) - break; + /* Choose prctl as the default mode */ + mode = SPEC_STORE_BYPASS_PRCTL; + break; case SPEC_STORE_BYPASS_CMD_ON: mode = SPEC_STORE_BYPASS_DISABLE; break; + case SPEC_STORE_BYPASS_CMD_PRCTL: + mode = SPEC_STORE_BYPASS_PRCTL; + break; case SPEC_STORE_BYPASS_CMD_NONE: break; } @@ -492,7 +498,7 @@ static enum ssb_mitigation_cmd __init __ssb_select_mitigation(void) * - X86_FEATURE_RDS - CPU is able to turn off speculative store bypass * - X86_FEATURE_SPEC_STORE_BYPASS_DISABLE - engage the mitigation */ - if (mode != SPEC_STORE_BYPASS_NONE) { + if (mode == SPEC_STORE_BYPASS_DISABLE) { setup_force_cpu_cap(X86_FEATURE_SPEC_STORE_BYPASS_DISABLE); /* * Intel uses the SPEC CTRL MSR Bit(2) for this, while AMD uses @@ -523,6 +529,63 @@ static void ssb_select_mitigation() #undef pr_fmt +static int ssb_prctl_set(unsigned long ctrl) +{ + bool rds = !!test_tsk_thread_flag(current, TIF_RDS); + + if (ssb_mode != SPEC_STORE_BYPASS_PRCTL) + return -ENXIO; + + if (ctrl == PR_SPEC_ENABLE) + clear_tsk_thread_flag(current, TIF_RDS); + else + set_tsk_thread_flag(current, TIF_RDS); + + if (rds != !!test_tsk_thread_flag(current, TIF_RDS)) + speculative_store_bypass_update(); + + return 0; +} + +static int ssb_prctl_get(void) +{ + switch (ssb_mode) { + case SPEC_STORE_BYPASS_DISABLE: + return PR_SPEC_DISABLE; + case SPEC_STORE_BYPASS_PRCTL: + if (test_tsk_thread_flag(current, TIF_RDS)) + return PR_SPEC_PRCTL | PR_SPEC_DISABLE; + return PR_SPEC_PRCTL | PR_SPEC_ENABLE; + default: + if (boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS)) + return PR_SPEC_ENABLE; + return PR_SPEC_NOT_AFFECTED; + } +} + +int arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl) +{ + if (ctrl != PR_SPEC_ENABLE && ctrl != PR_SPEC_DISABLE) + return -ERANGE; + + switch (which) { + case PR_SPEC_STORE_BYPASS: + return ssb_prctl_set(ctrl); + default: + return -ENODEV; + } +} + +int arch_prctl_spec_ctrl_get(unsigned long which) +{ + switch (which) { + case PR_SPEC_STORE_BYPASS: + return ssb_prctl_get(); + default: + return -ENODEV; + } +} + void x86_spec_ctrl_setup_ap(void) { if (boot_cpu_has(X86_FEATURE_IBRS)) -- GitLab From 4272f528da381673a8e7845c93daa88b8aa4f4e9 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 1 May 2018 15:19:04 -0700 Subject: [PATCH 391/855] nospec: Allow getting/setting on non-current task commit 7bbf1373e228840bb0295a2ca26d548ef37f448e upstream Adjust arch_prctl_get/set_spec_ctrl() to operate on tasks other than current. This is needed both for /proc/$pid/status queries and for seccomp (since thread-syncing can trigger seccomp in non-current threads). Signed-off-by: Kees Cook Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/bugs.c | 27 ++++++++++++++++----------- include/linux/nospec.h | 7 +++++-- kernel/sys.c | 9 +++++---- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index b7d9adf22585..3760931cd40a 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -529,31 +529,35 @@ static void ssb_select_mitigation() #undef pr_fmt -static int ssb_prctl_set(unsigned long ctrl) +static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl) { - bool rds = !!test_tsk_thread_flag(current, TIF_RDS); + bool rds = !!test_tsk_thread_flag(task, TIF_RDS); if (ssb_mode != SPEC_STORE_BYPASS_PRCTL) return -ENXIO; if (ctrl == PR_SPEC_ENABLE) - clear_tsk_thread_flag(current, TIF_RDS); + clear_tsk_thread_flag(task, TIF_RDS); else - set_tsk_thread_flag(current, TIF_RDS); + set_tsk_thread_flag(task, TIF_RDS); - if (rds != !!test_tsk_thread_flag(current, TIF_RDS)) + /* + * If being set on non-current task, delay setting the CPU + * mitigation until it is next scheduled. + */ + if (task == current && rds != !!test_tsk_thread_flag(task, TIF_RDS)) speculative_store_bypass_update(); return 0; } -static int ssb_prctl_get(void) +static int ssb_prctl_get(struct task_struct *task) { switch (ssb_mode) { case SPEC_STORE_BYPASS_DISABLE: return PR_SPEC_DISABLE; case SPEC_STORE_BYPASS_PRCTL: - if (test_tsk_thread_flag(current, TIF_RDS)) + if (test_tsk_thread_flag(task, TIF_RDS)) return PR_SPEC_PRCTL | PR_SPEC_DISABLE; return PR_SPEC_PRCTL | PR_SPEC_ENABLE; default: @@ -563,24 +567,25 @@ static int ssb_prctl_get(void) } } -int arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl) +int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, + unsigned long ctrl) { if (ctrl != PR_SPEC_ENABLE && ctrl != PR_SPEC_DISABLE) return -ERANGE; switch (which) { case PR_SPEC_STORE_BYPASS: - return ssb_prctl_set(ctrl); + return ssb_prctl_set(task, ctrl); default: return -ENODEV; } } -int arch_prctl_spec_ctrl_get(unsigned long which) +int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which) { switch (which) { case PR_SPEC_STORE_BYPASS: - return ssb_prctl_get(); + return ssb_prctl_get(task); default: return -ENODEV; } diff --git a/include/linux/nospec.h b/include/linux/nospec.h index 700bb8a4e4ea..a908c954484d 100644 --- a/include/linux/nospec.h +++ b/include/linux/nospec.h @@ -7,6 +7,8 @@ #define _LINUX_NOSPEC_H #include +struct task_struct; + /** * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise * @index: array element index @@ -57,7 +59,8 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, }) /* Speculation control prctl */ -int arch_prctl_spec_ctrl_get(unsigned long which); -int arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl); +int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which); +int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, + unsigned long ctrl); #endif /* _LINUX_NOSPEC_H */ diff --git a/kernel/sys.c b/kernel/sys.c index 312c985c4643..143cd63f1d47 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2074,12 +2074,13 @@ static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr) } #endif -int __weak arch_prctl_spec_ctrl_get(unsigned long which) +int __weak arch_prctl_spec_ctrl_get(struct task_struct *t, unsigned long which) { return -EINVAL; } -int __weak arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl) +int __weak arch_prctl_spec_ctrl_set(struct task_struct *t, unsigned long which, + unsigned long ctrl) { return -EINVAL; } @@ -2285,12 +2286,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, case PR_GET_SPECULATION_CTRL: if (arg3 || arg4 || arg5) return -EINVAL; - error = arch_prctl_spec_ctrl_get(arg2); + error = arch_prctl_spec_ctrl_get(me, arg2); break; case PR_SET_SPECULATION_CTRL: if (arg4 || arg5) return -EINVAL; - error = arch_prctl_spec_ctrl_set(arg2, arg3); + error = arch_prctl_spec_ctrl_set(me, arg2, arg3); break; default: error = -EINVAL; -- GitLab From 51ef9af2a35bbc21334c801fd15cbfe01210760f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 1 May 2018 15:31:45 -0700 Subject: [PATCH 392/855] proc: Provide details on speculation flaw mitigations commit fae1fa0fc6cca8beee3ab8ed71d54f9a78fa3f64 upstream As done with seccomp and no_new_privs, also show speculation flaw mitigation state in /proc/$pid/status. Signed-off-by: Kees Cook Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- fs/proc/array.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/fs/proc/array.c b/fs/proc/array.c index 794b52a6c20d..64f3f2084f07 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #include #include @@ -345,8 +346,29 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p) { #ifdef CONFIG_SECCOMP seq_put_decimal_ull(m, "Seccomp:\t", p->seccomp.mode); - seq_putc(m, '\n'); #endif + seq_printf(m, "\nSpeculation Store Bypass:\t"); + switch (arch_prctl_spec_ctrl_get(p, PR_SPEC_STORE_BYPASS)) { + case -EINVAL: + seq_printf(m, "unknown"); + break; + case PR_SPEC_NOT_AFFECTED: + seq_printf(m, "not vulnerable"); + break; + case PR_SPEC_PRCTL | PR_SPEC_DISABLE: + seq_printf(m, "thread mitigated"); + break; + case PR_SPEC_PRCTL | PR_SPEC_ENABLE: + seq_printf(m, "thread vulnerable"); + break; + case PR_SPEC_DISABLE: + seq_printf(m, "globally mitigated"); + break; + default: + seq_printf(m, "vulnerable"); + break; + } + seq_putc(m, '\n'); } static inline void task_context_switch_counts(struct seq_file *m, -- GitLab From 0a112f104548667f5618477ff0f2a54ee626addd Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 1 May 2018 15:07:31 -0700 Subject: [PATCH 393/855] seccomp: Enable speculation flaw mitigations commit 5c3070890d06ff82eecb808d02d2ca39169533ef upstream When speculation flaw mitigations are opt-in (via prctl), using seccomp will automatically opt-in to these protections, since using seccomp indicates at least some level of sandboxing is desired. Signed-off-by: Kees Cook Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- kernel/seccomp.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index af182a6df25b..1d3078b45a70 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -214,6 +216,19 @@ static inline bool seccomp_may_assign_mode(unsigned long seccomp_mode) return true; } +/* + * If a given speculation mitigation is opt-in (prctl()-controlled), + * select it, by disabling speculation (enabling mitigation). + */ +static inline void spec_mitigate(struct task_struct *task, + unsigned long which) +{ + int state = arch_prctl_spec_ctrl_get(task, which); + + if (state > 0 && (state & PR_SPEC_PRCTL)) + arch_prctl_spec_ctrl_set(task, which, PR_SPEC_DISABLE); +} + static inline void seccomp_assign_mode(struct task_struct *task, unsigned long seccomp_mode) { @@ -225,6 +240,8 @@ static inline void seccomp_assign_mode(struct task_struct *task, * filter) is set. */ smp_mb__before_atomic(); + /* Assume seccomp processes want speculation flaw mitigation. */ + spec_mitigate(task, PR_SPEC_STORE_BYPASS); set_tsk_thread_flag(task, TIF_SECCOMP); } -- GitLab From ea055f7d43fb3a9d56e80d0116104555d6dde3f7 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 3 May 2018 15:03:30 -0700 Subject: [PATCH 394/855] x86/bugs: Make boot modes __ro_after_init commit f9544b2b076ca90d887c5ae5d74fab4c21bb7c13 upstream There's no reason for these to be changed after boot. Signed-off-by: Kees Cook Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/bugs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 3760931cd40a..65114d2edea8 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -128,7 +128,8 @@ static const char *spectre_v2_strings[] = { #undef pr_fmt #define pr_fmt(fmt) "Spectre V2 : " fmt -static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE; +static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init = + SPECTRE_V2_NONE; void x86_spec_ctrl_set(u64 val) { @@ -406,7 +407,7 @@ static void __init spectre_v2_select_mitigation(void) #undef pr_fmt #define pr_fmt(fmt) "Speculative Store Bypass: " fmt -static enum ssb_mitigation ssb_mode = SPEC_STORE_BYPASS_NONE; +static enum ssb_mitigation ssb_mode __ro_after_init = SPEC_STORE_BYPASS_NONE; /* The kernel command line selection */ enum ssb_mitigation_cmd { -- GitLab From 036608d62a838aeb63cae0adaf8ac773cb53148c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 3 May 2018 22:09:15 +0200 Subject: [PATCH 395/855] prctl: Add force disable speculation commit 356e4bfff2c5489e016fdb925adbf12a1e3950ee upstream For certain use cases it is desired to enforce mitigations so they cannot be undone afterwards. That's important for loader stubs which want to prevent a child from disabling the mitigation again. Will also be used for seccomp(). The extra state preserving of the prctl state for SSB is a preparatory step for EBPF dymanic speculation control. Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- Documentation/spec_ctrl.txt | 34 +++++++++++++++++++++------------- arch/x86/kernel/cpu/bugs.c | 35 +++++++++++++++++++++++++---------- fs/proc/array.c | 3 +++ include/linux/sched.h | 9 +++++++++ include/uapi/linux/prctl.h | 1 + 5 files changed, 59 insertions(+), 23 deletions(-) diff --git a/Documentation/spec_ctrl.txt b/Documentation/spec_ctrl.txt index ddbebcd01208..1b3690d30943 100644 --- a/Documentation/spec_ctrl.txt +++ b/Documentation/spec_ctrl.txt @@ -25,19 +25,21 @@ PR_GET_SPECULATION_CTRL ----------------------- PR_GET_SPECULATION_CTRL returns the state of the speculation misfeature -which is selected with arg2 of prctl(2). The return value uses bits 0-2 with +which is selected with arg2 of prctl(2). The return value uses bits 0-3 with the following meaning: -==== ================ =================================================== -Bit Define Description -==== ================ =================================================== -0 PR_SPEC_PRCTL Mitigation can be controlled per task by - PR_SET_SPECULATION_CTRL -1 PR_SPEC_ENABLE The speculation feature is enabled, mitigation is - disabled -2 PR_SPEC_DISABLE The speculation feature is disabled, mitigation is - enabled -==== ================ =================================================== +==== ===================== =================================================== +Bit Define Description +==== ===================== =================================================== +0 PR_SPEC_PRCTL Mitigation can be controlled per task by + PR_SET_SPECULATION_CTRL +1 PR_SPEC_ENABLE The speculation feature is enabled, mitigation is + disabled +2 PR_SPEC_DISABLE The speculation feature is disabled, mitigation is + enabled +3 PR_SPEC_FORCE_DISABLE Same as PR_SPEC_DISABLE, but cannot be undone. A + subsequent prctl(..., PR_SPEC_ENABLE) will fail. +==== ===================== =================================================== If all bits are 0 the CPU is not affected by the speculation misfeature. @@ -47,9 +49,11 @@ misfeature will fail. PR_SET_SPECULATION_CTRL ----------------------- + PR_SET_SPECULATION_CTRL allows to control the speculation misfeature, which is selected by arg2 of :manpage:`prctl(2)` per task. arg3 is used to hand -in the control value, i.e. either PR_SPEC_ENABLE or PR_SPEC_DISABLE. +in the control value, i.e. either PR_SPEC_ENABLE or PR_SPEC_DISABLE or +PR_SPEC_FORCE_DISABLE. Common error codes ------------------ @@ -70,10 +74,13 @@ Value Meaning 0 Success ERANGE arg3 is incorrect, i.e. it's neither PR_SPEC_ENABLE nor - PR_SPEC_DISABLE + PR_SPEC_DISABLE nor PR_SPEC_FORCE_DISABLE ENXIO Control of the selected speculation misfeature is not possible. See PR_GET_SPECULATION_CTRL. + +EPERM Speculation was disabled with PR_SPEC_FORCE_DISABLE and caller + tried to enable it again. ======= ================================================================= Speculation misfeature controls @@ -84,3 +91,4 @@ Speculation misfeature controls * prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, 0, 0, 0); * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_ENABLE, 0, 0); * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_DISABLE, 0, 0); + * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_FORCE_DISABLE, 0, 0); diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 65114d2edea8..fdbd8e54c549 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -532,21 +532,37 @@ static void ssb_select_mitigation() static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl) { - bool rds = !!test_tsk_thread_flag(task, TIF_RDS); + bool update; if (ssb_mode != SPEC_STORE_BYPASS_PRCTL) return -ENXIO; - if (ctrl == PR_SPEC_ENABLE) - clear_tsk_thread_flag(task, TIF_RDS); - else - set_tsk_thread_flag(task, TIF_RDS); + switch (ctrl) { + case PR_SPEC_ENABLE: + /* If speculation is force disabled, enable is not allowed */ + if (task_spec_ssb_force_disable(task)) + return -EPERM; + task_clear_spec_ssb_disable(task); + update = test_and_clear_tsk_thread_flag(task, TIF_RDS); + break; + case PR_SPEC_DISABLE: + task_set_spec_ssb_disable(task); + update = !test_and_set_tsk_thread_flag(task, TIF_RDS); + break; + case PR_SPEC_FORCE_DISABLE: + task_set_spec_ssb_disable(task); + task_set_spec_ssb_force_disable(task); + update = !test_and_set_tsk_thread_flag(task, TIF_RDS); + break; + default: + return -ERANGE; + } /* * If being set on non-current task, delay setting the CPU * mitigation until it is next scheduled. */ - if (task == current && rds != !!test_tsk_thread_flag(task, TIF_RDS)) + if (task == current && update) speculative_store_bypass_update(); return 0; @@ -558,7 +574,9 @@ static int ssb_prctl_get(struct task_struct *task) case SPEC_STORE_BYPASS_DISABLE: return PR_SPEC_DISABLE; case SPEC_STORE_BYPASS_PRCTL: - if (test_tsk_thread_flag(task, TIF_RDS)) + if (task_spec_ssb_force_disable(task)) + return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE; + if (task_spec_ssb_disable(task)) return PR_SPEC_PRCTL | PR_SPEC_DISABLE; return PR_SPEC_PRCTL | PR_SPEC_ENABLE; default: @@ -571,9 +589,6 @@ static int ssb_prctl_get(struct task_struct *task) int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, unsigned long ctrl) { - if (ctrl != PR_SPEC_ENABLE && ctrl != PR_SPEC_DISABLE) - return -ERANGE; - switch (which) { case PR_SPEC_STORE_BYPASS: return ssb_prctl_set(task, ctrl); diff --git a/fs/proc/array.c b/fs/proc/array.c index 64f3f2084f07..3e37195485fc 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -355,6 +355,9 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p) case PR_SPEC_NOT_AFFECTED: seq_printf(m, "not vulnerable"); break; + case PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE: + seq_printf(m, "thread force mitigated"); + break; case PR_SPEC_PRCTL | PR_SPEC_DISABLE: seq_printf(m, "thread mitigated"); break; diff --git a/include/linux/sched.h b/include/linux/sched.h index c549c8c9245c..5ebef8c86c26 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2354,6 +2354,8 @@ static inline void memalloc_noio_restore(unsigned int flags) #define PFA_SPREAD_PAGE 1 /* Spread page cache over cpuset */ #define PFA_SPREAD_SLAB 2 /* Spread some slab caches over cpuset */ #define PFA_LMK_WAITING 3 /* Lowmemorykiller is waiting */ +#define PFA_SPEC_SSB_DISABLE 4 /* Speculative Store Bypass disabled */ +#define PFA_SPEC_SSB_FORCE_DISABLE 5 /* Speculative Store Bypass force disabled*/ #define TASK_PFA_TEST(name, func) \ @@ -2380,6 +2382,13 @@ TASK_PFA_CLEAR(SPREAD_SLAB, spread_slab) TASK_PFA_TEST(LMK_WAITING, lmk_waiting) TASK_PFA_SET(LMK_WAITING, lmk_waiting) +TASK_PFA_TEST(SPEC_SSB_DISABLE, spec_ssb_disable) +TASK_PFA_SET(SPEC_SSB_DISABLE, spec_ssb_disable) +TASK_PFA_CLEAR(SPEC_SSB_DISABLE, spec_ssb_disable) + +TASK_PFA_TEST(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable) +TASK_PFA_SET(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable) + /* * task->jobctl flags */ diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index 3b316be71c56..64776b72e1eb 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -207,5 +207,6 @@ struct prctl_mm_map { # define PR_SPEC_PRCTL (1UL << 0) # define PR_SPEC_ENABLE (1UL << 1) # define PR_SPEC_DISABLE (1UL << 2) +# define PR_SPEC_FORCE_DISABLE (1UL << 3) #endif /* _LINUX_PRCTL_H */ -- GitLab From c71def81cd07e1bd74da468ae6abe1ce62e3157b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 4 May 2018 09:40:03 +0200 Subject: [PATCH 396/855] seccomp: Use PR_SPEC_FORCE_DISABLE commit b849a812f7eb92e96d1c8239b06581b2cfd8b275 upstream Use PR_SPEC_FORCE_DISABLE in seccomp() because seccomp does not allow to widen restrictions. Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- kernel/seccomp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 1d3078b45a70..a0bd6ea1ff90 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -226,7 +226,7 @@ static inline void spec_mitigate(struct task_struct *task, int state = arch_prctl_spec_ctrl_get(task, which); if (state > 0 && (state & PR_SPEC_PRCTL)) - arch_prctl_spec_ctrl_set(task, which, PR_SPEC_DISABLE); + arch_prctl_spec_ctrl_set(task, which, PR_SPEC_FORCE_DISABLE); } static inline void seccomp_assign_mode(struct task_struct *task, -- GitLab From ab677c2addbb128f334c4906f27a0285a67d2180 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 3 May 2018 14:56:12 -0700 Subject: [PATCH 397/855] seccomp: Add filter flag to opt-out of SSB mitigation commit 00a02d0c502a06d15e07b857f8ff921e3e402675 upstream If a seccomp user is not interested in Speculative Store Bypass mitigation by default, it can set the new SECCOMP_FILTER_FLAG_SPEC_ALLOW flag when adding filters. Signed-off-by: Kees Cook Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- include/linux/seccomp.h | 3 +- include/uapi/linux/seccomp.h | 4 +- kernel/seccomp.c | 19 +++-- tools/testing/selftests/seccomp/seccomp_bpf.c | 78 ++++++++++++++++++- 4 files changed, 93 insertions(+), 11 deletions(-) diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index ecc296c137cd..50c460a956f1 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -3,7 +3,8 @@ #include -#define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC) +#define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC | \ + SECCOMP_FILTER_FLAG_SPEC_ALLOW) #ifdef CONFIG_SECCOMP diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h index 0f238a43ff1e..e4acb615792b 100644 --- a/include/uapi/linux/seccomp.h +++ b/include/uapi/linux/seccomp.h @@ -15,7 +15,9 @@ #define SECCOMP_SET_MODE_FILTER 1 /* Valid flags for SECCOMP_SET_MODE_FILTER */ -#define SECCOMP_FILTER_FLAG_TSYNC 1 +#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0) +/* In v4.14+ SECCOMP_FILTER_FLAG_LOG is (1UL << 1) */ +#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2) /* * All BPF programs must return a 32-bit value. diff --git a/kernel/seccomp.c b/kernel/seccomp.c index a0bd6ea1ff90..62a60e7454a9 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -230,7 +230,8 @@ static inline void spec_mitigate(struct task_struct *task, } static inline void seccomp_assign_mode(struct task_struct *task, - unsigned long seccomp_mode) + unsigned long seccomp_mode, + unsigned long flags) { assert_spin_locked(&task->sighand->siglock); @@ -240,8 +241,9 @@ static inline void seccomp_assign_mode(struct task_struct *task, * filter) is set. */ smp_mb__before_atomic(); - /* Assume seccomp processes want speculation flaw mitigation. */ - spec_mitigate(task, PR_SPEC_STORE_BYPASS); + /* Assume default seccomp processes want spec flaw mitigation. */ + if ((flags & SECCOMP_FILTER_FLAG_SPEC_ALLOW) == 0) + spec_mitigate(task, PR_SPEC_STORE_BYPASS); set_tsk_thread_flag(task, TIF_SECCOMP); } @@ -309,7 +311,7 @@ static inline pid_t seccomp_can_sync_threads(void) * without dropping the locks. * */ -static inline void seccomp_sync_threads(void) +static inline void seccomp_sync_threads(unsigned long flags) { struct task_struct *thread, *caller; @@ -350,7 +352,8 @@ static inline void seccomp_sync_threads(void) * allow one thread to transition the other. */ if (thread->seccomp.mode == SECCOMP_MODE_DISABLED) - seccomp_assign_mode(thread, SECCOMP_MODE_FILTER); + seccomp_assign_mode(thread, SECCOMP_MODE_FILTER, + flags); } } @@ -469,7 +472,7 @@ static long seccomp_attach_filter(unsigned int flags, /* Now that the new filter is in place, synchronize to all threads. */ if (flags & SECCOMP_FILTER_FLAG_TSYNC) - seccomp_sync_threads(); + seccomp_sync_threads(flags); return 0; } @@ -729,7 +732,7 @@ static long seccomp_set_mode_strict(void) #ifdef TIF_NOTSC disable_TSC(); #endif - seccomp_assign_mode(current, seccomp_mode); + seccomp_assign_mode(current, seccomp_mode, 0); ret = 0; out: @@ -787,7 +790,7 @@ static long seccomp_set_mode_filter(unsigned int flags, /* Do not free the successfully attached filter. */ prepared = NULL; - seccomp_assign_mode(current, seccomp_mode); + seccomp_assign_mode(current, seccomp_mode, flags); out: spin_unlock_irq(¤t->sighand->siglock); if (flags & SECCOMP_FILTER_FLAG_TSYNC) diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index f68998149351..d5be7b5ff899 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -1692,7 +1692,11 @@ TEST_F_SIGNAL(TRACE_syscall, kill_after_ptrace, SIGSYS) #endif #ifndef SECCOMP_FILTER_FLAG_TSYNC -#define SECCOMP_FILTER_FLAG_TSYNC 1 +#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0) +#endif + +#ifndef SECCOMP_FILTER_FLAG_SPEC_ALLOW +#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2) #endif #ifndef seccomp @@ -1791,6 +1795,78 @@ TEST(seccomp_syscall_mode_lock) } } +/* + * Test detection of known and unknown filter flags. Userspace needs to be able + * to check if a filter flag is supported by the current kernel and a good way + * of doing that is by attempting to enter filter mode, with the flag bit in + * question set, and a NULL pointer for the _args_ parameter. EFAULT indicates + * that the flag is valid and EINVAL indicates that the flag is invalid. + */ +TEST(detect_seccomp_filter_flags) +{ + unsigned int flags[] = { SECCOMP_FILTER_FLAG_TSYNC, + SECCOMP_FILTER_FLAG_SPEC_ALLOW }; + unsigned int flag, all_flags; + int i; + long ret; + + /* Test detection of known-good filter flags */ + for (i = 0, all_flags = 0; i < ARRAY_SIZE(flags); i++) { + int bits = 0; + + flag = flags[i]; + /* Make sure the flag is a single bit! */ + while (flag) { + if (flag & 0x1) + bits ++; + flag >>= 1; + } + ASSERT_EQ(1, bits); + flag = flags[i]; + + ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL); + ASSERT_NE(ENOSYS, errno) { + TH_LOG("Kernel does not support seccomp syscall!"); + } + EXPECT_EQ(-1, ret); + EXPECT_EQ(EFAULT, errno) { + TH_LOG("Failed to detect that a known-good filter flag (0x%X) is supported!", + flag); + } + + all_flags |= flag; + } + + /* Test detection of all known-good filter flags */ + ret = seccomp(SECCOMP_SET_MODE_FILTER, all_flags, NULL); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EFAULT, errno) { + TH_LOG("Failed to detect that all known-good filter flags (0x%X) are supported!", + all_flags); + } + + /* Test detection of an unknown filter flag */ + flag = -1; + ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno) { + TH_LOG("Failed to detect that an unknown filter flag (0x%X) is unsupported!", + flag); + } + + /* + * Test detection of an unknown filter flag that may simply need to be + * added to this test + */ + flag = flags[ARRAY_SIZE(flags) - 1] << 1; + ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno) { + TH_LOG("Failed to detect that an unknown filter flag (0x%X) is unsupported! Does a new flag need to be added to this test?", + flag); + } +} + TEST(TSYNC_first) { struct sock_filter filter[] = { -- GitLab From 094c2767c4f02c36eabc27309d78b04f4a216e88 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 4 May 2018 15:12:06 +0200 Subject: [PATCH 398/855] seccomp: Move speculation migitation control to arch code commit 8bf37d8c067bb7eb8e7c381bdadf9bd89182b6bc upstream The migitation control is simpler to implement in architecture code as it avoids the extra function call to check the mode. Aside of that having an explicit seccomp enabled mode in the architecture mitigations would require even more workarounds. Move it into architecture code and provide a weak function in the seccomp code. Remove the 'which' argument as this allows the architecture to decide which mitigations are relevant for seccomp. Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/bugs.c | 29 ++++++++++++++++++----------- include/linux/nospec.h | 2 ++ kernel/seccomp.c | 15 ++------------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index fdbd8e54c549..131617dffe21 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -568,6 +568,24 @@ static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl) return 0; } +int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, + unsigned long ctrl) +{ + switch (which) { + case PR_SPEC_STORE_BYPASS: + return ssb_prctl_set(task, ctrl); + default: + return -ENODEV; + } +} + +#ifdef CONFIG_SECCOMP +void arch_seccomp_spec_mitigate(struct task_struct *task) +{ + ssb_prctl_set(task, PR_SPEC_FORCE_DISABLE); +} +#endif + static int ssb_prctl_get(struct task_struct *task) { switch (ssb_mode) { @@ -586,17 +604,6 @@ static int ssb_prctl_get(struct task_struct *task) } } -int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, - unsigned long ctrl) -{ - switch (which) { - case PR_SPEC_STORE_BYPASS: - return ssb_prctl_set(task, ctrl); - default: - return -ENODEV; - } -} - int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which) { switch (which) { diff --git a/include/linux/nospec.h b/include/linux/nospec.h index a908c954484d..0c5ef54fd416 100644 --- a/include/linux/nospec.h +++ b/include/linux/nospec.h @@ -62,5 +62,7 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which); int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, unsigned long ctrl); +/* Speculation control for seccomp enforced mitigation */ +void arch_seccomp_spec_mitigate(struct task_struct *task); #endif /* _LINUX_NOSPEC_H */ diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 62a60e7454a9..3975856d476c 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -216,18 +216,7 @@ static inline bool seccomp_may_assign_mode(unsigned long seccomp_mode) return true; } -/* - * If a given speculation mitigation is opt-in (prctl()-controlled), - * select it, by disabling speculation (enabling mitigation). - */ -static inline void spec_mitigate(struct task_struct *task, - unsigned long which) -{ - int state = arch_prctl_spec_ctrl_get(task, which); - - if (state > 0 && (state & PR_SPEC_PRCTL)) - arch_prctl_spec_ctrl_set(task, which, PR_SPEC_FORCE_DISABLE); -} +void __weak arch_seccomp_spec_mitigate(struct task_struct *task) { } static inline void seccomp_assign_mode(struct task_struct *task, unsigned long seccomp_mode, @@ -243,7 +232,7 @@ static inline void seccomp_assign_mode(struct task_struct *task, smp_mb__before_atomic(); /* Assume default seccomp processes want spec flaw mitigation. */ if ((flags & SECCOMP_FILTER_FLAG_SPEC_ALLOW) == 0) - spec_mitigate(task, PR_SPEC_STORE_BYPASS); + arch_seccomp_spec_mitigate(task); set_tsk_thread_flag(task, TIF_SECCOMP); } -- GitLab From 05a85a396f3989e9ac953785d9dccfc7cd0110f2 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 3 May 2018 14:37:54 -0700 Subject: [PATCH 399/855] x86/speculation: Make "seccomp" the default mode for Speculative Store Bypass commit f21b53b20c754021935ea43364dbf53778eeba32 upstream Unless explicitly opted out of, anything running under seccomp will have SSB mitigations enabled. Choosing the "prctl" mode will disable this. [ tglx: Adjusted it to the new arch_seccomp_spec_mitigate() mechanism ] Signed-off-by: Kees Cook Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 26 ++++++++++++++-------- arch/x86/include/asm/nospec-branch.h | 1 + arch/x86/kernel/cpu/bugs.c | 32 ++++++++++++++++++++-------- 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 543923b35260..52240a63132e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3997,19 +3997,27 @@ bytes respectively. Such letter suffixes can also be entirely omitted. This parameter controls whether the Speculative Store Bypass optimization is used. - on - Unconditionally disable Speculative Store Bypass - off - Unconditionally enable Speculative Store Bypass - auto - Kernel detects whether the CPU model contains an - implementation of Speculative Store Bypass and - picks the most appropriate mitigation. - prctl - Control Speculative Store Bypass per thread - via prctl. Speculative Store Bypass is enabled - for a process by default. The state of the control - is inherited on fork. + on - Unconditionally disable Speculative Store Bypass + off - Unconditionally enable Speculative Store Bypass + auto - Kernel detects whether the CPU model contains an + implementation of Speculative Store Bypass and + picks the most appropriate mitigation. If the + CPU is not vulnerable, "off" is selected. If the + CPU is vulnerable the default mitigation is + architecture and Kconfig dependent. See below. + prctl - Control Speculative Store Bypass per thread + via prctl. Speculative Store Bypass is enabled + for a process by default. The state of the control + is inherited on fork. + seccomp - Same as "prctl" above, but all seccomp threads + will disable SSB unless they explicitly opt out. Not specifying this option is equivalent to spec_store_bypass_disable=auto. + Default mitigations: + X86: If CONFIG_SECCOMP=y "seccomp", otherwise "prctl" + spia_io_base= [HW,MTD] spia_fio_base= spia_pedr= diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 71ad01422655..328ea3cb769f 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -233,6 +233,7 @@ enum ssb_mitigation { SPEC_STORE_BYPASS_NONE, SPEC_STORE_BYPASS_DISABLE, SPEC_STORE_BYPASS_PRCTL, + SPEC_STORE_BYPASS_SECCOMP, }; extern char __indirect_thunk_start[]; diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 131617dffe21..9a3bb658d6dc 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -415,22 +415,25 @@ enum ssb_mitigation_cmd { SPEC_STORE_BYPASS_CMD_AUTO, SPEC_STORE_BYPASS_CMD_ON, SPEC_STORE_BYPASS_CMD_PRCTL, + SPEC_STORE_BYPASS_CMD_SECCOMP, }; static const char *ssb_strings[] = { [SPEC_STORE_BYPASS_NONE] = "Vulnerable", [SPEC_STORE_BYPASS_DISABLE] = "Mitigation: Speculative Store Bypass disabled", - [SPEC_STORE_BYPASS_PRCTL] = "Mitigation: Speculative Store Bypass disabled via prctl" + [SPEC_STORE_BYPASS_PRCTL] = "Mitigation: Speculative Store Bypass disabled via prctl", + [SPEC_STORE_BYPASS_SECCOMP] = "Mitigation: Speculative Store Bypass disabled via prctl and seccomp", }; static const struct { const char *option; enum ssb_mitigation_cmd cmd; } ssb_mitigation_options[] = { - { "auto", SPEC_STORE_BYPASS_CMD_AUTO }, /* Platform decides */ - { "on", SPEC_STORE_BYPASS_CMD_ON }, /* Disable Speculative Store Bypass */ - { "off", SPEC_STORE_BYPASS_CMD_NONE }, /* Don't touch Speculative Store Bypass */ - { "prctl", SPEC_STORE_BYPASS_CMD_PRCTL }, /* Disable Speculative Store Bypass via prctl */ + { "auto", SPEC_STORE_BYPASS_CMD_AUTO }, /* Platform decides */ + { "on", SPEC_STORE_BYPASS_CMD_ON }, /* Disable Speculative Store Bypass */ + { "off", SPEC_STORE_BYPASS_CMD_NONE }, /* Don't touch Speculative Store Bypass */ + { "prctl", SPEC_STORE_BYPASS_CMD_PRCTL }, /* Disable Speculative Store Bypass via prctl */ + { "seccomp", SPEC_STORE_BYPASS_CMD_SECCOMP }, /* Disable Speculative Store Bypass via prctl and seccomp */ }; static enum ssb_mitigation_cmd __init ssb_parse_cmdline(void) @@ -480,8 +483,15 @@ static enum ssb_mitigation_cmd __init __ssb_select_mitigation(void) switch (cmd) { case SPEC_STORE_BYPASS_CMD_AUTO: - /* Choose prctl as the default mode */ - mode = SPEC_STORE_BYPASS_PRCTL; + case SPEC_STORE_BYPASS_CMD_SECCOMP: + /* + * Choose prctl+seccomp as the default mode if seccomp is + * enabled. + */ + if (IS_ENABLED(CONFIG_SECCOMP)) + mode = SPEC_STORE_BYPASS_SECCOMP; + else + mode = SPEC_STORE_BYPASS_PRCTL; break; case SPEC_STORE_BYPASS_CMD_ON: mode = SPEC_STORE_BYPASS_DISABLE; @@ -529,12 +539,14 @@ static void ssb_select_mitigation() } #undef pr_fmt +#define pr_fmt(fmt) "Speculation prctl: " fmt static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl) { bool update; - if (ssb_mode != SPEC_STORE_BYPASS_PRCTL) + if (ssb_mode != SPEC_STORE_BYPASS_PRCTL && + ssb_mode != SPEC_STORE_BYPASS_SECCOMP) return -ENXIO; switch (ctrl) { @@ -582,7 +594,8 @@ int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, #ifdef CONFIG_SECCOMP void arch_seccomp_spec_mitigate(struct task_struct *task) { - ssb_prctl_set(task, PR_SPEC_FORCE_DISABLE); + if (ssb_mode == SPEC_STORE_BYPASS_SECCOMP) + ssb_prctl_set(task, PR_SPEC_FORCE_DISABLE); } #endif @@ -591,6 +604,7 @@ static int ssb_prctl_get(struct task_struct *task) switch (ssb_mode) { case SPEC_STORE_BYPASS_DISABLE: return PR_SPEC_DISABLE; + case SPEC_STORE_BYPASS_SECCOMP: case SPEC_STORE_BYPASS_PRCTL: if (task_spec_ssb_force_disable(task)) return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE; -- GitLab From bf3da841edae882de545d2d19b1fae205cab8d98 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 9 May 2018 21:41:38 +0200 Subject: [PATCH 400/855] x86/bugs: Rename _RDS to _SSBD commit 9f65fb29374ee37856dbad847b4e121aab72b510 upstream Intel collateral will reference the SSB mitigation bit in IA32_SPEC_CTL[2] as SSBD (Speculative Store Bypass Disable). Hence changing it. It is unclear yet what the MSR_IA32_ARCH_CAPABILITIES (0x10a) Bit(4) name is going to be. Following the rename it would be SSBD_NO but that rolls out to Speculative Store Bypass Disable No. Also fixed the missing space in X86_FEATURE_AMD_SSBD. [ tglx: Fixup x86_amd_rds_enable() and rds_tif_to_amd_ls_cfg() as well ] Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/cpufeatures.h | 4 ++-- arch/x86/include/asm/msr-index.h | 10 ++++----- arch/x86/include/asm/spec-ctrl.h | 12 +++++----- arch/x86/include/asm/thread_info.h | 6 ++--- arch/x86/kernel/cpu/amd.c | 14 ++++++------ arch/x86/kernel/cpu/bugs.c | 36 +++++++++++++++--------------- arch/x86/kernel/cpu/common.c | 2 +- arch/x86/kernel/cpu/intel.c | 2 +- arch/x86/kernel/process.c | 8 +++---- arch/x86/kvm/cpuid.c | 2 +- arch/x86/kvm/cpuid.h | 2 +- arch/x86/kvm/vmx.c | 2 +- 12 files changed, 50 insertions(+), 50 deletions(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 87970694cac1..0ed8ea5419c1 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -205,7 +205,7 @@ #define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ #define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ #define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* "" Disable Speculative Store Bypass. */ -#define X86_FEATURE_AMD_RDS (7*32+24) /* "" AMD RDS implementation */ +#define X86_FEATURE_AMD_SSBD (7*32+24) /* "" AMD SSBD implementation */ /* Virtualization flags: Linux defined, word 8 */ #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ @@ -308,7 +308,7 @@ #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ -#define X86_FEATURE_RDS (18*32+31) /* Reduced Data Speculation */ +#define X86_FEATURE_SSBD (18*32+31) /* Speculative Store Bypass Disable */ /* * BUG word(s) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 5dd28d0e9f0e..b67d57eb4d0f 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -40,8 +40,8 @@ #define MSR_IA32_SPEC_CTRL 0x00000048 /* Speculation Control */ #define SPEC_CTRL_IBRS (1 << 0) /* Indirect Branch Restricted Speculation */ #define SPEC_CTRL_STIBP (1 << 1) /* Single Thread Indirect Branch Predictors */ -#define SPEC_CTRL_RDS_SHIFT 2 /* Reduced Data Speculation bit */ -#define SPEC_CTRL_RDS (1 << SPEC_CTRL_RDS_SHIFT) /* Reduced Data Speculation */ +#define SPEC_CTRL_SSBD_SHIFT 2 /* Speculative Store Bypass Disable bit */ +#define SPEC_CTRL_SSBD (1 << SPEC_CTRL_SSBD_SHIFT) /* Speculative Store Bypass Disable */ #define MSR_IA32_PRED_CMD 0x00000049 /* Prediction Command */ #define PRED_CMD_IBPB (1 << 0) /* Indirect Branch Prediction Barrier */ @@ -63,10 +63,10 @@ #define MSR_IA32_ARCH_CAPABILITIES 0x0000010a #define ARCH_CAP_RDCL_NO (1 << 0) /* Not susceptible to Meltdown */ #define ARCH_CAP_IBRS_ALL (1 << 1) /* Enhanced IBRS support */ -#define ARCH_CAP_RDS_NO (1 << 4) /* +#define ARCH_CAP_SSBD_NO (1 << 4) /* * Not susceptible to Speculative Store Bypass - * attack, so no Reduced Data Speculation control - * required. + * attack, so no Speculative Store Bypass + * control required. */ #define MSR_IA32_BBL_CR_CTL 0x00000119 diff --git a/arch/x86/include/asm/spec-ctrl.h b/arch/x86/include/asm/spec-ctrl.h index 45ef00ad5105..dc21209790bf 100644 --- a/arch/x86/include/asm/spec-ctrl.h +++ b/arch/x86/include/asm/spec-ctrl.h @@ -17,20 +17,20 @@ extern void x86_spec_ctrl_restore_host(u64); /* AMD specific Speculative Store Bypass MSR data */ extern u64 x86_amd_ls_cfg_base; -extern u64 x86_amd_ls_cfg_rds_mask; +extern u64 x86_amd_ls_cfg_ssbd_mask; /* The Intel SPEC CTRL MSR base value cache */ extern u64 x86_spec_ctrl_base; -static inline u64 rds_tif_to_spec_ctrl(u64 tifn) +static inline u64 ssbd_tif_to_spec_ctrl(u64 tifn) { - BUILD_BUG_ON(TIF_RDS < SPEC_CTRL_RDS_SHIFT); - return (tifn & _TIF_RDS) >> (TIF_RDS - SPEC_CTRL_RDS_SHIFT); + BUILD_BUG_ON(TIF_SSBD < SPEC_CTRL_SSBD_SHIFT); + return (tifn & _TIF_SSBD) >> (TIF_SSBD - SPEC_CTRL_SSBD_SHIFT); } -static inline u64 rds_tif_to_amd_ls_cfg(u64 tifn) +static inline u64 ssbd_tif_to_amd_ls_cfg(u64 tifn) { - return (tifn & _TIF_RDS) ? x86_amd_ls_cfg_rds_mask : 0ULL; + return (tifn & _TIF_SSBD) ? x86_amd_ls_cfg_ssbd_mask : 0ULL; } extern void speculative_store_bypass_update(void); diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 661afac34502..2d8788a59b4d 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -83,7 +83,7 @@ struct thread_info { #define TIF_SIGPENDING 2 /* signal pending */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/ -#define TIF_RDS 5 /* Reduced data speculation */ +#define TIF_SSBD 5 /* Reduced data speculation */ #define TIF_SYSCALL_EMU 6 /* syscall emulation active */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_SECCOMP 8 /* secure computing */ @@ -107,7 +107,7 @@ struct thread_info { #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) -#define _TIF_RDS (1 << TIF_RDS) +#define _TIF_SSBD (1 << TIF_SSBD) #define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SECCOMP (1 << TIF_SECCOMP) @@ -141,7 +141,7 @@ struct thread_info { /* flags to check in __switch_to() */ #define _TIF_WORK_CTXSW \ - (_TIF_IO_BITMAP|_TIF_NOTSC|_TIF_BLOCKSTEP|_TIF_RDS) + (_TIF_IO_BITMAP|_TIF_NOTSC|_TIF_BLOCKSTEP|_TIF_SSBD) #define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY) #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index a176c81a74b2..acb2fcc510d2 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -555,12 +555,12 @@ static void bsp_init_amd(struct cpuinfo_x86 *c) } /* * Try to cache the base value so further operations can - * avoid RMW. If that faults, do not enable RDS. + * avoid RMW. If that faults, do not enable SSBD. */ if (!rdmsrl_safe(MSR_AMD64_LS_CFG, &x86_amd_ls_cfg_base)) { - setup_force_cpu_cap(X86_FEATURE_RDS); - setup_force_cpu_cap(X86_FEATURE_AMD_RDS); - x86_amd_ls_cfg_rds_mask = 1ULL << bit; + setup_force_cpu_cap(X86_FEATURE_SSBD); + setup_force_cpu_cap(X86_FEATURE_AMD_SSBD); + x86_amd_ls_cfg_ssbd_mask = 1ULL << bit; } } } @@ -849,9 +849,9 @@ static void init_amd(struct cpuinfo_x86 *c) if (!cpu_has(c, X86_FEATURE_XENPV)) set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); - if (boot_cpu_has(X86_FEATURE_AMD_RDS)) { - set_cpu_cap(c, X86_FEATURE_RDS); - set_cpu_cap(c, X86_FEATURE_AMD_RDS); + if (boot_cpu_has(X86_FEATURE_AMD_SSBD)) { + set_cpu_cap(c, X86_FEATURE_SSBD); + set_cpu_cap(c, X86_FEATURE_AMD_SSBD); } } diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 9a3bb658d6dc..ae6f9bae17ce 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -44,10 +44,10 @@ static u64 __ro_after_init x86_spec_ctrl_mask = ~SPEC_CTRL_IBRS; /* * AMD specific MSR info for Speculative Store Bypass control. - * x86_amd_ls_cfg_rds_mask is initialized in identify_boot_cpu(). + * x86_amd_ls_cfg_ssbd_mask is initialized in identify_boot_cpu(). */ u64 __ro_after_init x86_amd_ls_cfg_base; -u64 __ro_after_init x86_amd_ls_cfg_rds_mask; +u64 __ro_after_init x86_amd_ls_cfg_ssbd_mask; void __init check_bugs(void) { @@ -145,7 +145,7 @@ u64 x86_spec_ctrl_get_default(void) u64 msrval = x86_spec_ctrl_base; if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) - msrval |= rds_tif_to_spec_ctrl(current_thread_info()->flags); + msrval |= ssbd_tif_to_spec_ctrl(current_thread_info()->flags); return msrval; } EXPORT_SYMBOL_GPL(x86_spec_ctrl_get_default); @@ -158,7 +158,7 @@ void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl) return; if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) - host |= rds_tif_to_spec_ctrl(current_thread_info()->flags); + host |= ssbd_tif_to_spec_ctrl(current_thread_info()->flags); if (host != guest_spec_ctrl) wrmsrl(MSR_IA32_SPEC_CTRL, guest_spec_ctrl); @@ -173,18 +173,18 @@ void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl) return; if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) - host |= rds_tif_to_spec_ctrl(current_thread_info()->flags); + host |= ssbd_tif_to_spec_ctrl(current_thread_info()->flags); if (host != guest_spec_ctrl) wrmsrl(MSR_IA32_SPEC_CTRL, host); } EXPORT_SYMBOL_GPL(x86_spec_ctrl_restore_host); -static void x86_amd_rds_enable(void) +static void x86_amd_ssb_disable(void) { - u64 msrval = x86_amd_ls_cfg_base | x86_amd_ls_cfg_rds_mask; + u64 msrval = x86_amd_ls_cfg_base | x86_amd_ls_cfg_ssbd_mask; - if (boot_cpu_has(X86_FEATURE_AMD_RDS)) + if (boot_cpu_has(X86_FEATURE_AMD_SSBD)) wrmsrl(MSR_AMD64_LS_CFG, msrval); } @@ -472,7 +472,7 @@ static enum ssb_mitigation_cmd __init __ssb_select_mitigation(void) enum ssb_mitigation mode = SPEC_STORE_BYPASS_NONE; enum ssb_mitigation_cmd cmd; - if (!boot_cpu_has(X86_FEATURE_RDS)) + if (!boot_cpu_has(X86_FEATURE_SSBD)) return mode; cmd = ssb_parse_cmdline(); @@ -506,7 +506,7 @@ static enum ssb_mitigation_cmd __init __ssb_select_mitigation(void) /* * We have three CPU feature flags that are in play here: * - X86_BUG_SPEC_STORE_BYPASS - CPU is susceptible. - * - X86_FEATURE_RDS - CPU is able to turn off speculative store bypass + * - X86_FEATURE_SSBD - CPU is able to turn off speculative store bypass * - X86_FEATURE_SPEC_STORE_BYPASS_DISABLE - engage the mitigation */ if (mode == SPEC_STORE_BYPASS_DISABLE) { @@ -517,12 +517,12 @@ static enum ssb_mitigation_cmd __init __ssb_select_mitigation(void) */ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_INTEL: - x86_spec_ctrl_base |= SPEC_CTRL_RDS; - x86_spec_ctrl_mask &= ~SPEC_CTRL_RDS; - x86_spec_ctrl_set(SPEC_CTRL_RDS); + x86_spec_ctrl_base |= SPEC_CTRL_SSBD; + x86_spec_ctrl_mask &= ~SPEC_CTRL_SSBD; + x86_spec_ctrl_set(SPEC_CTRL_SSBD); break; case X86_VENDOR_AMD: - x86_amd_rds_enable(); + x86_amd_ssb_disable(); break; } } @@ -555,16 +555,16 @@ static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl) if (task_spec_ssb_force_disable(task)) return -EPERM; task_clear_spec_ssb_disable(task); - update = test_and_clear_tsk_thread_flag(task, TIF_RDS); + update = test_and_clear_tsk_thread_flag(task, TIF_SSBD); break; case PR_SPEC_DISABLE: task_set_spec_ssb_disable(task); - update = !test_and_set_tsk_thread_flag(task, TIF_RDS); + update = !test_and_set_tsk_thread_flag(task, TIF_SSBD); break; case PR_SPEC_FORCE_DISABLE: task_set_spec_ssb_disable(task); task_set_spec_ssb_force_disable(task); - update = !test_and_set_tsk_thread_flag(task, TIF_RDS); + update = !test_and_set_tsk_thread_flag(task, TIF_SSBD); break; default: return -ERANGE; @@ -634,7 +634,7 @@ void x86_spec_ctrl_setup_ap(void) x86_spec_ctrl_set(x86_spec_ctrl_base & ~x86_spec_ctrl_mask); if (ssb_mode == SPEC_STORE_BYPASS_DISABLE) - x86_amd_rds_enable(); + x86_amd_ssb_disable(); } #ifdef CONFIG_SYSFS diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index beb1da89ea7d..d0dd73605cf5 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -911,7 +911,7 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) rdmsrl(MSR_IA32_ARCH_CAPABILITIES, ia32_cap); if (!x86_match_cpu(cpu_no_spec_store_bypass) && - !(ia32_cap & ARCH_CAP_RDS_NO)) + !(ia32_cap & ARCH_CAP_SSBD_NO)) setup_force_cpu_bug(X86_BUG_SPEC_STORE_BYPASS); if (x86_match_cpu(cpu_no_speculation)) diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index f15aea653e8a..047adaa28f3b 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -154,7 +154,7 @@ static void early_init_intel(struct cpuinfo_x86 *c) setup_clear_cpu_cap(X86_FEATURE_STIBP); setup_clear_cpu_cap(X86_FEATURE_SPEC_CTRL); setup_clear_cpu_cap(X86_FEATURE_INTEL_STIBP); - setup_clear_cpu_cap(X86_FEATURE_RDS); + setup_clear_cpu_cap(X86_FEATURE_SSBD); } /* diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 9c48e18d4aeb..c3442300b8f7 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -207,11 +207,11 @@ static __always_inline void __speculative_store_bypass_update(unsigned long tifn { u64 msr; - if (static_cpu_has(X86_FEATURE_AMD_RDS)) { - msr = x86_amd_ls_cfg_base | rds_tif_to_amd_ls_cfg(tifn); + if (static_cpu_has(X86_FEATURE_AMD_SSBD)) { + msr = x86_amd_ls_cfg_base | ssbd_tif_to_amd_ls_cfg(tifn); wrmsrl(MSR_AMD64_LS_CFG, msr); } else { - msr = x86_spec_ctrl_base | rds_tif_to_spec_ctrl(tifn); + msr = x86_spec_ctrl_base | ssbd_tif_to_spec_ctrl(tifn); wrmsrl(MSR_IA32_SPEC_CTRL, msr); } } @@ -250,7 +250,7 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, if ((tifp ^ tifn) & _TIF_NOTSC) cr4_toggle_bits(X86_CR4_TSD); - if ((tifp ^ tifn) & _TIF_RDS) + if ((tifp ^ tifn) & _TIF_SSBD) __speculative_store_bypass_update(tifn); } diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index a9409f06ddc9..18e6db5010e0 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -382,7 +382,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, /* cpuid 7.0.edx*/ const u32 kvm_cpuid_7_0_edx_x86_features = - F(SPEC_CTRL) | F(RDS) | F(ARCH_CAPABILITIES); + F(SPEC_CTRL) | F(SSBD) | F(ARCH_CAPABILITIES); /* all calls to cpuid_count() should be made on the same cpu */ get_cpu(); diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index 24187d07c2cf..aedeb6cc2871 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -179,7 +179,7 @@ static inline bool guest_cpuid_has_spec_ctrl(struct kvm_vcpu *vcpu) if (best && (best->ebx & bit(X86_FEATURE_IBRS))) return true; best = kvm_find_cpuid_entry(vcpu, 7, 0); - return best && (best->edx & (bit(X86_FEATURE_SPEC_CTRL) | bit(X86_FEATURE_RDS))); + return best && (best->edx & (bit(X86_FEATURE_SPEC_CTRL) | bit(X86_FEATURE_SSBD))); } static inline bool guest_cpuid_has_arch_capabilities(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 0eb3863d3159..874b6615ddf5 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -3141,7 +3141,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return 1; /* The STIBP bit doesn't fault even if it's not advertised */ - if (data & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP | SPEC_CTRL_RDS)) + if (data & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP | SPEC_CTRL_SSBD)) return 1; vmx->spec_ctrl = data; -- GitLab From f8cd89f5e05d49422315e60ec2db9fcb66d25aca Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 9 May 2018 21:41:38 +0200 Subject: [PATCH 401/855] proc: Use underscores for SSBD in 'status' commit e96f46ee8587607a828f783daa6eb5b44d25004d upstream The style for the 'status' file is CamelCase or this. _. Fixes: fae1fa0fc ("proc: Provide details on speculation flaw mitigations") Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- fs/proc/array.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/proc/array.c b/fs/proc/array.c index 3e37195485fc..94f83e74db24 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -347,7 +347,7 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p) #ifdef CONFIG_SECCOMP seq_put_decimal_ull(m, "Seccomp:\t", p->seccomp.mode); #endif - seq_printf(m, "\nSpeculation Store Bypass:\t"); + seq_printf(m, "\nSpeculation_Store_Bypass:\t"); switch (arch_prctl_spec_ctrl_get(p, PR_SPEC_STORE_BYPASS)) { case -EINVAL: seq_printf(m, "unknown"); -- GitLab From f79f0efe8e1816063f83926c946026d83b9b287f Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 8 May 2018 15:43:45 +0200 Subject: [PATCH 402/855] Documentation/spec_ctrl: Do some minor cleanups commit dd0792699c4058e63c0715d9a7c2d40226fcdddc upstream Fix some typos, improve formulations, end sentences with a fullstop. Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- Documentation/spec_ctrl.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Documentation/spec_ctrl.txt b/Documentation/spec_ctrl.txt index 1b3690d30943..32f3d55c54b7 100644 --- a/Documentation/spec_ctrl.txt +++ b/Documentation/spec_ctrl.txt @@ -2,13 +2,13 @@ Speculation Control =================== -Quite some CPUs have speculation related misfeatures which are in fact -vulnerabilites causing data leaks in various forms even accross privilege -domains. +Quite some CPUs have speculation-related misfeatures which are in +fact vulnerabilities causing data leaks in various forms even across +privilege domains. The kernel provides mitigation for such vulnerabilities in various -forms. Some of these mitigations are compile time configurable and some on -the kernel command line. +forms. Some of these mitigations are compile-time configurable and some +can be supplied on the kernel command line. There is also a class of mitigations which are very expensive, but they can be restricted to a certain set of processes or tasks in controlled @@ -32,18 +32,18 @@ the following meaning: Bit Define Description ==== ===================== =================================================== 0 PR_SPEC_PRCTL Mitigation can be controlled per task by - PR_SET_SPECULATION_CTRL + PR_SET_SPECULATION_CTRL. 1 PR_SPEC_ENABLE The speculation feature is enabled, mitigation is - disabled + disabled. 2 PR_SPEC_DISABLE The speculation feature is disabled, mitigation is - enabled + enabled. 3 PR_SPEC_FORCE_DISABLE Same as PR_SPEC_DISABLE, but cannot be undone. A subsequent prctl(..., PR_SPEC_ENABLE) will fail. ==== ===================== =================================================== If all bits are 0 the CPU is not affected by the speculation misfeature. -If PR_SPEC_PRCTL is set, then the per task control of the mitigation is +If PR_SPEC_PRCTL is set, then the per-task control of the mitigation is available. If not set, prctl(PR_SET_SPECULATION_CTRL) for the speculation misfeature will fail. @@ -61,9 +61,9 @@ Common error codes Value Meaning ======= ================================================================= EINVAL The prctl is not implemented by the architecture or unused - prctl(2) arguments are not 0 + prctl(2) arguments are not 0. -ENODEV arg2 is selecting a not supported speculation misfeature +ENODEV arg2 is selecting a not supported speculation misfeature. ======= ================================================================= PR_SET_SPECULATION_CTRL error codes @@ -74,7 +74,7 @@ Value Meaning 0 Success ERANGE arg3 is incorrect, i.e. it's neither PR_SPEC_ENABLE nor - PR_SPEC_DISABLE nor PR_SPEC_FORCE_DISABLE + PR_SPEC_DISABLE nor PR_SPEC_FORCE_DISABLE. ENXIO Control of the selected speculation misfeature is not possible. See PR_GET_SPECULATION_CTRL. -- GitLab From eb7b5624be3e6249a880310be486245db15a5f5c Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 10 May 2018 22:47:18 +0200 Subject: [PATCH 403/855] x86/bugs: Fix __ssb_select_mitigation() return type commit d66d8ff3d21667b41eddbe86b35ab411e40d8c5f upstream __ssb_select_mitigation() returns one of the members of enum ssb_mitigation, not ssb_mitigation_cmd; fix the prototype to reflect that. Fixes: 24f7fc83b9204 ("x86/bugs: Provide boot parameters for the spec_store_bypass_disable mitigation") Signed-off-by: Jiri Kosina Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/bugs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index ae6f9bae17ce..c7b4d117f652 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -467,7 +467,7 @@ static enum ssb_mitigation_cmd __init ssb_parse_cmdline(void) return cmd; } -static enum ssb_mitigation_cmd __init __ssb_select_mitigation(void) +static enum ssb_mitigation __init __ssb_select_mitigation(void) { enum ssb_mitigation mode = SPEC_STORE_BYPASS_NONE; enum ssb_mitigation_cmd cmd; -- GitLab From dbb264a253c8b07259d55fb3373b783fcb641b04 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 10 May 2018 22:47:32 +0200 Subject: [PATCH 404/855] x86/bugs: Make cpu_show_common() static commit 7bb4d366cba992904bffa4820d24e70a3de93e76 upstream cpu_show_common() is not used outside of arch/x86/kernel/cpu/bugs.c, so make it static. Signed-off-by: Jiri Kosina Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/bugs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index c7b4d117f652..8187642236b6 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -639,7 +639,7 @@ void x86_spec_ctrl_setup_ap(void) #ifdef CONFIG_SYSFS -ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr, +static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr, char *buf, unsigned int bug) { if (!boot_cpu_has_bug(bug)) -- GitLab From 6fdd277a9326c5ef3fe94999c9c319ad64333fdd Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 11 May 2018 16:50:35 -0400 Subject: [PATCH 405/855] x86/bugs: Fix the parameters alignment and missing void commit ffed645e3be0e32f8e9ab068d257aee8d0fe8eec upstream Fixes: 7bb4d366c ("x86/bugs: Make cpu_show_common() static") Fixes: 24f7fc83b ("x86/bugs: Provide boot parameters for the spec_store_bypass_disable mitigation") Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/bugs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 8187642236b6..4f8c88ec8bed 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -530,7 +530,7 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void) return mode; } -static void ssb_select_mitigation() +static void ssb_select_mitigation(void) { ssb_mode = __ssb_select_mitigation(); @@ -640,7 +640,7 @@ void x86_spec_ctrl_setup_ap(void) #ifdef CONFIG_SYSFS static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr, - char *buf, unsigned int bug) + char *buf, unsigned int bug) { if (!boot_cpu_has_bug(bug)) return sprintf(buf, "Not affected\n"); -- GitLab From 3a684641619ff0e06b8d4cb8c2ffbef304c9bdb1 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Sun, 13 May 2018 17:33:57 -0400 Subject: [PATCH 406/855] x86/cpu: Make alternative_msr_write work for 32-bit code commit 5f2b745f5e1304f438f9b2cd03ebc8120b6e0d3b upstream Cast val and (val >> 32) to (u32), so that they fit in a general-purpose register in both 32-bit and 64-bit code. [ tglx: Made it u32 instead of uintptr_t ] Fixes: c65732e4f721 ("x86/cpu: Restore CPUID_8000_0008_EBX reload") Signed-off-by: Jim Mattson Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Acked-by: Linus Torvalds Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/nospec-branch.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 328ea3cb769f..bc258e644e5e 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -265,8 +265,8 @@ void alternative_msr_write(unsigned int msr, u64 val, unsigned int feature) { asm volatile(ALTERNATIVE("", "wrmsr", %c[feature]) : : "c" (msr), - "a" (val), - "d" (val >> 32), + "a" ((u32)val), + "d" ((u32)(val >> 32)), [feature] "i" (feature) : "memory"); } -- GitLab From 69e9b0b1e04001a743927489bb8b9a10344810d8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 11 May 2018 15:21:01 +0200 Subject: [PATCH 407/855] KVM: SVM: Move spec control call after restore of GS commit 15e6c22fd8e5a42c5ed6d487b7c9fe44c2517765 upstream svm_vcpu_run() invokes x86_spec_ctrl_restore_host() after VMEXIT, but before the host GS is restored. x86_spec_ctrl_restore_host() uses 'current' to determine the host SSBD state of the thread. 'current' is GS based, but host GS is not yet restored and the access causes a triple fault. Move the call after the host GS restore. Fixes: 885f82bfbc6f x86/process: Allow runtime control of Speculative Store Bypass Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Konrad Rzeszutek Wilk Acked-by: Paolo Bonzini Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/svm.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 516ddfff8c8b..d1a4321d4631 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -5011,6 +5011,18 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) #endif ); + /* Eliminate branch target predictions from guest mode */ + vmexit_fill_RSB(); + +#ifdef CONFIG_X86_64 + wrmsrl(MSR_GS_BASE, svm->host.gs_base); +#else + loadsegment(fs, svm->host.fs); +#ifndef CONFIG_X86_32_LAZY_GS + loadsegment(gs, svm->host.gs); +#endif +#endif + /* * We do not use IBRS in the kernel. If this vCPU has used the * SPEC_CTRL MSR it may have left it on; save the value and @@ -5031,18 +5043,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) x86_spec_ctrl_restore_host(svm->spec_ctrl); - /* Eliminate branch target predictions from guest mode */ - vmexit_fill_RSB(); - -#ifdef CONFIG_X86_64 - wrmsrl(MSR_GS_BASE, svm->host.gs_base); -#else - loadsegment(fs, svm->host.fs); -#ifndef CONFIG_X86_32_LAZY_GS - loadsegment(gs, svm->host.gs); -#endif -#endif - reload_tss(vcpu); local_irq_disable(); -- GitLab From 4a58908fa1476c600548f82effc75bcfa890454a Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 2 May 2018 18:15:14 +0200 Subject: [PATCH 408/855] x86/speculation: Use synthetic bits for IBRS/IBPB/STIBP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e7c587da125291db39ddf1f49b18e5970adbac17 upstream Intel and AMD have different CPUID bits hence for those use synthetic bits which get set on the respective vendor's in init_speculation_control(). So that debacles like what the commit message of c65732e4f721 ("x86/cpu: Restore CPUID_8000_0008_EBX reload") talks about don't happen anymore. Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Reviewed-by: Konrad Rzeszutek Wilk Tested-by: Jörg Otte Cc: Linus Torvalds Cc: "Kirill A. Shutemov" Link: https://lkml.kernel.org/r/20180504161815.GG9257@pd.tnic Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/cpufeatures.h | 12 ++++++++---- arch/x86/kernel/cpu/common.c | 14 ++++++++++---- arch/x86/kvm/cpuid.c | 10 +++++----- arch/x86/kvm/cpuid.h | 4 ++-- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 0ed8ea5419c1..059437ae9fac 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -205,7 +205,10 @@ #define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ #define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ #define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* "" Disable Speculative Store Bypass. */ -#define X86_FEATURE_AMD_SSBD (7*32+24) /* "" AMD SSBD implementation */ +#define X86_FEATURE_AMD_SSBD ( 7*32+24) /* "" AMD SSBD implementation */ +#define X86_FEATURE_IBRS ( 7*32+25) /* Indirect Branch Restricted Speculation */ +#define X86_FEATURE_IBPB ( 7*32+26) /* Indirect Branch Prediction Barrier */ +#define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */ /* Virtualization flags: Linux defined, word 8 */ #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ @@ -263,9 +266,9 @@ /* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */ #define X86_FEATURE_CLZERO (13*32+0) /* CLZERO instruction */ #define X86_FEATURE_IRPERF (13*32+1) /* Instructions Retired Count */ -#define X86_FEATURE_IBPB (13*32+12) /* Indirect Branch Prediction Barrier */ -#define X86_FEATURE_IBRS (13*32+14) /* Indirect Branch Restricted Speculation */ -#define X86_FEATURE_STIBP (13*32+15) /* Single Thread Indirect Branch Predictors */ +#define X86_FEATURE_AMD_IBPB (13*32+12) /* Indirect Branch Prediction Barrier */ +#define X86_FEATURE_AMD_IBRS (13*32+14) /* Indirect Branch Restricted Speculation */ +#define X86_FEATURE_AMD_STIBP (13*32+15) /* Single Thread Indirect Branch Predictors */ /* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */ #define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ @@ -301,6 +304,7 @@ #define X86_FEATURE_SUCCOR (17*32+1) /* Uncorrectable error containment and recovery */ #define X86_FEATURE_SMCA (17*32+3) /* Scalable MCA */ + /* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ #define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ #define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index d0dd73605cf5..67bfa3cad8a2 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -725,17 +725,23 @@ static void init_speculation_control(struct cpuinfo_x86 *c) * and they also have a different bit for STIBP support. Also, * a hypervisor might have set the individual AMD bits even on * Intel CPUs, for finer-grained selection of what's available. - * - * We use the AMD bits in 0x8000_0008 EBX as the generic hardware - * features, which are visible in /proc/cpuinfo and used by the - * kernel. So set those accordingly from the Intel bits. */ if (cpu_has(c, X86_FEATURE_SPEC_CTRL)) { set_cpu_cap(c, X86_FEATURE_IBRS); set_cpu_cap(c, X86_FEATURE_IBPB); } + if (cpu_has(c, X86_FEATURE_INTEL_STIBP)) set_cpu_cap(c, X86_FEATURE_STIBP); + + if (cpu_has(c, X86_FEATURE_AMD_IBRS)) + set_cpu_cap(c, X86_FEATURE_IBRS); + + if (cpu_has(c, X86_FEATURE_AMD_IBPB)) + set_cpu_cap(c, X86_FEATURE_IBPB); + + if (cpu_has(c, X86_FEATURE_AMD_STIBP)) + set_cpu_cap(c, X86_FEATURE_STIBP); } void get_cpu_cap(struct cpuinfo_x86 *c) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 18e6db5010e0..910c2dbb38de 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -357,7 +357,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, /* cpuid 0x80000008.ebx */ const u32 kvm_cpuid_8000_0008_ebx_x86_features = - F(IBPB) | F(IBRS); + F(AMD_IBPB) | F(AMD_IBRS); /* cpuid 0xC0000001.edx */ const u32 kvm_cpuid_C000_0001_edx_x86_features = @@ -619,10 +619,10 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, entry->eax = g_phys_as | (virt_as << 8); entry->edx = 0; /* IBRS and IBPB aren't necessarily present in hardware cpuid */ - if (boot_cpu_has(X86_FEATURE_IBPB)) - entry->ebx |= F(IBPB); - if (boot_cpu_has(X86_FEATURE_IBRS)) - entry->ebx |= F(IBRS); + if (boot_cpu_has(X86_FEATURE_AMD_IBPB)) + entry->ebx |= F(AMD_IBPB); + if (boot_cpu_has(X86_FEATURE_AMD_IBRS)) + entry->ebx |= F(AMD_IBRS); entry->ebx &= kvm_cpuid_8000_0008_ebx_x86_features; cpuid_mask(&entry->ebx, CPUID_8000_0008_EBX); break; diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index aedeb6cc2871..eb47c37db15f 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -165,7 +165,7 @@ static inline bool guest_cpuid_has_ibpb(struct kvm_vcpu *vcpu) struct kvm_cpuid_entry2 *best; best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0); - if (best && (best->ebx & bit(X86_FEATURE_IBPB))) + if (best && (best->ebx & bit(X86_FEATURE_AMD_IBPB))) return true; best = kvm_find_cpuid_entry(vcpu, 7, 0); return best && (best->edx & bit(X86_FEATURE_SPEC_CTRL)); @@ -176,7 +176,7 @@ static inline bool guest_cpuid_has_spec_ctrl(struct kvm_vcpu *vcpu) struct kvm_cpuid_entry2 *best; best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0); - if (best && (best->ebx & bit(X86_FEATURE_IBRS))) + if (best && (best->ebx & bit(X86_FEATURE_AMD_IBRS))) return true; best = kvm_find_cpuid_entry(vcpu, 7, 0); return best && (best->edx & (bit(X86_FEATURE_SPEC_CTRL) | bit(X86_FEATURE_SSBD))); -- GitLab From a7c343228e5c32802431e6cc5b855ae61eb4db72 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 10 May 2018 19:13:18 +0200 Subject: [PATCH 409/855] x86/cpufeatures: Disentangle MSR_SPEC_CTRL enumeration from IBRS commit 7eb8956a7fec3c1f0abc2a5517dada99ccc8a961 upstream The availability of the SPEC_CTRL MSR is enumerated by a CPUID bit on Intel and implied by IBRS or STIBP support on AMD. That's just confusing and in case an AMD CPU has IBRS not supported because the underlying problem has been fixed but has another bit valid in the SPEC_CTRL MSR, the thing falls apart. Add a synthetic feature bit X86_FEATURE_MSR_SPEC_CTRL to denote the availability on both Intel and AMD. While at it replace the boot_cpu_has() checks with static_cpu_has() where possible. This prevents late microcode loading from exposing SPEC_CTRL, but late loading is already very limited as it does not reevaluate the mitigation options and other bits and pieces. Having static_cpu_has() is the simplest and least fragile solution. Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/cpufeatures.h | 2 ++ arch/x86/kernel/cpu/bugs.c | 18 +++++++++++------- arch/x86/kernel/cpu/common.c | 9 +++++++-- arch/x86/kernel/cpu/intel.c | 1 + 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 059437ae9fac..ca0f33f5260a 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -197,6 +197,8 @@ #define X86_FEATURE_RETPOLINE ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */ #define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */ +#define X86_FEATURE_MSR_SPEC_CTRL ( 7*32+16) /* "" MSR SPEC_CTRL is implemented */ + #define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* "" Fill RSB on context switches */ /* Because the ALTERNATIVE scheme is for members of the X86_FEATURE club... */ diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 4f8c88ec8bed..59649310f9f3 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -63,7 +63,7 @@ void __init check_bugs(void) * have unknown values. AMD64_LS_CFG MSR is cached in the early AMD * init code as it is not enumerated and depends on the family. */ - if (boot_cpu_has(X86_FEATURE_IBRS)) + if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) rdmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base); /* Select the proper spectre mitigation before patching alternatives */ @@ -144,7 +144,7 @@ u64 x86_spec_ctrl_get_default(void) { u64 msrval = x86_spec_ctrl_base; - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + if (static_cpu_has(X86_FEATURE_SPEC_CTRL)) msrval |= ssbd_tif_to_spec_ctrl(current_thread_info()->flags); return msrval; } @@ -154,10 +154,12 @@ void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl) { u64 host = x86_spec_ctrl_base; - if (!boot_cpu_has(X86_FEATURE_IBRS)) + /* Is MSR_SPEC_CTRL implemented ? */ + if (!static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) return; - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + /* Intel controls SSB in MSR_SPEC_CTRL */ + if (static_cpu_has(X86_FEATURE_SPEC_CTRL)) host |= ssbd_tif_to_spec_ctrl(current_thread_info()->flags); if (host != guest_spec_ctrl) @@ -169,10 +171,12 @@ void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl) { u64 host = x86_spec_ctrl_base; - if (!boot_cpu_has(X86_FEATURE_IBRS)) + /* Is MSR_SPEC_CTRL implemented ? */ + if (!static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) return; - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + /* Intel controls SSB in MSR_SPEC_CTRL */ + if (static_cpu_has(X86_FEATURE_SPEC_CTRL)) host |= ssbd_tif_to_spec_ctrl(current_thread_info()->flags); if (host != guest_spec_ctrl) @@ -630,7 +634,7 @@ int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which) void x86_spec_ctrl_setup_ap(void) { - if (boot_cpu_has(X86_FEATURE_IBRS)) + if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) x86_spec_ctrl_set(x86_spec_ctrl_base & ~x86_spec_ctrl_mask); if (ssb_mode == SPEC_STORE_BYPASS_DISABLE) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 67bfa3cad8a2..043622827331 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -729,19 +729,24 @@ static void init_speculation_control(struct cpuinfo_x86 *c) if (cpu_has(c, X86_FEATURE_SPEC_CTRL)) { set_cpu_cap(c, X86_FEATURE_IBRS); set_cpu_cap(c, X86_FEATURE_IBPB); + set_cpu_cap(c, X86_FEATURE_MSR_SPEC_CTRL); } if (cpu_has(c, X86_FEATURE_INTEL_STIBP)) set_cpu_cap(c, X86_FEATURE_STIBP); - if (cpu_has(c, X86_FEATURE_AMD_IBRS)) + if (cpu_has(c, X86_FEATURE_AMD_IBRS)) { set_cpu_cap(c, X86_FEATURE_IBRS); + set_cpu_cap(c, X86_FEATURE_MSR_SPEC_CTRL); + } if (cpu_has(c, X86_FEATURE_AMD_IBPB)) set_cpu_cap(c, X86_FEATURE_IBPB); - if (cpu_has(c, X86_FEATURE_AMD_STIBP)) + if (cpu_has(c, X86_FEATURE_AMD_STIBP)) { set_cpu_cap(c, X86_FEATURE_STIBP); + set_cpu_cap(c, X86_FEATURE_MSR_SPEC_CTRL); + } } void get_cpu_cap(struct cpuinfo_x86 *c) diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 047adaa28f3b..7f495e846da3 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -153,6 +153,7 @@ static void early_init_intel(struct cpuinfo_x86 *c) setup_clear_cpu_cap(X86_FEATURE_IBPB); setup_clear_cpu_cap(X86_FEATURE_STIBP); setup_clear_cpu_cap(X86_FEATURE_SPEC_CTRL); + setup_clear_cpu_cap(X86_FEATURE_MSR_SPEC_CTRL); setup_clear_cpu_cap(X86_FEATURE_INTEL_STIBP); setup_clear_cpu_cap(X86_FEATURE_SSBD); } -- GitLab From f69e91f2c4ce59deb66bd30150e5153c08873ae9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 10 May 2018 20:21:36 +0200 Subject: [PATCH 410/855] x86/cpufeatures: Disentangle SSBD enumeration commit 52817587e706686fcdb27f14c1b000c92f266c96 upstream The SSBD enumeration is similarly to the other bits magically shared between Intel and AMD though the mechanisms are different. Make X86_FEATURE_SSBD synthetic and set it depending on the vendor specific features or family dependent setup. Change the Intel bit to X86_FEATURE_SPEC_CTRL_SSBD to denote that SSBD is controlled via MSR_SPEC_CTRL and fix up the usage sites. Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/cpufeatures.h | 5 +++-- arch/x86/kernel/cpu/amd.c | 7 +------ arch/x86/kernel/cpu/bugs.c | 10 +++++----- arch/x86/kernel/cpu/common.c | 3 +++ arch/x86/kernel/cpu/intel.c | 1 + arch/x86/kernel/process.c | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index ca0f33f5260a..d071767ed80d 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -198,6 +198,7 @@ #define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */ #define X86_FEATURE_MSR_SPEC_CTRL ( 7*32+16) /* "" MSR SPEC_CTRL is implemented */ +#define X86_FEATURE_SSBD ( 7*32+17) /* Speculative Store Bypass Disable */ #define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* "" Fill RSB on context switches */ @@ -207,7 +208,7 @@ #define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ #define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ #define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* "" Disable Speculative Store Bypass. */ -#define X86_FEATURE_AMD_SSBD ( 7*32+24) /* "" AMD SSBD implementation */ +#define X86_FEATURE_LS_CFG_SSBD ( 7*32+24) /* "" AMD SSBD implementation */ #define X86_FEATURE_IBRS ( 7*32+25) /* Indirect Branch Restricted Speculation */ #define X86_FEATURE_IBPB ( 7*32+26) /* Indirect Branch Prediction Barrier */ #define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */ @@ -314,7 +315,7 @@ #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ -#define X86_FEATURE_SSBD (18*32+31) /* Speculative Store Bypass Disable */ +#define X86_FEATURE_SPEC_CTRL_SSBD (18*32+31) /* "" Speculative Store Bypass Disable */ /* * BUG word(s) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index acb2fcc510d2..179d5721a509 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -558,8 +558,8 @@ static void bsp_init_amd(struct cpuinfo_x86 *c) * avoid RMW. If that faults, do not enable SSBD. */ if (!rdmsrl_safe(MSR_AMD64_LS_CFG, &x86_amd_ls_cfg_base)) { + setup_force_cpu_cap(X86_FEATURE_LS_CFG_SSBD); setup_force_cpu_cap(X86_FEATURE_SSBD); - setup_force_cpu_cap(X86_FEATURE_AMD_SSBD); x86_amd_ls_cfg_ssbd_mask = 1ULL << bit; } } @@ -848,11 +848,6 @@ static void init_amd(struct cpuinfo_x86 *c) /* AMD CPUs don't reset SS attributes on SYSRET, Xen does. */ if (!cpu_has(c, X86_FEATURE_XENPV)) set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); - - if (boot_cpu_has(X86_FEATURE_AMD_SSBD)) { - set_cpu_cap(c, X86_FEATURE_SSBD); - set_cpu_cap(c, X86_FEATURE_AMD_SSBD); - } } #ifdef CONFIG_X86_32 diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 59649310f9f3..15a6c58c4226 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -158,8 +158,8 @@ void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl) if (!static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) return; - /* Intel controls SSB in MSR_SPEC_CTRL */ - if (static_cpu_has(X86_FEATURE_SPEC_CTRL)) + /* SSBD controlled in MSR_SPEC_CTRL */ + if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD)) host |= ssbd_tif_to_spec_ctrl(current_thread_info()->flags); if (host != guest_spec_ctrl) @@ -175,8 +175,8 @@ void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl) if (!static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) return; - /* Intel controls SSB in MSR_SPEC_CTRL */ - if (static_cpu_has(X86_FEATURE_SPEC_CTRL)) + /* SSBD controlled in MSR_SPEC_CTRL */ + if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD)) host |= ssbd_tif_to_spec_ctrl(current_thread_info()->flags); if (host != guest_spec_ctrl) @@ -188,7 +188,7 @@ static void x86_amd_ssb_disable(void) { u64 msrval = x86_amd_ls_cfg_base | x86_amd_ls_cfg_ssbd_mask; - if (boot_cpu_has(X86_FEATURE_AMD_SSBD)) + if (boot_cpu_has(X86_FEATURE_LS_CFG_SSBD)) wrmsrl(MSR_AMD64_LS_CFG, msrval); } diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 043622827331..945e84105f8d 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -735,6 +735,9 @@ static void init_speculation_control(struct cpuinfo_x86 *c) if (cpu_has(c, X86_FEATURE_INTEL_STIBP)) set_cpu_cap(c, X86_FEATURE_STIBP); + if (cpu_has(c, X86_FEATURE_SPEC_CTRL_SSBD)) + set_cpu_cap(c, X86_FEATURE_SSBD); + if (cpu_has(c, X86_FEATURE_AMD_IBRS)) { set_cpu_cap(c, X86_FEATURE_IBRS); set_cpu_cap(c, X86_FEATURE_MSR_SPEC_CTRL); diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 7f495e846da3..93781e3f05b2 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -156,6 +156,7 @@ static void early_init_intel(struct cpuinfo_x86 *c) setup_clear_cpu_cap(X86_FEATURE_MSR_SPEC_CTRL); setup_clear_cpu_cap(X86_FEATURE_INTEL_STIBP); setup_clear_cpu_cap(X86_FEATURE_SSBD); + setup_clear_cpu_cap(X86_FEATURE_SPEC_CTRL_SSBD); } /* diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index c3442300b8f7..b3cd08eb664e 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -207,7 +207,7 @@ static __always_inline void __speculative_store_bypass_update(unsigned long tifn { u64 msr; - if (static_cpu_has(X86_FEATURE_AMD_SSBD)) { + if (static_cpu_has(X86_FEATURE_LS_CFG_SSBD)) { msr = x86_amd_ls_cfg_base | ssbd_tif_to_amd_ls_cfg(tifn); wrmsrl(MSR_AMD64_LS_CFG, msr); } else { -- GitLab From 5a63725cd18fcee2af6ec46ccb856b64ad3077b4 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 7 Sep 2017 19:08:21 +0200 Subject: [PATCH 411/855] x86/cpu/AMD: Fix erratum 1076 (CPB bit) commit f7f3dc00f61261cdc9ccd8b886f21bc4dffd6fd9 upstream CPUID Fn8000_0007_EDX[CPB] is wrongly 0 on models up to B1. But they do support CPB (AMD's Core Performance Boosting cpufreq CPU feature), so fix that. Signed-off-by: Borislav Petkov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Sherry Hurwitz Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20170907170821.16021-1-bp@alien8.de Signed-off-by: Ingo Molnar Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/amd.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 179d5721a509..21367b51c2f3 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -749,6 +749,16 @@ static void init_amd_bd(struct cpuinfo_x86 *c) } } +static void init_amd_zn(struct cpuinfo_x86 *c) +{ + /* + * Fix erratum 1076: CPB feature bit not being set in CPUID. It affects + * all up to and including B1. + */ + if (c->x86_model <= 1 && c->x86_stepping <= 1) + set_cpu_cap(c, X86_FEATURE_CPB); +} + static void init_amd(struct cpuinfo_x86 *c) { u32 dummy; @@ -779,6 +789,7 @@ static void init_amd(struct cpuinfo_x86 *c) case 0x10: init_amd_gh(c); break; case 0x12: init_amd_ln(c); break; case 0x15: init_amd_bd(c); break; + case 0x17: init_amd_zn(c); break; } /* Enable workaround for FXSAVE leak */ -- GitLab From 53c434e735fffbf8715a1778ce44387131e0b080 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 10 May 2018 16:26:00 +0200 Subject: [PATCH 412/855] x86/cpufeatures: Add FEATURE_ZEN commit d1035d971829dcf80e8686ccde26f94b0a069472 upstream Add a ZEN feature bit so family-dependent static_cpu_has() optimizations can be built for ZEN. Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/cpufeatures.h | 2 ++ arch/x86/kernel/cpu/amd.c | 1 + 2 files changed, 3 insertions(+) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index d071767ed80d..ec87b8caa9b9 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -212,6 +212,8 @@ #define X86_FEATURE_IBRS ( 7*32+25) /* Indirect Branch Restricted Speculation */ #define X86_FEATURE_IBPB ( 7*32+26) /* Indirect Branch Prediction Barrier */ #define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */ +#define X86_FEATURE_ZEN ( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */ + /* Virtualization flags: Linux defined, word 8 */ #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 21367b51c2f3..4c2be99fa0fb 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -751,6 +751,7 @@ static void init_amd_bd(struct cpuinfo_x86 *c) static void init_amd_zn(struct cpuinfo_x86 *c) { + set_cpu_cap(c, X86_FEATURE_ZEN); /* * Fix erratum 1076: CPB feature bit not being set in CPUID. It affects * all up to and including B1. -- GitLab From d0cb78f5e4214db86b12a9448d8ccaa005f43cb9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 9 May 2018 21:53:09 +0200 Subject: [PATCH 413/855] x86/speculation: Handle HT correctly on AMD commit 1f50ddb4f4189243c05926b842dc1a0332195f31 upstream The AMD64_LS_CFG MSR is a per core MSR on Family 17H CPUs. That means when hyperthreading is enabled the SSBD bit toggle needs to take both cores into account. Otherwise the following situation can happen: CPU0 CPU1 disable SSB disable SSB enable SSB <- Enables it for the Core, i.e. for CPU0 as well So after the SSB enable on CPU1 the task on CPU0 runs with SSB enabled again. On Intel the SSBD control is per core as well, but the synchronization logic is implemented behind the per thread SPEC_CTRL MSR. It works like this: CORE_SPEC_CTRL = THREAD0_SPEC_CTRL | THREAD1_SPEC_CTRL i.e. if one of the threads enables a mitigation then this affects both and the mitigation is only disabled in the core when both threads disabled it. Add the necessary synchronization logic for AMD family 17H. Unfortunately that requires a spinlock to serialize the access to the MSR, but the locks are only shared between siblings. Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/spec-ctrl.h | 6 ++ arch/x86/kernel/process.c | 125 +++++++++++++++++++++++++++++-- arch/x86/kernel/smpboot.c | 5 ++ 3 files changed, 130 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/spec-ctrl.h b/arch/x86/include/asm/spec-ctrl.h index dc21209790bf..0cb49c4564b0 100644 --- a/arch/x86/include/asm/spec-ctrl.h +++ b/arch/x86/include/asm/spec-ctrl.h @@ -33,6 +33,12 @@ static inline u64 ssbd_tif_to_amd_ls_cfg(u64 tifn) return (tifn & _TIF_SSBD) ? x86_amd_ls_cfg_ssbd_mask : 0ULL; } +#ifdef CONFIG_SMP +extern void speculative_store_bypass_ht_init(void); +#else +static inline void speculative_store_bypass_ht_init(void) { } +#endif + extern void speculative_store_bypass_update(void); #endif diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index b3cd08eb664e..1e9d155544ee 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -203,22 +203,135 @@ static inline void switch_to_bitmap(struct tss_struct *tss, } } -static __always_inline void __speculative_store_bypass_update(unsigned long tifn) +#ifdef CONFIG_SMP + +struct ssb_state { + struct ssb_state *shared_state; + raw_spinlock_t lock; + unsigned int disable_state; + unsigned long local_state; +}; + +#define LSTATE_SSB 0 + +static DEFINE_PER_CPU(struct ssb_state, ssb_state); + +void speculative_store_bypass_ht_init(void) { - u64 msr; + struct ssb_state *st = this_cpu_ptr(&ssb_state); + unsigned int this_cpu = smp_processor_id(); + unsigned int cpu; + + st->local_state = 0; + + /* + * Shared state setup happens once on the first bringup + * of the CPU. It's not destroyed on CPU hotunplug. + */ + if (st->shared_state) + return; + + raw_spin_lock_init(&st->lock); - if (static_cpu_has(X86_FEATURE_LS_CFG_SSBD)) { - msr = x86_amd_ls_cfg_base | ssbd_tif_to_amd_ls_cfg(tifn); + /* + * Go over HT siblings and check whether one of them has set up the + * shared state pointer already. + */ + for_each_cpu(cpu, topology_sibling_cpumask(this_cpu)) { + if (cpu == this_cpu) + continue; + + if (!per_cpu(ssb_state, cpu).shared_state) + continue; + + /* Link it to the state of the sibling: */ + st->shared_state = per_cpu(ssb_state, cpu).shared_state; + return; + } + + /* + * First HT sibling to come up on the core. Link shared state of + * the first HT sibling to itself. The siblings on the same core + * which come up later will see the shared state pointer and link + * themself to the state of this CPU. + */ + st->shared_state = st; +} + +/* + * Logic is: First HT sibling enables SSBD for both siblings in the core + * and last sibling to disable it, disables it for the whole core. This how + * MSR_SPEC_CTRL works in "hardware": + * + * CORE_SPEC_CTRL = THREAD0_SPEC_CTRL | THREAD1_SPEC_CTRL + */ +static __always_inline void amd_set_core_ssb_state(unsigned long tifn) +{ + struct ssb_state *st = this_cpu_ptr(&ssb_state); + u64 msr = x86_amd_ls_cfg_base; + + if (!static_cpu_has(X86_FEATURE_ZEN)) { + msr |= ssbd_tif_to_amd_ls_cfg(tifn); wrmsrl(MSR_AMD64_LS_CFG, msr); + return; + } + + if (tifn & _TIF_SSBD) { + /* + * Since this can race with prctl(), block reentry on the + * same CPU. + */ + if (__test_and_set_bit(LSTATE_SSB, &st->local_state)) + return; + + msr |= x86_amd_ls_cfg_ssbd_mask; + + raw_spin_lock(&st->shared_state->lock); + /* First sibling enables SSBD: */ + if (!st->shared_state->disable_state) + wrmsrl(MSR_AMD64_LS_CFG, msr); + st->shared_state->disable_state++; + raw_spin_unlock(&st->shared_state->lock); } else { - msr = x86_spec_ctrl_base | ssbd_tif_to_spec_ctrl(tifn); - wrmsrl(MSR_IA32_SPEC_CTRL, msr); + if (!__test_and_clear_bit(LSTATE_SSB, &st->local_state)) + return; + + raw_spin_lock(&st->shared_state->lock); + st->shared_state->disable_state--; + if (!st->shared_state->disable_state) + wrmsrl(MSR_AMD64_LS_CFG, msr); + raw_spin_unlock(&st->shared_state->lock); } } +#else +static __always_inline void amd_set_core_ssb_state(unsigned long tifn) +{ + u64 msr = x86_amd_ls_cfg_base | ssbd_tif_to_amd_ls_cfg(tifn); + + wrmsrl(MSR_AMD64_LS_CFG, msr); +} +#endif + +static __always_inline void intel_set_ssb_state(unsigned long tifn) +{ + u64 msr = x86_spec_ctrl_base | ssbd_tif_to_spec_ctrl(tifn); + + wrmsrl(MSR_IA32_SPEC_CTRL, msr); +} + +static __always_inline void __speculative_store_bypass_update(unsigned long tifn) +{ + if (static_cpu_has(X86_FEATURE_LS_CFG_SSBD)) + amd_set_core_ssb_state(tifn); + else + intel_set_ssb_state(tifn); +} void speculative_store_bypass_update(void) { + preempt_disable(); __speculative_store_bypass_update(current_thread_info()->flags); + preempt_enable(); } void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 83929cc47a4b..cb945146b7c8 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -75,6 +75,7 @@ #include #include #include +#include /* Number of siblings per CPU package */ int smp_num_siblings = 1; @@ -229,6 +230,8 @@ static void notrace start_secondary(void *unused) */ check_tsc_sync_target(); + speculative_store_bypass_ht_init(); + /* * Lock vector_lock and initialize the vectors on this cpu * before setting the cpu online. We must set it online with @@ -1325,6 +1328,8 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) set_mtrr_aps_delayed_init(); smp_quirk_init_udelay(); + + speculative_store_bypass_ht_init(); } void arch_enable_nonboot_cpus_begin(void) -- GitLab From 1189cbf52ad35cfd04a715016200ea81dd4c708f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 9 May 2018 23:01:01 +0200 Subject: [PATCH 414/855] x86/bugs, KVM: Extend speculation control for VIRT_SPEC_CTRL commit ccbcd2674472a978b48c91c1fbfb66c0ff959f24 upstream AMD is proposing a VIRT_SPEC_CTRL MSR to handle the Speculative Store Bypass Disable via MSR_AMD64_LS_CFG so that guests do not have to care about the bit position of the SSBD bit and thus facilitate migration. Also, the sibling coordination on Family 17H CPUs can only be done on the host. Extend x86_spec_ctrl_set_guest() and x86_spec_ctrl_restore_host() with an extra argument for the VIRT_SPEC_CTRL MSR. Hand in 0 from VMX and in SVM add a new virt_spec_ctrl member to the CPU data structure which is going to be used in later patches for the actual implementation. Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/spec-ctrl.h | 9 ++++++--- arch/x86/kernel/cpu/bugs.c | 20 ++++++++++++++++++-- arch/x86/kvm/svm.c | 11 +++++++++-- arch/x86/kvm/vmx.c | 5 +++-- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/arch/x86/include/asm/spec-ctrl.h b/arch/x86/include/asm/spec-ctrl.h index 0cb49c4564b0..6e2874049afd 100644 --- a/arch/x86/include/asm/spec-ctrl.h +++ b/arch/x86/include/asm/spec-ctrl.h @@ -10,10 +10,13 @@ * the guest has, while on VMEXIT we restore the host view. This * would be easier if SPEC_CTRL were architecturally maskable or * shadowable for guests but this is not (currently) the case. - * Takes the guest view of SPEC_CTRL MSR as a parameter. + * Takes the guest view of SPEC_CTRL MSR as a parameter and also + * the guest's version of VIRT_SPEC_CTRL, if emulated. */ -extern void x86_spec_ctrl_set_guest(u64); -extern void x86_spec_ctrl_restore_host(u64); +extern void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl, + u64 guest_virt_spec_ctrl); +extern void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl, + u64 guest_virt_spec_ctrl); /* AMD specific Speculative Store Bypass MSR data */ extern u64 x86_amd_ls_cfg_base; diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 15a6c58c4226..d00e246d4661 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -150,7 +150,15 @@ u64 x86_spec_ctrl_get_default(void) } EXPORT_SYMBOL_GPL(x86_spec_ctrl_get_default); -void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl) +/** + * x86_spec_ctrl_set_guest - Set speculation control registers for the guest + * @guest_spec_ctrl: The guest content of MSR_SPEC_CTRL + * @guest_virt_spec_ctrl: The guest controlled bits of MSR_VIRT_SPEC_CTRL + * (may get translated to MSR_AMD64_LS_CFG bits) + * + * Avoids writing to the MSR if the content/bits are the same + */ +void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl) { u64 host = x86_spec_ctrl_base; @@ -167,7 +175,15 @@ void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl) } EXPORT_SYMBOL_GPL(x86_spec_ctrl_set_guest); -void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl) +/** + * x86_spec_ctrl_restore_host - Restore host speculation control registers + * @guest_spec_ctrl: The guest content of MSR_SPEC_CTRL + * @guest_virt_spec_ctrl: The guest controlled bits of MSR_VIRT_SPEC_CTRL + * (may get translated to MSR_AMD64_LS_CFG bits) + * + * Avoids writing to the MSR if the content/bits are the same + */ +void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl) { u64 host = x86_spec_ctrl_base; diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index d1a4321d4631..57c96f165ac4 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -185,6 +185,12 @@ struct vcpu_svm { } host; u64 spec_ctrl; + /* + * Contains guest-controlled bits of VIRT_SPEC_CTRL, which will be + * translated into the appropriate L2_CFG bits on the host to + * perform speculative control. + */ + u64 virt_spec_ctrl; u32 *msrpm; @@ -1561,6 +1567,7 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) u32 eax = 1; svm->spec_ctrl = 0; + svm->virt_spec_ctrl = 0; if (!init_event) { svm->vcpu.arch.apic_base = APIC_DEFAULT_PHYS_BASE | @@ -4917,7 +4924,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) * is no need to worry about the conditional branch over the wrmsr * being speculatively taken. */ - x86_spec_ctrl_set_guest(svm->spec_ctrl); + x86_spec_ctrl_set_guest(svm->spec_ctrl, svm->virt_spec_ctrl); asm volatile ( "push %%" _ASM_BP "; \n\t" @@ -5041,7 +5048,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))) svm->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL); - x86_spec_ctrl_restore_host(svm->spec_ctrl); + x86_spec_ctrl_restore_host(svm->spec_ctrl, svm->virt_spec_ctrl); reload_tss(vcpu); diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 874b6615ddf5..f1d158a268a2 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -8916,9 +8916,10 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) * is no need to worry about the conditional branch over the wrmsr * being speculatively taken. */ - x86_spec_ctrl_set_guest(vmx->spec_ctrl); + x86_spec_ctrl_set_guest(vmx->spec_ctrl, 0); vmx->__launched = vmx->loaded_vmcs->launched; + asm( /* Store host registers */ "push %%" _ASM_DX "; push %%" _ASM_BP ";" @@ -9054,7 +9055,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))) vmx->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL); - x86_spec_ctrl_restore_host(vmx->spec_ctrl); + x86_spec_ctrl_restore_host(vmx->spec_ctrl, 0); /* Eliminate branch target predictions from guest mode */ vmexit_fill_RSB(); -- GitLab From 7c0b2dc44956533c5aac95f07575feef7b63344c Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Thu, 17 May 2018 17:09:18 +0200 Subject: [PATCH 415/855] x86/speculation: Add virtualized speculative store bypass disable support commit 11fb0683493b2da112cd64c9dada221b52463bf7 upstream Some AMD processors only support a non-architectural means of enabling speculative store bypass disable (SSBD). To allow a simplified view of this to a guest, an architectural definition has been created through a new CPUID bit, 0x80000008_EBX[25], and a new MSR, 0xc001011f. With this, a hypervisor can virtualize the existence of this definition and provide an architectural method for using SSBD to a guest. Add the new CPUID feature, the new MSR and update the existing SSBD support to use this MSR when present. Signed-off-by: Tom Lendacky Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/msr-index.h | 2 ++ arch/x86/kernel/cpu/bugs.c | 4 +++- arch/x86/kernel/process.c | 13 ++++++++++++- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index ec87b8caa9b9..c278f276c9b3 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -274,6 +274,7 @@ #define X86_FEATURE_AMD_IBPB (13*32+12) /* Indirect Branch Prediction Barrier */ #define X86_FEATURE_AMD_IBRS (13*32+14) /* Indirect Branch Restricted Speculation */ #define X86_FEATURE_AMD_STIBP (13*32+15) /* Single Thread Indirect Branch Predictors */ +#define X86_FEATURE_VIRT_SSBD (13*32+25) /* Virtualized Speculative Store Bypass Disable */ /* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */ #define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index b67d57eb4d0f..9fd9dcfe179e 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -323,6 +323,8 @@ #define MSR_AMD64_IBSOPDATA4 0xc001103d #define MSR_AMD64_IBS_REG_COUNT_MAX 8 /* includes MSR_AMD64_IBSBRTARGET */ +#define MSR_AMD64_VIRT_SPEC_CTRL 0xc001011f + /* Fam 17h MSRs */ #define MSR_F17H_IRPERF 0xc00000e9 diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index d00e246d4661..97987b53acbd 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -204,7 +204,9 @@ static void x86_amd_ssb_disable(void) { u64 msrval = x86_amd_ls_cfg_base | x86_amd_ls_cfg_ssbd_mask; - if (boot_cpu_has(X86_FEATURE_LS_CFG_SSBD)) + if (boot_cpu_has(X86_FEATURE_VIRT_SSBD)) + wrmsrl(MSR_AMD64_VIRT_SPEC_CTRL, SPEC_CTRL_SSBD); + else if (boot_cpu_has(X86_FEATURE_LS_CFG_SSBD)) wrmsrl(MSR_AMD64_LS_CFG, msrval); } diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 1e9d155544ee..6d9e1ee0f5b2 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -312,6 +312,15 @@ static __always_inline void amd_set_core_ssb_state(unsigned long tifn) } #endif +static __always_inline void amd_set_ssb_virt_state(unsigned long tifn) +{ + /* + * SSBD has the same definition in SPEC_CTRL and VIRT_SPEC_CTRL, + * so ssbd_tif_to_spec_ctrl() just works. + */ + wrmsrl(MSR_AMD64_VIRT_SPEC_CTRL, ssbd_tif_to_spec_ctrl(tifn)); +} + static __always_inline void intel_set_ssb_state(unsigned long tifn) { u64 msr = x86_spec_ctrl_base | ssbd_tif_to_spec_ctrl(tifn); @@ -321,7 +330,9 @@ static __always_inline void intel_set_ssb_state(unsigned long tifn) static __always_inline void __speculative_store_bypass_update(unsigned long tifn) { - if (static_cpu_has(X86_FEATURE_LS_CFG_SSBD)) + if (static_cpu_has(X86_FEATURE_VIRT_SSBD)) + amd_set_ssb_virt_state(tifn); + else if (static_cpu_has(X86_FEATURE_LS_CFG_SSBD)) amd_set_core_ssb_state(tifn); else intel_set_ssb_state(tifn); -- GitLab From b7b84401576d3858e9573d69d8287e182444f8e9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 10 May 2018 20:31:44 +0200 Subject: [PATCH 416/855] x86/speculation: Rework speculative_store_bypass_update() commit 0270be3e34efb05a88bc4c422572ece038ef3608 upstream The upcoming support for the virtual SPEC_CTRL MSR on AMD needs to reuse speculative_store_bypass_update() to avoid code duplication. Add an argument for supplying a thread info (TIF) value and create a wrapper speculative_store_bypass_update_current() which is used at the existing call site. Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/spec-ctrl.h | 7 ++++++- arch/x86/kernel/cpu/bugs.c | 2 +- arch/x86/kernel/process.c | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/spec-ctrl.h b/arch/x86/include/asm/spec-ctrl.h index 6e2874049afd..82b6c5a0d61e 100644 --- a/arch/x86/include/asm/spec-ctrl.h +++ b/arch/x86/include/asm/spec-ctrl.h @@ -42,6 +42,11 @@ extern void speculative_store_bypass_ht_init(void); static inline void speculative_store_bypass_ht_init(void) { } #endif -extern void speculative_store_bypass_update(void); +extern void speculative_store_bypass_update(unsigned long tif); + +static inline void speculative_store_bypass_update_current(void) +{ + speculative_store_bypass_update(current_thread_info()->flags); +} #endif diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 97987b53acbd..eddbdc843b3f 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -597,7 +597,7 @@ static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl) * mitigation until it is next scheduled. */ if (task == current && update) - speculative_store_bypass_update(); + speculative_store_bypass_update_current(); return 0; } diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 6d9e1ee0f5b2..00a9047539d7 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -338,10 +338,10 @@ static __always_inline void __speculative_store_bypass_update(unsigned long tifn intel_set_ssb_state(tifn); } -void speculative_store_bypass_update(void) +void speculative_store_bypass_update(unsigned long tif) { preempt_disable(); - __speculative_store_bypass_update(current_thread_info()->flags); + __speculative_store_bypass_update(tif); preempt_enable(); } -- GitLab From ea99935b633bd4766a679e51b173197c750fb00b Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sat, 12 May 2018 00:14:51 +0200 Subject: [PATCH 417/855] x86/bugs: Unify x86_spec_ctrl_{set_guest,restore_host} commit cc69b34989210f067b2c51d5539b5f96ebcc3a01 upstream Function bodies are very similar and are going to grow more almost identical code. Add a bool arg to determine whether SPEC_CTRL is being set for the guest or restored to the host. No functional changes. Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/spec-ctrl.h | 33 +++++++++++++++--- arch/x86/kernel/cpu/bugs.c | 60 ++++++++------------------------ 2 files changed, 44 insertions(+), 49 deletions(-) diff --git a/arch/x86/include/asm/spec-ctrl.h b/arch/x86/include/asm/spec-ctrl.h index 82b6c5a0d61e..9cecbe5e57ee 100644 --- a/arch/x86/include/asm/spec-ctrl.h +++ b/arch/x86/include/asm/spec-ctrl.h @@ -13,10 +13,35 @@ * Takes the guest view of SPEC_CTRL MSR as a parameter and also * the guest's version of VIRT_SPEC_CTRL, if emulated. */ -extern void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl, - u64 guest_virt_spec_ctrl); -extern void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl, - u64 guest_virt_spec_ctrl); +extern void x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool guest); + +/** + * x86_spec_ctrl_set_guest - Set speculation control registers for the guest + * @guest_spec_ctrl: The guest content of MSR_SPEC_CTRL + * @guest_virt_spec_ctrl: The guest controlled bits of MSR_VIRT_SPEC_CTRL + * (may get translated to MSR_AMD64_LS_CFG bits) + * + * Avoids writing to the MSR if the content/bits are the same + */ +static inline +void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl) +{ + x86_virt_spec_ctrl(guest_spec_ctrl, guest_virt_spec_ctrl, true); +} + +/** + * x86_spec_ctrl_restore_host - Restore host speculation control registers + * @guest_spec_ctrl: The guest content of MSR_SPEC_CTRL + * @guest_virt_spec_ctrl: The guest controlled bits of MSR_VIRT_SPEC_CTRL + * (may get translated to MSR_AMD64_LS_CFG bits) + * + * Avoids writing to the MSR if the content/bits are the same + */ +static inline +void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl) +{ + x86_virt_spec_ctrl(guest_spec_ctrl, guest_virt_spec_ctrl, false); +} /* AMD specific Speculative Store Bypass MSR data */ extern u64 x86_amd_ls_cfg_base; diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index eddbdc843b3f..92031508be01 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -150,55 +150,25 @@ u64 x86_spec_ctrl_get_default(void) } EXPORT_SYMBOL_GPL(x86_spec_ctrl_get_default); -/** - * x86_spec_ctrl_set_guest - Set speculation control registers for the guest - * @guest_spec_ctrl: The guest content of MSR_SPEC_CTRL - * @guest_virt_spec_ctrl: The guest controlled bits of MSR_VIRT_SPEC_CTRL - * (may get translated to MSR_AMD64_LS_CFG bits) - * - * Avoids writing to the MSR if the content/bits are the same - */ -void x86_spec_ctrl_set_guest(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl) +void +x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest) { - u64 host = x86_spec_ctrl_base; + struct thread_info *ti = current_thread_info(); + u64 msr, host = x86_spec_ctrl_base; /* Is MSR_SPEC_CTRL implemented ? */ - if (!static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) - return; - - /* SSBD controlled in MSR_SPEC_CTRL */ - if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD)) - host |= ssbd_tif_to_spec_ctrl(current_thread_info()->flags); - - if (host != guest_spec_ctrl) - wrmsrl(MSR_IA32_SPEC_CTRL, guest_spec_ctrl); -} -EXPORT_SYMBOL_GPL(x86_spec_ctrl_set_guest); - -/** - * x86_spec_ctrl_restore_host - Restore host speculation control registers - * @guest_spec_ctrl: The guest content of MSR_SPEC_CTRL - * @guest_virt_spec_ctrl: The guest controlled bits of MSR_VIRT_SPEC_CTRL - * (may get translated to MSR_AMD64_LS_CFG bits) - * - * Avoids writing to the MSR if the content/bits are the same - */ -void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl) -{ - u64 host = x86_spec_ctrl_base; - - /* Is MSR_SPEC_CTRL implemented ? */ - if (!static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) - return; - - /* SSBD controlled in MSR_SPEC_CTRL */ - if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD)) - host |= ssbd_tif_to_spec_ctrl(current_thread_info()->flags); - - if (host != guest_spec_ctrl) - wrmsrl(MSR_IA32_SPEC_CTRL, host); + if (static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) { + /* SSBD controlled in MSR_SPEC_CTRL */ + if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD)) + host |= ssbd_tif_to_spec_ctrl(ti->flags); + + if (host != guest_spec_ctrl) { + msr = setguest ? guest_spec_ctrl : host; + wrmsrl(MSR_IA32_SPEC_CTRL, msr); + } + } } -EXPORT_SYMBOL_GPL(x86_spec_ctrl_restore_host); +EXPORT_SYMBOL_GPL(x86_virt_spec_ctrl); static void x86_amd_ssb_disable(void) { -- GitLab From 599288ec9e20d9772e6e8a27aeae021f018c7336 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 12 May 2018 20:49:16 +0200 Subject: [PATCH 418/855] x86/bugs: Expose x86_spec_ctrl_base directly commit fa8ac4988249c38476f6ad678a4848a736373403 upstream x86_spec_ctrl_base is the system wide default value for the SPEC_CTRL MSR. x86_spec_ctrl_get_default() returns x86_spec_ctrl_base and was intended to prevent modification to that variable. Though the variable is read only after init and globaly visible already. Remove the function and export the variable instead. Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/nospec-branch.h | 16 +++++----------- arch/x86/include/asm/spec-ctrl.h | 3 --- arch/x86/kernel/cpu/bugs.c | 11 +---------- 3 files changed, 6 insertions(+), 24 deletions(-) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index bc258e644e5e..8d9deec00de9 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -217,16 +217,7 @@ enum spectre_v2_mitigation { SPECTRE_V2_IBRS, }; -/* - * The Intel specification for the SPEC_CTRL MSR requires that we - * preserve any already set reserved bits at boot time (e.g. for - * future additions that this kernel is not currently aware of). - * We then set any additional mitigation bits that we want - * ourselves and always use this as the base for SPEC_CTRL. - * We also use this when handling guest entry/exit as below. - */ extern void x86_spec_ctrl_set(u64); -extern u64 x86_spec_ctrl_get_default(void); /* The Speculative Store Bypass disable variants */ enum ssb_mitigation { @@ -278,6 +269,9 @@ static inline void indirect_branch_prediction_barrier(void) alternative_msr_write(MSR_IA32_PRED_CMD, val, X86_FEATURE_USE_IBPB); } +/* The Intel SPEC CTRL MSR base value cache */ +extern u64 x86_spec_ctrl_base; + /* * With retpoline, we must use IBRS to restrict branch prediction * before calling into firmware. @@ -286,7 +280,7 @@ static inline void indirect_branch_prediction_barrier(void) */ #define firmware_restrict_branch_speculation_start() \ do { \ - u64 val = x86_spec_ctrl_get_default() | SPEC_CTRL_IBRS; \ + u64 val = x86_spec_ctrl_base | SPEC_CTRL_IBRS; \ \ preempt_disable(); \ alternative_msr_write(MSR_IA32_SPEC_CTRL, val, \ @@ -295,7 +289,7 @@ do { \ #define firmware_restrict_branch_speculation_end() \ do { \ - u64 val = x86_spec_ctrl_get_default(); \ + u64 val = x86_spec_ctrl_base; \ \ alternative_msr_write(MSR_IA32_SPEC_CTRL, val, \ X86_FEATURE_USE_IBRS_FW); \ diff --git a/arch/x86/include/asm/spec-ctrl.h b/arch/x86/include/asm/spec-ctrl.h index 9cecbe5e57ee..763d49710329 100644 --- a/arch/x86/include/asm/spec-ctrl.h +++ b/arch/x86/include/asm/spec-ctrl.h @@ -47,9 +47,6 @@ void x86_spec_ctrl_restore_host(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl) extern u64 x86_amd_ls_cfg_base; extern u64 x86_amd_ls_cfg_ssbd_mask; -/* The Intel SPEC CTRL MSR base value cache */ -extern u64 x86_spec_ctrl_base; - static inline u64 ssbd_tif_to_spec_ctrl(u64 tifn) { BUILD_BUG_ON(TIF_SSBD < SPEC_CTRL_SSBD_SHIFT); diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 92031508be01..47b7f4f6b5ac 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -35,6 +35,7 @@ static void __init ssb_select_mitigation(void); * writes to SPEC_CTRL contain whatever reserved bits have been set. */ u64 __ro_after_init x86_spec_ctrl_base; +EXPORT_SYMBOL_GPL(x86_spec_ctrl_base); /* * The vendor and possibly platform specific bits which can be modified in @@ -140,16 +141,6 @@ void x86_spec_ctrl_set(u64 val) } EXPORT_SYMBOL_GPL(x86_spec_ctrl_set); -u64 x86_spec_ctrl_get_default(void) -{ - u64 msrval = x86_spec_ctrl_base; - - if (static_cpu_has(X86_FEATURE_SPEC_CTRL)) - msrval |= ssbd_tif_to_spec_ctrl(current_thread_info()->flags); - return msrval; -} -EXPORT_SYMBOL_GPL(x86_spec_ctrl_get_default); - void x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest) { -- GitLab From ec90464d96c50f90bfe1bde6dea748a6c962313c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 12 May 2018 20:53:14 +0200 Subject: [PATCH 419/855] x86/bugs: Remove x86_spec_ctrl_set() commit 4b59bdb569453a60b752b274ca61f009e37f4dae upstream x86_spec_ctrl_set() is only used in bugs.c and the extra mask checks there provide no real value as both call sites can just write x86_spec_ctrl_base to MSR_SPEC_CTRL. x86_spec_ctrl_base is valid and does not need any extra masking or checking. Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/nospec-branch.h | 2 -- arch/x86/kernel/cpu/bugs.c | 13 ++----------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 8d9deec00de9..8b38df98548e 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -217,8 +217,6 @@ enum spectre_v2_mitigation { SPECTRE_V2_IBRS, }; -extern void x86_spec_ctrl_set(u64); - /* The Speculative Store Bypass disable variants */ enum ssb_mitigation { SPEC_STORE_BYPASS_NONE, diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 47b7f4f6b5ac..82a99d00563e 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -132,15 +132,6 @@ static const char *spectre_v2_strings[] = { static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init = SPECTRE_V2_NONE; -void x86_spec_ctrl_set(u64 val) -{ - if (val & x86_spec_ctrl_mask) - WARN_ONCE(1, "SPEC_CTRL MSR value 0x%16llx is unknown.\n", val); - else - wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base | val); -} -EXPORT_SYMBOL_GPL(x86_spec_ctrl_set); - void x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest) { @@ -502,7 +493,7 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void) case X86_VENDOR_INTEL: x86_spec_ctrl_base |= SPEC_CTRL_SSBD; x86_spec_ctrl_mask &= ~SPEC_CTRL_SSBD; - x86_spec_ctrl_set(SPEC_CTRL_SSBD); + wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base); break; case X86_VENDOR_AMD: x86_amd_ssb_disable(); @@ -614,7 +605,7 @@ int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which) void x86_spec_ctrl_setup_ap(void) { if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) - x86_spec_ctrl_set(x86_spec_ctrl_base & ~x86_spec_ctrl_mask); + wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base); if (ssb_mode == SPEC_STORE_BYPASS_DISABLE) x86_amd_ssb_disable(); -- GitLab From 0ec827f974e198c609c2f258a5a1f11f9af48bb2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 12 May 2018 20:10:00 +0200 Subject: [PATCH 420/855] x86/bugs: Rework spec_ctrl base and mask logic commit be6fcb5478e95bb1c91f489121238deb3abca46a upstream x86_spec_ctrL_mask is intended to mask out bits from a MSR_SPEC_CTRL value which are not to be modified. However the implementation is not really used and the bitmask was inverted to make a check easier, which was removed in "x86/bugs: Remove x86_spec_ctrl_set()" Aside of that it is missing the STIBP bit if it is supported by the platform, so if the mask would be used in x86_virt_spec_ctrl() then it would prevent a guest from setting STIBP. Add the STIBP bit if supported and use the mask in x86_virt_spec_ctrl() to sanitize the value which is supplied by the guest. Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/bugs.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 82a99d00563e..2ae358668ab8 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -41,7 +41,7 @@ EXPORT_SYMBOL_GPL(x86_spec_ctrl_base); * The vendor and possibly platform specific bits which can be modified in * x86_spec_ctrl_base. */ -static u64 __ro_after_init x86_spec_ctrl_mask = ~SPEC_CTRL_IBRS; +static u64 __ro_after_init x86_spec_ctrl_mask = SPEC_CTRL_IBRS; /* * AMD specific MSR info for Speculative Store Bypass control. @@ -67,6 +67,10 @@ void __init check_bugs(void) if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) rdmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base); + /* Allow STIBP in MSR_SPEC_CTRL if supported */ + if (boot_cpu_has(X86_FEATURE_STIBP)) + x86_spec_ctrl_mask |= SPEC_CTRL_STIBP; + /* Select the proper spectre mitigation before patching alternatives */ spectre_v2_select_mitigation(); @@ -135,18 +139,26 @@ static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init = void x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest) { + u64 msrval, guestval, hostval = x86_spec_ctrl_base; struct thread_info *ti = current_thread_info(); - u64 msr, host = x86_spec_ctrl_base; /* Is MSR_SPEC_CTRL implemented ? */ if (static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) { + /* + * Restrict guest_spec_ctrl to supported values. Clear the + * modifiable bits in the host base value and or the + * modifiable bits from the guest value. + */ + guestval = hostval & ~x86_spec_ctrl_mask; + guestval |= guest_spec_ctrl & x86_spec_ctrl_mask; + /* SSBD controlled in MSR_SPEC_CTRL */ if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD)) - host |= ssbd_tif_to_spec_ctrl(ti->flags); + hostval |= ssbd_tif_to_spec_ctrl(ti->flags); - if (host != guest_spec_ctrl) { - msr = setguest ? guest_spec_ctrl : host; - wrmsrl(MSR_IA32_SPEC_CTRL, msr); + if (hostval != guestval) { + msrval = setguest ? guestval : hostval; + wrmsrl(MSR_IA32_SPEC_CTRL, msrval); } } } @@ -492,7 +504,7 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void) switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_INTEL: x86_spec_ctrl_base |= SPEC_CTRL_SSBD; - x86_spec_ctrl_mask &= ~SPEC_CTRL_SSBD; + x86_spec_ctrl_mask |= SPEC_CTRL_SSBD; wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base); break; case X86_VENDOR_AMD: -- GitLab From b0ef8c72b3d70505ba7fd72af6b1e3fc9b3ae9bc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 10 May 2018 20:42:48 +0200 Subject: [PATCH 421/855] x86/speculation, KVM: Implement support for VIRT_SPEC_CTRL/LS_CFG commit 47c61b3955cf712cadfc25635bf9bc174af030ea upstream Add the necessary logic for supporting the emulated VIRT_SPEC_CTRL MSR to x86_virt_spec_ctrl(). If either X86_FEATURE_LS_CFG_SSBD or X86_FEATURE_VIRT_SPEC_CTRL is set then use the new guest_virt_spec_ctrl argument to check whether the state must be modified on the host. The update reuses speculative_store_bypass_update() so the ZEN-specific sibling coordination can be reused. Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/spec-ctrl.h | 6 ++++++ arch/x86/kernel/cpu/bugs.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/arch/x86/include/asm/spec-ctrl.h b/arch/x86/include/asm/spec-ctrl.h index 763d49710329..ae7c2c5cd7f0 100644 --- a/arch/x86/include/asm/spec-ctrl.h +++ b/arch/x86/include/asm/spec-ctrl.h @@ -53,6 +53,12 @@ static inline u64 ssbd_tif_to_spec_ctrl(u64 tifn) return (tifn & _TIF_SSBD) >> (TIF_SSBD - SPEC_CTRL_SSBD_SHIFT); } +static inline unsigned long ssbd_spec_ctrl_to_tif(u64 spec_ctrl) +{ + BUILD_BUG_ON(TIF_SSBD < SPEC_CTRL_SSBD_SHIFT); + return (spec_ctrl & SPEC_CTRL_SSBD) << (TIF_SSBD - SPEC_CTRL_SSBD_SHIFT); +} + static inline u64 ssbd_tif_to_amd_ls_cfg(u64 tifn) { return (tifn & _TIF_SSBD) ? x86_amd_ls_cfg_ssbd_mask : 0ULL; diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 2ae358668ab8..86af9b1b049d 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -161,6 +161,36 @@ x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest) wrmsrl(MSR_IA32_SPEC_CTRL, msrval); } } + + /* + * If SSBD is not handled in MSR_SPEC_CTRL on AMD, update + * MSR_AMD64_L2_CFG or MSR_VIRT_SPEC_CTRL if supported. + */ + if (!static_cpu_has(X86_FEATURE_LS_CFG_SSBD) && + !static_cpu_has(X86_FEATURE_VIRT_SSBD)) + return; + + /* + * If the host has SSBD mitigation enabled, force it in the host's + * virtual MSR value. If its not permanently enabled, evaluate + * current's TIF_SSBD thread flag. + */ + if (static_cpu_has(X86_FEATURE_SPEC_STORE_BYPASS_DISABLE)) + hostval = SPEC_CTRL_SSBD; + else + hostval = ssbd_tif_to_spec_ctrl(ti->flags); + + /* Sanitize the guest value */ + guestval = guest_virt_spec_ctrl & SPEC_CTRL_SSBD; + + if (hostval != guestval) { + unsigned long tif; + + tif = setguest ? ssbd_spec_ctrl_to_tif(guestval) : + ssbd_spec_ctrl_to_tif(hostval); + + speculative_store_bypass_update(tif); + } } EXPORT_SYMBOL_GPL(x86_virt_spec_ctrl); -- GitLab From b965592a07a248ef254d9d421bd34a6b548db21f Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Thu, 10 May 2018 22:06:39 +0200 Subject: [PATCH 422/855] KVM: SVM: Implement VIRT_SPEC_CTRL support for SSBD commit bc226f07dcd3c9ef0b7f6236fe356ea4a9cb4769 upstream Expose the new virtualized architectural mechanism, VIRT_SSBD, for using speculative store bypass disable (SSBD) under SVM. This will allow guests to use SSBD on hardware that uses non-architectural mechanisms for enabling SSBD. [ tglx: Folded the migration fixup from Paolo Bonzini ] Signed-off-by: Tom Lendacky Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kernel/cpu/common.c | 3 ++- arch/x86/kvm/cpuid.c | 11 +++++++++-- arch/x86/kvm/cpuid.h | 9 +++++++++ arch/x86/kvm/svm.c | 21 +++++++++++++++++++-- arch/x86/kvm/vmx.c | 18 +++++++++++++++--- arch/x86/kvm/x86.c | 13 ++++--------- 7 files changed, 59 insertions(+), 18 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 20cfeeb681c6..7598a6c26f76 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -864,7 +864,7 @@ struct kvm_x86_ops { int (*hardware_setup)(void); /* __init */ void (*hardware_unsetup)(void); /* __exit */ bool (*cpu_has_accelerated_tpr)(void); - bool (*cpu_has_high_real_mode_segbase)(void); + bool (*has_emulated_msr)(int index); void (*cpuid_update)(struct kvm_vcpu *vcpu); int (*vm_init)(struct kvm *kvm); diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 945e84105f8d..40fc748f60f6 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -735,7 +735,8 @@ static void init_speculation_control(struct cpuinfo_x86 *c) if (cpu_has(c, X86_FEATURE_INTEL_STIBP)) set_cpu_cap(c, X86_FEATURE_STIBP); - if (cpu_has(c, X86_FEATURE_SPEC_CTRL_SSBD)) + if (cpu_has(c, X86_FEATURE_SPEC_CTRL_SSBD) || + cpu_has(c, X86_FEATURE_VIRT_SSBD)) set_cpu_cap(c, X86_FEATURE_SSBD); if (cpu_has(c, X86_FEATURE_AMD_IBRS)) { diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 910c2dbb38de..a69f18d4676c 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -357,7 +357,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, /* cpuid 0x80000008.ebx */ const u32 kvm_cpuid_8000_0008_ebx_x86_features = - F(AMD_IBPB) | F(AMD_IBRS); + F(AMD_IBPB) | F(AMD_IBRS) | F(VIRT_SSBD); /* cpuid 0xC0000001.edx */ const u32 kvm_cpuid_C000_0001_edx_x86_features = @@ -618,13 +618,20 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, g_phys_as = phys_as; entry->eax = g_phys_as | (virt_as << 8); entry->edx = 0; - /* IBRS and IBPB aren't necessarily present in hardware cpuid */ + /* + * IBRS, IBPB and VIRT_SSBD aren't necessarily present in + * hardware cpuid + */ if (boot_cpu_has(X86_FEATURE_AMD_IBPB)) entry->ebx |= F(AMD_IBPB); if (boot_cpu_has(X86_FEATURE_AMD_IBRS)) entry->ebx |= F(AMD_IBRS); + if (boot_cpu_has(X86_FEATURE_VIRT_SSBD)) + entry->ebx |= F(VIRT_SSBD); entry->ebx &= kvm_cpuid_8000_0008_ebx_x86_features; cpuid_mask(&entry->ebx, CPUID_8000_0008_EBX); + if (boot_cpu_has(X86_FEATURE_LS_CFG_SSBD)) + entry->ebx |= F(VIRT_SSBD); break; } case 0x80000019: diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index eb47c37db15f..c38369781239 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -190,6 +190,15 @@ static inline bool guest_cpuid_has_arch_capabilities(struct kvm_vcpu *vcpu) return best && (best->edx & bit(X86_FEATURE_ARCH_CAPABILITIES)); } +static inline bool guest_cpuid_has_virt_ssbd(struct kvm_vcpu *vcpu) +{ + struct kvm_cpuid_entry2 *best; + + best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0); + return best && (best->ebx & bit(X86_FEATURE_VIRT_SSBD)); +} + + /* * NRIPS is provided through cpuidfn 0x8000000a.edx bit 3 diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 57c96f165ac4..a27f9e442ffc 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -3557,6 +3557,13 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = svm->spec_ctrl; break; + case MSR_AMD64_VIRT_SPEC_CTRL: + if (!msr_info->host_initiated && + !guest_cpuid_has_virt_ssbd(vcpu)) + return 1; + + msr_info->data = svm->virt_spec_ctrl; + break; case MSR_IA32_UCODE_REV: msr_info->data = 0x01000065; break; @@ -3691,6 +3698,16 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) break; set_msr_interception(svm->msrpm, MSR_IA32_PRED_CMD, 0, 1); break; + case MSR_AMD64_VIRT_SPEC_CTRL: + if (!msr->host_initiated && + !guest_cpuid_has_virt_ssbd(vcpu)) + return 1; + + if (data & ~SPEC_CTRL_SSBD) + return 1; + + svm->virt_spec_ctrl = data; + break; case MSR_STAR: svm->vmcb->save.star = data; break; @@ -5150,7 +5167,7 @@ static bool svm_cpu_has_accelerated_tpr(void) return false; } -static bool svm_has_high_real_mode_segbase(void) +static bool svm_has_emulated_msr(int index) { return true; } @@ -5467,7 +5484,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = { .hardware_enable = svm_hardware_enable, .hardware_disable = svm_hardware_disable, .cpu_has_accelerated_tpr = svm_cpu_has_accelerated_tpr, - .cpu_has_high_real_mode_segbase = svm_has_high_real_mode_segbase, + .has_emulated_msr = svm_has_emulated_msr, .vcpu_create = svm_create_vcpu, .vcpu_free = svm_free_vcpu, diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index f1d158a268a2..d92523afb425 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -8691,9 +8691,21 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu) } } -static bool vmx_has_high_real_mode_segbase(void) +static bool vmx_has_emulated_msr(int index) { - return enable_unrestricted_guest || emulate_invalid_guest_state; + switch (index) { + case MSR_IA32_SMBASE: + /* + * We cannot do SMM unless we can run the guest in big + * real mode. + */ + return enable_unrestricted_guest || emulate_invalid_guest_state; + case MSR_AMD64_VIRT_SPEC_CTRL: + /* This is AMD only. */ + return false; + default: + return true; + } } static bool vmx_mpx_supported(void) @@ -11346,7 +11358,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = { .hardware_enable = hardware_enable, .hardware_disable = hardware_disable, .cpu_has_accelerated_tpr = report_flexpriority, - .cpu_has_high_real_mode_segbase = vmx_has_high_real_mode_segbase, + .has_emulated_msr = vmx_has_emulated_msr, .vcpu_create = vmx_create_vcpu, .vcpu_free = vmx_free_vcpu, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3aaaf305420d..a0cb85f30c94 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1002,6 +1002,7 @@ static u32 emulated_msrs[] = { MSR_IA32_MCG_CTL, MSR_IA32_MCG_EXT_CTL, MSR_IA32_SMBASE, + MSR_AMD64_VIRT_SPEC_CTRL, }; static unsigned num_emulated_msrs; @@ -2664,7 +2665,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) * fringe case that is not enabled except via specific settings * of the module parameters. */ - r = kvm_x86_ops->cpu_has_high_real_mode_segbase(); + r = kvm_x86_ops->has_emulated_msr(MSR_IA32_SMBASE); break; case KVM_CAP_COALESCED_MMIO: r = KVM_COALESCED_MMIO_PAGE_OFFSET; @@ -4226,14 +4227,8 @@ static void kvm_init_msr_list(void) num_msrs_to_save = j; for (i = j = 0; i < ARRAY_SIZE(emulated_msrs); i++) { - switch (emulated_msrs[i]) { - case MSR_IA32_SMBASE: - if (!kvm_x86_ops->cpu_has_high_real_mode_segbase()) - continue; - break; - default: - break; - } + if (!kvm_x86_ops->has_emulated_msr(emulated_msrs[i])) + continue; if (j < i) emulated_msrs[j] = emulated_msrs[i]; -- GitLab From 3394ef1a7efc08e3c185ac2446f06284847ccb37 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 16 May 2018 23:18:09 -0400 Subject: [PATCH 423/855] x86/bugs: Rename SSBD_NO to SSB_NO commit 240da953fcc6a9008c92fae5b1f727ee5ed167ab upstream The "336996 Speculative Execution Side Channel Mitigations" from May defines this as SSB_NO, hence lets sync-up. Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/msr-index.h | 2 +- arch/x86/kernel/cpu/common.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 9fd9dcfe179e..1ec13e253174 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -63,7 +63,7 @@ #define MSR_IA32_ARCH_CAPABILITIES 0x0000010a #define ARCH_CAP_RDCL_NO (1 << 0) /* Not susceptible to Meltdown */ #define ARCH_CAP_IBRS_ALL (1 << 1) /* Enhanced IBRS support */ -#define ARCH_CAP_SSBD_NO (1 << 4) /* +#define ARCH_CAP_SSB_NO (1 << 4) /* * Not susceptible to Speculative Store Bypass * attack, so no Speculative Store Bypass * control required. diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 40fc748f60f6..b0fd028b2eee 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -926,7 +926,7 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) rdmsrl(MSR_IA32_ARCH_CAPABILITIES, ia32_cap); if (!x86_match_cpu(cpu_no_spec_store_bypass) && - !(ia32_cap & ARCH_CAP_SSBD_NO)) + !(ia32_cap & ARCH_CAP_SSB_NO)) setup_force_cpu_bug(X86_BUG_SPEC_STORE_BYPASS); if (x86_match_cpu(cpu_no_speculation)) -- GitLab From 2272cdd5d5bf42e3721430ae6076656a42043c34 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 22 May 2018 16:58:04 +0200 Subject: [PATCH 424/855] Linux 4.9.102 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7d7bda23db8f..d84c39c290f7 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 101 +SUBLEVEL = 102 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 21e74a4cede0cd2122244327beba6ea893a2cd12 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Tue, 22 May 2018 11:41:31 -0700 Subject: [PATCH 425/855] ANDROID: build: cuttlefish: Fix path to clang. Reconcile with changes made to the kernel manifest. Clang must come from master because it was not usable for kernel builds in older branches of the Android platform. Bug: 63889157 Change-Id: Id0a080fc2f1cba495f37f26afa48e43e736b756a Signed-off-by: Alistair Strachan --- build.config.cuttlefish.x86_64 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64 index edfa1506dcff..fad1c3faad72 100644 --- a/build.config.cuttlefish.x86_64 +++ b/build.config.cuttlefish.x86_64 @@ -6,7 +6,7 @@ DEFCONFIG=x86_64_cuttlefish_defconfig EXTRA_CMDS='' KERNEL_DIR=common POST_DEFCONFIG_CMDS="check_defconfig" -CLANG_PREBUILT_BIN=prebuilts/clang/host/linux-x86/clang-4630689/bin +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-4630689/bin LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin FILES=" arch/x86/boot/bzImage -- GitLab From 666be3144d5dcd9e124ffc5b0674c001bc69c71c Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Tue, 22 May 2018 16:09:23 -0700 Subject: [PATCH 426/855] ANDROID: build: cuttlefish: Upgrade clang to newer version. Use the same clang version as hikey-linaro. Bug: 63889157 Change-Id: I6932d6149642d429086207e63aa8a8d5c2afd6f7 Signed-off-by: Alistair Strachan --- build.config.cuttlefish.x86_64 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64 index fad1c3faad72..ee340b499dea 100644 --- a/build.config.cuttlefish.x86_64 +++ b/build.config.cuttlefish.x86_64 @@ -6,7 +6,7 @@ DEFCONFIG=x86_64_cuttlefish_defconfig EXTRA_CMDS='' KERNEL_DIR=common POST_DEFCONFIG_CMDS="check_defconfig" -CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-4630689/bin +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-4679922/bin LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin FILES=" arch/x86/boot/bzImage -- GitLab From d054505522c4d242109ecf3d505e7079f72a200c Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Tue, 22 May 2018 18:01:41 -0700 Subject: [PATCH 427/855] ANDROID: build: cuttlefish: Upgrade clang to newer version. The last upgrade introduced a new build failure, because it had a bug which caused it to emit PLT relocations, certain types of which cannot be handled by the reloc tool in the kernel. See https://bugs.llvm.org/show_bug.cgi?id=36674 for more details. Bug: 63889157 Change-Id: I813febdbacb0579abcb12dc7f2164cce1e2f5a26 Signed-off-by: Alistair Strachan --- build.config.cuttlefish.x86_64 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64 index ee340b499dea..8d56143c17c0 100644 --- a/build.config.cuttlefish.x86_64 +++ b/build.config.cuttlefish.x86_64 @@ -6,7 +6,7 @@ DEFCONFIG=x86_64_cuttlefish_defconfig EXTRA_CMDS='' KERNEL_DIR=common POST_DEFCONFIG_CMDS="check_defconfig" -CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-4679922/bin +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r328903/bin LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin FILES=" arch/x86/boot/bzImage -- GitLab From c5aceac71b68f388cb011a8dc395943c5b083519 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Tue, 22 May 2018 17:38:34 -0700 Subject: [PATCH 428/855] x86: vdso: Fix leaky vdso linker with CC=clang. The vdso{32,64}.so can fail to build when CC=clang when clang tries to find a suitable GCC toolchain to link these libraries with. /usr/bin/ld: arch/x86/entry/vdso/vclock_gettime.o: access beyond end of merged section (782) This happens because the host environment leaked into the CROSS_COMPILE environment due to the way clang searches for suitable GCC toolchains. Most of the time this goes unnoticed because the host linker is new enough to work anyway, but on this particular machine it was not. Extract the needed --target and --gcc-toolchain flags added in the top level Makefile from KBUILD_CFLAGS. Bug: 63889157 Change-Id: If7d4097d1d2eaf95f18d0295483bde8792a06844 Signed-off-by: Alistair Strachan --- arch/x86/entry/vdso/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index d5409660f5de..51a858ea9158 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -171,7 +171,8 @@ quiet_cmd_vdso = VDSO $@ sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@' VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=both) \ - $(call cc-ldoption, -Wl$(comma)--build-id) -Wl,-Bsymbolic $(LTO_CFLAGS) + $(call cc-ldoption, -Wl$(comma)--build-id) -Wl,-Bsymbolic $(LTO_CFLAGS) \ + $(filter --target=% --gcc-toolchain=%,$(KBUILD_CFLAGS)) GCOV_PROFILE := n # -- GitLab From 01ea431593299770ff44867fe029c087eba6c373 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Wed, 2 May 2018 12:32:38 +0530 Subject: [PATCH 429/855] ARM: dts: msm: Update GPU wake-up freq. to 430MHz for QCS605 Set GPU wake-up frequency to 430MHz for GPU 700MHz and 780MHz clock plan. This is needed to resolve GPU first frame rendering time performance issues. Change-Id: I41c2ebba075f15f8f424f7f7d757ed2a2e707fdb Signed-off-by: Deepak Kumar --- arch/arm64/boot/dts/qcom/qcs605.dtsi | 272 +++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi index 747593f87f88..16ae8de73bf8 100644 --- a/arch/arm64/boot/dts/qcom/qcs605.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi @@ -108,4 +108,276 @@ &msm_gpu { /delete-node/qcom,gpu-mempools; + /delete-node/qcom,gpu-pwrlevel-bins; + + qcom,gpu-pwrlevel-bins { + #address-cells = <1>; + #size-cells = <0>; + + compatible="qcom,gpu-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + + qcom,initial-pwrlevel = <4>; + qcom,ca-target-pwrlevel = <5>; + + /* TURBO_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <780000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* TURBO */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <750000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <565000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <430000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <355000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <267000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <4>; + qcom,bus-max = <7>; + }; + + /* MIN SVS */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <180000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <4>; + }; + + /* XO */ + qcom,gpu-pwrlevel@8 { + reg = <8>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <146>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <4>; + + /* TURBO */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <700000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <565000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <430000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <355000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <267000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <4>; + qcom,bus-max = <7>; + }; + + /* MIN SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <180000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <4>; + }; + + /* XO */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <163>; + + qcom,initial-pwrlevel = <4>; + qcom,ca-target-pwrlevel = <5>; + + /* TURBO_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <780000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* TURBO */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <750000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <565000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <430000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <355000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <267000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <4>; + qcom,bus-max = <7>; + }; + + /* MIN SVS */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <180000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <4>; + }; + + /* XO */ + qcom,gpu-pwrlevel@8 { + reg = <8>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; }; -- GitLab From d2225bc91de4386a28540e1f99ee198cf67baa05 Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Wed, 28 Mar 2018 11:46:23 -0700 Subject: [PATCH 430/855] drm/msm: atomic seamless connector change Handle dynamic connector attach or detach of additional connector on crtc. Avoid full modeset disable and enable if multiple connectors connected to single CRTC. It allows seamless handling of usecase like concurrent writeback. Attempt to keep existing seamless mode checks intact. CRs-Fixed: 2232050 Change-Id: Ia8ab0ef27400f2ba08a7d2dc6984820f3c956231 Signed-off-by: Prabhanjan Kandula --- drivers/gpu/drm/msm/msm_atomic.c | 96 ++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 95bdc3624767..8ffe0449f712 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2014 Red Hat * Author: Rob Clark * @@ -25,6 +25,8 @@ #include "msm_fence.h" #include "sde_trace.h" +#define MULTIPLE_CONN_DETECTED(x) (x > 1) + struct msm_commit { struct drm_device *dev; struct drm_atomic_state *state; @@ -111,6 +113,66 @@ static void commit_destroy(struct msm_commit *c) kfree(c); } +static inline bool _msm_seamless_for_crtc(struct drm_atomic_state *state, + struct drm_crtc_state *crtc_state, bool enable) +{ + struct drm_connector *connector = NULL; + struct drm_connector_state *conn_state = NULL; + int i = 0; + int conn_cnt = 0; + + if (msm_is_mode_seamless(&crtc_state->mode) || + msm_is_mode_seamless_vrr(&crtc_state->adjusted_mode)) + return true; + + if (msm_is_mode_seamless_dms(&crtc_state->adjusted_mode) && !enable) + return true; + + if (!crtc_state->mode_changed && crtc_state->connectors_changed) { + for_each_connector_in_state(state, connector, conn_state, i) { + if ((conn_state->crtc == crtc_state->crtc) || + (connector->state->crtc == + crtc_state->crtc)) + conn_cnt++; + + if (MULTIPLE_CONN_DETECTED(conn_cnt)) + return true; + } + } + + return false; +} + +static inline bool _msm_seamless_for_conn(struct drm_connector *connector, + struct drm_connector_state *old_conn_state, bool enable) +{ + if (!old_conn_state || !old_conn_state->crtc) + return false; + + if (!old_conn_state->crtc->state->mode_changed && + !old_conn_state->crtc->state->active_changed && + old_conn_state->crtc->state->connectors_changed) { + if (old_conn_state->crtc == connector->state->crtc) + return true; + } + + if (enable) + return false; + + if (msm_is_mode_seamless(&connector->encoder->crtc->state->mode)) + return true; + + if (msm_is_mode_seamless_vrr( + &connector->encoder->crtc->state->adjusted_mode)) + return true; + + if (msm_is_mode_seamless_dms( + &connector->encoder->crtc->state->adjusted_mode)) + return true; + + return false; +} + static void msm_atomic_wait_for_commit_done( struct drm_device *dev, struct drm_atomic_state *old_state) @@ -174,14 +236,7 @@ msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) if (WARN_ON(!encoder)) continue; - if (msm_is_mode_seamless( - &connector->encoder->crtc->state->mode) || - msm_is_mode_seamless_vrr( - &connector->encoder->crtc->state->adjusted_mode)) - continue; - - if (msm_is_mode_seamless_dms( - &connector->encoder->crtc->state->adjusted_mode)) + if (_msm_seamless_for_conn(connector, old_conn_state, false)) continue; funcs = encoder->helper_private; @@ -223,11 +278,7 @@ msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) if (!old_crtc_state->active) continue; - if (msm_is_mode_seamless(&crtc->state->mode) || - msm_is_mode_seamless_vrr(&crtc->state->adjusted_mode)) - continue; - - if (msm_is_mode_seamless_dms(&crtc->state->adjusted_mode)) + if (_msm_seamless_for_crtc(old_state, crtc->state, false)) continue; funcs = crtc->helper_private; @@ -286,8 +337,14 @@ msm_crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) mode = &new_crtc_state->mode; adjusted_mode = &new_crtc_state->adjusted_mode; - if (!new_crtc_state->mode_changed) + if (!new_crtc_state->mode_changed && + new_crtc_state->connectors_changed) { + if (_msm_seamless_for_conn(connector, + old_conn_state, false)) + continue; + } else if (!new_crtc_state->mode_changed) { continue; + } DRM_DEBUG_ATOMIC("modeset on [ENCODER:%d:%s]\n", encoder->base.id, encoder->name); @@ -365,8 +422,7 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev, if (!crtc->state->active) continue; - if (msm_is_mode_seamless(&crtc->state->mode) || - msm_is_mode_seamless_vrr(&crtc->state->adjusted_mode)) + if (_msm_seamless_for_crtc(old_state, crtc->state, true)) continue; funcs = crtc->helper_private; @@ -397,6 +453,9 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev, connector->state->crtc->state)) continue; + if (_msm_seamless_for_conn(connector, old_conn_state, true)) + continue; + encoder = connector->state->best_encoder; funcs = encoder->helper_private; @@ -444,6 +503,9 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev, connector->state->crtc->state)) continue; + if (_msm_seamless_for_conn(connector, old_conn_state, true)) + continue; + encoder = connector->state->best_encoder; DRM_DEBUG_ATOMIC("bridge enable enabling [ENCODER:%d:%s]\n", -- GitLab From 699fbd96fd8c6b73a57364b8f561918db8702df1 Mon Sep 17 00:00:00 2001 From: Suraj Dongre Date: Wed, 16 May 2018 11:35:49 -0700 Subject: [PATCH 431/855] msm: camera: jpeg flush function cleanup Remove duplicate code to deregister IRQ callback Change-Id: Ib05ecfa38c172895bdc95b6ea5413be666122c55 Signed-off-by: Suraj Dongre --- .../platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index f172a797e5b3..97d076a78c04 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -770,13 +770,6 @@ static int cam_jpeg_mgr_flush(void *hw_mgr_priv, } else { CAM_ERR(CAM_JPEG, "process_cmd null "); } - rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd( - hw_mgr->devices[dev_type][0]->hw_priv, - CAM_JPEG_CMD_SET_IRQ_CB, - &irq_cb, sizeof(irq_cb)); - if (rc) - CAM_ERR(CAM_JPEG, - "CMD_SET_IRQ_CB failed %d", rc); if (hw_mgr->devices[dev_type][0]->hw_ops.stop) { rc = hw_mgr->devices[dev_type][0]->hw_ops.stop( -- GitLab From 2e35bed46b507e1b816866637c1cb2e4bda610ee Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 23 May 2018 13:00:23 -0700 Subject: [PATCH 432/855] ANDROID: proc: fix undefined behavior in proc_uid_base_readdir When uid_base_stuff has no entries, proc_uid_base_readdir tries to compute an address before the start of the array. Revise this check to use uid_base_stuff + nents instead, which makes the code valid regardless of array size. Bug: 80158484 Test: No more compiler warning with CONFIG_CPU_FREQ_TIMES=n Change-Id: I6e55b27c3ba8210cee194f6d27bbd62c0b263796 Signed-off-by: Connor O'Brien --- fs/proc/uid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/proc/uid.c b/fs/proc/uid.c index 3fd7b9fe974e..b2bb08509212 100644 --- a/fs/proc/uid.c +++ b/fs/proc/uid.c @@ -174,7 +174,7 @@ static int proc_uid_base_readdir(struct file *file, struct dir_context *ctx) return 0; for (u = uid_base_stuff + (ctx->pos - 2); - u <= uid_base_stuff + nents - 1; u++) { + u < uid_base_stuff + nents; u++) { if (!proc_fill_cache(file, ctx, u->name, u->len, proc_uident_instantiate, NULL, u)) break; -- GitLab From 212cec77dc850555062b254416a65a3f6a0cc9b7 Mon Sep 17 00:00:00 2001 From: Animesh Kishore Date: Thu, 3 May 2018 15:28:59 +0530 Subject: [PATCH 433/855] ARM: dts: msm: Fix vbif OT read limit for sdm439 Configure MDSS max number of pending reads from AXI as provided by QoS settings. Change-Id: Ia9bb709da65c1e24854f141e45900e6016360cdf Signed-off-by: Animesh Kishore --- arch/arm64/boot/dts/qcom/sdm439.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi index 0e4f6666462f..3c1cb5075e28 100644 --- a/arch/arm64/boot/dts/qcom/sdm439.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi @@ -622,3 +622,7 @@ }; }; }; + +&mdss_mdp { + qcom,vbif-settings = <0xd0 0x20>; +}; -- GitLab From 1004530b7075d1f3ce1c3e38f8897b68898354d1 Mon Sep 17 00:00:00 2001 From: Manapragada Sai Date: Thu, 24 May 2018 12:56:30 +0530 Subject: [PATCH 434/855] defconfig: msm: Enable CPUSETS config for msm8953 and SDM632 targets CONFIG_CPUSETS is required for 4.9 kernel on msm8953 and SDM632 targets. Change-Id: I371e3a3b4c5f2c3d710a0f54c6ebdc794d335b7d Signed-off-by: Manapragada Sai --- arch/arm/configs/msm8953-perf_defconfig | 1 + arch/arm/configs/msm8953_defconfig | 1 + arch/arm64/configs/msm8953-perf_defconfig | 1 + arch/arm64/configs/msm8953_defconfig | 1 + 4 files changed, 4 insertions(+) diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index aa557b0aeb73..88e5e228444f 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -17,6 +17,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index f38341ddfb33..adee9a59c051 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -18,6 +18,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig index f0ced733d528..af10015c055f 100644 --- a/arch/arm64/configs/msm8953-perf_defconfig +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -18,6 +18,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index 733ac6991dcb..a754e2f462a1 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -19,6 +19,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y -- GitLab From 0cc8d50d6b854912df879cc1a1738240f2768058 Mon Sep 17 00:00:00 2001 From: Vikas Reddy Pachika Date: Fri, 13 Apr 2018 20:55:58 +0530 Subject: [PATCH 435/855] msm: vidc_3x: add support to enable frame average QP Add support to enable frame average QP in encoder output extra data. Change-Id: Ibebf59ccf8830729c7303bd54644dca8fdd03345 Signed-off-by: Vikas Reddy Pachika --- drivers/media/platform/msm/vidc_3x/hfi_packetization.c | 5 ++++- drivers/media/platform/msm/vidc_3x/msm_venc.c | 6 ++++-- drivers/media/platform/msm/vidc_3x/msm_vidc_common.c | 9 +++++++-- drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h | 2 +- drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h | 3 ++- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/msm/vidc_3x/hfi_packetization.c b/drivers/media/platform/msm/vidc_3x/hfi_packetization.c index b15baaa5d298..1de5bd1c4310 100644 --- a/drivers/media/platform/msm/vidc_3x/hfi_packetization.c +++ b/drivers/media/platform/msm/vidc_3x/hfi_packetization.c @@ -658,9 +658,12 @@ static int get_hfi_extradata_index(enum hal_extradata_id index) case HAL_EXTRADATA_STREAM_USERDATA: ret = HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA; break; - case HAL_EXTRADATA_FRAME_QP: + case HAL_EXTRADATA_DEC_FRAME_QP: ret = HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA; break; + case HAL_EXTRADATA_ENC_FRAME_QP: + ret = HFI_PROPERTY_PARAM_VENC_FRAME_QP_EXTRADATA; + break; case HAL_EXTRADATA_FRAME_BITS_INFO: ret = HFI_PROPERTY_PARAM_VDEC_FRAME_BITS_INFO_EXTRADATA; break; diff --git a/drivers/media/platform/msm/vidc_3x/msm_venc.c b/drivers/media/platform/msm/vidc_3x/msm_venc.c index d129dc24cb1a..ef6e3606404f 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_venc.c +++ b/drivers/media/platform/msm/vidc_3x/msm_venc.c @@ -823,7 +823,7 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .name = "Extradata Type", .type = V4L2_CTRL_TYPE_MENU, .minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE, - .maximum = V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO, + .maximum = V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP, .default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE, .menu_skip_mask = ~( (1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) | @@ -846,7 +846,8 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { (1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI) | (1 << V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS)| (1 << V4L2_MPEG_VIDC_EXTRADATA_ROI_QP) | - (1 << V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO) + (1 << V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO) | + (1ULL << V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP) ), .qmenu = mpeg_video_vidc_extradata, }, @@ -1564,6 +1565,7 @@ static void msm_venc_update_plane_count(struct msm_vidc_inst *inst, int type) case V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB: case V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER: case V4L2_MPEG_VIDC_EXTRADATA_LTR: + case V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP: case V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI: inst->fmts[CAPTURE_PORT].num_planes = 2; default: diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c index bd5811750082..502a5c74bdfb 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c @@ -77,9 +77,11 @@ const char *const mpeg_video_vidc_extradata[] = { "Extradata output crop", "Extradata display colour SEI", "Extradata light level SEI", + "Extradata PQ Info", "Extradata display VUI", "Extradata vpx color space", - "Extradata PQ Info", + "Extradata UBWC CR stats info", + "Extradata enc frame QP" }; struct getprop_buf { @@ -4727,7 +4729,10 @@ enum hal_extradata_id msm_comm_get_hal_extradata_index( ret = HAL_EXTRADATA_STREAM_USERDATA; break; case V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP: - ret = HAL_EXTRADATA_FRAME_QP; + ret = HAL_EXTRADATA_DEC_FRAME_QP; + break; + case V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP: + ret = HAL_EXTRADATA_ENC_FRAME_QP; break; case V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO: ret = HAL_EXTRADATA_FRAME_BITS_INFO; diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h index 93368f652e16..c7eb5f136382 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h @@ -316,7 +316,7 @@ struct msm_vidc_ctrl { s32 maximum; s32 default_value; u32 step; - u32 menu_skip_mask; + u64 menu_skip_mask; u32 flags; const char * const *qmenu; }; diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h index 1a25a58f1032..875db097d9b2 100644 --- a/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h @@ -112,7 +112,8 @@ enum hal_extradata_id { HAL_EXTRADATA_ASPECT_RATIO, HAL_EXTRADATA_MPEG2_SEQDISP, HAL_EXTRADATA_STREAM_USERDATA, - HAL_EXTRADATA_FRAME_QP, + HAL_EXTRADATA_DEC_FRAME_QP, + HAL_EXTRADATA_ENC_FRAME_QP, HAL_EXTRADATA_FRAME_BITS_INFO, HAL_EXTRADATA_INPUT_CROP, HAL_EXTRADATA_DIGITAL_ZOOM, -- GitLab From 607a42d9dbbc4588ae0dd9f791e3c4a1d5d68118 Mon Sep 17 00:00:00 2001 From: Lynus Vaz Date: Wed, 23 May 2018 20:26:51 +0530 Subject: [PATCH 436/855] msm: kgsl: Correct the iommu protection ranges The iommu protection range was not set correctly to the range set in the dt files. Change-Id: I9c1e4cd6aba8b555ca0714299e919acffd4aaa17 Signed-off-by: Lynus Vaz --- drivers/gpu/msm/adreno_a3xx.c | 4 ++-- drivers/gpu/msm/adreno_a4xx.c | 4 ++-- drivers/gpu/msm/adreno_a5xx.c | 2 +- drivers/gpu/msm/adreno_a6xx.c | 2 +- drivers/gpu/msm/kgsl_iommu.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index e5c82220175e..4f9891278118 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1332,7 +1332,7 @@ static void a3xx_protect_init(struct adreno_device *adreno_dev) iommu_regs = kgsl_mmu_get_prot_regs(&device->mmu); if (iommu_regs) adreno_set_protected_registers(adreno_dev, &index, - iommu_regs->base, iommu_regs->range); + iommu_regs->base, ilog2(iommu_regs->range)); } static void a3xx_start(struct adreno_device *adreno_dev) diff --git a/drivers/gpu/msm/adreno_a4xx.c b/drivers/gpu/msm/adreno_a4xx.c index 771d035875a0..432e98dbed94 100644 --- a/drivers/gpu/msm/adreno_a4xx.c +++ b/drivers/gpu/msm/adreno_a4xx.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -524,7 +524,7 @@ static void a4xx_protect_init(struct adreno_device *adreno_dev) iommu_regs = kgsl_mmu_get_prot_regs(&device->mmu); if (iommu_regs) adreno_set_protected_registers(adreno_dev, &index, - iommu_regs->base, iommu_regs->range); + iommu_regs->base, ilog2(iommu_regs->range)); } static struct adreno_snapshot_sizes a4xx_snap_sizes = { diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 876b7c96a551..2a3ae3ed6add 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -386,7 +386,7 @@ static void a5xx_protect_init(struct adreno_device *adreno_dev) iommu_regs = kgsl_mmu_get_prot_regs(&device->mmu); if (iommu_regs) adreno_set_protected_registers(adreno_dev, &index, - iommu_regs->base, iommu_regs->range); + iommu_regs->base, ilog2(iommu_regs->range)); } /* diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 37330cb0a501..517b813b4dcc 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -446,7 +446,7 @@ static void a6xx_protect_init(struct adreno_device *adreno_dev) if (mmu_prot) { mmu_base = mmu_prot->base; - mmu_range = 1 << mmu_prot->range; + mmu_range = mmu_prot->range; req_sets += DIV_ROUND_UP(mmu_range, 0x2000); } diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 325d44ad8913..0e8b7b2a0b98 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -2630,7 +2630,7 @@ static int _kgsl_iommu_probe(struct kgsl_device *device, return -EINVAL; } iommu->protect.base = reg_val[0] / sizeof(u32); - iommu->protect.range = ilog2(reg_val[1] / sizeof(u32)); + iommu->protect.range = reg_val[1] / sizeof(u32); of_property_for_each_string(node, "clock-names", prop, cname) { struct clk *c = devm_clk_get(&pdev->dev, cname); -- GitLab From 34790299e81c8989d50aa5135b1ae433a9290ac0 Mon Sep 17 00:00:00 2001 From: Arun kumar Date: Wed, 23 May 2018 17:10:43 +0530 Subject: [PATCH 437/855] ARM: dts: msm: reset interface configuration on idle exit for msm8909w Reset interface configuration to MIPI after idle mode exit for AUO390p panel. Change-Id: I0e484d77f5267cf758ea73e6d71065de3486cb1c Signed-off-by: Arun kumar --- arch/arm64/boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi index b4ac287f8bad..06fc5a4f7f75 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi @@ -70,6 +70,10 @@ 29 01 00 00 00 00 05 2a 00 04 01 89 /* Reset row start address */ 29 01 00 00 00 00 05 2b 00 00 01 85 + 15 01 00 00 00 00 02 fe 01 + 15 01 00 00 00 00 02 04 00 + 15 01 00 00 00 00 02 fe 00 + 15 01 00 00 00 00 02 3a 77 ]; qcom,mdss-dsi-traffic-mode = "burst_mode"; qcom,mdss-dsi-lane-map = "lane_map_0123"; -- GitLab From b8881edf0804395716194dc932ccd79c7a379784 Mon Sep 17 00:00:00 2001 From: Padmanabhan Komanduru Date: Mon, 21 May 2018 16:10:14 +0530 Subject: [PATCH 438/855] msm: mdss: add support to handle LP_RX_TO/BTA_TO errors for DSI 12nm PHY Add support to handle LP_RX_TIMEOUT and BTA_TIMEOUT errors by performing a display blank/unblank sequence whenever DSI doesn't re-enter normal state as part of recovery sequence for targets with DSI 12nm PHY. Change-Id: Ica4738c87eb3ec7e6f34dd32720e3d5f2ee9185d Signed-off-by: Padmanabhan Komanduru --- drivers/video/fbdev/msm/mdss_dsi_host.c | 107 +++++++++++++++--- drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c | 9 +- drivers/video/fbdev/msm/mdss_mdp_intf_video.c | 9 +- drivers/video/fbdev/msm/mdss_panel.h | 1 + 4 files changed, 107 insertions(+), 19 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index f425620efefa..e221c1c4aed8 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -82,6 +82,8 @@ struct mdss_dsi_event { static struct mdss_dsi_event dsi_event; static int dsi_event_thread(void *data); +static void dsi_send_events(struct mdss_dsi_ctrl_pdata *ctrl, + u32 events, u32 arg); void mdss_dsi_ctrl_init(struct device *ctrl_dev, struct mdss_dsi_ctrl_pdata *ctrl) @@ -820,8 +822,10 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event) * Disable PHY contention detection and receive. * Configure the strength ctrl 1 register. */ - MIPI_OUTP((ctrl0->phy_io.base) + 0x0188, 0); - MIPI_OUTP((ctrl1->phy_io.base) + 0x0188, 0); + if (ctrl0->shared_data->phy_rev != DSI_PHY_REV_12NM) { + MIPI_OUTP((ctrl0->phy_io.base) + 0x0188, 0); + MIPI_OUTP((ctrl1->phy_io.base) + 0x0188, 0); + } data0 = MIPI_INP(ctrl0->ctrl_base + 0x0004); data1 = MIPI_INP(ctrl1->ctrl_base + 0x0004); @@ -876,6 +880,18 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event) udelay(u_dly); } if (i == loop) { + if ((ctrl0->shared_data->phy_rev == DSI_PHY_REV_12NM) && + (event == DSI_EV_LP_RX_TIMEOUT)) { + struct mdss_panel_info *pinfo = + &ctrl0->panel_data.panel_info; + /* If ESD is not enabled, report panel dead */ + if (!pinfo->esd_check_enabled && + ctrl0->recovery) + ctrl0->recovery->fxn( + ctrl0->recovery->data, + MDP_INTF_DSI_PANEL_DEAD); + return; + } MDSS_XLOG(ctrl0->ndx, ln0, 0x1f1f); MDSS_XLOG(ctrl1->ndx, ln1, 0x1f1f); pr_err("%s: Clock lane still in stop state\n", @@ -896,13 +912,20 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event) * Enable PHY contention detection and receive. * Configure the strength ctrl 1 register. */ - MIPI_OUTP((ctrl0->phy_io.base) + 0x0188, 0x6); - MIPI_OUTP((ctrl1->phy_io.base) + 0x0188, 0x6); + if (ctrl0->shared_data->phy_rev != DSI_PHY_REV_12NM) { + MIPI_OUTP((ctrl0->phy_io.base) + 0x0188, 0x6); + MIPI_OUTP((ctrl1->phy_io.base) + 0x0188, 0x6); + } /* * Add sufficient delay to make sure * pixel transmission as started */ udelay(200); + /* Un-mask LP_RX_TIMEOUT error if recovery successful */ + if (event == DSI_EV_LP_RX_TIMEOUT) { + mdss_dsi_set_reg(ctrl0, 0x10c, BIT(5), 0); + mdss_dsi_set_reg(ctrl1, 0x10c, BIT(5), 0); + } } else { if (ctrl->recovery) { rc = ctrl->recovery->fxn(ctrl->recovery->data, @@ -914,7 +937,8 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event) } } /* Disable PHY contention detection and receive */ - MIPI_OUTP((ctrl->phy_io.base) + 0x0188, 0); + if (ctrl->shared_data->phy_rev != DSI_PHY_REV_12NM) + MIPI_OUTP((ctrl->phy_io.base) + 0x0188, 0); data0 = MIPI_INP(ctrl->ctrl_base + 0x0004); /* Disable DSI video mode */ @@ -955,6 +979,17 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event) udelay(u_dly); } if (i == loop) { + if ((ctrl->shared_data->phy_rev == DSI_PHY_REV_12NM) && + (event == DSI_EV_LP_RX_TIMEOUT)) { + struct mdss_panel_info *pinfo = + &ctrl->panel_data.panel_info; + /* If ESD is not enabled, report panel dead */ + if (!pinfo->esd_check_enabled && ctrl->recovery) + ctrl->recovery->fxn( + ctrl->recovery->data, + MDP_INTF_DSI_PANEL_DEAD); + return; + } MDSS_XLOG(ctrl->ndx, ln0, 0x1f1f); pr_err("%s: Clock lane still in stop state\n", __func__); @@ -968,12 +1003,16 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event) /* Enable Video mode for DSI controller */ MIPI_OUTP(ctrl->ctrl_base + 0x004, data0); /* Enable PHY contention detection and receiver */ - MIPI_OUTP((ctrl->phy_io.base) + 0x0188, 0x6); + if (ctrl->shared_data->phy_rev != DSI_PHY_REV_12NM) + MIPI_OUTP((ctrl->phy_io.base) + 0x0188, 0x6); /* * Add sufficient delay to make sure * pixel transmission as started */ udelay(200); + /* Un-mask LP_RX_TIMEOUT error if recovery successful */ + if (event == DSI_EV_LP_RX_TIMEOUT) + mdss_dsi_set_reg(ctrl, 0x10c, BIT(5), 0); } pr_debug("Recovery done\n"); } @@ -1513,15 +1552,45 @@ int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata) ret = wait_for_completion_killable_timeout(&ctrl_pdata->bta_comp, DSI_BTA_EVENT_TIMEOUT); if (ret <= 0) { - mdss_dsi_disable_irq(ctrl_pdata, DSI_BTA_TERM); - pr_err("%s: DSI BTA error: %i\n", __func__, ret); + u32 reg_val, status; + + reg_val = MIPI_INP(ctrl_pdata->ctrl_base + 0x0110); + status = reg_val & DSI_INTR_BTA_DONE; + if (status) { + reg_val &= DSI_INTR_MASK_ALL; + /* clear BTA_DONE isr only */ + reg_val |= DSI_INTR_BTA_DONE; + MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0110, reg_val); + mdss_dsi_disable_irq(ctrl_pdata, DSI_BTA_TERM); + complete(&ctrl_pdata->bta_comp); + ret = 1; + pr_warn("%s: bta done but irq not triggered\n", + __func__); + } else { + pr_err("%s: DSI BTA error: %i\n", __func__, ret); + /* + * For 12nm DSI PHY, BTA_TO interrupt may not trigger. + * Treat software timer timeout as BTA_TO. + */ + if (ctrl_pdata->shared_data->phy_rev == + DSI_PHY_REV_12NM) { + /* Mask BTA_TIMEOUT/LP_RX_TIMEOUT error */ + mdss_dsi_set_reg(ctrl_pdata, 0x10c, + (BIT(5) | BIT(7)), (BIT(5) | BIT(7))); + dsi_send_events(ctrl_pdata, + DSI_EV_LP_RX_TIMEOUT, 0); + } + ret = -ETIMEDOUT; + } } if (ignore_underflow) { + u32 data = MIPI_INP((ctrl_pdata->ctrl_base) + 0x10c); /* clear pending overflow status */ mdss_dsi_set_reg(ctrl_pdata, 0xc, 0xffffffff, 0x44440000); - /* restore overflow isr */ - mdss_dsi_set_reg(ctrl_pdata, 0x10c, 0x0f0000, 0); + /* restore overflow isr if LP_RX_TO not masked*/ + if (!(data & BIT(5))) + mdss_dsi_set_reg(ctrl_pdata, 0x10c, 0x0f0000, 0); } mdss_dsi_clk_ctrl(ctrl_pdata, ctrl_pdata->dsi_clk_handle, @@ -2164,10 +2233,12 @@ static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl, if (mctrl && mctrl->dma_addr) { if (ignored) { + u32 data = MIPI_INP((mctrl->ctrl_base) + 0x10c); /* clear pending overflow status */ mdss_dsi_set_reg(mctrl, 0xc, 0xffffffff, 0x44440000); - /* restore overflow isr */ - mdss_dsi_set_reg(mctrl, 0x10c, 0x0f0000, 0); + /* restore overflow isr if LP_RX_TO not masked*/ + if (!(data & BIT(5))) + mdss_dsi_set_reg(mctrl, 0x10c, 0x0f0000, 0); } if (mctrl->dmap_iommu_map) { mdss_smmu_dsi_unmap_buffer(mctrl->dma_addr, domain, @@ -2185,10 +2256,12 @@ static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl, } if (ignored) { + u32 data = MIPI_INP((ctrl->ctrl_base) + 0x10c); /* clear pending overflow status */ mdss_dsi_set_reg(ctrl, 0xc, 0xffffffff, 0x44440000); - /* restore overflow isr */ - mdss_dsi_set_reg(ctrl, 0x10c, 0x0f0000, 0); + /* restore overflow isr if LP_RX_TO/BTA_TO not masked*/ + if (!(data & BIT(5))) + mdss_dsi_set_reg(ctrl, 0x10c, 0x0f0000, 0); } ctrl->dma_addr = 0; ctrl->dma_size = 0; @@ -3024,8 +3097,12 @@ static bool mdss_dsi_timeout_status(struct mdss_dsi_ctrl_pdata *ctrl) if (status & 0x0111) { MIPI_OUTP(base + 0x00c0, status); - if (status & 0x0110) + if (status & 0x0110) { + /* Mask BTA_TIMEOUT/LP_RX_TIMEOUT error */ + mdss_dsi_set_reg(ctrl, 0x10c, + (BIT(5) | BIT(7)), (BIT(5) | BIT(7))); dsi_send_events(ctrl, DSI_EV_LP_RX_TIMEOUT, 0); + } pr_err("%s: status=%x\n", __func__, status); ret = true; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index b49e9545acad..c002ba4ed9e4 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -1135,16 +1135,21 @@ static int mdss_mdp_cmd_intf_recovery(void *data, int event) return -EINVAL; /* - * Currently, only intf_fifo_underflow is + * Currently, intf_fifo_overflow is not * supported for recovery sequence for command * mode DSI interface */ - if (event != MDP_INTF_DSI_CMD_FIFO_UNDERFLOW) { + if (event == MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW) { pr_warn("%s: unsupported recovery event:%d\n", __func__, event); return -EPERM; } + if (event == MDP_INTF_DSI_PANEL_DEAD) { + mdss_fb_report_panel_dead(ctx->ctl->mfd); + return 0; + } + if (atomic_read(&ctx->koff_cnt)) { mdss_mdp_ctl_reset(ctx->ctl, true); reset_done = true; diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index f18987ce4da7..591fa38aa8a1 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -327,11 +327,11 @@ static int mdss_mdp_video_intf_recovery(void *data, int event) } /* - * Currently, only intf_fifo_overflow is + * Currently, intf_fifo_underflow is not * supported for recovery sequence for video * mode DSI interface */ - if (event != MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW) { + if (event == MDP_INTF_DSI_CMD_FIFO_UNDERFLOW) { pr_warn("%s: unsupported recovery event:%d\n", __func__, event); return -EPERM; @@ -341,6 +341,11 @@ static int mdss_mdp_video_intf_recovery(void *data, int event) pr_debug("%s: ctl num = %d, event = %d\n", __func__, ctl->num, event); + if (event == MDP_INTF_DSI_PANEL_DEAD) { + mdss_fb_report_panel_dead(ctx->ctl->mfd); + return 0; + } + pinfo = &ctl->panel_data->panel_info; clk_rate = ((ctl->intf_type == MDSS_INTF_DSI) ? pinfo->mipi.dsi_pclk_rate : diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index c9e7e619679c..aa90d5fb2cd5 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -167,6 +167,7 @@ struct mdss_panel_cfg { #define MDP_INTF_DSI_CMD_FIFO_UNDERFLOW 0x0001 #define MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW 0x0002 +#define MDP_INTF_DSI_PANEL_DEAD 0x0003 enum { -- GitLab From 615b0bf7eeacd8ab73f1661e886d627d9eeed565 Mon Sep 17 00:00:00 2001 From: Animesh Kishore Date: Thu, 24 May 2018 15:39:22 +0530 Subject: [PATCH 439/855] fbdev: msm: Fix iova alignment for smmu mappings Smmu driver expects all iova addresses to be 1Mb aligned. Additionally, 32 bit mode requires 128Mb alignment. Change-Id: I001642d8e6943f0595377b6b12d198e3e62899f2 Signed-off-by: Animesh Kishore --- drivers/video/fbdev/msm/mdss_smmu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_smmu.c b/drivers/video/fbdev/msm/mdss_smmu.c index 972c8dec9336..4ff8e90dc8b6 100644 --- a/drivers/video/fbdev/msm/mdss_smmu.c +++ b/drivers/video/fbdev/msm/mdss_smmu.c @@ -693,13 +693,13 @@ int mdss_smmu_init(struct mdss_data_type *mdata, struct device *dev) } static struct mdss_smmu_domain mdss_mdp_unsec = { - "mdp_0", MDSS_IOMMU_DOMAIN_UNSECURE, SZ_128K, (SZ_4G - SZ_128M)}; + "mdp_0", MDSS_IOMMU_DOMAIN_UNSECURE, SZ_128M, (SZ_4G - SZ_128M)}; static struct mdss_smmu_domain mdss_rot_unsec = { - NULL, MDSS_IOMMU_DOMAIN_ROT_UNSECURE, SZ_128K, (SZ_4G - SZ_128M)}; + NULL, MDSS_IOMMU_DOMAIN_ROT_UNSECURE, SZ_128M, (SZ_4G - SZ_128M)}; static struct mdss_smmu_domain mdss_mdp_sec = { - "mdp_1", MDSS_IOMMU_DOMAIN_SECURE, SZ_128K, (SZ_4G - SZ_128M)}; + "mdp_1", MDSS_IOMMU_DOMAIN_SECURE, SZ_128M, (SZ_4G - SZ_128M)}; static struct mdss_smmu_domain mdss_rot_sec = { - NULL, MDSS_IOMMU_DOMAIN_ROT_SECURE, SZ_128K, (SZ_4G - SZ_128M)}; + NULL, MDSS_IOMMU_DOMAIN_ROT_SECURE, SZ_128M, (SZ_4G - SZ_128M)}; static const struct of_device_id mdss_smmu_dt_match[] = { { .compatible = "qcom,smmu_mdp_unsec", .data = &mdss_mdp_unsec}, -- GitLab From cefe5d6852523768f1d151bf55b0f981eace0312 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Tue, 22 May 2018 18:50:43 +0530 Subject: [PATCH 440/855] phy: msm: usb: Support for mode switch based on PHY ID IRQ Add support where user can specify using dtsi attribute to switch target modes(host or peripheral) solely depending on PHY ID IRQ. If PHY ID state is low, then enable host mode. If PHY ID state is high, then enable peripheral mode. Change-Id: I8b04760965a13dfb993c08453394bf5194c9bede Signed-off-by: Ajay Agarwal --- .../devicetree/bindings/usb/msm-hsusb.txt | 2 ++ drivers/usb/phy/phy-msm-usb.c | 20 +++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt index 5256eddcfe77..431c32a4460c 100644 --- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt @@ -189,6 +189,8 @@ Optional properties : point to external connector device, which provide "USB-HOST" cable events. A single phandle may be specified if a single connector device provides both "USB" and "USB-HOST" events. +- qcom,phy-id-high-as-peripheral: If present, specifies device to switch to device mode + if PHY ID state is high or host mode if PHY ID state is low. Example HSUSB OTG controller device node : usb@f9690000 { diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 39086bff5e50..96675f2478cf 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -213,6 +213,7 @@ struct msm_otg_platform_data { bool enable_streaming; bool enable_axi_prefetch; bool vbus_low_as_hostmode; + bool phy_id_high_as_peripheral; }; #define SDP_CHECK_DELAY_MS 10000 /* in ms */ @@ -2325,10 +2326,17 @@ static void msm_otg_init_sm(struct msm_otg *motg) else clear_bit(ID, &motg->inputs); } else if (motg->phy_irq) { - if (msm_otg_read_phy_id_state(motg)) + if (msm_otg_read_phy_id_state(motg)) { set_bit(ID, &motg->inputs); - else + if (pdata->phy_id_high_as_peripheral) + set_bit(B_SESS_VLD, + &motg->inputs); + } else { clear_bit(ID, &motg->inputs); + if (pdata->phy_id_high_as_peripheral) + clear_bit(B_SESS_VLD, + &motg->inputs); + } } } break; @@ -2637,6 +2645,8 @@ static void msm_id_status_w(struct work_struct *w) gpio_direction_input(motg->pdata->switch_sel_gpio); if (!test_and_set_bit(ID, &motg->inputs)) { pr_debug("ID set\n"); + if (motg->pdata->phy_id_high_as_peripheral) + set_bit(B_SESS_VLD, &motg->inputs); msm_otg_dbg_log_event(&motg->phy, "ID SET", motg->inputs, motg->phy.otg->state); work = 1; @@ -2646,6 +2656,8 @@ static void msm_id_status_w(struct work_struct *w) gpio_direction_output(motg->pdata->switch_sel_gpio, 1); if (test_and_clear_bit(ID, &motg->inputs)) { pr_debug("ID clear\n"); + if (motg->pdata->phy_id_high_as_peripheral) + clear_bit(B_SESS_VLD, &motg->inputs); msm_otg_dbg_log_event(&motg->phy, "ID CLEAR", motg->inputs, motg->phy.otg->state); work = 1; @@ -3424,6 +3436,10 @@ struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev) pdata->vbus_low_as_hostmode = of_property_read_bool(node, "qcom,vbus-low-as-hostmode"); + + pdata->phy_id_high_as_peripheral = of_property_read_bool(node, + "qcom,phy-id-high-as-peripheral"); + return pdata; } -- GitLab From 2c209ecf5f9afad7f6a762d84626b4b94eb2ee0c Mon Sep 17 00:00:00 2001 From: Venkateswara Rao Tadikonda Date: Wed, 23 May 2018 15:54:00 +0530 Subject: [PATCH 441/855] msm: kgsl: Don't dump GPMU registers on non GPMU devices In Snapshot path, GPMU register offsets are being dumped on all A5xx devices. But some targets on A5xx does not have GPMU. So accessing GPMU registers would cause device fault. Allow the GPMU register access only on targets with GPMU. Change-Id: I2885dbdaf1cc95f960dcfacad52d6ded1dc9ac1d Signed-off-by: Venkateswara Rao Tadikonda --- drivers/gpu/msm/adreno_a5xx_snapshot.c | 119 ++++++++++++++++--------- 1 file changed, 76 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/msm/adreno_a5xx_snapshot.c b/drivers/gpu/msm/adreno_a5xx_snapshot.c index d1a6005ca2a3..4bde8c6fbbae 100644 --- a/drivers/gpu/msm/adreno_a5xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a5xx_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -412,6 +412,15 @@ static const unsigned int a5xx_registers[] = { 0xEC00, 0xEC05, 0xEC08, 0xECE9, 0xECF0, 0xECF0, /* VPC CTX 1 */ 0xEA80, 0xEA80, 0xEA82, 0xEAA3, 0xEAA5, 0xEAC2, +}; + +/* + * GPMU registers to dump for A5XX on snapshot. + * Registers in pairs - first value is the start offset, second + * is the stop offset (inclusive) + */ + +static const unsigned int a5xx_gpmu_registers[] = { /* GPMU */ 0xA800, 0xA8FF, 0xAC60, 0xAC60, }; @@ -664,24 +673,23 @@ static size_t a5xx_snapshot_pre_crashdump_regs(struct kgsl_device *device, return kgsl_snapshot_dump_registers(device, buf, remain, &pre_cdregs); } +struct registers { + const unsigned int *regs; + size_t size; +}; + static size_t a5xx_legacy_snapshot_registers(struct kgsl_device *device, - u8 *buf, size_t remain) + u8 *buf, size_t remain, const unsigned int *regs, size_t size) { - struct kgsl_snapshot_registers regs = { - .regs = a5xx_registers, - .count = ARRAY_SIZE(a5xx_registers) / 2, + struct kgsl_snapshot_registers snapshot_regs = { + .regs = regs, + .count = size / 2, }; - return kgsl_snapshot_dump_registers(device, buf, remain, ®s); + return kgsl_snapshot_dump_registers(device, buf, remain, + &snapshot_regs); } -static struct cdregs { - const unsigned int *regs; - unsigned int size; -} _a5xx_cd_registers[] = { - { a5xx_registers, ARRAY_SIZE(a5xx_registers) }, -}; - #define REG_PAIR_COUNT(_a, _i) \ (((_a)[(2 * (_i)) + 1] - (_a)[2 * (_i)]) + 1) @@ -691,11 +699,13 @@ static size_t a5xx_snapshot_registers(struct kgsl_device *device, u8 *buf, struct kgsl_snapshot_regs *header = (struct kgsl_snapshot_regs *)buf; unsigned int *data = (unsigned int *)(buf + sizeof(*header)); unsigned int *src = (unsigned int *) registers.hostptr; - unsigned int i, j, k; + struct registers *regs = (struct registers *)priv; + unsigned int j, k; unsigned int count = 0; if (crash_dump_valid == false) - return a5xx_legacy_snapshot_registers(device, buf, remain); + return a5xx_legacy_snapshot_registers(device, buf, remain, + regs->regs, regs->size); if (remain < sizeof(*header)) { SNAPSHOT_ERR_NOMEM(device, "REGISTERS"); @@ -704,24 +714,20 @@ static size_t a5xx_snapshot_registers(struct kgsl_device *device, u8 *buf, remain -= sizeof(*header); - for (i = 0; i < ARRAY_SIZE(_a5xx_cd_registers); i++) { - struct cdregs *regs = &_a5xx_cd_registers[i]; + for (j = 0; j < regs->size / 2; j++) { + unsigned int start = regs->regs[2 * j]; + unsigned int end = regs->regs[(2 * j) + 1]; - for (j = 0; j < regs->size / 2; j++) { - unsigned int start = regs->regs[2 * j]; - unsigned int end = regs->regs[(2 * j) + 1]; - - if (remain < ((end - start) + 1) * 8) { - SNAPSHOT_ERR_NOMEM(device, "REGISTERS"); - goto out; - } + if (remain < ((end - start) + 1) * 8) { + SNAPSHOT_ERR_NOMEM(device, "REGISTERS"); + goto out; + } - remain -= ((end - start) + 1) * 8; + remain -= ((end - start) + 1) * 8; - for (k = start; k <= end; k++, count++) { - *data++ = k; - *data++ = *src++; - } + for (k = start; k <= end; k++, count++) { + *data++ = k; + *data++ = *src++; } } @@ -861,6 +867,7 @@ void a5xx_snapshot(struct adreno_device *adreno_dev, struct adreno_snapshot_data *snap_data = gpudev->snapshot_data; unsigned int reg, i; struct adreno_ringbuffer *rb; + struct registers regs; /* Disable Clock gating temporarily for the debug bus to work */ a5xx_hwcg_set(adreno_dev, false); @@ -877,8 +884,20 @@ void a5xx_snapshot(struct adreno_device *adreno_dev, /* Try to run the crash dumper */ _a5xx_do_crashdump(device); - kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, - snapshot, a5xx_snapshot_registers, NULL); + regs.regs = a5xx_registers; + regs.size = ARRAY_SIZE(a5xx_registers); + + kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot, + a5xx_snapshot_registers, ®s); + + if (ADRENO_FEATURE(adreno_dev, ADRENO_GPMU)) { + regs.regs = a5xx_gpmu_registers; + regs.size = ARRAY_SIZE(a5xx_gpmu_registers); + + kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, + snapshot, a5xx_snapshot_registers, ®s); + } + /* Dump SP TP HLSQ registers */ kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot, @@ -1035,17 +1054,23 @@ void a5xx_crashdump_init(struct adreno_device *adreno_dev) * To save the registers, we need 16 bytes per register pair for the * script and a dword for each register int the data */ - for (i = 0; i < ARRAY_SIZE(_a5xx_cd_registers); i++) { - struct cdregs *regs = &_a5xx_cd_registers[i]; + /* Each pair needs 16 bytes (2 qwords) */ + script_size += (ARRAY_SIZE(a5xx_registers) / 2) * 16; + + /* Each register needs a dword in the data */ + for (j = 0; j < ARRAY_SIZE(a5xx_registers) / 2; j++) + data_size += REG_PAIR_COUNT(a5xx_registers, j) * + sizeof(unsigned int); + + if (ADRENO_FEATURE(adreno_dev, ADRENO_GPMU)) { /* Each pair needs 16 bytes (2 qwords) */ - script_size += (regs->size / 2) * 16; + script_size += (ARRAY_SIZE(a5xx_gpmu_registers) / 2) * 16; /* Each register needs a dword in the data */ - for (j = 0; j < regs->size / 2; j++) - data_size += REG_PAIR_COUNT(regs->regs, j) * + for (j = 0; j < ARRAY_SIZE(a5xx_gpmu_registers) / 2; j++) + data_size += REG_PAIR_COUNT(a5xx_gpmu_registers, j) * sizeof(unsigned int); - } /* @@ -1083,13 +1108,21 @@ void a5xx_crashdump_init(struct adreno_device *adreno_dev) ptr = (uint64_t *) capturescript.hostptr; /* For the registers, program a read command for each pair */ - for (i = 0; i < ARRAY_SIZE(_a5xx_cd_registers); i++) { - struct cdregs *regs = &_a5xx_cd_registers[i]; - for (j = 0; j < regs->size / 2; j++) { - unsigned int r = REG_PAIR_COUNT(regs->regs, j); + for (j = 0; j < ARRAY_SIZE(a5xx_registers) / 2; j++) { + unsigned int r = REG_PAIR_COUNT(a5xx_registers, j); + *ptr++ = registers.gpuaddr + offset; + *ptr++ = (((uint64_t) a5xx_registers[2 * j]) << 44) + | r; + offset += r * sizeof(unsigned int); + } + + if (ADRENO_FEATURE(adreno_dev, ADRENO_GPMU)) { + for (j = 0; j < ARRAY_SIZE(a5xx_gpmu_registers) / 2; j++) { + unsigned int r = REG_PAIR_COUNT(a5xx_gpmu_registers, j); *ptr++ = registers.gpuaddr + offset; - *ptr++ = (((uint64_t) regs->regs[2 * j]) << 44) | r; + *ptr++ = (((uint64_t) a5xx_gpmu_registers[2 * j]) << 44) + | r; offset += r * sizeof(unsigned int); } } -- GitLab From 303325f8a991993a5dca9134ddb1d8ed982427bf Mon Sep 17 00:00:00 2001 From: Charan Teja Reddy Date: Thu, 24 May 2018 14:23:42 +0530 Subject: [PATCH 442/855] ARM: dts: msm: correct size property of cma in sdxpoorwills Correct the size property of CMA pool of mem_dump region. Change-Id: I115b8f92b88f67166679b73bc86b07cb4f09d90d Signed-off-by: Charan Teja Reddy Signed-off-by: Mao Jinlong --- arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index 50bbebfa9e20..ba800cb3f300 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -77,7 +77,7 @@ dump_mem: mem_dump_region { compatible = "shared-dma-pool"; reusable; - size = <0 0x2400000>; + size = <0x400000>; }; }; -- GitLab From b024ae466757cd806ce7ca4037e1759db42954b8 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Thu, 24 May 2018 10:05:54 -0700 Subject: [PATCH 443/855] drm/msm: track msm_gem_obj in active_list with a boolean The active_list is maintained to keep track of the unmapped buffers during the detach of a context-bank, so that it can be re-mapped during the re-attach process. Add a boolean to track if the msm_obj is part of active_list to avoid adding it twice. In addition, set the aspace domain_attached flag before the re-mapping of buffers during the re-attach process. This is required to re-map the buffers for which the domains were removed during detach of the context-bank. Change-Id: Ic4daa020dbed2faaffd609ceb369a2fbd36af4cf Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/msm_gem.c | 3 ++- drivers/gpu/drm/msm/msm_gem.h | 1 + drivers/gpu/drm/msm/msm_gem_vma.c | 2 ++ drivers/gpu/drm/msm/sde/sde_kms.c | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 277b42162e7c..4f77b74de797 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -428,7 +428,7 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, if (!ret && domain) { *iova = domain->iova; - if (aspace && aspace->domain_attached) + if (aspace && !msm_obj->in_active_list) msm_gem_add_obj_to_aspace_active_list(aspace, obj); } else { obj_remove_domain(domain); @@ -968,6 +968,7 @@ static int msm_gem_new_impl(struct drm_device *dev, INIT_LIST_HEAD(&msm_obj->domains); INIT_LIST_HEAD(&msm_obj->iova_list); msm_obj->aspace = NULL; + msm_obj->in_active_list = false; list_add_tail(&msm_obj->mm_list, &priv->inactive_list); diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 8521beabe50a..ba01ffb48040 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -124,6 +124,7 @@ struct msm_gem_object { struct list_head iova_list; struct msm_gem_address_space *aspace; + bool in_active_list; }; #define to_msm_bo(x) container_of(x, struct msm_gem_object, base) diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index d02228ad4bac..e5b1cc37e9d6 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -71,6 +71,7 @@ static void smmu_aspace_add_to_active( { WARN_ON(!mutex_is_locked(&aspace->dev->struct_mutex)); list_move_tail(&msm_obj->iova_list, &aspace->active_list); + msm_obj->in_active_list = true; } static void smmu_aspace_remove_from_active( @@ -84,6 +85,7 @@ static void smmu_aspace_remove_from_active( list_for_each_entry_safe(msm_obj, next, &aspace->active_list, iova_list) { if (msm_obj == obj) { + msm_obj->in_active_list = false; list_del(&msm_obj->iova_list); break; } diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index b0a52a705cb5..7b28712a0f4d 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -2151,8 +2151,8 @@ int sde_kms_mmu_attach(struct sde_kms *sde_kms, bool secure_only) aspace->mmu->funcs->attach(mmu, (const char **)iommu_ports, ARRAY_SIZE(iommu_ports)); - msm_gem_aspace_domain_attach_detach_update(aspace, false); aspace->domain_attached = true; + msm_gem_aspace_domain_attach_detach_update(aspace, false); } return 0; -- GitLab From f28be31b1819bfca767b6ca6f9f8c6be63088c31 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Tue, 22 May 2018 23:21:53 -0700 Subject: [PATCH 444/855] ARM: dts: msm: update sleep vote node for sdm845 Display module keeps fix sleep vote on mnoc, ebi and llcc. This does not need the split vote because it is same for all three clients. Single node creation also reduces the bus vote latency. Change-Id: I850ab1fdcaa05db389c1a4a163af34db6865f545 Signed-off-by: Dhaval Patel --- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 28 ++++-------------------- 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index bfcebf6db95a..6132722a562b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -258,33 +258,13 @@ /* data and reg bus scale settings */ qcom,sde-data-bus { - qcom,msm-bus,name = "mdss_sde_mnoc"; + qcom,msm-bus,name = "mdss_sde"; qcom,msm-bus,num-cases = <3>; qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = - <22 773 0 0>, <23 773 0 0>, - <22 773 0 6400000>, <23 773 0 6400000>, - <22 773 0 6400000>, <23 773 0 6400000>; - }; - - qcom,sde-llcc-bus { - qcom,msm-bus,name = "mdss_sde_llcc"; - qcom,msm-bus,num-cases = <3>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <132 770 0 0>, - <132 770 0 6400000>, - <132 770 0 6400000>; - }; - - qcom,sde-ebi-bus { - qcom,msm-bus,name = "mdss_sde_ebi"; - qcom,msm-bus,num-cases = <3>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <129 512 0 0>, - <129 512 0 6400000>, - <129 512 0 6400000>; + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; }; qcom,sde-reg-bus { -- GitLab From 48a483dff3dad15eee9ae42ed58fe661b883a1f5 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 17 May 2018 21:54:08 -0700 Subject: [PATCH 445/855] msm: camera: eeprom: Correct free call for power settings Currently memory for the power settings is allocated whenever we receive an init packet in packet parser but that memory is freed only during device close leading to repeated allocations. This change ensures that we free the memory as soon as we power down the device avoiding repeated allocations of memory. Change-Id: I7fac6498c9403e8ae913dfc4f20f9aa8f0bdb999 Signed-off-by: Karthik Anantha Ram --- .../camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 6523607f0274..37e768324f08 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -781,6 +781,10 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; kfree(e_ctrl->cal_data.mapdata); kfree(e_ctrl->cal_data.map); + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; e_ctrl->cal_data.num_data = 0; e_ctrl->cal_data.num_map = 0; break; @@ -795,6 +799,8 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) error: kfree(power_info->power_setting); kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; kfree(e_ctrl->cal_data.map); e_ctrl->cal_data.num_data = 0; e_ctrl->cal_data.num_map = 0; @@ -830,6 +836,8 @@ void cam_eeprom_shutdown(struct cam_eeprom_ctrl_t *e_ctrl) kfree(power_info->power_setting); kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; } e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; -- GitLab From 320babd6a88d2abbe0ac67bed98b5e89554171bc Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 22 May 2018 14:16:26 -0700 Subject: [PATCH 446/855] msm: camera: isp: Dynamic update of epoch0 line config Currently epoch0 is configured to 20 lines from start of frame, this change dynamically updates the configuration based on the chosen sensor dimension for a given use case. Change-Id: I66474c39ea19b83a2137e5f2417a2cef88164a5b Signed-off-by: Karthik Anantha Ram --- .../isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 90c80066b4b1..8bc9bd23a039 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -204,6 +204,9 @@ static int cam_vfe_camif_resource_start( { struct cam_vfe_mux_camif_data *rsrc_data; uint32_t val = 0; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t computed_epoch_line_cfg; if (!camif_res) { CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); @@ -243,9 +246,16 @@ static int cam_vfe_camif_resource_start( rsrc_data->common_reg->module_ctrl[ CAM_VFE_TOP_VER2_MODULE_STATS]->cgc_ovd); - /* epoch config with 20 line */ - cam_io_w_mb(rsrc_data->reg_data->epoch_line_cfg, + /* epoch config */ + epoch0_irq_mask = ((rsrc_data->last_line - rsrc_data->first_line) / 2) + + rsrc_data->first_line; + epoch1_irq_mask = rsrc_data->reg_data->epoch_line_cfg & 0xFFFF; + computed_epoch_line_cfg = (epoch0_irq_mask << 16) | epoch1_irq_mask; + cam_io_w_mb(computed_epoch_line_cfg, rsrc_data->mem_base + rsrc_data->camif_reg->epoch_irq); + CAM_DBG(CAM_ISP, "first_line:%u last_line:%u epoch_line_cfg: 0x%x", + rsrc_data->first_line, rsrc_data->last_line, + computed_epoch_line_cfg); camif_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; -- GitLab From 819dfd8dbf26eb75841826dc97a78d54dceda391 Mon Sep 17 00:00:00 2001 From: Sumit Agrawal Date: Mon, 21 May 2018 19:21:58 +0530 Subject: [PATCH 447/855] ARM: dts: msm: Remove obsolete device tree files Remove device tree files which are not required. Change-Id: I93272808ba8c8af2958acc16c88dc428b89980c2 Signed-off-by: Sumit Agrawal --- arch/arm64/boot/dts/qcom/Makefile | 4 - .../dts/qcom/apq8053-lite-harman-v1.0.dts | 27 ------- .../dts/qcom/apq8053-lite-harman-v1.0.dtsi | 80 ------------------- .../dts/qcom/apq8053-lite-lenovo-v1.0.dts | 27 ------- .../dts/qcom/apq8053-lite-lenovo-v1.0.dtsi | 68 ---------------- .../dts/qcom/apq8053-lite-lenovo-v1.1.dts | 27 ------- .../dts/qcom/apq8053-lite-lenovo-v1.1.dtsi | 62 -------------- .../boot/dts/qcom/apq8053-lite-lge-v1.0.dts | 27 ------- .../boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi | 30 ------- 9 files changed, 352 deletions(-) delete mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts delete mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi delete mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts delete mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi delete mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts delete mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi delete mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts delete mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 9cfb7cb79769..4db459a3ad29 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -408,10 +408,6 @@ dtb-$(CONFIG_ARCH_MSM8953) += msm8953-cdp.dtb \ apq8053-lite-dragon-v2.2.dtb \ apq8053-lite-dragon-v2.3.dtb \ apq8053-lite-dragon-v2.4.dtb \ - apq8053-lite-lenovo-v1.0.dtb \ - apq8053-lite-lenovo-v1.1.dtb \ - apq8053-lite-harman-v1.0.dtb \ - apq8053-lite-lge-v1.0.dtb \ msm8953-pmi8940-cdp.dtb \ msm8953-pmi8940-mtp.dtb \ msm8953-pmi8937-cdp.dtb \ diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts deleted file mode 100644 index 203b6b89ef6a..000000000000 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "apq8053-lite-harman-v1.0.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. APQ8053 Lite Harman v1.0 Board"; - compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053", - "qcom,dragonboard"; - qcom,board-id= <0x01020020 0>; -}; - -&blsp2_uart0 { - status = "okay"; -}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi deleted file mode 100644 index 5cf8ac06ff43..000000000000 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "apq8053-lite-dragon.dtsi" - -&pm8953_l4 { - status = "okay"; - regulator-always-on; -}; - -&pm8953_l10 { - status = "okay"; - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; -}; - -&pm8953_l2 { - status = "okay"; - regulator-always-on; -}; - -&pm8953_l17 { - status = "okay"; - regulator-always-on; -}; - -&pm8953_l22 { - status = "okay"; - regulator-always-on; -}; - -&i2c_3 { - status = "okay"; - /delete-node/ himax_ts@48; - focaltech_ts@38 { - compatible = "focaltech,fts"; - reg = <0x38>; - interrupt-parent = <&tlmm>; - interrupts = <65 0x2>; - vdd-supply = <&pm8953_l10>; - avdd-supply = <&pm8953_l6>; - pinctrl-names = "pmx_ts_active","pmx_ts_suspend", - "pmx_ts_release"; - pinctrl-0 = <&ts_int_active &ts_reset_active>; - pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; - pinctrl-2 = <&ts_release>; - focaltech,display-coords = <0 0 800 1280>; - focaltech,reset-gpio = <&tlmm 64 0x0>; - focaltech,irq-gpio = <&tlmm 65 0x2>; - focaltech,max-touch-number = <5>; - report_type = <1>; - }; -}; - -&wled { - qcom,led-strings-list = [00 01 02]; -}; - -&camera0 { - qcom,mount-angle = <90>; -}; - -&camera1 { - qcom,mount-angle = <90>; -}; - -&camera2{ - qcom,mount-angle = <90>; -}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts deleted file mode 100644 index 325accffdf5c..000000000000 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "apq8053-lite-lenovo-v1.0.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. APQ8053 Lite Lenovo v1.0 Board"; - compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053", - "qcom,dragonboard"; - qcom,board-id= <0x01010020 0>; -}; - -&blsp2_uart0 { - status = "okay"; -}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi deleted file mode 100644 index 4d9c40c2d070..000000000000 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "apq8053-lite-dragon.dtsi" - -&mdss_dsi0 { - qcom,ext_vdd-gpio = <&tlmm 100 0>; - qcom,platform-bklight-en-gpio = <&tlmm 95 0>; - - qcom,platform-lane-config = [00 00 ff 0f - 00 00 ff 0f - 00 00 ff 0f - 00 00 ff 0f - 00 00 ff 8f]; -}; - -&eeprom0 { - gpios = <&tlmm 26 0>, - <&tlmm 40 0>, - <&tlmm 118 0>, - <&tlmm 119 0>, - <&tlmm 39 0>; - qcom,gpio-vdig = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK0", - "CAM_RESET0", - "CAM_VDIG", - "CAM_VANA", - "CAM_STANDBY0"; -}; - -&camera0 { - qcom,mount-angle = <270>; - gpios = <&tlmm 26 0>, - <&tlmm 40 0>, - <&tlmm 39 0>, - <&tlmm 118 0>, - <&tlmm 119 0>; - qcom,gpio-vdig = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK0", - "CAM_RESET0", - "CAM_STANDBY0", - "CAM_VDIG", - "CAM_VANA"; -}; - -&camera1 { - qcom,mount-angle = <270>; -}; - -&camera2{ - qcom,mount-angle = <270>; -}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts deleted file mode 100644 index 0c7b5577ff4d..000000000000 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "apq8053-lite-lenovo-v1.1.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. APQ8053 Lite Lenovo v1.1 Board"; - compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053", - "qcom,dragonboard"; - qcom,board-id= <0x01010120 0>; -}; - -&blsp2_uart0 { - status = "okay"; -}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi deleted file mode 100644 index 396fd55b7c3a..000000000000 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "apq8053-lite-dragon.dtsi" - -&i2c_3 { - status = "okay"; - /delete-node/ himax_ts@48; -}; - -&eeprom0 { - gpios = <&tlmm 26 0>, - <&tlmm 40 0>, - <&tlmm 118 0>, - <&tlmm 119 0>, - <&tlmm 39 0>; - qcom,gpio-vdig = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK0", - "CAM_RESET0", - "CAM_VDIG", - "CAM_VANA", - "CAM_STANDBY0"; -}; - -&camera0 { - qcom,mount-angle = <270>; - gpios = <&tlmm 26 0>, - <&tlmm 40 0>, - <&tlmm 39 0>, - <&tlmm 118 0>, - <&tlmm 119 0>; - qcom,gpio-vdig = <3>; - qcom,gpio-vana = <4>; - qcom,gpio-req-tbl-num = <0 1 2 3 4>; - qcom,gpio-req-tbl-flags = <1 0 0 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK0", - "CAM_RESET0", - "CAM_STANDBY0", - "CAM_VDIG", - "CAM_VANA"; -}; - -&camera1 { - qcom,mount-angle = <270>; -}; - -&camera2{ - qcom,mount-angle = <270>; -}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts deleted file mode 100644 index 70952dc6d835..000000000000 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "apq8053-lite-lge-v1.0.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. APQ8053 Lite LGE v1.0 Board"; - compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053", - "qcom,dragonboard"; - qcom,board-id= <0x01030020 0>; -}; - -&blsp2_uart0 { - status = "okay"; -}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi deleted file mode 100644 index db0331e18ce6..000000000000 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "apq8053-lite-dragon.dtsi" - -&wled { - qcom,fs-curr-ua = <17500>; -}; - -&camera0 { - qcom,mount-angle = <180>; -}; - -&camera1 { - qcom,mount-angle = <180>; -}; - -&camera2 { - qcom,mount-angle = <180>; -}; -- GitLab From 25728b37070fecb799093b63119975e9f5db320c Mon Sep 17 00:00:00 2001 From: Shaoqing Liu Date: Fri, 25 May 2018 12:38:21 +0800 Subject: [PATCH 448/855] defconfig: msm: disable ETM4X for msm8937 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove CONFIG_CORESIGHT_SOURCE_ETM4X=y in msm8937-perf_defconfig. This configure will auto enable jtagv8 config and enable jtagv8 driver, which will vote for QDSS clock in probe and keep it voted. It can’t be enabled on perf configure due to power concern. CRs-Fixed: 2245491 Change-Id: I9570b6b6a86355bbb9acf9a4cdbd53e450ecba54 Signed-off-by: Shaoqing Liu --- arch/arm/configs/msm8937-perf_defconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index 11308ba3343c..1230b0888529 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -571,7 +571,6 @@ CONFIG_QCOM_DCC=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MEM_SHARE_QMI_SERVICE=y -# CONFIG_MSM_JTAGV8 is not set CONFIG_MSM_BAM_DMUX=y CONFIG_WCNSS_CORE=y CONFIG_WCNSS_CORE_PRONTO=y @@ -617,7 +616,6 @@ CONFIG_IPC_LOGGING=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y -CONFIG_CORESIGHT_SOURCE_ETM4X=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_QCOM_REPLICATOR=y -- GitLab From d5a01c4b5892e96cf6c1c173d31f6da7470c2121 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Wed, 9 May 2018 10:22:33 +0530 Subject: [PATCH 449/855] ARM: dts: msm: Enable UFS force probe for SDM710 CDP platform SDM710 can support both UFS device and eMMC device. And there is a requirement to support both on a given platform. But if UFS is not a bootdevice it won't get probed. So enable "force-ufshc-probe" property for ufs probe to happen even though its not a bootdevice. Both eMMC & UFS can be supported only on CDP, since only CDP has the provision to support external eMMC/UFS cards besides internal eMMC /UFS. So enable force-probe flag only for CDP platform. Change-Id: I8933a2d287dbe304d9177158cf2fba2caa76d660 Signed-off-by: Veerabhadrarao Badiganti --- arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi index bd88087d94fe..975200d57067 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi @@ -38,6 +38,8 @@ qcom,vddp-ref-clk-supply = <&pm660_l1>; qcom,vddp-ref-clk-max-microamp = <100>; + force-ufshc-probe; + status = "ok"; }; -- GitLab From 598a17225e12d553a78d0b3db6eae6008d0b1e15 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Thu, 24 May 2018 15:52:38 +0530 Subject: [PATCH 450/855] cpuidle: lpm-levels: Use of_node_put on node pointers Add missing of_node_put calls on node pointers to decrement ref counts. Change-Id: I7c385ed854f2b7c9483af88877ca738e14e9e464 Signed-off-by: Maulik Shah --- drivers/cpuidle/lpm-levels-of.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index 7a653c6c2035..1d1d7e74e942 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -614,6 +614,7 @@ static int get_cpumask_for_node(struct device_node *node, struct cpumask *mask) break; } } + of_node_put(cpu_node); cpu_node = of_parse_phandle(node, "qcom,cpu", idx++); } @@ -651,13 +652,16 @@ static int parse_cpu(struct device_node *node, struct lpm_cpu *cpu) cpu->nlevels++; ret = parse_cpu_mode(n, l); - if (ret) + if (ret) { + of_node_put(n); return ret; + } ret = parse_power_params(n, &l->pwr); - if (ret) + if (ret) { + of_node_put(n); return ret; - + } key = "qcom,use-broadcast-timer"; l->use_bc_timer = of_property_read_bool(n, key); @@ -670,6 +674,7 @@ static int parse_cpu(struct device_node *node, struct lpm_cpu *cpu) l->reset_level = LPM_RESET_LVL_NONE; else if (ret) return ret; + of_node_put(n); } for (i = 0; i < cpu->nlevels; i++) { @@ -820,8 +825,11 @@ struct lpm_cluster *parse_cluster(struct device_node *node, key = "qcom,pm-cluster-level"; if (!of_node_cmp(n->name, key)) { - if (parse_cluster_level(n, c)) + if (parse_cluster_level(n, c)) { + of_node_put(n); goto failed_parse_cluster; + } + of_node_put(n); continue; } @@ -830,22 +838,28 @@ struct lpm_cluster *parse_cluster(struct device_node *node, struct lpm_cluster *child; child = parse_cluster(n, c); - if (!child) + if (!child) { + of_node_put(n); goto failed_parse_cluster; + } list_add(&child->list, &c->child); cpumask_or(&c->child_cpus, &c->child_cpus, &child->child_cpus); c->aff_level = child->aff_level + 1; + of_node_put(n); continue; } key = "qcom,pm-cpu"; if (!of_node_cmp(n->name, key)) { - if (parse_cpu_levels(n, c)) + if (parse_cpu_levels(n, c)) { + of_node_put(n); goto failed_parse_cluster; + } c->aff_level = 1; + of_node_put(n); } } @@ -879,6 +893,7 @@ struct lpm_cluster *parse_cluster(struct device_node *node, struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev) { struct device_node *top = NULL; + struct lpm_cluster *c; top = of_find_node_by_name(pdev->dev.of_node, "qcom,pm-cluster"); if (!top) { @@ -887,7 +902,9 @@ struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev) } lpm_pdev = pdev; - return parse_cluster(top, NULL); + c = parse_cluster(top, NULL); + of_node_put(top); + return c; } void cluster_dt_walkthrough(struct lpm_cluster *cluster) -- GitLab From be780054fd2831306e17a3771e1e08671b9e6f2d Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Thu, 17 May 2018 16:17:46 +0530 Subject: [PATCH 451/855] ARM: dts: msm: Disable SPDM governor on SDM439/429 CPU performance is impacted due to SPDM governor, disable it for now and will be enabled back if required. Change-Id: Idc081b88d7f739aa57d5adbd406304af82d03ab2 Signed-off-by: Odelu Kukatla --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 10 ++++++++++ arch/arm64/boot/dts/qcom/sdm439.dtsi | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 19df05491c49..b52ee2d1292e 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -145,6 +145,16 @@ #clock-cells = <1>; }; +&soc { + devfreq_spdm_cpu { + status = "disabled"; + }; + + devfreq_spdm_gov { + status = "disabled"; + }; +}; + &soc { /delete-node/ qcom,cpu-clock-8939@b111050; clock_cpu: qcom,cpu-clock-8939@b111050 { diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi index 0b010351e8c0..fe22fcfd2047 100644 --- a/arch/arm64/boot/dts/qcom/sdm439.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi @@ -325,6 +325,16 @@ vdd_hf_pll-supply = <&pm8953_l7_ao>; }; +&soc { + devfreq_spdm_cpu { + status = "disabled"; + }; + + devfreq_spdm_gov { + status = "disabled"; + }; +}; + &clock_gcc_mdss { compatible = "qcom,gcc-mdss-sdm439"; clocks = <&mdss_dsi0_pll clk_dsi0pll_pixel_clk_src>, -- GitLab From bb5b0e61527011e4ebfc4058713a9068da9e7492 Mon Sep 17 00:00:00 2001 From: Joonwoo Park Date: Thu, 1 Jun 2017 14:54:23 -0700 Subject: [PATCH 452/855] sched: prevent out of bound access in sched_group_energy() group_idle_state() can return INT_MAX + 1 which is undefined behaviour when there is no CPUs in sched_group. Prevent such by error correctly. Change-Id: If9796c829c091e461231569dc38c5e5456f58037 Signed-off-by: Joonwoo Park Signed-off-by: Satya Durga Srinivasu Prabhala [clingutla@codeaurora.org: Fixed trivial merge conflicts and squashed msm-4.14 change] Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/fair.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 78c433aab123..69cc74a00853 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5710,6 +5710,9 @@ static int group_idle_state(struct energy_env *eenv, int cpu_idx) for_each_cpu(i, sched_group_cpus(sg)) state = min(state, idle_get_state_idx(cpu_rq(i))); + if (unlikely(state == INT_MAX)) + return -EINVAL; + /* Take non-cpuidle idling into account (active idle/arch_cpu_idle()) */ state++; @@ -5776,7 +5779,7 @@ static int group_idle_state(struct energy_env *eenv, int cpu_idx) * The required scaling will be performed just one time, by the calling * functions, once we accumulated the contributons for all the SGs. */ -static void calc_sg_energy(struct energy_env *eenv) +static int calc_sg_energy(struct energy_env *eenv) { struct sched_group *sg = eenv->sg; int busy_energy, idle_energy; @@ -5805,6 +5808,8 @@ static void calc_sg_energy(struct energy_env *eenv) /* Compute IDLE energy */ idle_idx = group_idle_state(eenv, cpu_idx); + if (unlikely(idle_idx < 0)) + return idle_idx; idle_power = sg->sge->idle_states[idle_idx].power; idle_energy = SCHED_CAPACITY_SCALE - sg_util; @@ -5813,6 +5818,7 @@ static void calc_sg_energy(struct energy_env *eenv) total_energy = busy_energy + idle_energy; eenv->cpu[cpu_idx].energy += total_energy; } + return 0; } /* @@ -5874,7 +5880,8 @@ static int compute_energy(struct energy_env *eenv) * CPUs in the current visited SG. */ eenv->sg = sg; - calc_sg_energy(eenv); + if (calc_sg_energy(eenv)) + return -EINVAL; /* remove CPUs we have just visited */ if (!sd->child) { -- GitLab From ecedc7afd841c8d7ef0145924620304608d269ef Mon Sep 17 00:00:00 2001 From: Joonwoo Park Date: Wed, 7 Jun 2017 11:51:54 -0700 Subject: [PATCH 453/855] sched: ceil idle index to prevent from out of bound accessing It's possible size of given idle cost index is smaller than CPU's possible idle index size. Ceil the CPU's idle index to prevent out of bound accessing. Change-Id: Idecb4f68758dd0183886ea74d0e9da3d236b0062 Signed-off-by: Joonwoo Park Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/fair.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 69cc74a00853..e98606c1fc61 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5810,6 +5810,9 @@ static int calc_sg_energy(struct energy_env *eenv) idle_idx = group_idle_state(eenv, cpu_idx); if (unlikely(idle_idx < 0)) return idle_idx; + if (idle_idx > sg->sge->nr_idle_states - 1) + idle_idx = sg->sge->nr_idle_states - 1; + idle_power = sg->sge->idle_states[idle_idx].power; idle_energy = SCHED_CAPACITY_SCALE - sg_util; -- GitLab From efe1cba4247149c84c4611a31fbf1045880bba3d Mon Sep 17 00:00:00 2001 From: Venkata Prahlad Valluru Date: Tue, 6 Feb 2018 19:49:40 +0530 Subject: [PATCH 454/855] input: touchscreen: synaptics_2.6: Add regulator configuration support Add bus and power regulator configurations for both active and suspend mode. Move to low power mode during idle suspend. Enable configuration options through device tree. Change-Id: Ic1509ab7e31e7488460a6cc86e5cd434a84fa7a8 Signed-off-by: Venkata Prahlad Valluru --- .../touchscreen/synaptics_dsxv26_i2c.txt | 2 + .../synaptics_dsx_2.6/synaptics_dsx_core.c | 147 +++++++++++++++++- .../synaptics_dsx_2.6/synaptics_dsx_i2c.c | 7 + include/linux/input/synaptics_dsx_v2_6.h | 4 + 4 files changed, 153 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt index 87a551bac965..885be729be24 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt @@ -24,6 +24,7 @@ Optional property: - synaptics,reset-on-state : reset gpio active state. - synaptics,power-on-state : power switch active state. - synaptics,ub-i2c-addr : microbootloader mode I2C slave address. + - synaptics,do-not-disable-regulators : If specified, regulators cannot be disabled/enabled during suspend/resume. - synaptics,cap-button-codes : virtual key code mappings to be used. - synaptics,vir-button-codes : virtual key code and the response region on panel. - synaptics,wakeup-gestures-en: enable wakeup gestures. @@ -33,6 +34,7 @@ Optional property: - synaptics,reset-active-ms : reset active duration for controller (ms), default 100. - synaptics,power-delay-ms : power delay for controller (ms), default 100. - synaptics,max-y-for-2d : maximal y value of the panel. + - synaptics,bus-lpm-cur-uA : I2C bus idle mode current setting. - synaptics,swap-axes : specify whether to swap axes. - synaptics,resume-in-workqueue : specify whether to defer the resume to workqueue. - clock-names : Clock names used for secure touch. They are: "iface_clk", "core_clk" diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c index 21a9e8f84245..21236e9bf192 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c @@ -113,6 +113,13 @@ #define F12_WAKEUP_GESTURE_MODE 0x02 #define F12_UDG_DETECT 0x0f +#define PWR_VTG_MIN_UV 2700000 +#define PWR_VTG_MAX_UV 3600000 +#define PWR_ACTIVE_LOAD_UA 2000 +#define I2C_VTG_MIN_UV 1710000 +#define I2C_VTG_MAX_UV 2000000 +#define I2C_ACTIVE_LOAD_UA 7000 + static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data, bool *was_in_bl_mode); static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data); @@ -3407,6 +3414,66 @@ static int synaptics_rmi4_set_gpio(struct synaptics_rmi4_data *rmi4_data) return retval; } +static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA) +{ + return (regulator_count_voltages(reg) > 0) ? + regulator_set_load(reg, load_uA) : 0; +} + +static int synaptics_rmi4_configure_reg(struct synaptics_rmi4_data *rmi4_data, + bool on) +{ + int retval; + + if (on == false) + goto hw_shutdown; + + if (rmi4_data->pwr_reg) { + if (regulator_count_voltages(rmi4_data->pwr_reg) > 0) { + retval = regulator_set_voltage(rmi4_data->pwr_reg, + PWR_VTG_MIN_UV, PWR_VTG_MAX_UV); + if (retval) { + dev_err(rmi4_data->pdev->dev.parent, + "regulator set_vtg failed retval =%d\n", + retval); + goto err_set_vtg_pwr; + } + } + } + + if (rmi4_data->bus_reg) { + if (regulator_count_voltages(rmi4_data->bus_reg) > 0) { + retval = regulator_set_voltage(rmi4_data->bus_reg, + I2C_VTG_MIN_UV, I2C_VTG_MAX_UV); + if (retval) { + dev_err(rmi4_data->pdev->dev.parent, + "regulator set_vtg failed retval =%d\n", + retval); + goto err_set_vtg_bus; + } + } + } + + return 0; + +err_set_vtg_bus: + if (rmi4_data->pwr_reg && + regulator_count_voltages(rmi4_data->pwr_reg) > 0) + regulator_set_voltage(rmi4_data->pwr_reg, 0, PWR_VTG_MAX_UV); +err_set_vtg_pwr: + return retval; + +hw_shutdown: + if (rmi4_data->pwr_reg && + regulator_count_voltages(rmi4_data->pwr_reg) > 0) + regulator_set_voltage(rmi4_data->pwr_reg, 0, PWR_VTG_MAX_UV); + if (rmi4_data->bus_reg && + regulator_count_voltages(rmi4_data->bus_reg) > 0) + regulator_set_voltage(rmi4_data->bus_reg, 0, I2C_VTG_MAX_UV); + + return 0; +} + static int synaptics_rmi4_get_reg(struct synaptics_rmi4_data *rmi4_data, bool get) { @@ -3472,37 +3539,66 @@ static int synaptics_rmi4_enable_reg(struct synaptics_rmi4_data *rmi4_data, } if (rmi4_data->bus_reg) { + retval = reg_set_optimum_mode_check(rmi4_data->bus_reg, + I2C_ACTIVE_LOAD_UA); + if (retval < 0) { + dev_err(rmi4_data->pdev->dev.parent, + "%s: Regulator set_opt failed rc=%d\n", + __func__, retval); + return retval; + } + retval = regulator_enable(rmi4_data->bus_reg); if (retval < 0) { dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to enable bus pullup regulator\n", __func__); - goto exit; + goto err_bus_reg_en; } } if (rmi4_data->pwr_reg) { + retval = reg_set_optimum_mode_check(rmi4_data->pwr_reg, + PWR_ACTIVE_LOAD_UA); + if (retval < 0) { + dev_err(rmi4_data->pdev->dev.parent, + "%s: Regulator set_opt failed rc=%d\n", + __func__, retval); + goto disable_bus_reg; + } + retval = regulator_enable(rmi4_data->pwr_reg); if (retval < 0) { dev_err(rmi4_data->pdev->dev.parent, "%s: Failed to enable power regulator\n", __func__); - goto disable_bus_reg; + goto err_pwr_reg_en; } msleep(bdata->power_delay_ms); } return 0; +err_pwr_reg_en: + reg_set_optimum_mode_check(rmi4_data->pwr_reg, 0); + goto disable_bus_reg; +err_bus_reg_en: + reg_set_optimum_mode_check(rmi4_data->bus_reg, 0); + + return retval; + disable_pwr_reg: - if (rmi4_data->pwr_reg) + if (rmi4_data->pwr_reg) { + reg_set_optimum_mode_check(rmi4_data->pwr_reg, 0); regulator_disable(rmi4_data->pwr_reg); + } disable_bus_reg: - if (rmi4_data->bus_reg) + if (rmi4_data->bus_reg) { + reg_set_optimum_mode_check(rmi4_data->bus_reg, 0); regulator_disable(rmi4_data->bus_reg); + } -exit: return retval; } @@ -3976,6 +4072,14 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) goto err_get_reg; } + retval = synaptics_rmi4_configure_reg(rmi4_data, true); + if (retval < 0) { + dev_err(&pdev->dev, + "%s: Failed to configure regulators\n", + __func__); + goto err_configure_reg; + } + retval = synaptics_rmi4_enable_reg(rmi4_data, true); if (retval < 0) { dev_err(&pdev->dev, @@ -4202,6 +4306,8 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) err_enable_reg: synaptics_rmi4_get_reg(rmi4_data, false); +err_configure_reg: + synaptics_rmi4_configure_reg(rmi4_data, false); err_get_reg: kfree(rmi4_data); @@ -4284,6 +4390,7 @@ static int synaptics_rmi4_remove(struct platform_device *pdev) } synaptics_rmi4_enable_reg(rmi4_data, false); + synaptics_rmi4_configure_reg(rmi4_data, false); synaptics_rmi4_get_reg(rmi4_data, false); kfree(rmi4_data); @@ -4557,6 +4664,7 @@ static int synaptics_rmi4_suspend(struct device *dev) struct synaptics_rmi4_exp_fhandler *exp_fhandler; struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); int retval; + int lpm_uA; if (rmi4_data->stay_awake) return 0; @@ -4565,6 +4673,17 @@ static int synaptics_rmi4_suspend(struct device *dev) if (rmi4_data->enable_wakeup_gesture) { if (!rmi4_data->suspend) { + /* Set lpm current for bus regulator */ + lpm_uA = rmi4_data->hw_if->board_data->bus_lpm_cur_uA; + if (lpm_uA) { + retval = reg_set_optimum_mode_check( + rmi4_data->bus_reg, lpm_uA); + if (retval < 0) + dev_err(dev, + "Bus Regulator set_opt failed rc=%d\n", + retval); + } + synaptics_rmi4_wakeup_gesture(rmi4_data, true); enable_irq_wake(rmi4_data->irq); } @@ -4594,7 +4713,8 @@ static int synaptics_rmi4_suspend(struct device *dev) } mutex_unlock(&exp_data.mutex); - if (!rmi4_data->suspend && !rmi4_data->enable_wakeup_gesture) + if (!rmi4_data->suspend && !rmi4_data->enable_wakeup_gesture && + !rmi4_data->hw_if->board_data->dont_disable_regs) synaptics_rmi4_enable_reg(rmi4_data, false); rmi4_data->suspend = true; @@ -4623,6 +4743,18 @@ static int synaptics_rmi4_resume(struct device *dev) if (rmi4_data->enable_wakeup_gesture) { if (rmi4_data->suspend) { + /* Set active current for the bus regulator */ + if (rmi4_data->hw_if->board_data->bus_lpm_cur_uA) { + retval = reg_set_optimum_mode_check( + rmi4_data->bus_reg, + I2C_ACTIVE_LOAD_UA); + if (retval < 0) + dev_err(dev, + "Pwr regulator set_opt failed rc=%d\n", + retval); + } + + synaptics_rmi4_wakeup_gesture(rmi4_data, false); disable_irq_wake(rmi4_data->irq); } @@ -4631,7 +4763,8 @@ static int synaptics_rmi4_resume(struct device *dev) rmi4_data->current_page = MASK_8BIT; - if (rmi4_data->suspend) + if (rmi4_data->suspend && + !rmi4_data->hw_if->board_data->dont_disable_regs) synaptics_rmi4_enable_reg(rmi4_data, true); synaptics_rmi4_sleep_enable(rmi4_data, false); diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c index f634f179751d..e0788537e0f4 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c @@ -84,6 +84,9 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) bdata->wakeup_gesture_en = of_property_read_bool(np, "synaptics,wakeup-gestures-en"); + bdata->dont_disable_regs = of_property_read_bool(np, + "synaptics,do-not-disable-regulators"); + retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name); if (retval < 0) bdata->pwr_reg_name = NULL; @@ -184,6 +187,10 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) bdata->max_y_for_2d = -1; } + retval = of_property_read_u32(np, "synaptics,bus-lpm-cur-uA", + &value); + bdata->bus_lpm_cur_uA = retval < 0 ? 0 : value; + bdata->swap_axes = of_property_read_bool(np, "synaptics,swap-axes"); bdata->x_flip = of_property_read_bool(np, "synaptics,x-flip"); bdata->y_flip = of_property_read_bool(np, "synaptics,y-flip"); diff --git a/include/linux/input/synaptics_dsx_v2_6.h b/include/linux/input/synaptics_dsx_v2_6.h index 5cd26bba4dd6..75d4b7763f68 100644 --- a/include/linux/input/synaptics_dsx_v2_6.h +++ b/include/linux/input/synaptics_dsx_v2_6.h @@ -59,6 +59,7 @@ struct synaptics_dsx_button_map { * @y_flip: y flip flag * @swap_axes: swap axes flag * @resume_in_workqueue: defer resume function to workqueue + * @resume_in_workqueue: do not disable/enable regulators in suspend/resume * @irq_gpio: attention interrupt GPIO * @irq_on_state: attention interrupt active state * @power_gpio: power switch GPIO @@ -75,6 +76,7 @@ struct synaptics_dsx_button_map { * @power_delay_ms: delay time to wait after powering up device * @reset_delay_ms: delay time to wait after resetting device * @reset_active_ms: reset active time + * @bus_lpm_cur_uA: low power mode current setting for bus * @byte_delay_us: delay time between two bytes of SPI data * @block_delay_us: delay time between two SPI transfers * @pwr_reg_name: pointer to name of regulator for power control @@ -88,12 +90,14 @@ struct synaptics_dsx_board_data { bool swap_axes; bool resume_in_workqueue; bool wakeup_gesture_en; + bool dont_disable_regs; int irq_gpio; int irq_on_state; int power_gpio; int power_on_state; int reset_gpio; int reset_on_state; + int bus_lpm_cur_uA; int max_y_for_2d; unsigned long irq_flags; unsigned short i2c_addr; -- GitLab From 5d67992813b204917e345fbd70765c7fc23cf9da Mon Sep 17 00:00:00 2001 From: Azhar Shaikh Date: Mon, 1 Feb 2016 11:57:51 -0800 Subject: [PATCH 455/855] usb: gadget: gsi: Add a debugfs entry to simulate remote wakeup Add a debugfs entry to simulate IPA callback for remote wakeup on USB side. On executing the below command a timer will be started and remote wakeup will be done for every specified time interval. - To enable timer execute the below command: echo 1 > /sys/kernel/debug/usb_gsi/remote_wakeup_enable - To disable timer execute the below command: echo 0 > /sys/kernel/debug/usb_gsi/remote_wakeup_enable - To update timer value, execute the below command (default 500 ms): echo 5000 > /sys/kernel/debug/usb_gsi/remote_wakeup_interval Change-Id: I0799123710e064311321593b893e06940a54aa14 Signed-off-by: Azhar Shaikh Signed-off-by: Mayank Rana Signed-off-by: Chandana Kishori Chiluveru --- drivers/usb/gadget/function/f_gsi.c | 225 ++++++++++++++++++++++++++++ drivers/usb/gadget/function/f_gsi.h | 5 + 2 files changed, 230 insertions(+) diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 94dd64a8d8a9..7c2a557da940 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -14,6 +14,12 @@ #include "f_gsi.h" #include "rndis.h" +struct usb_gsi_debugfs { + struct dentry *debugfs_root; +}; + +static struct usb_gsi_debugfs debugfs; + static bool qti_packet_debug; module_param(qti_packet_debug, bool, 0644); MODULE_PARM_DESC(qti_packet_debug, "Print QTI Packet's Raw Data"); @@ -205,6 +211,223 @@ static int gsi_wakeup_host(struct f_gsi *gsi) return ret; } +static void debugfs_rw_timer_func(unsigned long arg) +{ + struct f_gsi *gsi; + + gsi = (struct f_gsi *)arg; + + if (!atomic_read(&gsi->connected)) { + log_event_dbg("%s: gsi not connected..del timer\n", __func__); + gsi->debugfs_rw_enable = 0; + del_timer(&gsi->debugfs_rw_timer); + return; + } + + log_event_dbg("%s: calling gsi_wakeup_host\n", __func__); + gsi_wakeup_host(gsi); + + if (gsi->debugfs_rw_enable) { + log_event_dbg("%s: re-arm the timer\n", __func__); + mod_timer(&gsi->debugfs_rw_timer, + jiffies + msecs_to_jiffies(gsi->debugfs_rw_interval)); + } +} + +static struct f_gsi *get_connected_gsi(void) +{ + struct f_gsi *connected_gsi; + bool gsi_connected = false; + unsigned int i; + + for (i = 0; i < IPA_USB_MAX_TETH_PROT_SIZE; i++) { + connected_gsi = __gsi[i]; + if (connected_gsi && atomic_read(&connected_gsi->connected)) { + gsi_connected = true; + break; + } + } + + if (!gsi_connected) + connected_gsi = NULL; + + return connected_gsi; +} + +#define DEFAULT_RW_TIMER_INTERVAL 500 /* in ms */ +static ssize_t usb_gsi_rw_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct f_gsi *gsi; + u8 input; + int ret; + + gsi = get_connected_gsi(); + if (!gsi) { + log_event_dbg("%s: gsi not connected\n", __func__); + goto err; + } + + if (ubuf == NULL) { + log_event_dbg("%s: buffer is Null.\n", __func__); + goto err; + } + + ret = kstrtou8_from_user(ubuf, count, 0, &input); + if (ret) { + log_event_err("%s: Invalid value. err:%d\n", __func__, ret); + goto err; + } + + if (gsi->debugfs_rw_enable == !!input) { + if (!!input) + log_event_dbg("%s: RW already enabled\n", __func__); + else + log_event_dbg("%s: RW already disabled\n", __func__); + goto err; + } + + gsi->debugfs_rw_enable = !!input; + if (gsi->debugfs_rw_enable) { + init_timer(&gsi->debugfs_rw_timer); + gsi->debugfs_rw_timer.data = (unsigned long) gsi; + gsi->debugfs_rw_timer.function = debugfs_rw_timer_func; + + /* Use default remote wakeup timer interval if it is not set */ + if (!gsi->debugfs_rw_interval) + gsi->debugfs_rw_interval = DEFAULT_RW_TIMER_INTERVAL; + gsi->debugfs_rw_timer.expires = jiffies + + msecs_to_jiffies(gsi->debugfs_rw_interval); + add_timer(&gsi->debugfs_rw_timer); + log_event_dbg("%s: timer initialized\n", __func__); + } else { + del_timer_sync(&gsi->debugfs_rw_timer); + log_event_dbg("%s: timer deleted\n", __func__); + } + +err: + return count; +} + +static int usb_gsi_rw_show(struct seq_file *s, void *unused) +{ + + struct f_gsi *gsi; + + gsi = get_connected_gsi(); + if (!gsi) { + log_event_dbg("%s: gsi not connected\n", __func__); + return 0; + } + + seq_printf(s, "%d\n", gsi->debugfs_rw_enable); + + return 0; +} + +static int usb_gsi_rw_open(struct inode *inode, struct file *f) +{ + return single_open(f, usb_gsi_rw_show, inode->i_private); +} + +static const struct file_operations fops_usb_gsi_rw = { + .open = usb_gsi_rw_open, + .read = seq_read, + .write = usb_gsi_rw_write, + .owner = THIS_MODULE, + .llseek = seq_lseek, + .release = seq_release, +}; + +static ssize_t usb_gsi_rw_timer_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct f_gsi *gsi; + u16 timer_val; + int ret; + + gsi = get_connected_gsi(); + if (!gsi) { + log_event_dbg("%s: gsi not connected\n", __func__); + goto err; + } + + if (ubuf == NULL) { + log_event_dbg("%s: buffer is NULL.\n", __func__); + goto err; + } + + ret = kstrtou16_from_user(ubuf, count, 0, &timer_val); + if (ret) { + log_event_err("%s: Invalid value. err:%d\n", __func__, ret); + goto err; + } + + if (timer_val <= 0 || timer_val > 10000) { + log_event_err("%s: value must be > 0 and < 10000.\n", __func__); + goto err; + } + + gsi->debugfs_rw_interval = timer_val; +err: + return count; +} + +static int usb_gsi_rw_timer_show(struct seq_file *s, void *unused) +{ + struct f_gsi *gsi; + unsigned int timer_interval; + + gsi = get_connected_gsi(); + if (!gsi) { + log_event_dbg("%s: gsi not connected\n", __func__); + return 0; + } + + timer_interval = DEFAULT_RW_TIMER_INTERVAL; + if (gsi->debugfs_rw_interval) + timer_interval = gsi->debugfs_rw_interval; + + seq_printf(s, "%ums\n", timer_interval); + + return 0; +} + +static int usb_gsi_rw_timer_open(struct inode *inode, struct file *f) +{ + return single_open(f, usb_gsi_rw_timer_show, inode->i_private); +} + +static const struct file_operations fops_usb_gsi_rw_timer = { + .open = usb_gsi_rw_timer_open, + .read = seq_read, + .write = usb_gsi_rw_timer_write, + .owner = THIS_MODULE, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int usb_gsi_debugfs_init(void) +{ + debugfs.debugfs_root = debugfs_create_dir("usb_gsi", NULL); + if (!debugfs.debugfs_root) + return -ENOMEM; + + debugfs_create_file("remote_wakeup_enable", 0600, + debugfs.debugfs_root, + __gsi, &fops_usb_gsi_rw); + debugfs_create_file("remote_wakeup_interval", 0600, + debugfs.debugfs_root, + __gsi, + &fops_usb_gsi_rw_timer); + return 0; +} + +static void usb_gsi_debugfs_exit(void) +{ + debugfs_remove_recursive(debugfs.debugfs_root); +} + /* * Callback for when when network interface is up * and userspace is ready to answer DHCP requests, or remote wakeup @@ -3366,6 +3589,7 @@ static int fgsi_init(void) if (!ipc_log_ctxt) pr_err("%s: Err allocating ipc_log_ctxt\n", __func__); + usb_gsi_debugfs_init(); return usb_function_register(&gsiusb_func); } module_init(fgsi_init); @@ -3382,6 +3606,7 @@ static void __exit fgsi_exit(void) for (i = 0; i < USB_PROT_MAX; i++) kfree(__gsi[i]); + usb_gsi_debugfs_exit(); usb_function_unregister(&gsiusb_func); } module_exit(fgsi_exit); diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index 7e998c4fafa8..1d4b4e382460 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "u_ether.h" @@ -275,6 +276,10 @@ struct f_gsi { struct gsi_data_port d_port; struct gsi_ctrl_port c_port; bool rmnet_dtr_status; + /* To test remote wakeup using debugfs */ + struct timer_list debugfs_rw_timer; + u8 debugfs_rw_enable; + u16 debugfs_rw_interval; }; static inline struct f_gsi *func_to_gsi(struct usb_function *f) -- GitLab From 658785469b4cc0e576fd1e8cbb0f8cd2d3198046 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Thu, 15 Feb 2018 18:48:27 -0800 Subject: [PATCH 456/855] usb: gadget: f_gsi: Add support for gps function driver gps usb functionality is implemented using qmi packets. User space entity sends and receives QMI packets using misc device named /dev/gps. Change-Id: I73af1caa9b272597909199022739390274a4b034 Signed-off-by: Hemant Kumar --- drivers/usb/gadget/function/f_gsi.c | 40 ++++++++++++- drivers/usb/gadget/function/f_gsi.h | 91 +++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 7c2a557da940..e9cbefc407ed 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -1591,6 +1591,9 @@ static int gsi_function_ctrl_port_init(struct f_gsi *gsi) case USB_PROT_DPL_ETHER: cdev_name = ETHER_DPL_CTRL_NAME; break; + case USB_PROT_GPS_CTRL: + cdev_name = GSI_GPS_CTRL_NAME; + break; default: break; } @@ -2461,6 +2464,11 @@ static void gsi_suspend(struct usb_function *f) return; } + if (!gsi->data_interface_up) { + log_event_dbg("%s: suspend done\n", __func__); + return; + } + block_db = true; usb_gsi_ep_op(gsi->d_port.in_ep, (void *)&block_db, GSI_EP_OP_SET_CLR_BLOCK_DBL); @@ -2490,6 +2498,11 @@ static void gsi_resume(struct usb_function *f) /* Check any pending cpkt, and queue immediately on resume */ gsi_ctrl_send_notification(gsi); + if (!gsi->data_interface_up) { + log_event_dbg("%s: resume done\n", __func__); + return; + } + /* * Linux host does not send RNDIS_MSG_INIT or non-zero * RNDIS_MESSAGE_PACKET_FILTER after performing bus resume. @@ -2783,9 +2796,11 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) goto fail; } - status = gsi->data_id = usb_interface_id(c, f); - if (status < 0) - goto fail; + if (gsi->prot_id != USB_PROT_GPS_CTRL) { + status = gsi->data_id = usb_interface_id(c, f); + if (status < 0) + goto fail; + } switch (gsi->prot_id) { case USB_PROT_RNDIS_IPA: @@ -3076,6 +3091,18 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) info.notify_buf_len = sizeof(struct usb_cdc_notification); name = "dpl_usb"; break; + case USB_PROT_GPS_CTRL: + info.string_defs = gps_string_defs; + info.ctrl_str_idx = 0; + info.ctrl_desc = &gps_interface_desc; + info.fs_notify_desc = &gps_fs_notify_desc; + info.hs_notify_desc = &gps_hs_notify_desc; + info.ss_notify_desc = &gps_ss_notify_desc; + info.fs_desc_hdr = gps_fs_function; + info.hs_desc_hdr = gps_hs_function; + info.ss_desc_hdr = gps_ss_function; + info.notify_buf_len = sizeof(struct usb_cdc_notification); + break; default: log_event_err("%s: Invalid prot id %d", __func__, gsi->prot_id); @@ -3086,6 +3113,9 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) if (status) goto dereg_rndis; + if (gsi->prot_id == USB_PROT_GPS_CTRL) + goto skip_ipa_init; + if (is_ext_prot_ether(gsi->prot_id)) { if (!name) return -EINVAL; @@ -3237,6 +3267,10 @@ static int gsi_bind_config(struct f_gsi *gsi) gsi->function.name = "dpl"; gsi->function.strings = qdss_gsi_strings; break; + case USB_PROT_GPS_CTRL: + gsi->function.name = "gps"; + gsi->function.strings = gps_strings; + break; default: log_event_err("%s: invalid prot id %d", __func__, gsi->prot_id); return -EINVAL; diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index 1d4b4e382460..6510deedb88a 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -35,6 +35,7 @@ #define GSI_DPL_CTRL_NAME "dpl_ctrl" #define ETHER_RMNET_CTRL_NAME "rmnet_ctrl0" #define ETHER_DPL_CTRL_NAME "dpl_ctrl0" +#define GSI_GPS_CTRL_NAME "gps" #define GSI_CTRL_NAME_LEN (sizeof(GSI_MBIM_CTRL_NAME)+2) #define GSI_MAX_CTRL_PKT_SIZE 4096 @@ -131,6 +132,7 @@ enum usb_prot_id { /* non-accelerated */ USB_PROT_RMNET_ETHER, USB_PROT_DPL_ETHER, + USB_PROT_GPS_CTRL, USB_PROT_MAX, }; @@ -330,6 +332,8 @@ static enum usb_prot_id name_to_prot_id(const char *name) return USB_PROT_RMNET_ETHER; if (!strncasecmp(name, "dpl.ether", MAX_INST_NAME_LEN)) return USB_PROT_DPL_ETHER; + if (!strncasecmp(name, "gps", MAX_INST_NAME_LEN)) + return USB_PROT_GPS_CTRL; error: return -EINVAL; @@ -1429,4 +1433,91 @@ static struct usb_gadget_strings *qdss_gsi_strings[] = { &qdss_gsi_string_table, NULL, }; + +/* gps device descriptor */ +static struct usb_interface_descriptor gps_interface_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceProtocol = USB_CLASS_VENDOR_SPEC, + /* .iInterface = DYNAMIC */ +}; + +/* Full speed support */ +static struct usb_endpoint_descriptor gps_fs_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(MAX_NOTIFY_SIZE), + .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, +}; + +static struct usb_descriptor_header *gps_fs_function[] = { + (struct usb_descriptor_header *) &gps_interface_desc, + (struct usb_descriptor_header *) &gps_fs_notify_desc, + NULL, +}; + +/* High speed support */ +static struct usb_endpoint_descriptor gps_hs_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(MAX_NOTIFY_SIZE), + .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, +}; + +static struct usb_descriptor_header *gps_hs_function[] = { + (struct usb_descriptor_header *) &gps_interface_desc, + (struct usb_descriptor_header *) &gps_hs_notify_desc, + NULL, +}; + +/* Super speed support */ +static struct usb_endpoint_descriptor gps_ss_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(MAX_NOTIFY_SIZE), + .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, +}; + +static struct usb_ss_ep_comp_descriptor gps_ss_notify_comp_desc = { + .bLength = sizeof(gps_ss_notify_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 3 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ + .wBytesPerInterval = cpu_to_le16(MAX_NOTIFY_SIZE), +}; + +static struct usb_descriptor_header *gps_ss_function[] = { + (struct usb_descriptor_header *) &gps_interface_desc, + (struct usb_descriptor_header *) &gps_ss_notify_desc, + (struct usb_descriptor_header *) &gps_ss_notify_comp_desc, + NULL, +}; + +/* String descriptors */ + +static struct usb_string gps_string_defs[] = { + [0].s = "GPS", + { } /* end of list */ +}; + +static struct usb_gadget_strings gps_string_table = { + .language = 0x0409, /* en-us */ + .strings = gps_string_defs, +}; + +static struct usb_gadget_strings *gps_strings[] = { + &gps_string_table, + NULL, +}; #endif -- GitLab From fa70a0f5d568ece1669012cbf80b42c713850f96 Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Wed, 23 May 2018 11:49:43 +0530 Subject: [PATCH 457/855] usb: f_gsi: Add EP_LOOKUP for USB_PROT_GPS_CTRL Add EP_LOOKUP for gps control channel and update the ep_type as USB and interface id used for GPS function so that user space Qmuxbridge process will use this info and update the response in DPM_OPEN_QMI Request for QMI communication. Change-Id: I45f640d952bdb513eb45c69711e61b2c2708f541 Signed-off-by: Chandana Kishori Chiluveru --- drivers/usb/gadget/function/f_gsi.c | 41 ++++++++++++++++++----------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index e9cbefc407ed..2cab156aa430 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -1449,27 +1449,36 @@ static long gsi_ctrl_dev_ioctl(struct file *fp, unsigned int cmd, break; } - if (gsi->d_port.in_channel_handle == -EINVAL && - gsi->d_port.out_channel_handle == -EINVAL) { - ret = -EAGAIN; - break; + if (gsi->prot_id != USB_PROT_GPS_CTRL) { + if (gsi->d_port.in_channel_handle == -EINVAL && + gsi->d_port.out_channel_handle == -EINVAL) { + ret = -EAGAIN; + break; + } + info.ph_ep_info.ep_type = GSI_MBIM_DATA_EP_TYPE_HSUSB; + info.ph_ep_info.peripheral_iface_id = gsi->data_id; + } else { + info.ph_ep_info.ep_type = GSI_MBIM_DATA_EP_TYPE_HSUSB; + info.ph_ep_info.peripheral_iface_id = gsi->ctrl_id; } - info.ph_ep_info.ep_type = GSI_MBIM_DATA_EP_TYPE_HSUSB; - info.ph_ep_info.peripheral_iface_id = gsi->data_id; - info.ipa_ep_pair.cons_pipe_num = - (gsi->prot_id == USB_PROT_DIAG_IPA || - gsi->prot_id == USB_PROT_DPL_ETHER) ? -1 : - gsi->d_port.out_channel_handle; - info.ipa_ep_pair.prod_pipe_num = gsi->d_port.in_channel_handle; - log_event_dbg("%s: prot id :%d ep_type:%d intf:%d", __func__, gsi->prot_id, info.ph_ep_info.ep_type, info.ph_ep_info.peripheral_iface_id); - - log_event_dbg("%s: ipa_cons_idx:%d ipa_prod_idx:%d", - __func__, info.ipa_ep_pair.cons_pipe_num, - info.ipa_ep_pair.prod_pipe_num); + if (gsi->prot_id != USB_PROT_GPS_CTRL) { + info.ipa_ep_pair.cons_pipe_num = + (gsi->prot_id == USB_PROT_DIAG_IPA || + gsi->prot_id == USB_PROT_DPL_ETHER) ? -1 : + gsi->d_port.out_channel_handle; + info.ipa_ep_pair.prod_pipe_num = + gsi->d_port.in_channel_handle; + + + log_event_dbg("%s: ipa_cons_idx:%d ipa_prod_idx:%d", + __func__, + info.ipa_ep_pair.cons_pipe_num, + info.ipa_ep_pair.prod_pipe_num); + } ret = copy_to_user((void __user *)arg, &info, sizeof(info)); -- GitLab From d7d18b2a6a5d1c83fc65dfacc1d30c41baefc58b Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Fri, 27 Apr 2018 18:00:09 +0530 Subject: [PATCH 458/855] usb: f_gsi: Increase GPS EP maxpacket size to 64bytes Currently usb driver is using 8 bytes request on interrupt endpoint for all CDC functions. GPS host driver is expecting short packet/zero length packet on interrupt endpoint and failing the transfer with 8 bytes maxpacket. Increase the maxpacket size to 64 bytes so that host ends the transfer with a short packet. Change-Id: Icc9919fbd633468d3cc7d4d8ab1945730cdc7c06 Signed-off-by: Chandana Kishori Chiluveru --- drivers/usb/gadget/function/f_gsi.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index 6510deedb88a..f4c30579a883 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -343,6 +343,7 @@ static enum usb_prot_id name_to_prot_id(const char *name) #define LOG2_STATUS_INTERVAL_MSEC 5 #define MAX_NOTIFY_SIZE sizeof(struct usb_cdc_notification) +#define GPS_MAX_NOTIFY_SIZE 64 /* rmnet device descriptors */ @@ -1451,7 +1452,7 @@ static struct usb_endpoint_descriptor gps_fs_notify_desc = { .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(MAX_NOTIFY_SIZE), + .wMaxPacketSize = cpu_to_le16(GPS_MAX_NOTIFY_SIZE), .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, }; @@ -1467,7 +1468,7 @@ static struct usb_endpoint_descriptor gps_hs_notify_desc = { .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(MAX_NOTIFY_SIZE), + .wMaxPacketSize = cpu_to_le16(GPS_MAX_NOTIFY_SIZE), .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, }; @@ -1483,7 +1484,7 @@ static struct usb_endpoint_descriptor gps_ss_notify_desc = { .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(MAX_NOTIFY_SIZE), + .wMaxPacketSize = cpu_to_le16(GPS_MAX_NOTIFY_SIZE), .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, }; @@ -1494,7 +1495,7 @@ static struct usb_ss_ep_comp_descriptor gps_ss_notify_comp_desc = { /* the following 3 values can be tweaked if necessary */ /* .bMaxBurst = 0, */ /* .bmAttributes = 0, */ - .wBytesPerInterval = cpu_to_le16(MAX_NOTIFY_SIZE), + .wBytesPerInterval = cpu_to_le16(GPS_MAX_NOTIFY_SIZE), }; static struct usb_descriptor_header *gps_ss_function[] = { -- GitLab From bba3bb8c9a29a9b016e4ad126d67ae60d935ae2d Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Fri, 18 May 2018 17:10:05 +0530 Subject: [PATCH 459/855] ARM: dts: msm: update energy model for sdm845v2 Update energy costs with maximum available frequency, Which is used in task placement. Change-Id: Ia248decbb8065da39ff70c041bf840e22c4e38a2 Signed-off-by: Lingutla Chandrasekhar --- arch/arm64/boot/dts/qcom/sdm845-v2.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index ba76273d507e..c6ed0fd04173 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -470,6 +470,7 @@ 2784000 35000 2803200 40000 2841600 50000 + 2956800 60000 >; idle-cost-data = < 100 80 60 40 @@ -537,6 +538,7 @@ 2784000 165 2803200 170 2841600 180 + 2956800 190 >; idle-cost-data = < 4 3 2 1 -- GitLab From f76558611335f9c754e8c618edacfe21d07f3d53 Mon Sep 17 00:00:00 2001 From: Maria Yu Date: Wed, 23 May 2018 18:44:44 +0800 Subject: [PATCH 460/855] ARM: dts: msm: Update the pet time NS WDOG on msm8953 10 second timer have granularity at 640ms for HZ == 100. Update the pet time to account for the timer inaccuracy. Change-Id: I66d10a5a6160777c5f413e730474a241d9f900c8 Signed-off-by: Maria Yu --- arch/arm64/boot/dts/qcom/msm8953.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index 67fd75ff7bc3..05c8fff6eacf 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -1230,7 +1230,7 @@ reg-names = "wdt-base"; interrupts = <0 3 0>, <0 4 0>; qcom,bark-time = <11000>; - qcom,pet-time = <10000>; + qcom,pet-time = <9760>; qcom,ipi-ping; qcom,wakeup-enable; qcom,scandump-size = <0x40000>; -- GitLab From fc38e9283209f6b5da2bed74c0df3000ad8667de Mon Sep 17 00:00:00 2001 From: Maria Yu Date: Fri, 25 May 2018 19:02:48 +0800 Subject: [PATCH 461/855] ARM: dts: msm: Update the pet time NS WDOG on msm8937 10 second timer have granularity at 640ms for HZ == 100. Update the pet time to account for the timer inaccuracy. Change-Id: I40398348c27c976d72726ef42adb753543476c17 Signed-off-by: Maria Yu --- arch/arm64/boot/dts/qcom/msm8937.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi index 66c7e7cd987f..9b6a7e9469fa 100644 --- a/arch/arm64/boot/dts/qcom/msm8937.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi @@ -998,7 +998,7 @@ reg-names = "wdt-base"; interrupts = <0 3 0>, <0 4 0>; qcom,bark-time = <11000>; - qcom,pet-time = <10000>; + qcom,pet-time = <9760>; qcom,ipi-ping; qcom,wakeup-enable; status = "okay"; -- GitLab From b67df12eedb803b697400dd8424eba5d037450ba Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Fri, 25 May 2018 19:38:17 +0800 Subject: [PATCH 462/855] ARM: hw_breakpoint: Add ARM_DEBUG_ARCH_V8_8 Add ARM_DEBUG_ARCH_V8_8 definition in hw_breakpoint. Change-Id: I6d900044c12cd71ff56ee7e869cfcda5e7dfe49a Signed-off-by: Tingwei Zhang --- arch/arm/include/asm/hw_breakpoint.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/include/asm/hw_breakpoint.h b/arch/arm/include/asm/hw_breakpoint.h index afcaf8bf971b..e40bbc5471d0 100644 --- a/arch/arm/include/asm/hw_breakpoint.h +++ b/arch/arm/include/asm/hw_breakpoint.h @@ -52,6 +52,7 @@ static inline void decode_ctrl_reg(u32 reg, #define ARM_DEBUG_ARCH_V7_MM 4 #define ARM_DEBUG_ARCH_V7_1 5 #define ARM_DEBUG_ARCH_V8 6 +#define ARM_DEBUG_ARCH_V8_8 8 /* Breakpoint */ #define ARM_BREAKPOINT_EXECUTE 0 -- GitLab From 22078a250cb8d72a29b81b710796122571862545 Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Wed, 25 Apr 2018 19:13:44 +0530 Subject: [PATCH 463/855] usb: dwc3: Add support for USB hibernation in host mode Add support for hibernation of USB in host mode and cable disconnected mode by adding proper pm operations freeze and restore. Change-Id: Ie1761a8afb0bb44a37d6ed4d046e8a09e1f53c5c Signed-off-by: Sriharsha Allenki --- drivers/usb/dwc3/core.c | 20 +++++++- drivers/usb/dwc3/dwc3-msm.c | 100 ++++++++++++++++++++++++++++++------ 2 files changed, 104 insertions(+), 16 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ef3f542cd59a..248dd9a96c5a 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1567,6 +1567,19 @@ static int dwc3_suspend(struct device *dev) return 0; } +static int dwc3_pm_restore(struct device *dev) +{ + /* + * Set the core as runtime active to prevent the runtime + * PM ops being called before the PM restore is completed. + */ + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + static int dwc3_resume(struct device *dev) { struct dwc3 *dwc = dev_get_drvdata(dev); @@ -1591,7 +1604,12 @@ static int dwc3_resume(struct device *dev) #endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops dwc3_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume) + .suspend = dwc3_suspend, + .resume = dwc3_resume, + .freeze = dwc3_suspend, + .thaw = dwc3_pm_restore, + .poweroff = dwc3_suspend, + .restore = dwc3_pm_restore, SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume, dwc3_runtime_idle) }; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 810546a23518..180a5b62cda6 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -2093,6 +2093,19 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) dwc3_core_init(dwc); /* Re-configure event buffers */ dwc3_event_buffers_setup(dwc); + + /* Get initial P3 status and enable IN_P3 event */ + val = dwc3_msm_read_reg_field(mdwc->base, + DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); + atomic_set(&mdwc->in_p3, val == DWC3_LINK_STATE_U3); + dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, + PWR_EVNT_POWERDOWN_IN_P3_MASK, 1); + + if (mdwc->otg_state == OTG_STATE_A_HOST) { + dev_dbg(mdwc->dev, "%s: set the core in host mode\n", + __func__); + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); + } } static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc) @@ -2246,7 +2259,7 @@ static void configure_nonpdc_usb_interrupt(struct dwc3_msm *mdwc, } } -static int dwc3_msm_suspend(struct dwc3_msm *mdwc) +static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation) { int ret; struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); @@ -2363,8 +2376,8 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) clk_disable_unprepare(mdwc->xo_clk); /* Perform controller power collapse */ - if (!mdwc->in_host_mode && (!mdwc->in_device_mode || - mdwc->in_restart)) { + if ((!mdwc->in_host_mode && (!mdwc->in_device_mode || + mdwc->in_restart)) || hibernation) { mdwc->lpm_flags |= MDWC3_POWER_COLLAPSE; dev_dbg(mdwc->dev, "%s: power collapse\n", __func__); dwc3_msm_config_gdsc(mdwc, 0); @@ -2520,8 +2533,6 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) /* Recover from controller power collapse */ if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) { - u32 tmp; - if (mdwc->iommu_map) { ret = arm_iommu_attach_device(mdwc->dev, mdwc->iommu_map); @@ -2536,13 +2547,6 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) dwc3_msm_power_collapse_por(mdwc); - /* Get initial P3 status and enable IN_P3 event */ - tmp = dwc3_msm_read_reg_field(mdwc->base, - DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); - atomic_set(&mdwc->in_p3, tmp == DWC3_LINK_STATE_U3); - dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, - PWR_EVNT_POWERDOWN_IN_P3_MASK, 1); - mdwc->lpm_flags &= ~MDWC3_POWER_COLLAPSE; } @@ -4401,7 +4405,39 @@ static int dwc3_msm_pm_suspend(struct device *dev) return -EBUSY; } - ret = dwc3_msm_suspend(mdwc); + ret = dwc3_msm_suspend(mdwc, false); + if (!ret) + atomic_set(&mdwc->pm_suspended, 1); + + return ret; +} + +static int dwc3_msm_pm_freeze(struct device *dev) +{ + int ret = 0; + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); + + dev_dbg(dev, "dwc3-msm PM freeze\n"); + dbg_event(0xFF, "PM Freeze", 0); + + flush_workqueue(mdwc->dwc3_wq); + + /* Resume the core to make sure we can power collapse it */ + ret = dwc3_msm_resume(mdwc); + + /* + * PHYs also needed to be power collapsed, so call the notify_disconnect + * before suspend to ensure it. + */ + usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH); + mdwc->hs_phy->flags &= ~PHY_HOST_MODE; + if (mdwc->ss_phy) { + usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER); + mdwc->ss_phy->flags &= ~PHY_HOST_MODE; + } + + ret = dwc3_msm_suspend(mdwc, true); if (!ret) atomic_set(&mdwc->pm_suspended, 1); @@ -4423,6 +4459,35 @@ static int dwc3_msm_pm_resume(struct device *dev) /* kick in otg state machine */ queue_work(mdwc->dwc3_wq, &mdwc->resume_work); + return 0; +} + +static int dwc3_msm_pm_restore(struct device *dev) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); + + dev_dbg(dev, "dwc3-msm PM restore\n"); + dbg_event(0xFF, "PM Restore", 0); + + atomic_set(&mdwc->pm_suspended, 0); + + dwc3_msm_resume(mdwc); + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + /* Restore PHY flags if hibernated in host mode */ + if (mdwc->otg_state == OTG_STATE_A_HOST) { + usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH); + mdwc->hs_phy->flags |= PHY_HOST_MODE; + if (mdwc->ss_phy) { + usb_phy_notify_connect(mdwc->ss_phy, USB_SPEED_SUPER); + mdwc->ss_phy->flags |= PHY_HOST_MODE; + } + } + + return 0; } #endif @@ -4447,7 +4512,7 @@ static int dwc3_msm_runtime_suspend(struct device *dev) dev_dbg(dev, "DWC3-msm runtime suspend\n"); dbg_event(0xFF, "RT Sus", 0); - return dwc3_msm_suspend(mdwc); + return dwc3_msm_suspend(mdwc, false); } static int dwc3_msm_runtime_resume(struct device *dev) @@ -4463,7 +4528,12 @@ static int dwc3_msm_runtime_resume(struct device *dev) #endif static const struct dev_pm_ops dwc3_msm_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(dwc3_msm_pm_suspend, dwc3_msm_pm_resume) + .suspend = dwc3_msm_pm_suspend, + .resume = dwc3_msm_pm_resume, + .freeze = dwc3_msm_pm_freeze, + .restore = dwc3_msm_pm_restore, + .thaw = dwc3_msm_pm_restore, + .poweroff = dwc3_msm_pm_suspend, SET_RUNTIME_PM_OPS(dwc3_msm_runtime_suspend, dwc3_msm_runtime_resume, dwc3_msm_runtime_idle) }; -- GitLab From b77d2469a31e80dce7f8a8ffe15de88de87d0a7c Mon Sep 17 00:00:00 2001 From: Manapragada Sai Date: Fri, 25 May 2018 14:51:43 +0530 Subject: [PATCH 464/855] defconfig: msm: Enable CPUSETS config for msm8937 and SDM429/439 targets CONFIG_CPUSETS is required for 4.9 kernel on msm8937 and SDM429/439 targets. Change-Id: Ib794d7dfdeecd02eb870fbcb0b9ca42db0538f34 Signed-off-by: Manapragada Sai --- arch/arm/configs/msm8937-perf_defconfig | 1 + arch/arm/configs/msm8937_defconfig | 1 + arch/arm64/configs/msm8937-perf_defconfig | 1 + arch/arm64/configs/msm8937_defconfig | 1 + 4 files changed, 4 insertions(+) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index 11308ba3343c..c0d1f705682f 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -17,6 +17,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 2f7941f6b014..5914ef089c11 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -18,6 +18,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index 48d2becd6327..8ed77a7c914c 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -18,6 +18,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig index acb4a258be59..2c39c44432eb 100644 --- a/arch/arm64/configs/msm8937_defconfig +++ b/arch/arm64/configs/msm8937_defconfig @@ -19,6 +19,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y -- GitLab From 3ec8544d64248d4ae6a195243351937b5c7fb464 Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Thu, 17 May 2018 11:25:06 +0530 Subject: [PATCH 465/855] usb: core: Resume the devices on pm restore On system restoring from hibernation to reset-resume the connected USB devices, resume the devices on pm restore irrespective of the skip_resume flag. Change-Id: I56e46c579db572e39eabdc6d2be95b00f2c7d9cb Signed-off-by: Sriharsha Allenki --- drivers/usb/core/driver.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ee33c0d796b5..55322469084d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1495,9 +1495,10 @@ int usb_resume(struct device *dev, pm_message_t msg) * Some buses would like to keep their devices in suspend * state after system resume. Their resume happen when * a remote wakeup is detected or interface driver start - * I/O. + * I/O. And in the case when the system is restoring from + * hibernation, make sure all the devices are resumed. */ - if (udev->bus->skip_resume) + if (udev->bus->skip_resume && msg.event != PM_EVENT_RESTORE) return 0; /* For all calls, take the device back to full power and -- GitLab From c79ef74a4b1ddda77dfbb78f8d7174568185c021 Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Thu, 17 May 2018 11:34:11 +0530 Subject: [PATCH 466/855] xhci-plat: Add hibernation support to xhci platform Add hibernation support to xhci platform by adding the proper PM ops freeze and restore. Also set the hibernated argument to xhci_resume which will trigger the reset-resume of the connected root-hubs and the devices. Change-Id: Ib536bb2485928326f34bfc3422b672cc62309efe Signed-off-by: Sriharsha Allenki --- drivers/usb/host/xhci-plat.c | 37 +++++++++++++++++++++++++++++++++++- drivers/usb/host/xhci.c | 6 ++++-- drivers/usb/host/xhci.h | 1 + 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index a1dedf0ffae9..67821a1003cb 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -439,6 +439,39 @@ static int xhci_plat_runtime_idle(struct device *dev) return -EBUSY; } +static int xhci_plat_pm_freeze(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + if (!xhci) + return 0; + + dev_dbg(dev, "xhci-plat freeze\n"); + + return xhci_suspend(xhci, false); +} + +static int xhci_plat_pm_restore(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret; + + if (!xhci) + return 0; + + dev_dbg(dev, "xhci-plat restore\n"); + + ret = xhci_resume(xhci, true); + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_mark_last_busy(dev); + + return ret; +} + static int xhci_plat_runtime_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); @@ -470,7 +503,9 @@ static int xhci_plat_runtime_resume(struct device *dev) } static const struct dev_pm_ops xhci_plat_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(NULL, NULL) + .freeze = xhci_plat_pm_freeze, + .restore = xhci_plat_pm_restore, + .thaw = xhci_plat_pm_restore, SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend, xhci_plat_runtime_resume, xhci_plat_runtime_idle) }; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index fe2bbfbe5fa6..9cba03707133 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -947,7 +947,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) struct usb_hcd *hcd = xhci_to_hcd(xhci); u32 command; - if (!hcd->state) + if (!hcd->state || xhci->suspended) return 0; if (hcd->state != HC_STATE_SUSPENDED || @@ -1017,6 +1017,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) /* step 5: remove core well power */ /* synchronize irq when using MSI-X */ xhci_msix_sync_irqs(xhci); + xhci->suspended = true; return rc; } @@ -1036,7 +1037,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) int retval = 0; bool comp_timer_running = false; - if (!hcd->state) + if (!hcd->state || !xhci->suspended) return 0; /* Wait a bit if either of the roothubs need to settle from the @@ -1173,6 +1174,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* Re-enable port polling. */ xhci_dbg(xhci, "%s: starting port polling.\n", __func__); + xhci->suspended = false; set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); usb_hcd_poll_rh_status(xhci->shared_hcd); set_bit(HCD_FLAG_POLL_RH, &hcd->flags); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 4c1f5563f2fc..a5153ca79723 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1697,6 +1697,7 @@ struct xhci_hcd { /* Compliance Mode Recovery Data */ struct timer_list comp_mode_recovery_timer; u32 port_status_u0; + bool suspended; /* Compliance Mode Timer Triggered every 2 seconds */ #define COMP_MODE_RCVRY_MSECS 2000 -- GitLab From 97b7270c3dc8bee6bf43df84595fd898014e3e0c Mon Sep 17 00:00:00 2001 From: Tarick Bedeir Date: Sun, 13 May 2018 16:38:45 -0700 Subject: [PATCH 467/855] net/mlx4_core: Fix error handling in mlx4_init_port_info. [ Upstream commit 57f6f99fdad9984801cde05c1db68fe39b474a10 ] Avoid exiting the function with a lingering sysfs file (if the first call to device_create_file() fails while the second succeeds), and avoid calling devlink_port_unregister() twice. In other words, either mlx4_init_port_info() succeeds and returns zero, or it fails, returns non-zero, and requires no cleanup. Fixes: 096335b3f983 ("mlx4_core: Allow dynamic MTU configuration for IB ports") Signed-off-by: Tarick Bedeir Reviewed-by: Leon Romanovsky Reviewed-by: Tariq Toukan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 5411ca48978a..cb7c3ef97134 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2983,6 +2983,7 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) mlx4_err(dev, "Failed to create file for port %d\n", port); devlink_port_unregister(&info->devlink_port); info->port = -1; + return err; } sprintf(info->dev_mtu_name, "mlx4_port%d_mtu", port); @@ -3004,9 +3005,10 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) &info->port_attr); devlink_port_unregister(&info->devlink_port); info->port = -1; + return err; } - return err; + return 0; } static void mlx4_cleanup_port_info(struct mlx4_port_info *info) -- GitLab From 2ef22bd08dcff6a8d761829647e5eb321576a83a Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 17 May 2018 13:13:29 -0400 Subject: [PATCH 468/855] net: test tailroom before appending to linear skb [ Upstream commit 113f99c3358564a0647d444c2ae34e8b1abfd5b9 ] Device features may change during transmission. In particular with corking, a device may toggle scatter-gather in between allocating and writing to an skb. Do not unconditionally assume that !NETIF_F_SG at write time implies that the same held at alloc time and thus the skb has sufficient tailroom. This issue predates git history. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: Eric Dumazet Signed-off-by: Willem de Bruijn Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_output.c | 3 ++- net/ipv6/ip6_output.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 2c3c1a223df4..3b1f3bc8becb 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1076,7 +1076,8 @@ static int __ip_append_data(struct sock *sk, if (copy > length) copy = length; - if (!(rt->dst.dev->features&NETIF_F_SG)) { + if (!(rt->dst.dev->features&NETIF_F_SG) && + skb_tailroom(skb) >= copy) { unsigned int off; off = skb->len; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 58a6eeeacbf7..e8560031a0be 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1545,7 +1545,8 @@ static int __ip6_append_data(struct sock *sk, if (copy > length) copy = length; - if (!(rt->dst.dev->features&NETIF_F_SG)) { + if (!(rt->dst.dev->features&NETIF_F_SG) && + skb_tailroom(skb) >= copy) { unsigned int off; off = skb->len; -- GitLab From 6190cce26e40bf71c4d375b21eea74bb07b6a0f3 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Fri, 11 May 2018 13:24:25 -0400 Subject: [PATCH 469/855] packet: in packet_snd start writing at link layer allocation [ Upstream commit b84bbaf7a6c8cca24f8acf25a2c8e46913a947ba ] Packet sockets allow construction of packets shorter than dev->hard_header_len to accommodate protocols with variable length link layer headers. These packets are padded to dev->hard_header_len, because some device drivers interpret that as a minimum packet size. packet_snd reserves dev->hard_header_len bytes on allocation. SOCK_DGRAM sockets call skb_push in dev_hard_header() to ensure that link layer headers are stored in the reserved range. SOCK_RAW sockets do the same in tpacket_snd, but not in packet_snd. Syzbot was able to send a zero byte packet to a device with massive 116B link layer header, causing padding to cross over into skb_shinfo. Fix this by writing from the start of the llheader reserved range also in the case of packet_snd/SOCK_RAW. Update skb_set_network_header to the new offset. This also corrects it for SOCK_DGRAM, where it incorrectly double counted reserve due to the skb_push in dev_hard_header. Fixes: 9ed988cd5915 ("packet: validate variable length ll headers") Reported-by: syzbot+71d74a5406d02057d559@syzkaller.appspotmail.com Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/packet/af_packet.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index a027f8c00944..b2b50756263b 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2910,13 +2910,15 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) if (skb == NULL) goto out_unlock; - skb_set_network_header(skb, reserve); + skb_reset_network_header(skb); err = -EINVAL; if (sock->type == SOCK_DGRAM) { offset = dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len); if (unlikely(offset < 0)) goto out_free; + } else if (reserve) { + skb_push(skb, reserve); } /* Returns -EFAULT on error */ -- GitLab From a5e907c347211d94727da350d8b784a68ac18a24 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 18 May 2018 04:47:55 -0700 Subject: [PATCH 470/855] sock_diag: fix use-after-free read in __sk_free [ Upstream commit 9709020c86f6bf8439ca3effc58cfca49a5de192 ] We must not call sock_diag_has_destroy_listeners(sk) on a socket that has no reference on net structure. BUG: KASAN: use-after-free in sock_diag_has_destroy_listeners include/linux/sock_diag.h:75 [inline] BUG: KASAN: use-after-free in __sk_free+0x329/0x340 net/core/sock.c:1609 Read of size 8 at addr ffff88018a02e3a0 by task swapper/1/0 CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.17.0-rc5+ #54 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x1b9/0x294 lib/dump_stack.c:113 print_address_description+0x6c/0x20b mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report.cold.7+0x242/0x2fe mm/kasan/report.c:412 __asan_report_load8_noabort+0x14/0x20 mm/kasan/report.c:433 sock_diag_has_destroy_listeners include/linux/sock_diag.h:75 [inline] __sk_free+0x329/0x340 net/core/sock.c:1609 sk_free+0x42/0x50 net/core/sock.c:1623 sock_put include/net/sock.h:1664 [inline] reqsk_free include/net/request_sock.h:116 [inline] reqsk_put include/net/request_sock.h:124 [inline] inet_csk_reqsk_queue_drop_and_put net/ipv4/inet_connection_sock.c:672 [inline] reqsk_timer_handler+0xe27/0x10e0 net/ipv4/inet_connection_sock.c:739 call_timer_fn+0x230/0x940 kernel/time/timer.c:1326 expire_timers kernel/time/timer.c:1363 [inline] __run_timers+0x79e/0xc50 kernel/time/timer.c:1666 run_timer_softirq+0x4c/0x70 kernel/time/timer.c:1692 __do_softirq+0x2e0/0xaf5 kernel/softirq.c:285 invoke_softirq kernel/softirq.c:365 [inline] irq_exit+0x1d1/0x200 kernel/softirq.c:405 exiting_irq arch/x86/include/asm/apic.h:525 [inline] smp_apic_timer_interrupt+0x17e/0x710 arch/x86/kernel/apic/apic.c:1052 apic_timer_interrupt+0xf/0x20 arch/x86/entry/entry_64.S:863 RIP: 0010:native_safe_halt+0x6/0x10 arch/x86/include/asm/irqflags.h:54 RSP: 0018:ffff8801d9ae7c38 EFLAGS: 00000282 ORIG_RAX: ffffffffffffff13 RAX: dffffc0000000000 RBX: 1ffff1003b35cf8a RCX: 0000000000000000 RDX: 1ffffffff11a30d0 RSI: 0000000000000001 RDI: ffffffff88d18680 RBP: ffff8801d9ae7c38 R08: ffffed003b5e46c3 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000001 R13: ffff8801d9ae7cf0 R14: ffffffff897bef20 R15: 0000000000000000 arch_safe_halt arch/x86/include/asm/paravirt.h:94 [inline] default_idle+0xc2/0x440 arch/x86/kernel/process.c:354 arch_cpu_idle+0x10/0x20 arch/x86/kernel/process.c:345 default_idle_call+0x6d/0x90 kernel/sched/idle.c:93 cpuidle_idle_call kernel/sched/idle.c:153 [inline] do_idle+0x395/0x560 kernel/sched/idle.c:262 cpu_startup_entry+0x104/0x120 kernel/sched/idle.c:368 start_secondary+0x426/0x5b0 arch/x86/kernel/smpboot.c:269 secondary_startup_64+0xa5/0xb0 arch/x86/kernel/head_64.S:242 Allocated by task 4557: save_stack+0x43/0xd0 mm/kasan/kasan.c:448 set_track mm/kasan/kasan.c:460 [inline] kasan_kmalloc+0xc4/0xe0 mm/kasan/kasan.c:553 kasan_slab_alloc+0x12/0x20 mm/kasan/kasan.c:490 kmem_cache_alloc+0x12e/0x760 mm/slab.c:3554 kmem_cache_zalloc include/linux/slab.h:691 [inline] net_alloc net/core/net_namespace.c:383 [inline] copy_net_ns+0x159/0x4c0 net/core/net_namespace.c:423 create_new_namespaces+0x69d/0x8f0 kernel/nsproxy.c:107 unshare_nsproxy_namespaces+0xc3/0x1f0 kernel/nsproxy.c:206 ksys_unshare+0x708/0xf90 kernel/fork.c:2408 __do_sys_unshare kernel/fork.c:2476 [inline] __se_sys_unshare kernel/fork.c:2474 [inline] __x64_sys_unshare+0x31/0x40 kernel/fork.c:2474 do_syscall_64+0x1b1/0x800 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x49/0xbe Freed by task 69: save_stack+0x43/0xd0 mm/kasan/kasan.c:448 set_track mm/kasan/kasan.c:460 [inline] __kasan_slab_free+0x11a/0x170 mm/kasan/kasan.c:521 kasan_slab_free+0xe/0x10 mm/kasan/kasan.c:528 __cache_free mm/slab.c:3498 [inline] kmem_cache_free+0x86/0x2d0 mm/slab.c:3756 net_free net/core/net_namespace.c:399 [inline] net_drop_ns.part.14+0x11a/0x130 net/core/net_namespace.c:406 net_drop_ns net/core/net_namespace.c:405 [inline] cleanup_net+0x6a1/0xb20 net/core/net_namespace.c:541 process_one_work+0xc1e/0x1b50 kernel/workqueue.c:2145 worker_thread+0x1cc/0x1440 kernel/workqueue.c:2279 kthread+0x345/0x410 kernel/kthread.c:240 ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:412 The buggy address belongs to the object at ffff88018a02c140 which belongs to the cache net_namespace of size 8832 The buggy address is located 8800 bytes inside of 8832-byte region [ffff88018a02c140, ffff88018a02e3c0) The buggy address belongs to the page: page:ffffea0006280b00 count:1 mapcount:0 mapping:ffff88018a02c140 index:0x0 compound_mapcount: 0 flags: 0x2fffc0000008100(slab|head) raw: 02fffc0000008100 ffff88018a02c140 0000000000000000 0000000100000001 raw: ffffea00062a1320 ffffea0006268020 ffff8801d9bdde40 0000000000000000 page dumped because: kasan: bad access detected Fixes: b922622ec6ef ("sock_diag: don't broadcast kernel sockets") Signed-off-by: Eric Dumazet Cc: Craig Gallek Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/sock.c b/net/core/sock.c index e3b60460dc9c..1c4c43483b54 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1457,7 +1457,7 @@ void sk_destruct(struct sock *sk) static void __sk_free(struct sock *sk) { - if (unlikely(sock_diag_has_destroy_listeners(sk) && sk->sk_net_refcnt)) + if (unlikely(sk->sk_net_refcnt && sock_diag_has_destroy_listeners(sk))) sock_diag_broadcast_destroy(sk); else sk_destruct(sk); -- GitLab From 74a4c09d4b05c67ed6bd6aed088a5552f4f64aaa Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 14 May 2018 21:14:26 -0700 Subject: [PATCH 471/855] tcp: purge write queue in tcp_connect_init() [ Upstream commit 7f582b248d0a86bae5788c548d7bb5bca6f7691a ] syzkaller found a reliable way to crash the host, hitting a BUG() in __tcp_retransmit_skb() Malicous MSG_FASTOPEN is the root cause. We need to purge write queue in tcp_connect_init() at the point we init snd_una/write_seq. This patch also replaces the BUG() by a less intrusive WARN_ON_ONCE() kernel BUG at net/ipv4/tcp_output.c:2837! invalid opcode: 0000 [#1] SMP KASAN Dumping ftrace buffer: (ftrace buffer empty) Modules linked in: CPU: 0 PID: 5276 Comm: syz-executor0 Not tainted 4.17.0-rc3+ #51 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:__tcp_retransmit_skb+0x2992/0x2eb0 net/ipv4/tcp_output.c:2837 RSP: 0000:ffff8801dae06ff8 EFLAGS: 00010206 RAX: ffff8801b9fe61c0 RBX: 00000000ffc18a16 RCX: ffffffff864e1a49 RDX: 0000000000000100 RSI: ffffffff864e2e12 RDI: 0000000000000005 RBP: ffff8801dae073a0 R08: ffff8801b9fe61c0 R09: ffffed0039c40dd2 R10: ffffed0039c40dd2 R11: ffff8801ce206e93 R12: 00000000421eeaad R13: ffff8801ce206d4e R14: ffff8801ce206cc0 R15: ffff8801cd4f4a80 FS: 0000000000000000(0000) GS:ffff8801dae00000(0063) knlGS:00000000096bc900 CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033 CR2: 0000000020000000 CR3: 00000001c47b6000 CR4: 00000000001406f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: tcp_retransmit_skb+0x2e/0x250 net/ipv4/tcp_output.c:2923 tcp_retransmit_timer+0xc50/0x3060 net/ipv4/tcp_timer.c:488 tcp_write_timer_handler+0x339/0x960 net/ipv4/tcp_timer.c:573 tcp_write_timer+0x111/0x1d0 net/ipv4/tcp_timer.c:593 call_timer_fn+0x230/0x940 kernel/time/timer.c:1326 expire_timers kernel/time/timer.c:1363 [inline] __run_timers+0x79e/0xc50 kernel/time/timer.c:1666 run_timer_softirq+0x4c/0x70 kernel/time/timer.c:1692 __do_softirq+0x2e0/0xaf5 kernel/softirq.c:285 invoke_softirq kernel/softirq.c:365 [inline] irq_exit+0x1d1/0x200 kernel/softirq.c:405 exiting_irq arch/x86/include/asm/apic.h:525 [inline] smp_apic_timer_interrupt+0x17e/0x710 arch/x86/kernel/apic/apic.c:1052 apic_timer_interrupt+0xf/0x20 arch/x86/entry/entry_64.S:863 Fixes: cf60af03ca4e ("net-tcp: Fast Open client - sendmsg(MSG_FASTOPEN)") Signed-off-by: Eric Dumazet Cc: Yuchung Cheng Cc: Neal Cardwell Reported-by: syzbot Acked-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_output.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index a69606031e5f..f07a0a1c98ff 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2691,8 +2691,10 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) return -EBUSY; if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) { - if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) - BUG(); + if (unlikely(before(TCP_SKB_CB(skb)->end_seq, tp->snd_una))) { + WARN_ON_ONCE(1); + return -EINVAL; + } if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq)) return -ENOMEM; } @@ -3236,6 +3238,7 @@ static void tcp_connect_init(struct sock *sk) sock_reset_flag(sk, SOCK_DONE); tp->snd_wnd = 0; tcp_init_wl(tp, 0); + tcp_write_queue_purge(sk); tp->snd_una = tp->write_seq; tp->snd_sml = tp->write_seq; tp->snd_up = tp->write_seq; -- GitLab From 779fd38b60d86511f1ff17c29c2fc9ee2adb0697 Mon Sep 17 00:00:00 2001 From: "hpreg@vmware.com" Date: Mon, 14 May 2018 08:14:34 -0400 Subject: [PATCH 472/855] vmxnet3: set the DMA mask before the first DMA map operation [ Upstream commit 61aeecea40afb2b89933e27cd4adb10fc2e75cfd ] The DMA mask must be set before, not after, the first DMA map operation, or the first DMA map operation could in theory fail on some systems. Fixes: b0eb57cb97e78 ("VMXNET3: Add support for virtual IOMMU") Signed-off-by: Regis Duchesne Acked-by: Ronak Doshi Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/vmxnet3/vmxnet3_drv.c | 50 +++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index f809eed0343c..d27937fcdf85 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -2675,7 +2675,7 @@ vmxnet3_set_mac_addr(struct net_device *netdev, void *p) /* ==================== initialization and cleanup routines ============ */ static int -vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64) +vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter) { int err; unsigned long mmio_start, mmio_len; @@ -2687,30 +2687,12 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64) return err; } - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { - if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) { - dev_err(&pdev->dev, - "pci_set_consistent_dma_mask failed\n"); - err = -EIO; - goto err_set_mask; - } - *dma64 = true; - } else { - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { - dev_err(&pdev->dev, - "pci_set_dma_mask failed\n"); - err = -EIO; - goto err_set_mask; - } - *dma64 = false; - } - err = pci_request_selected_regions(pdev, (1 << 2) - 1, vmxnet3_driver_name); if (err) { dev_err(&pdev->dev, "Failed to request region for adapter: error %d\n", err); - goto err_set_mask; + goto err_enable_device; } pci_set_master(pdev); @@ -2738,7 +2720,7 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64) iounmap(adapter->hw_addr0); err_ioremap: pci_release_selected_regions(pdev, (1 << 2) - 1); -err_set_mask: +err_enable_device: pci_disable_device(pdev); return err; } @@ -3246,7 +3228,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, #endif }; int err; - bool dma64 = false; /* stupid gcc */ + bool dma64; u32 ver; struct net_device *netdev; struct vmxnet3_adapter *adapter; @@ -3292,6 +3274,24 @@ vmxnet3_probe_device(struct pci_dev *pdev, adapter->rx_ring_size = VMXNET3_DEF_RX_RING_SIZE; adapter->rx_ring2_size = VMXNET3_DEF_RX_RING2_SIZE; + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) { + dev_err(&pdev->dev, + "pci_set_consistent_dma_mask failed\n"); + err = -EIO; + goto err_set_mask; + } + dma64 = true; + } else { + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { + dev_err(&pdev->dev, + "pci_set_dma_mask failed\n"); + err = -EIO; + goto err_set_mask; + } + dma64 = false; + } + spin_lock_init(&adapter->cmd_lock); adapter->adapter_pa = dma_map_single(&adapter->pdev->dev, adapter, sizeof(struct vmxnet3_adapter), @@ -3299,7 +3299,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, if (dma_mapping_error(&adapter->pdev->dev, adapter->adapter_pa)) { dev_err(&pdev->dev, "Failed to map dma\n"); err = -EFAULT; - goto err_dma_map; + goto err_set_mask; } adapter->shared = dma_alloc_coherent( &adapter->pdev->dev, @@ -3350,7 +3350,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, } #endif /* VMXNET3_RSS */ - err = vmxnet3_alloc_pci_resources(adapter, &dma64); + err = vmxnet3_alloc_pci_resources(adapter); if (err < 0) goto err_alloc_pci; @@ -3492,7 +3492,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, err_alloc_shared: dma_unmap_single(&adapter->pdev->dev, adapter->adapter_pa, sizeof(struct vmxnet3_adapter), PCI_DMA_TODEVICE); -err_dma_map: +err_set_mask: free_netdev(netdev); return err; } -- GitLab From aab32922616365dc84d26972ade407f6ceb7bdff Mon Sep 17 00:00:00 2001 From: "hpreg@vmware.com" Date: Mon, 14 May 2018 08:14:49 -0400 Subject: [PATCH 473/855] vmxnet3: use DMA memory barriers where required [ Upstream commit f3002c1374fb2367c9d8dbb28852791ef90d2bac ] The gen bits must be read first from (resp. written last to) DMA memory. The proper way to enforce this on Linux is to call dma_rmb() (resp. dma_wmb()). Signed-off-by: Regis Duchesne Acked-by: Ronak Doshi Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/vmxnet3/vmxnet3_drv.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index d27937fcdf85..c999b10531c5 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -369,6 +369,11 @@ vmxnet3_tq_tx_complete(struct vmxnet3_tx_queue *tq, gdesc = tq->comp_ring.base + tq->comp_ring.next2proc; while (VMXNET3_TCD_GET_GEN(&gdesc->tcd) == tq->comp_ring.gen) { + /* Prevent any &gdesc->tcd field from being (speculatively) + * read before (&gdesc->tcd)->gen is read. + */ + dma_rmb(); + completed += vmxnet3_unmap_pkt(VMXNET3_TCD_GET_TXIDX( &gdesc->tcd), tq, adapter->pdev, adapter); @@ -1099,6 +1104,11 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, gdesc->txd.tci = skb_vlan_tag_get(skb); } + /* Ensure that the write to (&gdesc->txd)->gen will be observed after + * all other writes to &gdesc->txd. + */ + dma_wmb(); + /* finally flips the GEN bit of the SOP desc. */ gdesc->dword[2] = cpu_to_le32(le32_to_cpu(gdesc->dword[2]) ^ VMXNET3_TXD_GEN); @@ -1286,6 +1296,12 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, */ break; } + + /* Prevent any rcd field from being (speculatively) read before + * rcd->gen is read. + */ + dma_rmb(); + BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2 && rcd->rqID != rq->dataRingQid); idx = rcd->rxdIdx; @@ -1515,6 +1531,12 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, ring->next2comp = idx; num_to_alloc = vmxnet3_cmd_ring_desc_avail(ring); ring = rq->rx_ring + ring_idx; + + /* Ensure that the writes to rxd->gen bits will be observed + * after all other writes to rxd objects. + */ + dma_wmb(); + while (num_to_alloc) { vmxnet3_getRxDesc(rxd, &ring->base[ring->next2fill].rxd, &rxCmdDesc); -- GitLab From 808449d2bc56bf0de49e03b6784e0986da526ea7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 17 May 2018 17:18:30 -0400 Subject: [PATCH 474/855] ext2: fix a block leak commit 5aa1437d2d9a068c0334bd7c9dafa8ec4f97f13b upstream. open file, unlink it, then use ioctl(2) to make it immutable or append only. Now close it and watch the blocks *not* freed... Immutable/append-only checks belong in ->setattr(). Note: the bug is old and backport to anything prior to 737f2e93b972 ("ext2: convert to use the new truncate convention") will need these checks lifted into ext2_setattr(). Cc: stable@kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/ext2/inode.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 41b8b44a391c..85449a6ddc56 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1258,21 +1258,11 @@ static void __ext2_truncate_blocks(struct inode *inode, loff_t offset) static void ext2_truncate_blocks(struct inode *inode, loff_t offset) { - /* - * XXX: it seems like a bug here that we don't allow - * IS_APPEND inode to have blocks-past-i_size trimmed off. - * review and fix this. - * - * Also would be nice to be able to handle IO errors and such, - * but that's probably too much to ask. - */ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) return; if (ext2_inode_is_fast_symlink(inode)) return; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return; dax_sem_down_write(EXT2_I(inode)); __ext2_truncate_blocks(inode, offset); -- GitLab From 63257f26cec0ef8461d1f1d8a8f81384dcfff93f Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 23 May 2018 18:21:44 +0200 Subject: [PATCH 475/855] s390: add assembler macros for CPU alternatives [ Upstream commit fba9eb7946251d6e420df3bdf7bc45195be7be9a ] Add a header with macros usable in assembler files to emit alternative code sequences. It works analog to the alternatives for inline assmeblies in C files, with the same restrictions and capabilities. The syntax is ALTERNATIVE "", \ "", \ "" and ALTERNATIVE_2 "", \ "", \ "", "", \ "" Reviewed-by: Vasily Gorbik Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/alternative-asm.h | 108 ++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 arch/s390/include/asm/alternative-asm.h diff --git a/arch/s390/include/asm/alternative-asm.h b/arch/s390/include/asm/alternative-asm.h new file mode 100644 index 000000000000..955d620db23e --- /dev/null +++ b/arch/s390/include/asm/alternative-asm.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_S390_ALTERNATIVE_ASM_H +#define _ASM_S390_ALTERNATIVE_ASM_H + +#ifdef __ASSEMBLY__ + +/* + * Check the length of an instruction sequence. The length may not be larger + * than 254 bytes and it has to be divisible by 2. + */ +.macro alt_len_check start,end + .if ( \end - \start ) > 254 + .error "cpu alternatives does not support instructions blocks > 254 bytes\n" + .endif + .if ( \end - \start ) % 2 + .error "cpu alternatives instructions length is odd\n" + .endif +.endm + +/* + * Issue one struct alt_instr descriptor entry (need to put it into + * the section .altinstructions, see below). This entry contains + * enough information for the alternatives patching code to patch an + * instruction. See apply_alternatives(). + */ +.macro alt_entry orig_start, orig_end, alt_start, alt_end, feature + .long \orig_start - . + .long \alt_start - . + .word \feature + .byte \orig_end - \orig_start + .byte \alt_end - \alt_start +.endm + +/* + * Fill up @bytes with nops. The macro emits 6-byte nop instructions + * for the bulk of the area, possibly followed by a 4-byte and/or + * a 2-byte nop if the size of the area is not divisible by 6. + */ +.macro alt_pad_fill bytes + .fill ( \bytes ) / 6, 6, 0xc0040000 + .fill ( \bytes ) % 6 / 4, 4, 0x47000000 + .fill ( \bytes ) % 6 % 4 / 2, 2, 0x0700 +.endm + +/* + * Fill up @bytes with nops. If the number of bytes is larger + * than 6, emit a jg instruction to branch over all nops, then + * fill an area of size (@bytes - 6) with nop instructions. + */ +.macro alt_pad bytes + .if ( \bytes > 0 ) + .if ( \bytes > 6 ) + jg . + \bytes + alt_pad_fill \bytes - 6 + .else + alt_pad_fill \bytes + .endif + .endif +.endm + +/* + * Define an alternative between two instructions. If @feature is + * present, early code in apply_alternatives() replaces @oldinstr with + * @newinstr. ".skip" directive takes care of proper instruction padding + * in case @newinstr is longer than @oldinstr. + */ +.macro ALTERNATIVE oldinstr, newinstr, feature + .pushsection .altinstr_replacement,"ax" +770: \newinstr +771: .popsection +772: \oldinstr +773: alt_len_check 770b, 771b + alt_len_check 772b, 773b + alt_pad ( ( 771b - 770b ) - ( 773b - 772b ) ) +774: .pushsection .altinstructions,"a" + alt_entry 772b, 774b, 770b, 771b, \feature + .popsection +.endm + +/* + * Define an alternative between two instructions. If @feature is + * present, early code in apply_alternatives() replaces @oldinstr with + * @newinstr. ".skip" directive takes care of proper instruction padding + * in case @newinstr is longer than @oldinstr. + */ +.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2 + .pushsection .altinstr_replacement,"ax" +770: \newinstr1 +771: \newinstr2 +772: .popsection +773: \oldinstr +774: alt_len_check 770b, 771b + alt_len_check 771b, 772b + alt_len_check 773b, 774b + .if ( 771b - 770b > 772b - 771b ) + alt_pad ( ( 771b - 770b ) - ( 774b - 773b ) ) + .else + alt_pad ( ( 772b - 771b ) - ( 774b - 773b ) ) + .endif +775: .pushsection .altinstructions,"a" + alt_entry 773b, 775b, 770b, 771b,\feature1 + alt_entry 773b, 775b, 771b, 772b,\feature2 + .popsection +.endm + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_S390_ALTERNATIVE_ASM_H */ -- GitLab From 4a5c26ddfb8657402073f8b43393ede53ad82e6a Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 23 May 2018 18:21:45 +0200 Subject: [PATCH 476/855] s390: move expoline assembler macros to a header [ Upstream commit 6dd85fbb87d1d6b87a3b1f02ca28d7b2abd2e7ba ] To be able to use the expoline branches in different assembler files move the associated macros from entry.S to a new header nospec-insn.h. While we are at it make the macros a bit nicer to use. Cc: stable@vger.kernel.org # 4.16 Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches") Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/nospec-insn.h | 125 ++++++++++++++++++++++++++++ arch/s390/kernel/entry.S | 105 ++++++----------------- 2 files changed, 149 insertions(+), 81 deletions(-) create mode 100644 arch/s390/include/asm/nospec-insn.h diff --git a/arch/s390/include/asm/nospec-insn.h b/arch/s390/include/asm/nospec-insn.h new file mode 100644 index 000000000000..fcb6529de9b7 --- /dev/null +++ b/arch/s390/include/asm/nospec-insn.h @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_S390_NOSPEC_ASM_H +#define _ASM_S390_NOSPEC_ASM_H + +#ifdef __ASSEMBLY__ + +#ifdef CONFIG_EXPOLINE + +/* + * The expoline macros are used to create thunks in the same format + * as gcc generates them. The 'comdat' section flag makes sure that + * the various thunks are merged into a single copy. + */ + .macro __THUNK_PROLOG_NAME name + .pushsection .text.\name,"axG",@progbits,\name,comdat + .globl \name + .hidden \name + .type \name,@function +\name: + .cfi_startproc + .endm + + .macro __THUNK_EPILOG + .cfi_endproc + .popsection + .endm + + .macro __THUNK_PROLOG_BR r1,r2 + __THUNK_PROLOG_NAME __s390x_indirect_jump_r\r2\()use_r\r1 + .endm + + .macro __THUNK_BR r1,r2 + jg __s390x_indirect_jump_r\r2\()use_r\r1 + .endm + + .macro __THUNK_BRASL r1,r2,r3 + brasl \r1,__s390x_indirect_jump_r\r3\()use_r\r2 + .endm + + .macro __DECODE_RR expand,reg,ruse + .set __decode_fail,1 + .irp r1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \reg,%r\r1 + .irp r2,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \ruse,%r\r2 + \expand \r1,\r2 + .set __decode_fail,0 + .endif + .endr + .endif + .endr + .if __decode_fail == 1 + .error "__DECODE_RR failed" + .endif + .endm + + .macro __DECODE_RRR expand,rsave,rtarget,ruse + .set __decode_fail,1 + .irp r1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \rsave,%r\r1 + .irp r2,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \rtarget,%r\r2 + .irp r3,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \ruse,%r\r3 + \expand \r1,\r2,\r3 + .set __decode_fail,0 + .endif + .endr + .endif + .endr + .endif + .endr + .if __decode_fail == 1 + .error "__DECODE_RRR failed" + .endif + .endm + + .macro __THUNK_EX_BR reg,ruse +#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES + exrl 0,555f + j . +#else + larl \ruse,555f + ex 0,0(\ruse) + j . +#endif +555: br \reg + .endm + + .macro GEN_BR_THUNK reg,ruse=%r1 + __DECODE_RR __THUNK_PROLOG_BR,\reg,\ruse + __THUNK_EX_BR \reg,\ruse + __THUNK_EPILOG + .endm + + .macro BR_EX reg,ruse=%r1 +557: __DECODE_RR __THUNK_BR,\reg,\ruse + .pushsection .s390_indirect_branches,"a",@progbits + .long 557b-. + .popsection + .endm + + .macro BASR_EX rsave,rtarget,ruse=%r1 +559: __DECODE_RRR __THUNK_BRASL,\rsave,\rtarget,\ruse + .pushsection .s390_indirect_branches,"a",@progbits + .long 559b-. + .popsection + .endm + +#else + .macro GEN_BR_THUNK reg,ruse=%r1 + .endm + + .macro BR_EX reg,ruse=%r1 + br \reg + .endm + + .macro BASR_EX rsave,rtarget,ruse=%r1 + basr \rsave,\rtarget + .endm +#endif + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_S390_NOSPEC_ASM_H */ diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 1996afeb2e81..a4fd00064c80 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -24,6 +24,7 @@ #include #include #include +#include __PT_R0 = __PT_GPRS __PT_R1 = __PT_GPRS + 8 @@ -226,67 +227,9 @@ _PIF_WORK = (_PIF_PER_TRAP) .popsection .endm -#ifdef CONFIG_EXPOLINE - - .macro GEN_BR_THUNK name,reg,tmp - .section .text.\name,"axG",@progbits,\name,comdat - .globl \name - .hidden \name - .type \name,@function -\name: - .cfi_startproc -#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES - exrl 0,0f -#else - larl \tmp,0f - ex 0,0(\tmp) -#endif - j . -0: br \reg - .cfi_endproc - .endm - - GEN_BR_THUNK __s390x_indirect_jump_r1use_r9,%r9,%r1 - GEN_BR_THUNK __s390x_indirect_jump_r1use_r14,%r14,%r1 - GEN_BR_THUNK __s390x_indirect_jump_r11use_r14,%r14,%r11 - - .macro BASR_R14_R9 -0: brasl %r14,__s390x_indirect_jump_r1use_r9 - .pushsection .s390_indirect_branches,"a",@progbits - .long 0b-. - .popsection - .endm - - .macro BR_R1USE_R14 -0: jg __s390x_indirect_jump_r1use_r14 - .pushsection .s390_indirect_branches,"a",@progbits - .long 0b-. - .popsection - .endm - - .macro BR_R11USE_R14 -0: jg __s390x_indirect_jump_r11use_r14 - .pushsection .s390_indirect_branches,"a",@progbits - .long 0b-. - .popsection - .endm - -#else /* CONFIG_EXPOLINE */ - - .macro BASR_R14_R9 - basr %r14,%r9 - .endm - - .macro BR_R1USE_R14 - br %r14 - .endm - - .macro BR_R11USE_R14 - br %r14 - .endm - -#endif /* CONFIG_EXPOLINE */ - + GEN_BR_THUNK %r9 + GEN_BR_THUNK %r14 + GEN_BR_THUNK %r14,%r11 .section .kprobes.text, "ax" .Ldummy: @@ -303,7 +246,7 @@ _PIF_WORK = (_PIF_PER_TRAP) ENTRY(__bpon) .globl __bpon BPON - BR_R1USE_R14 + BR_EX %r14 /* * Scheduler resume function, called by switch_to @@ -333,7 +276,7 @@ ENTRY(__switch_to) TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_LPP jz 0f .insn s,0xb2800000,__LC_LPP # set program parameter -0: BR_R1USE_R14 +0: BR_EX %r14 .L__critical_start: @@ -399,7 +342,7 @@ sie_exit: xgr %r5,%r5 lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers lg %r2,__SF_EMPTY+16(%r15) # return exit reason code - BR_R1USE_R14 + BR_EX %r14 .Lsie_fault: lghi %r14,-EFAULT stg %r14,__SF_EMPTY+16(%r15) # set exit reason code @@ -458,7 +401,7 @@ ENTRY(system_call) lgf %r9,0(%r8,%r10) # get system call add. TSTMSK __TI_flags(%r12),_TIF_TRACE jnz .Lsysc_tracesys - BASR_R14_R9 # call sys_xxxx + BASR_EX %r14,%r9 # call sys_xxxx stg %r2,__PT_R2(%r11) # store return value .Lsysc_return: @@ -598,7 +541,7 @@ ENTRY(system_call) lmg %r3,%r7,__PT_R3(%r11) stg %r7,STACK_FRAME_OVERHEAD(%r15) lg %r2,__PT_ORIG_GPR2(%r11) - BASR_R14_R9 # call sys_xxx + BASR_EX %r14,%r9 # call sys_xxx stg %r2,__PT_R2(%r11) # store return value .Lsysc_tracenogo: TSTMSK __TI_flags(%r12),_TIF_TRACE @@ -622,7 +565,7 @@ ENTRY(ret_from_fork) lmg %r9,%r10,__PT_R9(%r11) # load gprs ENTRY(kernel_thread_starter) la %r2,0(%r10) - BASR_R14_R9 + BASR_EX %r14,%r9 j .Lsysc_tracenogo /* @@ -698,7 +641,7 @@ ENTRY(pgm_check_handler) je .Lpgm_return lgf %r9,0(%r10,%r1) # load address of handler routine lgr %r2,%r11 # pass pointer to pt_regs - BASR_R14_R9 # branch to interrupt-handler + BASR_EX %r14,%r9 # branch to interrupt-handler .Lpgm_return: LOCKDEP_SYS_EXIT tm __PT_PSW+1(%r11),0x01 # returning to user ? @@ -976,7 +919,7 @@ ENTRY(psw_idle) stpt __TIMER_IDLE_ENTER(%r2) .Lpsw_idle_lpsw: lpswe __SF_EMPTY(%r15) - BR_R1USE_R14 + BR_EX %r14 .Lpsw_idle_end: /* @@ -1021,7 +964,7 @@ ENTRY(save_fpu_regs) .Lsave_fpu_regs_done: oi __LC_CPU_FLAGS+7,_CIF_FPU .Lsave_fpu_regs_exit: - BR_R1USE_R14 + BR_EX %r14 .Lsave_fpu_regs_end: #if IS_ENABLED(CONFIG_KVM) EXPORT_SYMBOL(save_fpu_regs) @@ -1071,7 +1014,7 @@ load_fpu_regs: .Lload_fpu_regs_done: ni __LC_CPU_FLAGS+7,255-_CIF_FPU .Lload_fpu_regs_exit: - BR_R1USE_R14 + BR_EX %r14 .Lload_fpu_regs_end: .L__critical_end: @@ -1244,7 +1187,7 @@ cleanup_critical: jl 0f clg %r9,BASED(.Lcleanup_table+104) # .Lload_fpu_regs_end jl .Lcleanup_load_fpu_regs -0: BR_R11USE_R14 +0: BR_EX %r14 .align 8 .Lcleanup_table: @@ -1274,7 +1217,7 @@ cleanup_critical: ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce larl %r9,sie_exit # skip forward to sie_exit - BR_R11USE_R14 + BR_EX %r14 #endif .Lcleanup_system_call: @@ -1332,7 +1275,7 @@ cleanup_critical: stg %r15,56(%r11) # r15 stack pointer # set new psw address and exit larl %r9,.Lsysc_do_svc - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_system_call_insn: .quad system_call .quad .Lsysc_stmg @@ -1342,7 +1285,7 @@ cleanup_critical: .Lcleanup_sysc_tif: larl %r9,.Lsysc_tif - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_sysc_restore: # check if stpt has been executed @@ -1359,14 +1302,14 @@ cleanup_critical: mvc 0(64,%r11),__PT_R8(%r9) lmg %r0,%r7,__PT_R0(%r9) 1: lmg %r8,%r9,__LC_RETURN_PSW - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_sysc_restore_insn: .quad .Lsysc_exit_timer .quad .Lsysc_done - 4 .Lcleanup_io_tif: larl %r9,.Lio_tif - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_io_restore: # check if stpt has been executed @@ -1380,7 +1323,7 @@ cleanup_critical: mvc 0(64,%r11),__PT_R8(%r9) lmg %r0,%r7,__PT_R0(%r9) 1: lmg %r8,%r9,__LC_RETURN_PSW - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_io_restore_insn: .quad .Lio_exit_timer .quad .Lio_done - 4 @@ -1433,17 +1376,17 @@ cleanup_critical: # prepare return psw nihh %r8,0xfcfd # clear irq & wait state bits lg %r9,48(%r11) # return from psw_idle - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_idle_insn: .quad .Lpsw_idle_lpsw .Lcleanup_save_fpu_regs: larl %r9,save_fpu_regs - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_load_fpu_regs: larl %r9,load_fpu_regs - BR_R11USE_R14 + BR_EX %r14,%r11 /* * Integer constants -- GitLab From f37bfc0d20a0031f82ec46c1107501c40c1626b2 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 23 May 2018 18:21:46 +0200 Subject: [PATCH 477/855] s390/crc32-vx: use expoline for indirect branches [ Upstream commit 467a3bf219cee12259182c5cb4821f88fd518a51 ] The return from the crc32_le_vgfm_16/crc32c_le_vgfm_16 and the crc32_be_vgfm_16 functions are done with "br %r14". These are indirect branches as well and need to use execute trampolines for CONFIG_EXPOLINE=y. Cc: stable@vger.kernel.org # 4.16 Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches") Reviewed-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/crypto/crc32be-vx.S | 5 ++++- arch/s390/crypto/crc32le-vx.S | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/s390/crypto/crc32be-vx.S b/arch/s390/crypto/crc32be-vx.S index 8013989cd2e5..096affb74446 100644 --- a/arch/s390/crypto/crc32be-vx.S +++ b/arch/s390/crypto/crc32be-vx.S @@ -12,6 +12,7 @@ */ #include +#include #include /* Vector register range containing CRC-32 constants */ @@ -66,6 +67,8 @@ .previous + GEN_BR_THUNK %r14 + .text /* * The CRC-32 function(s) use these calling conventions: @@ -202,6 +205,6 @@ ENTRY(crc32_be_vgfm_16) .Ldone: VLGVF %r2,%v2,3 - br %r14 + BR_EX %r14 .previous diff --git a/arch/s390/crypto/crc32le-vx.S b/arch/s390/crypto/crc32le-vx.S index 17f2504c2633..8dc98c1d7cb1 100644 --- a/arch/s390/crypto/crc32le-vx.S +++ b/arch/s390/crypto/crc32le-vx.S @@ -13,6 +13,7 @@ */ #include +#include #include /* Vector register range containing CRC-32 constants */ @@ -75,6 +76,7 @@ .previous + GEN_BR_THUNK %r14 .text @@ -263,6 +265,6 @@ crc32_le_vgfm_generic: .Ldone: VLGVF %r2,%v2,2 - br %r14 + BR_EX %r14 .previous -- GitLab From cba0d6c2d6301f32b0b5d86ad70f3fdd8574d43b Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 23 May 2018 18:21:47 +0200 Subject: [PATCH 478/855] s390/lib: use expoline for indirect branches [ Upstream commit 97489e0663fa700d6e7febddc43b58df98d7bcda ] The return from the memmove, memset, memcpy, __memset16, __memset32 and __memset64 functions are done with "br %r14". These are indirect branches as well and need to use execute trampolines for CONFIG_EXPOLINE=y. Cc: stable@vger.kernel.org # 4.16 Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches") Reviewed-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/lib/mem.S | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/s390/lib/mem.S b/arch/s390/lib/mem.S index be9fa65bfac4..e7672edc284a 100644 --- a/arch/s390/lib/mem.S +++ b/arch/s390/lib/mem.S @@ -6,6 +6,9 @@ #include #include +#include + + GEN_BR_THUNK %r14 /* * memset implementation @@ -39,7 +42,7 @@ ENTRY(memset) .Lmemset_clear_rest: larl %r3,.Lmemset_xc ex %r4,0(%r3) - br %r14 + BR_EX %r14 .Lmemset_fill: stc %r3,0(%r2) cghi %r4,1 @@ -56,7 +59,7 @@ ENTRY(memset) .Lmemset_fill_rest: larl %r3,.Lmemset_mvc ex %r4,0(%r3) - br %r14 + BR_EX %r14 .Lmemset_xc: xc 0(1,%r1),0(%r1) .Lmemset_mvc: @@ -79,7 +82,7 @@ ENTRY(memcpy) .Lmemcpy_rest: larl %r5,.Lmemcpy_mvc ex %r4,0(%r5) - br %r14 + BR_EX %r14 .Lmemcpy_loop: mvc 0(256,%r1),0(%r3) la %r1,256(%r1) -- GitLab From caa47e1f7fb8c35137f1d683cd2f9d43775be009 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 23 May 2018 18:21:48 +0200 Subject: [PATCH 479/855] s390/ftrace: use expoline for indirect branches [ Upstream commit 23a4d7fd34856da8218c4cfc23dba7a6ec0a423a ] The return from the ftrace_stub, _mcount, ftrace_caller and return_to_handler functions is done with "br %r14" and "br %r1". These are indirect branches as well and need to use execute trampolines for CONFIG_EXPOLINE=y. The ftrace_caller function is a special case as it returns to the start of a function and may only use %r0 and %r1. For a pre z10 machine the standard execute trampoline uses a LARL + EX to do this, but this requires *two* registers in the range %r1..%r15. To get around this the 'br %r1' located in the lowcore is used, then the EX instruction does not need an address register. But the lowcore trick may only be used for pre z14 machines, with noexec=on the mapping for the first page may not contain instructions. The solution for that is an ALTERNATIVE in the expoline THUNK generated by 'GEN_BR_THUNK %r1' to switch to EXRL, this relies on the fact that a machine that supports noexec=on has EXRL as well. Cc: stable@vger.kernel.org # 4.16 Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches") Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/nospec-insn.h | 13 +++++++++++++ arch/s390/kernel/asm-offsets.c | 1 + arch/s390/kernel/mcount.S | 14 +++++++++----- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/arch/s390/include/asm/nospec-insn.h b/arch/s390/include/asm/nospec-insn.h index fcb6529de9b7..84c3f1f463a6 100644 --- a/arch/s390/include/asm/nospec-insn.h +++ b/arch/s390/include/asm/nospec-insn.h @@ -2,10 +2,15 @@ #ifndef _ASM_S390_NOSPEC_ASM_H #define _ASM_S390_NOSPEC_ASM_H +#include +#include + #ifdef __ASSEMBLY__ #ifdef CONFIG_EXPOLINE +_LC_BR_R1 = __LC_BR_R1 + /* * The expoline macros are used to create thunks in the same format * as gcc generates them. The 'comdat' section flag makes sure that @@ -76,13 +81,21 @@ .endm .macro __THUNK_EX_BR reg,ruse + # Be very careful when adding instructions to this macro! + # The ALTERNATIVE replacement code has a .+10 which targets + # the "br \reg" after the code has been patched. #ifdef CONFIG_HAVE_MARCH_Z10_FEATURES exrl 0,555f j . #else + .ifc \reg,%r1 + ALTERNATIVE "ex %r0,_LC_BR_R1", ".insn ril,0xc60000000000,0,.+10", 35 + j . + .else larl \ruse,555f ex 0,0(\ruse) j . + .endif #endif 555: br \reg .endm diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index f3df9e0a5dec..85c8ead29582 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -175,6 +175,7 @@ int main(void) OFFSET(__LC_MACHINE_FLAGS, lowcore, machine_flags); OFFSET(__LC_GMAP, lowcore, gmap); OFFSET(__LC_PASTE, lowcore, paste); + OFFSET(__LC_BR_R1, lowcore, br_r1_trampoline); /* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */ OFFSET(__LC_DUMP_REIPL, lowcore, ipib); /* hardware defined lowcore locations 0x1000 - 0x18ff */ diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S index 9a17e4475d27..be75e8e49e43 100644 --- a/arch/s390/kernel/mcount.S +++ b/arch/s390/kernel/mcount.S @@ -8,13 +8,17 @@ #include #include #include +#include #include #include + GEN_BR_THUNK %r1 + GEN_BR_THUNK %r14 + .section .kprobes.text, "ax" ENTRY(ftrace_stub) - br %r14 + BR_EX %r14 #define STACK_FRAME_SIZE (STACK_FRAME_OVERHEAD + __PT_SIZE) #define STACK_PTREGS (STACK_FRAME_OVERHEAD) @@ -22,7 +26,7 @@ ENTRY(ftrace_stub) #define STACK_PTREGS_PSW (STACK_PTREGS + __PT_PSW) ENTRY(_mcount) - br %r14 + BR_EX %r14 EXPORT_SYMBOL(_mcount) @@ -52,7 +56,7 @@ ENTRY(ftrace_caller) #endif lgr %r3,%r14 la %r5,STACK_PTREGS(%r15) - basr %r14,%r1 + BASR_EX %r14,%r1 #ifdef CONFIG_FUNCTION_GRAPH_TRACER # The j instruction gets runtime patched to a nop instruction. # See ftrace_enable_ftrace_graph_caller. @@ -67,7 +71,7 @@ ftrace_graph_caller_end: #endif lg %r1,(STACK_PTREGS_PSW+8)(%r15) lmg %r2,%r15,(STACK_PTREGS_GPRS+2*8)(%r15) - br %r1 + BR_EX %r1 #ifdef CONFIG_FUNCTION_GRAPH_TRACER @@ -80,6 +84,6 @@ ENTRY(return_to_handler) aghi %r15,STACK_FRAME_OVERHEAD lgr %r14,%r2 lmg %r2,%r5,32(%r15) - br %r14 + BR_EX %r14 #endif -- GitLab From b35421ab5735f08b58a7e0cee03228f91465ed99 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 23 May 2018 18:21:49 +0200 Subject: [PATCH 480/855] s390/kernel: use expoline for indirect branches [ Upstream commit c50c84c3ac4d5db683904bdb3257798b6ef980ae ] The assember code in arch/s390/kernel uses a few more indirect branches which need to be done with execute trampolines for CONFIG_EXPOLINE=y. Cc: stable@vger.kernel.org # 4.16 Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches") Reviewed-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/base.S | 24 ++++++++++++++---------- arch/s390/kernel/reipl.S | 7 +++++-- arch/s390/kernel/swsusp.S | 9 ++++++--- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S index 326f717df587..61fca549a93b 100644 --- a/arch/s390/kernel/base.S +++ b/arch/s390/kernel/base.S @@ -8,18 +8,22 @@ #include #include +#include #include #include + GEN_BR_THUNK %r9 + GEN_BR_THUNK %r14 + ENTRY(s390_base_mcck_handler) basr %r13,0 0: lg %r15,__LC_PANIC_STACK # load panic stack aghi %r15,-STACK_FRAME_OVERHEAD larl %r1,s390_base_mcck_handler_fn - lg %r1,0(%r1) - ltgr %r1,%r1 + lg %r9,0(%r1) + ltgr %r9,%r9 jz 1f - basr %r14,%r1 + BASR_EX %r14,%r9 1: la %r1,4095 lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) lpswe __LC_MCK_OLD_PSW @@ -36,10 +40,10 @@ ENTRY(s390_base_ext_handler) basr %r13,0 0: aghi %r15,-STACK_FRAME_OVERHEAD larl %r1,s390_base_ext_handler_fn - lg %r1,0(%r1) - ltgr %r1,%r1 + lg %r9,0(%r1) + ltgr %r9,%r9 jz 1f - basr %r14,%r1 + BASR_EX %r14,%r9 1: lmg %r0,%r15,__LC_SAVE_AREA_ASYNC ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit lpswe __LC_EXT_OLD_PSW @@ -56,10 +60,10 @@ ENTRY(s390_base_pgm_handler) basr %r13,0 0: aghi %r15,-STACK_FRAME_OVERHEAD larl %r1,s390_base_pgm_handler_fn - lg %r1,0(%r1) - ltgr %r1,%r1 + lg %r9,0(%r1) + ltgr %r9,%r9 jz 1f - basr %r14,%r1 + BASR_EX %r14,%r9 lmg %r0,%r15,__LC_SAVE_AREA_SYNC lpswe __LC_PGM_OLD_PSW 1: lpswe disabled_wait_psw-0b(%r13) @@ -116,7 +120,7 @@ ENTRY(diag308_reset) larl %r4,.Lcontinue_psw # Restore PSW flags lpswe 0(%r4) .Lcontinue: - br %r14 + BR_EX %r14 .align 16 .Lrestart_psw: .long 0x00080000,0x80000000 + .Lrestart_part2 diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S index 89ea8c213d82..70d635da782c 100644 --- a/arch/s390/kernel/reipl.S +++ b/arch/s390/kernel/reipl.S @@ -6,8 +6,11 @@ #include #include +#include #include + GEN_BR_THUNK %r9 + # # Issue "store status" for the current CPU to its prefix page # and call passed function afterwards @@ -66,9 +69,9 @@ ENTRY(store_status) st %r4,0(%r1) st %r5,4(%r1) stg %r2,8(%r1) - lgr %r1,%r2 + lgr %r9,%r2 lgr %r2,%r3 - br %r1 + BR_EX %r9 .section .bss .align 8 diff --git a/arch/s390/kernel/swsusp.S b/arch/s390/kernel/swsusp.S index 2d6b6e81f812..4e76aaf7bb38 100644 --- a/arch/s390/kernel/swsusp.S +++ b/arch/s390/kernel/swsusp.S @@ -12,6 +12,7 @@ #include #include #include +#include #include /* @@ -23,6 +24,8 @@ * (see below) in the resume process. * This function runs with disabled interrupts. */ + GEN_BR_THUNK %r14 + .section .text ENTRY(swsusp_arch_suspend) stmg %r6,%r15,__SF_GPRS(%r15) @@ -102,7 +105,7 @@ ENTRY(swsusp_arch_suspend) spx 0x318(%r1) lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) lghi %r2,0 - br %r14 + BR_EX %r14 /* * Restore saved memory image to correct place and restore register context. @@ -200,7 +203,7 @@ pgm_check_entry: lghi %r1,0 sam31 sigp %r1,%r0,SIGP_SET_ARCHITECTURE - basr %r14,%r3 + brasl %r14,_sclp_print_early larl %r3,.Ldisabled_wait_31 lpsw 0(%r3) 4: @@ -266,7 +269,7 @@ restore_registers: /* Return 0 */ lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) lghi %r2,0 - br %r14 + BR_EX %r14 .section .data..nosave,"aw",@progbits .align 8 -- GitLab From b004790d7ec587024443c3194411f6a89a93a3d1 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 23 May 2018 18:21:50 +0200 Subject: [PATCH 481/855] s390: move spectre sysfs attribute code [ Upstream commit 4253b0e0627ee3461e64c2495c616f1c8f6b127b ] The nospec-branch.c file is compiled without the gcc options to generate expoline thunks. The return branch of the sysfs show functions cpu_show_spectre_v1 and cpu_show_spectre_v2 is an indirect branch as well. These need to be compiled with expolines. Move the sysfs functions for spectre reporting to a separate file and loose an '.' for one of the messages. Cc: stable@vger.kernel.org # 4.16 Fixes: d424986f1d ("s390: add sysfs attributes for spectre") Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/Makefile | 1 + arch/s390/kernel/nospec-branch.c | 18 ------------------ arch/s390/kernel/nospec-sysfs.c | 21 +++++++++++++++++++++ 3 files changed, 22 insertions(+), 18 deletions(-) create mode 100644 arch/s390/kernel/nospec-sysfs.c diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 0501cac2ab95..5b139977a3a4 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -63,6 +63,7 @@ obj-y += nospec-branch.o extra-y += head.o head64.o vmlinux.lds +obj-$(CONFIG_SYSFS) += nospec-sysfs.o CFLAGS_REMOVE_nospec-branch.o += $(CC_FLAGS_EXPOLINE) obj-$(CONFIG_MODULES) += module.o diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 9f3b5b382743..060ec24ad0c4 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -44,24 +44,6 @@ static int __init nospec_report(void) } arch_initcall(nospec_report); -#ifdef CONFIG_SYSFS -ssize_t cpu_show_spectre_v1(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "Mitigation: __user pointer sanitization\n"); -} - -ssize_t cpu_show_spectre_v2(struct device *dev, - struct device_attribute *attr, char *buf) -{ - if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) - return sprintf(buf, "Mitigation: execute trampolines\n"); - if (__test_facility(82, S390_lowcore.alt_stfle_fac_list)) - return sprintf(buf, "Mitigation: limited branch prediction.\n"); - return sprintf(buf, "Vulnerable\n"); -} -#endif - #ifdef CONFIG_EXPOLINE int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); diff --git a/arch/s390/kernel/nospec-sysfs.c b/arch/s390/kernel/nospec-sysfs.c new file mode 100644 index 000000000000..8affad5f18cb --- /dev/null +++ b/arch/s390/kernel/nospec-sysfs.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include + +ssize_t cpu_show_spectre_v1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Mitigation: __user pointer sanitization\n"); +} + +ssize_t cpu_show_spectre_v2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) + return sprintf(buf, "Mitigation: execute trampolines\n"); + if (__test_facility(82, S390_lowcore.alt_stfle_fac_list)) + return sprintf(buf, "Mitigation: limited branch prediction\n"); + return sprintf(buf, "Vulnerable\n"); +} -- GitLab From 1ace5fcb2263afab21852dd4ac95db70e2bb03cf Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 23 May 2018 18:21:51 +0200 Subject: [PATCH 482/855] s390: extend expoline to BC instructions [ Upstream commit 6deaa3bbca804b2a3627fd685f75de64da7be535 ] The BPF JIT uses a 'b (%r)' instruction in the definition of the sk_load_word and sk_load_half functions. Add support for branch-on-condition instructions contained in the thunk code of an expoline. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/nospec-insn.h | 57 +++++++++++++++++++++++++++++ arch/s390/kernel/nospec-branch.c | 25 ++++++++++--- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/arch/s390/include/asm/nospec-insn.h b/arch/s390/include/asm/nospec-insn.h index 84c3f1f463a6..9a56e738d645 100644 --- a/arch/s390/include/asm/nospec-insn.h +++ b/arch/s390/include/asm/nospec-insn.h @@ -34,10 +34,18 @@ _LC_BR_R1 = __LC_BR_R1 __THUNK_PROLOG_NAME __s390x_indirect_jump_r\r2\()use_r\r1 .endm + .macro __THUNK_PROLOG_BC d0,r1,r2 + __THUNK_PROLOG_NAME __s390x_indirect_branch_\d0\()_\r2\()use_\r1 + .endm + .macro __THUNK_BR r1,r2 jg __s390x_indirect_jump_r\r2\()use_r\r1 .endm + .macro __THUNK_BC d0,r1,r2 + jg __s390x_indirect_branch_\d0\()_\r2\()use_\r1 + .endm + .macro __THUNK_BRASL r1,r2,r3 brasl \r1,__s390x_indirect_jump_r\r3\()use_r\r2 .endm @@ -80,6 +88,23 @@ _LC_BR_R1 = __LC_BR_R1 .endif .endm + .macro __DECODE_DRR expand,disp,reg,ruse + .set __decode_fail,1 + .irp r1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \reg,%r\r1 + .irp r2,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \ruse,%r\r2 + \expand \disp,\r1,\r2 + .set __decode_fail,0 + .endif + .endr + .endif + .endr + .if __decode_fail == 1 + .error "__DECODE_DRR failed" + .endif + .endm + .macro __THUNK_EX_BR reg,ruse # Be very careful when adding instructions to this macro! # The ALTERNATIVE replacement code has a .+10 which targets @@ -100,17 +125,42 @@ _LC_BR_R1 = __LC_BR_R1 555: br \reg .endm + .macro __THUNK_EX_BC disp,reg,ruse +#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES + exrl 0,556f + j . +#else + larl \ruse,556f + ex 0,0(\ruse) + j . +#endif +556: b \disp(\reg) + .endm + .macro GEN_BR_THUNK reg,ruse=%r1 __DECODE_RR __THUNK_PROLOG_BR,\reg,\ruse __THUNK_EX_BR \reg,\ruse __THUNK_EPILOG .endm + .macro GEN_B_THUNK disp,reg,ruse=%r1 + __DECODE_DRR __THUNK_PROLOG_BC,\disp,\reg,\ruse + __THUNK_EX_BC \disp,\reg,\ruse + __THUNK_EPILOG + .endm + .macro BR_EX reg,ruse=%r1 557: __DECODE_RR __THUNK_BR,\reg,\ruse .pushsection .s390_indirect_branches,"a",@progbits .long 557b-. .popsection + .endm + + .macro B_EX disp,reg,ruse=%r1 +558: __DECODE_DRR __THUNK_BC,\disp,\reg,\ruse + .pushsection .s390_indirect_branches,"a",@progbits + .long 558b-. + .popsection .endm .macro BASR_EX rsave,rtarget,ruse=%r1 @@ -122,10 +172,17 @@ _LC_BR_R1 = __LC_BR_R1 #else .macro GEN_BR_THUNK reg,ruse=%r1 + .endm + + .macro GEN_B_THUNK disp,reg,ruse=%r1 .endm .macro BR_EX reg,ruse=%r1 br \reg + .endm + + .macro B_EX disp,reg,ruse=%r1 + b \disp(\reg) .endm .macro BASR_EX rsave,rtarget,ruse=%r1 diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 060ec24ad0c4..d5eed651b5ab 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -94,7 +94,6 @@ static void __init_or_module __nospec_revert(s32 *start, s32 *end) s32 *epo; /* Second part of the instruction replace is always a nop */ - memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x00, 0x00 }, 4); for (epo = start; epo < end; epo++) { instr = (u8 *) epo + *epo; if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x04) @@ -115,18 +114,34 @@ static void __init_or_module __nospec_revert(s32 *start, s32 *end) br = thunk + (*(int *)(thunk + 2)) * 2; else continue; - if (br[0] != 0x07 || (br[1] & 0xf0) != 0xf0) + /* Check for unconditional branch 0x07f? or 0x47f???? */ + if ((br[0] & 0xbf) != 0x07 || (br[1] & 0xf0) != 0xf0) continue; + + memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x07, 0x00 }, 4); switch (type) { case BRCL_EXPOLINE: - /* brcl to thunk, replace with br + nop */ insnbuf[0] = br[0]; insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f); + if (br[0] == 0x47) { + /* brcl to b, replace with bc + nopr */ + insnbuf[2] = br[2]; + insnbuf[3] = br[3]; + } else { + /* brcl to br, replace with bcr + nop */ + } break; case BRASL_EXPOLINE: - /* brasl to thunk, replace with basr + nop */ - insnbuf[0] = 0x0d; insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f); + if (br[0] == 0x47) { + /* brasl to b, replace with bas + nopr */ + insnbuf[0] = 0x4d; + insnbuf[2] = br[2]; + insnbuf[3] = br[3]; + } else { + /* brasl to br, replace with basr + nop */ + insnbuf[0] = 0x0d; + } break; } -- GitLab From 6089a72d44deb251f347a5d4e4e5f1e99245c0cc Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 23 May 2018 18:21:52 +0200 Subject: [PATCH 483/855] s390: use expoline thunks in the BPF JIT [ Upstream commit de5cb6eb514ebe241e3edeb290cb41deb380b81d ] The BPF JIT need safe guarding against spectre v2 in the sk_load_xxx assembler stubs and the indirect branches generated by the JIT itself need to be converted to expolines. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/net/bpf_jit.S | 16 +++++---- arch/s390/net/bpf_jit_comp.c | 63 ++++++++++++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/arch/s390/net/bpf_jit.S b/arch/s390/net/bpf_jit.S index a1c917d881ec..fa716f2a95a7 100644 --- a/arch/s390/net/bpf_jit.S +++ b/arch/s390/net/bpf_jit.S @@ -8,6 +8,7 @@ */ #include +#include #include "bpf_jit.h" /* @@ -53,7 +54,7 @@ ENTRY(sk_load_##NAME##_pos); \ clg %r3,STK_OFF_HLEN(%r15); /* Offset + SIZE > hlen? */ \ jh sk_load_##NAME##_slow; \ LOAD %r14,-SIZE(%r3,%r12); /* Get data from skb */ \ - b OFF_OK(%r6); /* Return */ \ + B_EX OFF_OK,%r6; /* Return */ \ \ sk_load_##NAME##_slow:; \ lgr %r2,%r7; /* Arg1 = skb pointer */ \ @@ -63,11 +64,14 @@ sk_load_##NAME##_slow:; \ brasl %r14,skb_copy_bits; /* Get data from skb */ \ LOAD %r14,STK_OFF_TMP(%r15); /* Load from temp bufffer */ \ ltgr %r2,%r2; /* Set cc to (%r2 != 0) */ \ - br %r6; /* Return */ + BR_EX %r6; /* Return */ sk_load_common(word, 4, llgf) /* r14 = *(u32 *) (skb->data+offset) */ sk_load_common(half, 2, llgh) /* r14 = *(u16 *) (skb->data+offset) */ + GEN_BR_THUNK %r6 + GEN_B_THUNK OFF_OK,%r6 + /* * Load 1 byte from SKB (optimized version) */ @@ -79,7 +83,7 @@ ENTRY(sk_load_byte_pos) clg %r3,STK_OFF_HLEN(%r15) # Offset >= hlen? jnl sk_load_byte_slow llgc %r14,0(%r3,%r12) # Get byte from skb - b OFF_OK(%r6) # Return OK + B_EX OFF_OK,%r6 # Return OK sk_load_byte_slow: lgr %r2,%r7 # Arg1 = skb pointer @@ -89,7 +93,7 @@ sk_load_byte_slow: brasl %r14,skb_copy_bits # Get data from skb llgc %r14,STK_OFF_TMP(%r15) # Load result from temp buffer ltgr %r2,%r2 # Set cc to (%r2 != 0) - br %r6 # Return cc + BR_EX %r6 # Return cc #define sk_negative_common(NAME, SIZE, LOAD) \ sk_load_##NAME##_slow_neg:; \ @@ -103,7 +107,7 @@ sk_load_##NAME##_slow_neg:; \ jz bpf_error; \ LOAD %r14,0(%r2); /* Get data from pointer */ \ xr %r3,%r3; /* Set cc to zero */ \ - br %r6; /* Return cc */ + BR_EX %r6; /* Return cc */ sk_negative_common(word, 4, llgf) sk_negative_common(half, 2, llgh) @@ -112,4 +116,4 @@ sk_negative_common(byte, 1, llgc) bpf_error: # force a return 0 from jit handler ltgr %r15,%r15 # Set condition code - br %r6 + BR_EX %r6 diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index e8dee623d545..e7ce2577f0c9 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "bpf_jit.h" int bpf_jit_enable __read_mostly; @@ -41,6 +43,8 @@ struct bpf_jit { int base_ip; /* Base address for literal pool */ int ret0_ip; /* Address of return 0 */ int exit_ip; /* Address of exit */ + int r1_thunk_ip; /* Address of expoline thunk for 'br %r1' */ + int r14_thunk_ip; /* Address of expoline thunk for 'br %r14' */ int tail_call_start; /* Tail call start offset */ int labels[1]; /* Labels for local jumps */ }; @@ -251,6 +255,19 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1) REG_SET_SEEN(b2); \ }) +#define EMIT6_PCREL_RILB(op, b, target) \ +({ \ + int rel = (target - jit->prg) / 2; \ + _EMIT6(op | reg_high(b) << 16 | rel >> 16, rel & 0xffff); \ + REG_SET_SEEN(b); \ +}) + +#define EMIT6_PCREL_RIL(op, target) \ +({ \ + int rel = (target - jit->prg) / 2; \ + _EMIT6(op | rel >> 16, rel & 0xffff); \ +}) + #define _EMIT6_IMM(op, imm) \ ({ \ unsigned int __imm = (imm); \ @@ -470,8 +487,45 @@ static void bpf_jit_epilogue(struct bpf_jit *jit) EMIT4(0xb9040000, REG_2, BPF_REG_0); /* Restore registers */ save_restore_regs(jit, REGS_RESTORE); + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) { + jit->r14_thunk_ip = jit->prg; + /* Generate __s390_indirect_jump_r14 thunk */ + if (test_facility(35)) { + /* exrl %r0,.+10 */ + EMIT6_PCREL_RIL(0xc6000000, jit->prg + 10); + } else { + /* larl %r1,.+14 */ + EMIT6_PCREL_RILB(0xc0000000, REG_1, jit->prg + 14); + /* ex 0,0(%r1) */ + EMIT4_DISP(0x44000000, REG_0, REG_1, 0); + } + /* j . */ + EMIT4_PCREL(0xa7f40000, 0); + } /* br %r14 */ _EMIT2(0x07fe); + + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable && + (jit->seen & SEEN_FUNC)) { + jit->r1_thunk_ip = jit->prg; + /* Generate __s390_indirect_jump_r1 thunk */ + if (test_facility(35)) { + /* exrl %r0,.+10 */ + EMIT6_PCREL_RIL(0xc6000000, jit->prg + 10); + /* j . */ + EMIT4_PCREL(0xa7f40000, 0); + /* br %r1 */ + _EMIT2(0x07f1); + } else { + /* larl %r1,.+14 */ + EMIT6_PCREL_RILB(0xc0000000, REG_1, jit->prg + 14); + /* ex 0,S390_lowcore.br_r1_tampoline */ + EMIT4_DISP(0x44000000, REG_0, REG_0, + offsetof(struct lowcore, br_r1_trampoline)); + /* j . */ + EMIT4_PCREL(0xa7f40000, 0); + } + } } /* @@ -977,8 +1031,13 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i /* lg %w1,(%l) */ EMIT6_DISP_LH(0xe3000000, 0x0004, REG_W1, REG_0, REG_L, EMIT_CONST_U64(func)); - /* basr %r14,%w1 */ - EMIT2(0x0d00, REG_14, REG_W1); + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) { + /* brasl %r14,__s390_indirect_jump_r1 */ + EMIT6_PCREL_RILB(0xc0050000, REG_14, jit->r1_thunk_ip); + } else { + /* basr %r14,%w1 */ + EMIT2(0x0d00, REG_14, REG_W1); + } /* lgr %b0,%r2: load return value into %b0 */ EMIT4(0xb9040000, BPF_REG_0, REG_2); if (bpf_helper_changes_skb_data((void *)func)) { -- GitLab From e420d98384760f55ffac9951b9b5cccbf2edd752 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Thu, 8 Mar 2018 10:34:53 +0800 Subject: [PATCH 484/855] scsi: libsas: defer ata device eh commands to libata commit 318aaf34f1179b39fa9c30fa0f3288b645beee39 upstream. When ata device doing EH, some commands still attached with tasks are not passed to libata when abort failed or recover failed, so libata did not handle these commands. After these commands done, sas task is freed, but ata qc is not freed. This will cause ata qc leak and trigger a warning like below: WARNING: CPU: 0 PID: 28512 at drivers/ata/libata-eh.c:4037 ata_eh_finish+0xb4/0xcc CPU: 0 PID: 28512 Comm: kworker/u32:2 Tainted: G W OE 4.14.0#1 ...... Call trace: [] ata_eh_finish+0xb4/0xcc [] ata_do_eh+0xc4/0xd8 [] ata_std_error_handler+0x44/0x8c [] ata_scsi_port_error_handler+0x480/0x694 [] async_sas_ata_eh+0x4c/0x80 [] async_run_entry_fn+0x4c/0x170 [] process_one_work+0x144/0x390 [] worker_thread+0x144/0x418 [] kthread+0x10c/0x138 [] ret_from_fork+0x10/0x18 If ata qc leaked too many, ata tag allocation will fail and io blocked for ever. As suggested by Dan Williams, defer ata device commands to libata and merge sas_eh_finish_cmd() with sas_eh_defer_cmd(). libata will handle ata qcs correctly after this. Signed-off-by: Jason Yan CC: Xiaofei Tan CC: John Garry CC: Dan Williams Reviewed-by: Dan Williams Signed-off-by: Martin K. Petersen Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/libsas/sas_scsi_host.c | 33 ++++++++++++----------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 519dac4e341e..9a8c2f97ed70 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -222,6 +222,7 @@ int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) { struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host); + struct domain_device *dev = cmd_to_domain_dev(cmd); struct sas_task *task = TO_SAS_TASK(cmd); /* At this point, we only get called following an actual abort @@ -230,6 +231,14 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) */ sas_end_task(cmd, task); + if (dev_is_sata(dev)) { + /* defer commands to libata so that libata EH can + * handle ata qcs correctly + */ + list_move_tail(&cmd->eh_entry, &sas_ha->eh_ata_q); + return; + } + /* now finish the command and move it on to the error * handler done list, this also takes it off the * error handler pending list. @@ -237,22 +246,6 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q); } -static void sas_eh_defer_cmd(struct scsi_cmnd *cmd) -{ - struct domain_device *dev = cmd_to_domain_dev(cmd); - struct sas_ha_struct *ha = dev->port->ha; - struct sas_task *task = TO_SAS_TASK(cmd); - - if (!dev_is_sata(dev)) { - sas_eh_finish_cmd(cmd); - return; - } - - /* report the timeout to libata */ - sas_end_task(cmd, task); - list_move_tail(&cmd->eh_entry, &ha->eh_ata_q); -} - static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd) { struct scsi_cmnd *cmd, *n; @@ -260,7 +253,7 @@ static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd list_for_each_entry_safe(cmd, n, error_q, eh_entry) { if (cmd->device->sdev_target == my_cmd->device->sdev_target && cmd->device->lun == my_cmd->device->lun) - sas_eh_defer_cmd(cmd); + sas_eh_finish_cmd(cmd); } } @@ -622,12 +615,12 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head * case TASK_IS_DONE: SAS_DPRINTK("%s: task 0x%p is done\n", __func__, task); - sas_eh_defer_cmd(cmd); + sas_eh_finish_cmd(cmd); continue; case TASK_IS_ABORTED: SAS_DPRINTK("%s: task 0x%p is aborted\n", __func__, task); - sas_eh_defer_cmd(cmd); + sas_eh_finish_cmd(cmd); continue; case TASK_IS_AT_LU: SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); @@ -638,7 +631,7 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head * "recovered\n", SAS_ADDR(task->dev), cmd->device->lun); - sas_eh_defer_cmd(cmd); + sas_eh_finish_cmd(cmd); sas_scsi_clear_queue_lu(work_q, cmd); goto Again; } -- GitLab From ad2518320bc440ed3db072e2444a1bb226a9cf7a Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 18 May 2018 16:23:18 +0200 Subject: [PATCH 485/855] scsi: sg: allocate with __GFP_ZERO in sg_build_indirect() commit a45b599ad808c3c982fdcdc12b0b8611c2f92824 upstream. This shall help avoid copying uninitialized memory to the userspace when calling ioctl(fd, SG_IO) with an empty command. Reported-by: syzbot+7d26fc1eea198488deab@syzkaller.appspotmail.com Cc: stable@vger.kernel.org Signed-off-by: Alexander Potapenko Acked-by: Douglas Gilbert Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index f61b37109e5c..0f81d739f9e9 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1893,7 +1893,7 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) num = (rem_sz > scatter_elem_sz_prev) ? scatter_elem_sz_prev : rem_sz; - schp->pages[k] = alloc_pages(gfp_mask, order); + schp->pages[k] = alloc_pages(gfp_mask | __GFP_ZERO, order); if (!schp->pages[k]) goto out; -- GitLab From 6c65719153f983dc3ac6afd321fd463cba22ee13 Mon Sep 17 00:00:00 2001 From: Jens Remus Date: Thu, 3 May 2018 13:52:47 +0200 Subject: [PATCH 486/855] scsi: zfcp: fix infinite iteration on ERP ready list commit fa89adba1941e4f3b213399b81732a5c12fd9131 upstream. zfcp_erp_adapter_reopen() schedules blocking of all of the adapter's rports via zfcp_scsi_schedule_rports_block() and enqueues a reopen adapter ERP action via zfcp_erp_action_enqueue(). Both are separately processed asynchronously and concurrently. Blocking of rports is done in a kworker by zfcp_scsi_rport_work(). It calls zfcp_scsi_rport_block(), which then traces a DBF REC "scpdely" via zfcp_dbf_rec_trig(). zfcp_dbf_rec_trig() acquires the DBF REC spin lock and then iterates with list_for_each() over the adapter's ERP ready list without holding the ERP lock. This opens a race window in which the current list entry can be moved to another list, causing list_for_each() to iterate forever on the wrong list, as the erp_ready_head is never encountered as terminal condition. Meanwhile the ERP action can be processed in the ERP thread by zfcp_erp_thread(). It calls zfcp_erp_strategy(), which acquires the ERP lock and then calls zfcp_erp_action_to_running() to move the ERP action from the ready to the running list. zfcp_erp_action_to_running() can move the ERP action using list_move() just during the aforementioned race window. It then traces a REC RUN "erator1" via zfcp_dbf_rec_run(). zfcp_dbf_rec_run() tries to acquire the DBF REC spin lock. If this is held by the infinitely looping kworker, it effectively spins forever. Example Sequence Diagram: Process ERP Thread rport_work ------------------- ------------------- ------------------- zfcp_erp_adapter_reopen() zfcp_erp_adapter_block() zfcp_scsi_schedule_rports_block() lock ERP zfcp_scsi_rport_work() zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER) list_add_tail() on ready !(rport_task==RPORT_ADD) wake_up() ERP thread zfcp_scsi_rport_block() zfcp_dbf_rec_trig() zfcp_erp_strategy() zfcp_dbf_rec_trig() unlock ERP lock DBF REC zfcp_erp_wait() lock ERP | zfcp_erp_action_to_running() | list_for_each() ready | list_move() current entry | ready to running | zfcp_dbf_rec_run() endless loop over running | zfcp_dbf_rec_run_lvl() | lock DBF REC spins forever Any adapter recovery can trigger this, such as setting the device offline or reboot. V4.9 commit 4eeaa4f3f1d6 ("zfcp: close window with unblocked rport during rport gone") introduced additional tracing of (un)blocking of rports. It missed that the adapter->erp_lock must be held when calling zfcp_dbf_rec_trig(). This fix uses the approach formerly introduced by commit aa0fec62391c ("[SCSI] zfcp: Fix sparse warning by providing new entry in dbf") that got later removed by commit ae0904f60fab ("[SCSI] zfcp: Redesign of the debug tracing for recovery actions."). Introduce zfcp_dbf_rec_trig_lock(), a wrapper for zfcp_dbf_rec_trig() that acquires and releases the adapter->erp_lock for read. Reported-by: Sebastian Ott Signed-off-by: Jens Remus Fixes: 4eeaa4f3f1d6 ("zfcp: close window with unblocked rport during rport gone") Cc: # 2.6.32+ Reviewed-by: Benjamin Block Signed-off-by: Steffen Maier Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_dbf.c | 23 ++++++++++++++++++++++- drivers/s390/scsi/zfcp_ext.h | 5 ++++- drivers/s390/scsi/zfcp_scsi.c | 14 +++++++------- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 34367d172961..4534a7ce77b8 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -3,7 +3,7 @@ * * Debug traces for zfcp. * - * Copyright IBM Corp. 2002, 2017 + * Copyright IBM Corp. 2002, 2018 */ #define KMSG_COMPONENT "zfcp" @@ -287,6 +287,27 @@ void zfcp_dbf_rec_trig(char *tag, struct zfcp_adapter *adapter, spin_unlock_irqrestore(&dbf->rec_lock, flags); } +/** + * zfcp_dbf_rec_trig_lock - trace event related to triggered recovery with lock + * @tag: identifier for event + * @adapter: adapter on which the erp_action should run + * @port: remote port involved in the erp_action + * @sdev: scsi device involved in the erp_action + * @want: wanted erp_action + * @need: required erp_action + * + * The adapter->erp_lock must not be held. + */ +void zfcp_dbf_rec_trig_lock(char *tag, struct zfcp_adapter *adapter, + struct zfcp_port *port, struct scsi_device *sdev, + u8 want, u8 need) +{ + unsigned long flags; + + read_lock_irqsave(&adapter->erp_lock, flags); + zfcp_dbf_rec_trig(tag, adapter, port, sdev, want, need); + read_unlock_irqrestore(&adapter->erp_lock, flags); +} /** * zfcp_dbf_rec_run_lvl - trace event related to running recovery diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 21c8c689b02b..7a7984a50683 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -3,7 +3,7 @@ * * External function declarations. * - * Copyright IBM Corp. 2002, 2016 + * Copyright IBM Corp. 2002, 2018 */ #ifndef ZFCP_EXT_H @@ -34,6 +34,9 @@ extern int zfcp_dbf_adapter_register(struct zfcp_adapter *); extern void zfcp_dbf_adapter_unregister(struct zfcp_adapter *); extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *, struct zfcp_port *, struct scsi_device *, u8, u8); +extern void zfcp_dbf_rec_trig_lock(char *tag, struct zfcp_adapter *adapter, + struct zfcp_port *port, + struct scsi_device *sdev, u8 want, u8 need); extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *); extern void zfcp_dbf_rec_run_lvl(int level, char *tag, struct zfcp_erp_action *erp); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index a9b8104b982e..bb99db2948ab 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -3,7 +3,7 @@ * * Interface to Linux SCSI midlayer. * - * Copyright IBM Corp. 2002, 2017 + * Copyright IBM Corp. 2002, 2018 */ #define KMSG_COMPONENT "zfcp" @@ -616,9 +616,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port) ids.port_id = port->d_id; ids.roles = FC_RPORT_ROLE_FCP_TARGET; - zfcp_dbf_rec_trig("scpaddy", port->adapter, port, NULL, - ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD, - ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD); + zfcp_dbf_rec_trig_lock("scpaddy", port->adapter, port, NULL, + ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD, + ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD); rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); if (!rport) { dev_err(&port->adapter->ccw_device->dev, @@ -640,9 +640,9 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port) struct fc_rport *rport = port->rport; if (rport) { - zfcp_dbf_rec_trig("scpdely", port->adapter, port, NULL, - ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL, - ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL); + zfcp_dbf_rec_trig_lock("scpdely", port->adapter, port, NULL, + ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL, + ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL); fc_remote_port_delete(rport); port->rport = NULL; } -- GitLab From 7d73a8c07d8486c3d1fd7d22bacc7dd7c19007cb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 3 Apr 2018 14:33:49 +0200 Subject: [PATCH 487/855] cfg80211: limit wiphy names to 128 bytes commit a7cfebcb7594a24609268f91299ab85ba064bf82 upstream. There's currently no limit on wiphy names, other than netlink message size and memory limitations, but that causes issues when, for example, the wiphy name is used in a uevent, e.g. in rfkill where we use the same name for the rfkill instance, and then the buffer there is "only" 2k for the environment variables. This was reported by syzkaller, which used a 4k name. Limit the name to something reasonable, I randomly picked 128. Reported-by: syzbot+230d9e642a85d3fec29c@syzkaller.appspotmail.com Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/nl80211.h | 2 ++ net/wireless/core.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index d3cbe48b286d..7290eacc8cee 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2379,6 +2379,8 @@ enum nl80211_attrs { #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS +#define NL80211_WIPHY_NAME_MAXLEN 128 + #define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_HT_RATES 77 #define NL80211_MAX_SUPP_REG_RULES 64 diff --git a/net/wireless/core.c b/net/wireless/core.c index ce16da2905dc..7fbf4dd07277 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -95,6 +95,9 @@ static int cfg80211_dev_check_name(struct cfg80211_registered_device *rdev, ASSERT_RTNL(); + if (strlen(newname) > NL80211_WIPHY_NAME_MAXLEN) + return -EINVAL; + /* prohibit calling the thing phy%d when %d is not its number */ sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) { -- GitLab From 2595f213a4ad5071d419e2f5e15d3ca81679c231 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 18 May 2018 16:09:16 -0700 Subject: [PATCH 488/855] hfsplus: stop workqueue when fill_super() failed commit 66072c29328717072fd84aaff3e070e3f008ba77 upstream. syzbot is reporting ODEBUG messages at hfsplus_fill_super() [1]. This is because hfsplus_fill_super() forgot to call cancel_delayed_work_sync(). As far as I can see, it is hfsplus_mark_mdb_dirty() from hfsplus_new_inode() in hfsplus_fill_super() that calls queue_delayed_work(). Therefore, I assume that hfsplus_new_inode() does not fail if queue_delayed_work() was called, and the out_put_hidden_dir label is the appropriate location to call cancel_delayed_work_sync(). [1] https://syzkaller.appspot.com/bug?id=a66f45e96fdbeb76b796bf46eb25ea878c42a6c9 Link: http://lkml.kernel.org/r/964a8b27-cd69-357c-fe78-76b066056201@I-love.SAKURA.ne.jp Signed-off-by: Tetsuo Handa Reported-by: syzbot Cc: Al Viro Cc: David Howells Cc: Ernesto A. Fernandez Cc: Vyacheslav Dubeyko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/hfsplus/super.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 11854dd84572..b9563cdcfe28 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -588,6 +588,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) return 0; out_put_hidden_dir: + cancel_delayed_work_sync(&sbi->sync_work); iput(sbi->hidden_dir); out_put_root: dput(sb->s_root); -- GitLab From a81f401585737316b29bef95fe6cfb3a4f0bbe5d Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 9 May 2018 19:42:20 +0900 Subject: [PATCH 489/855] x86/kexec: Avoid double free_page() upon do_kexec_load() failure commit a466ef76b815b86748d9870ef2a430af7b39c710 upstream. >From ff82bedd3e12f0d3353282054ae48c3bd8c72012 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 9 May 2018 12:12:39 +0900 Subject: x86/kexec: Avoid double free_page() upon do_kexec_load() failure syzbot is reporting crashes after memory allocation failure inside do_kexec_load() [1]. This is because free_transition_pgtable() is called by both init_transition_pgtable() and machine_kexec_cleanup() when memory allocation failed inside init_transition_pgtable(). Regarding 32bit code, machine_kexec_free_page_tables() is called by both machine_kexec_alloc_page_tables() and machine_kexec_cleanup() when memory allocation failed inside machine_kexec_alloc_page_tables(). Fix this by leaving the error handling to machine_kexec_cleanup() (and optionally setting NULL after free_page()). [1] https://syzkaller.appspot.com/bug?id=91e52396168cf2bdd572fe1e1bc0bc645c1c6b40 Fixes: f5deb79679af6eb4 ("x86: kexec: Use one page table in x86_64 machine_kexec") Fixes: 92be3d6bdf2cb349 ("kexec/i386: allocate page table pages dynamically") Reported-by: syzbot Signed-off-by: Tetsuo Handa Signed-off-by: Thomas Gleixner Acked-by: Baoquan He Cc: thomas.lendacky@amd.com Cc: prudo@linux.vnet.ibm.com Cc: Huang Ying Cc: syzkaller-bugs@googlegroups.com Cc: takahiro.akashi@linaro.org Cc: H. Peter Anvin Cc: akpm@linux-foundation.org Cc: dyoung@redhat.com Cc: kirill.shutemov@linux.intel.com Link: https://lkml.kernel.org/r/201805091942.DGG12448.tMFVFSJFQOOLHO@I-love.SAKURA.ne.jp Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/machine_kexec_32.c | 6 +++++- arch/x86/kernel/machine_kexec_64.c | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c index 469b23d6acc2..fd7e9937ddd6 100644 --- a/arch/x86/kernel/machine_kexec_32.c +++ b/arch/x86/kernel/machine_kexec_32.c @@ -71,12 +71,17 @@ static void load_segments(void) static void machine_kexec_free_page_tables(struct kimage *image) { free_page((unsigned long)image->arch.pgd); + image->arch.pgd = NULL; #ifdef CONFIG_X86_PAE free_page((unsigned long)image->arch.pmd0); + image->arch.pmd0 = NULL; free_page((unsigned long)image->arch.pmd1); + image->arch.pmd1 = NULL; #endif free_page((unsigned long)image->arch.pte0); + image->arch.pte0 = NULL; free_page((unsigned long)image->arch.pte1); + image->arch.pte1 = NULL; } static int machine_kexec_alloc_page_tables(struct kimage *image) @@ -93,7 +98,6 @@ static int machine_kexec_alloc_page_tables(struct kimage *image) !image->arch.pmd0 || !image->arch.pmd1 || #endif !image->arch.pte0 || !image->arch.pte1) { - machine_kexec_free_page_tables(image); return -ENOMEM; } return 0; diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index a5784a14f8d1..eae59cad0b07 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c @@ -37,8 +37,11 @@ static struct kexec_file_ops *kexec_file_loaders[] = { static void free_transition_pgtable(struct kimage *image) { free_page((unsigned long)image->arch.pud); + image->arch.pud = NULL; free_page((unsigned long)image->arch.pmd); + image->arch.pmd = NULL; free_page((unsigned long)image->arch.pte); + image->arch.pte = NULL; } static int init_transition_pgtable(struct kimage *image, pgd_t *pgd) @@ -79,7 +82,6 @@ static int init_transition_pgtable(struct kimage *image, pgd_t *pgd) set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL_EXEC)); return 0; err: - free_transition_pgtable(image); return result; } -- GitLab From d9a19ff1fa9a627f4cae3e7608532ac807f66963 Mon Sep 17 00:00:00 2001 From: John Keeping Date: Fri, 12 Jan 2018 18:43:32 +0000 Subject: [PATCH 490/855] usb: gadget: f_uac2: fix bFirstInterface in composite gadget [ Upstream commit 8813a59ed892305b5ac1b5b901740b1ad4b5fefa ] If there are multiple functions associated with a configuration, then the UAC2 interfaces may not start at zero. Set the correct first interface number in the association descriptor so that the audio interfaces are enumerated correctly in this case. Reviewed-by: Krzysztof Opasiak Signed-off-by: John Keeping Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_uac2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 969cfe741380..5474b5187be0 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -1040,6 +1040,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); return ret; } + iad_desc.bFirstInterface = ret; + std_ac_if_desc.bInterfaceNumber = ret; agdev->ac_intf = ret; agdev->ac_alt = 0; -- GitLab From c6a43f20ff3e1e7fdfba7e12d17ba1898e5421bf Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 17 Jan 2018 13:22:49 -0800 Subject: [PATCH 491/855] usb: dwc3: Undo PHY init if soft reset fails [ Upstream commit 00b42170c86f90ac9dea83a7dfcd3f0c38098fe2 ] In this function, we init the USB2 and USB3 PHYs, but if soft reset times out, we don't unwind this. Noticed by inspection. Signed-off-by: Brian Norris Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a0c2b8b6edd0..b8d272ed2355 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -166,6 +166,9 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) udelay(1); } while (--retries); + phy_exit(dwc->usb3_generic_phy); + phy_exit(dwc->usb2_generic_phy); + return -ETIMEDOUT; } -- GitLab From 7a1edc325506d2671429e27753a29fc829847858 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 22 Jan 2018 15:01:42 +0200 Subject: [PATCH 492/855] usb: dwc3: omap: don't miss events during suspend/resume [ Upstream commit c49f63055e252810e5d6c83a4943b18db16b3cd8 ] The USB cable state can change during suspend/resume so be sure to check and update the extcon state. Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-omap.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 35b63518baf6..f221cb479e14 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -598,9 +598,25 @@ static int dwc3_omap_resume(struct device *dev) return 0; } +static void dwc3_omap_complete(struct device *dev) +{ + struct dwc3_omap *omap = dev_get_drvdata(dev); + + if (extcon_get_state(omap->edev, EXTCON_USB)) + dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); + else + dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF); + + if (extcon_get_state(omap->edev, EXTCON_USB_HOST)) + dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); + else + dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT); +} + static const struct dev_pm_ops dwc3_omap_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume) + .complete = dwc3_omap_complete, }; #define DEV_PM_OPS (&dwc3_omap_dev_pm_ops) -- GitLab From 36d64865d33462851aaf35c1f8e021889beec15a Mon Sep 17 00:00:00 2001 From: Manu Gautam Date: Thu, 21 Dec 2017 09:54:25 +0530 Subject: [PATCH 493/855] usb: gadget: core: Fix use-after-free of usb_request [ Upstream commit e74bd4d358e5455233f1dcc3975425905b270b91 ] Driver is tracing usb_request after freeing it. Fix it by changing the order. Signed-off-by: Manu Gautam Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 188961780b8a..139f6cce30b1 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -190,8 +190,8 @@ EXPORT_SYMBOL_GPL(usb_ep_alloc_request); void usb_ep_free_request(struct usb_ep *ep, struct usb_request *req) { - ep->ops->free_request(ep, req); trace_usb_ep_free_request(ep, req, 0); + ep->ops->free_request(ep, req); } EXPORT_SYMBOL_GPL(usb_ep_free_request); -- GitLab From 20eeffc5ba328afbf73550ae8aa9e43be3a8dd6e Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 12 Feb 2018 00:14:42 +0100 Subject: [PATCH 494/855] usb: gadget: fsl_udc_core: fix ep valid checks [ Upstream commit 20c63f4089cceab803438c383631963e34c4d8e5 ] Clang reports the following warning: drivers/usb/gadget/udc/fsl_udc_core.c:1312:10: warning: address of array 'ep->name' will always evaluate to 'true' [-Wpointer-bool-conversion] if (ep->name) ~~ ~~~~^~~~ It seems that the authors intention was to check if the ep has been configured through struct_ep_setup. Check whether struct usb_ep name pointer has been set instead. Signed-off-by: Stefan Agner Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/fsl_udc_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index aac0ce8aeb0b..8991a4070792 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -1310,7 +1310,7 @@ static void udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe) { struct fsl_ep *ep = get_ep_by_pipe(udc, pipe); - if (ep->name) + if (ep->ep.name) nuke(ep, -ESHUTDOWN); } @@ -1698,7 +1698,7 @@ static void dtd_complete_irq(struct fsl_udc *udc) curr_ep = get_ep_by_pipe(udc, i); /* If the ep is configured */ - if (curr_ep->name == NULL) { + if (!curr_ep->ep.name) { WARNING("Invalid EP?"); continue; } -- GitLab From 0e025f5b63713f850bdd7bea7a2bedf8fb23f75d Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Tue, 16 Jan 2018 16:04:24 +0400 Subject: [PATCH 495/855] usb: dwc2: Fix dwc2_hsotg_core_init_disconnected() [ Upstream commit 755d739534f998d92e348fba8ffb0478416576e7 ] We should call dwc2_hsotg_enqueue_setup() after properly setting lx_state. Because it may cause error-out from dwc2_hsotg_enqueue_setup() due to wrong value in lx_state. Issue can be reproduced by loading driver while connected A-Connector (start in A-HOST mode) then disconnect A-Connector to switch to B-DEVICE. Acked-by: John Youn Signed-off-by: Vardan Mikayelyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/gadget.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index cfdd5c3da236..09921ef07ac5 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2642,12 +2642,6 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0); - dwc2_hsotg_enqueue_setup(hsotg); - - dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", - dwc2_readl(hsotg->regs + DIEPCTL0), - dwc2_readl(hsotg->regs + DOEPCTL0)); - /* clear global NAKs */ val = DCTL_CGOUTNAK | DCTL_CGNPINNAK; if (!is_usb_reset) @@ -2658,6 +2652,12 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, mdelay(3); hsotg->lx_state = DWC2_L0; + + dwc2_hsotg_enqueue_setup(hsotg); + + dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", + dwc2_readl(hsotg->regs + DIEPCTL0), + dwc2_readl(hsotg->regs + DOEPCTL0)); } static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) -- GitLab From 8f271cf4114fe3871679da7b819f55b02c4894a5 Mon Sep 17 00:00:00 2001 From: Dominik Bozek Date: Thu, 15 Feb 2018 21:27:48 -0800 Subject: [PATCH 496/855] usb: cdc_acm: prevent race at write to acm while system resumes [ Upstream commit b86b8eb6fecb5a4bac1ed0ca925c4082a61ea6e9 ] ACM driver may accept data to transmit while system is not fully resumed. In this case ACM driver buffers data and prepare URBs on usb anchor list. There is a little chance that two tasks put a char and initiate acm_tty_flush_chars(). In such a case, driver will put one URB twice on usb anchor list. This patch also reset length of data before resue of a buffer. This not only prevent sending rubbish, but also lower risc of race. Without this patch we hit following kernel panic in one of our stabilty/stress tests. [ 46.884442] *list_add double add*: new=ffff9b2ab7289330, prev=ffff9b2ab7289330, next=ffff9b2ab81e28e0. [ 46.884476] Modules linked in: hci_uart btbcm bluetooth rfkill_gpio igb_avb(O) cfg80211 snd_soc_sst_bxt_tdf8532 snd_soc_skl snd_soc_skl_ipc snd_soc_sst_ipc snd_soc_sst_dsp snd_soc_sst_acpi snd_soc_sst_match snd_hda_ext_core snd_hda_core trusty_timer trusty_wall trusty_log trusty_virtio trusty_ipc trusty_mem trusty_irq trusty virtio_ring virtio intel_ipu4_mmu_bxtB0 lib2600_mod_bxtB0 intel_ipu4_isys_mod_bxtB0 lib2600psys_mod_bxtB0 intel_ipu4_psys_mod_bxtB0 intel_ipu4_mod_bxtB0 intel_ipu4_wrapper_bxtB0 intel_ipu4_acpi videobuf2_dma_contig as3638 dw9714 lm3643 crlmodule smiapp smiapp_pll [ 46.884480] CPU: 1 PID: 33 Comm: kworker/u8:1 Tainted: G U W O 4.9.56-quilt-2e5dc0ac-g618ed69ced6e-dirty #4 [ 46.884489] Workqueue: events_unbound flush_to_ldisc [ 46.884494] ffffb98ac012bb08 ffffffffad3e82e5 ffffb98ac012bb58 0000000000000000 [ 46.884497] ffffb98ac012bb48 ffffffffad0a23d1 00000024ad6374dd ffff9b2ab7289330 [ 46.884500] ffff9b2ab81e28e0 ffff9b2ab7289330 0000000000000002 0000000000000000 [ 46.884501] Call Trace: [ 46.884507] [] dump_stack+0x67/0x92 [ 46.884511] [] __warn+0xd1/0xf0 [ 46.884513] [] warn_slowpath_fmt+0x5f/0x80 [ 46.884516] [] __list_add+0xb3/0xc0 [ 46.884521] [] *usb_anchor_urb*+0x4c/0xa0 [ 46.884524] [] *acm_tty_flush_chars*+0x8f/0xb0 [ 46.884527] [] *acm_tty_put_char*+0x41/0x100 [ 46.884530] [] tty_put_char+0x24/0x40 [ 46.884533] [] do_output_char+0xa5/0x200 [ 46.884535] [] __process_echoes+0x148/0x290 [ 46.884538] [] n_tty_receive_buf_common+0x57c/0xb00 [ 46.884541] [] n_tty_receive_buf2+0x14/0x20 [ 46.884543] [] tty_ldisc_receive_buf+0x22/0x50 [ 46.884545] [] flush_to_ldisc+0xc5/0xe0 [ 46.884549] [] process_one_work+0x148/0x440 [ 46.884551] [] worker_thread+0x69/0x4a0 [ 46.884554] [] ? max_active_store+0x80/0x80 [ 46.884556] [] kthread+0x110/0x130 [ 46.884559] [] ? kthread_park+0x60/0x60 [ 46.884563] [] ret_from_fork+0x27/0x40 [ 46.884566] ---[ end trace 3bd599058b8a9eb3 ]--- Signed-off-by: Dominik Bozek Signed-off-by: Kuppuswamy Sathyanarayanan Acked-by: Oliver Neukum Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 34d23cc99fbd..fe22ac7c760a 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -174,6 +174,7 @@ static int acm_wb_alloc(struct acm *acm) wb = &acm->wb[wbn]; if (!wb->use) { wb->use = 1; + wb->len = 0; return wbn; } wbn = (wbn + 1) % ACM_NW; @@ -731,16 +732,18 @@ static int acm_tty_write(struct tty_struct *tty, static void acm_tty_flush_chars(struct tty_struct *tty) { struct acm *acm = tty->driver_data; - struct acm_wb *cur = acm->putbuffer; + struct acm_wb *cur; int err; unsigned long flags; + spin_lock_irqsave(&acm->write_lock, flags); + + cur = acm->putbuffer; if (!cur) /* nothing to do */ - return; + goto out; acm->putbuffer = NULL; err = usb_autopm_get_interface_async(acm->control); - spin_lock_irqsave(&acm->write_lock, flags); if (err < 0) { cur->use = 0; acm->putbuffer = cur; -- GitLab From cb30834f103a46bca83334ab1efbefe6c75f372e Mon Sep 17 00:00:00 2001 From: Fredrik Noring Date: Fri, 9 Mar 2018 18:34:34 +0100 Subject: [PATCH 497/855] USB: OHCI: Fix NULL dereference in HCDs using HCD_LOCAL_MEM [ Upstream commit d6c931ea32dc08ac2665bb5f009f9c40ad1bbdb3 ] Scatter-gather needs to be disabled when using dma_declare_coherent_memory and HCD_LOCAL_MEM. Andrea Righi made the equivalent fix for EHCI drivers in commit 4307a28eb01284 "USB: EHCI: fix NULL pointer dererence in HCDs that use HCD_LOCAL_MEM". The following NULL pointer WARN_ON_ONCE triggered with OHCI drivers: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 49 at drivers/usb/core/hcd.c:1379 hcd_alloc_coherent+0x4c/0xc8 Modules linked in: CPU: 0 PID: 49 Comm: usb-storage Not tainted 4.15.0+ #1014 Stack : 00000000 00000000 805a78d2 0000003a 81f5c2cc 8053d367 804d77fc 00000031 805a3a08 00000563 81ee9400 805a0000 00000000 10058c00 81f61b10 805c0000 00000000 00000000 805a0000 00d9038e 00000004 803ee818 00000006 312e3420 805c0000 00000000 00000073 81f61958 00000000 00000000 802eb380 804fd538 00000009 00000563 81ee9400 805a0000 00000002 80056148 00000000 805a0000 ... Call Trace: [<578af360>] show_stack+0x74/0x104 [<2f3702c6>] __warn+0x118/0x120 [] warn_slowpath_null+0x44/0x58 [] hcd_alloc_coherent+0x4c/0xc8 [<3578fa36>] usb_hcd_map_urb_for_dma+0x4d8/0x534 [<110bc94c>] usb_hcd_submit_urb+0x82c/0x834 [<02eb5baf>] usb_sg_wait+0x14c/0x1a0 [] usb_stor_bulk_transfer_sglist.part.1+0xac/0x124 [<87a5c34c>] usb_stor_bulk_srb+0x40/0x60 [] usb_stor_Bulk_transport+0x160/0x37c [] usb_stor_invoke_transport+0x3c/0x500 [<004754f4>] usb_stor_control_thread+0x258/0x28c [<22edf42e>] kthread+0x134/0x13c [] ret_from_kernel_thread+0x14/0x1c ---[ end trace bcdb825805eefdcc ]--- Signed-off-by: Fredrik Noring Acked-by: Alan Stern Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index a646ca3b0d00..1afb76e8b1a5 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -446,7 +446,8 @@ static int ohci_init (struct ohci_hcd *ohci) struct usb_hcd *hcd = ohci_to_hcd(ohci); /* Accept arbitrarily long scatter-gather lists */ - hcd->self.sg_tablesize = ~0; + if (!(hcd->driver->flags & HCD_LOCAL_MEM)) + hcd->self.sg_tablesize = ~0; if (distrust_firmware) ohci->flags |= OHCI_QUIRK_HUB_POWER; -- GitLab From a76b68bf31c54afc585730cd0b4bcac800aaff00 Mon Sep 17 00:00:00 2001 From: Torsten Hilbrich Date: Mon, 26 Mar 2018 07:19:57 +0200 Subject: [PATCH 498/855] net/usb/qmi_wwan.c: Add USB id for lt4120 modem [ Upstream commit f3d801baf118c9d452ee7c278df16880c892e669 ] This is needed to support the modem found in HP EliteBook 820 G3. Signed-off-by: Torsten Hilbrich Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 3e893fe890a0..cf5bcd6b8d27 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -942,6 +942,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x413c, 0x81b6, 8)}, /* Dell Wireless 5811e */ {QMI_FIXED_INTF(0x413c, 0x81b6, 10)}, /* Dell Wireless 5811e */ {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */ + {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)}, /* HP lt4120 Snapdragon X5 LTE */ {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */ {QMI_FIXED_INTF(0x1e0e, 0x9001, 5)}, /* SIMCom 7230E */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ -- GitLab From c9dc2614bbebd18277319de0f35e89bf2956f669 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Mon, 26 Mar 2018 16:34:39 +0200 Subject: [PATCH 499/855] net-usb: add qmi_wwan if on lte modem wistron neweb d18q1 [ Upstream commit d4c4bc11353f3bea6754f7d21e3612c9f32d1d64 ] This modem is embedded on dlink dwr-921 router. The oem configuration states: T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1435 ProdID=0918 Rev= 2.32 S: Manufacturer=Android S: Product=Android S: SerialNumber=0123456789ABCDEF C:* #Ifs= 7 Cfg#= 1 Atr=80 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=84(I) Atr=03(Int.) MxPS= 64 Ivl=32ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan E: Ad=86(I) Atr=03(Int.) MxPS= 64 Ivl=32ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan E: Ad=88(I) Atr=03(Int.) MxPS= 64 Ivl=32ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=32ms E: Ad=89(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 6 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=(none) E: Ad=8b(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=07(O) Atr=02(Bulk) MxPS= 512 Ivl=125us Tested on openwrt distribution Signed-off-by: Giuseppe Lippolis Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index cf5bcd6b8d27..8daf5db3d922 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -810,6 +810,9 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x0846, 0x68a2, 8)}, {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)}, /* Huawei E1820 */ + {QMI_FIXED_INTF(0x1435, 0xd181, 3)}, /* Wistron NeWeb D18Q1 */ + {QMI_FIXED_INTF(0x1435, 0xd181, 4)}, /* Wistron NeWeb D18Q1 */ + {QMI_FIXED_INTF(0x1435, 0xd181, 5)}, /* Wistron NeWeb D18Q1 */ {QMI_FIXED_INTF(0x16d8, 0x6003, 0)}, /* CMOTech 6003 */ {QMI_FIXED_INTF(0x16d8, 0x6007, 0)}, /* CMOTech CHE-628S */ {QMI_FIXED_INTF(0x16d8, 0x6008, 0)}, /* CMOTech CMU-301 */ -- GitLab From e6e57a8592a931ded050662a9ec37986e1fc83de Mon Sep 17 00:00:00 2001 From: Vicente Bergas Date: Tue, 20 Mar 2018 19:41:10 +0100 Subject: [PATCH 500/855] Bluetooth: btusb: Add USB ID 7392:a611 for Edimax EW-7611ULB [ Upstream commit a41e0796396eeceff673af4a38feaee149c6ff86 ] This WiFi/Bluetooth USB dongle uses a Realtek chipset, so, use btrtl for it. Product information: https://wikidevi.com/wiki/Edimax_EW-7611ULB >From /sys/kernel/debug/usb/devices T: Bus=02 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=7392 ProdID=a611 Rev= 2.00 S: Manufacturer=Realtek S: Product=Edimax Wi-Fi N150 Bluetooth4.0 USB Adapter S: SerialNumber=00e04c000001 C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=500mA A: FirstIf#= 0 IfCount= 2 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 6 Cls=ff(vend.) Sub=ff Prot=ff Driver=rtl8723bu E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=03(Int.) MxPS= 64 Ivl=500us E: Ad=08(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=09(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms Tested-by: Vicente Bergas Signed-off-by: Vicente Bergas Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 3257647d4f74..586c1885732c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -345,6 +345,9 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3494), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8723BU Bluetooth devices */ + { USB_DEVICE(0x7392, 0xa611), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8821AE Bluetooth devices */ { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK }, -- GitLab From 70d79bf9fbb997cb3de6f7af08a1f430d576636c Mon Sep 17 00:00:00 2001 From: Nobutaka Okabe Date: Fri, 23 Mar 2018 19:18:22 +0900 Subject: [PATCH 501/855] ALSA: usb-audio: Add native DSD support for Luxman DA-06 [ Upstream commit 71426535f49fe6034d0e0db77608b91a0c1a022d ] Add native DSD support quirk for Luxman DA-06 DAC, by adding the PID/VID 1852:5065. Rename "is_marantz_denon_dac()" function to "is_itf_usb_dsd_2alts_dac()" to cover broader device family sharing the same USB audio implementation(*). For the same reason, rename "is_teac_dsd_dac()" function to "is_itf_usb_dsd_3alts_dac()". (*) These devices have the same USB controller "ITF-USB DSD", supplied by INTERFACE Co., Ltd. "ITF-USB DSD" USB controller has two patterns, Pattern 1. (2 altsets version) - Altset 0: for control - Altset 1: for stream (S32) - Altset 2: for stream (S32, DSD_U32) Pattern 2. (3 altsets version) - Altset 0: for control - Altset 1: for stream (S16) - Altset 2: for stream (S32) - Altset 3: for stream (S32, DSD_U32) "is_itf_usb_dsd_2alts_dac()" returns true, if the DAC has "Pattern 1" USB controller, and "is_itf_usb_dsd_3alts_dac()" returns true, if "Pattern2". Signed-off-by: Nobutaka Okabe Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/usb/quirks.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 45655b9108e8..da9fc08b20bb 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1153,24 +1153,27 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) return false; } -/* Marantz/Denon USB DACs need a vendor cmd to switch +/* ITF-USB DSD based DACs need a vendor cmd to switch * between PCM and native DSD mode + * (2 altsets version) */ -static bool is_marantz_denon_dac(unsigned int id) +static bool is_itf_usb_dsd_2alts_dac(unsigned int id) { switch (id) { case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */ case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */ case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */ + case USB_ID(0x1852, 0x5065): /* Luxman DA-06 */ return true; } return false; } -/* TEAC UD-501/UD-503/NT-503 USB DACs need a vendor cmd to switch - * between PCM/DOP and native DSD mode +/* ITF-USB DSD based DACs need a vendor cmd to switch + * between PCM and native DSD mode + * (3 altsets version) */ -static bool is_teac_dsd_dac(unsigned int id) +static bool is_itf_usb_dsd_3alts_dac(unsigned int id) { switch (id) { case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-503/NT-503 */ @@ -1187,7 +1190,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, struct usb_device *dev = subs->dev; int err; - if (is_marantz_denon_dac(subs->stream->chip->usb_id)) { + if (is_itf_usb_dsd_2alts_dac(subs->stream->chip->usb_id)) { /* First switch to alt set 0, otherwise the mode switch cmd * will not be accepted by the DAC */ @@ -1208,7 +1211,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, break; } mdelay(20); - } else if (is_teac_dsd_dac(subs->stream->chip->usb_id)) { + } else if (is_itf_usb_dsd_3alts_dac(subs->stream->chip->usb_id)) { /* Vendor mode switch cmd is required. */ switch (fmt->altsetting) { case 3: /* DSD mode (DSD_U32) requested */ @@ -1304,10 +1307,10 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) mdelay(20); - /* Marantz/Denon devices with USB DAC functionality need a delay + /* ITF-USB DSD based DACs functionality need a delay * after each class compliant request */ - if (is_marantz_denon_dac(chip->usb_id) + if (is_itf_usb_dsd_2alts_dac(chip->usb_id) && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) mdelay(20); @@ -1371,14 +1374,14 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, break; } - /* Denon/Marantz devices with USB DAC functionality */ - if (is_marantz_denon_dac(chip->usb_id)) { + /* ITF-USB DSD based DACs (2 altsets version) */ + if (is_itf_usb_dsd_2alts_dac(chip->usb_id)) { if (fp->altsetting == 2) return SNDRV_PCM_FMTBIT_DSD_U32_BE; } - /* TEAC devices with USB DAC functionality */ - if (is_teac_dsd_dac(chip->usb_id)) { + /* ITF-USB DSD based DACs (3 altsets version) */ + if (is_itf_usb_dsd_3alts_dac(chip->usb_id)) { if (fp->altsetting == 3) return SNDRV_PCM_FMTBIT_DSD_U32_BE; } -- GitLab From 0acea84f20dbc938200a796fa15d682511bb07e1 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Fri, 16 Mar 2018 15:33:48 -0700 Subject: [PATCH 502/855] usb: dwc3: Add SoftReset PHY synchonization delay [ Upstream commit fab3833338779e1e668bd58d1f76d601657304b8 ] >From DWC_usb31 programming guide section 1.3.2, once DWC3_DCTL_CSFTRST bit is cleared, we must wait at least 50ms before accessing the PHY domain (synchronization delay). Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index b8d272ed2355..53b26e978d90 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -161,7 +161,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) do { reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (!(reg & DWC3_DCTL_CSFTRST)) - return 0; + goto done; udelay(1); } while (--retries); @@ -170,6 +170,17 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) phy_exit(dwc->usb2_generic_phy); return -ETIMEDOUT; + +done: + /* + * For DWC_usb31 controller, once DWC3_DCTL_CSFTRST bit is cleared, + * we must wait at least 50ms before accessing the PHY domain + * (synchronization delay). DWC_usb31 programming guide section 1.3.2. + */ + if (dwc3_is_usb31(dwc)) + msleep(50); + + return 0; } /** -- GitLab From 4f46a9164454acb84db8e814866f6a506c18037b Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Fri, 16 Mar 2018 15:33:54 -0700 Subject: [PATCH 503/855] usb: dwc3: Update DWC_usb31 GTXFIFOSIZ reg fields [ Upstream commit 0cab8d26d6e5e053b2bed3356992aaa71dc93628 ] Update two GTXFIFOSIZ bit fields for the DWC_usb31 controller. TXFDEP is a 15-bit value instead of 16-bit value, and bit 15 is TXFRAMNUM. The GTXFIFOSIZ register for DWC_usb31 is as follows: +-------+-----------+----------------------------------+ | BITS | Name | Description | +=======+===========+==================================+ | 31:16 | TXFSTADDR | Transmit FIFOn RAM Start Address | | 15 | TXFRAMNUM | Asynchronous/Periodic TXFIFO | | 14:0 | TXFDEP | TXFIFO Depth | +-------+-----------+----------------------------------+ Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 94d6a3e2ad97..affb3d757310 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -238,6 +238,8 @@ #define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1) /* Global TX Fifo Size Register */ +#define DWC31_GTXFIFOSIZ_TXFRAMNUM BIT(15) /* DWC_usb31 only */ +#define DWC31_GTXFIFOSIZ_TXFDEF(n) ((n) & 0x7fff) /* DWC_usb31 only */ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) #define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000) -- GitLab From 48701a8f4adbaa04a046edb68871b76f809fd57b Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 16 Mar 2018 16:33:01 +0200 Subject: [PATCH 504/855] xhci: zero usb device slot_id member when disabling and freeing a xhci slot [ Upstream commit a400efe455f7b61ac9a801ac8d0d01f8c8d82dd5 ] set udev->slot_id to zero when disabling and freeing the xhci slot. Prevents usb core from calling xhci with a stale slot id. xHC controller may be reset during resume to recover from some error. All slots are unusable as they are disabled and freed. xhci driver starts slot enumeration again from 1 in the order they are enabled. In the worst case a stale udev->slot_id for one device matches a newly enabled slot_id for a different device, causing us to perform a action on the wrong device. Signed-off-by: Mathias Nyman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 3b7d69ca83be..48bdab4fdc8f 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -975,6 +975,8 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) if (dev->out_ctx) xhci_free_container_ctx(xhci, dev->out_ctx); + if (dev->udev && dev->udev->slot_id) + dev->udev->slot_id = 0; kfree(xhci->devs[slot_id]); xhci->devs[slot_id] = NULL; } -- GitLab From fba46ae2cd7a5117299c435d71adcaf30acd8b01 Mon Sep 17 00:00:00 2001 From: Grigor Tovmasyan Date: Tue, 6 Feb 2018 19:07:38 +0400 Subject: [PATCH 505/855] usb: dwc2: Fix interval type issue [ Upstream commit 12814a3f8f9b247531d7863170cc82b3fe4218fd ] The maximum value that unsigned char can hold is 255, meanwhile the maximum value of interval is 2^(bIntervalMax-1)=2^15. Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 2a21a0414b1d..0f45a2f165e5 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -209,7 +209,7 @@ struct dwc2_hsotg_ep { unsigned char dir_in; unsigned char index; unsigned char mc; - unsigned char interval; + u16 interval; unsigned int halted:1; unsigned int periodic:1; -- GitLab From 26f4a6d638d52351f3e2583b61ef3f79e26d0a7d Mon Sep 17 00:00:00 2001 From: Minas Harutyunyan Date: Fri, 19 Jan 2018 14:44:20 +0400 Subject: [PATCH 506/855] usb: dwc2: host: Fix transaction errors in host mode [ Upstream commit 92a8dd26464e1f21f1d869ec53717bd2c1200d63 ] Added missing GUSBCFG programming in host mode, which fixes transaction errors issue on HiKey and Altera Cyclone V boards. These field even if was programmed in device mode (in function dwc2_hsotg_core_init_disconnected()) will be resetting to POR values after core soft reset applied. So, each time when switching to host mode required to set this field to correct value. Acked-by: John Youn Signed-off-by: Minas Harutyunyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hcd.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 919a32153060..0a0cf154814b 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -2268,10 +2268,22 @@ static int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup) */ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg) { - u32 hcfg, hfir, otgctl; + u32 hcfg, hfir, otgctl, usbcfg; dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg); + /* Set HS/FS Timeout Calibration to 7 (max available value). + * The number of PHY clocks that the application programs in + * this field is added to the high/full speed interpacket timeout + * duration in the core to account for any additional delays + * introduced by the PHY. This can be required, because the delay + * introduced by the PHY in generating the linestate condition + * can vary from one PHY to another. + */ + usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); + usbcfg |= GUSBCFG_TOUTCAL(7); + dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); + /* Restart the Phy Clock */ dwc2_writel(0, hsotg->regs + PCGCTL); -- GitLab From 10be2659c629f815edbb12a9ec9e4f73f31b73fe Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 12 Jan 2018 11:26:16 +0100 Subject: [PATCH 507/855] usb: gadget: ffs: Let setup() return USB_GADGET_DELAYED_STATUS [ Upstream commit 946ef68ad4e45aa048a5fb41ce8823ed29da866a ] Some UDC drivers (like the DWC3) expect that the response to a setup() request is queued from within the setup function itself so that it is available as soon as setup() has completed. Upon receiving a setup request the function fs driver creates an event that is made available to userspace. And only once userspace has acknowledged that event the response to the setup request is queued. So it violates the requirement of those UDC drivers and random failures can be observed. This is basically a race condition and if userspace is able to read the event and queue the response fast enough all is good. But if it is not, for example because other processes are currently scheduled to run, the USB host that sent the setup request will observe an error. To avoid this the gadget framework provides the USB_GADGET_DELAYED_STATUS return code. If a setup() callback returns this value the UDC driver is aware that response is not yet available and can uses the appropriate methods to handle this case. Since in the case of function fs the response will never be available when the setup() function returns make sure that this status code is used. This fixed random occasional failures that were previously observed on a DWC3 based system under high system load. Signed-off-by: Lars-Peter Clausen Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 071346973dd6..77f0c68c3d9b 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -3239,7 +3239,7 @@ static int ffs_func_setup(struct usb_function *f, __ffs_event_add(ffs, FUNCTIONFS_SETUP); spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); - return 0; + return USB_GADGET_DELAYED_STATUS; } static bool ffs_func_req_match(struct usb_function *f, -- GitLab From 5209c778346ac9e34a4100b55a7dd23503821fe1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 12 Jan 2018 11:05:02 +0100 Subject: [PATCH 508/855] usb: gadget: ffs: Execute copy_to_user() with USER_DS set [ Upstream commit 4058ebf33cb0be88ca516f968eda24ab7b6b93e4 ] When using a AIO read() operation on the function FS gadget driver a URB is submitted asynchronously and on URB completion the received data is copied to the userspace buffer associated with the read operation. This is done from a kernel worker thread invoking copy_to_user() (through copy_to_iter()). And while the user space process memory is made available to the kernel thread using use_mm(), some architecture require in addition to this that the operation runs with USER_DS set. Otherwise the userspace memory access will fail. For example on ARM64 with Privileged Access Never (PAN) and User Access Override (UAO) enabled the following crash occurs. Internal error: Accessing user space memory with fs=KERNEL_DS: 9600004f [#1] SMP Modules linked in: CPU: 2 PID: 1636 Comm: kworker/2:1 Not tainted 4.9.0-04081-g8ab2dfb-dirty #487 Hardware name: ZynqMP ZCU102 Rev1.0 (DT) Workqueue: events ffs_user_copy_worker task: ffffffc87afc8080 task.stack: ffffffc87a00c000 PC is at __arch_copy_to_user+0x190/0x220 LR is at copy_to_iter+0x78/0x3c8 [...] [] __arch_copy_to_user+0x190/0x220 [] ffs_user_copy_worker+0x70/0x130 [] process_one_work+0x1dc/0x460 [] worker_thread+0x50/0x4b0 [] kthread+0xd8/0xf0 [] ret_from_fork+0x10/0x50 Address this by placing a set_fs(USER_DS) before of the copy operation and revert it again once the copy operation has finished. This patch is analogous to commit d7ffde35e31a ("vhost: use USER_DS in vhost_worker thread") which addresses the same underlying issue. Signed-off-by: Lars-Peter Clausen Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_fs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 77f0c68c3d9b..af72224f8ba2 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -759,9 +759,13 @@ static void ffs_user_copy_worker(struct work_struct *work) bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD; if (io_data->read && ret > 0) { + mm_segment_t oldfs = get_fs(); + + set_fs(USER_DS); use_mm(io_data->mm); ret = ffs_copy_to_iter(io_data->buf, ret, &io_data->data); unuse_mm(io_data->mm); + set_fs(oldfs); } io_data->kiocb->ki_complete(io_data->kiocb, ret, ret); -- GitLab From 2e94f8cde34742ccfe9642ac42d31bbe76d1e77d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 6 Feb 2018 09:50:40 +0100 Subject: [PATCH 509/855] usb: gadget: udc: change comparison to bitshift when dealing with a mask [ Upstream commit ac87e560f7c0f91b62012e9a159c0681a373b922 ] Due to a typo, the mask was destroyed by a comparison instead of a bit shift. Reported-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/goku_udc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/goku_udc.h b/drivers/usb/gadget/udc/goku_udc.h index 86d2adafe149..64eb0f2b5ea0 100644 --- a/drivers/usb/gadget/udc/goku_udc.h +++ b/drivers/usb/gadget/udc/goku_udc.h @@ -28,7 +28,7 @@ struct goku_udc_regs { # define INT_EP1DATASET 0x00040 # define INT_EP2DATASET 0x00080 # define INT_EP3DATASET 0x00100 -#define INT_EPnNAK(n) (0x00100 < (n)) /* 0 < n < 4 */ +#define INT_EPnNAK(n) (0x00100 << (n)) /* 0 < n < 4 */ # define INT_EP1NAK 0x00200 # define INT_EP2NAK 0x00400 # define INT_EP3NAK 0x00800 -- GitLab From bf54f31e1fbe656cd8fea7a54404296e6077f9e9 Mon Sep 17 00:00:00 2001 From: Chris Dickens Date: Sun, 31 Dec 2017 18:59:42 -0800 Subject: [PATCH 510/855] usb: gadget: composite: fix incorrect handling of OS desc requests [ Upstream commit 5d6ae4f0da8a64a185074dabb1b2f8c148efa741 ] When handling an OS descriptor request, one of the first operations is to zero out the request buffer using the wLength from the setup packet. There is no bounds checking, so a wLength > 4096 would clobber memory adjacent to the request buffer. Fix this by taking the min of wLength and the request buffer length prior to the memset. While at it, define the buffer length in a header file so that magic numbers don't appear throughout the code. When returning data to the host, the data length should be the min of the wLength and the valid data we have to return. Currently we are returning wLength, thus requests for a wLength greater than the amount of data in the OS descriptor buffer would return invalid (albeit zero'd) data following the valid descriptor data. Fix this by counting the number of bytes when constructing the data and using this when determining the length of the request. Signed-off-by: Chris Dickens Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/composite.c | 40 ++++++++++++++++------------------ include/linux/usb/composite.h | 3 +++ 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 406758ed0b23..ca97f5b36e1b 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1421,7 +1421,7 @@ static int count_ext_compat(struct usb_configuration *c) return res; } -static void fill_ext_compat(struct usb_configuration *c, u8 *buf) +static int fill_ext_compat(struct usb_configuration *c, u8 *buf) { int i, count; @@ -1448,10 +1448,12 @@ static void fill_ext_compat(struct usb_configuration *c, u8 *buf) buf += 23; } count += 24; - if (count >= 4096) - return; + if (count + 24 >= USB_COMP_EP0_OS_DESC_BUFSIZ) + return count; } } + + return count; } static int count_ext_prop(struct usb_configuration *c, int interface) @@ -1496,25 +1498,20 @@ static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf) struct usb_os_desc *d; struct usb_os_desc_ext_prop *ext_prop; int j, count, n, ret; - u8 *start = buf; f = c->interface[interface]; + count = 10; /* header length */ for (j = 0; j < f->os_desc_n; ++j) { if (interface != f->os_desc_table[j].if_id) continue; d = f->os_desc_table[j].os_desc; if (d) list_for_each_entry(ext_prop, &d->ext_prop, entry) { - /* 4kB minus header length */ - n = buf - start; - if (n >= 4086) - return 0; - - count = ext_prop->data_len + + n = ext_prop->data_len + ext_prop->name_len + 14; - if (count > 4086 - n) - return -EINVAL; - usb_ext_prop_put_size(buf, count); + if (count + n >= USB_COMP_EP0_OS_DESC_BUFSIZ) + return count; + usb_ext_prop_put_size(buf, n); usb_ext_prop_put_type(buf, ext_prop->type); ret = usb_ext_prop_put_name(buf, ext_prop->name, ext_prop->name_len); @@ -1540,11 +1537,12 @@ static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf) default: return -EINVAL; } - buf += count; + buf += n; + count += n; } } - return 0; + return count; } /* @@ -1822,6 +1820,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) req->complete = composite_setup_complete; buf = req->buf; os_desc_cfg = cdev->os_desc_config; + w_length = min_t(u16, w_length, USB_COMP_EP0_OS_DESC_BUFSIZ); memset(buf, 0, w_length); buf[5] = 0x01; switch (ctrl->bRequestType & USB_RECIP_MASK) { @@ -1845,8 +1844,8 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) count += 16; /* header */ put_unaligned_le32(count, buf); buf += 16; - fill_ext_compat(os_desc_cfg, buf); - value = w_length; + value = fill_ext_compat(os_desc_cfg, buf); + value = min_t(u16, w_length, value); } break; case USB_RECIP_INTERFACE: @@ -1875,8 +1874,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) interface, buf); if (value < 0) return value; - - value = w_length; + value = min_t(u16, w_length, value); } break; } @@ -2151,8 +2149,8 @@ int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, goto end; } - /* OS feature descriptor length <= 4kB */ - cdev->os_desc_req->buf = kmalloc(4096, GFP_KERNEL); + cdev->os_desc_req->buf = kmalloc(USB_COMP_EP0_OS_DESC_BUFSIZ, + GFP_KERNEL); if (!cdev->os_desc_req->buf) { ret = -ENOMEM; usb_ep_free_request(ep0, cdev->os_desc_req); diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 4616a49a1c2e..667d20454a21 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -53,6 +53,9 @@ /* big enough to hold our biggest descriptor */ #define USB_COMP_EP0_BUFSIZ 1024 +/* OS feature descriptor length <= 4kB */ +#define USB_COMP_EP0_OS_DESC_BUFSIZ 4096 + #define USB_MS_TO_HS_INTERVAL(x) (ilog2((x * 1000 / 125)) + 1) struct usb_configuration; -- GitLab From 5104f3671139006e323afcdffaec50a2205c856b Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 4 Jan 2018 19:04:13 -0500 Subject: [PATCH 511/855] media: em28xx: USB bulk packet size fix [ Upstream commit c7c7e8d7803406daa21e96d00c357de8b77b6764 ] Hauppauge em28xx bulk devices exhibit continuity errors and corrupted packets, when run in VMWare virtual machines. Unknown if other manufacturers bulk models exhibit the same issue. KVM/Qemu is unaffected. According to documentation the maximum packet multiplier for em28xx in bulk transfer mode is 256 * 188 bytes. This changes the size of bulk transfers to maximum supported value and have a bonus beneficial alignment. Before: After: This sets up USB to expect just as many bytes as the em28xx is set to emit. Successful usage under load afterwards natively and in both VMWare and KVM/Qemu virtual machines. Signed-off-by: Brad Love Reviewed-by: Michael Ira Krufky Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/em28xx/em28xx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index d148463b22c1..6bf48a75688e 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -189,7 +189,7 @@ USB 2.0 spec says bulk packet size is always 512 bytes */ #define EM28XX_BULK_PACKET_MULTIPLIER 384 -#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 384 +#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 94 #define EM28XX_INTERLACED_DEFAULT 1 -- GitLab From d6f521863130a0328cd46f08264dbab6c65787e6 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 11 Feb 2018 12:24:32 -0600 Subject: [PATCH 512/855] Bluetooth: btusb: Add device ID for RTL8822BE [ Upstream commit fed03fe7e55b7dc16077f672bd9d7bbe92b3a691 ] The Asus Z370-I contains a Realtek RTL8822BE device with an associated BT chip using a USB ID of 0b05:185c. This device is added to the driver. Signed-off-by: Hon Weng Chong Signed-off-by: Larry Finger Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 586c1885732c..bff67c5a5fe7 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -355,6 +355,9 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3461), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3462), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8822BE Bluetooth devices */ + { USB_DEVICE(0x0b05, 0x185c), .driver_info = BTUSB_REALTEK }, + /* Silicon Wave based devices */ { USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE }, -- GitLab From 602263054df7733f2ceeda7d1c61dd8d72145613 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 2 Mar 2018 10:31:25 +1100 Subject: [PATCH 513/855] staging: lustre: fix bug in osc_enter_cache_try [ Upstream commit 2fab9faf9b27298c4536c1c1b14072ab18b8f80b ] The lustre-release patch commit bdc5bb52c554 ("LU-4933 osc: Automatically increase the max_dirty_mb") changed - if (cli->cl_dirty + PAGE_CACHE_SIZE <= cli->cl_dirty_max && + if (cli->cl_dirty_pages < cli->cl_dirty_max_pages && When this patch landed in Linux a couple of years later, it landed as - if (cli->cl_dirty + PAGE_SIZE <= cli->cl_dirty_max && + if (cli->cl_dirty_pages <= cli->cl_dirty_max_pages && which is clearly different ('<=' vs '<'), and allows cl_dirty_pages to increase beyond cl_dirty_max_pages - which causes a latter assertion to fails. Fixes: 3147b268400a ("staging: lustre: osc: Automatically increase the max_dirty_mb") Signed-off-by: NeilBrown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/obd.h | 2 +- drivers/staging/lustre/lustre/osc/osc_cache.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index f6fc4dd05bd6..722c33f7eecc 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -253,7 +253,7 @@ struct client_obd { struct sptlrpc_flavor cl_flvr_mgc; /* fixed flavor of mgc->mgs */ /* the grant values are protected by loi_list_lock below */ - unsigned long cl_dirty_pages; /* all _dirty_ in pahges */ + unsigned long cl_dirty_pages; /* all _dirty_ in pages */ unsigned long cl_dirty_max_pages; /* allowed w/o rpc */ unsigned long cl_dirty_transit; /* dirty synchronous */ unsigned long cl_avail_grant; /* bytes of credit for ost */ diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index 4bbe219add98..1a8c9f535200 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -1542,7 +1542,7 @@ static int osc_enter_cache_try(struct client_obd *cli, if (rc < 0) return 0; - if (cli->cl_dirty_pages <= cli->cl_dirty_max_pages && + if (cli->cl_dirty_pages < cli->cl_dirty_max_pages && atomic_long_read(&obd_dirty_pages) + 1 <= obd_max_dirty_pages) { osc_consume_write_grant(cli, &oap->oap_brw_page); if (transient) { -- GitLab From 1c0344c493086357926ef9fe71312d414c238bee Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 28 Feb 2018 11:28:49 +0000 Subject: [PATCH 514/855] staging: rtl8192u: return -ENOMEM on failed allocation of priv->oldaddr [ Upstream commit e1a7418529e33bc4efc346324557251a16a3e79b ] Currently the allocation of priv->oldaddr is not null checked which will lead to subsequent errors when accessing priv->oldaddr. Fix this with a null pointer check and a return of -ENOMEM on allocation failure. Detected with Coccinelle: drivers/staging/rtl8192u/r8192U_core.c:1708:2-15: alloc with no test, possible model on line 1723 Fixes: 8fc8598e61f6 ("Staging: Added Realtek rtl8192u driver to staging") Signed-off-by: Colin Ian King Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192u/r8192U_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 457eeb5f5239..5fe95937d811 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -1705,6 +1705,8 @@ static short rtl8192_usb_initendpoints(struct net_device *dev) priv->rx_urb[16] = usb_alloc_urb(0, GFP_KERNEL); priv->oldaddr = kmalloc(16, GFP_KERNEL); + if (!priv->oldaddr) + return -ENOMEM; oldaddr = priv->oldaddr; align = ((long)oldaddr) & 3; if (align) { -- GitLab From 86a3f2d3b758e0ba5c02d56500fc273657ff941d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 23 Feb 2018 09:09:33 +1100 Subject: [PATCH 515/855] staging: lustre: lmv: correctly iput lmo_root [ Upstream commit 17556cdbe6ed70a6a20e597b228628f7f34387f8 ] Commit 8f18c8a48b73 ("staging: lustre: lmv: separate master object with master stripe") changed how lmo_root inodes were managed, particularly when LMV_HASH_FLAG_MIGRATION is not set. Previously lsm_md_oinfo[0].lmo_root was always a borrowed inode reference and didn't need to by iput(). Since the change, that special case only applies when LMV_HASH_FLAG_MIGRATION is set In the upstream (lustre-release) version of this patch [Commit 60e07b972114 ("LU-4690 lod: separate master object with master stripe")] the for loop in the lmv_unpack_md() was changed to count from 0 and to ignore entry 0 if LMV_HASH_FLAG_MIGRATION is set. In the patch that got applied to Linux, that change was missing, so lsm_md_oinfo[0].lmo_root is never iput(). This results in a "VFS: Busy inodes" warning at unmount. Fixes: 8f18c8a48b73 ("staging: lustre: lmv: separate master object with master stripe") Signed-off-by: NeilBrown Reviewed-by: James Simmons Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/lmv/lmv_obd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index cd19ce811e62..9e63171c1ec3 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -2928,7 +2928,7 @@ int lmv_unpack_md(struct obd_export *exp, struct lmv_stripe_md **lsmp, if (lsm && !lmm) { int i; - for (i = 1; i < lsm->lsm_md_stripe_count; i++) { + for (i = 0; i < lsm->lsm_md_stripe_count; i++) { /* * For migrating inode, the master stripe and master * object will be the same, so do not need iput, see -- GitLab From e422d89fb59d05fd28a2e9bd9cfb496e3f50be81 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Sun, 11 Feb 2018 23:15:37 +0000 Subject: [PATCH 516/855] crypto: sunxi-ss - Add MODULE_ALIAS to sun4i-ss [ Upstream commit 7c73cf4cc2ac16465f5102437dc0a12d66671bd6 ] The MODULE_ALIAS is required to enable the sun4i-ss driver to load automatically when built at a module. Tested on a Cubietruck. Fixes: 6298e948215f ("crypto: sunxi-ss - Add Allwinner Security System crypto accelerator") Signed-off-by: Peter Robinson Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/sunxi-ss/sun4i-ss-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-core.c b/drivers/crypto/sunxi-ss/sun4i-ss-core.c index 3ac6c6c4ad18..16bb66091cf0 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-core.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-core.c @@ -422,6 +422,7 @@ static struct platform_driver sun4i_ss_driver = { module_platform_driver(sun4i_ss_driver); +MODULE_ALIAS("platform:sun4i-ss"); MODULE_DESCRIPTION("Allwinner Security System cryptographic accelerator"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Corentin LABBE "); -- GitLab From 2c0fd4ba0587fa3e78c9b42cf50db0556b7e1c0b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 Jan 2018 14:16:38 +0100 Subject: [PATCH 517/855] scsi: fas216: fix sense buffer initialization [ Upstream commit 96d5eaa9bb74d299508d811d865c2c41b38b0301 ] While testing with the ARM specific memset() macro removed, I ran into a compiler warning that shows an old bug: drivers/scsi/arm/fas216.c: In function 'fas216_rq_sns_done': drivers/scsi/arm/fas216.c:2014:40: error: argument to 'sizeof' in 'memset' call is the same expression as the destination; did you mean to provide an explicit length? [-Werror=sizeof-pointer-memaccess] It turns out that the definition of the scsi_cmd structure changed back in linux-2.6.25, so now we clear only four bytes (sizeof(pointer)) instead of 96 (SCSI_SENSE_BUFFERSIZE). I did not check whether we actually need to initialize the buffer here, but it's clear that if we do it, we should use the correct size. Fixes: de25deb18016 ("[SCSI] use dynamically allocated sense buffer") Signed-off-by: Arnd Bergmann Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/arm/fas216.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index 24388795ee9a..936e8c735656 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2011,7 +2011,7 @@ static void fas216_rq_sns_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, * have valid data in the sense buffer that could * confuse the higher levels. */ - memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); + memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); //printk("scsi%d.%c: sense buffer: ", info->host->host_no, '0' + SCpnt->device->id); //{ int i; for (i = 0; i < 32; i++) printk("%02x ", SCpnt->sense_buffer[i]); printk("\n"); } /* -- GitLab From 9760af4d2eca3e836b43de41f4108b582ff7c02b Mon Sep 17 00:00:00 2001 From: Sujit Reddy Thumma Date: Wed, 24 Jan 2018 09:52:35 +0530 Subject: [PATCH 518/855] scsi: ufs: Enable quirk to ignore sending WRITE_SAME command [ Upstream commit 84af7e8b895088d89f246d6b0f82717fafdebf61 ] WRITE_SAME command is not supported by UFS. Enable a quirk for the upper level drivers to not send WRITE SAME command. [mkp: botched patch, applied by hand] Signed-off-by: Sujit Reddy Thumma Signed-off-by: Subhash Jadavani Signed-off-by: Asutosh Das Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/ufs/ufshcd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 2e9341233f66..98a7111dd53f 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3338,6 +3338,8 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev) /* REPORT SUPPORTED OPERATION CODES is not supported */ sdev->no_report_opcodes = 1; + /* WRITE_SAME command is not supported */ + sdev->no_write_same = 1; ufshcd_set_queue_depth(sdev); -- GitLab From ac6572952cbbac58381636a7e28cb57fffe90adb Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Wed, 24 Jan 2018 08:07:06 -0800 Subject: [PATCH 519/855] scsi: bnx2fc: Fix check in SCSI completion handler for timed out request [ Upstream commit ecf7ff49945f5741fa1da112f994939f942031d3 ] When a request times out we set the io_req flag BNX2FC_FLAG_IO_COMPL so that if a subsequent completion comes in on that task ID we will ignore it. The issue is that in the check for this flag there is a missing return so we will continue to process a request which may have already been returned to the ownership of the SCSI layer. This can cause unpredictable results. Solution is to add in the missing return. [mkp: typo plus title shortening] Signed-off-by: Chad Dupuis Reviewed-by: Laurence Oberman Tested-by: Laurence Oberman Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/bnx2fc/bnx2fc_io.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index f501095f91ac..bd39590d81c4 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1869,6 +1869,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, /* we will not receive ABTS response for this IO */ BNX2FC_IO_DBG(io_req, "Timer context finished processing " "this scsi cmd\n"); + return; } /* Cancel the timeout_work, as we received IO completion */ -- GitLab From 13a3e883ce6f2c740b4e75c1f907792fab493470 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 25 Jan 2018 17:13:40 +0300 Subject: [PATCH 520/855] scsi: sym53c8xx_2: iterator underflow in sym_getsync() [ Upstream commit e6f791d95313c85f3dd4a26141e28e50ae9aa0ae ] We wanted to exit the loop with "div" set to zero, but instead, if we don't hit the break then "div" is -1 when we finish the loop. It leads to an array underflow a few lines later. Signed-off-by: Dan Carpenter Reviewed-by: Johannes Thumshirn Acked-by: Matthew Wilcox Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sym53c8xx_2/sym_hipd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index 6b349e301869..c6425e3df5a0 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -536,7 +536,7 @@ sym_getsync(struct sym_hcb *np, u_char dt, u_char sfac, u_char *divp, u_char *fa * Look for the greatest clock divisor that allows an * input speed faster than the period. */ - while (div-- > 0) + while (--div > 0) if (kpc >= (div_10M[div] << 2)) break; /* -- GitLab From 95bcf5b14e31a232bdeb606219c5eaa5b96e285c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 25 Jan 2018 17:27:27 +0300 Subject: [PATCH 521/855] scsi: mptfusion: Add bounds check in mptctl_hp_targetinfo() [ Upstream commit a7043e9529f3c367cc4d82997e00be034cbe57ca ] My static checker complains about an out of bounds read: drivers/message/fusion/mptctl.c:2786 mptctl_hp_targetinfo() error: buffer overflow 'hd->sel_timeout' 255 <= u32max. It's true that we probably should have a bounds check here. Signed-off-by: Dan Carpenter Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/message/fusion/mptctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 02b5f69e1a42..14cf6dfc3b14 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -2698,6 +2698,8 @@ mptctl_hp_targetinfo(unsigned long arg) __FILE__, __LINE__, iocnum); return -ENODEV; } + if (karg.hdr.id >= MPT_MAX_FC_DEVICES) + return -EINVAL; dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n", ioc->name)); -- GitLab From 4646c1af466c3999afa6fe36965206a7ca4449de Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 25 Jan 2018 08:24:29 -0800 Subject: [PATCH 522/855] scsi: qla2xxx: Avoid triggering undefined behavior in qla2x00_mbx_completion() [ Upstream commit c02189e12ce3bf3808cb880569d3b10249f50bd9 ] A left shift must shift less than the bit width of the left argument. Avoid triggering undefined behavior if ha->mbx_count == 32. This patch avoids that UBSAN reports the following complaint: UBSAN: Undefined behaviour in drivers/scsi/qla2xxx/qla_isr.c:275:14 shift exponent 32 is too large for 32-bit type 'int' Call Trace: dump_stack+0x4e/0x6c ubsan_epilogue+0xd/0x3b __ubsan_handle_shift_out_of_bounds+0x112/0x14c qla2x00_mbx_completion+0x1c5/0x25d [qla2xxx] qla2300_intr_handler+0x1ea/0x3bb [qla2xxx] qla2x00_mailbox_command+0x77b/0x139a [qla2xxx] qla2x00_mbx_reg_test+0x83/0x114 [qla2xxx] qla2x00_chip_diag+0x354/0x45f [qla2xxx] qla2x00_initialize_adapter+0x2c2/0xa4e [qla2xxx] qla2x00_probe_one+0x1681/0x392e [qla2xxx] pci_device_probe+0x10b/0x1f1 driver_probe_device+0x21f/0x3a4 __driver_attach+0xa9/0xe1 bus_for_each_dev+0x6e/0xb5 driver_attach+0x22/0x3c bus_add_driver+0x1d1/0x2ae driver_register+0x78/0x130 __pci_register_driver+0x75/0xa8 qla2x00_module_init+0x21b/0x267 [qla2xxx] do_one_initcall+0x5a/0x1e2 do_init_module+0x9d/0x285 load_module+0x20db/0x38e3 SYSC_finit_module+0xa8/0xbc SyS_finit_module+0x9/0xb do_syscall_64+0x77/0x271 entry_SYSCALL64_slow_path+0x25/0x25 Reported-by: Meelis Roos Signed-off-by: Bart Van Assche Cc: Himanshu Madhani Reviewed-by: Laurence Oberman Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_isr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index bddaabb288d4..73c99f237b10 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -272,7 +272,8 @@ qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; /* Read all mbox registers? */ - mboxes = (1 << ha->mbx_count) - 1; + WARN_ON_ONCE(ha->mbx_count > 32); + mboxes = (1ULL << ha->mbx_count) - 1; if (!ha->mcp) ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n"); else @@ -2516,7 +2517,8 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; /* Read all mbox registers? */ - mboxes = (1 << ha->mbx_count) - 1; + WARN_ON_ONCE(ha->mbx_count > 32); + mboxes = (1ULL << ha->mbx_count) - 1; if (!ha->mcp) ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n"); else -- GitLab From cd8acc46808b3e7f209c8168094d85d988a2229e Mon Sep 17 00:00:00 2001 From: "Michael Kelley (EOSG)" Date: Wed, 24 Jan 2018 22:49:57 +0000 Subject: [PATCH 523/855] scsi: storvsc: Increase cmd_per_lun for higher speed devices [ Upstream commit cabe92a55e3a12005a4ac4d3954c9a174b0efe2a ] Increase cmd_per_lun to allow more I/Os in progress per device, particularly for NVMe's. The Hyper-V host side can handle the higher count with no issues. Signed-off-by: Michael Kelley Reviewed-by: K. Y. Srinivasan Acked-by: K. Y. Srinivasan Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/storvsc_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 0dd1984e381e..d92b2808d191 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1580,7 +1580,7 @@ static struct scsi_host_template scsi_driver = { .eh_timed_out = storvsc_eh_timed_out, .slave_alloc = storvsc_device_alloc, .slave_configure = storvsc_device_configure, - .cmd_per_lun = 255, + .cmd_per_lun = 2048, .this_id = -1, .use_clustering = ENABLE_CLUSTERING, /* Make sure we dont get a sg segment crosses a page boundary */ -- GitLab From 3e0421562e04c341e996baa89370339d0282469b Mon Sep 17 00:00:00 2001 From: Meelis Roos Date: Fri, 9 Feb 2018 08:57:44 +0200 Subject: [PATCH 524/855] scsi: aacraid: fix shutdown crash when init fails [ Upstream commit 00c20cdc79259c6c5bf978b21af96c2d3edb646d ] When aacraid init fails with "AAC0: adapter self-test failed.", shutdown leads to UBSAN warning and then oops: [154316.118423] ================================================================================ [154316.118508] UBSAN: Undefined behaviour in drivers/scsi/scsi_lib.c:2328:27 [154316.118566] member access within null pointer of type 'struct Scsi_Host' [154316.118631] CPU: 2 PID: 14530 Comm: reboot Tainted: G W 4.15.0-dirty #89 [154316.118701] Hardware name: Hewlett Packard HP NetServer/HP System Board, BIOS 4.06.46 PW 06/25/2003 [154316.118774] Call Trace: [154316.118848] dump_stack+0x48/0x65 [154316.118916] ubsan_epilogue+0xe/0x40 [154316.118976] __ubsan_handle_type_mismatch+0xfb/0x180 [154316.119043] scsi_block_requests+0x20/0x30 [154316.119135] aac_shutdown+0x18/0x40 [aacraid] [154316.119196] pci_device_shutdown+0x33/0x50 [154316.119269] device_shutdown+0x18a/0x390 [...] [154316.123435] BUG: unable to handle kernel NULL pointer dereference at 000000f4 [154316.123515] IP: scsi_block_requests+0xa/0x30 This is because aac_shutdown() does struct Scsi_Host *shost = pci_get_drvdata(dev); scsi_block_requests(shost); and that assumes shost has been assigned with pci_set_drvdata(). However, pci_set_drvdata(pdev, shost) is done in aac_probe_one() far after bailing out with error from calling the init function ((*aac_drivers[index].init)(aac)), and when the init function fails, no error is returned from aac_probe_one() so PCI layer assumes there is driver attached, and tries to shut it down later. Fix it by returning error from aac_probe_one() when card-specific init function fails. This fixes reboot on my HP NetRAID-4M with dead battery. Signed-off-by: Meelis Roos Reviewed-by: Dave Carroll Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/aacraid/linit.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index d5b26fa541d3..f5ac3747aa16 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1203,8 +1203,10 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) * Map in the registers from the adapter. */ aac->base_size = AAC_MIN_FOOTPRINT_SIZE; - if ((*aac_drivers[index].init)(aac)) + if ((*aac_drivers[index].init)(aac)) { + error = -ENODEV; goto out_unmap; + } if (aac->sync_mode) { if (aac_sync_mode) -- GitLab From e3685f99492c323061d1c33ff1cfadc2d7406a9f Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Sun, 11 Feb 2018 22:48:41 -0800 Subject: [PATCH 525/855] scsi: qla4xxx: skip error recovery in case of register disconnect. [ Upstream commit 1bc5ad3a6acdcf56f83272f2de1cd2389ea9e9e2 ] A system crashes when continuously removing/re-adding the storage controller. Signed-off-by: Manish Rangankar Reviewed-by: Ewan D. Milne Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla4xxx/ql4_def.h | 2 ++ drivers/scsi/qla4xxx/ql4_os.c | 46 ++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index a7cfc270bd08..ce1d063f3e83 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -168,6 +168,8 @@ #define DEV_DB_NON_PERSISTENT 0 #define DEV_DB_PERSISTENT 1 +#define QL4_ISP_REG_DISCONNECT 0xffffffffU + #define COPY_ISID(dst_isid, src_isid) { \ int i, j; \ for (i = 0, j = ISID_SIZE - 1; i < ISID_SIZE;) \ diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 01c3610a60cf..d8c03431d0aa 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -262,6 +262,24 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { static struct scsi_transport_template *qla4xxx_scsi_transport; +static int qla4xxx_isp_check_reg(struct scsi_qla_host *ha) +{ + u32 reg_val = 0; + int rval = QLA_SUCCESS; + + if (is_qla8022(ha)) + reg_val = readl(&ha->qla4_82xx_reg->host_status); + else if (is_qla8032(ha) || is_qla8042(ha)) + reg_val = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER); + else + reg_val = readw(&ha->reg->ctrl_status); + + if (reg_val == QL4_ISP_REG_DISCONNECT) + rval = QLA_ERROR; + + return rval; +} + static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, uint32_t iface_type, uint32_t payload_size, uint32_t pid, struct sockaddr *dst_addr) @@ -9196,10 +9214,17 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) struct srb *srb = NULL; int ret = SUCCESS; int wait = 0; + int rval; ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Abort command issued cmd=%p, cdb=0x%x\n", ha->host_no, id, lun, cmd, cmd->cmnd[0]); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + spin_lock_irqsave(&ha->hardware_lock, flags); srb = (struct srb *) CMD_SP(cmd); if (!srb) { @@ -9251,6 +9276,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; int ret = FAILED, stat; + int rval; if (!ddb_entry) return ret; @@ -9270,6 +9296,12 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) cmd, jiffies, cmd->request->timeout / HZ, ha->dpc_flags, cmd->result, cmd->allowed)); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + /* FIXME: wait for hba to go online */ stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); if (stat != QLA_SUCCESS) { @@ -9313,6 +9345,7 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; int stat, ret; + int rval; if (!ddb_entry) return FAILED; @@ -9330,6 +9363,12 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) ha->host_no, cmd, jiffies, cmd->request->timeout / HZ, ha->dpc_flags, cmd->result, cmd->allowed)); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + stat = qla4xxx_reset_target(ha, ddb_entry); if (stat != QLA_SUCCESS) { starget_printk(KERN_INFO, scsi_target(cmd->device), @@ -9384,9 +9423,16 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) { int return_status = FAILED; struct scsi_qla_host *ha; + int rval; ha = to_qla_host(cmd->device->host); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba) qla4_83xx_set_idc_dontreset(ha); -- GitLab From 4a8907dc9fa9d54c4a4a09a386ec453d3c1128db Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 26 Feb 2018 15:26:01 +0100 Subject: [PATCH 526/855] scsi: mpt3sas: Do not mark fw_event workqueue as WQ_MEM_RECLAIM [ Upstream commit 864449eea7c600596e305ffdc4a6a846414b222c ] The firmware event workqueue should not be marked as WQ_MEM_RECLAIM as it's doesn't need to make forward progress under memory pressure. In the current state it will result in a deadlock if the device had been forcefully removed. Cc: Sreekanth Reddy Cc: Suganath Prabu Subramani Acked-by: Sreekanth Reddy Signed-off-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index b8589068d175..ec48c010a3ba 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -8853,7 +8853,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), "fw_event_%s%d", ioc->driver_name, ioc->id); ioc->firmware_event_thread = alloc_ordered_workqueue( - ioc->firmware_event_name, WQ_MEM_RECLAIM); + ioc->firmware_event_name, 0); if (!ioc->firmware_event_thread) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); -- GitLab From 466a2b7ac9fb99ddc0ff1771c31194d9855997d2 Mon Sep 17 00:00:00 2001 From: Jeremy Cline Date: Tue, 6 Mar 2018 21:47:32 +0000 Subject: [PATCH 527/855] scsi: sd: Keep disk read-only when re-reading partition [ Upstream commit 20bd1d026aacc5399464f8328f305985c493cde3 ] If the read-only flag is true on a SCSI disk, re-reading the partition table sets the flag back to false. To observe this bug, you can run: 1. blockdev --setro /dev/sda 2. blockdev --rereadpt /dev/sda 3. blockdev --getro /dev/sda This commit reads the disk's old state and combines it with the device disk-reported state rather than unconditionally marking it as RW. Reported-by: Li Ning Signed-off-by: Jeremy Cline Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 14ba1a2c0b7c..f8b6bf56c48e 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2401,6 +2401,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) int res; struct scsi_device *sdp = sdkp->device; struct scsi_mode_data data; + int disk_ro = get_disk_ro(sdkp->disk); int old_wp = sdkp->write_prot; set_disk_ro(sdkp->disk, 0); @@ -2441,7 +2442,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) "Test WP failed, assume Write Enabled\n"); } else { sdkp->write_prot = ((data.device_specific & 0x80) != 0); - set_disk_ro(sdkp->disk, sdkp->write_prot); + set_disk_ro(sdkp->disk, sdkp->write_prot || disk_ro); if (sdkp->first_scan || old_wp != sdkp->write_prot) { sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n", sdkp->write_prot ? "on" : "off"); -- GitLab From 2272b67140651aade50a65579a68bdf51bffe2c5 Mon Sep 17 00:00:00 2001 From: Dave Carroll Date: Tue, 3 Apr 2018 15:50:42 -0600 Subject: [PATCH 528/855] scsi: aacraid: Insure command thread is not recursively stopped [ Upstream commit 1c6b41fb92936fa5facea464d5d7cbf855966d04 ] If a recursive IOP_RESET is invoked, usually due to the eh_thread handling errors after the first reset, be sure we flag that the command thread has been stopped to avoid an Oops of the form; [ 336.620256] CPU: 28 PID: 1193 Comm: scsi_eh_0 Kdump: loaded Not tainted 4.14.0-49.el7a.ppc64le #1 [ 336.620297] task: c000003fd630b800 task.stack: c000003fd61a4000 [ 336.620326] NIP: c000000000176794 LR: c00000000013038c CTR: c00000000024bc10 [ 336.620361] REGS: c000003fd61a7720 TRAP: 0300 Not tainted (4.14.0-49.el7a.ppc64le) [ 336.620395] MSR: 9000000000009033 CR: 22084022 XER: 20040000 [ 336.620435] CFAR: c000000000130388 DAR: 0000000000000000 DSISR: 40000000 SOFTE: 1 [ 336.620435] GPR00: c00000000013038c c000003fd61a79a0 c0000000014c7e00 0000000000000000 [ 336.620435] GPR04: 000000000000000c 000000000000000c 9000000000009033 0000000000000477 [ 336.620435] GPR08: 0000000000000477 0000000000000000 0000000000000000 c008000010f7d940 [ 336.620435] GPR12: c00000000024bc10 c000000007a33400 c0000000001708a8 c000003fe3b881d8 [ 336.620435] GPR16: c000003fe3b88060 c000003fd61a7d10 fffffffffffff000 000000000000001e [ 336.620435] GPR20: 0000000000000001 c000000000ebf1a0 0000000000000001 c000003fe3b88000 [ 336.620435] GPR24: 0000000000000003 0000000000000002 c000003fe3b88840 c000003fe3b887e8 [ 336.620435] GPR28: c000003fe3b88000 c000003fc8181788 0000000000000000 c000003fc8181700 [ 336.620750] NIP [c000000000176794] exit_creds+0x34/0x160 [ 336.620775] LR [c00000000013038c] __put_task_struct+0x8c/0x1f0 [ 336.620804] Call Trace: [ 336.620817] [c000003fd61a79a0] [c000003fe3b88000] 0xc000003fe3b88000 (unreliable) [ 336.620853] [c000003fd61a79d0] [c00000000013038c] __put_task_struct+0x8c/0x1f0 [ 336.620889] [c000003fd61a7a00] [c000000000171418] kthread_stop+0x1e8/0x1f0 [ 336.620922] [c000003fd61a7a40] [c008000010f7448c] aac_reset_adapter+0x14c/0x8d0 [aacraid] [ 336.620959] [c000003fd61a7b00] [c008000010f60174] aac_eh_host_reset+0x84/0x100 [aacraid] [ 336.621010] [c000003fd61a7b30] [c000000000864f24] scsi_try_host_reset+0x74/0x180 [ 336.621046] [c000003fd61a7bb0] [c000000000867ac0] scsi_eh_ready_devs+0xc00/0x14d0 [ 336.625165] [c000003fd61a7ca0] [c0000000008699e0] scsi_error_handler+0x550/0x730 [ 336.632101] [c000003fd61a7dc0] [c000000000170a08] kthread+0x168/0x1b0 [ 336.639031] [c000003fd61a7e30] [c00000000000b528] ret_from_kernel_thread+0x5c/0xb4 [ 336.645971] Instruction dump: [ 336.648743] 384216a0 7c0802a6 fbe1fff8 f8010010 f821ffd1 7c7f1b78 60000000 60000000 [ 336.657056] 39400000 e87f0838 f95f0838 7c0004ac <7d401828> 314affff 7d40192d 40c2fff4 [ 336.663997] -[ end trace 4640cf8d4945ad95 ]- So flag when the thread is stopped by setting the thread pointer to NULL. Signed-off-by: Dave Carroll Reviewed-by: Raghava Aditya Renukunta Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/aacraid/commsup.c | 4 +++- drivers/scsi/aacraid/linit.c | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index e2962f15c189..fe670b696251 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1374,9 +1374,10 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) host = aac->scsi_host_ptr; scsi_block_requests(host); aac_adapter_disable_int(aac); - if (aac->thread->pid != current->pid) { + if (aac->thread && aac->thread->pid != current->pid) { spin_unlock_irq(host->host_lock); kthread_stop(aac->thread); + aac->thread = NULL; jafo = 1; } @@ -1445,6 +1446,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) aac->name); if (IS_ERR(aac->thread)) { retval = PTR_ERR(aac->thread); + aac->thread = NULL; goto out; } } diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index f5ac3747aa16..ad902a6e7c12 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1083,6 +1083,7 @@ static void __aac_shutdown(struct aac_dev * aac) up(&fib->event_wait); } kthread_stop(aac->thread); + aac->thread = NULL; } aac_adapter_disable_int(aac); cpu = cpumask_first(cpu_online_mask); -- GitLab From f652149cf3cb0faffe186d6243ee2a55346835b9 Mon Sep 17 00:00:00 2001 From: Wilfried Weissmann Date: Fri, 23 Feb 2018 20:52:34 +0100 Subject: [PATCH 529/855] scsi: mvsas: fix wrong endianness of sgpio api [ Upstream commit e75fba9c0668b3767f608ea07485f48d33c270cf ] This patch fixes the byte order of the SGPIO api and brings it back in sync with ledmon v0.80 and above. [mkp: added missing SoB and fixed whitespace] Signed-off-by: Wilfried Weissmann Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mvsas/mv_94xx.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c index 7de5d8d75480..eb5471bc7263 100644 --- a/drivers/scsi/mvsas/mv_94xx.c +++ b/drivers/scsi/mvsas/mv_94xx.c @@ -1080,16 +1080,16 @@ static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv, void __iomem *regs = mvi->regs_ex - 0x10200; int drive = (i/3) & (4-1); /* drive number on host */ - u32 block = mr32(MVS_SGPIO_DCTRL + + int driveshift = drive * 8; /* bit offset of drive */ + u32 block = ioread32be(regs + MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id); - /* * if bit is set then create a mask with the first * bit of the drive set in the mask ... */ - u32 bit = (write_data[i/8] & (1 << (i&(8-1)))) ? - 1<<(24-drive*8) : 0; + u32 bit = get_unaligned_be32(write_data) & (1 << i) ? + 1 << driveshift : 0; /* * ... and then shift it to the right position based @@ -1098,26 +1098,27 @@ static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv, switch (i%3) { case 0: /* activity */ block &= ~((0x7 << MVS_SGPIO_DCTRL_ACT_SHIFT) - << (24-drive*8)); + << driveshift); /* hardwire activity bit to SOF */ block |= LED_BLINKA_SOF << ( MVS_SGPIO_DCTRL_ACT_SHIFT + - (24-drive*8)); + driveshift); break; case 1: /* id */ block &= ~((0x3 << MVS_SGPIO_DCTRL_LOC_SHIFT) - << (24-drive*8)); + << driveshift); block |= bit << MVS_SGPIO_DCTRL_LOC_SHIFT; break; case 2: /* fail */ block &= ~((0x7 << MVS_SGPIO_DCTRL_ERR_SHIFT) - << (24-drive*8)); + << driveshift); block |= bit << MVS_SGPIO_DCTRL_ERR_SHIFT; break; } - mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id, - block); + iowrite32be(block, + regs + MVS_SGPIO_DCTRL + + MVS_SGPIO_HOST_OFFSET * mvi->id); } @@ -1132,7 +1133,7 @@ static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv, void __iomem *regs = mvi->regs_ex - 0x10200; mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id, - be32_to_cpu(((u32 *) write_data)[i])); + ((u32 *) write_data)[i]); } return reg_count; } -- GitLab From a3adc584abfb4ca44715a5c38d9fe88d9f16f1e5 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 30 Jan 2018 15:58:55 -0800 Subject: [PATCH 530/855] scsi: lpfc: Fix issue_lip if link is disabled [ Upstream commit 2289e9598dde9705400559ca2606fb8c145c34f0 ] The driver ignored checks on whether the link should be kept administratively down after a link bounce. Correct the checks. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/lpfc/lpfc_attr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 453299095847..cf15b9754402 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -635,7 +635,12 @@ lpfc_issue_lip(struct Scsi_Host *shost) LPFC_MBOXQ_t *pmboxq; int mbxstatus = MBXERR_ERROR; + /* + * If the link is offline, disabled or BLOCK_MGMT_IO + * it doesn't make any sense to allow issue_lip + */ if ((vport->fc_flag & FC_OFFLINE_MODE) || + (phba->hba_flag & LINK_DISABLED) || (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)) return -EPERM; -- GitLab From 24678510078c388e89a14545790f28c62c010914 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 30 Jan 2018 15:58:54 -0800 Subject: [PATCH 531/855] scsi: lpfc: Fix soft lockup in lpfc worker thread during LIP testing [ Upstream commit 161df4f09987ae2e9f0f97f0b38eee298b4a39ff ] During link bounce testing in a point-to-point topology, the host may enter a soft lockup on the lpfc_worker thread: Call Trace: lpfc_work_done+0x1f3/0x1390 [lpfc] lpfc_do_work+0x16f/0x180 [lpfc] kthread+0xc7/0xe0 ret_from_fork+0x3f/0x70 The driver was simultaneously setting a combination of flags that caused lpfc_do_work()to effectively spin between slow path work and new event data, causing the lockup. Ensure in the typical wq completions, that new event data flags are set if the slow path flag is running. The slow path will eventually reschedule the wq handling. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/lpfc/lpfc_hbadisc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 7d2ad633b6bc..81736457328a 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -690,8 +690,9 @@ lpfc_work_done(struct lpfc_hba *phba) (phba->hba_flag & HBA_SP_QUEUE_EVT)) { if (pring->flag & LPFC_STOP_IOCB_EVENT) { pring->flag |= LPFC_DEFERRED_RING_EVENT; - /* Set the lpfc data pending flag */ - set_bit(LPFC_DATA_READY, &phba->data_flags); + /* Preserve legacy behavior. */ + if (!(phba->hba_flag & HBA_SP_QUEUE_EVT)) + set_bit(LPFC_DATA_READY, &phba->data_flags); } else { if (phba->link_state >= LPFC_LINK_UP) { pring->flag &= ~LPFC_DEFERRED_RING_EVENT; -- GitLab From e0d35e31c5257438ab6824ab27dd9ac06277a58f Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 30 Jan 2018 15:58:45 -0800 Subject: [PATCH 532/855] scsi: lpfc: Fix frequency of Release WQE CQEs [ Upstream commit 04673e38f56b30cd39b1fa0f386137d818b17781 ] The driver controls when the hardware sends completions that communicate consumption of elements from the WQ. This is done by setting a WQEC bit on a WQE. The current driver sets it on every Nth WQE posting. However, the driver isn't clearing the bit if the WQE is reused. Thus, if the queue depth isn't evenly divisible by N, with enough time, it can be set on every element, creating a lot of overhead and risking CQ full conditions. Correct by clearing the bit when not setting it on an Nth element. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/lpfc/lpfc_sli.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 0902ed204ba8..6df06e716da1 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -116,6 +116,8 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) /* set consumption flag every once in a while */ if (!((q->host_index + 1) % q->entry_repost)) bf_set(wqe_wqec, &wqe->generic.wqe_com, 1); + else + bf_set(wqe_wqec, &wqe->generic.wqe_com, 0); if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED) bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id); lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size); -- GitLab From bdaea52d57a2b80c4f7770be894f6b83415510a0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 15 Jan 2018 11:08:38 +0300 Subject: [PATCH 533/855] ASoC: au1x: Fix timeout tests in au1xac97c_ac97_read() [ Upstream commit 123af9043e93cb6f235207d260d50f832cdb5439 ] The loop timeout doesn't work because it's a post op and ends with "tmo" set to -1. I changed it from a post-op to a pre-op and I changed the initial the starting value from 5 to 6 so we still iterate 5 times. I left the other as it was because it's a large number. Fixes: b3c70c9ea62a ("ASoC: Alchemy AC97C/I2SC audio support") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/au1x/ac97c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index 29a97d52e8ad..66d6c52e7761 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c @@ -91,8 +91,8 @@ static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97, do { mutex_lock(&ctx->lock); - tmo = 5; - while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--) + tmo = 6; + while ((RD(ctx, AC97_STATUS) & STAT_CP) && --tmo) udelay(21); /* wait an ac97 frame time */ if (!tmo) { pr_debug("ac97rd timeout #1\n"); @@ -105,7 +105,7 @@ static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97, * poll, Forrest, poll... */ tmo = 0x10000; - while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--) + while ((RD(ctx, AC97_STATUS) & STAT_CP) && --tmo) asm volatile ("nop"); data = RD(ctx, AC97_CMDRESP); -- GitLab From a74ae617a73b520f0ed719388d3c502d54b164da Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 9 Mar 2018 11:11:17 -0800 Subject: [PATCH 534/855] ASoC: topology: create TLV data for dapm widgets [ Upstream commit bde8b3887add8368ecf0ca71117baf2fd56a6fc9 ] This patch adds the change required to create the TLV data for dapm widget kcontrols from topology. This also fixes the following TLV read error shown in amixer while showing the card control contents. "amixer: Control hw:1 element TLV read error: No such device or address" Signed-off-by: Ranjani Sridharan Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 8a758c994506..d6b48c796bfc 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1180,6 +1180,9 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( kfree(sm); continue; } + + /* create any TLV data */ + soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr); } return kc; -- GitLab From 608ae38610e62c719ad5fff57b7d47c82f68cd84 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 5 Feb 2018 16:43:56 +0100 Subject: [PATCH 535/855] ASoC: samsung: i2s: Ensure the RCLK rate is properly determined [ Upstream commit 647d04f8e07afc7c3b7a42b3ee01a8b28db29631 ] If the RCLK mux clock configuration is specified in DT and no set_sysclk() callback is used in the sound card driver the sclk_srcrate field will remain set to 0, leading to an incorrect PSR divider setting. To fix this the frequency value is retrieved from the CLK_I2S_RCLK_SRC clock, so the actual RCLK mux selection is taken into account. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/samsung/i2s.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 85324e61cbd5..2d14e37ddc3f 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -642,8 +642,12 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, tmp |= mod_slave; break; case SND_SOC_DAIFMT_CBS_CFS: - /* Set default source clock in Master mode */ - if (i2s->rclk_srcrate == 0) + /* + * Set default source clock in Master mode, only when the + * CLK_I2S_RCLK_SRC clock is not exposed so we ensure any + * clock configuration assigned in DT is not overwritten. + */ + if (i2s->rclk_srcrate == 0 && i2s->clk_data.clks == NULL) i2s_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0, 0, SND_SOC_CLOCK_IN); break; @@ -858,6 +862,11 @@ static int config_setup(struct i2s_dai *i2s) return 0; if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { + struct clk *rclksrc = i2s->clk_table[CLK_I2S_RCLK_SRC]; + + if (i2s->rclk_srcrate == 0 && rclksrc && !IS_ERR(rclksrc)) + i2s->rclk_srcrate = clk_get_rate(rclksrc); + psr = i2s->rclk_srcrate / i2s->frmclk / rfs; writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR); dev_dbg(&i2s->pdev->dev, -- GitLab From f19681dfbb927df582e856a6d26c685ee201892c Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 21 Mar 2018 10:39:19 +0800 Subject: [PATCH 536/855] clk: rockchip: Fix wrong parent for SDMMC phase clock for rk3228 [ Upstream commit 4b0556a441dd37e598887215bc89b49a6ef525b3 ] commit c420c1e4db22 ("clk: rockchip: Prevent calculating mmc phase if clock rate is zero") catches one gremlin again for clk-rk3228.c that the parent of SDMMC phase clock should be sclk_sdmmc0, but not sclk_sdmmc. However, the naming of the sdmmc clocks varies in the manual with the card clock having the 0 while the hclk is named without appended 0. So standardize one one format to prevent confusion, as there also is only one (non-sdio) mmc controller on the soc. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/rockchip/clk-rk3228.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c index db6e5a9e6de6..53f16efbb8f4 100644 --- a/drivers/clk/rockchip/clk-rk3228.c +++ b/drivers/clk/rockchip/clk-rk3228.c @@ -369,7 +369,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 6, DFLAGS, RK2928_CLKGATE_CON(2), 15, GFLAGS), - COMPOSITE(SCLK_SDMMC, "sclk_sdmmc0", mux_mmc_src_p, 0, + COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0, RK2928_CLKSEL_CON(11), 8, 2, MFLAGS, 0, 8, DFLAGS, RK2928_CLKGATE_CON(2), 11, GFLAGS), -- GitLab From 2c440ef456c297c44c2fa5bc061f995ab7692344 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 14 Mar 2018 08:28:31 +0800 Subject: [PATCH 537/855] clk: Don't show the incorrect clock phase [ Upstream commit 1f9c63e8de3d7b377c9d74e4a17524cfb60e6384 ] It's found that the clock phase output from clk_summary is wrong compared to the actual phase reading from the register. cat /sys/kernel/debug/clk/clk_summary | grep sdio_sample sdio_sample 0 1 0 50000000 0 -22 It exposes an issue that clk core, clk_core_get_phase, always returns the cached core->phase which should be either updated by calling clk_set_phase or directly from the first place the clk was registered. When registering the clk, the core->phase geting from ->get_phase() may return negative value indicating error. This is quite common since the clk's phase may be highly related to its parent chain, but it was temporarily orphan when registered, since its parent chains hadn't be ready at that time, so the clk drivers decide to return error in this case. However, if no clk_set_phase is called or maybe the ->set_phase() isn't even implemented, the core->phase would never be updated. This is wrong, and we should try to update it when all its parent chains are settled down, like the way of updating clock rate for that. But it's not deserved to complicate the code now and just update it anyway when calling clk_core_get_phase, which would be much simple and enough. Signed-off-by: Shawn Lin Acked-by: Jerome Brunet Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/clk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 0cdb8550729d..c745dad7f85e 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1929,6 +1929,9 @@ static int clk_core_get_phase(struct clk_core *core) int ret; clk_prepare_lock(); + /* Always try to update cached phase if possible */ + if (core->ops->get_phase) + core->phase = core->ops->get_phase(core->hw); ret = core->phase; clk_prepare_unlock(); -- GitLab From eaab238dbb53206d2864074d0365a263a51054e2 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Fri, 23 Feb 2018 00:04:51 +0100 Subject: [PATCH 538/855] clk: tegra: Fix pll_u rate configuration [ Upstream commit c35b518f9ba06c9de79fb3ff62eed7462d804995 ] Turns out latest upstream U-Boot does not configure/enable pll_u which leaves it at some default rate of 500 kHz: root@apalis-t30:~# cat /sys/kernel/debug/clk/clk_summary | grep pll_u pll_u 3 3 0 500000 0 Of course this won't quite work leading to the following messages: [ 6.559593] usb 2-1: new full-speed USB device number 2 using tegra- ehci [ 11.759173] usb 2-1: device descriptor read/64, error -110 [ 27.119453] usb 2-1: device descriptor read/64, error -110 [ 27.389217] usb 2-1: new full-speed USB device number 3 using tegra- ehci [ 32.559454] usb 2-1: device descriptor read/64, error -110 [ 47.929777] usb 2-1: device descriptor read/64, error -110 [ 48.049658] usb usb2-port1: attempt power cycle [ 48.759475] usb 2-1: new full-speed USB device number 4 using tegra- ehci [ 59.349457] usb 2-1: device not accepting address 4, error -110 [ 59.509449] usb 2-1: new full-speed USB device number 5 using tegra- ehci [ 70.069457] usb 2-1: device not accepting address 5, error -110 [ 70.079721] usb usb2-port1: unable to enumerate USB device Fix this by actually allowing the rate also being set from within the Linux kernel. Signed-off-by: Marcel Ziswiler Tested-by: Jon Hunter Signed-off-by: Thierry Reding Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/tegra/clk-pll.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index b3855360d6bc..66d1fc7dff58 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -1145,6 +1145,8 @@ static const struct clk_ops tegra_clk_pllu_ops = { .enable = clk_pllu_enable, .disable = clk_pll_disable, .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_round_rate, + .set_rate = clk_pll_set_rate, }; static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params, -- GitLab From e651dc5a400262cf0f9f52edaf381df2f8dfd634 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:15:36 -0500 Subject: [PATCH 539/855] media: cx23885: Set subdev host data to clk_freq pointer [ Upstream commit 5ceade1d97fc6687e050c44c257382c192f56276 ] Currently clk_freq is ignored entirely, because the cx235840 driver configures the xtal at the chip defaults. This is an issue if a board is produced with a non-default frequency crystal. If clk_freq is not zero the cx25840 will attempt to use the setting provided, or fall back to defaults otherwise. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/pci/cx23885/cx23885-cards.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 99ba8d6328f0..427ece11340b 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -2282,6 +2282,10 @@ void cx23885_card_setup(struct cx23885_dev *dev) &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); if (dev->sd_cx25840) { + /* set host data for clk_freq configuration */ + v4l2_set_subdev_hostdata(dev->sd_cx25840, + &dev->clk_freq); + dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE; v4l2_subdev_call(dev->sd_cx25840, core, load_fw); } -- GitLab From 1325a6c91a880e3aacb7a0acc3dfba3840361653 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 5 Mar 2018 11:25:58 +0800 Subject: [PATCH 540/855] clk: rockchip: Prevent calculating mmc phase if clock rate is zero [ Upstream commit 4bf59902b50012b1dddeeaa23b217d9c4956cdda ] The MMC sample and drv clock for rockchip platforms are derived from the bus clock output to the MMC/SDIO card. So it should never happens that the clk rate is zero given it should inherits the clock rate from its parent. If something goes wrong and makes the clock rate to be zero, the calculation would be wrong but may still make the mmc tuning process work luckily. However it makes people harder to debug when the following data transfer is unstable. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/rockchip/clk-mmc-phase.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index 077fcdc7908b..fe7d9ed1d436 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -58,6 +58,12 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw) u16 degrees; u32 delay_num = 0; + /* See the comment for rockchip_mmc_set_phase below */ + if (!rate) { + pr_err("%s: invalid clk rate\n", __func__); + return -EINVAL; + } + raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift); degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; @@ -84,6 +90,23 @@ static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees) u32 raw_value; u32 delay; + /* + * The below calculation is based on the output clock from + * MMC host to the card, which expects the phase clock inherits + * the clock rate from its parent, namely the output clock + * provider of MMC host. However, things may go wrong if + * (1) It is orphan. + * (2) It is assigned to the wrong parent. + * + * This check help debug the case (1), which seems to be the + * most likely problem we often face and which makes it difficult + * for people to debug unstable mmc tuning results. + */ + if (!rate) { + pr_err("%s: invalid clk rate\n", __func__); + return -EINVAL; + } + nineties = degrees / 90; remainder = (degrees % 90); -- GitLab From c2cc0c41a7ab54ac20cf04589a9f84aae0d28f30 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 16 Feb 2018 15:57:53 +0100 Subject: [PATCH 541/855] clk: samsung: s3c2410: Fix PLL rates [ Upstream commit 179db533c08431f509a3823077549773d519358b ] Rates declared in PLL rate tables should match exactly rates calculated from the PLL coefficients. If that is not the case, rate of the PLL's child clock might be set not as expected. For instance, if in the PLL rates table we have a 393216000 Hz entry and the real value as returned by the PLL's recalc_rate callback is 393216003, after setting PLL's clk rate to 393216000 clk_get_rate will return 393216003. If we now attempt to set rate of a PLL's child divider clock to 393216000/2 its rate will be 131072001, rather than 196608000. That is, the divider will be set to 3 instead of 2, because 393216003/2 is greater than 196608000. To fix this issue declared rates are changed to exactly match rates generated by the PLL, as calculated from the P, M, S, K coefficients. Signed-off-by: Andrzej Hajda Acked-by: Tomasz Figa Acked-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/samsung/clk-s3c2410.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c index d7a1e772d95a..5f50037586ea 100644 --- a/drivers/clk/samsung/clk-s3c2410.c +++ b/drivers/clk/samsung/clk-s3c2410.c @@ -168,7 +168,7 @@ static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = { PLL_35XX_RATE(226000000, 105, 1, 1), PLL_35XX_RATE(210000000, 132, 2, 1), /* 2410 common */ - PLL_35XX_RATE(203000000, 161, 3, 1), + PLL_35XX_RATE(202800000, 161, 3, 1), PLL_35XX_RATE(192000000, 88, 1, 1), PLL_35XX_RATE(186000000, 85, 1, 1), PLL_35XX_RATE(180000000, 82, 1, 1), @@ -178,18 +178,18 @@ static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = { PLL_35XX_RATE(147000000, 90, 2, 1), PLL_35XX_RATE(135000000, 82, 2, 1), PLL_35XX_RATE(124000000, 116, 1, 2), - PLL_35XX_RATE(118000000, 150, 2, 2), + PLL_35XX_RATE(118500000, 150, 2, 2), PLL_35XX_RATE(113000000, 105, 1, 2), - PLL_35XX_RATE(101000000, 127, 2, 2), + PLL_35XX_RATE(101250000, 127, 2, 2), PLL_35XX_RATE(90000000, 112, 2, 2), - PLL_35XX_RATE(85000000, 105, 2, 2), + PLL_35XX_RATE(84750000, 105, 2, 2), PLL_35XX_RATE(79000000, 71, 1, 2), - PLL_35XX_RATE(68000000, 82, 2, 2), - PLL_35XX_RATE(56000000, 142, 2, 3), + PLL_35XX_RATE(67500000, 82, 2, 2), + PLL_35XX_RATE(56250000, 142, 2, 3), PLL_35XX_RATE(48000000, 120, 2, 3), - PLL_35XX_RATE(51000000, 161, 3, 3), + PLL_35XX_RATE(50700000, 161, 3, 3), PLL_35XX_RATE(45000000, 82, 1, 3), - PLL_35XX_RATE(34000000, 82, 2, 3), + PLL_35XX_RATE(33750000, 82, 2, 3), { /* sentinel */ }, }; -- GitLab From 2434a0623bccd3c4bc68df79697fcb5e8ed1165a Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 16 Feb 2018 15:57:52 +0100 Subject: [PATCH 542/855] clk: samsung: exynos7: Fix PLL rates [ Upstream commit 7e4db0c2836e892766565965207eee051c8037b9 ] Rates declared in PLL rate tables should match exactly rates calculated from the PLL coefficients. If that is not the case, rate of the PLL's child clock might be set not as expected. For instance, if in the PLL rates table we have a 393216000 Hz entry and the real value as returned by the PLL's recalc_rate callback is 393216003, after setting PLL's clk rate to 393216000 clk_get_rate will return 393216003. If we now attempt to set rate of a PLL's child divider clock to 393216000/2 its rate will be 131072001, rather than 196608000. That is, the divider will be set to 3 instead of 2, because 393216003/2 is greater than 196608000. To fix this issue declared rates are changed to exactly match rates generated by the PLL, as calculated from the P, M, S, K coefficients. Signed-off-by: Andrzej Hajda Acked-by: Tomasz Figa Acked-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/samsung/clk-exynos7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c index 5931a4140c3d..bbfa57b4e017 100644 --- a/drivers/clk/samsung/clk-exynos7.c +++ b/drivers/clk/samsung/clk-exynos7.c @@ -140,7 +140,7 @@ static const struct samsung_div_clock topc_div_clks[] __initconst = { }; static const struct samsung_pll_rate_table pll1460x_24mhz_tbl[] __initconst = { - PLL_36XX_RATE(491520000, 20, 1, 0, 31457), + PLL_36XX_RATE(491519897, 20, 1, 0, 31457), {}, }; -- GitLab From 1b287c3a10d8a993af3728664ce84f1ade62c3f2 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 16 Feb 2018 15:57:50 +0100 Subject: [PATCH 543/855] clk: samsung: exynos5260: Fix PLL rates [ Upstream commit cdb68fbd4e7962be742c4f29475220c5bf28d8a5 ] Rates declared in PLL rate tables should match exactly rates calculated from the PLL coefficients. If that is not the case, rate of the PLL's child clock might be set not as expected. For instance, if in the PLL rates table we have a 393216000 Hz entry and the real value as returned by the PLL's recalc_rate callback is 393216003, after setting PLL's clk rate to 393216000 clk_get_rate will return 393216003. If we now attempt to set rate of a PLL's child divider clock to 393216000/2 its rate will be 131072001, rather than 196608000. That is, the divider will be set to 3 instead of 2, because 393216003/2 is greater than 196608000. To fix this issue declared rates are changed to exactly match rates generated by the PLL, as calculated from the P, M, S, K coefficients. Signed-off-by: Andrzej Hajda Acked-by: Tomasz Figa Acked-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/samsung/clk-exynos5260.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index fd1d9bfc151b..8eae1752d700 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c @@ -65,7 +65,7 @@ static const struct samsung_pll_rate_table pll2650_24mhz_tbl[] __initconst = { PLL_36XX_RATE(480000000, 160, 2, 2, 0), PLL_36XX_RATE(432000000, 144, 2, 2, 0), PLL_36XX_RATE(400000000, 200, 3, 2, 0), - PLL_36XX_RATE(394073130, 459, 7, 2, 49282), + PLL_36XX_RATE(394073128, 459, 7, 2, 49282), PLL_36XX_RATE(333000000, 111, 2, 2, 0), PLL_36XX_RATE(300000000, 100, 2, 2, 0), PLL_36XX_RATE(266000000, 266, 3, 3, 0), -- GitLab From 8c762043010c19ebe3bc59ba7119234531929bb4 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 16 Feb 2018 15:57:51 +0100 Subject: [PATCH 544/855] clk: samsung: exynos5433: Fix PLL rates [ Upstream commit ab0447845cffc0fd752df2ccd6b4e34006000ce4 ] Rates declared in PLL rate tables should match exactly rates calculated from the PLL coefficients. If that is not the case, rate of the PLL's child clock might be set not as expected. For instance, if in the PLL rates table we have a 393216000 Hz entry and the real value as returned by the PLL's recalc_rate callback is 393216003, after setting PLL's clk rate to 393216000 clk_get_rate will return 393216003. If we now attempt to set rate of a PLL's child divider clock to 393216000/2 its rate will be 131072001, rather than 196608000. That is, the divider will be set to 3 instead of 2, because 393216003/2 is greater than 196608000. To fix this issue declared rates are changed to exactly match rates generated by the PLL, as calculated from the P, M, S, K coefficients. Signed-off-by: Andrzej Hajda Acked-by: Tomasz Figa Acked-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/samsung/clk-exynos5433.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 2fe057326552..09cdd35dc434 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -725,7 +725,7 @@ static const struct samsung_pll_rate_table exynos5443_pll_rates[] __initconst = PLL_35XX_RATE(800000000U, 400, 6, 1), PLL_35XX_RATE(733000000U, 733, 12, 1), PLL_35XX_RATE(700000000U, 175, 3, 1), - PLL_35XX_RATE(667000000U, 222, 4, 1), + PLL_35XX_RATE(666000000U, 222, 4, 1), PLL_35XX_RATE(633000000U, 211, 4, 1), PLL_35XX_RATE(600000000U, 500, 5, 2), PLL_35XX_RATE(552000000U, 460, 5, 2), @@ -751,12 +751,12 @@ static const struct samsung_pll_rate_table exynos5443_pll_rates[] __initconst = /* AUD_PLL */ static const struct samsung_pll_rate_table exynos5443_aud_pll_rates[] __initconst = { PLL_36XX_RATE(400000000U, 200, 3, 2, 0), - PLL_36XX_RATE(393216000U, 197, 3, 2, -25690), + PLL_36XX_RATE(393216003U, 197, 3, 2, -25690), PLL_36XX_RATE(384000000U, 128, 2, 2, 0), - PLL_36XX_RATE(368640000U, 246, 4, 2, -15729), - PLL_36XX_RATE(361507200U, 181, 3, 2, -16148), - PLL_36XX_RATE(338688000U, 113, 2, 2, -6816), - PLL_36XX_RATE(294912000U, 98, 1, 3, 19923), + PLL_36XX_RATE(368639991U, 246, 4, 2, -15729), + PLL_36XX_RATE(361507202U, 181, 3, 2, -16148), + PLL_36XX_RATE(338687988U, 113, 2, 2, -6816), + PLL_36XX_RATE(294912002U, 98, 1, 3, 19923), PLL_36XX_RATE(288000000U, 96, 1, 3, 0), PLL_36XX_RATE(252000000U, 84, 1, 3, 0), { /* sentinel */ } -- GitLab From a5637e4c95106da860472bbe528dff4c7c8b8d65 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 16 Feb 2018 15:57:49 +0100 Subject: [PATCH 545/855] clk: samsung: exynos5250: Fix PLL rates [ Upstream commit 2ac051eeabaa411ef89ae7cd5bb8e60cb41ad780 ] Rates declared in PLL rate tables should match exactly rates calculated from PLL coefficients. If that is not the case, rate of the PLL's child clock might be set not as expected. For instance, if in the PLL rates table we have a 393216000 Hz entry and the real value as returned by the PLL's recalc_rate callback is 393216003, after setting PLL's clk rate to 393216000 clk_get_rate will return 393216003. If we now attempt to set rate of a PLL's child divider clock to 393216000/2 its rate will be 131072001, rather than 196608000. That is, the divider will be set to 3 instead of 2, because 393216003/2 is greater than 196608000. To fix this issue declared rates are changed to exactly match rates generated by the PLL, as calculated from the P, M, S, K coefficients. Signed-off-by: Andrzej Hajda Acked-by: Chanwoo Choi Acked-by: Tomasz Figa Signed-off-by: Sylwester Nawrocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/samsung/clk-exynos5250.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 27a227d6620c..6a0cb8a515e8 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -711,13 +711,13 @@ static const struct samsung_pll_rate_table epll_24mhz_tbl[] __initconst = { /* sorted in descending order */ /* PLL_36XX_RATE(rate, m, p, s, k) */ PLL_36XX_RATE(192000000, 64, 2, 2, 0), - PLL_36XX_RATE(180633600, 90, 3, 2, 20762), + PLL_36XX_RATE(180633605, 90, 3, 2, 20762), PLL_36XX_RATE(180000000, 90, 3, 2, 0), PLL_36XX_RATE(73728000, 98, 2, 4, 19923), - PLL_36XX_RATE(67737600, 90, 2, 4, 20762), + PLL_36XX_RATE(67737602, 90, 2, 4, 20762), PLL_36XX_RATE(49152000, 98, 3, 4, 19923), - PLL_36XX_RATE(45158400, 90, 3, 4, 20762), - PLL_36XX_RATE(32768000, 131, 3, 5, 4719), + PLL_36XX_RATE(45158401, 90, 3, 4, 20762), + PLL_36XX_RATE(32768001, 131, 3, 5, 4719), { }, }; -- GitLab From 515702e0a90097344b9ec851501bb87074be47f5 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 16 Feb 2018 15:57:48 +0100 Subject: [PATCH 546/855] clk: samsung: exynos3250: Fix PLL rates [ Upstream commit a8321e7887410a2b2e80ab89d1ef7b30562658ea ] Rates declared in PLL rate tables should match exactly rates calculated from PLL coefficients. If that is not the case, rate of the PLL's child clock might be set not as expected. For instance, if in the PLL rates table we have a 393216000 Hz entry and the real value as returned by the PLL's recalc_rate callback is 393216003, after setting PLL's clk rate to 393216000 clk_get_rate will return 393216003. If we now attempt to set rate of a PLL's child divider clock to 393216000/2 its rate will be 131072001, rather than 196608000. That is, the divider will be set to 3 instead of 2, because 393216003/2 is greater than 196608000. To fix this issue declared rates are changed to exactly match rates generated by the PLL, as calculated from the P, M, S, K coefficients. In this patch an erroneous P value for 74176002 output frequency is also corrected. Signed-off-by: Andrzej Hajda Acked-by: Chanwoo Choi Acked-by: Tomasz Figa Signed-off-by: Sylwester Nawrocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/samsung/clk-exynos3250.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index 1b81e283f605..ed36728424a2 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -698,7 +698,7 @@ static const struct samsung_pll_rate_table exynos3250_epll_rates[] __initconst = PLL_36XX_RATE(144000000, 96, 2, 3, 0), PLL_36XX_RATE( 96000000, 128, 2, 4, 0), PLL_36XX_RATE( 84000000, 112, 2, 4, 0), - PLL_36XX_RATE( 80000004, 106, 2, 4, 43691), + PLL_36XX_RATE( 80000003, 106, 2, 4, 43691), PLL_36XX_RATE( 73728000, 98, 2, 4, 19923), PLL_36XX_RATE( 67737598, 270, 3, 5, 62285), PLL_36XX_RATE( 65535999, 174, 2, 5, 49982), @@ -734,7 +734,7 @@ static const struct samsung_pll_rate_table exynos3250_vpll_rates[] __initconst = PLL_36XX_RATE(148352005, 98, 2, 3, 59070), PLL_36XX_RATE(108000000, 144, 2, 4, 0), PLL_36XX_RATE( 74250000, 99, 2, 4, 0), - PLL_36XX_RATE( 74176002, 98, 3, 4, 59070), + PLL_36XX_RATE( 74176002, 98, 2, 4, 59070), PLL_36XX_RATE( 54054000, 216, 3, 5, 14156), PLL_36XX_RATE( 54000000, 144, 2, 5, 0), { /* sentinel */ } -- GitLab From 40a8962a531db9823db2c091303357debed16c5b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 11 Feb 2018 05:44:21 -0500 Subject: [PATCH 547/855] media: dmxdev: fix error code for invalid ioctls [ Upstream commit a145f64c6107d3aa5a7cec9f8977d04ac2a896c9 ] Returning -EINVAL when an ioctl is not implemented is a very bad idea, as it is hard to distinguish from other error contitions that an ioctl could lead. Replace it by its right error code: -ENOTTY. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb-core/dmxdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 7b67e1dd97fd..0418b5a0fb64 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1071,7 +1071,7 @@ static int dvb_demux_do_ioctl(struct file *file, break; default: - ret = -EINVAL; + ret = -ENOTTY; break; } mutex_unlock(&dmxdev->mutex); -- GitLab From 9a2347ab98806576b7159740220021d4fbe80fdb Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:15:37 -0500 Subject: [PATCH 548/855] media: cx23885: Override 888 ImpactVCBe crystal frequency [ Upstream commit 779c79d4b833ec646b0aed878da38edb45bbe156 ] Hauppauge produced a revision of ImpactVCBe using an 888, with a 25MHz crystal, instead of using the default third overtone 50Mhz crystal. This overrides that frequency so that the cx25840 is properly configured. Without the proper crystal setup the cx25840 cannot load the firmware or decode video. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/pci/cx23885/cx23885-core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index c86b1093ab99..dcbb3a260b52 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -872,6 +872,16 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) if (cx23885_boards[dev->board].clk_freq > 0) dev->clk_freq = cx23885_boards[dev->board].clk_freq; + if (dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE && + dev->pci->subsystem_device == 0x7137) { + /* Hauppauge ImpactVCBe device ID 0x7137 is populated + * with an 888, and a 25Mhz crystal, instead of the + * usual third overtone 50Mhz. The default clock rate must + * be overridden so the cx25840 is properly configured + */ + dev->clk_freq = 25000000; + } + dev->pci_bus = dev->pci->bus->number; dev->pci_slot = PCI_SLOT(dev->pci->devfn); cx23885_irq_add(dev, 0x001f00); -- GitLab From 07c41c408f32fceabcc4541d9d550333c427f7fc Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 16 Jan 2018 16:52:15 -0500 Subject: [PATCH 549/855] media: s3c-camif: fix out-of-bounds array access [ Upstream commit a398e043637a4819a0e96467bfecaabf3224dd62 ] While experimenting with older compiler versions, I ran into a warning that no longer shows up on gcc-4.8 or newer: drivers/media/platform/s3c-camif/camif-capture.c: In function '__camif_subdev_try_format': drivers/media/platform/s3c-camif/camif-capture.c:1265:25: error: array subscript is below array bounds This is an off-by-one bug, leading to an access before the start of the array, while newer compilers silently assume this undefined behavior cannot happen and leave the loop at index 0 if no other entry matches. As Sylvester explains, we actually need to ensure that the value is within the range, so this reworks the loop to be easier to parse correctly, and an additional check to fall back on the first format value for any unexpected input. I found an existing gcc bug for it and added a reduced version of the function there. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69249#c3 Fixes: babde1c243b2 ("[media] V4L: Add driver for S3C24XX/S3C64XX SoC series camera interface") Signed-off-by: Arnd Bergmann Reviewed-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/s3c-camif/camif-capture.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 0413a861a59a..5c9db0910a76 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -1256,16 +1256,17 @@ static void __camif_subdev_try_format(struct camif_dev *camif, { const struct s3c_camif_variant *variant = camif->variant; const struct vp_pix_limits *pix_lim; - int i = ARRAY_SIZE(camif_mbus_formats); + unsigned int i; /* FIXME: constraints against codec or preview path ? */ pix_lim = &variant->vp_pix_limits[VP_CODEC]; - while (i-- >= 0) + for (i = 0; i < ARRAY_SIZE(camif_mbus_formats); i++) if (camif_mbus_formats[i] == mf->code) break; - mf->code = camif_mbus_formats[i]; + if (i == ARRAY_SIZE(camif_mbus_formats)) + mf->code = camif_mbus_formats[0]; if (pad == CAMIF_SD_PAD_SINK) { v4l_bound_align_image(&mf->width, 8, CAMIF_MAX_PIX_WIDTH, -- GitLab From 28ea156b65622edc8384d0688db8aeb206f2e48b Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 6 Feb 2018 03:02:23 -0500 Subject: [PATCH 550/855] media: vb2: Fix videobuf2 to map correct area [ Upstream commit d13a0139d7874a0577b5955d6eed895517d23b72 ] Fixes vb2_vmalloc_get_userptr() to ioremap correct area. Since the current code does ioremap the page address, if the offset > 0, it does not do ioremap the last page and results in kernel panic. This fixes to pass the size + offset to ioremap so that ioremap can map correct area. Also, this uses __pfn_to_phys() to get the physical address of given PFN. Signed-off-by: Masami Hiramatsu Reported-by: Takao Orito Reported-by: Fumihiro ATSUMI Reviewed-by: Marek Szyprowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/videobuf2-vmalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index ab3227b75c84..760cbf2ba01a 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -104,7 +104,7 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr, if (nums[i-1] + 1 != nums[i]) goto fail_map; buf->vaddr = (__force void *) - ioremap_nocache(nums[0] << PAGE_SHIFT, size); + ioremap_nocache(__pfn_to_phys(nums[0]), size + offset); } else { buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1, PAGE_KERNEL); -- GitLab From 9639854bd3b82d8590e1888f80b6ca4bacc3465b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 1 Feb 2018 02:36:33 -0500 Subject: [PATCH 551/855] media: vivid: fix incorrect capabilities for radio [ Upstream commit 65243386f41d38460bfd4375d231a7c0346d0401 ] The vivid driver has two custom controls that change the behavior of RDS. Depending on the control setting the V4L2_CAP_READWRITE capability is toggled. However, after an earlier commit the capability was no longer set correctly. This is now fixed. Fixes: 9765a32cd8 ("vivid: set device_caps in video_device") Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/vivid/vivid-ctrls.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index aceb38d9f7e7..b1c37252a6c7 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -1167,6 +1167,7 @@ static int vivid_radio_rx_s_ctrl(struct v4l2_ctrl *ctrl) v4l2_ctrl_activate(dev->radio_rx_rds_ta, dev->radio_rx_rds_controls); v4l2_ctrl_activate(dev->radio_rx_rds_tp, dev->radio_rx_rds_controls); v4l2_ctrl_activate(dev->radio_rx_rds_ms, dev->radio_rx_rds_controls); + dev->radio_rx_dev.device_caps = dev->radio_rx_caps; break; case V4L2_CID_RDS_RECEPTION: dev->radio_rx_rds_enabled = ctrl->val; @@ -1241,6 +1242,7 @@ static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl) dev->radio_tx_caps &= ~V4L2_CAP_READWRITE; if (!dev->radio_tx_rds_controls) dev->radio_tx_caps |= V4L2_CAP_READWRITE; + dev->radio_tx_dev.device_caps = dev->radio_tx_caps; break; case V4L2_CID_RDS_TX_PTY: if (dev->radio_rx_rds_controls) -- GitLab From 7c36063750f3fcc7b22a0b301a8f78cde5fa5365 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 31 Jan 2018 12:33:09 -0500 Subject: [PATCH 552/855] media: cx25821: prevent out-of-bounds read on array card [ Upstream commit 67300abdbe9f1717532aaf4e037222762716d0f6 ] Currently an out of range dev->nr is detected by just reporting the issue and later on an out-of-bounds read on array card occurs because of this. Fix this by checking the upper range of dev->nr with the size of array card (removes the hard coded size), move this check earlier and also exit with the error -ENOSYS to avoid the later out-of-bounds array read. Detected by CoverityScan, CID#711191 ("Out-of-bounds-read") Fixes: commit 02b20b0b4cde ("V4L/DVB (12730): Add conexant cx25821 driver") Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil [hans.verkuil@cisco.com: %ld -> %zd] Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/pci/cx25821/cx25821-core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 9a5f912ca859..0d4cacb93664 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -871,6 +871,10 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) dev->nr = ++cx25821_devcount; sprintf(dev->name, "cx25821[%d]", dev->nr); + if (dev->nr >= ARRAY_SIZE(card)) { + CX25821_INFO("dev->nr >= %zd", ARRAY_SIZE(card)); + return -ENODEV; + } if (dev->pci->device != 0x8210) { pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", __func__, dev->pci->device); @@ -886,9 +890,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) dev->channels[i].sram_channels = &cx25821_sram_channels[i]; } - if (dev->nr > 1) - CX25821_INFO("dev->nr > 1!"); - /* board config */ dev->board = 1; /* card[dev->nr]; */ dev->_max_num_decoders = MAX_DECODERS; -- GitLab From 4cb84bd8720ebe445d0ef8976307b78894b93262 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:37 +0100 Subject: [PATCH 553/855] serial: xuartps: Fix out-of-bounds access through DT alias [ Upstream commit e7d75e18d0fc3f7193b65282b651f980c778d935 ] The cdns_uart_port[] array is indexed using a value derived from the "serialN" alias in DT, which may lead to an out-of-bounds access. Fix this by adding a range check. Fixes: 928e9263492069ee ("tty: xuartps: Initialize ports according to aliases") Signed-off-by: Geert Uytterhoeven Reviewed-by: Michal Simek Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index dd4c02fa4820..7497f1d4a818 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1106,7 +1106,7 @@ static struct uart_port *cdns_uart_get_port(int id) struct uart_port *port; /* Try the given port id if failed use default method */ - if (cdns_uart_port[id].mapbase != 0) { + if (id < CDNS_UART_NR_PORTS && cdns_uart_port[id].mapbase != 0) { /* Find the next unused port */ for (id = 0; id < CDNS_UART_NR_PORTS; id++) if (cdns_uart_port[id].mapbase == 0) -- GitLab From 2803df3004f05ed6649e01cbf16224be0c845494 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:34 +0100 Subject: [PATCH 554/855] serial: samsung: Fix out-of-bounds access through serial port index [ Upstream commit 49ee23b71877831ac087d6083f6f397dc19c9664 ] The s3c24xx_serial_ports[] array is indexed using a value derived from the "serialN" alias in DT, or from an incrementing probe index, which may lead to an out-of-bounds access. Fix this by adding a range check. Note that the array size is defined by a Kconfig symbol (CONFIG_SERIAL_SAMSUNG_UARTS), so this can even be triggered using a legitimate DTB or legitimate board code. Fixes: 13a9f6c64fdc55eb ("serial: samsung: Consider DT alias when probing ports") Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index d65f92bcd0f1..f2ab6d8aab41 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1813,6 +1813,10 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) dbg("s3c24xx_serial_probe(%p) %d\n", pdev, index); + if (index >= ARRAY_SIZE(s3c24xx_serial_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", index); + return -EINVAL; + } ourport = &s3c24xx_serial_ports[index]; ourport->drv_data = s3c24xx_get_driver_data(pdev); -- GitLab From 2e876eae48736674bf2c5caa9c49566dffabb991 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:32 +0100 Subject: [PATCH 555/855] serial: mxs-auart: Fix out-of-bounds access through serial port index [ Upstream commit dd345a31bfdec350d2593e6de5964e55c7f19c76 ] The auart_port[] array is indexed using a value derived from the "serialN" alias in DT, or from platform data, which may lead to an out-of-bounds access. Fix this by adding a range check. Fixes: 1ea6607d4cdc9179 ("serial: mxs-auart: Allow device tree probing") Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mxs-auart.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 07390f8c3681..1d9d778828ba 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1664,6 +1664,10 @@ static int mxs_auart_probe(struct platform_device *pdev) s->port.line = pdev->id < 0 ? 0 : pdev->id; else if (ret < 0) return ret; + if (s->port.line >= ARRAY_SIZE(auart_port)) { + dev_err(&pdev->dev, "serial%d out of range\n", s->port.line); + return -EINVAL; + } if (of_id) { pdev->id_entry = of_id->data; -- GitLab From a301f13f34b8359f4844b2961789afbfc10bd21d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:31 +0100 Subject: [PATCH 556/855] serial: imx: Fix out-of-bounds access through serial port index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 5673444821406dda5fc25e4b52aca419f8065a19 ] The imx_ports[] array is indexed using a value derived from the "serialN" alias in DT, or from platform data, which may lead to an out-of-bounds access. Fix this by adding a range check. Fixes: ff05967a07225ab6 ("serial/imx: add of_alias_get_id() reference back") Signed-off-by: Geert Uytterhoeven Reviewed-by: Uwe Kleine-König Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index ecadc27eea48..b24edf634985 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2080,6 +2080,12 @@ static int serial_imx_probe(struct platform_device *pdev) else if (ret < 0) return ret; + if (sport->port.line >= ARRAY_SIZE(imx_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", + sport->port.line); + return -EINVAL; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) -- GitLab From cd777719e331432c74ecc75acbe653beb1d9180c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:30 +0100 Subject: [PATCH 557/855] serial: fsl_lpuart: Fix out-of-bounds access through DT alias [ Upstream commit ffab87fdecc655cc676f8be8dd1a2c5e22bd6d47 ] The lpuart_ports[] array is indexed using a value derived from the "serialN" alias in DT, which may lead to an out-of-bounds access. Fix this by adding a range check. Fixes: c9e2e946fb0ba5d2 ("tty: serial: add Freescale lpuart driver support") Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 76103f2c4a80..937f5e10f165 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1902,6 +1902,10 @@ static int lpuart_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); return ret; } + if (ret >= ARRAY_SIZE(lpuart_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", ret); + return -EINVAL; + } sport->port.line = ret; sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart"); -- GitLab From 561a4f4d9d4d0f71333ab53bc29a96b74edaedb2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:29 +0100 Subject: [PATCH 558/855] serial: arc_uart: Fix out-of-bounds access through DT alias [ Upstream commit f9f5786987e81d166c60833edcb7d1836aa16944 ] The arc_uart_ports[] array is indexed using a value derived from the "serialN" alias in DT, which may lead to an out-of-bounds access. Fix this by adding a range check. Note that the array size is defined by a Kconfig symbol (CONFIG_SERIAL_ARC_NR_PORTS), so this can even be triggered using a legitimate DTB. Fixes: ea28fd56fcde69af ("serial/arc-uart: switch to devicetree based probing") Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/arc_uart.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 5ac06fcaa9c6..fec48deb074c 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -596,6 +596,11 @@ static int arc_serial_probe(struct platform_device *pdev) if (dev_id < 0) dev_id = 0; + if (dev_id >= ARRAY_SIZE(arc_uart_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", dev_id); + return -EINVAL; + } + uart = &arc_uart_ports[dev_id]; port = &uart->port; -- GitLab From 3ac3103cd0dd2d67c2331377844dffd8b13c3ba6 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Thu, 8 Feb 2018 18:25:41 +0530 Subject: [PATCH 559/855] serial: 8250: Don't service RX FIFO if interrupts are disabled [ Upstream commit 2e9fe539108320820016f78ca7704a7342788380 ] Currently, data in RX FIFO is read based on UART_LSR register state even if RDI and RLSI interrupts are disabled in UART_IER register. This is because when IRQ handler is called due to TX FIFO empty event, RX FIFO is serviced based on UART_LSR register status instead of UART_IIR status. This defeats the purpose of disabling UART RX FIFO interrupts during throttling(see, omap_8250_throttle()) as IRQ handler continues to drain UART RX FIFO resulting in overflow of buffer at tty layer. Fix this by making sure that driver drains UART RX FIFO only when UART_IIR_RDI is set along with UART_LSR_BI or UART_LSR_DR bits. Signed-off-by: Vignesh R Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index f6e4373a8850..5d9038a5bbc4 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1815,7 +1815,8 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) status = serial_port_in(port, UART_LSR); - if (status & (UART_LSR_DR | UART_LSR_BI)) { + if (status & (UART_LSR_DR | UART_LSR_BI) && + iir & UART_IIR_RDI) { if (!up->dma || handle_rx_dma(up, iir)) status = serial8250_rx_chars(up, status); } -- GitLab From 36ce931c4286f77c5f37b487514a59103a2308c4 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 28 Mar 2018 20:14:05 +0100 Subject: [PATCH 560/855] rtc: snvs: Fix usage of snvs_rtc_enable [ Upstream commit 1485991c024603b2fb4ae77beb7a0d741128a48e ] commit 179a502f8c46 ("rtc: snvs: add Freescale rtc-snvs driver") introduces the SNVS RTC driver with a function snvs_rtc_enable(). snvs_rtc_enable() can return an error on the enable path however this driver does not currently trap that failure on the probe() path and consequently if enabling the RTC fails we encounter a later error spinning forever in rtc_write_sync_lp(). [ 36.093481] [] (__irq_svc) from [] (_raw_spin_unlock_irqrestore+0x34/0x44) [ 36.102122] [] (_raw_spin_unlock_irqrestore) from [] (regmap_read+0x4c/0x5c) [ 36.110938] [] (regmap_read) from [] (rtc_write_sync_lp+0x6c/0x98) [ 36.118881] [] (rtc_write_sync_lp) from [] (snvs_rtc_alarm_irq_enable+0x40/0x4c) [ 36.128041] [] (snvs_rtc_alarm_irq_enable) from [] (rtc_timer_do_work+0xd8/0x1a8) [ 36.137291] [] (rtc_timer_do_work) from [] (process_one_work+0x28c/0x76c) [ 36.145840] [] (process_one_work) from [] (worker_thread+0x34/0x58c) [ 36.153961] [] (worker_thread) from [] (kthread+0x138/0x150) [ 36.161388] [] (kthread) from [] (ret_from_fork+0x14/0x20) [ 36.168635] rcu_sched kthread starved for 2602 jiffies! g496 c495 f0x2 RCU_GP_WAIT_FQS(3) ->state=0x0 ->cpu=0 [ 36.178564] rcu_sched R running task 0 8 2 0x00000000 [ 36.185664] [] (__schedule) from [] (schedule+0x3c/0xa0) [ 36.192739] [] (schedule) from [] (schedule_timeout+0x78/0x4e0) [ 36.200422] [] (schedule_timeout) from [] (rcu_gp_kthread+0x648/0x1864) [ 36.208800] [] (rcu_gp_kthread) from [] (kthread+0x138/0x150) [ 36.216309] [] (kthread) from [] (ret_from_fork+0x14/0x20) This patch fixes by parsing the result of rtc_write_sync_lp() and propagating both in the probe and elsewhere. If the RTC doesn't start we don't proceed loading the driver and don't get into this loop mess later on. Fixes: 179a502f8c46 ("rtc: snvs: add Freescale rtc-snvs driver") Signed-off-by: Bryan O'Donoghue Acked-by: Shawn Guo Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-snvs.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index a753ef9c1459..3e8fd33c2576 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -132,20 +132,23 @@ static int snvs_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct snvs_rtc_data *data = dev_get_drvdata(dev); unsigned long time; + int ret; rtc_tm_to_time(tm, &time); /* Disable RTC first */ - snvs_rtc_enable(data, false); + ret = snvs_rtc_enable(data, false); + if (ret) + return ret; /* Write 32-bit time to 47-bit timer, leaving 15 LSBs blank */ regmap_write(data->regmap, data->offset + SNVS_LPSRTCLR, time << CNTR_TO_SECS_SH); regmap_write(data->regmap, data->offset + SNVS_LPSRTCMR, time >> (32 - CNTR_TO_SECS_SH)); /* Enable RTC again */ - snvs_rtc_enable(data, true); + ret = snvs_rtc_enable(data, true); - return 0; + return ret; } static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -287,7 +290,11 @@ static int snvs_rtc_probe(struct platform_device *pdev) regmap_write(data->regmap, data->offset + SNVS_LPSR, 0xffffffff); /* Enable RTC */ - snvs_rtc_enable(data, true); + ret = snvs_rtc_enable(data, true); + if (ret) { + dev_err(&pdev->dev, "failed to enable rtc %d\n", ret); + goto error_rtc_device_register; + } device_init_wakeup(&pdev->dev, true); -- GitLab From dd6b3e0a66592a72914be1d38ba29f93804e3161 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 8 Mar 2018 23:27:31 +0100 Subject: [PATCH 561/855] rtc: hctosys: Ensure system time doesn't overflow time_t [ Upstream commit b3a5ac42ab18b7d1a8f2f072ca0ee76a3b754a43 ] On 32bit platforms, time_t is still a signed 32bit long. If it is overflowed, userspace and the kernel cant agree on the current system time. This causes multiple issues, in particular with systemd: https://github.com/systemd/systemd/issues/1143 A good workaround is to simply avoid using hctosys which is something I greatly encourage as the time is better set by userspace. However, many distribution enable it and use systemd which is rendering the system unusable in case the RTC holds a date after 2038 (and more so after 2106). Many drivers have workaround for this case and they should be eliminated so there is only one place left to fix when userspace is able to cope with dates after the 31bit overflow. Acked-by: Arnd Bergmann Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/hctosys.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c index e1cfa06810ef..e79f2a181ad2 100644 --- a/drivers/rtc/hctosys.c +++ b/drivers/rtc/hctosys.c @@ -49,6 +49,11 @@ static int __init rtc_hctosys(void) tv64.tv_sec = rtc_tm_to_time64(&tm); +#if BITS_PER_LONG == 32 + if (tv64.tv_sec > INT_MAX) + goto err_read; +#endif + err = do_settimeofday64(&tv64); dev_info(rtc->dev.parent, -- GitLab From 0c60045656488690b047aa535bc3c3328a544062 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 15 Feb 2018 19:36:14 +0000 Subject: [PATCH 562/855] rtc: tx4939: avoid unintended sign extension on a 24 bit shift [ Upstream commit 347876ad47b9923ce26e686173bbf46581802ffa ] The shifting of buf[5] by 24 bits to the left will be promoted to a 32 bit signed int and then sign-extended to an unsigned long. If the top bit of buf[5] is set then all then all the upper bits sec end up as also being set because of the sign-extension. Fix this by casting buf[5] to an unsigned long before the shift. Detected by CoverityScan, CID#1465292 ("Unintended sign extension") Fixes: 0e1492330cd2 ("rtc: add rtc-tx4939 driver") Signed-off-by: Colin Ian King Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-tx4939.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index 560d9a5e0225..a9528083061d 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -86,7 +86,8 @@ static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm) for (i = 2; i < 6; i++) buf[i] = __raw_readl(&rtcreg->dat); spin_unlock_irq(&pdata->lock); - sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; + sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) | + (buf[3] << 8) | buf[2]; rtc_time_to_tm(sec, tm); return rtc_valid_tm(tm); } @@ -147,7 +148,8 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0; alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0; spin_unlock_irq(&pdata->lock); - sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; + sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) | + (buf[3] << 8) | buf[2]; rtc_time_to_tm(sec, &alrm->time); return rtc_valid_tm(&alrm->time); } -- GitLab From aa4b4ace9ce02cf164e0982739e9565d6214cfa9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 25 May 2018 16:13:16 +0200 Subject: [PATCH 563/855] Linux 4.9.103 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d84c39c290f7..6090f655fb32 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 102 +SUBLEVEL = 103 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From d60cdac2645f273812b008694ad49de839244924 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Fri, 25 May 2018 15:22:59 +0530 Subject: [PATCH 564/855] sched: walt: fix updating stale window_start for walt load With commit '45121eb2cdb ("sched/walt: Fix stale window start marker passed to the schedutil")', sched reports 'walt_irq_work_lastq_ws' time as window start for schedutil. With that there is a possiblilty of sending staled value as window start, as it is not protect by common lock but only atomically updated by any cpu. Here is one possible scenario, CPU1 reporting the load at the window boundary and preempted by secure world and on window rollover other cpu reports load with new window_start. CPU1 CPU2 try_to_wake_up() update_task_ravg() wallclock=779987000 rq_lock(cpu1) cpufreq_update_util() try_to_wake_up() cpu_util_freq() update_task_ravg() walt_irq_work_lastq_ws=760000000 wallclock=780080182 curr_ws = 760000000 run_walt_irq_work() walt_irq_work_lastq_ws=780000000 rq_lock(cpu2) cpufreq_update_util() cpu_util_freq() curr_ws = 780000000 < return back > lock(sg_policy->update_lock) < waiting update_lock > sg_policy->last_ws= 780000000 unlock(sg_policy->update_lock) lock(sg_policy->update_lock) BUG(curr_ws < last_ws) 760000000 < 780000000 Fix this by updating the load reporting window start variable when all rq locks held at walt irq work. Change-Id: Id8c767420845ce003bee96d006bd2551321a9923 Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/sched.h | 4 ++-- kernel/sched/walt.c | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 61aa3c78e8d1..d73dfaed7037 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1861,7 +1861,7 @@ cpu_util_freq_pelt(int cpu) } #ifdef CONFIG_SCHED_WALT -extern atomic64_t walt_irq_work_lastq_ws; +extern u64 walt_load_reported_window; static inline unsigned long cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load) @@ -1899,7 +1899,7 @@ cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load) walt_load->prev_window_util = util; walt_load->nl = nl; walt_load->pl = pl; - walt_load->ws = atomic64_read(&walt_irq_work_lastq_ws); + walt_load->ws = walt_load_reported_window; } return (util >= capacity) ? capacity : util; diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index a2debf9dc405..8bacb6f07fba 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -44,7 +44,8 @@ const char *migrate_type_names[] = {"GROUP_TO_RQ", "RQ_TO_GROUP", static struct cpu_cycle_counter_cb cpu_cycle_counter_cb; static bool use_cycle_counter; DEFINE_MUTEX(cluster_lock); -atomic64_t walt_irq_work_lastq_ws; +static atomic64_t walt_irq_work_lastq_ws; +u64 walt_load_reported_window; static struct irq_work walt_cpufreq_irq_work; static struct irq_work walt_migration_irq_work; @@ -866,6 +867,9 @@ void set_window_start(struct rq *rq) rq->window_start = 1; sync_cpu_available = 1; atomic64_set(&walt_irq_work_lastq_ws, rq->window_start); + walt_load_reported_window = + atomic64_read(&walt_irq_work_lastq_ws); + } else { struct rq *sync_rq = cpu_rq(cpumask_any(cpu_online_mask)); @@ -3142,7 +3146,7 @@ void walt_irq_work(struct irq_work *irq_work) raw_spin_lock(&cpu_rq(cpu)->lock); wc = ktime_get_ns(); - + walt_load_reported_window = atomic64_read(&walt_irq_work_lastq_ws); for_each_sched_cluster(cluster) { u64 aggr_grp_load = 0; -- GitLab From b5e135c0fb2ce27a500ede21e049c9346ea96dd1 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 24 May 2018 15:11:39 -0700 Subject: [PATCH 565/855] msm: camera: sensor: Validate power settings As part of shutdown when we free the power settings we should assign the pointer to NULL. And in power down we validate the settings. Change-Id: I7abe11548e211dfd89387069191234488dcfd0ce Signed-off-by: Karthik Anantha Ram --- .../cam_sensor/cam_sensor_core.c | 23 ++++--------------- .../cam_sensor_utils/cam_sensor_util.c | 20 ++++++++++------ 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index d58834c3d719..2133932dde57 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -518,6 +518,8 @@ void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) kfree(power_info->power_setting); kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; s_ctrl->streamon_count = 0; s_ctrl->streamoff_count = 0; @@ -584,24 +586,6 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, "Already Sensor Probed in the slot"); break; } - /* Allocate memory for power up setting */ - pu = kzalloc(sizeof(struct cam_sensor_power_setting) * - MAX_POWER_CONFIG, GFP_KERNEL); - if (!pu) { - rc = -ENOMEM; - goto release_mutex; - } - - pd = kzalloc(sizeof(struct cam_sensor_power_setting) * - MAX_POWER_CONFIG, GFP_KERNEL); - if (!pd) { - kfree(pu); - rc = -ENOMEM; - goto release_mutex; - } - - power_info->power_setting = pu; - power_info->power_down_setting = pd; if (cmd->handle_type == CAM_HANDLE_MEM_HANDLE) { @@ -618,6 +602,9 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, return -EINVAL; } + pu = power_info->power_setting; + pd = power_info->power_down_setting; + /* Parse and fill vreg params for powerup settings */ rc = msm_camera_fill_vreg_params( &s_ctrl->soc_info, diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 10d29c91f03e..c05db9123936 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -860,8 +860,10 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, return rc; free_power_down_settings: kfree(power_info->power_down_setting); + power_info->power_down_setting = NULL; free_power_settings: kfree(power_info->power_setting); + power_info->power_setting = NULL; return rc; } @@ -1304,7 +1306,9 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, CAM_DBG(CAM_SENSOR, "index: %d", index); power_setting = &ctrl->power_setting[index]; if (!power_setting) { - CAM_ERR(CAM_SENSOR, "Invalid power up settings"); + CAM_ERR(CAM_SENSOR, + "Invalid power up settings for index %d", + index); return -EINVAL; } @@ -1594,11 +1598,6 @@ static int cam_config_mclk_reg(struct cam_sensor_power_ctrl_t *ctrl, pd = &ctrl->power_down_setting[index]; - if (!pd) { - CAM_ERR(CAM_SENSOR, "Invalid power down setting"); - return -EINVAL; - } - for (j = 0; j < num_vreg; j++) { if (!strcmp(soc_info->rgltr_name[j], "cam_clk")) { @@ -1641,7 +1640,7 @@ int msm_camera_power_down(struct cam_sensor_power_ctrl_t *ctrl, { int index = 0, ret = 0, num_vreg = 0, i; struct cam_sensor_power_setting *pd = NULL; - struct cam_sensor_power_setting *ps; + struct cam_sensor_power_setting *ps = NULL; struct msm_camera_gpio_num_info *gpio_num_info = NULL; CAM_DBG(CAM_SENSOR, "Enter"); @@ -1661,6 +1660,13 @@ int msm_camera_power_down(struct cam_sensor_power_ctrl_t *ctrl, for (index = 0; index < ctrl->power_down_setting_size; index++) { CAM_DBG(CAM_SENSOR, "index %d", index); pd = &ctrl->power_down_setting[index]; + if (!pd) { + CAM_ERR(CAM_SENSOR, + "Invalid power down settings for index %d", + index); + return -EINVAL; + } + ps = NULL; CAM_DBG(CAM_SENSOR, "type %d", pd->seq_type); switch (pd->seq_type) { -- GitLab From dfbd96335e3579d0c88c316e67af9e5e4da80578 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Thu, 24 May 2018 15:38:48 -0700 Subject: [PATCH 566/855] power: smb138x: set some USB/Typec IRQs as wakeup ones The device cannot wake up from sleep on USB insertion, because USBIN_PLUGIN_IRQ, USBIN_SRC_CHANGE_IRQ and TYPE_C_CHANGE_IRQ are not set as wakeup IRQs. Fix it. CRs-Fixed: 2249396 Change-Id: Iaf5ecbf9c77ae847cc9071f9742fdd16936c0e73 Signed-off-by: Harry Yang --- drivers/power/supply/qcom/smb138x-charger.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c index f1df8f076eb0..86ecda548996 100644 --- a/drivers/power/supply/qcom/smb138x-charger.c +++ b/drivers/power/supply/qcom/smb138x-charger.c @@ -1371,10 +1371,12 @@ static struct smb_irq_info smb138x_irqs[] = { [USBIN_PLUGIN_IRQ] = { .name = "usbin-plugin", .handler = smblib_handle_usb_plugin, + .wake = true, }, [USBIN_SRC_CHANGE_IRQ] = { .name = "usbin-src-change", .handler = smblib_handle_usb_source_change, + .wake = true, }, [USBIN_ICL_CHANGE_IRQ] = { .name = "usbin-icl-change", @@ -1383,6 +1385,7 @@ static struct smb_irq_info smb138x_irqs[] = { [TYPE_C_CHANGE_IRQ] = { .name = "type-c-change", .handler = smblib_handle_usb_typec_change, + .wake = true, }, /* DC INPUT IRQs */ [DCIN_COLLAPSE_IRQ] = { @@ -1825,6 +1828,8 @@ static int smb138x_probe(struct platform_device *pdev) goto cleanup; } + device_init_wakeup(chip->chg.dev, true); + pr_info("SMB138X probed successfully mode=%d\n", chip->chg.mode); return rc; -- GitLab From 89b6cbe300e1d4b7442ae5ad9a1929eb2129e00d Mon Sep 17 00:00:00 2001 From: Lakshmi Narayana Kalavala Date: Fri, 11 May 2018 11:28:12 -0700 Subject: [PATCH 567/855] drm/msm: Fix the format prints in display driver Fix the %p format prints with %pK. Change-Id: I1743bacb76c1db4bfa304146f7d391751b35273c Signed-off-by: Lakshmi Narayana Kalavala --- drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c | 2 +- drivers/gpu/drm/msm/dsi-staging/dsi_phy.c | 3 ++- drivers/gpu/drm/msm/edp/edp.c | 4 ++-- drivers/gpu/drm/msm/msm_drv.c | 11 ++++++----- drivers/gpu/drm/msm/msm_fb.c | 8 ++++---- drivers/gpu/drm/msm/msm_fbdev.c | 4 ++-- drivers/gpu/drm/msm/msm_gem.c | 4 ++-- drivers/gpu/drm/msm/sde/sde_crtc.c | 2 +- .../gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c | 2 +- drivers/gpu/drm/msm/sde/sde_kms.c | 2 +- 10 files changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index 32bc3eb5b655..673d07efb3fc 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -461,7 +461,7 @@ static int dsi_ctrl_init_regmap(struct platform_device *pdev, } ctrl->hw.base = ptr; - pr_debug("[%s] map dsi_ctrl registers to %p\n", ctrl->name, + pr_debug("[%s] map dsi_ctrl registers to %pK\n", ctrl->name, ctrl->hw.base); switch (ctrl->version) { diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c index 2e2d0d81d643..989dc3d01875 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c @@ -107,7 +107,8 @@ static int dsi_phy_regmap_init(struct platform_device *pdev, phy->hw.base = ptr; - pr_debug("[%s] map dsi_phy registers to %p\n", phy->name, phy->hw.base); + pr_debug("[%s] map dsi_phy registers to %pK\n", + phy->name, phy->hw.base); return rc; } diff --git a/drivers/gpu/drm/msm/edp/edp.c b/drivers/gpu/drm/msm/edp/edp.c index 0940e84b2821..2c9d11638f29 100644 --- a/drivers/gpu/drm/msm/edp/edp.c +++ b/drivers/gpu/drm/msm/edp/edp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015,2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -54,7 +54,7 @@ static struct msm_edp *edp_init(struct platform_device *pdev) ret = -ENOMEM; goto fail; } - DBG("eDP probed=%p", edp); + DBG("eDP probed=%pK", edp); edp->pdev = pdev; platform_set_drvdata(pdev, edp); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 0697db831867..9eb62fe92454 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -156,7 +156,8 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, } if (reglog) - printk(KERN_DEBUG "IO:region %s %p %08lx\n", dbgname, ptr, size); + dev_dbg(&pdev->dev, "IO:region %s %pK %08lx\n", + dbgname, ptr, size); return ptr; } @@ -187,7 +188,7 @@ void msm_iounmap(struct platform_device *pdev, void __iomem *addr) void msm_writel(u32 data, void __iomem *addr) { if (reglog) - printk(KERN_DEBUG "IO:W %p %08x\n", addr, data); + pr_debug("IO:W %pK %08x\n", addr, data); writel(data, addr); } @@ -196,7 +197,7 @@ u32 msm_readl(const void __iomem *addr) u32 val = readl(addr); if (reglog) - printk(KERN_ERR "IO:R %p %08x\n", addr, val); + pr_err("IO:R %pK %08x\n", addr, val); return val; } @@ -1024,7 +1025,7 @@ static int msm_enable_vblank(struct drm_device *dev, unsigned int pipe) if (!kms) return -ENXIO; - DBG("dev=%p, crtc=%u", dev, pipe); + DBG("dev=%pK, crtc=%u", dev, pipe); return vblank_ctrl_queue_work(priv, pipe, true); } @@ -1035,7 +1036,7 @@ static void msm_disable_vblank(struct drm_device *dev, unsigned int pipe) if (!kms) return; - DBG("dev=%p, crtc=%u", dev, pipe); + DBG("dev=%pK, crtc=%u", dev, pipe); vblank_ctrl_queue_work(priv, pipe, false); } diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index e8bf244cd612..a1c9d82e7601 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -68,7 +68,7 @@ static void msm_framebuffer_destroy(struct drm_framebuffer *fb) msm_fb = to_msm_framebuffer(fb); n = drm_format_num_planes(fb->pixel_format); - DBG("destroy: FB ID: %d (%p)", fb->base.id, fb); + DBG("destroy: FB ID: %d (%pK)", fb->base.id, fb); drm_framebuffer_cleanup(fb); @@ -336,7 +336,7 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, unsigned int hsub, vsub; bool is_modified = false; - DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)", + DBG("create framebuffer: dev=%pK, mode_cmd=%pK (%dx%d@%4.4s)", dev, mode_cmd, mode_cmd->width, mode_cmd->height, (char *)&mode_cmd->pixel_format); @@ -420,7 +420,7 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, goto fail; } - DBG("create: FB ID: %d (%p)", fb->base.id, fb); + DBG("create: FB ID: %d (%pK)", fb->base.id, fb); return fb; diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index ffd4a338ca12..5b886d027593 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -142,7 +142,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, goto fail_unlock; } - DBG("fbi=%p, dev=%p", fbi, dev); + DBG("fbi=%pK, dev=%pK", fbi, dev); fbdev->fb = fb; helper->fb = fb; @@ -167,7 +167,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, fbi->fix.smem_start = paddr; fbi->fix.smem_len = fbdev->bo->size; - DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); + DBG("par=%pK, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 277b42162e7c..5b15c8c72256 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -253,7 +253,7 @@ int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) pfn = page_to_pfn(pages[pgoff]); - VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address, + VERB("Inserting %pK pfn %lx, pa %lx", vmf->virtual_address, pfn, pfn << PAGE_SHIFT); ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, @@ -799,7 +799,7 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) break; } - seq_printf(m, "%08x: %c %2d (%2d) %08llx %p %zu%s\n", + seq_printf(m, "%08x: %c %2d (%2d) %08llx %pK %zu%s\n", msm_obj->flags, is_active(msm_obj) ? 'A' : 'I', obj->name, obj->refcount.refcount.counter, diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index cefa5139e29b..a8cde808c846 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -4848,7 +4848,7 @@ void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - SDE_DEBUG("%s: cancel: %p\n", sde_crtc->name, file); + SDE_DEBUG("%s: cancel: %pK\n", sde_crtc->name, file); _sde_crtc_complete_flip(crtc, file); } diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c index 9e64d7863842..c7989cd8d96e 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c @@ -680,7 +680,7 @@ void sde_setup_dspp_pcc_v1_7(struct sde_hw_dspp *ctx, void *cfg) void __iomem *base; if (!hw_cfg || (hw_cfg->len != sizeof(*pcc) && hw_cfg->payload)) { - DRM_ERROR("invalid params hw %p payload %p payloadsize %d \"\ + DRM_ERROR("invalid params hw %pK payload %pK payloadsize %d \"\ exp size %zd\n", hw_cfg, ((hw_cfg) ? hw_cfg->payload : NULL), ((hw_cfg) ? hw_cfg->len : 0), sizeof(*pcc)); diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index b0a52a705cb5..1358ddda8559 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -3195,7 +3195,7 @@ static int sde_kms_hw_init(struct msm_kms *kms) sde_kms->mmio = NULL; goto error; } - DRM_INFO("mapped mdp address space @%p\n", sde_kms->mmio); + DRM_INFO("mapped mdp address space @%pK\n", sde_kms->mmio); sde_kms->mmio_len = msm_iomap_size(dev->platformdev, "mdp_phys"); rc = sde_dbg_reg_register_base(SDE_DBG_NAME, sde_kms->mmio, -- GitLab From f669c7c86315b006e7f8dd81ef169befd3272bed Mon Sep 17 00:00:00 2001 From: Raja Mallik Date: Mon, 21 May 2018 23:59:11 +0530 Subject: [PATCH 568/855] ARM: defconfig: Remove CONFIG_QCOM_PM for msm8909 Remove CONFIG_QCOM_PM as msm8909 uses different spm driver. Change-Id: I348b69467103c6b953c518ae807e5d07ca3c877f Signed-off-by: Chinkit Kumar,Kirti Kumar Parmar --- arch/arm/configs/msm8909-perf_defconfig | 1 - arch/arm/configs/msm8909_defconfig | 1 - arch/arm/configs/msm8909w-perf_defconfig | 1 - arch/arm/configs/msm8909w_defconfig | 1 - 4 files changed, 4 deletions(-) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 6046ae6430d8..1eaf4ffc03ce 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -398,7 +398,6 @@ CONFIG_USB_BAM=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_MAILBOX=y CONFIG_ARM_SMMU=y -CONFIG_QCOM_PM=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y CONFIG_MSM_BOOT_STATS=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index 67e7f06a3a22..5e6a68b97b7b 100644 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -393,7 +393,6 @@ CONFIG_USB_BAM=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_MAILBOX=y CONFIG_ARM_SMMU=y -CONFIG_QCOM_PM=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y CONFIG_MSM_BOOT_STATS=y diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 5a56d638d3c3..14ba558c176d 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -411,7 +411,6 @@ CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_MAILBOX=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y -CONFIG_QCOM_PM=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y CONFIG_MSM_BOOT_STATS=y diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index 17baa044e9a4..2eb602bab1a5 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -425,7 +425,6 @@ CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_MAILBOX=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y -CONFIG_QCOM_PM=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y CONFIG_MSM_BOOT_STATS=y -- GitLab From bc46a78f13da9c237493a12cf21b1e2d67ae7dcc Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Tue, 15 May 2018 11:28:08 +0530 Subject: [PATCH 569/855] arm: irq: call irq affinity notifiers on cpu hotplug Commit '813aa7765fb4a ("genirq: Use irq_set_affinity_locked to change irq affinity")' has introduced the change in generic irq, which is needed by PM QoS to get irq affinity notifications, but it is not addressing 32-bit cpu hotplug path. So update 32-bit cpu hotplug path also to call irq_set_affinity_locked. Change-Id: Ic5971b8a75a2faaf78d861d9e1e6989132beea79 Signed-off-by: Lingutla Chandrasekhar --- arch/arm/kernel/irq.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 2d1d821063b8..42d3974671d9 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -150,10 +150,15 @@ static bool migrate_one_irq(struct irq_desc *desc) } c = irq_data_get_irq_chip(d); - if (!c->irq_set_affinity) + if (!c->irq_set_affinity) { pr_debug("IRQ%u: unable to set affinity\n", d->irq); - else if (c->irq_set_affinity(d, affinity, false) == IRQ_SET_MASK_OK && ret) - cpumask_copy(irq_data_get_affinity_mask(d), affinity); + } else { + int r = irq_set_affinity_locked(d, affinity, false); + + if (r) + pr_warn_ratelimited("IRQ%u: set affinity failed(%d).\n", + d->irq, r); + } return ret; } -- GitLab From dd1872442d2df839825797ba80f83f9c69392687 Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Fri, 25 May 2018 12:29:24 +0530 Subject: [PATCH 570/855] ARM: dts: msm: Add support for HD+ video mode panel on msm8917 Add changes to add panel init sequence, on/off commands and other panel properties for MirrorLake HD+ (720x1440p) video mode panel for msm8917. (cherry-pick from 'commit 9bed34516289 ("ARM: dts: msm: Add support for HD+ video mode panel on msm8917")' and 'commit c1cf2a945237 ("ARM: dts: msm: add support for mirror lake touch panel on msm8917")'). Change-Id: I47a23696afe91ea28dafa4cd94281ce0d1830f46 Signed-off-by: Nirmal Abraham --- .../dsi-panel-icn9706-720-1440p-video.dtsi | 98 +++++++++++++++++++ .../qcom/msm8917-cdp-mirror-lake-touch.dtsi | 6 ++ .../boot/dts/qcom/msm8937-mdss-panels.dtsi | 2 + 3 files changed, 106 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-icn9706-720-1440p-video.dtsi diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-icn9706-720-1440p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-icn9706-720-1440p-video.dtsi new file mode 100644 index 000000000000..d50fe3be60d0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-icn9706-720-1440p-video.dtsi @@ -0,0 +1,98 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_icn9706_720_1440_vid: qcom,mdss_dsi_icn9706_720_1440p_video { + qcom,mdss-dsi-panel-name = + "icn9706 720 1440p video mode dsi panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1440>; + qcom,mdss-dsi-h-front-porch = <84>; + qcom,mdss-dsi-h-back-porch = <84>; + qcom,mdss-dsi-h-pulse-width = <24>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <20>; + qcom,mdss-dsi-v-front-porch = <24>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [8b 1e 14 00 44 48 18 22 19 + 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1c>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-on-command = [39 01 00 00 64 00 02 01 00 + 39 01 00 00 00 00 03 f0 5a 5a + 39 01 00 00 00 00 03 f1 5a 5a + 39 01 00 00 00 00 03 f0 b4 4b + 39 01 00 00 00 00 03 b6 10 10 + 39 01 00 00 00 00 15 b4 0a 08 12 10 0e 0c 00 00 + 00 03 00 03 03 03 03 03 03 03 04 06 + 39 01 00 00 00 00 15 b3 0b 09 13 11 0f 0d 00 00 + 00 03 00 03 03 03 03 03 03 03 05 07 + 39 01 00 00 00 00 0d b0 54 32 23 45 44 44 44 44 + 60 01 60 01 + 39 01 00 00 00 00 09 b1 32 84 02 83 15 01 57 01 + 39 01 00 00 00 00 02 b2 33 + 39 01 00 00 00 00 07 bd 54 14 6a 6a 20 19 + 39 01 00 00 00 00 12 b7 01 01 09 11 0d 15 19 0d + 21 1d 00 00 20 00 02 ff 3c + 39 01 00 00 00 00 06 b8 23 01 30 34 53 + 39 01 00 00 00 00 05 b9 a1 2c ff c4 + 39 01 00 00 00 00 03 ba 88 23 + 39 01 00 00 00 00 07 c1 16 16 04 0c 10 04 + 39 01 00 00 00 00 03 c2 12 68 + 39 01 00 00 00 00 04 c3 22 31 04 + 39 01 00 00 00 00 06 c7 05 23 6b 41 00 + 39 01 00 00 00 00 27 c8 7c 54 3d 2d 26 16 1b 08 + 25 28 2d 4f 3e 48 3d 3d 35 25 06 7c 54 3d 2d + 26 16 1b 08 25 28 2d 4f 3e 48 3d 3d 35 25 06 + 39 01 00 00 00 00 09 c6 00 00 68 00 00 60 36 00 + 05 01 00 00 64 00 02 11 00 + 05 01 00 00 32 00 02 29 00]; + + qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 + 05 01 00 00 32 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "bta_check"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 2>, <0 20>, <1 50>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-pan-physical-width-dimension = <63>; + qcom,mdss-pan-physical-height-dimension = <112>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi index d6d85fa7fdea..1f19e209ee12 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi @@ -141,6 +141,12 @@ qcom,panel-roi-alignment = <2 2 2 2 2 2>; }; +&dsi_icn9706_720_1440_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; +}; + &tlmm { tlmm_gpio_key { gpio_key_active: gpio_key_active { diff --git a/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi index ef4f4b09c451..528e8aa3025e 100644 --- a/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi @@ -25,6 +25,8 @@ #include "dsi-panel-hx8399c-hd-plus-video.dtsi" #include "dsi-panel-nt35695b-truly-fhd-video.dtsi" #include "dsi-panel-nt35695b-truly-fhd-cmd.dtsi" +#include "dsi-panel-icn9706-720-1440p-video.dtsi" + &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { #address-cells = <1>; -- GitLab From 36c6512ecdc28e18befec67802af4ed075772112 Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Wed, 18 Apr 2018 21:04:46 +0530 Subject: [PATCH 571/855] Enable hardware based FBE on f2fs and adapt ext4 fs Hardware File Based Encryption (FBE) uses crypto engine to encrypt the user data with unique key for each file. File name and data both are encrypted with this feature. 1. security/pfk: changes to support per file encryption for f2fs using hardware crypto engine. 2. fs/ext4: adapted crypto APIs for generic crypto layer. 3. fs/f2fs: support hardware crypto engine based per file encryption. 4. fs/crypto: export APIs to support hardware crypto engine based per file encryption. Other changes made to provide support framework for per file encryption. Change-Id: I7981fa7f8f0c4bc058b80b7b8e342cfd81697c74 Signed-off-by: Neeraj Soni --- block/bio.c | 10 ++ block/blk-merge.c | 2 +- block/elevator.c | 5 +- drivers/scsi/scsi_lib.c | 2 + drivers/scsi/ufs/ufs-qcom.c | 19 ++- fs/crypto/Makefile | 4 +- fs/crypto/bio.c | 2 +- fs/crypto/fscrypt_ice.c | 146 +++++++++++++++++++++++ fs/crypto/fscrypt_ice.h | 106 +++++++++++++++++ fs/crypto/fscrypt_private.h | 20 +++- fs/crypto/keyinfo.c | 170 ++++++++++++--------------- fs/ext4/Makefile | 1 - fs/ext4/ext4_ice.c | 109 ----------------- fs/ext4/ext4_ice.h | 108 ----------------- fs/ext4/inode.c | 18 +-- fs/ext4/page-io.c | 4 +- fs/ext4/super.c | 6 + fs/f2fs/data.c | 37 +++++- fs/f2fs/f2fs.h | 13 ++- fs/f2fs/super.c | 6 + include/linux/bio.h | 8 ++ include/linux/blk_types.h | 4 + include/linux/blkdev.h | 3 + include/linux/bvec.h | 1 + include/linux/fscrypt.h | 8 ++ include/linux/fscrypt_notsupp.h | 15 +++ include/linux/fscrypt_supp.h | 12 +- include/linux/pfk.h | 13 +++ include/scsi/scsi_host.h | 3 + security/pfe/Makefile | 4 +- security/pfe/pfk.c | 162 +++++++++++++++++--------- security/pfe/pfk_ext4.c | 17 +-- security/pfe/pfk_f2fs.c | 200 ++++++++++++++++++++++++++++++++ security/pfe/pfk_f2fs.h | 37 ++++++ security/pfe/pfk_kc.c | 3 +- 35 files changed, 865 insertions(+), 413 deletions(-) create mode 100644 fs/crypto/fscrypt_ice.c create mode 100644 fs/crypto/fscrypt_ice.h delete mode 100644 fs/ext4/ext4_ice.c delete mode 100644 fs/ext4/ext4_ice.h create mode 100644 security/pfe/pfk_f2fs.c create mode 100644 security/pfe/pfk_f2fs.h diff --git a/block/bio.c b/block/bio.c index 4d938110a518..91b64620ac53 100644 --- a/block/bio.c +++ b/block/bio.c @@ -565,6 +565,15 @@ inline int bio_phys_segments(struct request_queue *q, struct bio *bio) } EXPORT_SYMBOL(bio_phys_segments); +static inline void bio_clone_crypt_key(struct bio *dst, const struct bio *src) +{ +#ifdef CONFIG_PFK + dst->bi_crypt_key = src->bi_crypt_key; + dst->bi_iter.bi_dun = src->bi_iter.bi_dun; +#endif + dst->bi_dio_inode = src->bi_dio_inode; +} + /** * __bio_clone_fast - clone a bio that shares the original bio's biovec * @bio: destination bio @@ -590,6 +599,7 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src) bio->bi_iter = bio_src->bi_iter; bio->bi_io_vec = bio_src->bi_io_vec; bio->bi_dio_inode = bio_src->bi_dio_inode; + bio_clone_crypt_key(bio, bio_src); bio_clone_blkcg_association(bio, bio_src); } EXPORT_SYMBOL(__bio_clone_fast); diff --git a/block/blk-merge.c b/block/blk-merge.c index 0272face5199..f44daa1925d4 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -8,7 +8,7 @@ #include #include #include - +#include #include "blk.h" static struct bio *blk_bio_discard_split(struct request_queue *q, diff --git a/block/elevator.c b/block/elevator.c index f7d973a56fd7..6dd2ca473b03 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -425,7 +425,10 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio) /* * First try one-hit cache. */ - if (q->last_merge && elv_bio_merge_ok(q->last_merge, bio)) { + if (q->last_merge) { + if (!elv_bio_merge_ok(q->last_merge, bio)) + return ELEVATOR_NO_MERGE; + ret = blk_try_merge(q->last_merge, bio); if (ret != ELEVATOR_NO_MERGE) { *req = q->last_merge; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 57a3ee099c3d..3ccc858318fe 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2044,6 +2044,8 @@ static void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) if (!shost->use_clustering) q->limits.cluster = 0; + if (shost->inlinecrypt_support) + queue_flag_set_unlocked(QUEUE_FLAG_INLINECRYPT, q); /* * Set a reasonable default alignment: The larger of 32-byte (dword), * which is a common minimum for HBAs, and the minimum DMA alignment, diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 39ab28aa32e9..8d867a203c74 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -897,11 +897,18 @@ static int ufs_qcom_crypto_req_setup(struct ufs_hba *hba, req = lrbp->cmd->request; else return 0; - - /* Use request LBA as the DUN value */ - if (req->bio) - *dun = (req->bio->bi_iter.bi_sector) >> - UFS_QCOM_ICE_TR_DATA_UNIT_4_KB; + /* + * Right now ICE do not support variable dun but can be + * taken as future enhancement + * if (bio_dun(req->bio)) { + * dun @bio can be split, so we have to adjust offset + * *dun = bio_dun(req->bio); + * } else + */ + if (req->bio) { + *dun = req->bio->bi_iter.bi_sector; + *dun >>= UFS_QCOM_ICE_TR_DATA_UNIT_4_KB; + } ret = ufs_qcom_ice_req_setup(host, lrbp->cmd, cc_index, enable); @@ -2133,6 +2140,8 @@ static int ufs_qcom_init(struct ufs_hba *hba) dev_err(dev, "%s: ufs_qcom_ice_get_dev failed %d\n", __func__, err); goto out_host_free; + } else { + hba->host->inlinecrypt_support = 1; } host->generic_phy = devm_phy_get(dev, "ufsphy"); diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile index a35f058cd6f5..cc42e5e29472 100644 --- a/fs/crypto/Makefile +++ b/fs/crypto/Makefile @@ -1,5 +1,7 @@ obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o ccflags-y += -Ifs/ext4 -fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o +ccflags-y += -Ifs/f2fs + +fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o fscrypt_ice.o fscrypto-$(CONFIG_BLOCK) += bio.o diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index 205e92806876..c629e9756ffe 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -33,7 +33,7 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done) bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; - if (fs_is_ice_enabled()) { + if (fscrypt_using_hardware_encryption(page->mapping->host)) { SetPageUptodate(page); } else { int ret = fscrypt_decrypt_page(page->mapping->host, diff --git a/fs/crypto/fscrypt_ice.c b/fs/crypto/fscrypt_ice.c new file mode 100644 index 000000000000..62dae83cf732 --- /dev/null +++ b/fs/crypto/fscrypt_ice.c @@ -0,0 +1,146 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "fscrypt_ice.h" + +int fscrypt_using_hardware_encryption(const struct inode *inode) +{ + struct fscrypt_info *ci = inode->i_crypt_info; + + return S_ISREG(inode->i_mode) && ci && + ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; +} +EXPORT_SYMBOL(fscrypt_using_hardware_encryption); + +/* + * Retrieves encryption key from the inode + */ +char *fscrypt_get_ice_encryption_key(const struct inode *inode) +{ + struct fscrypt_info *ci = NULL; + + if (!inode) + return NULL; + + ci = inode->i_crypt_info; + if (!ci) + return NULL; + + return &(ci->ci_raw_key[0]); +} + +/* + * Retrieves encryption salt from the inode + */ +char *fscrypt_get_ice_encryption_salt(const struct inode *inode) +{ + struct fscrypt_info *ci = NULL; + + if (!inode) + return NULL; + + ci = inode->i_crypt_info; + if (!ci) + return NULL; + + return &(ci->ci_raw_key[fscrypt_get_ice_encryption_key_size(inode)]); +} + +/* + * returns true if the cipher mode in inode is AES XTS + */ +int fscrypt_is_aes_xts_cipher(const struct inode *inode) +{ + struct fscrypt_info *ci = inode->i_crypt_info; + + if (!ci) + return 0; + + return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE); +} + +/* + * returns true if encryption info in both inodes is equal + */ +bool fscrypt_is_ice_encryption_info_equal(const struct inode *inode1, + const struct inode *inode2) +{ + char *key1 = NULL; + char *key2 = NULL; + char *salt1 = NULL; + char *salt2 = NULL; + + if (!inode1 || !inode2) + return false; + + if (inode1 == inode2) + return true; + + /* both do not belong to ice, so we don't care, they are equal + *for us + */ + if (!fscrypt_should_be_processed_by_ice(inode1) && + !fscrypt_should_be_processed_by_ice(inode2)) + return true; + + /* one belongs to ice, the other does not -> not equal */ + if (fscrypt_should_be_processed_by_ice(inode1) ^ + fscrypt_should_be_processed_by_ice(inode2)) + return false; + + key1 = fscrypt_get_ice_encryption_key(inode1); + key2 = fscrypt_get_ice_encryption_key(inode2); + salt1 = fscrypt_get_ice_encryption_salt(inode1); + salt2 = fscrypt_get_ice_encryption_salt(inode2); + + /* key and salt should not be null by this point */ + if (!key1 || !key2 || !salt1 || !salt2 || + (fscrypt_get_ice_encryption_key_size(inode1) != + fscrypt_get_ice_encryption_key_size(inode2)) || + (fscrypt_get_ice_encryption_salt_size(inode1) != + fscrypt_get_ice_encryption_salt_size(inode2))) + return false; + + if ((memcmp(key1, key2, + fscrypt_get_ice_encryption_key_size(inode1)) == 0) && + (memcmp(salt1, salt2, + fscrypt_get_ice_encryption_salt_size(inode1)) == 0)) + return true; + + return false; +} + +void fscrypt_set_ice_dun(const struct inode *inode, struct bio *bio, u64 dun) +{ + if (fscrypt_should_be_processed_by_ice(inode)) + bio->bi_iter.bi_dun = dun; +} +EXPORT_SYMBOL(fscrypt_set_ice_dun); + +/* + * This function will be used for filesystem when deciding to merge bios. + * Basic assumption is, if inline_encryption is set, single bio has to + * guarantee consecutive LBAs as well as ino|pg->index. + */ +bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted) +{ + if (!bio) + return true; + + /* if both of them are not encrypted, no further check is needed */ + if (!bio_dun(bio) && !bio_encrypted) + return true; + + /* ICE allows only consecutive iv_key stream. */ + return bio_end_dun(bio) == dun; +} +EXPORT_SYMBOL(fscrypt_mergeable_bio); diff --git a/fs/crypto/fscrypt_ice.h b/fs/crypto/fscrypt_ice.h new file mode 100644 index 000000000000..c5405060b5b1 --- /dev/null +++ b/fs/crypto/fscrypt_ice.h @@ -0,0 +1,106 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _FSCRYPT_ICE_H +#define _FSCRYPT_ICE_H + +#include +#include "fscrypt_private.h" + +#if IS_ENABLED(CONFIG_FS_ENCRYPTION) +static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode) +{ + if (!inode->i_sb->s_cop) + return 0; + if (!inode->i_sb->s_cop->is_encrypted((struct inode *)inode)) + return 0; + + return fscrypt_using_hardware_encryption(inode); +} + +static inline int fscrypt_is_ice_capable(const struct super_block *sb) +{ + return blk_queue_inlinecrypt(bdev_get_queue(sb->s_bdev)); +} + +int fscrypt_is_aes_xts_cipher(const struct inode *inode); + +char *fscrypt_get_ice_encryption_key(const struct inode *inode); +char *fscrypt_get_ice_encryption_salt(const struct inode *inode); + +bool fscrypt_is_ice_encryption_info_equal(const struct inode *inode1, + const struct inode *inode2); + +static inline size_t fscrypt_get_ice_encryption_key_size( + const struct inode *inode) +{ + return FS_AES_256_XTS_KEY_SIZE / 2; +} + +static inline size_t fscrypt_get_ice_encryption_salt_size( + const struct inode *inode) +{ + return FS_AES_256_XTS_KEY_SIZE / 2; +} +#else +static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode) +{ + return 0; +} + +static inline int fscrypt_is_ice_capable(const struct super_block *sb) +{ + return 0; +} + +static inline char *fscrypt_get_ice_encryption_key(const struct inode *inode) +{ + return NULL; +} + +static inline char *fscrypt_get_ice_encryption_salt(const struct inode *inode) +{ + return NULL; +} + +static inline size_t fscrypt_get_ice_encryption_key_size( + const struct inode *inode) +{ + return 0; +} + +static inline size_t fscrypt_get_ice_encryption_salt_size( + const struct inode *inode) +{ + return 0; +} + +static inline int fscrypt_is_xts_cipher(const struct inode *inode) +{ + return 0; +} + +static inline bool fscrypt_is_ice_encryption_info_equal( + const struct inode *inode1, + const struct inode *inode2) +{ + return 0; +} + +static inline int fscrypt_is_aes_xts_cipher(const struct inode *inode) +{ + return 0; +} + +#endif + +#endif /* _FSCRYPT_ICE_H */ diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 3e72d65e8a80..8f73c1db8929 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -11,9 +11,12 @@ #ifndef _FSCRYPT_PRIVATE_H #define _FSCRYPT_PRIVATE_H +#ifndef __FS_HAS_ENCRYPTION #define __FS_HAS_ENCRYPTION 1 +#endif #include #include +#include /* Encryption parameters */ #define FS_IV_SIZE 16 @@ -58,11 +61,18 @@ struct fscrypt_symlink_data { char encrypted_path[1]; } __packed; +enum ci_mode_info { + CI_NONE_MODE = 0, + CI_DATA_MODE, + CI_FNAME_MODE, +}; + /* * A pointer to this structure is stored in the file system's in-core * representation of an inode. */ struct fscrypt_info { + u8 ci_mode; u8 ci_data_mode; u8 ci_filename_mode; u8 ci_flags; @@ -97,6 +107,12 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode, return false; } +static inline bool is_private_data_mode(struct fscrypt_info *ci) +{ + return ci->ci_mode == CI_DATA_MODE && + ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; +} + /* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep; extern int fscrypt_initialize(unsigned int cop_flags); @@ -116,10 +132,6 @@ extern bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, u32 max_len, u32 *encrypted_len_ret); -static inline int fs_is_ice_enabled(void) -{ - return 1; -} /* keyinfo.c */ extern void __exit fscrypt_essiv_cleanup(void); diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index dcd00d5fe62c..d8478e7e0cb7 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -15,6 +15,7 @@ #include #include #include "fscrypt_private.h" +#include "fscrypt_ice.h" static struct crypto_shash *essiv_hash_tfm; @@ -67,7 +68,7 @@ static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE], } static int validate_user_key(struct fscrypt_info *crypt_info, - struct fscrypt_context *ctx, u8 *raw_key, + struct fscrypt_context *ctx, const char *prefix, int min_keysize) { char *description; @@ -115,7 +116,24 @@ static int validate_user_key(struct fscrypt_info *crypt_info, res = -ENOKEY; goto out; } - res = derive_key_aes(ctx->nonce, master_key, raw_key); + res = derive_key_aes(ctx->nonce, master_key, crypt_info->ci_raw_key); + /* If we don't need to derive, we still want to do everything + * up until now to validate the key. It's cleaner to fail now + * than to fail in block I/O. + if (!is_private_data_mode(crypt_info)) { + res = derive_key_aes(ctx->nonce, master_key, + crypt_info->ci_raw_key); + } else { + * Inline encryption: no key derivation required because IVs are + * assigned based on iv_sector. + + BUILD_BUG_ON(sizeof(crypt_info->ci_raw_key) != + sizeof(master_key->raw)); + memcpy(crypt_info->ci_raw_key, + master_key->raw, sizeof(crypt_info->ci_raw_key)); + res = 0; + } + */ out: up_read(&keyring_key->sem); key_put(keyring_key); @@ -151,8 +169,10 @@ static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode, } if (S_ISREG(inode->i_mode)) { + ci->ci_mode = CI_DATA_MODE; mode = ci->ci_data_mode; } else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { + ci->ci_mode = CI_FNAME_MODE; mode = ci->ci_filename_mode; *fname = 1; } else { @@ -173,7 +193,7 @@ static void put_crypt_info(struct fscrypt_info *ci) crypto_free_skcipher(ci->ci_ctfm); crypto_free_cipher(ci->ci_essiv_tfm); - memzero_explicit(ci->ci_raw_key, sizeof(ci->ci_raw_key)); + memset(ci, 0, sizeof(*ci)); /* sanitizes ->ci_raw_key */ kmem_cache_free(fscrypt_info_cachep, ci); } @@ -243,21 +263,12 @@ void __exit fscrypt_essiv_cleanup(void) crypto_free_shash(essiv_hash_tfm); } -static int fs_data_encryption_mode(void) +static int fscrypt_data_encryption_mode(struct inode *inode) { - return fs_is_ice_enabled() ? FS_ENCRYPTION_MODE_PRIVATE : - FS_ENCRYPTION_MODE_AES_256_XTS; + return fscrypt_should_be_processed_by_ice(inode) ? + FS_ENCRYPTION_MODE_PRIVATE : FS_ENCRYPTION_MODE_AES_256_XTS; } -int fs_using_hardware_encryption(struct inode *inode) -{ - struct fscrypt_info *ci = inode->i_crypt_info; - - return S_ISREG(inode->i_mode) && ci && - ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; -} -EXPORT_SYMBOL(fs_using_hardware_encryption); - int fscrypt_get_encryption_info(struct inode *inode) { struct fscrypt_info *crypt_info; @@ -283,7 +294,8 @@ int fscrypt_get_encryption_info(struct inode *inode) /* Fake up a context for an unencrypted directory */ memset(&ctx, 0, sizeof(ctx)); ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; - ctx.contents_encryption_mode = fs_data_encryption_mode(); + ctx.contents_encryption_mode = + fscrypt_data_encryption_mode(inode); ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE); } else if (res != sizeof(ctx)) { @@ -319,55 +331,65 @@ int fscrypt_get_encryption_info(struct inode *inode) */ res = -ENOMEM; - res = validate_user_key(crypt_info, &ctx, crypt_info->ci_raw_key, - FS_KEY_DESC_PREFIX, keysize); + res = validate_user_key(crypt_info, &ctx, FS_KEY_DESC_PREFIX, + keysize); if (res && inode->i_sb->s_cop->key_prefix) { int res2 = validate_user_key(crypt_info, &ctx, - crypt_info->ci_raw_key, - inode->i_sb->s_cop->key_prefix, keysize); + inode->i_sb->s_cop->key_prefix, + keysize); if (res2) { if (res2 == -ENOKEY) res = -ENOKEY; goto out; } + res = 0; } else if (res) { goto out; } - if (crypt_info->ci_data_mode != FS_ENCRYPTION_MODE_PRIVATE || fname) { - ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); - if (!ctfm || IS_ERR(ctfm)) { - res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; - pr_debug("%s: error %d (inode %lu) allocating crypto tfm\n", - __func__, res, inode->i_ino); + + if (is_private_data_mode(crypt_info)) { + if (!fscrypt_is_ice_capable(inode->i_sb)) { + pr_warn("%s: ICE support not available\n", + __func__); + res = -EINVAL; goto out; } - crypt_info->ci_ctfm = ctfm; - crypto_skcipher_clear_flags(ctfm, ~0); - crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); - /* - * if the provided key is longer than keysize, we use the first - * keysize bytes of the derived key only - */ - res = crypto_skcipher_setkey(ctfm, - crypt_info->ci_raw_key, keysize); - if (res) - goto out; + /* Let's encrypt/decrypt by ICE */ + goto do_ice; + } - if (S_ISREG(inode->i_mode) && crypt_info->ci_data_mode == - FS_ENCRYPTION_MODE_AES_128_CBC) { - res = init_essiv_generator(crypt_info, - crypt_info->ci_raw_key, keysize); - if (res) { - pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n", - __func__, res, inode->i_ino); - goto out; - } - } - } else if (!fs_is_ice_enabled()) { - pr_warn("%s: ICE support not available\n", __func__); - res = -EINVAL; + + ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); + if (!ctfm || IS_ERR(ctfm)) { + res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; + pr_debug("%s: error %d (inode %lu) allocating crypto tfm\n", + __func__, res, inode->i_ino); goto out; } + crypt_info->ci_ctfm = ctfm; + crypto_skcipher_clear_flags(ctfm, ~0); + crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); + /* + * if the provided key is longer than keysize, we use the first + * keysize bytes of the derived key only + */ + res = crypto_skcipher_setkey(ctfm, crypt_info->ci_raw_key, keysize); + if (res) + goto out; + + if (S_ISREG(inode->i_mode) && + crypt_info->ci_data_mode == FS_ENCRYPTION_MODE_AES_128_CBC) { + res = init_essiv_generator(crypt_info, crypt_info->ci_raw_key, + keysize); + if (res) { + pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n", + __func__, res, inode->i_ino); + goto out; + } + } + memzero_explicit(crypt_info->ci_raw_key, + sizeof(crypt_info->ci_raw_key)); +do_ice: if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL) crypt_info = NULL; out: @@ -384,51 +406,3 @@ void fscrypt_put_encryption_info(struct inode *inode) inode->i_crypt_info = NULL; } EXPORT_SYMBOL(fscrypt_put_encryption_info); - -char *fscrypt_get_ice_encryption_key(const struct inode *inode) -{ - struct fscrypt_info *ci; - - if (!inode) - return NULL; - - ci = inode->i_crypt_info; - if (!ci) - return NULL; - - return &(ci->ci_raw_key[0]); -} -EXPORT_SYMBOL(fscrypt_get_ice_encryption_key); - -/* - * Retrieves encryption salt from the inode - */ -char *fscrypt_get_ice_encryption_salt(const struct inode *inode) -{ - struct fscrypt_info *ci; - - if (!inode) - return NULL; - - ci = inode->i_crypt_info; - if (!ci) - return NULL; - - return &(ci->ci_raw_key[FS_AES_256_XTS_KEY_SIZE / 2]); -} -EXPORT_SYMBOL(fscrypt_get_ice_encryption_salt); - -/* - * returns true if the cipher mode in inode is AES XTS - */ -int fscrypt_is_aes_xts_cipher(const struct inode *inode) -{ - struct fscrypt_info *ci; - - ci = inode->i_crypt_info; - if (!ci) - return 0; - - return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE); -} -EXPORT_SYMBOL(fscrypt_is_aes_xts_cipher); diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index d9e563a914ad..b9dfa0d47b42 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -13,4 +13,3 @@ ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \ ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o -ext4-$(CONFIG_EXT4_FS_ICE_ENCRYPTION) += ext4_ice.o diff --git a/fs/ext4/ext4_ice.c b/fs/ext4/ext4_ice.c deleted file mode 100644 index 802df3699810..000000000000 --- a/fs/ext4/ext4_ice.c +++ /dev/null @@ -1,109 +0,0 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "ext4_ice.h" -#include - -/* - * Retrieves encryption key from the inode - */ -char *ext4_get_ice_encryption_key(const struct inode *inode) -{ - /* - * struct fscrypt_info *ci; - * if (!inode) - * return NULL; - * ci = inode->i_crypt_info; - * if (!ci) - * return NULL; - * return &(ci->ci_raw_key[0]); - */ - return fscrypt_get_ice_encryption_key(inode); -} - -/* - * Retrieves encryption salt from the inode - */ -char *ext4_get_ice_encryption_salt(const struct inode *inode) -{ - /* - * struct fscrypt_info *ci; - * if (!inode) - * return NULL; - * ci = inode->i_crypt_info; - * if (!ci) - * return NULL; - * return &(ci->ci_raw_key[ext4_get_ice_encryption_key_size(inode)]); - */ - return fscrypt_get_ice_encryption_salt(inode); -} - -/* - * returns true if the cipher mode in inode is AES XTS - */ -int ext4_is_aes_xts_cipher(const struct inode *inode) -{ - /* - * struct fscrypt_info *ci; - * ci = inode->i_crypt_info; - * if (!ci) - * return 0; - * return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE); - */ - return fscrypt_is_aes_xts_cipher(inode); -} - -/* - * returns true if encryption info in both inodes is equal - */ -int ext4_is_ice_encryption_info_equal(const struct inode *inode1, - const struct inode *inode2) -{ - char *key1 = NULL; - char *key2 = NULL; - char *salt1 = NULL; - char *salt2 = NULL; - - if (!inode1 || !inode2) - return 0; - - if (inode1 == inode2) - return 1; - - /* both do not belong to ice, so we don't care, they are equal for us */ - if (!ext4_should_be_processed_by_ice(inode1) && - !ext4_should_be_processed_by_ice(inode2)) - return 1; - - /* one belongs to ice, the other does not -> not equal */ - if (ext4_should_be_processed_by_ice(inode1) ^ - ext4_should_be_processed_by_ice(inode2)) - return 0; - - key1 = ext4_get_ice_encryption_key(inode1); - key2 = ext4_get_ice_encryption_key(inode2); - salt1 = ext4_get_ice_encryption_salt(inode1); - salt2 = ext4_get_ice_encryption_salt(inode2); - - /* key and salt should not be null by this point */ - if (!key1 || !key2 || !salt1 || !salt2 || - (ext4_get_ice_encryption_key_size(inode1) != - ext4_get_ice_encryption_key_size(inode2)) || - (ext4_get_ice_encryption_salt_size(inode1) != - ext4_get_ice_encryption_salt_size(inode2))) - return 0; - - return ((memcmp(key1, key2, - ext4_get_ice_encryption_key_size(inode1)) == 0) && - (memcmp(salt1, salt2, - ext4_get_ice_encryption_salt_size(inode1)) == 0)); -} diff --git a/fs/ext4/ext4_ice.h b/fs/ext4/ext4_ice.h deleted file mode 100644 index 8cf4d2e607c9..000000000000 --- a/fs/ext4/ext4_ice.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _EXT4_ICE_H -#define _EXT4_ICE_H - -#include "ext4.h" -#define EXT4_256_XTS_KEY_SIZE 64 - -#ifdef CONFIG_EXT4_FS_ICE_ENCRYPTION -static inline int ext4_should_be_processed_by_ice(const struct inode *inode) -{ - if (!ext4_encrypted_inode((struct inode *)inode)) - return 0; - - return fs_using_hardware_encryption((struct inode *)inode); -} - -static inline int ext4_is_ice_enabled(void) -{ - return 1; -} - -int ext4_is_aes_xts_cipher(const struct inode *inode); - -char *ext4_get_ice_encryption_key(const struct inode *inode); -char *ext4_get_ice_encryption_salt(const struct inode *inode); - -int ext4_is_ice_encryption_info_equal(const struct inode *inode1, - const struct inode *inode2); - -static inline size_t ext4_get_ice_encryption_key_size( - const struct inode *inode) -{ - return EXT4_256_XTS_KEY_SIZE / 2; -} - -static inline size_t ext4_get_ice_encryption_salt_size( - const struct inode *inode) -{ - return EXT4_256_XTS_KEY_SIZE / 2; -} - -#else -static inline int ext4_should_be_processed_by_ice(const struct inode *inode) -{ - return 0; -} -static inline int ext4_is_ice_enabled(void) -{ - return 0; -} - -static inline char *ext4_get_ice_encryption_key(const struct inode *inode) -{ - return NULL; -} - -static inline char *ext4_get_ice_encryption_salt(const struct inode *inode) -{ - return NULL; -} - -static inline size_t ext4_get_ice_encryption_key_size( - const struct inode *inode) -{ - return 0; -} - -static inline size_t ext4_get_ice_encryption_salt_size( - const struct inode *inode) -{ - return 0; -} - -static inline int ext4_is_xts_cipher(const struct inode *inode) -{ - return 0; -} - -static inline int ext4_is_ice_encryption_info_equal( - const struct inode *inode1, - const struct inode *inode2) -{ - return 0; -} - -static inline int ext4_is_aes_xts_cipher(const struct inode *inode) -{ - return 0; -} - -static int fs_using_hardware_encryption(struct inode *inode) -{ - return -EOPNOTSUPP; -} -#endif - -#endif /* _EXT4_ICE_H */ diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 3d89b98c8b37..ecee29a3cf82 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -42,7 +42,7 @@ #include "xattr.h" #include "acl.h" #include "truncate.h" -#include "ext4_ice.h" +//#include "ext4_ice.h" #include #include @@ -1154,7 +1154,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, *wait_bh++ = bh; decrypt = ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) && - !ext4_is_ice_enabled(); + !fscrypt_using_hardware_encryption(inode); } } /* @@ -3511,9 +3511,9 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) get_block_func = ext4_dio_get_block_unwritten_async; dio_flags = DIO_LOCKING; } -#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \ -!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION) - BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)); +#if defined(CONFIG_EXT4_FS_ENCRYPTION) + WARN_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) + && !fscrypt_using_hardware_encryption(inode)); #endif if (IS_DAX(inode)) { ret = dax_do_io(iocb, inode, iter, get_block_func, @@ -3634,9 +3634,9 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ssize_t ret; int rw = iov_iter_rw(iter); -#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \ -!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION) - if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) +#if defined(CONFIG_EXT4_FS_ENCRYPTION) + if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) + && !fscrypt_using_hardware_encryption(inode)) return 0; #endif @@ -3833,7 +3833,7 @@ static int __ext4_block_zero_page_range(handle_t *handle, goto unlock; if (S_ISREG(inode->i_mode) && ext4_encrypted_inode(inode) && - !fs_using_hardware_encryption(inode)) { + !fscrypt_using_hardware_encryption(inode)) { /* We expect the key to be set. */ BUG_ON(!fscrypt_has_encryption_key(inode)); BUG_ON(blocksize != PAGE_SIZE); diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index a9dc6723b9db..8d4ec1abd01f 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -28,7 +28,7 @@ #include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" -#include "ext4_ice.h" +//#include "ext4_ice.h" static struct kmem_cache *io_end_cachep; @@ -470,7 +470,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io, gfp_t gfp_flags = GFP_NOFS; retry_encrypt: - if (!fs_using_hardware_encryption(inode)) + if (!fscrypt_using_hardware_encryption(inode)) data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, 0, page->index, gfp_flags); if (IS_ERR(data_page)) { diff --git a/fs/ext4/super.c b/fs/ext4/super.c index e95b6e117477..23c571662f08 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1180,6 +1180,11 @@ static unsigned ext4_max_namelen(struct inode *inode) EXT4_NAME_LEN; } +static inline bool ext4_is_encrypted(struct inode *inode) +{ + return ext4_encrypted_inode(inode); +} + static const struct fscrypt_operations ext4_cryptops = { .key_prefix = "ext4:", .get_context = ext4_get_context, @@ -1187,6 +1192,7 @@ static const struct fscrypt_operations ext4_cryptops = { .dummy_context = ext4_dummy_context, .empty_dir = ext4_empty_dir, .max_namelen = ext4_max_namelen, + .is_encrypted = ext4_is_encrypted, }; #endif diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index b1fd4e2f63a5..66b069ba32eb 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -437,6 +437,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) struct bio *bio; struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page; + struct inode *inode = fio->page->mapping->host; verify_block_addr(fio, fio->new_blkaddr); trace_f2fs_submit_page_bio(page, fio); @@ -446,6 +447,9 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc, 1, is_read_io(fio->op), fio->type, fio->temp); + if (f2fs_may_encrypt_bio(inode, fio)) + fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, fio->page)); + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); return -EFAULT; @@ -465,6 +469,9 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) enum page_type btype = PAGE_TYPE_OF_BIO(fio->type); struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp; struct page *bio_page; + struct inode *inode; + bool bio_encrypted; + u64 dun; int err = 0; f2fs_bug_on(sbi, is_read_io(fio->op)); @@ -488,6 +495,9 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) verify_block_addr(fio, fio->new_blkaddr); bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page; + inode = fio->page->mapping->host; + dun = PG_DUN(inode, fio->page); + bio_encrypted = f2fs_may_encrypt_bio(inode, fio); /* set submitted = true as a return value */ fio->submitted = true; @@ -498,6 +508,11 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) (io->fio.op != fio->op || io->fio.op_flags != fio->op_flags) || !__same_bdev(sbi, fio->new_blkaddr, io->bio))) __submit_merged_bio(io); + + /* ICE support */ + if (!fscrypt_mergeable_bio(io->bio, dun, bio_encrypted)) + __submit_merged_bio(io); + alloc_new: if (io->bio == NULL) { if ((fio->type == DATA || fio->type == NODE) && @@ -509,6 +524,9 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc, BIO_MAX_PAGES, false, fio->type, fio->temp); + if (bio_encrypted) + fscrypt_set_ice_dun(inode, io->bio, dun); + io->fio = *fio; } @@ -575,6 +593,9 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page, if (IS_ERR(bio)) return PTR_ERR(bio); + if (f2fs_may_encrypt_bio(inode, NULL)) + fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, page)); + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); return -EFAULT; @@ -1434,6 +1455,8 @@ static int f2fs_mpage_readpages(struct address_space *mapping, sector_t last_block_in_file; sector_t block_nr; struct f2fs_map_blocks map; + bool bio_encrypted; + u64 dun; map.m_pblk = 0; map.m_lblk = 0; @@ -1511,6 +1534,14 @@ static int f2fs_mpage_readpages(struct address_space *mapping, __submit_bio(F2FS_I_SB(inode), bio, DATA); bio = NULL; } + + dun = PG_DUN(inode, page); + bio_encrypted = f2fs_may_encrypt_bio(inode, NULL); + if (!fscrypt_mergeable_bio(bio, dun, bio_encrypted)) { + __submit_bio(F2FS_I_SB(inode), bio, DATA); + bio = NULL; + } + if (bio == NULL) { bio = f2fs_grab_read_bio(inode, block_nr, nr_pages); if (IS_ERR(bio)) { @@ -1518,7 +1549,8 @@ static int f2fs_mpage_readpages(struct address_space *mapping, goto set_error_page; } } - + if (bio_encrypted) + fscrypt_set_ice_dun(inode, bio, dun); if (bio_add_page(bio, page, blocksize, 0) < blocksize) goto submit_and_realloc; @@ -1588,6 +1620,9 @@ static int encrypt_one_page(struct f2fs_io_info *fio) f2fs_wait_on_block_writeback(fio->sbi, fio->old_blkaddr); retry_encrypt: + if (fscrypt_using_hardware_encryption(inode)) + return 0; + fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page, PAGE_SIZE, 0, fio->page->index, gfp_flags); if (!IS_ERR(fio->encrypted_page)) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 84be1e7db9b6..c65b697b37f5 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3321,9 +3321,20 @@ static inline bool f2fs_may_encrypt(struct inode *inode) static inline bool f2fs_force_buffered_io(struct inode *inode, int rw) { - return (f2fs_post_read_required(inode) || + return ((f2fs_post_read_required(inode) && + !fscrypt_using_hardware_encryption(inode)) || (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) || F2FS_I_SB(inode)->s_ndevs); } +static inline bool f2fs_may_encrypt_bio(struct inode *inode, + struct f2fs_io_info *fio) +{ + if (fio && (fio->type != DATA || fio->encrypted_page)) + return false; + + return (f2fs_encrypted_file(inode) && + fscrypt_using_hardware_encryption(inode)); +} + #endif diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 7d4621a8a5e7..771b039ba83b 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1936,6 +1936,11 @@ static unsigned f2fs_max_namelen(struct inode *inode) inode->i_sb->s_blocksize : F2FS_NAME_LEN; } +static inline bool f2fs_is_encrypted(struct inode *inode) +{ + return f2fs_encrypted_file(inode); +} + static const struct fscrypt_operations f2fs_cryptops = { .key_prefix = "f2fs:", .get_context = f2fs_get_context, @@ -1943,6 +1948,7 @@ static const struct fscrypt_operations f2fs_cryptops = { .dummy_context = f2fs_dummy_context, .empty_dir = f2fs_empty_dir, .max_namelen = f2fs_max_namelen, + .is_encrypted = f2fs_is_encrypted, }; #endif diff --git a/include/linux/bio.h b/include/linux/bio.h index 97cb48f03dc7..0885c9ff8ba8 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -61,6 +61,9 @@ ((bio)->bi_iter.bi_size != bio_iovec(bio).bv_len) #define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) #define bio_end_sector(bio) ((bio)->bi_iter.bi_sector + bio_sectors((bio))) +#define bio_dun(bio) ((bio)->bi_iter.bi_dun) +#define bio_duns(bio) (bio_sectors(bio) >> 3) /* 4KB unit */ +#define bio_end_dun(bio) (bio_dun(bio) + bio_duns(bio)) /* * Check whether this bio carries any data or not. A NULL bio is allowed. @@ -169,6 +172,11 @@ static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, { iter->bi_sector += bytes >> 9; +#ifdef CONFIG_PFK + if (iter->bi_dun) + iter->bi_dun += bytes >> 12; +#endif + if (bio_no_advance_iter(bio)) iter->bi_size -= bytes; else diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 4115fa430be3..5a3712ce0112 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -66,6 +66,10 @@ struct bio { struct bio_integrity_payload *bi_integrity; /* data integrity */ #endif }; +#ifdef CONFIG_PFK + /* Encryption key to use (NULL if none) */ + const struct blk_encryption_key *bi_crypt_key; +#endif unsigned short bi_vcnt; /* how many bio_vec's */ diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index b0f981a96fbb..661dcec43adb 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -509,6 +509,7 @@ struct request_queue { #define QUEUE_FLAG_FLUSH_NQ 25 /* flush not queueuable */ #define QUEUE_FLAG_DAX 26 /* device supports DAX */ #define QUEUE_FLAG_FAST 27 /* fast block device (e.g. ram based) */ +#define QUEUE_FLAG_INLINECRYPT 28 /* inline encryption support */ #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ (1 << QUEUE_FLAG_STACKABLE) | \ @@ -600,6 +601,8 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) (test_bit(QUEUE_FLAG_SECERASE, &(q)->queue_flags)) #define blk_queue_dax(q) test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags) #define blk_queue_fast(q) test_bit(QUEUE_FLAG_FAST, &(q)->queue_flags) +#define blk_queue_inlinecrypt(q) \ + test_bit(QUEUE_FLAG_INLINECRYPT, &(q)->queue_flags) #define blk_noretry_request(rq) \ ((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \ diff --git a/include/linux/bvec.h b/include/linux/bvec.h index 89b65b82d98f..dbf1f2c47c65 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -41,6 +41,7 @@ struct bvec_iter { unsigned int bi_bvec_done; /* number of bytes completed in current bvec */ + u64 bi_dun; /* DUN setting for bio */ }; /* diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 9e535af579e8..8f4e90ce4326 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -18,6 +18,14 @@ #define FS_CRYPTO_BLOCK_SIZE 16 struct fscrypt_ctx; + +/* iv sector for security/pfe/pfk_fscrypt.c and f2fs. sizeof is required + * to accommodate 32 bit targets. + */ +#define PG_DUN(i, p) \ + ((((i)->i_ino & 0xffffffff) << (sizeof((i)->i_ino)/2)) | \ + ((p)->index & 0xffffffff)) + struct fscrypt_info; struct fscrypt_str { diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h index 6f97714fbd88..ce4df7ad7ee5 100644 --- a/include/linux/fscrypt_notsupp.h +++ b/include/linux/fscrypt_notsupp.h @@ -183,6 +183,21 @@ static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, return -EOPNOTSUPP; } +/* fscrypt_ice.c */ +static inline int fscrypt_using_hardware_encryption(const struct inode *inode) +{ + return 0; +} + +static inline void fscrypt_set_ice_dun(const struct inode *inode, + struct bio *bio, u64 dun){} + +static inline bool fscrypt_mergeable_bio(struct bio *bio, + sector_t iv_block, bool bio_encrypted) +{ + return true; +} + /* hooks.c */ static inline int fscrypt_file_open(struct inode *inode, struct file *filp) diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index 401584753746..32e2b6c99135 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -29,6 +29,7 @@ struct fscrypt_operations { bool (*dummy_context)(struct inode *); bool (*empty_dir)(struct inode *); unsigned (*max_namelen)(struct inode *); + bool (*is_encrypted)(struct inode *); }; struct fscrypt_ctx { @@ -97,10 +98,6 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *, /* keyinfo.c */ extern int fscrypt_get_encryption_info(struct inode *); extern void fscrypt_put_encryption_info(struct inode *); -extern int fs_using_hardware_encryption(struct inode *inode); -extern char *fscrypt_get_ice_encryption_key(const struct inode *inode); -extern char *fscrypt_get_ice_encryption_salt(const struct inode *inode); -extern int fscrypt_is_aes_xts_cipher(const struct inode *inode); /* fname.c */ extern int fscrypt_setup_filename(struct inode *, const struct qstr *, @@ -199,6 +196,13 @@ extern void fscrypt_pullback_bio_page(struct page **, bool); extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, unsigned int); +/* fscrypt_ice.c */ +extern int fscrypt_using_hardware_encryption(const struct inode *inode); +extern void fscrypt_set_ice_dun(const struct inode *inode, + struct bio *bio, u64 dun); +extern bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted); + + /* hooks.c */ extern int fscrypt_file_open(struct inode *inode, struct file *filp); extern int __fscrypt_prepare_link(struct inode *inode, struct inode *dir); diff --git a/include/linux/pfk.h b/include/linux/pfk.h index 3c7a389fd4d4..d7405eac1623 100644 --- a/include/linux/pfk.h +++ b/include/linux/pfk.h @@ -19,6 +19,19 @@ struct ice_crypto_setting; #ifdef CONFIG_PFK +/* + * Default key for inline encryption. + * + * For now only AES-256-XTS is supported, so this is a fixed length. But if + * ever needed, this should be made variable-length with a 'mode' and 'size'. + * (Remember to update pfk_allow_merge_bio() when doing so!) + */ +#define BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS 64 + +struct blk_encryption_key { + u8 raw[BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS]; +}; + int pfk_load_key_start(const struct bio *bio, struct ice_crypto_setting *ice_setting, bool *is_pfe, bool); int pfk_load_key_end(const struct bio *bio, bool *is_pfe); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 7e5430dcd76c..08b1b7badcf8 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -662,6 +662,9 @@ struct Scsi_Host { /* The controller does not support WRITE SAME */ unsigned no_write_same:1; + /* Inline encryption support? */ + unsigned inlinecrypt_support:1; + unsigned use_blk_mq:1; unsigned use_cmd_list:1; diff --git a/security/pfe/Makefile b/security/pfe/Makefile index 242a2165fccb..4096aad2dd4b 100644 --- a/security/pfe/Makefile +++ b/security/pfe/Makefile @@ -3,8 +3,8 @@ # ccflags-y += -Isecurity/selinux -Isecurity/selinux/include -ccflags-y += -Ifs/ext4 +#ccflags-y += -Ifs/ext4 ccflags-y += -Ifs/crypto obj-$(CONFIG_PFT) += pft.o -obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o +obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o pfk_f2fs.o diff --git a/security/pfe/pfk.c b/security/pfe/pfk.c index cd282a09c7d5..740da32190c7 100644 --- a/security/pfe/pfk.c +++ b/security/pfe/pfk.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -56,8 +57,9 @@ #include "objsec.h" #include "pfk_ice.h" #include "pfk_ext4.h" +#include "pfk_f2fs.h" #include "pfk_internal.h" -#include "ext4.h" +//#include "ext4.h" static bool pfk_ready; @@ -67,7 +69,7 @@ static bool pfk_ready; #define PFK_SUPPORTED_SALT_SIZE 32 /* Various PFE types and function tables to support each one of them */ -enum pfe_type {EXT4_CRYPT_PFE, INVALID_PFE}; +enum pfe_type {EXT4_CRYPT_PFE, F2FS_CRYPT_PFE, INVALID_PFE}; typedef int (*pfk_parse_inode_type)(const struct bio *bio, const struct inode *inode, @@ -81,16 +83,19 @@ typedef bool (*pfk_allow_merge_bio_type)(const struct bio *bio1, static const pfk_parse_inode_type pfk_parse_inode_ftable[] = { /* EXT4_CRYPT_PFE */ &pfk_ext4_parse_inode, + /* F2FS_CRYPT_PFE */ &pfk_f2fs_parse_inode, }; static const pfk_allow_merge_bio_type pfk_allow_merge_bio_ftable[] = { /* EXT4_CRYPT_PFE */ &pfk_ext4_allow_merge_bio, + /* F2FS_CRYPT_PFE */ &pfk_f2fs_allow_merge_bio, }; static void __exit pfk_exit(void) { pfk_ready = false; pfk_ext4_deinit(); + pfk_f2fs_deinit(); pfk_kc_deinit(); } @@ -103,10 +108,15 @@ static int __init pfk_init(void) if (ret != 0) goto fail; + ret = pfk_f2fs_init(); + if (ret != 0) + goto fail; + ret = pfk_kc_init(); if (ret != 0) { pr_err("could init pfk key cache, error %d\n", ret); pfk_ext4_deinit(); + pfk_f2fs_deinit(); goto fail; } @@ -132,6 +142,9 @@ static enum pfe_type pfk_get_pfe_type(const struct inode *inode) if (pfk_is_ext4_type(inode)) return EXT4_CRYPT_PFE; + if (pfk_is_f2fs_type(inode)) + return F2FS_CRYPT_PFE; + return INVALID_PFE; } @@ -148,6 +161,9 @@ char *inode_to_filename(const struct inode *inode) struct dentry *dentry = NULL; char *filename = NULL; + if (!inode) + return "NULL"; + if (hlist_empty(&inode->i_dentry)) return "unknown"; @@ -182,32 +198,30 @@ static inline bool pfk_is_ready(void) */ static struct inode *pfk_bio_get_inode(const struct bio *bio) { - struct address_space *mapping; - if (!bio) return NULL; + if (!bio_has_data((struct bio *)bio)) + return NULL; if (!bio->bi_io_vec) return NULL; if (!bio->bi_io_vec->bv_page) return NULL; - if (!bio_has_data((struct bio *)bio)) - return NULL; if (PageAnon(bio->bi_io_vec->bv_page)) { struct inode *inode; - //Using direct-io (O_DIRECT) without page cache + /* Using direct-io (O_DIRECT) without page cache */ inode = dio_bio_get_inode((struct bio *)bio); pr_debug("inode on direct-io, inode = 0x%pK.\n", inode); return inode; } - mapping = page_mapping(bio->bi_io_vec->bv_page); - if (!mapping) + if (!page_mapping(bio->bi_io_vec->bv_page)) return NULL; - if (!mapping->host) + if (!bio->bi_io_vec->bv_page->mapping->host) + return NULL; return bio->bi_io_vec->bv_page->mapping->host; @@ -258,6 +272,58 @@ bool pfe_is_inode_filesystem_type(const struct inode *inode, return (strcmp(inode->i_sb->s_type->name, fs_type) == 0); } +/** + * pfk_get_key_for_bio() - get the encryption key to be used for a bio + * + * @bio: pointer to the BIO + * @key_info: pointer to the key information which will be filled in + * @algo_mode: optional pointer to the algorithm identifier which will be set + * @is_pfe: will be set to false if the BIO should be left unencrypted + * + * Return: 0 if a key is being used, otherwise a -errno value + */ +static int pfk_get_key_for_bio(const struct bio *bio, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo_mode, + bool *is_pfe) +{ + const struct inode *inode; + enum pfe_type which_pfe; + const struct blk_encryption_key *key; + + inode = pfk_bio_get_inode(bio); + which_pfe = pfk_get_pfe_type(inode); + + if (which_pfe != INVALID_PFE) { + /* Encrypted file; override ->bi_crypt_key */ + pr_debug("parsing inode %lu with PFE type %d\n", + inode->i_ino, which_pfe); + return (*(pfk_parse_inode_ftable[which_pfe])) + (bio, inode, key_info, algo_mode, is_pfe); + } + + /* + * bio is not for an encrypted file. Use ->bi_crypt_key if it was set. + * Otherwise, don't encrypt/decrypt the bio. + */ + key = bio->bi_crypt_key; + if (!key) { + *is_pfe = false; + return -EINVAL; + } + + /* Note: the "salt" is really just the second half of the XTS key. */ + BUILD_BUG_ON(sizeof(key->raw) != + PFK_SUPPORTED_KEY_SIZE + PFK_SUPPORTED_SALT_SIZE); + key_info->key = &key->raw[0]; + key_info->key_size = PFK_SUPPORTED_KEY_SIZE; + key_info->salt = &key->raw[PFK_SUPPORTED_KEY_SIZE]; + key_info->salt_size = PFK_SUPPORTED_SALT_SIZE; + if (algo_mode) + *algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS; + return 0; +} + /** * pfk_load_key_start() - loads PFE encryption key to the ICE @@ -287,8 +353,6 @@ int pfk_load_key_start(const struct bio *bio, enum ice_cryto_algo_mode algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS; enum ice_crpto_key_size key_size_type = 0; u32 key_index = 0; - struct inode *inode = NULL; - enum pfe_type which_pfe = INVALID_PFE; if (!is_pfe) { pr_err("is_pfe is NULL\n"); @@ -310,23 +374,8 @@ int pfk_load_key_start(const struct bio *bio, return -EINVAL; } - inode = pfk_bio_get_inode(bio); - if (!inode) { - *is_pfe = false; - return -EINVAL; - } + ret = pfk_get_key_for_bio(bio, &key_info, &algo_mode, is_pfe); - which_pfe = pfk_get_pfe_type(inode); - if (which_pfe == INVALID_PFE) { - *is_pfe = false; - return -EPERM; - } - - pr_debug("parsing file %s with PFE %d\n", - inode_to_filename(inode), which_pfe); - - ret = (*(pfk_parse_inode_ftable[which_pfe])) - (bio, inode, &key_info, &algo_mode, is_pfe); if (ret != 0) return ret; @@ -351,7 +400,7 @@ int pfk_load_key_start(const struct bio *bio, ice_setting->key_index = key_index; pr_debug("loaded key for file %s key_index %d\n", - inode_to_filename(inode), key_index); + inode_to_filename(pfk_bio_get_inode(bio)), key_index); return 0; } @@ -371,8 +420,6 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) { int ret = 0; struct pfk_key_info key_info = {NULL, NULL, 0, 0}; - enum pfe_type which_pfe = INVALID_PFE; - struct inode *inode = NULL; if (!is_pfe) { pr_err("is_pfe is NULL\n"); @@ -388,20 +435,7 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) if (!pfk_is_ready()) return -ENODEV; - inode = pfk_bio_get_inode(bio); - if (!inode) { - *is_pfe = false; - return -EINVAL; - } - - which_pfe = pfk_get_pfe_type(inode); - if (which_pfe == INVALID_PFE) { - *is_pfe = false; - return -EPERM; - } - - ret = (*(pfk_parse_inode_ftable[which_pfe])) - (bio, inode, &key_info, NULL, is_pfe); + ret = pfk_get_key_for_bio(bio, &key_info, NULL, is_pfe); if (ret != 0) return ret; @@ -409,7 +443,7 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) key_info.salt, key_info.salt_size); pr_debug("finished using key for file %s\n", - inode_to_filename(inode)); + inode_to_filename(pfk_bio_get_inode(bio))); return 0; } @@ -431,10 +465,12 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) */ bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2) { - struct inode *inode1 = NULL; - struct inode *inode2 = NULL; - enum pfe_type which_pfe1 = INVALID_PFE; - enum pfe_type which_pfe2 = INVALID_PFE; + const struct blk_encryption_key *key1; + const struct blk_encryption_key *key2; + const struct inode *inode1; + const struct inode *inode2; + enum pfe_type which_pfe1; + enum pfe_type which_pfe2; if (!pfk_is_ready()) return false; @@ -445,24 +481,38 @@ bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2) if (bio1 == bio2) return true; + key1 = bio1->bi_crypt_key; + key2 = bio2->bi_crypt_key; + inode1 = pfk_bio_get_inode(bio1); inode2 = pfk_bio_get_inode(bio2); - which_pfe1 = pfk_get_pfe_type(inode1); which_pfe2 = pfk_get_pfe_type(inode2); - /* nodes with different encryption, do not merge */ + /* + * If one bio is for an encrypted file and the other is for a different + * type of encrypted file or for blocks that are not part of an + * encrypted file, do not merge. + */ if (which_pfe1 != which_pfe2) return false; - /* both nodes do not have encryption, allow merge */ - if (which_pfe1 == INVALID_PFE) - return true; - + if (which_pfe1 != INVALID_PFE) { + /* Both bios are for the same type of encrypted file. */ return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2, inode1, inode2); + } + + /* + * Neither bio is for an encrypted file. Merge only if the default keys + * are the same (or both are NULL). + */ + return key1 == key2 || + (key1 && key2 && + !crypto_memneq(key1->raw, key2->raw, sizeof(key1->raw))); } + /** * Flush key table on storage core reset. During core reset key configuration * is lost in ICE. We need to flash the cache, so that the keys will be diff --git a/security/pfe/pfk_ext4.c b/security/pfe/pfk_ext4.c index c8a527e4a671..0eb122565ecc 100644 --- a/security/pfe/pfk_ext4.c +++ b/security/pfe/pfk_ext4.c @@ -36,8 +36,9 @@ #include #include -#include "ext4_ice.h" +#include "fscrypt_ice.h" #include "pfk_ext4.h" +//#include "ext4_ice.h" static bool pfk_ext4_ready; @@ -102,7 +103,7 @@ bool pfk_is_ext4_type(const struct inode *inode) if (!pfe_is_inode_filesystem_type(inode, "ext4")) return false; - return ext4_should_be_processed_by_ice(inode); + return fscrypt_should_be_processed_by_ice(inode); } /** @@ -124,7 +125,7 @@ static int pfk_ext4_parse_cipher(const struct inode *inode, if (!inode) return -EINVAL; - if (!ext4_is_aes_xts_cipher(inode)) { + if (!fscrypt_is_aes_xts_cipher(inode)) { pr_err("ext4 alghoritm is not supported by pfk\n"); return -EINVAL; } @@ -163,25 +164,25 @@ int pfk_ext4_parse_inode(const struct bio *bio, if (!key_info) return -EINVAL; - key_info->key = ext4_get_ice_encryption_key(inode); + key_info->key = fscrypt_get_ice_encryption_key(inode); if (!key_info->key) { pr_err("could not parse key from ext4\n"); return -EINVAL; } - key_info->key_size = ext4_get_ice_encryption_key_size(inode); + key_info->key_size = fscrypt_get_ice_encryption_key_size(inode); if (!key_info->key_size) { pr_err("could not parse key size from ext4\n"); return -EINVAL; } - key_info->salt = ext4_get_ice_encryption_salt(inode); + key_info->salt = fscrypt_get_ice_encryption_salt(inode); if (!key_info->salt) { pr_err("could not parse salt from ext4\n"); return -EINVAL; } - key_info->salt_size = ext4_get_ice_encryption_salt_size(inode); + key_info->salt_size = fscrypt_get_ice_encryption_salt_size(inode); if (!key_info->salt_size) { pr_err("could not parse salt size from ext4\n"); return -EINVAL; @@ -207,5 +208,5 @@ bool pfk_ext4_allow_merge_bio(const struct bio *bio1, if (!inode1 || !inode2) return false; - return ext4_is_ice_encryption_info_equal(inode1, inode2); + return fscrypt_is_ice_encryption_info_equal(inode1, inode2); } diff --git a/security/pfe/pfk_f2fs.c b/security/pfe/pfk_f2fs.c new file mode 100644 index 000000000000..8b9d515043e8 --- /dev/null +++ b/security/pfe/pfk_f2fs.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Per-File-Key (PFK) - f2fs + * + * This driver is used for working with EXT4/F2FS crypt extension + * + * The key information is stored in node by EXT4/F2FS when file is first opened + * and will be later accessed by Block Device Driver to actually load the key + * to encryption hw. + * + * PFK exposes API's for loading and removing keys from encryption hw + * and also API to determine whether 2 adjacent blocks can be agregated by + * Block Layer in one request to encryption hw. + * + */ + + +/* Uncomment the line below to enable debug messages */ +#define DEBUG 1 +#define pr_fmt(fmt) "pfk_f2fs [%s]: " fmt, __func__ + +#include +#include +#include +#include + +#include "fscrypt_ice.h" +#include "pfk_f2fs.h" + +static bool pfk_f2fs_ready; + +/* + * pfk_f2fs_deinit() - Deinit function, should be invoked by upper PFK layer + */ +void pfk_f2fs_deinit(void) +{ + pfk_f2fs_ready = false; +} + +/* + * pfk_f2fs_init() - Init function, should be invoked by upper PFK layer + */ +int __init pfk_f2fs_init(void) +{ + pfk_f2fs_ready = true; + pr_info("PFK F2FS inited successfully\n"); + + return 0; +} + +/** + * pfk_f2fs_is_ready() - driver is initialized and ready. + * + * Return: true if the driver is ready. + */ +static inline bool pfk_f2fs_is_ready(void) +{ + return pfk_f2fs_ready; +} + +/** + * pfk_is_f2fs_type() - return true if inode belongs to ICE F2FS PFE + * @inode: inode pointer + */ +bool pfk_is_f2fs_type(const struct inode *inode) +{ + if (!pfe_is_inode_filesystem_type(inode, "f2fs")) + return false; + + return fscrypt_should_be_processed_by_ice(inode); +} + +/** + * pfk_f2fs_parse_cipher() - parse cipher from inode to enum + * @inode: inode + * @algo: pointer to store the output enum (can be null) + * + * return 0 in case of success, error otherwise (i.e not supported cipher) + */ +static int pfk_f2fs_parse_cipher(const struct inode *inode, + enum ice_cryto_algo_mode *algo) +{ + /* + * currently only AES XTS algo is supported + * in the future, table with supported ciphers might + * be introduced + */ + if (!inode) + return -EINVAL; + + if (!fscrypt_is_aes_xts_cipher(inode)) { + pr_err("f2fs alghoritm is not supported by pfk\n"); + return -EINVAL; + } + + if (algo) + *algo = ICE_CRYPTO_ALGO_MODE_AES_XTS; + + return 0; +} + + +int pfk_f2fs_parse_inode(const struct bio *bio, + const struct inode *inode, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo, + bool *is_pfe) +{ + int ret = 0; + + if (!is_pfe) + return -EINVAL; + + /* + * only a few errors below can indicate that + * this function was not invoked within PFE context, + * otherwise we will consider it PFE + */ + *is_pfe = true; + + if (!pfk_f2fs_is_ready()) + return -ENODEV; + + if (!inode) + return -EINVAL; + + if (!key_info) + return -EINVAL; + + key_info->key = fscrypt_get_ice_encryption_key(inode); + if (!key_info->key) { + pr_err("could not parse key from f2fs\n"); + return -EINVAL; + } + + key_info->key_size = fscrypt_get_ice_encryption_key_size(inode); + if (!key_info->key_size) { + pr_err("could not parse key size from f2fs\n"); + return -EINVAL; + } + + key_info->salt = fscrypt_get_ice_encryption_salt(inode); + if (!key_info->salt) { + pr_err("could not parse salt from f2fs\n"); + return -EINVAL; + } + + key_info->salt_size = fscrypt_get_ice_encryption_salt_size(inode); + if (!key_info->salt_size) { + pr_err("could not parse salt size from f2fs\n"); + return -EINVAL; + } + + ret = pfk_f2fs_parse_cipher(inode, algo); + if (ret != 0) { + pr_err("not supported cipher\n"); + return ret; + } + + return 0; +} + +bool pfk_f2fs_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2) +{ + bool mergeable; + + /* if there is no f2fs pfk, don't disallow merging blocks */ + if (!pfk_f2fs_is_ready()) + return true; + + if (!inode1 || !inode2) + return false; + + mergeable = fscrypt_is_ice_encryption_info_equal(inode1, inode2); + if (!mergeable) + return false; + + + /* ICE allows only consecutive iv_key stream. */ + if (!bio_dun(bio1) && !bio_dun(bio2)) + return true; + else if (!bio_dun(bio1) || !bio_dun(bio2)) + return false; + + return bio_end_dun(bio1) == bio_dun(bio2); +} diff --git a/security/pfe/pfk_f2fs.h b/security/pfe/pfk_f2fs.h new file mode 100644 index 000000000000..551d529bced6 --- /dev/null +++ b/security/pfe/pfk_f2fs.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _PFK_F2FS_H_ +#define _PFK_F2FS_H_ + +#include +#include +#include +#include "pfk_internal.h" + +bool pfk_is_f2fs_type(const struct inode *inode); + +int pfk_f2fs_parse_inode(const struct bio *bio, + const struct inode *inode, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo, + bool *is_pfe); + +bool pfk_f2fs_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2); + +int __init pfk_f2fs_init(void); + +void pfk_f2fs_deinit(void); + +#endif /* _PFK_F2FS_H_ */ diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c index a405d05ccbfb..eecc0260087d 100644 --- a/security/pfe/pfk_kc.c +++ b/security/pfe/pfk_kc.c @@ -435,6 +435,7 @@ int pfk_kc_init(void) } kc_ready = true; kc_spin_unlock(); + return 0; } @@ -446,8 +447,8 @@ int pfk_kc_init(void) int pfk_kc_deinit(void) { int res = pfk_kc_clear(); - kc_ready = false; + return res; } -- GitLab From 1ad2305a9c5cc0e971030a62e2dd7de56ca6fa20 Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Mon, 7 May 2018 15:23:37 +0530 Subject: [PATCH 572/855] defconfig: sdm845: Enable FBE config flag for f2fs Enable corresponding flags for file based encryption. Change-Id: I03e6f17cf462486f306ef1c7166600dea8535e4c Signed-off-by: Neeraj Soni --- arch/arm64/configs/sdm845-perf_defconfig | 1 + arch/arm64/configs/sdm845_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig index a29cfa70f228..abf30cde054d 100644 --- a/arch/arm64/configs/sdm845-perf_defconfig +++ b/arch/arm64/configs/sdm845-perf_defconfig @@ -576,6 +576,7 @@ CONFIG_EXT4_FS_ENCRYPTION=y CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y +CONFIG_F2FS_FS_ENCRYPTION=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig index d20d9edbebe7..a252757e2988 100644 --- a/arch/arm64/configs/sdm845_defconfig +++ b/arch/arm64/configs/sdm845_defconfig @@ -597,6 +597,7 @@ CONFIG_EXT4_FS_ENCRYPTION=y CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y +CONFIG_F2FS_FS_ENCRYPTION=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y -- GitLab From 58b276b1bfe1716fc14ed24be0db15f8ed7e96ee Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Fri, 25 May 2018 19:48:19 +0800 Subject: [PATCH 573/855] defconfig: Add missing config in arm for msm8937/msm8953 Add CONFIG_PAGE_POISONING, CONFIG_FORCE_PAGES, CONFIG_QCOM_CPUSS_DUMP, CONFIG_MSM_DEBUG_LAR_UNLOCK to enhance debug. Change-Id: Ia27827a50a3d5e5617d2bafe15e0f627ac111642 Signed-off-by: Tingwei Zhang --- arch/arm/configs/msm8937_defconfig | 5 +++++ arch/arm/configs/msm8953_defconfig | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 2f7941f6b014..d5c8386fbec1 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -553,6 +553,7 @@ CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y +CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y @@ -561,6 +562,7 @@ CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_MSM_GLADIATOR_HANG_DETECT=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_MSM_DEBUG_LAR_UNLOCK=y CONFIG_MSM_RPM_SMD=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_SECURE_BUFFER=y @@ -631,6 +633,8 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_PAGEALLOC=y CONFIG_SLUB_DEBUG_PANIC_ON=y CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_PAGE_POISONING=y +CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_FREE=y CONFIG_DEBUG_OBJECTS_TIMERS=y @@ -672,6 +676,7 @@ CONFIG_LKDTM=y CONFIG_MEMTEST=y CONFIG_PANIC_ON_DATA_CORRUPTION=y CONFIG_DEBUG_USER=y +CONFIG_FORCE_PAGES=y CONFIG_PID_IN_CONTEXTIDR=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_CORESIGHT=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index f38341ddfb33..98451c1bfec7 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -557,6 +557,7 @@ CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y +CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y @@ -565,6 +566,7 @@ CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_MSM_GLADIATOR_HANG_DETECT=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_MSM_DEBUG_LAR_UNLOCK=y CONFIG_MSM_RPM_SMD=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_SECURE_BUFFER=y @@ -631,6 +633,8 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_PAGEALLOC=y CONFIG_SLUB_DEBUG_PANIC_ON=y CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_PAGE_POISONING=y +CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_FREE=y CONFIG_DEBUG_OBJECTS_TIMERS=y @@ -672,6 +676,7 @@ CONFIG_LKDTM=y CONFIG_MEMTEST=y CONFIG_PANIC_ON_DATA_CORRUPTION=y CONFIG_DEBUG_USER=y +CONFIG_FORCE_PAGES=y CONFIG_PID_IN_CONTEXTIDR=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_CORESIGHT=y -- GitLab From 46792374ecdd80bb0ceaf80e4b37348a9aec57b4 Mon Sep 17 00:00:00 2001 From: Tejaswi Tanikella Date: Tue, 22 May 2018 12:30:02 +0530 Subject: [PATCH 574/855] defconfig: sdm845: Enable INET_UDP_DIAG Enable config to enable UDP stats collection by ss tool. "ss -uneiopan" should work now. Change-Id: If74647d5027f509c7f4f5878aae8e051ed15c979 Signed-off-by: Tejaswi Tanikella --- arch/arm64/configs/sdm845-perf_defconfig | 1 + arch/arm64/configs/sdm845_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig index a29cfa70f228..9fc179de4b74 100644 --- a/arch/arm64/configs/sdm845-perf_defconfig +++ b/arch/arm64/configs/sdm845-perf_defconfig @@ -105,6 +105,7 @@ CONFIG_IP_PNP_DHCP=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig index d20d9edbebe7..d7412050388e 100644 --- a/arch/arm64/configs/sdm845_defconfig +++ b/arch/arm64/configs/sdm845_defconfig @@ -108,6 +108,7 @@ CONFIG_IP_PNP_DHCP=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y -- GitLab From 016427da6d06f9d1d7d93f771b4ffc04fd03fcb9 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Fri, 25 May 2018 20:19:45 +0530 Subject: [PATCH 575/855] msm: mhi_dev: Switch to look-up table for UCI channel attributes Use a look-up table to easily add or remove support for UCI SW channels. The table includes the channel id, direction, TRB size, number of TRBs and a boolean flag indicating whether to register a channel state change notification with the MHI driver. Change-Id: I8697c24ee559546e279eac51cf9365d7570612e3 Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/mhi_dev/mhi.h | 1 + drivers/platform/msm/mhi_dev/mhi_uci.c | 278 ++++++++++++++++--------- 2 files changed, 186 insertions(+), 93 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h index b9120fceff38..2dfa58da4ae3 100644 --- a/drivers/platform/msm/mhi_dev/mhi.h +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -712,6 +712,7 @@ enum mhi_client_channel { MHI_CLIENT_RESERVED_2_LOWER = 102, MHI_CLIENT_RESERVED_2_UPPER = 127, MHI_MAX_CHANNELS = 102, + MHI_CLIENT_INVALID = 0xFFFFFFFF }; /* Use ID 0 for legacy /dev/mhi_ctrl. Channel 0 is used for internal only */ diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index ed02d0d472f4..febc867c849c 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -35,7 +35,7 @@ #define MHI_SOFTWARE_CLIENT_LIMIT (MHI_MAX_SOFTWARE_CHANNELS/2) #define MHI_UCI_IPC_LOG_PAGES (100) -#define MAX_NR_TRBS_PER_CHAN 1 +#define MAX_NR_TRBS_PER_CHAN 9 #define MHI_QTI_IFACE_ID 4 #define DEVICE_NAME "mhi" @@ -70,7 +70,131 @@ struct chan_attr { u32 nr_trbs; /* direction of the channel, see enum mhi_chan_dir */ enum mhi_chan_dir dir; - u32 uci_ownership; + /* need to register mhi channel state change callback */ + bool register_cb; +}; + +/* UCI channel attributes table */ +static const struct chan_attr uci_chan_attr_table[] = { + { + MHI_CLIENT_LOOPBACK_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_LOOPBACK_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_SAHARA_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_SAHARA_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_EFS_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_EFS_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_MBIM_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_MBIM_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_QMI_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_QMI_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_IP_CTRL_0_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_IP_CTRL_0_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_IP_CTRL_1_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_IP_CTRL_1_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_DUN_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_DUN_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { /* Must be the last */ + MHI_CLIENT_INVALID, + 0, + 0, + MHI_DIR_INVALID, + false + }, }; struct uci_ctrl { @@ -87,6 +211,8 @@ struct uci_client { u32 in_chan; struct mhi_dev_client *out_handle; struct mhi_dev_client *in_handle; + const struct chan_attr *in_chan_attr; + const struct chan_attr *out_chan_attr; wait_queue_head_t read_wq; wait_queue_head_t write_wq; atomic_t read_data_ready; @@ -104,7 +230,6 @@ struct uci_client { }; struct mhi_uci_ctxt_t { - struct chan_attr chan_attrib[MHI_MAX_SOFTWARE_CHANNELS]; struct uci_client client_handles[MHI_SOFTWARE_CLIENT_LIMIT]; struct uci_ctrl ctrl_handle; void (*event_notifier)(struct mhi_dev_client_cb_reason *cb); @@ -119,6 +244,7 @@ struct mhi_uci_ctxt_t { }; #define CHAN_TO_CLIENT(_CHAN_NR) (_CHAN_NR / 2) +#define CLIENT_TO_CHAN(_CLIENT_NR) (_CLIENT_NR * 2) #define uci_log(_msg_lvl, _msg, ...) do { \ if (_msg_lvl >= mhi_uci_msg_lvl) { \ @@ -156,7 +282,7 @@ static int mhi_init_read_chan(struct uci_client *client_handle, { int rc = 0; u32 i, j; - struct chan_attr *chan_attributes; + const struct chan_attr *in_chan_attr; size_t buf_size; void *data_loc; @@ -169,10 +295,15 @@ static int mhi_init_read_chan(struct uci_client *client_handle, return -EINVAL; } - chan_attributes = &uci_ctxt.chan_attrib[chan]; - buf_size = chan_attributes->max_packet_size; + in_chan_attr = client_handle->in_chan_attr; + if (!in_chan_attr) { + uci_log(UCI_DBG_ERROR, "Null channel attributes for chan %d\n", + client_handle->in_chan); + return -EINVAL; + } + buf_size = in_chan_attr->max_packet_size; - for (i = 0; i < (chan_attributes->nr_trbs); i++) { + for (i = 0; i < (in_chan_attr->nr_trbs); i++) { data_loc = kmalloc(buf_size, GFP_KERNEL); if (!data_loc) { rc = -ENOMEM; @@ -397,20 +528,11 @@ static int mhi_uci_client_release(struct inode *mhi_inode, struct file *file_handle) { struct uci_client *uci_handle = file_handle->private_data; - struct mhi_uci_ctxt_t *uci_ctxt; - u32 nr_in_bufs = 0; int rc = 0; - int in_chan = 0; - u32 buf_size = 0; if (!uci_handle) return -EINVAL; - uci_ctxt = uci_handle->uci_ctxt; - in_chan = iminor(mhi_inode) + 1; - nr_in_bufs = uci_ctxt->chan_attrib[in_chan].nr_trbs; - buf_size = uci_ctxt->chan_attrib[in_chan].max_packet_size; - if (atomic_sub_return(1, &uci_handle->ref_count) == 0) { uci_log(UCI_DBG_DBG, "Last client left, closing channel 0x%x\n", @@ -750,54 +872,25 @@ static ssize_t mhi_uci_client_write(struct file *file, static int uci_init_client_attributes(struct mhi_uci_ctxt_t *uci_ctxt) { - u32 i = 0; - u32 data_size = TRB_MAX_DATA_SIZE; - u32 index = 0; + u32 i; + u32 index; struct uci_client *client; - struct chan_attr *chan_attrib = NULL; - - for (i = 0; i < ARRAY_SIZE(uci_ctxt->chan_attrib); i++) { - chan_attrib = &uci_ctxt->chan_attrib[i]; - switch (i) { - case MHI_CLIENT_LOOPBACK_OUT: - case MHI_CLIENT_LOOPBACK_IN: - case MHI_CLIENT_SAHARA_OUT: - case MHI_CLIENT_SAHARA_IN: - case MHI_CLIENT_EFS_OUT: - case MHI_CLIENT_EFS_IN: - case MHI_CLIENT_MBIM_OUT: - case MHI_CLIENT_MBIM_IN: - case MHI_CLIENT_QMI_OUT: - case MHI_CLIENT_QMI_IN: - case MHI_CLIENT_IP_CTRL_0_OUT: - case MHI_CLIENT_IP_CTRL_0_IN: - case MHI_CLIENT_IP_CTRL_1_OUT: - case MHI_CLIENT_IP_CTRL_1_IN: - case MHI_CLIENT_DUN_OUT: - case MHI_CLIENT_DUN_IN: - chan_attrib->uci_ownership = 1; - break; - default: - chan_attrib->uci_ownership = 0; + const struct chan_attr *chan_attrib; + + for (i = 0; i < ARRAY_SIZE(uci_chan_attr_table); i += 2) { + chan_attrib = &uci_chan_attr_table[i]; + if (chan_attrib->chan_id == MHI_CLIENT_INVALID) break; - } - if (chan_attrib->uci_ownership) { - chan_attrib->chan_id = i; - chan_attrib->max_packet_size = data_size; - index = CHAN_TO_CLIENT(i); - client = &uci_ctxt->client_handles[index]; - chan_attrib->nr_trbs = 9; - client->in_buf_list = - kmalloc(sizeof(struct mhi_dev_iov) * - chan_attrib->nr_trbs, + index = CHAN_TO_CLIENT(i); + client = &uci_ctxt->client_handles[index]; + client->out_chan_attr = chan_attrib; + client->in_chan_attr = ++chan_attrib; + client->in_buf_list = + kcalloc(chan_attrib->nr_trbs, + sizeof(struct mhi_dev_iov), GFP_KERNEL); - if (client->in_buf_list == NULL) - return -ENOMEM; - } - if (i % 2 == 0) - chan_attrib->dir = MHI_DIR_OUT; - else - chan_attrib->dir = MHI_DIR_IN; + if (!client->in_buf_list) + return -ENOMEM; } return 0; } @@ -949,16 +1042,14 @@ int mhi_uci_init(void) uci_log(UCI_DBG_INFO, "Registering for MHI events.\n"); for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; i++) { - if (uci_ctxt.chan_attrib[i * 2].uci_ownership) { - mhi_client = &uci_ctxt.client_handles[i]; - - r = mhi_register_client(mhi_client, i); - - if (r) { - uci_log(UCI_DBG_CRITICAL, - "Failed to reg client %d ret %d\n", - r, i); - } + mhi_client = &uci_ctxt.client_handles[i]; + if (!mhi_client->in_chan_attr) + continue; + r = mhi_register_client(mhi_client, i); + if (r) { + uci_log(UCI_DBG_CRITICAL, + "Failed to reg client %d ret %d\n", + r, i); } } @@ -992,29 +1083,30 @@ int mhi_uci_init(void) uci_log(UCI_DBG_INFO, "Setting up device nodes.\n"); for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; i++) { - if (uci_ctxt.chan_attrib[i*2].uci_ownership) { - cdev_init(&uci_ctxt.cdev[i], &mhi_uci_client_fops); - uci_ctxt.cdev[i].owner = THIS_MODULE; - r = cdev_add(&uci_ctxt.cdev[i], - uci_ctxt.start_ctrl_nr + i, 1); - if (IS_ERR_VALUE(r)) { - uci_log(UCI_DBG_ERROR, - "Failed to add cdev %d, ret 0x%x\n", - i, r); - goto failed_char_add; - } + mhi_client = &uci_ctxt.client_handles[i]; + if (!mhi_client->in_chan_attr) + continue; + cdev_init(&uci_ctxt.cdev[i], &mhi_uci_client_fops); + uci_ctxt.cdev[i].owner = THIS_MODULE; + r = cdev_add(&uci_ctxt.cdev[i], + uci_ctxt.start_ctrl_nr + i, 1); + if (IS_ERR_VALUE(r)) { + uci_log(UCI_DBG_ERROR, + "Failed to add cdev %d, ret 0x%x\n", + i, r); + goto failed_char_add; + } - uci_ctxt.client_handles[i].dev = - device_create(uci_ctxt.mhi_uci_class, NULL, - uci_ctxt.start_ctrl_nr + i, - NULL, DEVICE_NAME "_pipe_%d", - i * 2); - if (IS_ERR(uci_ctxt.client_handles[i].dev)) { - uci_log(UCI_DBG_ERROR, - "Failed to add cdev %d\n", i); - cdev_del(&uci_ctxt.cdev[i]); - goto failed_device_create; - } + uci_ctxt.client_handles[i].dev = + device_create(uci_ctxt.mhi_uci_class, NULL, + uci_ctxt.start_ctrl_nr + i, + NULL, DEVICE_NAME "_pipe_%d", + i * 2); + if (IS_ERR(uci_ctxt.client_handles[i].dev)) { + uci_log(UCI_DBG_ERROR, + "Failed to add cdev %d\n", i); + cdev_del(&uci_ctxt.cdev[i]); + goto failed_device_create; } } -- GitLab From 80027d6a5c79b755f47e413e02a407e48eeeb6eb Mon Sep 17 00:00:00 2001 From: Ajit Kumar Date: Mon, 9 Apr 2018 09:56:15 +0530 Subject: [PATCH 576/855] soc: qcom: bgdaemon: add delay in SUBSYS_AFTER_SHUTDOWN Add delay for SPI bus synchronization in SUBSYS_AFTER_SHUTDOWN inplace of SUBSYS_BEFORE_SHUTDOWN. This helps PIL to handle SUBSYS_BEFORE_SHUTDOWN quickly. Change-Id: Icb9a322f1944ca24ca3c6f032a1d9b4889544d0e Signed-off-by: Ajit Kumar Signed-off-by: Ramesh Yadav Javadi --- drivers/soc/qcom/bgcom_interface.c | 7 +++++++ drivers/soc/qcom/bgcom_spi.c | 3 --- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/bgcom_interface.c b/drivers/soc/qcom/bgcom_interface.c index efef26ddbfbd..a5a42c5e5b6e 100644 --- a/drivers/soc/qcom/bgcom_interface.c +++ b/drivers/soc/qcom/bgcom_interface.c @@ -44,6 +44,7 @@ #define BGDAEMON_LDO03_NPM_VTG 10000 #define MPPS_DOWN_EVENT_TO_BG_TIMEOUT 100 +#define SLEEP_FOR_SPI_BUS 2000 enum { SSR_DOMAIN_BG, @@ -353,6 +354,8 @@ static long bg_com_ioctl(struct file *filp, break; case SET_SPI_BUSY: ret = bgcom_set_spi_state(BGCOM_SPI_BUSY); + /* Add sleep for SPI Bus to release*/ + msleep(SLEEP_FOR_SPI_BUS); break; case BG_SOFT_RESET: ret = bg_soft_reset(); @@ -515,6 +518,10 @@ static int ssr_bg_cb(struct notifier_block *this, bgcom_set_spi_state(BGCOM_SPI_BUSY); send_uevent(&bge); break; + case SUBSYS_AFTER_SHUTDOWN: + /* Add sleep for SPI Bus to release*/ + msleep(SLEEP_FOR_SPI_BUS); + break; case SUBSYS_AFTER_POWERUP: bge.e_type = BG_AFTER_POWER_UP; bgdaemon_ldowork(DISABLE_LDO03); diff --git a/drivers/soc/qcom/bgcom_spi.c b/drivers/soc/qcom/bgcom_spi.c index b8e3b841a8f7..c6f8857f2e9a 100644 --- a/drivers/soc/qcom/bgcom_spi.c +++ b/drivers/soc/qcom/bgcom_spi.c @@ -43,7 +43,6 @@ #define BG_SPI_MAX_WORDS (0x3FFFFFFD) #define BG_SPI_MAX_REGS (0x0A) -#define SLEEP_IN_STATE_CHNG 2000 #define HED_EVENT_ID_LEN (0x02) #define HED_EVENT_SIZE_LEN (0x02) #define HED_EVENT_DATA_STRT_LEN (0x05) @@ -149,8 +148,6 @@ int bgcom_set_spi_state(enum bgcom_spi_state state) mutex_lock(&bg_spi->xfer_mutex); spi_state = state; - if (spi_state == BGCOM_SPI_BUSY) - msleep(SLEEP_IN_STATE_CHNG); mutex_unlock(&bg_spi->xfer_mutex); return 0; } -- GitLab From 6b6cfd35299669630f485bc5a8984b685aad255c Mon Sep 17 00:00:00 2001 From: Ajit Kumar Date: Mon, 9 Apr 2018 10:24:45 +0530 Subject: [PATCH 577/855] soc: qcom: bgspi: increase Blackghost SPI resume timeout to 5ms Increase Blackghost SPI resume timeout from 2 ms to 5 ms. Change-Id: Ia9deb3f1c2757f004070f7448a0a268d8d19dc50 Signed-off-by: Ajit Kumar Signed-off-by: Ramesh Yadav Javadi --- drivers/soc/qcom/bgcom_spi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/soc/qcom/bgcom_spi.c b/drivers/soc/qcom/bgcom_spi.c index b8e3b841a8f7..c620d51a9102 100644 --- a/drivers/soc/qcom/bgcom_spi.c +++ b/drivers/soc/qcom/bgcom_spi.c @@ -48,7 +48,7 @@ #define HED_EVENT_SIZE_LEN (0x02) #define HED_EVENT_DATA_STRT_LEN (0x05) -#define MAX_RETRY 200 +#define MAX_RETRY 500 enum bgcom_state { /*BGCOM Staus ready*/ @@ -789,7 +789,6 @@ int bgcom_resume(void *handle) bg_soft_reset(); return -ETIMEDOUT; } - pr_info("BG retries for wake up : %d\n", retry); return 0; } EXPORT_SYMBOL(bgcom_resume); -- GitLab From 18ff5b18fcdf424ff549189d217a734ef1b51a82 Mon Sep 17 00:00:00 2001 From: Arjun Singh Date: Fri, 13 Apr 2018 16:32:59 +0530 Subject: [PATCH 578/855] soc: qcom: bgrsb: Increase time out for RSB channel opening Increases the required timeout for RSB channel opening as in BG ssr event re-open may take more than existing time out. Change-Id: Ibb20a55eef033fc51d567343798a0f5dbf00ca4e Signed-off-by: Arjun Singh Signed-off-by: Ramesh Yadav Javadi --- drivers/soc/qcom/bg_rsb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/bg_rsb.c b/drivers/soc/qcom/bg_rsb.c index fdfd7b7e9783..867b2e3c9dc2 100644 --- a/drivers/soc/qcom/bg_rsb.c +++ b/drivers/soc/qcom/bg_rsb.c @@ -33,7 +33,7 @@ #define BGRSB_GLINK_INTENT_SIZE 0x04 #define BGRSB_MSG_SIZE 0x08 -#define TIMEOUT_MS 500 +#define TIMEOUT_MS 2000 #define BGRSB_LDO15_VTG_MIN_UV 3300000 #define BGRSB_LDO15_VTG_MAX_UV 3300000 @@ -544,7 +544,7 @@ static void bgrsb_bgup_work(struct work_struct *work) rc = wait_event_timeout(dev->link_state_wait, (dev->chnl_state == true), - msecs_to_jiffies(TIMEOUT_MS*2)); + msecs_to_jiffies(TIMEOUT_MS)); if (rc == 0) { pr_err("Glink channel connection time out\n"); return; @@ -574,7 +574,7 @@ static void bgrsb_glink_bgup_work(struct work_struct *work) rc = wait_event_timeout(dev->link_state_wait, (dev->chnl_state == true), - msecs_to_jiffies(TIMEOUT_MS*2)); + msecs_to_jiffies(TIMEOUT_MS)); if (rc == 0) { pr_err("Glink channel connection time out\n"); return; -- GitLab From aec44a2435decf91fe0e69cbec85cfd5cbe28719 Mon Sep 17 00:00:00 2001 From: Arjun Singh Date: Fri, 20 Apr 2018 11:26:00 +0530 Subject: [PATCH 579/855] soc: qcom: bgcom: prevent BG status checking while SPI is busy Stops any transaction which try to resume BG while SPI is held by TZ. Change-Id: I45c5d4dcc9ab094f63742d7ca3f82b12a2fdae4a Signed-off-by: Arjun Singh Signed-off-by: Ramesh Yadav Javadi --- drivers/soc/qcom/bgcom_spi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/soc/qcom/bgcom_spi.c b/drivers/soc/qcom/bgcom_spi.c index b8e3b841a8f7..ed053adecdd7 100644 --- a/drivers/soc/qcom/bgcom_spi.c +++ b/drivers/soc/qcom/bgcom_spi.c @@ -749,11 +749,18 @@ static int is_bg_resume(void *handle) uint8_t rx_buf[8] = {0}; uint32_t cmnd_reg = 0; + if (spi_state == BGCOM_SPI_BUSY) { + printk_ratelimited("SPI is held by TZ\n"); + goto ret_err; + } + txn_len = 0x08; tx_buf[0] = 0x05; ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len); if (!ret) memcpy(&cmnd_reg, rx_buf+BG_SPI_READ_LEN, 0x04); + +ret_err: return cmnd_reg & BIT(31); } -- GitLab From 5c7b7fe76ce5ca2496b2d9e3bbcb66d0f5fb718e Mon Sep 17 00:00:00 2001 From: Arjun Singh Date: Tue, 24 Apr 2018 18:23:47 +0530 Subject: [PATCH 580/855] soc: qcom: bgdeamon: increase time out for BG response Increases time out as BG response would take more then two seconds. Change-Id: I01ab3d58cf80364909bf976a772ae609331ba726 Signed-off-by: Arjun Singh Signed-off-by: Ramesh Yadav Javadi --- drivers/soc/qcom/bgcom_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/bgcom_interface.c b/drivers/soc/qcom/bgcom_interface.c index a5a42c5e5b6e..9821018c24d3 100644 --- a/drivers/soc/qcom/bgcom_interface.c +++ b/drivers/soc/qcom/bgcom_interface.c @@ -43,7 +43,7 @@ #define BGDAEMON_LDO03_LPM_VTG 0 #define BGDAEMON_LDO03_NPM_VTG 10000 -#define MPPS_DOWN_EVENT_TO_BG_TIMEOUT 100 +#define MPPS_DOWN_EVENT_TO_BG_TIMEOUT 3000 #define SLEEP_FOR_SPI_BUS 2000 enum { -- GitLab From 04dddde8d25f61963e906995025eae25e6d1e161 Mon Sep 17 00:00:00 2001 From: Arjun Singh Date: Tue, 1 May 2018 22:30:12 +0530 Subject: [PATCH 581/855] soc: qcom: bgcom: Add suspend resume to aligned to SPI pm Adds pm suspend resume call backs to be aligned with SPI driver. Change-Id: I057c2d5f74b3c39c58647a0ea594d4d667644271 Signed-off-by: Arjun Singh Signed-off-by: Ramesh Yadav Javadi --- drivers/soc/qcom/bg_rsb.c | 21 ++++----- drivers/soc/qcom/bgcom_spi.c | 91 +++++++++++++++++++++++++++--------- 2 files changed, 78 insertions(+), 34 deletions(-) diff --git a/drivers/soc/qcom/bg_rsb.c b/drivers/soc/qcom/bg_rsb.c index fdfd7b7e9783..4ff25f3c73f9 100644 --- a/drivers/soc/qcom/bg_rsb.c +++ b/drivers/soc/qcom/bg_rsb.c @@ -968,9 +968,9 @@ static int bg_rsb_remove(struct platform_device *pdev) return 0; } -static int bg_rsb_resume(struct platform_device *pdev) +static int bg_rsb_resume(struct device *pldev) { - int rc; + struct platform_device *pdev = to_platform_device(pldev); struct bgrsb_priv *dev = platform_get_drvdata(pdev); if (dev->bgrsb_current_state == BGRSB_STATE_RSB_CONFIGURED) @@ -978,12 +978,6 @@ static int bg_rsb_resume(struct platform_device *pdev) if (dev->bgrsb_current_state == BGRSB_STATE_INIT) { if (bgrsb_ldo_work(dev, BGRSB_ENABLE_LDO11) == 0) { - rc = bgrsb_configr_rsb(dev, true); - if (rc != 0) { - pr_err("BG failed to configure RSB %d\n", rc); - bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO11); - return rc; - } dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED; pr_debug("RSB Cofigured\n"); return 0; @@ -993,8 +987,9 @@ static int bg_rsb_resume(struct platform_device *pdev) return -EINVAL; } -static int bg_rsb_suspend(struct platform_device *pdev, pm_message_t state) +static int bg_rsb_suspend(struct device *pldev) { + struct platform_device *pdev = to_platform_device(pldev); struct bgrsb_priv *dev = platform_get_drvdata(pdev); if (dev->bgrsb_current_state == BGRSB_STATE_INIT) @@ -1021,15 +1016,19 @@ static const struct of_device_id bg_rsb_of_match[] = { { } }; +static const struct dev_pm_ops pm_rsb = { + .resume = bg_rsb_resume, + .suspend = bg_rsb_suspend, +}; + static struct platform_driver bg_rsb_driver = { .driver = { .name = "bg-rsb", .of_match_table = bg_rsb_of_match, + .pm = &pm_rsb, }, .probe = bg_rsb_probe, .remove = bg_rsb_remove, - .resume = bg_rsb_resume, - .suspend = bg_rsb_suspend, }; module_platform_driver(bg_rsb_driver); diff --git a/drivers/soc/qcom/bgcom_spi.c b/drivers/soc/qcom/bgcom_spi.c index b8e3b841a8f7..01da6f14a2e4 100644 --- a/drivers/soc/qcom/bgcom_spi.c +++ b/drivers/soc/qcom/bgcom_spi.c @@ -63,6 +63,7 @@ enum bgcom_req_type { BGCOM_READ_REG = 0, BGCOM_READ_FIFO = 1, BGCOM_READ_AHB = 2, + BGCOM_WRITE_REG = 3, }; struct bg_spi_priv { @@ -112,6 +113,9 @@ static DECLARE_WORK(input_work, send_input_events); static struct mutex bg_resume_mutex; +static atomic_t bg_is_spi_active; +static int bg_irq; + static void augmnt_fifo(uint8_t *data, int pos) { data[pos] = '\0'; @@ -197,6 +201,10 @@ static int read_bg_locl(enum bgcom_req_type req_type, case BGCOM_READ_FIFO: ret = bgcom_fifo_read(&clnt_handle, no_of_words, buf); break; + case BGCOM_WRITE_REG: + ret = bgcom_reg_write(&clnt_handle, BG_CMND_REG, + no_of_words, buf); + break; case BGCOM_READ_AHB: break; } @@ -232,6 +240,9 @@ static int bgcom_transfer(void *handle, uint8_t *tx_buf, tx_xfer = &bg_spi->xfer1; spi = bg_spi->spi; + if (!atomic_read(&bg_is_spi_active)) + return -ECANCELED; + mutex_lock(&bg_spi->xfer_mutex); bg_spi_reinit_xfer(tx_xfer); tx_xfer->tx_buf = tx_buf; @@ -621,6 +632,11 @@ int bgcom_fifo_read(void *handle, uint32_t num_words, return -EBUSY; } + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + size = num_words*BG_SPI_WORD_SIZE; txn_len = BG_SPI_READ_LEN + size; tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); @@ -671,6 +687,11 @@ int bgcom_reg_write(void *handle, uint8_t reg_start_addr, return -EBUSY; } + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + size = num_regs*BG_SPI_WORD_SIZE; txn_len = BG_SPI_WRITE_CMND_LEN + size; @@ -766,6 +787,9 @@ int bgcom_resume(void *handle) if (handle == NULL) return -EINVAL; + if (!atomic_read(&bg_is_spi_active)) + return -ECANCELED; + cntx = (struct bg_context *)handle; bg_spi = cntx->bg_spi; @@ -796,29 +820,9 @@ EXPORT_SYMBOL(bgcom_resume); int bgcom_suspend(void *handle) { - struct bg_spi_priv *bg_spi; - struct bg_context *cntx; - uint32_t cmnd_reg = 0; - int ret = 0; - - if (handle == NULL) + if (!handle) return -EINVAL; - - cntx = (struct bg_context *)handle; - bg_spi = cntx->bg_spi; - mutex_lock(&bg_resume_mutex); - if (bg_spi->bg_state == BGCOM_STATE_SUSPEND) - goto unlock; - - cmnd_reg |= BIT(31); - ret = bgcom_reg_write(handle, BG_CMND_REG, 1, &cmnd_reg); - if (ret == 0) - bg_spi->bg_state = BGCOM_STATE_SUSPEND; - -unlock: - mutex_unlock(&bg_resume_mutex); - pr_info("suspended with : %d\n", ret); - return ret; + return 0; } EXPORT_SYMBOL(bgcom_suspend); @@ -931,7 +935,6 @@ static int bg_spi_probe(struct spi_device *spi) struct bg_spi_priv *bg_spi; struct device_node *node; int irq_gpio = 0; - int bg_irq = 0; int ret; bg_spi = devm_kzalloc(&spi->dev, sizeof(*bg_spi), @@ -969,6 +972,7 @@ static int bg_spi_probe(struct spi_device *spi) if (ret) goto err_ret; + atomic_set(&bg_is_spi_active, 1); pr_info("Bgcom Probed successfully\n"); return ret; @@ -990,6 +994,46 @@ static int bg_spi_remove(struct spi_device *spi) return 0; } +static int bgcom_pm_suspend(struct device *dev) +{ + uint32_t cmnd_reg = 0; + struct spi_device *s_dev = to_spi_device(dev); + struct bg_spi_priv *bg_spi = spi_get_drvdata(s_dev); + int ret = 0; + + if (bg_spi->bg_state == BGCOM_STATE_SUSPEND) + return 0; + + cmnd_reg |= BIT(31); + ret = read_bg_locl(BGCOM_WRITE_REG, 1, &cmnd_reg); + if (ret == 0) { + bg_spi->bg_state = BGCOM_STATE_SUSPEND; + atomic_set(&bg_is_spi_active, 0); + } + pr_info("suspended with : %d\n", ret); + return ret; +} + +static int bgcom_pm_resume(struct device *dev) +{ + struct bg_context clnt_handle; + int ret; + struct bg_spi_priv *spi = + container_of(bg_com_drv, struct bg_spi_priv, lhandle); + + clnt_handle.bg_spi = spi; + atomic_set(&bg_is_spi_active, 1); + ret = bgcom_resume(&clnt_handle); + if (ret == 0) + pr_info("Bgcom resumed\n"); + return ret; +} + +static const struct dev_pm_ops bgcom_pm = { + .suspend = bgcom_pm_suspend, + .resume = bgcom_pm_resume, +}; + static const struct of_device_id bg_spi_of_match[] = { { .compatible = "qcom,bg-spi", }, { } @@ -1000,6 +1044,7 @@ static struct spi_driver bg_spi_driver = { .driver = { .name = "bg-spi", .of_match_table = bg_spi_of_match, + .pm = &bgcom_pm, }, .probe = bg_spi_probe, .remove = bg_spi_remove, -- GitLab From 48f011abae8ef4f6ca3f318328468222bd2b9a01 Mon Sep 17 00:00:00 2001 From: Arjun Singh Date: Thu, 3 May 2018 11:30:14 +0530 Subject: [PATCH 582/855] soc: qcom: bgcom: add support for reserved cma memory allocation Adds support for reserved cma memory for read write assests. Change-Id: I7518ba1ed30aabd641e930d3a897c30c40234f4a Signed-off-by: Arjun Singh Signed-off-by: Ramesh Yadav Javadi --- drivers/soc/qcom/bgcom_spi.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/soc/qcom/bgcom_spi.c b/drivers/soc/qcom/bgcom_spi.c index 01da6f14a2e4..22d270b47c71 100644 --- a/drivers/soc/qcom/bgcom_spi.c +++ b/drivers/soc/qcom/bgcom_spi.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "bgcom.h" #include "bgrsb.h" #include "bgcom_interface.h" @@ -116,6 +117,14 @@ static struct mutex bg_resume_mutex; static atomic_t bg_is_spi_active; static int bg_irq; +static struct spi_device *get_spi_device(void) +{ + struct bg_spi_priv *bg_spi = container_of(bg_com_drv, + struct bg_spi_priv, lhandle); + struct spi_device *spi = bg_spi->spi; + return spi; +} + static void augmnt_fifo(uint8_t *data, int pos) { data[pos] = '\0'; @@ -454,6 +463,7 @@ static void bg_irq_tasklet_hndlr_l(void) int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr, uint32_t num_words, void *read_buf) { + dma_addr_t dma_hndl_tx, dma_hndl_rx; uint32_t txn_len; uint8_t *tx_buf; uint8_t *rx_buf; @@ -461,6 +471,7 @@ int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr, int ret; uint8_t cmnd = 0; uint32_t ahb_addr = 0; + struct spi_device *spi = get_spi_device(); if (!handle || !read_buf || num_words == 0 || num_words > BG_SPI_MAX_WORDS) { @@ -483,15 +494,16 @@ int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr, size = num_words*BG_SPI_WORD_SIZE; txn_len = BG_SPI_AHB_READ_CMD_LEN + size; - tx_buf = kzalloc(txn_len, GFP_KERNEL); + tx_buf = dma_zalloc_coherent(&spi->dev, txn_len, + &dma_hndl_tx, GFP_KERNEL); if (!tx_buf) return -ENOMEM; - rx_buf = kzalloc(txn_len, GFP_KERNEL); - + rx_buf = dma_zalloc_coherent(&spi->dev, txn_len, + &dma_hndl_rx, GFP_KERNEL); if (!rx_buf) { - kfree(tx_buf); + dma_free_coherent(&spi->dev, txn_len, tx_buf, dma_hndl_tx); return -ENOMEM; } @@ -506,8 +518,8 @@ int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr, if (!ret) memcpy(read_buf, rx_buf+BG_SPI_AHB_READ_CMD_LEN, size); - kfree(tx_buf); - kfree(rx_buf); + dma_free_coherent(&spi->dev, txn_len, tx_buf, dma_hndl_tx); + dma_free_coherent(&spi->dev, txn_len, rx_buf, dma_hndl_rx); return ret; } EXPORT_SYMBOL(bgcom_ahb_read); @@ -515,12 +527,14 @@ EXPORT_SYMBOL(bgcom_ahb_read); int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, uint32_t num_words, void *write_buf) { + dma_addr_t dma_hndl; uint32_t txn_len; uint8_t *tx_buf; uint32_t size; int ret; uint8_t cmnd = 0; uint32_t ahb_addr = 0; + struct spi_device *spi = get_spi_device(); if (!handle || !write_buf || num_words == 0 || num_words > BG_SPI_MAX_WORDS) { @@ -543,9 +557,7 @@ int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, size = num_words*BG_SPI_WORD_SIZE; txn_len = BG_SPI_AHB_CMD_LEN + size; - - tx_buf = kzalloc(txn_len, GFP_KERNEL); - + tx_buf = dma_zalloc_coherent(&spi->dev, txn_len, &dma_hndl, GFP_KERNEL); if (!tx_buf) return -ENOMEM; @@ -557,7 +569,7 @@ int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, memcpy(tx_buf+BG_SPI_AHB_CMD_LEN, write_buf, size); ret = bgcom_transfer(handle, tx_buf, NULL, txn_len); - kfree(tx_buf); + dma_free_coherent(&spi->dev, txn_len, tx_buf, dma_hndl); return ret; } EXPORT_SYMBOL(bgcom_ahb_write); @@ -973,6 +985,7 @@ static int bg_spi_probe(struct spi_device *spi) goto err_ret; atomic_set(&bg_is_spi_active, 1); + dma_set_coherent_mask(&spi->dev, DMA_BIT_MASK(64)); pr_info("Bgcom Probed successfully\n"); return ret; -- GitLab From 51fd240d1baf6a63967235f47cfc4af4b5169ada Mon Sep 17 00:00:00 2001 From: Ajit Kumar Date: Tue, 15 May 2018 14:40:20 +0530 Subject: [PATCH 583/855] soc: qcom: bgdaemon: add interface to get TWM exit flag Add an interface to find if the device bootup is after traditional watch mode exit. Change-Id: I174850bf09a8c91c2265c4675d4df735292d7fde Signed-off-by: Ajit Kumar Signed-off-by: Ramesh Yadav Javadi --- drivers/soc/qcom/bgcom_interface.c | 15 +++++++++++++++ drivers/soc/qcom/bgcom_interface.h | 9 ++++++++- include/uapi/linux/bgcom_interface.h | 4 ++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/bgcom_interface.c b/drivers/soc/qcom/bgcom_interface.c index efef26ddbfbd..a0efe7a7a16d 100644 --- a/drivers/soc/qcom/bgcom_interface.c +++ b/drivers/soc/qcom/bgcom_interface.c @@ -93,6 +93,7 @@ struct device *dev_ret; static dev_t bg_dev; static int device_open; static void *handle; +static bool twm_exit; static struct bgcom_open_config_type config_type; static DECLARE_COMPLETION(bg_modem_down_wait); @@ -360,6 +361,10 @@ static long bg_com_ioctl(struct file *filp, case BG_MODEM_DOWN2_BG_DONE: ret = modem_down2_bg(); break; + case BG_TWM_EXIT: + twm_exit = true; + ret = 0; + break; default: ret = -ENOIOCTLCMD; } @@ -555,6 +560,16 @@ static int ssr_modem_cb(struct notifier_block *this, return NOTIFY_DONE; } +bool is_twm_exit(void) +{ + if (twm_exit) { + twm_exit = false; + return true; + } + return false; +} +EXPORT_SYMBOL(is_twm_exit); + static struct notifier_block ssr_modem_nb = { .notifier_call = ssr_modem_cb, .priority = 0, diff --git a/drivers/soc/qcom/bgcom_interface.h b/drivers/soc/qcom/bgcom_interface.h index 500ca6d49d11..235995e21d5a 100644 --- a/drivers/soc/qcom/bgcom_interface.h +++ b/drivers/soc/qcom/bgcom_interface.h @@ -13,10 +13,17 @@ #ifndef BGCOM_INTERFACE_H #define BGCOM_INTERFACE_H -/** +/* * bg_soft_reset() - soft reset Blackghost * Return 0 on success or -Ve on error */ int bg_soft_reset(void); +/* + * is_twm_exit() + * Return true if device is booting up on TWM exit. + * value is auto cleared once read. + */ +bool is_twm_exit(void); + #endif /* BGCOM_INTERFACE_H */ diff --git a/include/uapi/linux/bgcom_interface.h b/include/uapi/linux/bgcom_interface.h index f18280a5a156..1ee7b8714018 100644 --- a/include/uapi/linux/bgcom_interface.h +++ b/include/uapi/linux/bgcom_interface.h @@ -19,6 +19,7 @@ #define BGCOM_REG_WRITE 5 #define BGCOM_SOFT_RESET 6 #define BGCOM_MODEM_DOWN2_BG 7 +#define BGCOM_TWM_EXIT 8 #define EXCHANGE_CODE 'V' struct bg_ui_data { @@ -57,6 +58,9 @@ enum bg_event_type { #define BG_SOFT_RESET \ _IOWR(EXCHANGE_CODE, BGCOM_SOFT_RESET, \ struct bg_ui_data) +#define BG_TWM_EXIT \ + _IOWR(EXCHANGE_CODE, BGCOM_TWM_EXIT, \ + struct bg_ui_data) #define BG_MODEM_DOWN2_BG_DONE \ _IOWR(EXCHANGE_CODE, BGCOM_MODEM_DOWN2_BG, \ struct bg_ui_data) -- GitLab From b600644991e7aa136c14c20cb76a5f0abf635f41 Mon Sep 17 00:00:00 2001 From: Ramesh Yadav Javadi Date: Fri, 25 May 2018 13:37:07 +0530 Subject: [PATCH 584/855] ARM: dts: msm: Avoid graceful shutdown attempt for MSM8909W When forceful shutdown flag is not defined for a PIL node, PIL framework tries to send a QMI communication for graceful shutdown of subsystem. This is not required for Blackghost subsystem, so add forceful shutdown flag. Change-Id: I0a09c6d453ba851eb509871ac292fea3343b88be Signed-off-by: Ramesh Yadav Javadi --- arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts | 1 + arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts | 1 + arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts b/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts index 1fe7b1551da3..c5b7c25a6439 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts +++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts @@ -52,6 +52,7 @@ qcom,blackghost { compatible = "qcom,pil-blackghost"; + qcom,pil-force-shutdown; qcom,firmware-name = "bg-wear"; /* GPIO inputs from blackghost */ qcom,bg2ap-status-gpio = <&msm_gpio 97 0>; diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts index 81136703dd47..5571f37a0c24 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts @@ -71,6 +71,7 @@ qcom,blackghost { compatible = "qcom,pil-blackghost"; + qcom,pil-force-shutdown; qcom,firmware-name = "bg-wear"; /* GPIO inputs from blackghost */ qcom,bg2ap-status-gpio = <&msm_gpio 97 0>; diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts index 9dd80f085c4e..f16c7a40e867 100644 --- a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts @@ -71,6 +71,7 @@ qcom,blackghost { compatible = "qcom,pil-blackghost"; + qcom,pil-force-shutdown; qcom,firmware-name = "bg-wear"; /* GPIO inputs from blackghost */ qcom,bg2ap-status-gpio = <&msm_gpio 97 0>; -- GitLab From 7346fda4d508c23c60492a77ab1d73e6ac94786d Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Tue, 24 Apr 2018 17:03:51 +0530 Subject: [PATCH 585/855] soc: qcom: Disable Blackghost interrupts before MSM is shutdown During system reboot, SSR signal from BG delays reboot of MSM. Disable Blackghost interrupt to avoid this. Change-Id: I874f033dc318b8653015bc909527411cf3645b7f Signed-off-by: Avaneesh Kumar Dwivedi Signed-off-by: Ramesh Yadav Javadi --- drivers/soc/qcom/subsys-pil-bg.c | 34 ++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/soc/qcom/subsys-pil-bg.c b/drivers/soc/qcom/subsys-pil-bg.c index 75c36667b456..6eff4bac09ff 100644 --- a/drivers/soc/qcom/subsys-pil-bg.c +++ b/drivers/soc/qcom/subsys-pil-bg.c @@ -90,9 +90,18 @@ static irqreturn_t bg_status_change(int irq, void *dev_id); static void bg_app_shutdown_notify(const struct subsys_desc *subsys) { struct pil_bg_data *bg_data = subsys_to_data(subsys); + + /* Disable irq if already BG is up */ + if (bg_data->is_ready) { + disable_irq(bg_data->status_irq); + disable_irq(bg_data->errfatal_irq); + bg_data->is_ready = false; + } /* Toggle AP2BG err fatal gpio here to inform apps err fatal event */ - if (gpio_is_valid(bg_data->gpios[2])) + if (gpio_is_valid(bg_data->gpios[2])) { + pr_debug("Sending Apps shutdown signal\n"); gpio_set_value(bg_data->gpios[2], 1); + } } /** @@ -106,9 +115,18 @@ static int bg_app_reboot_notify(struct notifier_block *nb, { struct pil_bg_data *bg_data = container_of(nb, struct pil_bg_data, reboot_blk); + + /* Disable irq if already BG is up */ + if (bg_data->is_ready) { + disable_irq(bg_data->status_irq); + disable_irq(bg_data->errfatal_irq); + bg_data->is_ready = false; + } /* Toggle AP2BG err fatal gpio here to inform apps err fatal event */ - if (gpio_is_valid(bg_data->gpios[2])) + if (gpio_is_valid(bg_data->gpios[2])) { + pr_debug("Sending reboot signal\n"); gpio_set_value(bg_data->gpios[2], 1); + } return NOTIFY_DONE; } @@ -266,7 +284,6 @@ static int bg_powerup(const struct subsys_desc *subsys) return ret; } enable_irq(bg_data->status_irq); - enable_irq(bg_data->errfatal_irq); ret = wait_for_err_ready(bg_data); if (ret) { dev_err(bg_data->desc.dev, @@ -289,10 +306,12 @@ static int bg_shutdown(const struct subsys_desc *subsys, bool force_stop) { struct pil_bg_data *bg_data = subsys_to_data(subsys); - disable_irq(bg_data->status_irq); - devm_free_irq(bg_data->desc.dev, bg_data->status_irq, bg_data); - disable_irq(bg_data->errfatal_irq); - bg_data->is_ready = false; + if (bg_data->is_ready) { + disable_irq(bg_data->status_irq); + devm_free_irq(bg_data->desc.dev, bg_data->status_irq, bg_data); + disable_irq(bg_data->errfatal_irq); + bg_data->is_ready = false; + } return 0; } @@ -586,7 +605,6 @@ static int setup_bg_gpio_irq(struct platform_device *pdev, goto err; } drvdata->errfatal_irq = irq; - enable_irq(drvdata->errfatal_irq); /* Configure outgoing GPIO's */ if (gpio_request(drvdata->gpios[2], "AP2BG_ERRFATAL")) { dev_err(&pdev->dev, -- GitLab From 305234e8c6b17121e2de11745f669544e5c973d1 Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Wed, 16 May 2018 22:02:59 +0530 Subject: [PATCH 586/855] soc: qcom: Fix blackghost SSR handling during TWM mode exit There were issues in handling of BG ramdump and SSR specially during TWM exit, as ramdump was being collected during cold boot as well. This change collect ramdump only if it is established that we are coming out of TWM mode. Also irq registration failure during SSR is fixed by this. Change-Id: Ia07c942f36fc1537b58dd62d4ca6feefbfba3921 Signed-off-by: Avaneesh Kumar Dwivedi Signed-off-by: Ramesh Yadav Javadi --- drivers/soc/qcom/pil_bg_intf.h | 2 +- drivers/soc/qcom/subsys-pil-bg.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/soc/qcom/pil_bg_intf.h b/drivers/soc/qcom/pil_bg_intf.h index 722024ba6bba..46aed2562a7b 100644 --- a/drivers/soc/qcom/pil_bg_intf.h +++ b/drivers/soc/qcom/pil_bg_intf.h @@ -36,7 +36,7 @@ __packed struct tzapp_bg_req { __packed struct tzapp_bg_rsp { uint32_t tzapp_bg_cmd; uint32_t bg_info_len; - uint32_t status; + int32_t status; uint32_t bg_info[100]; }; diff --git a/drivers/soc/qcom/subsys-pil-bg.c b/drivers/soc/qcom/subsys-pil-bg.c index 75c36667b456..a6d91b643cca 100644 --- a/drivers/soc/qcom/subsys-pil-bg.c +++ b/drivers/soc/qcom/subsys-pil-bg.c @@ -30,6 +30,7 @@ #include "peripheral-loader.h" #include "../../misc/qseecom_kernel.h" #include "pil_bg_intf.h" +#include "bgcom_interface.h" #define INVALID_GPIO -1 #define NUM_GPIOS 4 @@ -37,7 +38,7 @@ #define desc_to_data(d) container_of(d, struct pil_bg_data, desc) #define subsys_to_data(d) container_of(d, struct pil_bg_data, subsys_desc) #define BG_RAMDUMP_SZ 0x00102000 -#define BG_CRASH_IN_TWM 2 +#define BG_CRASH_IN_TWM -2 /** * struct pil_bg_data * @qseecom_handle: handle of TZ app @@ -393,7 +394,9 @@ static int bg_auth_and_xfer(struct pil_desc *pil) ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); if (bg_data->cmd_status == BG_CRASH_IN_TWM) { /* Do ramdump and resend boot cmd */ - bg_data->subsys_desc.ramdump(true, &bg_data->subsys_desc); + if (is_twm_exit()) + bg_data->subsys_desc.ramdump(true, + &bg_data->subsys_desc); bg_tz_req.tzapp_bg_cmd = BGPIL_DLOAD_CONT; ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); } @@ -524,7 +527,6 @@ static irqreturn_t bg_status_change(int irq, void *dev_id) } else if (value == false && drvdata->is_ready) { dev_err(drvdata->desc.dev, "BG got unexpected reset: irq state changed 1->0\n"); - drvdata->is_ready = false; queue_work(drvdata->bg_queue, &drvdata->restart_work); } else { dev_err(drvdata->desc.dev, -- GitLab From a557c9c14232ff2b97bca6803a940c3cb5b542c7 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Mon, 12 Mar 2018 14:20:49 +0530 Subject: [PATCH 587/855] msm: ipa2: Fix IPA kernel NULL pointer dereference Add changes to fix IPA kernel NULL pointer dereference issue Change-Id: I090d900688f13bc80616e7a3c49f7e1d6cf1be0b Acked-by: Pooja Kumari Acked-by: Ashok Vuyyuru Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v2/ipa_utils.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index d76c20821457..681b009a7128 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -72,6 +72,9 @@ static const int ipa_ihl_ofst_meq32[] = { IPA_IHL_OFFSET_MEQ32_0, #define INVALID_EP_MAPPING_INDEX (-1) +#define IPA_IS_RAN_OUT_OF_EQ(__eq_array, __eq_index) \ + (ARRAY_SIZE(__eq_array) <= (__eq_index)) + struct ipa_ep_confing { bool valid; int pipe_num; @@ -119,6 +122,7 @@ static const struct ipa_ep_confing ep_mapping[3][IPA_CLIENT_MAX] = { [IPA_2_0][IPA_CLIENT_MHI_PROD] = {true, 18}, [IPA_2_0][IPA_CLIENT_Q6_LAN_PROD] = {true, 6}, [IPA_2_0][IPA_CLIENT_Q6_CMD_PROD] = {true, 7}, + [IPA_2_0][IPA_CLIENT_MEMCPY_DMA_SYNC_PROD] = {true, 12}, [IPA_2_0][IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD] @@ -1409,6 +1413,11 @@ int ipa_generate_hw_rule(enum ipa_ip_type ip, } if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IP_TYPE) { + if (IPA_IS_RAN_OUT_OF_EQ(ipa_ihl_ofst_meq32, + ihl_ofst_meq32)) { + IPAERR("ran out of ihl_meq32 eq\n"); + return -EPERM; + } if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { IPAERR("ran out of ihl_meq32 eq\n"); return -EPERM; @@ -1426,6 +1435,11 @@ int ipa_generate_hw_rule(enum ipa_ip_type ip, } if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IPV4_DST_ADDR) { + if (IPA_IS_RAN_OUT_OF_EQ(ipa_ihl_ofst_meq32, + ihl_ofst_meq32)) { + IPAERR("ran out of ihl_meq32 eq\n"); + return -EPERM; + } if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { IPAERR("ran out of ihl_meq32 eq\n"); return -EPERM; -- GitLab From d0da75e005d4eb6b008ab06fdbad98e058d2f6fb Mon Sep 17 00:00:00 2001 From: Mulu He Date: Fri, 18 May 2018 10:35:21 +0800 Subject: [PATCH 588/855] coresight: stm: Fix null point issue in stm use-after-free over the global variable .stmdrvdata cause NULL point error. stm_register_device call fail will be deferred probe, this action will release all devm_** managed resource, so the preset stm_set_ost_params will be cleared, in this case, if any call function use the global .stmdrvdata variable will cause problem. Change-Id: I8b287389f47c0b131f26ff00eef3f4c1bb7e63cd Signed-off-by: Mulu He --- drivers/hwtracing/coresight/coresight-ost.c | 5 ++--- drivers/hwtracing/coresight/coresight-stm.c | 12 ++++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-ost.c b/drivers/hwtracing/coresight/coresight-ost.c index a5075ba53556..340c58944424 100644 --- a/drivers/hwtracing/coresight/coresight-ost.c +++ b/drivers/hwtracing/coresight/coresight-ost.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -280,14 +280,13 @@ EXPORT_SYMBOL(stm_ost_packet); int stm_set_ost_params(struct stm_drvdata *drvdata, size_t bitmap_size) { - stmdrvdata = drvdata; - drvdata->chs.bitmap = devm_kzalloc(drvdata->dev, bitmap_size, GFP_KERNEL); if (!drvdata->chs.bitmap) return -ENOMEM; bitmap_fill(drvdata->entities, OST_ENTITY_MAX); + stmdrvdata = drvdata; return 0; } diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 159512c5f342..caeda7bf37ae 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * Description: CoreSight System Trace Macrocell driver * @@ -839,11 +839,6 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id) } bitmap_size = BITS_TO_LONGS(drvdata->numsp) * sizeof(long); - /* Store the driver data pointer for use in exported functions */ - ret = stm_set_ost_params(drvdata, bitmap_size); - if (ret) - return ret; - guaranteed = devm_kzalloc(dev, bitmap_size, GFP_KERNEL); if (!guaranteed) return -ENOMEM; @@ -872,6 +867,11 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id) goto stm_unregister; } + /* Store the driver data pointer for use in exported functions */ + ret = stm_set_ost_params(drvdata, bitmap_size); + if (ret) + goto stm_unregister; + pm_runtime_put(&adev->dev); dev_info(dev, "%s initialized\n", (char *)id->data); -- GitLab From 45ba9f905c90449a1c549c30ff91dceecba94d38 Mon Sep 17 00:00:00 2001 From: Sundara Vinayagam Date: Sun, 27 May 2018 17:23:44 +0530 Subject: [PATCH 589/855] defconfig: msm: Enable RPM stats driver for LPM Enable RPM stats driver for LPM. Change-Id: Ib3c6c7d2cff979cd401e48ce9950d6a1e9f93fe8 Signed-off-by: Sundara Vinayagam --- arch/arm/configs/msm8909w-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 14ba558c176d..69dc93fe716f 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -441,6 +441,7 @@ CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_MSM_EVENT_TIMER=y +CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_BAM_DMUX=y CONFIG_MSM_GLINK_BGCOM_XPRT=y -- GitLab From a719e0fef80a3f777f7dd504a0215c8d4b2bd09e Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Mon, 28 May 2018 13:57:53 +0530 Subject: [PATCH 590/855] drivers: cpuidle: lpm-levels: Move local_irq_enable Cancelling histtimer after enabling local irqs can cause low sleep length to get calculated during next low power mode entry. Enable local irqs after cancelling histtimer. Use hrtimer_get_remaining before cancelling timer. Change-Id: I735770f779c5760acc6b62cb65811b21244d0e99 Signed-off-by: Maulik Shah --- drivers/cpuidle/lpm-levels.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 9694225f8ea8..463589a326c0 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -341,6 +341,11 @@ static void histtimer_cancel(void) { unsigned int cpu = raw_smp_processor_id(); struct hrtimer *cpu_histtimer = &per_cpu(histtimer, cpu); + ktime_t time_rem; + + time_rem = hrtimer_get_remaining(cpu_histtimer); + if (ktime_to_us(time_rem) <= 0) + return; hrtimer_try_to_cancel(cpu_histtimer); } @@ -386,11 +391,21 @@ static void clusttimer_cancel(void) { int cpu = raw_smp_processor_id(); struct lpm_cluster *cluster = per_cpu(cpu_lpm, cpu)->parent; + ktime_t time_rem; + + time_rem = hrtimer_get_remaining(&cluster->histtimer); + if (ktime_to_us(time_rem) > 0) + hrtimer_try_to_cancel(&cluster->histtimer); + + if (cluster->parent) { + time_rem = hrtimer_get_remaining( + &cluster->parent->histtimer); - hrtimer_try_to_cancel(&cluster->histtimer); + if (ktime_to_us(time_rem) <= 0) + return; - if (cluster->parent) hrtimer_try_to_cancel(&cluster->parent->histtimer); + } } static enum hrtimer_restart clusttimer_fn(struct hrtimer *h) @@ -1394,11 +1409,11 @@ static int lpm_cpuidle_enter(struct cpuidle_device *dev, dev->last_residency = ktime_us_delta(ktime_get(), start); update_history(dev, idx); trace_cpu_idle_exit(idx, success); - local_irq_enable(); if (lpm_prediction && cpu->lpm_prediction) { histtimer_cancel(); clusttimer_cancel(); } + local_irq_enable(); return idx; } -- GitLab From 0bccca6b1492cf4c00cb2a1969c9457a54b852e7 Mon Sep 17 00:00:00 2001 From: Yuan Zhao Date: Thu, 24 May 2018 18:47:04 +0800 Subject: [PATCH 591/855] drm/msm/dsi-staging: add property to set DSI channel for DCS command Some panel only support DSI1 to send DCS command, so we need to choose the right DSI channel to send DCS read command for ESD checks. Change-Id: I634013e28554acc56f6b8094ccdf1337d23c8679 Signed-off-by: Yuan Zhao Signed-off-by: Sandeep Panda --- .../devicetree/bindings/drm/msm/mdss-dsi-panel.txt | 3 +++ drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h | 12 ++++++++++++ drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 12 ++++++++++-- drivers/gpu/drm/msm/dsi-staging/dsi_panel.c | 3 +++ drivers/gpu/drm/msm/dsi-staging/dsi_panel.h | 1 + 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt index 24290c86302c..c17970c82c16 100644 --- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt @@ -521,6 +521,9 @@ Optional properties: value 0. - qcom,mdss-dsi-dma-schedule-line: An integer value indicates the line number after vertical active region, at which command DMA needs to be triggered. +- qcom,mdss-dsi-panel-cmds-only-by-right: Boolean used to mention whether the panel support DSI1 or + DSI0 to send commands. If this was set, that mean the panel only support + DSI1 to send commands, otherwise DSI0 will send comands. Required properties for sub-nodes: None Optional properties: diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h index b059fc550a3a..6ac7dd71ebf3 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h @@ -59,6 +59,18 @@ /* max size supported for dsi cmd transfer using TPG */ #define DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE 64 +/** + * enum dsi_channel_id - defines dsi channel id. + * @DSI_CTRL_LEFT: DSI 0 channel + * @DSI_CTRL_RIGHT: DSI 1 channel + * @DSI_CTRL_MAX: Maximum value. + */ +enum dsi_channel_id { + DSI_CTRL_LEFT = 0, + DSI_CTRL_RIGHT, + DSI_CTRL_MAX, +}; + /** * enum dsi_power_state - defines power states for dsi controller. * @DSI_CTRL_POWER_VREG_OFF: Digital and analog supplies for DSI controller diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index 7194f1aee24f..77e0bb3d3ebc 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -614,12 +614,20 @@ static int dsi_display_validate_status(struct dsi_display_ctrl *ctrl, static int dsi_display_status_reg_read(struct dsi_display *display) { - int rc = 0, i; + int rc = 0, i, cmd_channel_idx = DSI_CTRL_LEFT; struct dsi_display_ctrl *m_ctrl, *ctrl; pr_debug(" ++\n"); - m_ctrl = &display->ctrl[display->cmd_master_idx]; + /* + * Check the Panel DSI command channel. + * If the cmd_channel is set, then we should + * choose the right DSI(DSI1) controller to send command, + * else we choose the left(DSI0) controller. + */ + if (display->panel->esd_config.cmd_channel) + cmd_channel_idx = DSI_CTRL_RIGHT; + m_ctrl = &display->ctrl[cmd_channel_idx]; if (display->tx_cmd_buf == NULL) { rc = dsi_host_alloc_cmd_tx_buffer(display); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index cb9c1fae5aee..dab85f4fa6ee 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -2776,6 +2776,9 @@ int dsi_panel_parse_esd_reg_read_configs(struct dsi_panel *panel, esd_config->groups * status_len); } + esd_config->cmd_channel = of_property_read_bool(of_node, + "qcom,mdss-dsi-panel-cmds-only-by-right"); + return 0; error4: diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h index f8b65abb2279..c0ecb7ffb684 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h @@ -129,6 +129,7 @@ enum esd_check_status_mode { struct drm_panel_esd_config { bool esd_enabled; + bool cmd_channel; enum esd_check_status_mode status_mode; struct dsi_panel_cmd_set status_cmd; -- GitLab From d4d8538d4a2edaf50b76bfffbe5dc7c020f70850 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Thu, 24 May 2018 14:44:26 +0530 Subject: [PATCH 592/855] phy-msm-qusb-v2: Add debugfs support for changing BIAS_CTRL2 value Add debugfs support for changing value of BIAS_CTRL2 register for tuning eye-diagram at run time. Change-Id: I8214d623d2cce994995baae721b0665243e299c8 Signed-off-by: Vijayavardhan Vennapusa --- drivers/usb/phy/phy-msm-qusb-v2.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index e28173b13222..33a7f6afcccf 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -149,6 +149,7 @@ struct qusb_phy { /* override TUNEX registers value */ struct dentry *root; u8 tune[5]; + u8 bias_ctrl2; struct hrtimer timer; int soc_min_rev; @@ -494,6 +495,10 @@ static void qusb_phy_host_init(struct usb_phy *phy) writel_relaxed(BIAS_CTRL_2_OVERRIDE_VAL, qphy->base + qphy->phy_reg[BIAS_CTRL_2]); + if (qphy->bias_ctrl2) + writel_relaxed(qphy->bias_ctrl2, + qphy->base + qphy->phy_reg[BIAS_CTRL_2]); + /* Ensure above write is completed before turning ON ref clk */ wmb(); @@ -585,6 +590,10 @@ static int qusb_phy_init(struct usb_phy *phy) writel_relaxed(BIAS_CTRL_2_OVERRIDE_VAL, qphy->base + qphy->phy_reg[BIAS_CTRL_2]); + if (qphy->bias_ctrl2) + writel_relaxed(qphy->bias_ctrl2, + qphy->base + qphy->phy_reg[BIAS_CTRL_2]); + /* ensure above writes are completed before re-enabling PHY */ wmb(); @@ -946,11 +955,21 @@ static int qusb_phy_create_debugfs(struct qusb_phy *qphy) dev_err(qphy->phy.dev, "can't create debugfs entry for %s\n", name); debugfs_remove_recursive(qphy->root); - ret = ENOMEM; + ret = -ENOMEM; goto create_err; } } + file = debugfs_create_x8("bias_ctrl2", 0644, qphy->root, + &qphy->bias_ctrl2); + if (IS_ERR_OR_NULL(file)) { + dev_err(qphy->phy.dev, + "can't create debugfs entry for bias_ctrl2\n"); + debugfs_remove_recursive(qphy->root); + ret = -ENOMEM; + goto create_err; + } + create_err: return ret; } -- GitLab From 3a23897323ee19bd56d63470feaad30a5e112dd0 Mon Sep 17 00:00:00 2001 From: Yuan Zhao Date: Thu, 24 May 2018 18:37:50 +0800 Subject: [PATCH 593/855] ARM: dts: msm: add property for DSI trigger channel on SDM670 On SDM670 platform nt36850 panel only supports sending commands from DSI1(right side) controller. Add a property to mention the same. Change-Id: I88558f615a08b6881be7c778beadb019565e0835 Signed-off-by: Yuan Zhao --- arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi index 48deca6aecc5..5579dabcd847 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi @@ -858,6 +858,7 @@ qcom,mdss-dsi-panel-status-value = <0x9c>; qcom,mdss-dsi-panel-on-check-value = <0x9c>; qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-cmds-only-by-right; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 23 08 -- GitLab From ca13a0ce9d354a5eb3c68a7e4d6451ba3cd5c9ae Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Mon, 28 May 2018 11:44:26 +0530 Subject: [PATCH 594/855] ARM: dts: msm: Add PMI632 GPIO configuration for parallel-current sense The parallel charger's current is sensed by the external-sense over GPIO7/GPIO8 of PMI632. Add pinctrl configuration for these GPIOs to disable them. Change-Id: I348b69467103c6b953c518ae807e5d07ca3c877a Signed-off-by: Anirudh Ghayal --- arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi | 13 +++++++++++-- arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi | 13 +++++++++++-- arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi | 13 +++++++++++-- arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi | 13 +++++++++++-- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi index 9a9603d03f7d..0336d8255c4a 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi @@ -241,6 +241,15 @@ output-enable; }; }; + + pmi632_sense { + /* GPIO 7 and 8 are external-sense pins for PMI632 */ + pmi632_sense_default: pmi632_sense_default { + pins = "gpio7", "gpio8"; + bias-high-impedance; /* disable the GPIO */ + bias-disable; /* no-pull */ + }; + }; }; &tlmm { @@ -261,7 +270,7 @@ &smb1355_0 { pinctrl-names = "default"; pinctrl-0 = <&smb_int_default - &smb_en_default>; + &smb_en_default &pmi632_sense_default>; interrupt-parent = <&tlmm>; interrupts = <59 IRQ_TYPE_LEVEL_LOW>; smb1355_charger_0: qcom,smb1355-charger@1000 { @@ -275,7 +284,7 @@ &smb1355_1 { pinctrl-names = "default"; pinctrl-0 = <&smb_int_default - &smb_en_default>; + &smb_en_default &pmi632_sense_default>; interrupt-parent = <&tlmm>; interrupts = <59 IRQ_TYPE_LEVEL_LOW>; smb1355_charger_1: qcom,smb1355-charger@1000 { diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi index 5662e1770fbf..5097b7f5ea58 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi @@ -338,6 +338,15 @@ output-enable; }; }; + + pmi632_sense { + /* GPIO 7 and 8 are external-sense pins for PMI632 */ + pmi632_sense_default: pmi632_sense_default { + pins = "gpio7", "gpio8"; + bias-high-impedance; /* disable the GPIO */ + bias-disable; /* no-pull */ + }; + }; }; &tlmm { @@ -358,7 +367,7 @@ &smb1355_0 { pinctrl-names = "default"; pinctrl-0 = <&smb_int_default - &smb_en_default>; + &smb_en_default &pmi632_sense_default>; interrupt-parent = <&tlmm>; interrupts = <59 IRQ_TYPE_LEVEL_LOW>; smb1355_charger_0: qcom,smb1355-charger@1000 { @@ -372,7 +381,7 @@ &smb1355_1 { pinctrl-names = "default"; pinctrl-0 = <&smb_int_default - &smb_en_default>; + &smb_en_default &pmi632_sense_default>; interrupt-parent = <&tlmm>; interrupts = <59 IRQ_TYPE_LEVEL_LOW>; smb1355_charger_1: qcom,smb1355-charger@1000 { diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi index 265a86d39d80..07d2e08db67d 100644 --- a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi @@ -59,6 +59,15 @@ output-enable; }; }; + + pmi632_sense { + /* GPIO 7 and 8 are external-sense pins for PMI632 */ + pmi632_sense_default: pmi632_sense_default { + pins = "gpio7", "gpio8"; + bias-high-impedance; /* disable the GPIO */ + bias-disable; /* no-pull */ + }; + }; }; &tlmm { @@ -79,7 +88,7 @@ &smb1355_0 { pinctrl-names = "default"; pinctrl-0 = <&smb_int_default - &smb_en_default>; + &smb_en_default &pmi632_sense_default>; interrupt-parent = <&tlmm>; interrupts = <59 IRQ_TYPE_LEVEL_LOW>; smb1355_charger_0: qcom,smb1355-charger@1000 { @@ -93,7 +102,7 @@ &smb1355_1 { pinctrl-names = "default"; pinctrl-0 = <&smb_int_default - &smb_en_default>; + &smb_en_default &pmi632_sense_default>; interrupt-parent = <&tlmm>; interrupts = <59 IRQ_TYPE_LEVEL_LOW>; smb1355_charger_1: qcom,smb1355-charger@1000 { diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi index c5eff7b49c67..a2bd5cdd49e2 100644 --- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi @@ -189,6 +189,15 @@ output-enable; }; }; + + pmi632_sense { + /* GPIO 7 and 8 are external-sense pins for PMI632 */ + pmi632_sense_default: pmi632_sense_default { + pins = "gpio7", "gpio8"; + bias-high-impedance; /* disable the GPIO */ + bias-disable; /* no-pull */ + }; + }; }; &tlmm { @@ -209,7 +218,7 @@ &smb1355_0 { pinctrl-names = "default"; pinctrl-0 = <&smb_int_default - &smb_en_default>; + &smb_en_default &pmi632_sense_default>; interrupt-parent = <&tlmm>; interrupts = <59 IRQ_TYPE_LEVEL_LOW>; smb1355_charger_0: qcom,smb1355-charger@1000 { @@ -223,7 +232,7 @@ &smb1355_1 { pinctrl-names = "default"; pinctrl-0 = <&smb_int_default - &smb_en_default>; + &smb_en_default &pmi632_sense_default>; interrupt-parent = <&tlmm>; interrupts = <59 IRQ_TYPE_LEVEL_LOW>; smb1355_charger_1: qcom,smb1355-charger@1000 { -- GitLab From 30acd46016bc85725380ad23fa55846379de0c08 Mon Sep 17 00:00:00 2001 From: Sachin Grover Date: Mon, 28 May 2018 12:15:55 +0530 Subject: [PATCH 595/855] defconfig: Add Security config to enhance security Add HARDENED_USERCOPY AND Set loadable kernel module data as NX and text as RO. Change-Id: I100f09b8a6ffbc9658854bda6e34039c08ab1c3e Signed-off-by: Sachin Grover --- arch/arm/configs/sdxpoorwills-perf_defconfig | 2 ++ arch/arm/configs/sdxpoorwills_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig index 04a1e5b3a16c..7d05b9059b6c 100644 --- a/arch/arm/configs/sdxpoorwills-perf_defconfig +++ b/arch/arm/configs/sdxpoorwills-perf_defconfig @@ -411,6 +411,7 @@ CONFIG_SCHED_STACK_END_CHECK=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_IPC_LOGGING=y CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 @@ -422,6 +423,7 @@ CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y +CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y # CONFIG_SECURITY_SELINUX_AVC_STATS is not set CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig index f2f59451aed2..6f715769fc7c 100644 --- a/arch/arm/configs/sdxpoorwills_defconfig +++ b/arch/arm/configs/sdxpoorwills_defconfig @@ -431,6 +431,7 @@ CONFIG_IRQSOFF_TRACER=y CONFIG_PREEMPT_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_DEBUG_USER=y +CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y CONFIG_CORESIGHT_SOURCE_ETM3X=y @@ -447,6 +448,7 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y +CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y # CONFIG_SECURITY_SELINUX_AVC_STATS is not set CONFIG_CRYPTO_CMAC=y -- GitLab From 495ff45e9c64cca9223a9bcc1eda4cbb55fd2085 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Tue, 22 May 2018 11:32:48 +0530 Subject: [PATCH 596/855] mmc: card: Set INLINECRYPT queue flag based on host capability Set INLINECRYPT queue flag if the host can support h/w based inline encryption. This is needed to let the filesystem know that underlying storage device can support inline encryption so that data encryption/ decryption would be handled at h/w level, not at filesystem. Change-Id: Iad029439b0867d5bfbd04e2474a71421ab3f3cf4 Signed-off-by: Veerabhadrarao Badiganti --- drivers/mmc/card/queue.c | 5 +++++ include/linux/mmc/host.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index aa8373da92f2..66165d979173 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -314,6 +314,8 @@ void mmc_cmdq_setup_queue(struct mmc_queue *mq, struct mmc_card *card) host->max_req_size / 512)); blk_queue_max_segment_size(mq->queue, host->max_seg_size); blk_queue_max_segments(mq->queue, host->max_segs); + if (host->inlinecrypt_support) + queue_flag_set_unlocked(QUEUE_FLAG_INLINECRYPT, mq->queue); } /** @@ -483,6 +485,9 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, success: sema_init(&mq->thread_sem, 1); + if (host->inlinecrypt_support) + queue_flag_set_unlocked(QUEUE_FLAG_INLINECRYPT, mq->queue); + /* hook for pm qos legacy init */ if (card->host->ops->init) card->host->ops->init(card->host); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 7228bcd24ad5..9a20d3c16b86 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -652,6 +652,8 @@ struct mmc_host { void *cmdq_private; struct mmc_request *err_mrq; + bool inlinecrypt_support; /* Inline encryption support */ + atomic_t rpmb_req_pending; struct mutex rpmb_req_mutex; unsigned long private[0] ____cacheline_aligned; -- GitLab From fe3088f6a9399dd3cc9643bbd4ee7bacd409ce02 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Tue, 22 May 2018 11:48:01 +0530 Subject: [PATCH 597/855] mmc: msm-host: Set inline-crypto support host flag Set inline-crypto support host flag if sdhc controller is capable do performing inline encryption/decryption. Change-Id: I72a0443ad44f550aa49dbd558a378eaa63377166 Signed-off-by: Veerabhadrarao Badiganti --- drivers/mmc/host/sdhci-msm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index d91eb679e787..7d242133528d 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -5075,6 +5075,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) goto vreg_deinit; } host->is_crypto_en = true; + msm_host->mmc->inlinecrypt_support = true; /* Packed commands cannot be encrypted/decrypted using ICE */ msm_host->mmc->caps2 &= ~(MMC_CAP2_PACKED_WR | MMC_CAP2_PACKED_WR_CONTROL); -- GitLab From 775d0e9c44270810a999be1acd4f4e802c5dc195 Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Tue, 29 May 2018 10:19:09 +0530 Subject: [PATCH 598/855] memshare: Conditional free the clients allotted memory The patch adds an additional check to not free the clients memory if the client has a designated property of allocate-on-request. Change-Id: Iecf5886034ccd052ab82fff18cc66f1868604284 Signed-off-by: Manoj Prabhu B --- drivers/soc/qcom/memshare/msm_memshare.c | 20 +++++++++++++------- drivers/soc/qcom/memshare/msm_memshare.h | 2 ++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c index 696c043d8de4..6542861a2f48 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.c +++ b/drivers/soc/qcom/memshare/msm_memshare.c @@ -406,6 +406,7 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, memblock[i].peripheral == DHMS_MEM_PROC_MPSS_V01 && !memblock[i].guarantee && + !memblock[i].client_request && memblock[i].allotted && !memblock[i].alloc_request) { pr_debug("memshare: hypervisor unmapping for client id: %d\n", @@ -665,9 +666,10 @@ static int handle_free_generic_req(void *req_h, void *req, void *conn_h) __func__); flag = 1; } else if (!memblock[client_id].guarantee && - memblock[client_id].allotted) { - pr_debug("memshare: %s: size: %d", - __func__, memblock[client_id].size); + !memblock[client_id].client_request && + memblock[client_id].allotted) { + pr_debug("memshare: %s:client_id:%d - size: %d", + __func__, client_id, memblock[client_id].size); ret = hyp_assign_phys(memblock[client_id].phy_addr, memblock[client_id].size, source_vmlist, 1, dest_vmids, dest_perms, 1); @@ -676,8 +678,8 @@ static int handle_free_generic_req(void *req_h, void *req, void *conn_h) * This is an error case as hyp mapping was successful * earlier but during unmap it lead to failure. */ - pr_err("memshare: %s, failed to unmap the region\n", - __func__); + pr_err("memshare: %s, failed to unmap the region for client id:%d\n", + __func__, client_id); } size = memblock[client_id].size; if (memblock[client_id].client_id == 1) { @@ -696,8 +698,8 @@ static int handle_free_generic_req(void *req_h, void *req, void *conn_h) attrs); free_client(client_id); } else { - pr_err("memshare: %s, Request came for a guaranteed client cannot free up the memory\n", - __func__); + pr_err("memshare: %s, Request came for a guaranteed client (client_id: %d) cannot free up the memory\n", + __func__, client_id); } if (flag) { @@ -992,6 +994,10 @@ static int memshare_child_probe(struct platform_device *pdev) pdev->dev.of_node, "qcom,allocate-boot-time"); + memblock[num_clients].client_request = of_property_read_bool( + pdev->dev.of_node, + "qcom,allocate-on-request"); + rc = of_property_read_string(pdev->dev.of_node, "label", &name); if (rc) { diff --git a/drivers/soc/qcom/memshare/msm_memshare.h b/drivers/soc/qcom/memshare/msm_memshare.h index 6b546528404c..908f091c86eb 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.h +++ b/drivers/soc/qcom/memshare/msm_memshare.h @@ -41,6 +41,8 @@ struct mem_blocks { uint32_t allotted; /* Memory allocation request received or not */ uint32_t alloc_request; + /* Allocation on request from a client*/ + uint32_t client_request; /* Size required for client */ uint32_t size; /* -- GitLab From 5eca0c93b9b9251871062be89a9216ebc557e69e Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Thu, 24 May 2018 19:24:04 +0530 Subject: [PATCH 599/855] ARM: dts: msm: Update GPU bandwidth voting for SDM632 Update the bandwidth voting for GPU min. and low SVS frequency corners. This is needed to improve performance of few use cases. Change-Id: I1aaabd8fe4d00bff9d40056bde9bb0bbdb05d9ee Signed-off-by: Deepak Kumar --- arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi | 6 +++--- arch/arm64/boot/dts/qcom/sdm632.dtsi | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi b/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi index f82b68da03c3..14c4d2b6a24e 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi @@ -231,8 +231,8 @@ qcom,gpu-pwrlevel@5 { reg = <5>; qcom,gpu-freq = <216000000>; - qcom,bus-freq = <1>; - qcom,bus-min = <1>; + qcom,bus-freq = <3>; + qcom,bus-min = <2>; qcom,bus-max = <4>; }; @@ -240,7 +240,7 @@ qcom,gpu-pwrlevel@6 { reg = <6>; qcom,gpu-freq = <133300000>; - qcom,bus-freq = <1>; + qcom,bus-freq = <3>; qcom,bus-min = <1>; qcom,bus-max = <4>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi index cc6b1a359a4b..40a1de0f217f 100644 --- a/arch/arm64/boot/dts/qcom/sdm632.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi @@ -1077,15 +1077,15 @@ qcom,gpu-pwrlevel@6 { reg = <6>; qcom,gpu-freq = <216000000>; - qcom,bus-freq = <1>; - qcom,bus-min = <1>; + qcom,bus-freq = <3>; + qcom,bus-min = <2>; qcom,bus-max = <4>; }; qcom,gpu-pwrlevel@7 { reg = <7>; qcom,gpu-freq = <133300000>; - qcom,bus-freq = <1>; + qcom,bus-freq = <3>; qcom,bus-min = <1>; qcom,bus-max = <4>; }; -- GitLab From a617b267c96e08dbec17fa630ee236d5e2a4a5e6 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Mon, 19 Mar 2018 16:55:00 +0530 Subject: [PATCH 600/855] msm: ipa: Set ep delay on USB_PROD ep During SSR, set ep delay on USB_PROD ep for RMNET/MBIM config to avoid USB pushing data towards IPA. Change-Id: I51b7048f42fd393110f90939b67354006eb1411f Signed-off-by: Mohammed Javid --- .../platform/msm/ipa/ipa_clients/ipa_usb.c | 31 ++++++ drivers/platform/msm/ipa/ipa_v3/ipa.c | 2 + drivers/platform/msm/ipa/ipa_v3/ipa_client.c | 103 ++++++++++++++++++ drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 7 ++ 4 files changed, 143 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c index d9e3ab9d2fcc..c7df5cf39808 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c @@ -2153,6 +2153,18 @@ static void ipa_usb_debugfs_init(void){} static void ipa_usb_debugfs_remove(void){} #endif /* CONFIG_DEBUG_FS */ +static int ipa_usb_set_lock_unlock(bool is_lock) +{ + IPA_USB_DBG("entry\n"); + if (is_lock) + mutex_lock(&ipa3_usb_ctx->general_mutex); + else + mutex_unlock(&ipa3_usb_ctx->general_mutex); + IPA_USB_DBG("exit\n"); + + return 0; +} + int ipa_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params, @@ -2216,6 +2228,16 @@ int ipa_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params, goto connect_fail; } + /* + * Register for xdci lock/unlock callback with ipa core driver. + * As per use case, only register for IPA_CONS end point for now. + * If needed we can include the same for IPA_PROD ep. + * For IPA_USB_DIAG/DPL config there will not be any UL ep. + */ + if (connect_params->teth_prot != IPA_USB_DIAG) + ipa3_register_lock_unlock_callback(&ipa_usb_set_lock_unlock, + ul_out_params->clnt_hdl); + IPA_USB_DBG_LOW("exit\n"); mutex_unlock(&ipa3_usb_ctx->general_mutex); return 0; @@ -2293,6 +2315,15 @@ static int ipa_usb_xdci_dismiss_channels(u32 ul_clnt_hdl, u32 dl_clnt_hdl, } } + /* + * Deregister for xdci lock/unlock callback from ipa core driver. + * As per use case, only deregister for IPA_CONS end point for now. + * If needed we can include the same for IPA_PROD ep. + * For IPA_USB_DIAG/DPL config there will not be any UL config. + */ + if (!IPA3_USB_IS_TTYPE_DPL(ttype)) + ipa3_deregister_lock_unlock_callback(ul_clnt_hdl); + /* Change state to STOPPED */ if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype)) IPA_USB_ERR("failed to change state to stopped\n"); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index bd82aa9e4d3c..d64f89b375be 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -2507,6 +2507,8 @@ void ipa3_q6_pre_shutdown_cleanup(void) */ ipa3_q6_pipe_delay(false); + ipa3_set_usb_prod_pipe_delay(); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); IPADBG_LOW("Exit with success\n"); } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index fe39440eed79..5bcd49ec24bf 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -635,6 +635,69 @@ int ipa3_smmu_map_peer_buff(u64 iova, u32 size, bool map, struct sg_table *sgt, return 0; } +void ipa3_register_lock_unlock_callback(int (*client_cb)(bool is_lock), + u32 ipa_ep_idx) +{ + struct ipa3_ep_context *ep; + + IPADBG("entry\n"); + + ep = &ipa3_ctx->ep[ipa_ep_idx]; + + if (!ep->valid) { + IPAERR("Invalid EP\n"); + return; + } + + if (client_cb == NULL) { + IPAERR("Bad Param"); + return; + } + + ep->client_lock_unlock = client_cb; + IPADBG("exit\n"); +} + +void ipa3_deregister_lock_unlock_callback(u32 ipa_ep_idx) +{ + struct ipa3_ep_context *ep; + + IPADBG("entry\n"); + + ep = &ipa3_ctx->ep[ipa_ep_idx]; + + if (!ep->valid) { + IPAERR("Invalid EP\n"); + return; + } + + if (ep->client_lock_unlock == NULL) { + IPAERR("client_lock_unlock is already NULL"); + return; + } + + ep->client_lock_unlock = NULL; + IPADBG("exit\n"); +} + +static void client_lock_unlock_cb(u32 ipa_ep_idx, bool is_lock) +{ + struct ipa3_ep_context *ep; + + IPADBG("entry\n"); + + ep = &ipa3_ctx->ep[ipa_ep_idx]; + + if (!ep->valid) { + IPAERR("Invalid EP\n"); + return; + } + + if (ep->client_lock_unlock) + ep->client_lock_unlock(is_lock); + + IPADBG("exit\n"); +} int ipa3_request_gsi_channel(struct ipa_request_gsi_channel_params *params, struct ipa_req_chan_out_params *out_params) @@ -1259,6 +1322,46 @@ static int ipa3_stop_ul_chan_with_data_drain(u32 qmi_req_id, return result; } +/* + * Set USB PROD pipe delay for MBIM/RMNET config + * Clocks, should be voted before calling this API + * locks should be taken before calling this API + */ + +void ipa3_set_usb_prod_pipe_delay(void) +{ + int result; + int pipe_idx; + struct ipa3_ep_context *ep; + struct ipa_ep_cfg_ctrl ep_ctrl; + + memset(&ep_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl)); + ep_ctrl.ipa_ep_delay = true; + + + pipe_idx = ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD); + + if (pipe_idx == IPA_EP_NOT_ALLOCATED) { + IPAERR("client (%d) not valid\n", IPA_CLIENT_USB_PROD); + return; + } + + ep = &ipa3_ctx->ep[pipe_idx]; + + /* Setting delay on USB_PROD with skip_ep_cfg */ + client_lock_unlock_cb(pipe_idx, true); + if (ep->valid && ep->skip_ep_cfg) { + ep->ep_delay_set = ep_ctrl.ipa_ep_delay; + result = ipa3_cfg_ep_ctrl(pipe_idx, &ep_ctrl); + if (result) + IPAERR("client (ep: %d) failed result=%d\n", + pipe_idx, result); + else + IPADBG("client (ep: %d) success\n", pipe_idx); + } + client_lock_unlock_cb(pipe_idx, false); +} + void ipa3_xdci_ep_delay_rm(u32 clnt_hdl) { struct ipa3_ep_context *ep; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index fe649a7c8dbf..268f5fadddf9 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -740,6 +740,8 @@ struct ipa3_status_stats { * @qmi_request_sent: Indicates whether QMI request to enable clear data path * request is sent or not. * @napi_enabled: when true, IPA call client callback to start polling + * @client_lock_unlock: callback function to take mutex lock/unlock for USB + * clients */ struct ipa3_ep_context { int valid; @@ -772,6 +774,8 @@ struct ipa3_ep_context { u32 eot_in_poll_err; bool ep_delay_set; + int (*client_lock_unlock)(bool is_lock); + /* sys MUST be the last element of this struct */ struct ipa3_sys_context *sys; }; @@ -1914,6 +1918,9 @@ int ipa3_xdci_connect(u32 clnt_hdl); int ipa3_xdci_disconnect(u32 clnt_hdl, bool should_force_clear, u32 qmi_req_id); void ipa3_xdci_ep_delay_rm(u32 clnt_hdl); +void ipa3_register_lock_unlock_callback(int (*client_cb)(bool), u32 ipa_ep_idx); +void ipa3_deregister_lock_unlock_callback(u32 ipa_ep_idx); +void ipa3_set_usb_prod_pipe_delay(void); int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, bool should_force_clear, u32 qmi_req_id, bool is_dpl); -- GitLab From 483f90a2bd239a56a9fb4e8a43714d0769e0ce09 Mon Sep 17 00:00:00 2001 From: Vishwanath Raju K Date: Tue, 29 May 2018 13:38:37 +0530 Subject: [PATCH 601/855] ARM:dts:msm: update memory map for apq8009 Increase externel_image_mem size to 7MB from 6MB for APQ8009 based apq8009-robot-som-refboard platform. Change-Id: Icb421f4795e4f1d15e94d11944332613c6d10a0c Signed-off-by: Vishwanath Raju K --- arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts b/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts index 3e4cbca7f738..13141291fc8d 100644 --- a/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts +++ b/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts @@ -164,7 +164,7 @@ }; &external_image_mem { - reg = <0x0 0x87a00000 0x0 0x0600000>; + reg = <0x0 0x87900000 0x0 0x0700000>; }; &modem_adsp_mem { @@ -172,7 +172,7 @@ }; &peripheral_mem { - reg = <0x0 0x89e00000 0x0 0x0700000>; + status = "disabled"; }; &pm8916_chg { -- GitLab From 4ef55a07e000a43309b38229e86501add907ef74 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Tue, 29 May 2018 15:02:25 +0530 Subject: [PATCH 602/855] usb: gadget: ci13xxx: Do not clear USBCMD_SESS_VLD_CTRL on disconnect Clearing the bit SESS_VLD_CTRL of the USBCMD register on cable disconnect leads to leakage current in PHY if the USB regulators are still ON. Avoid this issue by not clearing the bit on USB cable disconnect. Change-Id: I67ec52ba95f31d5c108256b248f08a2c8ab60c23 Signed-off-by: Ajay Agarwal --- drivers/usb/gadget/ci13xxx_msm.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c index d4c243c2fa2f..42936f16df02 100644 --- a/drivers/usb/gadget/ci13xxx_msm.c +++ b/drivers/usb/gadget/ci13xxx_msm.c @@ -70,18 +70,11 @@ static void ci13xxx_msm_disconnect(void) struct usb_phy *phy = udc->transceiver; if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP)) { - u32 temp; - usb_phy_io_write(phy, ULPI_MISC_A_VBUSVLDEXT | ULPI_MISC_A_VBUSVLDEXTSEL, ULPI_CLR(ULPI_MISC_A)); - /* Notify LINK of VBUS LOW */ - temp = readl_relaxed(USB_USBCMD); - temp &= ~USBCMD_SESS_VLD_CTRL; - writel_relaxed(temp, USB_USBCMD); - /* * Add memory barrier as it is must to complete * above USB PHY and Link register writes before -- GitLab From cd9016e148078a6df1452a3de60c6eeea4787e84 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Tue, 15 May 2018 13:27:26 +0530 Subject: [PATCH 603/855] msm: ipa: Add support to get current ipa clock vote from apps Add support to get current ipa clk_rate vote via debugfs. Change-Id: Ia3590211f4ce6d29f10f8a2701d56a6ae0f30397 Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index dc5f5e0037aa..4751c75db38d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -2291,6 +2291,13 @@ void ipa3_debugfs_init(void) goto fail; } + file = debugfs_create_u32("clk_rate", IPA_READ_ONLY_MODE, + dent, &ipa3_ctx->curr_ipa_clk_rate); + if (!file) { + IPAERR("could not create clk_rate file\n"); + goto fail; + } + ipa_debugfs_init_stats(dent); return; -- GitLab From d5022b69ae105b35ce9775cabc660f0c25103309 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Sun, 27 May 2018 19:21:11 +0530 Subject: [PATCH 604/855] power: smb5: update VCONN control for PMI632 based platform PMI632 based platform does not support PD, thus keep VCONN control(enable/disable) in hardware mode(charger hardware will automatically turn-on VCONN for typeC cable with Ra present on one of the CC line). Change-Id: I064ec1dac368ee481229880b8909a15cc5dfaeaa Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/qpnp-smb5.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 8ff5330dca66..3ff80a9cb2f1 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1491,14 +1491,18 @@ static int smb5_configure_typec(struct smb_charger *chg) return rc; } - /* configure VCONN for software control */ - rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG, + /* Keep VCONN in h/w controlled mode for PMI632 */ + if (chg->smb_version != PMI632_SUBTYPE) { + /* configure VCONN for software control */ + rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG, VCONN_EN_SRC_BIT | VCONN_EN_VALUE_BIT, VCONN_EN_SRC_BIT); - if (rc < 0) { - dev_err(chg->dev, - "Couldn't configure VCONN for SW control rc=%d\n", rc); - return rc; + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure VCONN for SW control rc=%d\n", + rc); + return rc; + } } return rc; -- GitLab From 39d8c94cac3d0b3a8f11f0d30981eafcf0a63535 Mon Sep 17 00:00:00 2001 From: Ravi Kishore Tanuku Date: Tue, 29 May 2018 16:13:28 +0530 Subject: [PATCH 605/855] msm: camera: Reset the csiphy params in device release Reset the csi phy parameters to avoid using obsolete data in the subsequent configurations. Disable skew calibration setting in combo mode settings. Change-Id: I23ec8d8c0ae7264571de468ecaa5a60c85b47d7f Signed-off-by: Ravi Kishore Tanuku --- .../cam_sensor_module/cam_csiphy/cam_csiphy_core.c | 7 +++++++ .../cam_csiphy/include/cam_csiphy_1_0_hwreg.h | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index dbbac08a5879..2688cd57db89 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -614,6 +614,13 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, if (csiphy_dev->acquire_count == 0) csiphy_dev->csiphy_state = CAM_CSIPHY_INIT; + + if (csiphy_dev->config_count == 0) { + CAM_DBG(CAM_CSIPHY, "reset csiphy_info"); + csiphy_dev->csiphy_info.lane_mask = 0; + csiphy_dev->csiphy_info.lane_cnt = 0; + csiphy_dev->csiphy_info.combo_mode = 0; + } } break; case CAM_CONFIG_DEV: { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h index 3f743fca3ea6..324509340054 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h @@ -152,7 +152,7 @@ struct csiphy_reg_t {0x0008, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0060, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -168,7 +168,7 @@ struct csiphy_reg_t {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0760, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -183,7 +183,7 @@ struct csiphy_reg_t {0x0208, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0260, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -198,7 +198,7 @@ struct csiphy_reg_t {0x0408, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0460, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -214,7 +214,7 @@ struct csiphy_reg_t {0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0660, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; -- GitLab From b62fd6e6274e10f3d44392871ce7e7c195aa48c0 Mon Sep 17 00:00:00 2001 From: Padmanabhan Komanduru Date: Wed, 16 May 2018 15:38:51 +0530 Subject: [PATCH 606/855] drm/msm/dp: check for sink count before enabling post_open callback When the DP cable is disconnected at the sink side with the type-C cable connected to the device, some dongles retain the hpd_high variable to 'true' but change the sink count to zero as part of the attention callback. Check for sink count reported by the dongle in addition to hpd_high status variable before enabling post_open callback during DP disable sequence. Change-Id: I002d039f79543eb6176df2eb2b6c648f586be429 Signed-off-by: Padmanabhan Komanduru --- drivers/gpu/drm/msm/dp/dp_display.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 3e5cdc658306..1b92261f675f 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1182,7 +1182,8 @@ static int dp_display_pre_disable(struct dp_display *dp_display) dp->hdcp.ops->off(dp->hdcp.data); } - if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done) { + if (dp->usbpd->hpd_high && !dp_display_is_sink_count_zero(dp) && + dp->usbpd->alt_mode_cfg_done) { if (dp->audio_supported) dp->audio->off(dp->audio); @@ -1235,7 +1236,8 @@ static int dp_display_disable(struct dp_display *dp_display) * any notification from driver. Initialize post_open callback to notify * DP connection once framework restarts. */ - if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done) + if (dp->usbpd->hpd_high && !dp_display_is_sink_count_zero(dp) && + dp->usbpd->alt_mode_cfg_done) dp_display->post_open = dp_display_post_open; dp->power_on = false; -- GitLab From 3d515b80f07cd5b5fedee7408fb91720c6f361ba Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Fri, 6 Apr 2018 16:01:04 -0700 Subject: [PATCH 607/855] power: smb2: Handle QC2.0 charger collapse gracefully Adaptors that are non-compliant with QC2.0 are incapable of fulfilling either a 9V or 12V request. In such cases, when the SMB5 makes such a request, USB input collapse occurs - leading to an under-voltage situation and suspension of the charger buck. Fix this by by limiting the adaptor to a lower level, 5V or 9V correspondingly. Change-Id: Ib0d1fc025f34f87506cb351bc9169cac42f4d61d Signed-off-by: Harry Yang Signed-off-by: Guru Das Srinagesh --- drivers/power/supply/qcom/smb-lib.c | 54 +++++++++++++++++++++++++++++ drivers/power/supply/qcom/smb-lib.h | 4 ++- drivers/power/supply/qcom/smb-reg.h | 11 +++++- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 39005f61a0b8..86f6638ae950 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -3445,6 +3445,9 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data) struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; struct storm_watch *wdata; + const struct apsd_result *apsd = smblib_get_apsd_result(chg); + int rc; + u8 stat = 0, max_pulses = 0; smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data) @@ -3452,6 +3455,46 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data) wdata = &chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data->storm_data; reset_storm_count(wdata); + + if (!chg->non_compliant_chg_detected && + apsd->pst == POWER_SUPPLY_TYPE_USB_HVDCP) { + rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat); + if (rc < 0) + smblib_err(chg, + "Couldn't read CHANGE_STATUS_REG rc=%d\n", rc); + + if (stat & QC_5V_BIT) + return IRQ_HANDLED; + + rc = smblib_read(chg, HVDCP_PULSE_COUNT_MAX_REG, &max_pulses); + if (rc < 0) + smblib_err(chg, + "Couldn't read QC2 max pulses rc=%d\n", rc); + + chg->non_compliant_chg_detected = true; + chg->qc2_max_pulses = (max_pulses & + HVDCP_PULSE_COUNT_MAX_QC2_MASK); + + if (stat & QC_12V_BIT) { + rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG, + HVDCP_PULSE_COUNT_MAX_QC2_MASK, + HVDCP_PULSE_COUNT_MAX_QC2_9V); + if (rc < 0) + smblib_err(chg, "Couldn't force max pulses to 9V rc=%d\n", + rc); + + } else if (stat & QC_9V_BIT) { + rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG, + HVDCP_PULSE_COUNT_MAX_QC2_MASK, + HVDCP_PULSE_COUNT_MAX_QC2_5V); + if (rc < 0) + smblib_err(chg, "Couldn't force max pulses to 5V rc=%d\n", + rc); + + } + smblib_rerun_apsd(chg); + } + return IRQ_HANDLED; } @@ -4270,6 +4313,17 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) if (rc < 0) smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc); + /* if non-compliant charger caused UV, restore original max pulses */ + if (chg->non_compliant_chg_detected) { + rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG, + HVDCP_PULSE_COUNT_MAX_QC2_MASK, + chg->qc2_max_pulses); + if (rc < 0) + smblib_err(chg, "Couldn't restore max pulses rc=%d\n", + rc); + chg->non_compliant_chg_detected = false; + } + /* enable APSD CC trigger for next insertion */ rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT); diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index dc8cbc7b67d7..31298613c80f 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -361,6 +361,8 @@ struct smb_charger { bool try_sink_active; int boost_current_ua; int temp_speed_reading_count; + int qc2_max_pulses; + bool non_compliant_chg_detected; bool fake_usb_insertion; /* extcon for VBUS / ID notification to USB for uUSB */ diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h index d40d6fdc6a64..449d9747b0c4 100644 --- a/drivers/power/supply/qcom/smb-reg.h +++ b/drivers/power/supply/qcom/smb-reg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -587,6 +587,15 @@ enum { #define EN_LEGACY_CABLE_DETECTION_BIT BIT(1) #define ALLOW_PD_DRING_UFP_TCCDB_BIT BIT(0) +#define HVDCP_PULSE_COUNT_MAX_REG (USBIN_BASE + 0x5B) +#define HVDCP_PULSE_COUNT_MAX_QC2_MASK GENMASK(7, 6) +enum { + HVDCP_PULSE_COUNT_MAX_QC2_5V, + HVDCP_PULSE_COUNT_MAX_QC2_9V, + HVDCP_PULSE_COUNT_MAX_QC2_12V, + HVDCP_PULSE_COUNT_MAX_QC2_INVALID +}; + #define USBIN_ADAPTER_ALLOW_CFG_REG (USBIN_BASE + 0x60) #define USBIN_ADAPTER_ALLOW_MASK GENMASK(3, 0) enum { -- GitLab From d7f9d95ce9ddedec46f868604fc2f15ba96c95d0 Mon Sep 17 00:00:00 2001 From: Amit Shekhar Date: Wed, 23 May 2018 18:08:00 -0700 Subject: [PATCH 608/855] msm: vidc: Fix tile info table generation Tile info table is generated during grid dimension control handling. This table, however, should be generated at start streaming as the table values have dependencies on grid dimensions along with input resolution. Change-Id: If62b393afb4116ad1ffdba700ccb54da93649187 CRs-Fixed: 2247824 Signed-off-by: Amit Shekhar --- drivers/media/platform/msm/vidc/msm_venc.c | 36 --------------- drivers/media/platform/msm/vidc/msm_vidc.c | 52 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 36 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 9a7d272bd629..957a6f68e514 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1548,10 +1548,6 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } case V4L2_CID_MPEG_VIDC_IMG_GRID_DIMENSION: { - int i = 0, j = 0; - u32 width = 0, height = 0; - u32 trows, tcols; - property_id = HAL_CONFIG_HEIC_GRID_ENABLE; if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_HEVC) { dprintk(VIDC_ERR, "Grid is supported only for HEVC\n"); @@ -1566,38 +1562,6 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) grid_enable.grid_enable = ctrl->val; inst->img_grid_dimension = ctrl->val; pdata = &grid_enable; - - /* Update tile info table */ - width = inst->prop.width[OUTPUT_PORT]; - height = inst->prop.height[OUTPUT_PORT]; - tcols = (width + inst->img_grid_dimension - 1) / - inst->img_grid_dimension; - trows = (height + inst->img_grid_dimension - 1) / - inst->img_grid_dimension; - inst->tinfo.count = trows * tcols; - if (inst->tinfo.count > MAX_HEIC_TILES_COUNT) { - dprintk(VIDC_ERR, "Tiles count exceeds maximum\n"); - rc = -ENOTSUPP; - break; - } - - dprintk(VIDC_DBG, - "Grid dimension %d width %d height %d row %d col %d\n", - inst->img_grid_dimension, width, height, - trows, tcols); - - for (j = 0; j < trows; ++j) { - for (i = 0; i < tcols; ++i) { - inst->tinfo.tile_rects[j*tcols+i].left = - (i * inst->img_grid_dimension); - inst->tinfo.tile_rects[j*tcols+i].top = - (j * inst->img_grid_dimension); - inst->tinfo.tile_rects[j*tcols+i].width = - inst->img_grid_dimension; - inst->tinfo.tile_rects[j*tcols+i].height = - inst->img_grid_dimension; - } - } break; } case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 8e3250465e8f..651d0a2968c7 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -901,6 +901,51 @@ static inline int msm_vidc_verify_buffer_counts(struct msm_vidc_inst *inst) return rc; } +static int msm_vidc_create_tile_info_table(struct msm_vidc_inst *inst) +{ + int i = 0, j = 0; + u32 width = 0, height = 0; + u32 trows = 0, tcols = 0; + + /* Don't create table for non-HEIC formats*/ + if (inst->img_grid_dimension <= 0 || + inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_HEVC) + return 0; + + width = inst->prop.width[OUTPUT_PORT]; + height = inst->prop.height[OUTPUT_PORT]; + tcols = (width + inst->img_grid_dimension - 1) / + inst->img_grid_dimension; + trows = (height + inst->img_grid_dimension - 1) / + inst->img_grid_dimension; + inst->tinfo.count = trows * tcols; + if (inst->tinfo.count > MAX_HEIC_TILES_COUNT) { + dprintk(VIDC_ERR, + "Tiles count (%d) exceeds maximum\n", + inst->tinfo.count); + return -ENOTSUPP; + } + + dprintk(VIDC_DBG, + "Grid dimension %d width %d height %d row %d col %d\n", + inst->img_grid_dimension, width, height, + trows, tcols); + + for (j = 0; j < trows; ++j) { + for (i = 0; i < tcols; ++i) { + inst->tinfo.tile_rects[j*tcols+i].left = + (i * inst->img_grid_dimension); + inst->tinfo.tile_rects[j*tcols+i].top = + (j * inst->img_grid_dimension); + inst->tinfo.tile_rects[j*tcols+i].width = + inst->img_grid_dimension; + inst->tinfo.tile_rects[j*tcols+i].height = + inst->img_grid_dimension; + } + } + return 0; +} + static inline int start_streaming(struct msm_vidc_inst *inst) { int rc = 0; @@ -909,6 +954,13 @@ static inline int start_streaming(struct msm_vidc_inst *inst) hdev = inst->core->device; + /* Create tile info table */ + rc = msm_vidc_create_tile_info_table(inst); + if (rc) { + dprintk(VIDC_ERR, "Tile info table was not generated\n"); + goto fail_start; + } + /* Check if current session is under HW capability */ rc = msm_vidc_check_session_supported(inst); if (rc) { -- GitLab From 8f7deb4e8199ed7914f507bc46bd41df40bd5c5a Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Tue, 29 May 2018 17:41:03 -0700 Subject: [PATCH 609/855] usb: gadget: f_gsi: Fix return type for name_to_prot_id() name_to_prot_id() returns -EINVAL for error case when return type is enum usb_prot_id. This return type is compared against < 0 without type casting to integer which returns false. As a result invalid prot_id is indexed for __gsi array. Fix the issue by changing return type to int. Change-Id: I0d833d59e95e2257255e841913a2eed5204c6ef5 Signed-off-by: Hemant Kumar --- drivers/usb/gadget/function/f_gsi.c | 3 +-- drivers/usb/gadget/function/f_gsi.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 94dd64a8d8a9..a2fae4922167 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -3270,10 +3270,9 @@ static struct config_item_type gsi_func_rndis_type = { static int gsi_set_inst_name(struct usb_function_instance *fi, const char *name) { - int name_len, ret = 0; + int name_len, prot_id, ret = 0; struct gsi_opts *opts; struct f_gsi *gsi; - enum usb_prot_id prot_id; opts = container_of(fi, struct gsi_opts, func_inst); diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index 7e998c4fafa8..bd0376a5d588 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -306,7 +306,7 @@ static inline struct gsi_opts *to_gsi_opts(struct config_item *item) func_inst.group); } -static enum usb_prot_id name_to_prot_id(const char *name) +static int name_to_prot_id(const char *name) { if (!name) goto error; -- GitLab From 01be50ce7f0dc717296f7ad9506128da1fb433ab Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Thu, 17 May 2018 16:35:35 -0700 Subject: [PATCH 610/855] msm: ipa: fix a race condition in teardown pipe Starting IPA 4.0 a pipe cannot be suspended. Instead the GSI channel needs to be stopped. This change moves the GSI stop to the same place where pipe suspend used to be. Change-Id: I5b7f2301490cf45f6f02c4ede84a75925b381e6e CRs-Fixed: 2244241 Acked-by: Ady Abraham Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index e73349a2104b..84124ab9bb6f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -1110,11 +1110,6 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl) IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl)); ipa3_disable_data_path(clnt_hdl); - if (ep->napi_enabled) { - do { - usleep_range(95, 105); - } while (atomic_read(&ep->sys->curr_polling_state)); - } if (IPA_CLIENT_IS_PROD(ep->client)) { do { @@ -1128,9 +1123,6 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl) } while (1); } - if (IPA_CLIENT_IS_CONS(ep->client)) - cancel_delayed_work_sync(&ep->sys->replenish_rx_work); - flush_workqueue(ep->sys->wq); /* channel stop might fail on timeout if IPA is busy */ for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) { result = ipa3_stop_gsi_channel(clnt_hdl); @@ -1138,7 +1130,7 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl) break; if (result != -GSI_STATUS_AGAIN && - result != -GSI_STATUS_TIMED_OUT) + result != -GSI_STATUS_TIMED_OUT) break; } @@ -1147,6 +1139,17 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl) ipa_assert(); return result; } + + if (ep->napi_enabled) { + do { + usleep_range(95, 105); + } while (atomic_read(&ep->sys->curr_polling_state)); + } + + if (IPA_CLIENT_IS_CONS(ep->client)) + cancel_delayed_work_sync(&ep->sys->replenish_rx_work); + flush_workqueue(ep->sys->wq); + result = ipa3_reset_gsi_channel(clnt_hdl); if (result != GSI_STATUS_SUCCESS) { IPAERR("Failed to reset chan: %d.\n", result); -- GitLab From d0c2097e664c3b97f49b87729b385579bee19c11 Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Tue, 29 May 2018 12:01:36 +0530 Subject: [PATCH 611/855] ARM: dts: msm: Modify memory allocation for diag on sdm845 The patch removes the boot time allocation for diag and allocates only on request from peripheral. The new property added ensures memory will not be freed on free request or ssr case. Change-Id: I18882de4ce93ec52772553d67789ed89789f5b40 Signed-off-by: Manoj Prabhu B --- Documentation/devicetree/bindings/arm/msm/heap-sharing.txt | 4 ++++ arch/arm64/boot/dts/qcom/sdm845-v2.dtsi | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/msm/heap-sharing.txt b/Documentation/devicetree/bindings/arm/msm/heap-sharing.txt index e63d09b4c6da..de2a9639ce24 100644 --- a/Documentation/devicetree/bindings/arm/msm/heap-sharing.txt +++ b/Documentation/devicetree/bindings/arm/msm/heap-sharing.txt @@ -29,6 +29,10 @@ Optional properties for child nodes: - qcom,allocate-boot-time: Indicates whether clients needs boot time memory allocation. +- qcom,allocate-on-request: Indicates memory allocation happens only when client requests. + +/* "qcom,allocate-boot-time" and "qcom,allocate-on-request" are mutually exclusive properties. */ + Example: qcom,memshare { diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index ba76273d507e..324f3570d2e1 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -51,7 +51,7 @@ compatible = "qcom,memshare-peripheral"; qcom,peripheral-size = <0x500000>; qcom,client-id = <1>; - qcom,allocate-boot-time; + qcom,allocate-on-request; label = "modem"; }; }; -- GitLab From a6a4f429b12009ae8314e56e755deed0306c546f Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Tue, 29 May 2018 13:13:34 +0530 Subject: [PATCH 612/855] defconfig: arm: msm: Enable memshare driver on sdm845 The patch enables memshare driver compilation necessary for allocation of memory for the clients requesting. Change-Id: I580bc69a92e774e8e86db7de9e4e1217cbdbf5a0 Signed-off-by: Manoj Prabhu B --- arch/arm64/configs/sdm845-perf_defconfig | 1 + arch/arm64/configs/sdm845_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig index a29cfa70f228..b2303d581fed 100644 --- a/arch/arm64/configs/sdm845-perf_defconfig +++ b/arch/arm64/configs/sdm845-perf_defconfig @@ -549,6 +549,7 @@ CONFIG_MSM_QBT1000=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig index d20d9edbebe7..f02b0fd6cb6a 100644 --- a/arch/arm64/configs/sdm845_defconfig +++ b/arch/arm64/configs/sdm845_defconfig @@ -568,6 +568,7 @@ CONFIG_QCOM_DCC_V2=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_MSM_REMOTEQDSS=y CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_QCOM_BIMC_BWMON=y -- GitLab From adacc5f8479205644fec03c5123b7a328e90b5e2 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Thu, 19 Apr 2018 14:18:30 +0530 Subject: [PATCH 613/855] phy: msm: usb: Add charger detection support Add support for PHY based charger detection and notify the charger type and current to PMI. Change-Id: I93db3f18274083ecc07c34ac64e0c07ed517f29f Signed-off-by: Ajay Agarwal --- drivers/usb/phy/phy-msm-usb.c | 454 ++++++++++++++++++++++++++++++---- include/linux/usb/msm_hsusb.h | 36 ++- 2 files changed, 444 insertions(+), 46 deletions(-) diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 96675f2478cf..1550caee9886 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -258,11 +258,21 @@ module_param(lpm_disconnect_thresh, uint, 0644); MODULE_PARM_DESC(lpm_disconnect_thresh, "Delay before entering LPM on USB disconnect"); +static bool floated_charger_enable; +module_param(floated_charger_enable, bool, 0644); +MODULE_PARM_DESC(floated_charger_enable, + "Whether to enable floated charger"); + /* by default debugging is enabled */ static unsigned int enable_dbg_log = 1; module_param(enable_dbg_log, uint, 0644); MODULE_PARM_DESC(enable_dbg_log, "Debug buffer events"); +/* Max current to be drawn for DCP charger */ +static int dcp_max_current = IDEV_CHG_MAX; +module_param(dcp_max_current, int, 0644); +MODULE_PARM_DESC(dcp_max_current, "max current drawn for DCP charger"); + static struct msm_otg *the_msm_otg; static bool debug_bus_voting_enabled; @@ -1325,6 +1335,7 @@ static int msm_otg_suspend(struct msm_otg *motg) struct msm_otg_platform_data *pdata = motg->pdata; int cnt; bool host_bus_suspend, device_bus_suspend, sm_work_busy; + bool host_pc_charger; u32 cmd_val; u32 portsc, config2; u32 func_ctrl; @@ -1352,6 +1363,9 @@ static int msm_otg_suspend(struct msm_otg *motg) if (host_bus_suspend) msm_otg_perf_vote_update(motg, false); + host_pc_charger = (motg->chg_type == USB_SDP_CHARGER) || + (motg->chg_type == USB_CDP_CHARGER); + /* !BSV, but its handling is in progress by otg sm_work */ sm_work_busy = !test_bit(B_SESS_VLD, &motg->inputs) && phy->otg->state == OTG_STATE_B_PERIPHERAL; @@ -1378,8 +1392,8 @@ static int msm_otg_suspend(struct msm_otg *motg) * Don't abort suspend in case of dcp detected by PMIC */ - if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend) || - sm_work_busy) { + if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend && + host_pc_charger) || sm_work_busy) { msm_otg_dbg_log_event(phy, "LPM ENTER ABORTED", motg->inputs, 0); enable_irq(motg->irq); @@ -1825,7 +1839,49 @@ static int get_psy_type(struct msm_otg *motg) return pval.intval; } -static void msm_otg_notify_chg_current(struct msm_otg *motg, unsigned int mA) +static int msm_otg_notify_chg_type(struct msm_otg *motg) +{ + static int charger_type; + union power_supply_propval propval; + int ret = 0; + /* + * TODO + * Unify OTG driver charger types and power supply charger types + */ + if (charger_type == motg->chg_type) + return 0; + + if (motg->chg_type == USB_SDP_CHARGER) + charger_type = POWER_SUPPLY_TYPE_USB; + else if (motg->chg_type == USB_CDP_CHARGER) + charger_type = POWER_SUPPLY_TYPE_USB_CDP; + else if (motg->chg_type == USB_DCP_CHARGER || + motg->chg_type == USB_NONCOMPLIANT_CHARGER) + charger_type = POWER_SUPPLY_TYPE_USB_DCP; + else if (motg->chg_type == USB_FLOATED_CHARGER) + charger_type = POWER_SUPPLY_TYPE_USB_FLOAT; + else + charger_type = POWER_SUPPLY_TYPE_UNKNOWN; + + if (!psy) { + dev_err(motg->phy.dev, "no usb power supply registered\n"); + return -ENODEV; + } + + pr_debug("Trying to set usb power supply type %d\n", charger_type); + + propval.intval = charger_type; + ret = power_supply_set_property(psy, POWER_SUPPLY_PROP_REAL_TYPE, + &propval); + if (ret) + dev_dbg(motg->phy.dev, "power supply error when setting property\n"); + + msm_otg_dbg_log_event(&motg->phy, "SET USB PWR SUPPLY TYPE", + motg->chg_type, charger_type); + return ret; +} + +static void msm_otg_notify_charger(struct msm_otg *motg, unsigned int mA) { struct usb_gadget *g = motg->phy.otg->gadget; union power_supply_propval pval = {0}; @@ -1834,6 +1890,12 @@ static void msm_otg_notify_chg_current(struct msm_otg *motg, unsigned int mA) if (g && g->is_a_peripheral) return; + dev_dbg(motg->phy.dev, "Requested curr from USB = %u\n", mA); + + if (msm_otg_notify_chg_type(motg)) + dev_dbg(motg->phy.dev, "Failed notifying %d charger type to PMIC\n", + motg->chg_type); + psy_type = get_psy_type(motg); if (psy_type == POWER_SUPPLY_TYPE_USB_FLOAT) { if (!mA) @@ -1843,9 +1905,7 @@ static void msm_otg_notify_chg_current(struct msm_otg *motg, unsigned int mA) goto set_prop; } - dev_dbg(motg->phy.dev, "Requested curr from USB = %u\n", mA); - - if (motg->cur_power == mA || psy_type != POWER_SUPPLY_TYPE_USB) + if (motg->cur_power == mA) return; dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA); @@ -1864,15 +1924,12 @@ static void msm_otg_notify_chg_current(struct msm_otg *motg, unsigned int mA) motg->cur_power = mA; } -static void msm_otg_notify_chg_current_work(struct work_struct *w) +static void msm_otg_notify_charger_work(struct work_struct *w) { struct msm_otg *motg = container_of(w, - struct msm_otg, notify_chg_current_work); - /* - * Gadget driver uses set_power method to notify about the - * available current based on suspend/configured states. - */ - msm_otg_notify_chg_current(motg, motg->notify_current_mA); + struct msm_otg, notify_charger_work); + + msm_otg_notify_charger(motg, motg->notify_current_mA); } static int msm_otg_set_power(struct usb_phy *phy, unsigned int mA) @@ -1880,7 +1937,14 @@ static int msm_otg_set_power(struct usb_phy *phy, unsigned int mA) struct msm_otg *motg = container_of(phy, struct msm_otg, phy); motg->notify_current_mA = mA; - schedule_work(&motg->notify_chg_current_work); + /* + * Gadget driver uses set_power method to notify about the + * available current based on suspend/configured states. + */ + if (motg->chg_type == USB_SDP_CHARGER || + get_psy_type(motg) == POWER_SUPPLY_TYPE_USB || + get_psy_type(motg) == POWER_SUPPLY_TYPE_USB_FLOAT) + queue_work(motg->otg_wq, &motg->notify_charger_work); return 0; } @@ -2281,6 +2345,301 @@ static bool msm_otg_read_phy_id_state(struct msm_otg *motg) return true; } +static bool msm_chg_check_secondary_det(struct msm_otg *motg) +{ + struct usb_phy *phy = &motg->phy; + u32 chg_det; + + chg_det = ulpi_read(phy, 0x87); + + return (chg_det & 1); +} + +static void msm_chg_enable_secondary_det(struct msm_otg *motg) +{ + struct usb_phy *phy = &motg->phy; + + /* + * Configure DM as current source, DP as current sink + * and enable battery charging comparators. + */ + ulpi_write(phy, 0x8, 0x85); + ulpi_write(phy, 0x2, 0x85); + ulpi_write(phy, 0x1, 0x85); +} + +static bool msm_chg_check_primary_det(struct msm_otg *motg) +{ + struct usb_phy *phy = &motg->phy; + u32 chg_det; + bool ret = false; + + chg_det = ulpi_read(phy, 0x87); + ret = chg_det & 1; + /* Turn off VDP_SRC */ + ulpi_write(phy, 0x3, 0x86); + msleep(20); + + return ret; +} + +static void msm_chg_enable_primary_det(struct msm_otg *motg) +{ + struct usb_phy *phy = &motg->phy; + + /* + * Configure DP as current source, DM as current sink + * and enable battery charging comparators. + */ + ulpi_write(phy, 0x2, 0x85); + ulpi_write(phy, 0x1, 0x85); +} + +static bool msm_chg_check_dcd(struct msm_otg *motg) +{ + struct usb_phy *phy = &motg->phy; + u32 line_state; + + line_state = ulpi_read(phy, 0x87); + + return line_state & 2; +} + +static void msm_chg_disable_dcd(struct msm_otg *motg) +{ + struct usb_phy *phy = &motg->phy; + + ulpi_write(phy, 0x10, 0x86); + /* + * Disable the Rdm_down after + * the DCD is completed. + */ + ulpi_write(phy, 0x04, 0x0C); +} + +static void msm_chg_enable_dcd(struct msm_otg *motg) +{ + struct usb_phy *phy = &motg->phy; + + /* + * Idp_src and Rdm_down are de-coupled + * on Femto PHY. If Idp_src alone is + * enabled, DCD timeout is observed with + * wall charger. But a genuine DCD timeout + * may be incorrectly interpreted. Also + * BC1.2 compliance testers expect Rdm_down + * to enabled during DCD. Enable Rdm_down + * explicitly before enabling the DCD. + */ + ulpi_write(phy, 0x04, 0x0B); + ulpi_write(phy, 0x10, 0x85); +} + +static void msm_chg_block_on(struct msm_otg *motg) +{ + struct usb_phy *phy = &motg->phy; + u32 func_ctrl; + + /* put the controller in non-driving mode */ + func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL); + func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK; + func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; + ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL); + + /* disable DP and DM pull down resistors */ + ulpi_write(phy, 0x6, 0xC); + /* Clear charger detecting control bits */ + ulpi_write(phy, 0x1F, 0x86); + /* Clear alt interrupt latch and enable bits */ + ulpi_write(phy, 0x1F, 0x92); + ulpi_write(phy, 0x1F, 0x95); + udelay(100); +} + +static void msm_chg_block_off(struct msm_otg *motg) +{ + struct usb_phy *phy = &motg->phy; + u32 func_ctrl; + + /* Clear charger detecting control bits */ + ulpi_write(phy, 0x3F, 0x86); + /* Clear alt interrupt latch and enable bits */ + ulpi_write(phy, 0x1F, 0x92); + ulpi_write(phy, 0x1F, 0x95); + /* re-enable DP and DM pull down resistors */ + ulpi_write(phy, 0x6, 0xB); + + /* put the controller in normal mode */ + func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL); + func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK; + func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL; + ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL); +} + +#define MSM_CHG_DCD_TIMEOUT (750 * HZ/1000) /* 750 msec */ +#define MSM_CHG_DCD_POLL_TIME (50 * HZ/1000) /* 50 msec */ +#define MSM_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */ +#define MSM_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */ + +static void msm_chg_detect_work(struct work_struct *w) +{ + struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work); + struct usb_phy *phy = &motg->phy; + bool is_dcd = false, tmout, vout, queue_sm_work = false; + static bool dcd; + u32 line_state, dm_vlgc; + unsigned long delay = 0; + + dev_dbg(phy->dev, "chg detection work\n"); + msm_otg_dbg_log_event(phy, "CHG DETECTION WORK", + motg->chg_state, get_pm_runtime_counter(phy->dev)); + + switch (motg->chg_state) { + case USB_CHG_STATE_UNDEFINED: + pm_runtime_get_sync(phy->dev); + msm_chg_block_on(motg); + case USB_CHG_STATE_IN_PROGRESS: + if (!motg->vbus_state) { + motg->chg_state = USB_CHG_STATE_UNDEFINED; + motg->chg_type = USB_INVALID_CHARGER; + msm_chg_block_off(motg); + pm_runtime_put_sync(phy->dev); + return; + } + + msm_chg_enable_dcd(motg); + motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD; + motg->dcd_time = 0; + delay = MSM_CHG_DCD_POLL_TIME; + break; + case USB_CHG_STATE_WAIT_FOR_DCD: + if (!motg->vbus_state) { + motg->chg_state = USB_CHG_STATE_IN_PROGRESS; + break; + } + + is_dcd = msm_chg_check_dcd(motg); + motg->dcd_time += MSM_CHG_DCD_POLL_TIME; + tmout = motg->dcd_time >= MSM_CHG_DCD_TIMEOUT; + if (is_dcd || tmout) { + if (is_dcd) + dcd = true; + else + dcd = false; + msm_chg_disable_dcd(motg); + msm_chg_enable_primary_det(motg); + delay = MSM_CHG_PRIMARY_DET_TIME; + motg->chg_state = USB_CHG_STATE_DCD_DONE; + } else { + delay = MSM_CHG_DCD_POLL_TIME; + } + break; + case USB_CHG_STATE_DCD_DONE: + if (!motg->vbus_state) { + motg->chg_state = USB_CHG_STATE_IN_PROGRESS; + break; + } + + vout = msm_chg_check_primary_det(motg); + line_state = readl_relaxed(USB_PORTSC) & PORTSC_LS; + dm_vlgc = line_state & PORTSC_LS_DM; + if (vout && !dm_vlgc) { /* VDAT_REF < DM < VLGC */ + if (line_state) { /* DP > VLGC */ + motg->chg_type = USB_NONCOMPLIANT_CHARGER; + motg->chg_state = USB_CHG_STATE_DETECTED; + } else { + msm_chg_enable_secondary_det(motg); + delay = MSM_CHG_SECONDARY_DET_TIME; + motg->chg_state = USB_CHG_STATE_PRIMARY_DONE; + } + } else { /* DM < VDAT_REF || DM > VLGC */ + if (line_state) /* DP > VLGC or/and DM > VLGC */ + motg->chg_type = USB_NONCOMPLIANT_CHARGER; + else if (!dcd && floated_charger_enable) + motg->chg_type = USB_FLOATED_CHARGER; + else + motg->chg_type = USB_SDP_CHARGER; + + motg->chg_state = USB_CHG_STATE_DETECTED; + } + break; + case USB_CHG_STATE_PRIMARY_DONE: + if (!motg->vbus_state) { + motg->chg_state = USB_CHG_STATE_IN_PROGRESS; + break; + } + + vout = msm_chg_check_secondary_det(motg); + if (vout) + motg->chg_type = USB_DCP_CHARGER; + else + motg->chg_type = USB_CDP_CHARGER; + motg->chg_state = USB_CHG_STATE_SECONDARY_DONE; + /* fall through */ + case USB_CHG_STATE_SECONDARY_DONE: + motg->chg_state = USB_CHG_STATE_DETECTED; + case USB_CHG_STATE_DETECTED: + if (!motg->vbus_state) { + motg->chg_state = USB_CHG_STATE_IN_PROGRESS; + break; + } + + msm_chg_block_off(motg); + + /* Enable VDP_SRC in case of DCP charger */ + if (motg->chg_type == USB_DCP_CHARGER) { + ulpi_write(phy, 0x2, 0x85); + msm_otg_notify_charger(motg, dcp_max_current); + } else if (motg->chg_type == USB_NONCOMPLIANT_CHARGER) + msm_otg_notify_charger(motg, dcp_max_current); + else if (motg->chg_type == USB_FLOATED_CHARGER || + motg->chg_type == USB_CDP_CHARGER) + msm_otg_notify_charger(motg, IDEV_CHG_MAX); + + msm_otg_dbg_log_event(phy, "CHG WORK PUT: CHG_TYPE", + motg->chg_type, get_pm_runtime_counter(phy->dev)); + /* to match _get at the start of chg_det_work */ + pm_runtime_mark_last_busy(phy->dev); + pm_runtime_put_autosuspend(phy->dev); + motg->chg_state = USB_CHG_STATE_QUEUE_SM_WORK; + break; + case USB_CHG_STATE_QUEUE_SM_WORK: + if (!motg->vbus_state) { + pm_runtime_get_sync(phy->dev); + /* Turn off VDP_SRC if charger is DCP type */ + if (motg->chg_type == USB_DCP_CHARGER) + ulpi_write(phy, 0x2, 0x86); + + motg->chg_state = USB_CHG_STATE_UNDEFINED; + if (motg->chg_type == USB_SDP_CHARGER || + motg->chg_type == USB_CDP_CHARGER) + queue_sm_work = true; + + motg->chg_type = USB_INVALID_CHARGER; + msm_otg_notify_charger(motg, 0); + motg->cur_power = 0; + msm_chg_block_off(motg); + pm_runtime_mark_last_busy(phy->dev); + pm_runtime_put_autosuspend(phy->dev); + if (queue_sm_work) + queue_work(motg->otg_wq, &motg->sm_work); + else + return; + } + + if (motg->chg_type == USB_CDP_CHARGER || + motg->chg_type == USB_SDP_CHARGER) + queue_work(motg->otg_wq, &motg->sm_work); + + return; + default: + return; + } + + msm_otg_dbg_log_event(phy, "CHG WORK: QUEUE", motg->chg_type, delay); + queue_delayed_work(motg->otg_wq, &motg->chg_work, delay); +} + /* * We support OTG, Peripheral only and Host only configurations. In case * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen @@ -2382,32 +2741,31 @@ static void check_for_sdp_connection(struct work_struct *w) static void msm_otg_sm_work(struct work_struct *w) { struct msm_otg *motg = container_of(w, struct msm_otg, sm_work); + struct usb_phy *phy = &motg->phy; struct usb_otg *otg = motg->phy.otg; struct device *dev = otg->usb_phy->dev; bool work = 0; int ret; pr_debug("%s work\n", usb_otg_state_string(otg->state)); - msm_otg_dbg_log_event(&motg->phy, "SM WORK:", - otg->state, motg->inputs); + msm_otg_dbg_log_event(phy, "SM WORK:", otg->state, motg->inputs); /* Just resume h/w if reqd, pm_count is handled based on state/inputs */ if (motg->resume_pending) { - pm_runtime_get_sync(otg->usb_phy->dev); + pm_runtime_get_sync(dev); if (atomic_read(&motg->in_lpm)) { dev_err(dev, "SM WORK: USB is in LPM\n"); - msm_otg_dbg_log_event(&motg->phy, - "SM WORK: USB IS IN LPM", + msm_otg_dbg_log_event(phy, "SM WORK: USB IS IN LPM", otg->state, motg->inputs); msm_otg_resume(motg); } motg->resume_pending = false; - pm_runtime_put_noidle(otg->usb_phy->dev); + pm_runtime_put_noidle(dev); } switch (otg->state) { case OTG_STATE_UNDEFINED: - pm_runtime_get_sync(otg->usb_phy->dev); + pm_runtime_get_sync(dev); msm_otg_reset(otg->usb_phy); /* Add child device only after block reset */ ret = of_platform_populate(motg->pdev->dev.of_node, NULL, NULL, @@ -2419,21 +2777,20 @@ static void msm_otg_sm_work(struct work_struct *w) otg->state = OTG_STATE_B_IDLE; if (!test_bit(B_SESS_VLD, &motg->inputs) && test_bit(ID, &motg->inputs)) { - msm_otg_dbg_log_event(&motg->phy, - "PM RUNTIME: UNDEF PUT", - get_pm_runtime_counter(otg->usb_phy->dev), 0); - pm_runtime_put_sync(otg->usb_phy->dev); + msm_otg_dbg_log_event(phy, "PM RUNTIME: UNDEF PUT", + get_pm_runtime_counter(dev), 0); + pm_runtime_put_sync(dev); break; } - pm_runtime_put(otg->usb_phy->dev); + pm_runtime_put(dev); /* FALL THROUGH */ case OTG_STATE_B_IDLE: if (!test_bit(ID, &motg->inputs) && otg->host) { pr_debug("!id\n"); - msm_otg_dbg_log_event(&motg->phy, "!ID", + msm_otg_dbg_log_event(phy, "!ID", motg->inputs, otg->state); if (!otg->host) { - msm_otg_dbg_log_event(&motg->phy, + msm_otg_dbg_log_event(phy, "SM WORK: Host Not Set", otg->state, motg->inputs); break; @@ -2443,10 +2800,10 @@ static void msm_otg_sm_work(struct work_struct *w) otg->state = OTG_STATE_A_HOST; } else if (test_bit(B_SESS_VLD, &motg->inputs)) { pr_debug("b_sess_vld\n"); - msm_otg_dbg_log_event(&motg->phy, "B_SESS_VLD", + msm_otg_dbg_log_event(phy, "B_SESS_VLD", motg->inputs, otg->state); if (!otg->gadget) { - msm_otg_dbg_log_event(&motg->phy, + msm_otg_dbg_log_event(phy, "SM WORK: Gadget Not Set", otg->state, motg->inputs); break; @@ -2454,25 +2811,24 @@ static void msm_otg_sm_work(struct work_struct *w) if (get_psy_type(motg) == POWER_SUPPLY_TYPE_USB_FLOAT) queue_delayed_work(motg->otg_wq, - &motg->sdp_check, - msecs_to_jiffies(SDP_CHECK_DELAY_MS)); + &motg->sdp_check, + msecs_to_jiffies(SDP_CHECK_DELAY_MS)); pm_runtime_get_sync(otg->usb_phy->dev); msm_otg_start_peripheral(otg, 1); otg->state = OTG_STATE_B_PERIPHERAL; } else { pr_debug("Cable disconnected\n"); - msm_otg_dbg_log_event(&motg->phy, "RT: Cable DISC", - get_pm_runtime_counter(otg->usb_phy->dev), 0); - - msm_otg_notify_chg_current(motg, 0); + msm_otg_dbg_log_event(phy, "RT: Cable DISC", + get_pm_runtime_counter(dev), 0); + msm_otg_notify_charger(motg, 0); } break; case OTG_STATE_B_PERIPHERAL: if (!test_bit(B_SESS_VLD, &motg->inputs)) { cancel_delayed_work_sync(&motg->sdp_check); msm_otg_start_peripheral(otg, 0); - msm_otg_dbg_log_event(&motg->phy, "RT PM: B_PERI A PUT", + msm_otg_dbg_log_event(phy, "RT PM: B_PERI A PUT", get_pm_runtime_counter(dev), 0); /* _put for _get done on cable connect in B_IDLE */ pm_runtime_mark_last_busy(dev); @@ -2482,8 +2838,7 @@ static void msm_otg_sm_work(struct work_struct *w) work = 1; } else if (test_bit(A_BUS_SUSPEND, &motg->inputs)) { pr_debug("a_bus_suspend\n"); - msm_otg_dbg_log_event(&motg->phy, - "BUS_SUSPEND: PM RT PUT", + msm_otg_dbg_log_event(phy, "BUS_SUSPEND: PM RT PUT", get_pm_runtime_counter(dev), 0); otg->state = OTG_STATE_B_SUSPEND; /* _get on connect in B_IDLE or host resume in B_SUSP */ @@ -2501,8 +2856,7 @@ static void msm_otg_sm_work(struct work_struct *w) } else if (!test_bit(A_BUS_SUSPEND, &motg->inputs)) { pr_debug("!a_bus_suspend\n"); otg->state = OTG_STATE_B_PERIPHERAL; - msm_otg_dbg_log_event(&motg->phy, - "BUS_RESUME: PM RT GET", + msm_otg_dbg_log_event(phy, "BUS_RESUME: PM RT GET", get_pm_runtime_counter(dev), 0); pm_runtime_get_sync(dev); } @@ -2619,7 +2973,16 @@ static void msm_otg_set_vbus_state(int online) else set_bit(ID, &motg->inputs); } - msm_otg_kick_sm_work(motg); + + if (test_bit(B_SESS_VLD, &motg->inputs) && + get_psy_type(motg) == POWER_SUPPLY_TYPE_UNKNOWN && + !motg->chg_detection) + motg->chg_detection = true; + + if (motg->chg_detection) + queue_delayed_work(motg->otg_wq, &motg->chg_work, 0); + else + msm_otg_kick_sm_work(motg); } static void msm_id_status_w(struct work_struct *w) @@ -3881,11 +4244,11 @@ static int msm_otg_probe(struct platform_device *pdev) motg->id_state = USB_ID_FLOAT; set_bit(ID, &motg->inputs); INIT_WORK(&motg->sm_work, msm_otg_sm_work); + INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work); INIT_DELAYED_WORK(&motg->id_status_work, msm_id_status_w); INIT_DELAYED_WORK(&motg->perf_vote_work, msm_otg_perf_vote_work); INIT_DELAYED_WORK(&motg->sdp_check, check_for_sdp_connection); - INIT_WORK(&motg->notify_chg_current_work, - msm_otg_notify_chg_current_work); + INIT_WORK(&motg->notify_charger_work, msm_otg_notify_charger_work); motg->otg_wq = alloc_ordered_workqueue("k_otg", 0); if (!motg->otg_wq) { pr_err("%s: Unable to create workqueue otg_wq\n", @@ -4236,12 +4599,13 @@ static int msm_otg_remove(struct platform_device *pdev) if (psy) power_supply_put(psy); msm_otg_debugfs_cleanup(); + cancel_delayed_work_sync(&motg->chg_work); cancel_delayed_work_sync(&motg->sdp_check); cancel_delayed_work_sync(&motg->id_status_work); cancel_delayed_work_sync(&motg->perf_vote_work); msm_otg_perf_vote_update(motg, false); cancel_work_sync(&motg->sm_work); - cancel_work_sync(&motg->notify_chg_current_work); + cancel_work_sync(&motg->notify_charger_work); destroy_workqueue(motg->otg_wq); pm_runtime_resume(&pdev->dev); diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index c40355f2b859..d4f17596816e 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -43,6 +43,33 @@ enum usb_noc_mode { USB_NOC_NUM_VOTE, }; +/** + * Different states involved in USB charger detection. + * + * USB_CHG_STATE_UNDEFINED USB charger is not connected or detection + * process is not yet started. + * USB_CHG_STATE_IN_PROGRESS Charger detection in progress + * USB_CHG_STATE_WAIT_FOR_DCD Waiting for Data pins contact. + * USB_CHG_STATE_DCD_DONE Data pin contact is detected. + * USB_CHG_STATE_PRIMARY_DONE Primary detection is completed (Detects + * between SDP and DCP/CDP). + * USB_CHG_STATE_SECONDARY_DONE Secondary detection is completed (Detects + * between DCP and CDP). + * USB_CHG_STATE_DETECTED USB charger type is determined. + * USB_CHG_STATE_QUEUE_SM_WORK SM work to start/stop gadget is queued. + * + */ +enum usb_chg_state { + USB_CHG_STATE_UNDEFINED = 0, + USB_CHG_STATE_IN_PROGRESS, + USB_CHG_STATE_WAIT_FOR_DCD, + USB_CHG_STATE_DCD_DONE, + USB_CHG_STATE_PRIMARY_DONE, + USB_CHG_STATE_SECONDARY_DONE, + USB_CHG_STATE_DETECTED, + USB_CHG_STATE_QUEUE_SM_WORK, +}; + /** * USB charger types * @@ -126,7 +153,10 @@ enum usb_id_state { * @async_int: IRQ line on which ASYNC interrupt arrived in LPM. * @cur_power: The amount of mA available from downstream port. * @otg_wq: Strict order otg workqueue for OTG works (SM/ID/SUSPEND). + * @chg_work: Charger detection work. + * @chg_state: The state of charger detection process. * @chg_type: The type of charger attached. + * @chg_detection: True if PHY is doing charger type detection. * @bus_perf_client: Bus performance client handle to request BUS bandwidth * @host_bus_suspend: indicates host bus suspend or not. * @device_bus_suspend: indicates device bus suspend or not. @@ -149,6 +179,7 @@ enum usb_id_state { * @max_nominal_system_clk_rate: max freq at which system clock can run in nominal mode. * @sdp_check: SDP detection work in case of USB_FLOAT power supply + * @notify_charger_work: Charger notification work. */ struct msm_otg { struct usb_phy phy; @@ -191,8 +222,11 @@ struct msm_otg { int async_int; unsigned int cur_power; struct workqueue_struct *otg_wq; + struct delayed_work chg_work; struct delayed_work id_status_work; + enum usb_chg_state chg_state; enum usb_chg_type chg_type; + bool chg_detection; unsigned int dcd_time; unsigned long caps; uint32_t bus_perf_client; @@ -278,7 +312,7 @@ struct msm_otg { struct pm_qos_request pm_qos_req_dma; struct delayed_work perf_vote_work; struct delayed_work sdp_check; - struct work_struct notify_chg_current_work; + struct work_struct notify_charger_work; }; struct ci13xxx_platform_data { -- GitLab From cbdf2e8676be80ae3aabc7ad06a6fa99ea0bf0bc Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Sun, 27 May 2018 23:59:01 +0530 Subject: [PATCH 614/855] power: smb5: add support for ICL override In TypeC mode charger hardware follows a predefined ICL configuration and does not honor input limit configured in ICL configuration register, this limits the ability to control ICL of charger specifically in case of USBIN-USBIN based parallel charging where ICL is split between main and parallel charger or in situation where ICL de-rating is required. Change-Id: I446cf1460169a980c75c1413314fa53d93f7f57d Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/qpnp-smb5.c | 7 +++++++ drivers/power/supply/qcom/smb5-lib.c | 28 ++++++++++++++++++++++++++- drivers/power/supply/qcom/smb5-lib.h | 1 + 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 3ff80a9cb2f1..65a74c7c143a 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1616,6 +1616,13 @@ static int smb5_init_hw(struct smb5 *chip) smblib_rerun_apsd_if_required(chg); } + /* clear the ICL override if it is set */ + rc = smblib_icl_override(chg, false); + if (rc < 0) { + pr_err("Couldn't disable ICL override rc=%d\n", rc); + return rc; + } + /* vote 0mA on usb_icl for non battery platforms */ vote(chg->usb_icl_votable, DEFAULT_VOTER, chip->dt.no_battery, 0); diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 58466b838c88..9f395619092e 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -116,6 +116,19 @@ int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua) return 0; } +int smblib_icl_override(struct smb_charger *chg, bool override) +{ + int rc; + + rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG, + ICL_OVERRIDE_AFTER_APSD_BIT, + override ? ICL_OVERRIDE_AFTER_APSD_BIT : 0); + if (rc < 0) + smblib_err(chg, "Couldn't override ICL rc=%d\n", rc); + + return rc; +} + int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override) { int rc = 0; @@ -871,7 +884,7 @@ static int get_sdp_current(struct smb_charger *chg, int *icl_ua) int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) { int rc = 0; - bool hc_mode = false; + bool hc_mode = false, override = false; /* suspend and return if 25mA or less is requested */ if (icl_ua <= USBIN_25MA) @@ -897,6 +910,13 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) goto out; } hc_mode = true; + + /* + * Micro USB mode follows ICL register independent of override + * bit, configure override only for typeC mode. + */ + if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC) + override = true; } set_mode: @@ -907,6 +927,12 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) goto out; } + rc = smblib_icl_override(chg, override); + if (rc < 0) { + smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc); + goto out; + } + /* unsuspend after configuring current and override */ rc = smblib_set_usb_suspend(chg, false); if (rc < 0) { diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 57281cc7752c..7c0246806c06 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -540,6 +540,7 @@ int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override); int smblib_configure_wdog(struct smb_charger *chg, bool enable); int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val); int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable); +int smblib_icl_override(struct smb_charger *chg, bool override); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); -- GitLab From 5f8c053650828096d4d2be7960c33cce87f4f7cb Mon Sep 17 00:00:00 2001 From: Swetha Chikkaboraiah Date: Mon, 28 May 2018 11:45:28 +0530 Subject: [PATCH 615/855] defconfig: msm8937: Enable support for memory controller and LZ4 Enable support for memory controller and LZ4 compression algorithm CONFIG_MEMCG CONFIG_MEMCG_SWAP CONFIG_CRYPTO_LZ4 for msm8937 Change-Id: Id481a01fe7c23a8dc527bde380712babe966eec4 Signed-off-by: Swetha Chikkaboraiah --- arch/arm/configs/msm8937-perf_defconfig | 3 +++ arch/arm/configs/msm8937_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index 11308ba3343c..e64dd3389469 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -19,6 +19,8 @@ CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y @@ -638,6 +640,7 @@ CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_LZ4=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 2f7941f6b014..079f9114f221 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -20,6 +20,8 @@ CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y @@ -697,6 +699,7 @@ CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_LZ4=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y -- GitLab From dcb9f9d07ac477484a46fc235766f81ad1d31d70 Mon Sep 17 00:00:00 2001 From: Mukesh Kumar Savaliya Date: Thu, 17 May 2018 20:38:00 +0530 Subject: [PATCH 616/855] serial: msm_geni_serial: Fix the race between termios and ISR This patch makes sure to process the RX EOT bit post cancel command as part of stop rx sequencer. There could be a race between ISR and userspace thread doing stop rx where ISR clears out the interrupts generated as part of other operations and EOT poll may timeout. Also there are chances that stop_rx can generate an interrupt if the peer device sends data when client hasn't disabled the flow control. This will trigger a call to handle_dma_rx which basically un-maps the rx dma buffer, handles the rx data and remaps the same rx dma buffer. As part of baud change, make sure ISR gets called exclusively against the start_rx call. There is a slight window where dma_map of start_rx sets the iova as DMA_ERROR_CODE for a while before actually mapping to valid dma address and ISR uses this invalid address as part of un-mapping the same buffer address which results into the page fault. Change-Id: I9c69f7f9399aac060188ccee5648b8b7c46a656b Signed-off-by: Mukesh Kumar Savaliya --- drivers/tty/serial/msm_geni_serial.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 8e5d1000ff12..4e895eec8f3e 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -617,7 +617,6 @@ static void msm_geni_serial_abort_rx(struct uart_port *uport) static void msm_geni_serial_complete_rx_eot(struct uart_port *uport) { int poll_done = 0, tries = 0; - u32 geni_status = 0; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); do { @@ -626,11 +625,11 @@ static void msm_geni_serial_complete_rx_eot(struct uart_port *uport) tries++; } while (!poll_done && tries < 5); - geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); - if (!poll_done) - IPC_LOG_MSG(port->ipc_log_misc, "%s: RX_EOT, GENI:0x%x\n", - __func__, geni_status); + IPC_LOG_MSG(port->ipc_log_misc, + "%s: RX_EOT, GENI:0x%x, DMA_DEBUG:0x%x\n", __func__, + geni_read_reg_nolog(uport->membase, SE_GENI_STATUS), + geni_read_reg_nolog(uport->membase, SE_DMA_DEBUG_REG0)); else geni_write_reg_nolog(RX_EOT, uport->membase, SE_DMA_RX_IRQ_CLR); } @@ -1131,7 +1130,9 @@ static void stop_rx_sequencer(struct uart_port *uport) * cancel control bit. */ mb(); - msm_geni_serial_complete_rx_eot(uport); + if (!uart_console(uport)) + msm_geni_serial_complete_rx_eot(uport); + done = msm_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG, S_GENI_CMD_CANCEL, false); if (done) { @@ -1856,6 +1857,7 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, unsigned long ser_clk_cfg = 0; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); unsigned long clk_rate; + unsigned long flags; if (!uart_console(uport)) { int ret = msm_geni_serial_power_on(uport); @@ -1867,7 +1869,13 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, return; } } + /* Take a spinlock else stop_rx causes a race with an ISR due to Cancel + * and FSM_RESET. This also has a potential race with the dma_map/unmap + * operations of ISR. + */ + spin_lock_irqsave(&uport->lock, flags); msm_geni_serial_stop_rx(uport); + spin_unlock_irqrestore(&uport->lock, flags); /* baud rate */ baud = uart_get_baud_rate(uport, termios, old, 300, 4000000); port->cur_baud = baud; -- GitLab From 45e94a5955de0b516de5258bb4a2b2ef450394a4 Mon Sep 17 00:00:00 2001 From: Ravi Kishore Tanuku Date: Thu, 19 Apr 2018 18:46:13 +0530 Subject: [PATCH 617/855] msm: camera: Free power setting pointer during shutdown Free power up and power down setting pointers during power down of sensor modules. Also, add check to avoid memory allocation in multiple calls. Change-Id: I469453af060fb832e1b6e286fdb3c2954f6c9fe4 Signed-off-by: Ravi Kishore Tanuku --- .../cam_actuator/cam_actuator_core.c | 13 ++++++- .../cam_sensor_module/cam_ois/cam_ois_core.c | 12 ++++++- .../cam_sensor_utils/cam_sensor_util.c | 34 +++++++++++-------- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c index 2f74765f1437..a34d70c50a94 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -603,7 +603,11 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, void cam_actuator_shutdown(struct cam_actuator_ctrl_t *a_ctrl) { - int rc; + int rc = 0; + struct cam_actuator_soc_private *soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = + &soc_private->power_info; if (a_ctrl->cam_act_state == CAM_ACTUATOR_INIT) return; @@ -612,6 +616,7 @@ void cam_actuator_shutdown(struct cam_actuator_ctrl_t *a_ctrl) rc = cam_actuator_power_down(a_ctrl); if (rc < 0) CAM_ERR(CAM_ACTUATOR, "Actuator Power down failed"); + a_ctrl->cam_act_state = CAM_ACTUATOR_ACQUIRE; } if (a_ctrl->cam_act_state >= CAM_ACTUATOR_ACQUIRE) { @@ -622,6 +627,12 @@ void cam_actuator_shutdown(struct cam_actuator_ctrl_t *a_ctrl) a_ctrl->bridge_intf.link_hdl = -1; a_ctrl->bridge_intf.session_hdl = -1; } + + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c index 196df084d40b..dfcb9fcba4b7 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c @@ -636,7 +636,11 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl) { - int rc; + int rc = 0; + struct cam_ois_soc_private *soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = + &soc_private->power_info; if (o_ctrl->cam_ois_state == CAM_OIS_INIT) return; @@ -645,6 +649,7 @@ void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl) rc = cam_ois_power_down(o_ctrl); if (rc < 0) CAM_ERR(CAM_OIS, "OIS Power down failed"); + o_ctrl->cam_ois_state = CAM_OIS_ACQUIRE; } if (o_ctrl->cam_ois_state >= CAM_OIS_ACQUIRE) { @@ -656,6 +661,11 @@ void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl) o_ctrl->bridge_intf.session_hdl = -1; } + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + o_ctrl->cam_ois_state = CAM_OIS_INIT; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index c05db9123936..6fccf1b9c74b 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -698,21 +698,25 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, } power_info->power_setting_size = 0; - power_info->power_setting = - (struct cam_sensor_power_setting *) - kzalloc(sizeof(struct cam_sensor_power_setting) * - MAX_POWER_CONFIG, GFP_KERNEL); - if (!power_info->power_setting) - return -ENOMEM; + if (power_info->power_setting == NULL) { + power_info->power_setting = + (struct cam_sensor_power_setting *) + kzalloc(sizeof(struct cam_sensor_power_setting) * + MAX_POWER_CONFIG, GFP_KERNEL); + if (!power_info->power_setting) + return -ENOMEM; + } power_info->power_down_setting_size = 0; - power_info->power_down_setting = - (struct cam_sensor_power_setting *) - kzalloc(sizeof(struct cam_sensor_power_setting) * - MAX_POWER_CONFIG, GFP_KERNEL); - if (!power_info->power_down_setting) { - rc = -ENOMEM; - goto free_power_settings; + if (power_info->power_down_setting == NULL) { + power_info->power_down_setting = + (struct cam_sensor_power_setting *) + kzalloc(sizeof(struct cam_sensor_power_setting) * + MAX_POWER_CONFIG, GFP_KERNEL); + if (!power_info->power_down_setting) { + rc = -ENOMEM; + goto free_power_settings; + } } while (tot_size < cmd_length) { @@ -1552,7 +1556,7 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, if (ret) CAM_ERR(CAM_SENSOR, "cannot set pin to suspend state"); cam_res_mgr_shared_pinctrl_select_state(false); - pinctrl_put(ctrl->pinctrl_info.pinctrl); + devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); cam_res_mgr_shared_pinctrl_put(); } @@ -1766,7 +1770,7 @@ int msm_camera_power_down(struct cam_sensor_power_ctrl_t *ctrl, CAM_ERR(CAM_SENSOR, "cannot set pin to suspend state"); cam_res_mgr_shared_pinctrl_select_state(false); - pinctrl_put(ctrl->pinctrl_info.pinctrl); + devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); cam_res_mgr_shared_pinctrl_put(); } -- GitLab From ad9b5da1fe5d232e24106e16bdb07ba5f06c8951 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Wed, 23 May 2018 16:58:49 -0700 Subject: [PATCH 618/855] perf: Reorder idle notifier registration in armv7 PMU The registration of idle notifier in the armv7 PMU driver is currently being done as a part of the probe. However, issues might arise if the idle notifier is called during the probe itself as the data used by the notifier callback would not have been initialized yet. As a result, move the registration of idle notifier after the probe completes successfully. Change-Id: Ifb3e2bc9eed5a42fcf876274ea644c99ebef2a08 Signed-off-by: Raghavendra Rao Ananta Signed-off-by: Sundara Vinayagam --- arch/arm/kernel/perf_event_v7.c | 36 ++++++++++++++++----------------- drivers/perf/arm_pmu.c | 1 + 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 5b6cb335cf54..342efa69aca9 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -1225,25 +1225,9 @@ static int armv7_pmu_idle_notifier(struct notifier_block *nb, static int armv7_probe_pmu(struct arm_pmu *arm_pmu) { - int ret; - struct armv7_pmu_idle_nb *pmu_idle_nb; - - pmu_idle_nb = devm_kzalloc(&arm_pmu->plat_device->dev, - sizeof(*pmu_idle_nb), GFP_KERNEL); - if (!pmu_idle_nb) - return -ENOMEM; - - ret = smp_call_function_any(&arm_pmu->supported_cpus, + return smp_call_function_any(&arm_pmu->supported_cpus, armv7_read_num_pmnc_events, &arm_pmu->num_events, 1); - if (ret) - return ret; - - pmu_idle_nb->cpu_pmu = arm_pmu; - pmu_idle_nb->perf_cpu_idle_nb.notifier_call = armv7_pmu_idle_notifier; - idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb); - - return 0; } static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu) @@ -2077,8 +2061,24 @@ static const struct pmu_probe_info armv7_pmu_probe_table[] = { static int armv7_pmu_device_probe(struct platform_device *pdev) { - return arm_pmu_device_probe(pdev, armv7_pmu_of_device_ids, + int ret; + struct armv7_pmu_idle_nb *pmu_idle_nb; + + pmu_idle_nb = devm_kzalloc(&pdev->dev, sizeof(*pmu_idle_nb), + GFP_KERNEL); + if (!pmu_idle_nb) + return -ENOMEM; + + ret = arm_pmu_device_probe(pdev, armv7_pmu_of_device_ids, armv7_pmu_probe_table); + if (ret) + return ret; + + pmu_idle_nb->cpu_pmu = (struct arm_pmu *) platform_get_drvdata(pdev); + pmu_idle_nb->perf_cpu_idle_nb.notifier_call = armv7_pmu_idle_notifier; + idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb); + + return 0; } static struct platform_driver armv7_pmu_driver = { diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index df02f98796ec..37df1bf277ca 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -1128,6 +1128,7 @@ int arm_pmu_device_probe(struct platform_device *pdev, armpmu_init(pmu); pmu->plat_device = pdev; + platform_set_drvdata(pdev, pmu); if (node && (of_id = of_match_node(of_table, pdev->dev.of_node))) { init_fn = of_id->data; -- GitLab From a118d1d3690b0d0efd7d22f3de8c917045713143 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Fri, 11 May 2018 18:47:45 -0700 Subject: [PATCH 619/855] spmi: pmic-arb: Use asynchronous probe A spmi controller may have many child devices, which together may take a signifigant amount of time to register and probe. Reduce this effect by probing asynchronously. After: [ 0.277217] calling__software_resume+0x0/0x24c_@_1 Before: [ 0.319295] calling__software_resume+0x0/0x24c_@_1 Change-Id: I95704a2ae7aae98e23dc9f29c7d023867d60388d Signed-off-by: Patrick Daly --- drivers/spmi/spmi-pmic-arb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 61995231dc38..0f0b7ba54fe2 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -1449,6 +1449,7 @@ static struct platform_driver spmi_pmic_arb_driver = { .driver = { .name = "spmi_pmic_arb", .of_match_table = spmi_pmic_arb_match_table, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; -- GitLab From cf93cac524e788396770712aad8522986b2d0b9a Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Wed, 16 May 2018 20:51:04 -0700 Subject: [PATCH 620/855] iommu: arm-smmu: Remove hibernation dt-property Hibernation support is a software choice rather than a hardware property. Fix an issue where multiple targets share the same devicetree, but only some want hibernation enabled. Change-Id: Id5665556583f326108630802a71c4f00eef7a668 Signed-off-by: Patrick Daly --- Documentation/devicetree/bindings/iommu/arm,smmu.txt | 5 ----- drivers/iommu/arm-smmu.c | 11 +++++++++-- include/dt-bindings/arm/arm-smmu.h | 1 - 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 4839df482cbe..23e5f206cf7b 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -87,11 +87,6 @@ conditions. When qcom,enable-static-cb is selected, indicates which iommu context banks may be used by HLOS. -- qcom,hibernation-support: - A boolean, indicates that hibernation should be supported and - all secure usecases should be disabled, since they cannot be - restored properly. - - qcom,skip-init : Disable resetting configuration for all context banks during device reset. This is useful for targets where some context banks are dedicated to other execution diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 17193366d28f..c3376df44eef 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -579,7 +579,6 @@ static struct arm_smmu_option_prop arm_smmu_options[] = { { ARM_SMMU_OPT_MMU500_ERRATA1, "qcom,mmu500-errata-1" }, { ARM_SMMU_OPT_STATIC_CB, "qcom,enable-static-cb"}, { ARM_SMMU_OPT_HALT, "qcom,enable-smmu-halt"}, - { ARM_SMMU_OPT_HIBERNATION, "qcom,hibernation-support"}, { 0, NULL}, }; @@ -607,6 +606,7 @@ static struct iommu_gather_ops qsmmuv500_errata1_smmu_gather_ops; static bool arm_smmu_is_static_cb(struct arm_smmu_device *smmu); static bool arm_smmu_is_master_side_secure(struct arm_smmu_domain *smmu_domain); static bool arm_smmu_is_slave_side_secure(struct arm_smmu_domain *smmu_domain); +static bool arm_smmu_opt_hibernation(struct arm_smmu_device *smmu); static int msm_secure_smmu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t size, int prot); @@ -635,6 +635,13 @@ static void parse_driver_options(struct arm_smmu_device *smmu) arm_smmu_options[i].prop); } } while (arm_smmu_options[++i].opt); + + if (arm_smmu_opt_hibernation(smmu) && + smmu->options && ARM_SMMU_OPT_SKIP_INIT) { + dev_info(smmu->dev, + "Disabling incompatible option: skip-init\n"); + smmu->options &= ~ARM_SMMU_OPT_SKIP_INIT; + } } static bool is_dynamic_domain(struct iommu_domain *domain) @@ -707,7 +714,7 @@ static void arm_smmu_secure_domain_unlock(struct arm_smmu_domain *smmu_domain) static bool arm_smmu_opt_hibernation(struct arm_smmu_device *smmu) { - return smmu->options & ARM_SMMU_OPT_HIBERNATION; + return IS_ENABLED(CONFIG_HIBERNATION); } /* diff --git a/include/dt-bindings/arm/arm-smmu.h b/include/dt-bindings/arm/arm-smmu.h index 1de45a92f1e6..3a1dbd333e2a 100644 --- a/include/dt-bindings/arm/arm-smmu.h +++ b/include/dt-bindings/arm/arm-smmu.h @@ -23,6 +23,5 @@ #define ARM_SMMU_OPT_MMU500_ERRATA1 (1 << 7) #define ARM_SMMU_OPT_STATIC_CB (1 << 8) #define ARM_SMMU_OPT_HALT (1 << 9) -#define ARM_SMMU_OPT_HIBERNATION (1 << 10) #endif -- GitLab From fc00691916c11b7931e076c10236e8e4f21702ac Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Fri, 18 May 2018 14:01:34 -0700 Subject: [PATCH 621/855] of: make kobject and bin_attribute support configurable Having device_nodes be kobjects is only needed if sysfs or OF_DYNAMIC is enabled. Otherwise, having a kobject in struct device_node is unnecessary bloat in minimal kernel configurations. Likewise, bin_attribute is only needed in struct property when sysfs is enabled, so we can make it configurable too. Change-Id: I4f827e540c57a997ab123f40ff9290e485a50f52 Tested-by: Nicolas Pitre Reviewed-by: Frank Rowand Acked-by: Grant Likely Signed-off-by: Rob Herring Git-Commit: b56b5528f5b3c3d47e7c0ca67318c45e980d93f0 Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git [pdaly: removed %pOF printf format as it is not backported added NULL check in safe_name()] Signed-off-by: Patrick Daly --- drivers/of/Kconfig | 4 + drivers/of/Makefile | 1 + drivers/of/base.c | 133 -------------------------------- drivers/of/dynamic.c | 22 ------ drivers/of/kobj.c | 165 ++++++++++++++++++++++++++++++++++++++++ drivers/of/of_private.h | 23 ++++++ include/linux/of.h | 22 +++--- 7 files changed, 203 insertions(+), 167 deletions(-) create mode 100644 drivers/of/kobj.c diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 52a297d5560a..e4304e70a6d3 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -46,10 +46,14 @@ config OF_EARLY_FLATTREE config OF_PROMTREE bool +config OF_KOBJ + def_bool SYSFS + # Hardly any platforms need this. It is safe to select, but only do so if you # need it. config OF_DYNAMIC bool "Support for dynamic device trees" if OF_UNITTEST + select OF_KOBJ help On some platforms, the device tree can be manipulated at runtime. While this option is selected automatically on such platforms, you diff --git a/drivers/of/Makefile b/drivers/of/Makefile index b2f474a8f5be..760b730347d2 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,4 +1,5 @@ obj-y = base.o device.o platform.o +obj-$(CONFIG_OF_KOBJ) += kobj.o obj-$(CONFIG_OF_DYNAMIC) += dynamic.o obj-$(CONFIG_OF_FLATTREE) += fdt.o obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o diff --git a/drivers/of/base.c b/drivers/of/base.c index 23a6d36a69af..0dc31cfe1526 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -98,108 +98,6 @@ int __weak of_node_to_nid(struct device_node *np) } #endif -#ifndef CONFIG_OF_DYNAMIC -static void of_node_release(struct kobject *kobj) -{ - /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ -} -#endif /* CONFIG_OF_DYNAMIC */ - -struct kobj_type of_node_ktype = { - .release = of_node_release, -}; - -static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, - loff_t offset, size_t count) -{ - struct property *pp = container_of(bin_attr, struct property, attr); - return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length); -} - -/* always return newly allocated name, caller must free after use */ -static const char *safe_name(struct kobject *kobj, const char *orig_name) -{ - const char *name = orig_name; - struct kernfs_node *kn; - int i = 0; - - /* don't be a hero. After 16 tries give up */ - while (i < 16 && (kn = sysfs_get_dirent(kobj->sd, name))) { - sysfs_put(kn); - if (name != orig_name) - kfree(name); - name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i); - } - - if (name == orig_name) { - name = kstrdup(orig_name, GFP_KERNEL); - } else { - pr_warn("Duplicate name in %s, renamed to \"%s\"\n", - kobject_name(kobj), name); - } - return name; -} - -int __of_add_property_sysfs(struct device_node *np, struct property *pp) -{ - int rc; - - /* Important: Don't leak passwords */ - bool secure = strncmp(pp->name, "security-", 9) == 0; - - if (!IS_ENABLED(CONFIG_SYSFS)) - return 0; - - if (!of_kset || !of_node_is_attached(np)) - return 0; - - sysfs_bin_attr_init(&pp->attr); - pp->attr.attr.name = safe_name(&np->kobj, pp->name); - pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO; - pp->attr.size = secure ? 0 : pp->length; - pp->attr.read = of_node_property_read; - - rc = sysfs_create_bin_file(&np->kobj, &pp->attr); - WARN(rc, "error adding attribute %s to node %s\n", pp->name, np->full_name); - return rc; -} - -int __of_attach_node_sysfs(struct device_node *np) -{ - const char *name; - struct kobject *parent; - struct property *pp; - int rc; - - if (!IS_ENABLED(CONFIG_SYSFS)) - return 0; - - if (!of_kset) - return 0; - - np->kobj.kset = of_kset; - if (!np->parent) { - /* Nodes without parents are new top level trees */ - name = safe_name(&of_kset->kobj, "base"); - parent = NULL; - } else { - name = safe_name(&np->parent->kobj, kbasename(np->full_name)); - parent = &np->parent->kobj; - } - if (!name) - return -ENOMEM; - rc = kobject_add(&np->kobj, parent, "%s", name); - kfree(name); - if (rc) - return rc; - - for_each_property_of_node(np, pp) - __of_add_property_sysfs(np, pp); - - return 0; -} - static struct device_node **phandle_cache; static u32 phandle_cache_mask; @@ -2021,22 +1919,6 @@ int __of_remove_property(struct device_node *np, struct property *prop) return 0; } -void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop) -{ - sysfs_remove_bin_file(&np->kobj, &prop->attr); - kfree(prop->attr.attr.name); -} - -void __of_remove_property_sysfs(struct device_node *np, struct property *prop) -{ - if (!IS_ENABLED(CONFIG_SYSFS)) - return; - - /* at early boot, bail here and defer setup to of_init() */ - if (of_kset && of_node_is_attached(np)) - __of_sysfs_remove_bin_file(np, prop); -} - /** * of_remove_property - Remove a property from a node. * @@ -2096,21 +1978,6 @@ int __of_update_property(struct device_node *np, struct property *newprop, return 0; } -void __of_update_property_sysfs(struct device_node *np, struct property *newprop, - struct property *oldprop) -{ - if (!IS_ENABLED(CONFIG_SYSFS)) - return; - - /* At early boot, bail out and defer setup to of_init() */ - if (!of_kset) - return; - - if (oldprop) - __of_sysfs_remove_bin_file(np, oldprop); - __of_add_property_sysfs(np, newprop); -} - /* * of_update_property - Update a property in a node, if the property does * not exist, add it. diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index dc91a1b4c78c..765ba6e996a7 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -48,28 +48,6 @@ void of_node_put(struct device_node *node) } EXPORT_SYMBOL(of_node_put); -void __of_detach_node_sysfs(struct device_node *np) -{ - struct property *pp; - - if (!IS_ENABLED(CONFIG_SYSFS)) - return; - - BUG_ON(!of_node_is_initialized(np)); - if (!of_kset) - return; - - /* only remove properties if on sysfs */ - if (of_node_is_attached(np)) { - for_each_property_of_node(np, pp) - __of_sysfs_remove_bin_file(np, pp); - kobject_del(&np->kobj); - } - - /* finally remove the kobj_init ref */ - of_node_put(np); -} - static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); int of_reconfig_notifier_register(struct notifier_block *nb) diff --git a/drivers/of/kobj.c b/drivers/of/kobj.c new file mode 100644 index 000000000000..662f79e04bea --- /dev/null +++ b/drivers/of/kobj.c @@ -0,0 +1,165 @@ +#include +#include + +#include "of_private.h" + +/* true when node is initialized */ +static int of_node_is_initialized(struct device_node *node) +{ + return node && node->kobj.state_initialized; +} + +/* true when node is attached (i.e. present on sysfs) */ +int of_node_is_attached(struct device_node *node) +{ + return node && node->kobj.state_in_sysfs; +} + + +#ifndef CONFIG_OF_DYNAMIC +static void of_node_release(struct kobject *kobj) +{ + /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ +} +#endif /* CONFIG_OF_DYNAMIC */ + +struct kobj_type of_node_ktype = { + .release = of_node_release, +}; + +static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t offset, size_t count) +{ + struct property *pp = container_of(bin_attr, struct property, attr); + return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length); +} + +/* always return newly allocated name, caller must free after use */ +static const char *safe_name(struct kobject *kobj, const char *orig_name) +{ + const char *name = orig_name; + struct kernfs_node *kn; + int i = 0; + + /* don't be a hero. After 16 tries give up */ + while (i < 16 && name && (kn = sysfs_get_dirent(kobj->sd, name))) { + sysfs_put(kn); + if (name != orig_name) + kfree(name); + name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i); + } + + if (name == orig_name) { + name = kstrdup(orig_name, GFP_KERNEL); + } else { + pr_warn("Duplicate name in %s, renamed to \"%s\"\n", + kobject_name(kobj), name); + } + return name; +} + +int __of_add_property_sysfs(struct device_node *np, struct property *pp) +{ + int rc; + + /* Important: Don't leak passwords */ + bool secure = strncmp(pp->name, "security-", 9) == 0; + + if (!IS_ENABLED(CONFIG_SYSFS)) + return 0; + + if (!of_kset || !of_node_is_attached(np)) + return 0; + + sysfs_bin_attr_init(&pp->attr); + pp->attr.attr.name = safe_name(&np->kobj, pp->name); + pp->attr.attr.mode = secure ? 0400 : 0444; + pp->attr.size = secure ? 0 : pp->length; + pp->attr.read = of_node_property_read; + + rc = sysfs_create_bin_file(&np->kobj, &pp->attr); + WARN(rc, "error adding attribute %s to node %s\n", pp->name, + np->full_name); + return rc; +} + +void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop) +{ + if (!IS_ENABLED(CONFIG_SYSFS)) + return; + + sysfs_remove_bin_file(&np->kobj, &prop->attr); + kfree(prop->attr.attr.name); +} + +void __of_remove_property_sysfs(struct device_node *np, struct property *prop) +{ + /* at early boot, bail here and defer setup to of_init() */ + if (of_kset && of_node_is_attached(np)) + __of_sysfs_remove_bin_file(np, prop); +} + +void __of_update_property_sysfs(struct device_node *np, struct property *newprop, + struct property *oldprop) +{ + /* At early boot, bail out and defer setup to of_init() */ + if (!of_kset) + return; + + if (oldprop) + __of_sysfs_remove_bin_file(np, oldprop); + __of_add_property_sysfs(np, newprop); +} + +int __of_attach_node_sysfs(struct device_node *np) +{ + const char *name; + struct kobject *parent; + struct property *pp; + int rc; + + if (!of_kset) + return 0; + + np->kobj.kset = of_kset; + if (!np->parent) { + /* Nodes without parents are new top level trees */ + name = safe_name(&of_kset->kobj, "base"); + parent = NULL; + } else { + name = safe_name(&np->parent->kobj, kbasename(np->full_name)); + parent = &np->parent->kobj; + } + if (!name) + return -ENOMEM; + rc = kobject_add(&np->kobj, parent, "%s", name); + kfree(name); + if (rc) + return rc; + + for_each_property_of_node(np, pp) + __of_add_property_sysfs(np, pp); + + return 0; +} + +void __of_detach_node_sysfs(struct device_node *np) +{ + struct property *pp; + + BUG_ON(!of_node_is_initialized(np)); + if (!of_kset) + return; + + /* only remove properties if on sysfs */ + if (of_node_is_attached(np)) { + for_each_property_of_node(np, pp) + __of_sysfs_remove_bin_file(np, pp); + kobject_del(&np->kobj); + } + + /* finally remove the kobj_init ref */ + of_node_put(np); +} + diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index 61acd6bbd1aa..eb811185448c 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -49,6 +49,29 @@ static inline int of_property_notify(int action, struct device_node *np, } #endif /* CONFIG_OF_DYNAMIC */ +#if defined(CONFIG_OF_KOBJ) +int of_node_is_attached(struct device_node *node); +int __of_add_property_sysfs(struct device_node *np, struct property *pp); +void __of_remove_property_sysfs(struct device_node *np, struct property *prop); +void __of_update_property_sysfs(struct device_node *np, struct property *newprop, + struct property *oldprop); +int __of_attach_node_sysfs(struct device_node *np); +void __of_detach_node_sysfs(struct device_node *np); +#else +static inline int __of_add_property_sysfs(struct device_node *np, struct property *pp) +{ + return 0; +} +static inline void __of_remove_property_sysfs(struct device_node *np, struct property *prop) {} +static inline void __of_update_property_sysfs(struct device_node *np, + struct property *newprop, struct property *oldprop) {} +static inline int __of_attach_node_sysfs(struct device_node *np) +{ + return 0; +} +static inline void __of_detach_node_sysfs(struct device_node *np) {} +#endif + /** * General utilities for working with live trees. * diff --git a/include/linux/of.h b/include/linux/of.h index 3dcf853c4b14..e44e9a33ebae 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -39,7 +39,9 @@ struct property { struct property *next; unsigned long _flags; unsigned int unique_id; +#if defined(CONFIG_OF_KOBJ) struct bin_attribute attr; +#endif }; #if defined(CONFIG_SPARC) @@ -58,7 +60,9 @@ struct device_node { struct device_node *parent; struct device_node *child; struct device_node *sibling; +#if defined(CONFIG_OF_KOBJ) struct kobject kobj; +#endif unsigned long _flags; void *data; #if defined(CONFIG_SPARC) @@ -102,23 +106,17 @@ struct of_reconfig_data { extern struct kobj_type of_node_ktype; static inline void of_node_init(struct device_node *node) { +#if defined(CONFIG_OF_KOBJ) kobject_init(&node->kobj, &of_node_ktype); +#endif node->fwnode.type = FWNODE_OF; } +#if defined(CONFIG_OF_KOBJ) #define of_node_kobj(n) (&(n)->kobj) - -/* true when node is initialized */ -static inline int of_node_is_initialized(struct device_node *node) -{ - return node && node->kobj.state_initialized; -} - -/* true when node is attached (i.e. present on sysfs) */ -static inline int of_node_is_attached(struct device_node *node) -{ - return node && node->kobj.state_in_sysfs; -} +#else +#define of_node_kobj(n) NULL +#endif #ifdef CONFIG_OF_DYNAMIC extern struct device_node *of_node_get(struct device_node *node); -- GitLab From 27a4b773d5b47cd2ab871e62366b6b1e3709dba6 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Fri, 25 May 2018 12:38:25 -0700 Subject: [PATCH 622/855] of: Make CONFIG_OF_KOBJ configurable Add help text in order to allow this option to be selectable from menuconfig. Change-Id: I30de2aa184caa9dd5ad71b882fa4604cca910355 Signed-off-by: Patrick Daly --- drivers/of/Kconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index e4304e70a6d3..0a963b179105 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -47,7 +47,13 @@ config OF_PROMTREE bool config OF_KOBJ + bool "Display devicetree in sysfs" def_bool SYSFS + help + Some embedded platforms have no need to display the devicetree + nodes and properties in sysfs. Disabling this option will save + a small amount of memory, as well as decrease boot time. By + default this option will be enabled if SYSFS is enabled. # Hardly any platforms need this. It is safe to select, but only do so if you # need it. -- GitLab From 4ab3400a53b18a6a4df46f07a82c7e0076d2695e Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Fri, 18 May 2018 15:29:54 -0700 Subject: [PATCH 623/855] driver_core: Avoid NULL dereference when CONFIG_OF_KOBJ=n Avoid creating a symlink to a nonexistent kobject. Change-Id: I6468d8f5d6e585d84826762ba6c34ded71b030cd Signed-off-by: Patrick Daly --- drivers/base/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index b20d01699a85..42728680a678 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -876,7 +876,7 @@ static int device_add_class_symlinks(struct device *dev) struct device_node *of_node = dev_of_node(dev); int error; - if (of_node) { + if (of_node && of_node_kobj(of_node)) { error = sysfs_create_link(&dev->kobj, of_node_kobj(of_node), "of_node"); if (error) dev_warn(dev, "Error %d creating of_node link\n",error); -- GitLab From 9ec9c05f4ccde09500360ccf8055211e4fd14a63 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Wed, 16 May 2018 19:16:40 -0700 Subject: [PATCH 624/855] defconfig: msm8953-batcam: Enable performance optimizations Enable perfomance optimizations for msm8953-batcam. CONFIG_ARCH_MSM8953_BOOT_ORDERING causes devices to be added at late_initcall, with the result that probe order is controlled by the placement of a device in devicetree. Disabling CONFIG_OF_KOBJ causes no sysfs entries to be created for devicetree nodes or properties. Enabling HIBERNATION_SKIP_CRC improves decompression throughput. Change-Id: I0b6202fc34c0dd4685c7ba432af3b2608b94e5d7 Signed-off-by: Patrick Daly --- arch/arm/configs/msm8953-batcam-perf_defconfig | 3 +++ arch/arm/configs/msm8953-batcam_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/configs/msm8953-batcam-perf_defconfig b/arch/arm/configs/msm8953-batcam-perf_defconfig index a006ee1bb0b5..5b886a825e5a 100644 --- a/arch/arm/configs/msm8953-batcam-perf_defconfig +++ b/arch/arm/configs/msm8953-batcam-perf_defconfig @@ -40,6 +40,7 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_DEADLINE is not set CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSM8953=y +CONFIG_ARCH_MSM8953_BOOT_ORDERING=y # CONFIG_VDSO is not set CONFIG_SMP=y CONFIG_SCHED_MC=y @@ -66,6 +67,7 @@ CONFIG_KERNEL_MODE_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_HIBERNATION=y CONFIG_HIBERNATION_IMAGE_REUSE=y +CONFIG_HIBERNATION_SKIP_CRC=y CONFIG_PM_STD_PARTITION="/dev/mmcblk0p49" CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y @@ -75,6 +77,7 @@ CONFIG_NET=y CONFIG_UNIX=y CONFIG_INET=y CONFIG_DMA_CMA=y +# CONFIG_OF_KOBJ is not set CONFIG_QSEECOM=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y diff --git a/arch/arm/configs/msm8953-batcam_defconfig b/arch/arm/configs/msm8953-batcam_defconfig index 4a0c147a0362..dc6688c79b6b 100644 --- a/arch/arm/configs/msm8953-batcam_defconfig +++ b/arch/arm/configs/msm8953-batcam_defconfig @@ -39,6 +39,7 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_DEADLINE is not set CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSM8953=y +CONFIG_ARCH_MSM8953_BOOT_ORDERING=y # CONFIG_VDSO is not set CONFIG_SMP=y CONFIG_SCHED_MC=y @@ -65,6 +66,7 @@ CONFIG_KERNEL_MODE_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_HIBERNATION=y CONFIG_HIBERNATION_IMAGE_REUSE=y +CONFIG_HIBERNATION_SKIP_CRC=y CONFIG_PM_STD_PARTITION="/dev/mmcblk0p49" CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y @@ -74,6 +76,7 @@ CONFIG_NET=y CONFIG_UNIX=y CONFIG_INET=y CONFIG_DMA_CMA=y +# CONFIG_OF_KOBJ is not set CONFIG_QSEECOM=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y -- GitLab From 64f03f3d634bb6ba8309710752064d720b8d5ef4 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Wed, 4 Apr 2018 14:18:40 -0700 Subject: [PATCH 625/855] msm: camera: eeprom: Memory Allocation using vzalloc for larger data Use vzalloc instead of kzalloc to support for larger size data. Change-Id: I8d418bfbf8bc8fbe3b7c09850a674ee872d729cf Signed-off-by: Vishalsingh Hajeri --- .../cam_eeprom/cam_eeprom_core.c | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 37e768324f08..7f94f8d8c80d 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -315,8 +315,8 @@ int32_t cam_eeprom_parse_read_memory_map(struct device_node *of_node, power_down: cam_eeprom_power_down(e_ctrl); data_mem_free: - kfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); + vfree(e_ctrl->cal_data.mapdata); + vfree(e_ctrl->cal_data.map); e_ctrl->cal_data.num_data = 0; e_ctrl->cal_data.num_map = 0; e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; @@ -543,9 +543,9 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; - e_ctrl->cal_data.map = kcalloc((MSM_EEPROM_MEMORY_MAP_MAX_SIZE * - MSM_EEPROM_MAX_MEM_MAP_CNT), - (sizeof(struct cam_eeprom_memory_map_t)), GFP_KERNEL); + e_ctrl->cal_data.map = vzalloc((MSM_EEPROM_MEMORY_MAP_MAX_SIZE * + MSM_EEPROM_MAX_MEM_MAP_CNT) * + (sizeof(struct cam_eeprom_memory_map_t))); if (!e_ctrl->cal_data.map) { rc = -ENOMEM; CAM_ERR(CAM_EEPROM, "failed"); @@ -738,8 +738,8 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) return rc; } rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet); - kfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); + vfree(e_ctrl->cal_data.mapdata); + vfree(e_ctrl->cal_data.map); e_ctrl->cal_data.num_data = 0; e_ctrl->cal_data.num_map = 0; CAM_DBG(CAM_EEPROM, @@ -754,7 +754,7 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) } e_ctrl->cal_data.mapdata = - kzalloc(e_ctrl->cal_data.num_data, GFP_KERNEL); + vzalloc(e_ctrl->cal_data.num_data); if (!e_ctrl->cal_data.mapdata) { rc = -ENOMEM; CAM_ERR(CAM_EEPROM, "failed"); @@ -779,8 +779,8 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet); rc = cam_eeprom_power_down(e_ctrl); e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; - kfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); + vfree(e_ctrl->cal_data.mapdata); + vfree(e_ctrl->cal_data.map); kfree(power_info->power_setting); kfree(power_info->power_down_setting); power_info->power_setting = NULL; @@ -795,13 +795,13 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) power_down: cam_eeprom_power_down(e_ctrl); memdata_free: - kfree(e_ctrl->cal_data.mapdata); + vfree(e_ctrl->cal_data.mapdata); error: kfree(power_info->power_setting); kfree(power_info->power_down_setting); power_info->power_setting = NULL; power_info->power_down_setting = NULL; - kfree(e_ctrl->cal_data.map); + vfree(e_ctrl->cal_data.map); e_ctrl->cal_data.num_data = 0; e_ctrl->cal_data.num_map = 0; e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; -- GitLab From b01f3d75bb16e6466c4e420eae241ad7b805522e Mon Sep 17 00:00:00 2001 From: blong Date: Fri, 25 May 2018 16:37:37 +0800 Subject: [PATCH 626/855] arm64: Potential rollover condition for timer counter There is potential rollover condition for CNTVCT and CNTPCT counters. So on any architecture timer counter read, if the least significant 32 bits are set, reread counter. CRs-Fixed: 1074621 Change-Id: I136a5f0ee04deeb74c03800d591e44fbd9b4dd39 Signed-off-by: Prasad Sodagudi Signed-off-by: Biao long --- arch/arm64/include/asm/arch_timer.h | 11 ++++++++++- drivers/clocksource/Kconfig | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index eaa5bbe3fa87..f95235abc841 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h @@ -148,8 +148,17 @@ static inline u64 arch_counter_get_cntpct(void) static inline u64 arch_counter_get_cntvct(void) { + u64 cval; isb(); - return arch_timer_reg_read_stable(cntvct_el0); +#if IS_ENABLED(CONFIG_MSM_TIMER_LEAP) +#define L32_BITS 0x00000000FFFFFFFF + do { + cval = arch_timer_reg_read_stable(cntvct_el0); + } while ((cval & L32_BITS) == L32_BITS); +#else + cval = arch_timer_reg_read_stable(cntvct_el0); +#endif + return cval; } static inline int arch_timer_arch_init(void) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index cd6d3077d458..91cf85785782 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -331,6 +331,15 @@ config ARM_ARCH_TIMER_VCT_ACCESS This option enables support for reading the ARM architected timer's virtual counter in userspace. +config MSM_TIMER_LEAP + bool "ARCH TIMER counter rollover" + default n + depends on ARM_ARCH_TIMER && ARM64 + help + This option enables a check for least significant 32 bits of + counter rollover. On every counter read if least significant + 32 bits are set, reread counter. + config ARM_GLOBAL_TIMER bool "Support for the ARM global timer" if COMPILE_TEST select CLKSRC_OF if OF -- GitLab From 440b33a5fd28c961eff94b8837fcbfaf5733cd15 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Thu, 10 May 2018 22:25:03 +0530 Subject: [PATCH 627/855] drm/msm/dsi-staging: improve xlog debug support for dsi This change adds more debug points in xlog for dsi driver and also adds support to dump only dsi specific registers along with dsi debug bus registers instead of relying on full register dump every time. Change-Id: I27c122e7aea146af8a0241142486a7cf5a408e80 Signed-off-by: Sandeep Panda --- drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h | 3 +- drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c | 11 ++++- drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h | 4 +- .../gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c | 20 ++++---- drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 12 +++++ drivers/gpu/drm/msm/dsi-staging/dsi_phy.c | 2 + drivers/gpu/drm/msm/sde_dbg.c | 49 ++++++++++++++++++- drivers/gpu/drm/msm/sde_dbg.h | 8 +-- 8 files changed, 92 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h index 144ccd909cab..9a923aa179ca 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h @@ -108,7 +108,8 @@ void dsi_phy_hw_v3_0_toggle_resync_fifo(struct dsi_phy_hw *phy); /* DSI controller common ops */ u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl); -void dsi_ctrl_hw_cmn_debug_bus(struct dsi_ctrl_hw *ctrl); +void dsi_ctrl_hw_cmn_debug_bus(struct dsi_ctrl_hw *ctrl, u32 *entries, + u32 size); void dsi_ctrl_hw_cmn_clear_interrupt_status(struct dsi_ctrl_hw *ctrl, u32 ints); void dsi_ctrl_hw_cmn_enable_status_interrupts(struct dsi_ctrl_hw *ctrl, u32 ints); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index 32bc3eb5b655..ba147e22c5d1 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -243,6 +243,8 @@ static int dsi_ctrl_debugfs_init(struct dsi_ctrl *dsi_ctrl, dsi_ctrl->cell_index); sde_dbg_reg_register_base(dbg_name, dsi_ctrl->hw.base, msm_iomap_size(dsi_ctrl->pdev, "dsi_ctrl")); + sde_dbg_reg_register_dump_range(dbg_name, dbg_name, 0, + msm_iomap_size(dsi_ctrl->pdev, "dsi_ctrl"), 0); error_remove_dir: debugfs_remove(dir); error: @@ -272,6 +274,8 @@ static int dsi_ctrl_check_state(struct dsi_ctrl *dsi_ctrl, int rc = 0; struct dsi_ctrl_state_info *state = &dsi_ctrl->current_state; + SDE_EVT32(dsi_ctrl->cell_index, op); + switch (op) { case DSI_CTRL_OP_POWER_STATE_CHANGE: if (state->power_state == op_state) { @@ -1788,11 +1792,14 @@ static struct platform_driver dsi_ctrl_driver = { #if defined(CONFIG_DEBUG_FS) -void dsi_ctrl_debug_dump(void) +void dsi_ctrl_debug_dump(u32 *entries, u32 size) { struct list_head *pos, *tmp; struct dsi_ctrl *ctrl = NULL; + if (!entries || !size) + return; + mutex_lock(&dsi_ctrl_list_lock); list_for_each_safe(pos, tmp, &dsi_ctrl_list) { struct dsi_ctrl_list_item *n; @@ -1800,7 +1807,7 @@ void dsi_ctrl_debug_dump(void) n = list_entry(pos, struct dsi_ctrl_list_item, list); ctrl = n->ctrl; pr_err("dsi ctrl:%d\n", ctrl->cell_index); - ctrl->hw.ops.debug_bus(&ctrl->hw); + ctrl->hw.ops.debug_bus(&ctrl->hw, entries, size); } mutex_unlock(&dsi_ctrl_list_lock); } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h index d6fab59db44b..73aab3f5f9e3 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h @@ -457,8 +457,10 @@ struct dsi_ctrl_hw_ops { /** * debug_bus() - get dsi debug bus status. * @ctrl: Pointer to the controller host hardware. + * @entries: Array of dsi debug bus control values. + * @size: Size of dsi debug bus control array. */ - void (*debug_bus)(struct dsi_ctrl_hw *ctrl); + void (*debug_bus)(struct dsi_ctrl_hw *ctrl, u32 *entries, u32 size); /** * soft_reset() - perform a soft reset on DSI controller diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c index c1af52f84b91..6dde4548b71a 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c @@ -459,18 +459,20 @@ void dsi_ctrl_hw_cmn_video_engine_setup(struct dsi_ctrl_hw *ctrl, pr_debug("[DSI_%d] Video engine setup done\n", ctrl->index); } -void dsi_ctrl_hw_cmn_debug_bus(struct dsi_ctrl_hw *ctrl) +void dsi_ctrl_hw_cmn_debug_bus(struct dsi_ctrl_hw *ctrl, u32 *entries, u32 size) { - u32 reg = 0; - - DSI_W32(ctrl, DSI_DEBUG_BUS_CTL, 0x181); - - /* make sure that debug test point is enabled */ - wmb(); - reg = DSI_R32(ctrl, DSI_DEBUG_BUS_STATUS); + u32 reg = 0, i = 0; - pr_err("[DSI_%d] debug bus status:0x%x\n", ctrl->index, reg); + for (i = 0; i < size; i++) { + DSI_W32(ctrl, DSI_DEBUG_BUS_CTL, entries[i]); + /* make sure that debug test point is enabled */ + wmb(); + reg = DSI_R32(ctrl, DSI_DEBUG_BUS_STATUS); + pr_err("[DSI_%d] debug bus ctrl: 0x%x status:0x%x\n", + ctrl->index, entries[i], reg); + } } + /** * cmd_engine_setup() - setup dsi host controller for command mode * @ctrl: Pointer to the controller host hardware. diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index 7194f1aee24f..5e4506cae41a 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -715,6 +715,7 @@ int dsi_display_check_status(void *display, bool te_check_override) dsi_panel_release_panel_lock(panel); return rc; } + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); if (te_check_override && gpio_is_valid(dsi_display->disp_te_gpio)) status_mode = ESD_MODE_PANEL_TE; @@ -738,6 +739,7 @@ int dsi_display_check_status(void *display, bool te_check_override) dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_OFF); dsi_panel_release_panel_lock(panel); + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); return rc; } @@ -3665,6 +3667,7 @@ static int dsi_display_dfps_update(struct dsi_display *display, /* For split DSI, update the clock master first */ pr_debug("configuring seamless dynamic fps\n\n"); + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); m_ctrl = &display->ctrl[display->clk_master_idx]; rc = dsi_ctrl_async_timing_update(m_ctrl->ctrl, timing); @@ -3699,6 +3702,7 @@ static int dsi_display_dfps_update(struct dsi_display *display, panel_mode->dsi_mode_flags = 0; error: + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); return rc; } @@ -5820,6 +5824,7 @@ int dsi_display_prepare(struct dsi_display *display) return -EINVAL; } + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); mutex_lock(&display->display_lock); mode = display->panel->cur_mode; @@ -5954,6 +5959,7 @@ int dsi_display_prepare(struct dsi_display *display) (void)dsi_panel_post_unprepare(display->panel); error: mutex_unlock(&display->display_lock); + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); return rc; } @@ -6177,6 +6183,7 @@ int dsi_display_enable(struct dsi_display *display) pr_err("no valid mode set for the display"); return -EINVAL; } + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); /* Engine states and panel states are populated during splash * resource init and hence we return early @@ -6262,6 +6269,7 @@ int dsi_display_enable(struct dsi_display *display) (void)dsi_panel_disable(display->panel); error: mutex_unlock(&display->display_lock); + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); return rc; } @@ -6324,6 +6332,7 @@ int dsi_display_disable(struct dsi_display *display) return -EINVAL; } + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); mutex_lock(&display->display_lock); rc = dsi_display_wake_up(display); @@ -6352,6 +6361,7 @@ int dsi_display_disable(struct dsi_display *display) display->name, rc); mutex_unlock(&display->display_lock); + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); return rc; } @@ -6381,6 +6391,7 @@ int dsi_display_unprepare(struct dsi_display *display) return -EINVAL; } + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); mutex_lock(&display->display_lock); rc = dsi_display_wake_up(display); @@ -6434,6 +6445,7 @@ int dsi_display_unprepare(struct dsi_display *display) display->name, rc); mutex_unlock(&display->display_lock); + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); return rc; } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c index 2e2d0d81d643..14559fc73005 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c @@ -564,6 +564,8 @@ int dsi_phy_drv_init(struct msm_dsi_phy *dsi_phy) snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_phy", dsi_phy->index); sde_dbg_reg_register_base(dbg_name, dsi_phy->hw.base, msm_iomap_size(dsi_phy->pdev, "dsi_phy")); + sde_dbg_reg_register_dump_range(dbg_name, dbg_name, 0, + msm_iomap_size(dsi_phy->pdev, "dsi_phy"), 0); return 0; } diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c index 582909580be9..758cc53a1f9c 100644 --- a/drivers/gpu/drm/msm/sde_dbg.c +++ b/drivers/gpu/drm/msm/sde_dbg.c @@ -169,6 +169,11 @@ struct sde_dbg_vbif_debug_bus { struct vbif_debug_bus_entry *entries; }; +struct sde_dbg_dsi_debug_bus { + u32 *entries; + u32 size; +}; + /** * struct sde_dbg_base - global sde debug base structure * @evtlog: event log instance @@ -202,6 +207,7 @@ static struct sde_dbg_base { struct sde_dbg_sde_debug_bus dbgbus_sde; struct sde_dbg_vbif_debug_bus dbgbus_vbif_rt; + struct sde_dbg_dsi_debug_bus dbgbus_dsi; bool dump_all; bool dsi_dbg_bus; u32 debugfs_ctrl; @@ -2038,6 +2044,42 @@ static struct vbif_debug_bus_entry vbif_dbg_bus_msm8998[] = { {0x21c, 0x214, 0, 14, 0, 0xc}, /* xin blocks - clock side */ }; +static u32 dsi_dbg_bus_sdm845[] = { + 0x0001, 0x1001, 0x0001, 0x0011, + 0x1021, 0x0021, 0x0031, 0x0041, + 0x0051, 0x0061, 0x3061, 0x0061, + 0x2061, 0x2061, 0x1061, 0x1061, + 0x1061, 0x0071, 0x0071, 0x0071, + 0x0081, 0x0081, 0x00A1, 0x00A1, + 0x10A1, 0x20A1, 0x30A1, 0x10A1, + 0x10A1, 0x30A1, 0x20A1, 0x00B1, + 0x00C1, 0x00C1, 0x10C1, 0x20C1, + 0x30C1, 0x00D1, 0x00D1, 0x20D1, + 0x30D1, 0x00E1, 0x00E1, 0x00E1, + 0x00F1, 0x00F1, 0x0101, 0x0101, + 0x1101, 0x2101, 0x3101, 0x0111, + 0x0141, 0x1141, 0x0141, 0x1141, + 0x1141, 0x0151, 0x0151, 0x1151, + 0x2151, 0x3151, 0x0161, 0x0161, + 0x1161, 0x0171, 0x0171, 0x0181, + 0x0181, 0x0191, 0x0191, 0x01A1, + 0x01A1, 0x01B1, 0x01B1, 0x11B1, + 0x21B1, 0x01C1, 0x01C1, 0x11C1, + 0x21C1, 0x31C1, 0x01D1, 0x01D1, + 0x01D1, 0x01D1, 0x11D1, 0x21D1, + 0x21D1, 0x01E1, 0x01E1, 0x01F1, + 0x01F1, 0x0201, 0x0201, 0x0211, + 0x0221, 0x0231, 0x0241, 0x0251, + 0x0281, 0x0291, 0x0281, 0x0291, + 0x02A1, 0x02B1, 0x02C1, 0x0321, + 0x0321, 0x1321, 0x2321, 0x3321, + 0x0331, 0x0331, 0x1331, 0x0341, + 0x0341, 0x1341, 0x2341, 0x3341, + 0x0351, 0x0361, 0x0361, 0x1361, + 0x2361, 0x0371, 0x0381, 0x0391, + 0x03C1, 0x03D1, 0x03E1, 0x03F1, +}; + /** * _sde_dbg_enable_power - use callback to turn power on for hw register access * @enable: whether to turn power on or off @@ -2603,7 +2645,8 @@ static void _sde_dump_array(struct sde_dbg_reg_base *blk_arr[], _sde_dbg_dump_vbif_dbg_bus(&sde_dbg_base.dbgbus_vbif_rt); if (sde_dbg_base.dsi_dbg_bus || dump_all) - dsi_ctrl_debug_dump(); + dsi_ctrl_debug_dump(sde_dbg_base.dbgbus_dsi.entries, + sde_dbg_base.dbgbus_dsi.size); if (do_panic && sde_dbg_base.panic_on_err) panic(name); @@ -3355,6 +3398,8 @@ void sde_dbg_init_dbg_buses(u32 hwversion) dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998; dbg->dbgbus_vbif_rt.cmn.entries_size = ARRAY_SIZE(vbif_dbg_bus_msm8998); + dbg->dbgbus_dsi.entries = NULL; + dbg->dbgbus_dsi.size = 0; } else if (IS_SDM845_TARGET(hwversion) || IS_SDM670_TARGET(hwversion)) { dbg->dbgbus_sde.entries = dbg_bus_sde_sdm845; dbg->dbgbus_sde.cmn.entries_size = @@ -3365,6 +3410,8 @@ void sde_dbg_init_dbg_buses(u32 hwversion) dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998; dbg->dbgbus_vbif_rt.cmn.entries_size = ARRAY_SIZE(vbif_dbg_bus_msm8998); + dbg->dbgbus_dsi.entries = dsi_dbg_bus_sdm845; + dbg->dbgbus_dsi.size = ARRAY_SIZE(dsi_dbg_bus_sdm845); } else { pr_err("unsupported chipset id %X\n", hwversion); } diff --git a/drivers/gpu/drm/msm/sde_dbg.h b/drivers/gpu/drm/msm/sde_dbg.h index 9efb893d52e9..2921a38b6b68 100644 --- a/drivers/gpu/drm/msm/sde_dbg.h +++ b/drivers/gpu/drm/msm/sde_dbg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -344,8 +344,10 @@ void sde_rsc_debug_dump(u32 mux_sel); /** * dsi_ctrl_debug_dump - dump dsi debug dump status + * @entries: array of debug bus control values + * @size: size of the debug bus control array */ -void dsi_ctrl_debug_dump(void); +void dsi_ctrl_debug_dump(u32 *entries, u32 size); #else static inline struct sde_dbg_evtlog *sde_evtlog_init(void) @@ -437,7 +439,7 @@ static inline void sde_rsc_debug_dump(u32 mux_sel) { } -static inline void dsi_ctrl_debug_dump(void) +static inline void dsi_ctrl_debug_dump(u32 entries, u32 size) { } -- GitLab From 82e90fb332dbed8c59c6ed5c19e6a751ab934441 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Mon, 28 May 2018 20:32:44 +0530 Subject: [PATCH 628/855] arm64: smp: Get ipi_raise tracepoint working again 'commit 741a8ec5bb22 ("ARM64: smp: Prevent cluster LPM modes when pending IPIs on cluster CPUs")' broke ipi_raise trace point. Get it working again by replacing __smp_cross_call() with smp_cross_call(), which has a call to ipi_raise() tracepoint. While at it, add missing update to pending_ipi flag for IPI_IRQ_WORK. Change-Id: I4a847e833bf3b21abc58be88dfdc45da9bcfc676 Signed-off-by: Pavankumar Kondeti --- arch/arm64/kernel/smp.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 623dd48fd6a7..69d3266d41ee 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -602,16 +602,6 @@ acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header, void (*__smp_cross_call)(const struct cpumask *, unsigned int); DEFINE_PER_CPU(bool, pending_ipi); -void smp_cross_call_common(const struct cpumask *cpumask, unsigned int func) -{ - unsigned int cpu; - - for_each_cpu(cpu, cpumask) - per_cpu(pending_ipi, cpu) = true; - - __smp_cross_call(cpumask, func); -} - /* * Enumerate the possible CPU set from the device tree and build the * cpu logical map array containing MPIDR values related to logical @@ -779,6 +769,17 @@ static void smp_cross_call(const struct cpumask *target, unsigned int ipinr) __smp_cross_call(target, ipinr); } +static void smp_cross_call_common(const struct cpumask *cpumask, + unsigned int func) +{ + unsigned int cpu; + + for_each_cpu(cpu, cpumask) + per_cpu(pending_ipi, cpu) = true; + + smp_cross_call(cpumask, func); +} + void show_ipi_list(struct seq_file *p, int prec) { unsigned int cpu, i; @@ -825,7 +826,8 @@ void arch_send_wakeup_ipi_mask(const struct cpumask *mask) void arch_irq_work_raise(void) { if (__smp_cross_call) - smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK); + smp_cross_call_common(cpumask_of(smp_processor_id()), + IPI_IRQ_WORK); } #endif -- GitLab From 6c7b11455881982f4631c35997b334fb3b992bed Mon Sep 17 00:00:00 2001 From: Sachin Grover Date: Thu, 24 May 2018 22:48:55 +0530 Subject: [PATCH 629/855] selinux: KASAN: slab-out-of-bounds in xattr_getsecurity Call trace: [] dump_backtrace+0x0/0x428 [] show_stack+0x28/0x38 [] dump_stack+0xd4/0x124 [] print_address_description+0x68/0x258 [] kasan_report.part.2+0x228/0x2f0 [] kasan_report+0x5c/0x70 [] check_memory_region+0x12c/0x1c0 [] memcpy+0x34/0x68 [] xattr_getsecurity+0xe0/0x160 [] vfs_getxattr+0xc8/0x120 [] getxattr+0x100/0x2c8 [] SyS_fgetxattr+0x64/0xa0 [] el0_svc_naked+0x24/0x28 If user get root access and calls security.selinux setxattr() with an embedded NUL on a file and then if some process performs a getxattr() on that file with a length greater than the actual length of the string, it would result in a panic. To fix this, add the actual length of the string to the security context instead of the length passed by the userspace process. Change-Id: Ie0b8bfc7c96bc12282b955fb3adf41b3c2d011cd Signed-off-by: Sachin Grover --- security/selinux/ss/services.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 9b517a42a1af..a6b097098aba 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1434,7 +1434,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, scontext_len, &context, def_sid); if (rc == -EINVAL && force) { context.str = str; - context.len = scontext_len; + context.len = strlen(str) + 1; str = NULL; } else if (rc) goto out_unlock; -- GitLab From a06ed1d75e056da56db1b4afa74152a061089b95 Mon Sep 17 00:00:00 2001 From: Jayant Shekhar Date: Tue, 29 May 2018 21:25:58 +0530 Subject: [PATCH 630/855] drm/msm/sde: Add debugfs support for fence info dump Add changes to SDE driver to dump fence related information via debugfs node. Command to dump the information: cat /d/dri/0/crtc*/fence_status This provides CRTC ID: with fence status, associated connector fence, and all staged plane fence status. Change-Id: I3528bb5d864eb045c0c8611cc40e50739f602523 Signed-off-by: Jayant Shekhar --- drivers/gpu/drm/msm/sde/sde_crtc.c | 73 +++++++++++++++++++++++++++++ drivers/gpu/drm/msm/sde/sde_fence.c | 52 ++++++++++++++++++++ drivers/gpu/drm/msm/sde/sde_fence.h | 28 +++++++++++ 3 files changed, 153 insertions(+) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index cefa5139e29b..95034154813b 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -5692,6 +5692,73 @@ static int sde_crtc_debugfs_state_show(struct seq_file *s, void *v) } DEFINE_SDE_DEBUGFS_SEQ_FOPS(sde_crtc_debugfs_state); +static int _sde_debugfs_fence_status_show(struct seq_file *s, void *data) +{ + struct drm_crtc *crtc; + struct drm_plane *plane; + struct drm_connector *conn; + struct drm_mode_object *drm_obj; + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct sde_fence_context *ctx; + + if (!s || !s->private) + return -EINVAL; + + sde_crtc = s->private; + crtc = &sde_crtc->base; + cstate = to_sde_crtc_state(crtc->state); + + /* Dump input fence info */ + seq_puts(s, "===Input fence===\n"); + drm_atomic_crtc_for_each_plane(plane, crtc) { + struct sde_plane_state *pstate; + struct fence *fence; + + pstate = to_sde_plane_state(plane->state); + if (!pstate) + continue; + + seq_printf(s, "plane:%u stage:%d\n", plane->base.id, + pstate->stage); + + fence = pstate->input_fence; + if (fence) + sde_fence_list_dump(fence, &s); + } + + /* Dump release fence info */ + seq_puts(s, "\n"); + seq_puts(s, "===Release fence===\n"); + ctx = &sde_crtc->output_fence; + drm_obj = &crtc->base; + sde_debugfs_timeline_dump(ctx, drm_obj, &s); + seq_puts(s, "\n"); + + /* Dump retire fence info */ + seq_puts(s, "===Retire fence===\n"); + drm_for_each_connector(conn, crtc->dev) + if (conn->state && conn->state->crtc == crtc && + cstate->num_connectors < MAX_CONNECTORS) { + struct sde_connector *c_conn; + + c_conn = to_sde_connector(conn); + ctx = &c_conn->retire_fence; + drm_obj = &conn->base; + sde_debugfs_timeline_dump(ctx, drm_obj, &s); + } + + seq_puts(s, "\n"); + + return 0; +} + +static int _sde_debugfs_fence_status(struct inode *inode, struct file *file) +{ + return single_open(file, _sde_debugfs_fence_status_show, + inode->i_private); +} + static int _sde_crtc_init_debugfs(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc; @@ -5708,6 +5775,10 @@ static int _sde_crtc_init_debugfs(struct drm_crtc *crtc) .read = _sde_crtc_misr_read, .write = _sde_crtc_misr_setup, }; + static const struct file_operations debugfs_fence_fops = { + .open = _sde_debugfs_fence_status, + .read = seq_read, + }; if (!crtc) return -EINVAL; @@ -5732,6 +5803,8 @@ static int _sde_crtc_init_debugfs(struct drm_crtc *crtc) &sde_crtc_debugfs_state_fops); debugfs_create_file("misr_data", 0600, sde_crtc->debugfs_root, sde_crtc, &debugfs_misr_fops); + debugfs_create_file("fence_status", 0400, sde_crtc->debugfs_root, + sde_crtc, &debugfs_fence_fops); return 0; } diff --git a/drivers/gpu/drm/msm/sde/sde_fence.c b/drivers/gpu/drm/msm/sde/sde_fence.c index 1f30a5c85abc..8ffbb98a03fc 100644 --- a/drivers/gpu/drm/msm/sde/sde_fence.c +++ b/drivers/gpu/drm/msm/sde/sde_fence.c @@ -431,3 +431,55 @@ void sde_fence_timeline_status(struct sde_fence_context *ctx, obj_name, drm_obj->id, drm_obj->type, ctx->done_count, ctx->commit_count); } + +void sde_fence_list_dump(struct fence *fence, struct seq_file **s) +{ + char timeline_str[TIMELINE_VAL_LENGTH]; + + if (fence->ops->timeline_value_str) + fence->ops->timeline_value_str(fence, + timeline_str, TIMELINE_VAL_LENGTH); + + seq_printf(*s, "fence name:%s timeline name:%s seqno:0x%x timeline:%s signaled:0x%x\n", + fence->ops->get_driver_name(fence), + fence->ops->get_timeline_name(fence), + fence->seqno, timeline_str, + fence->ops->signaled ? + fence->ops->signaled(fence) : 0xffffffff); +} + +void sde_debugfs_timeline_dump(struct sde_fence_context *ctx, + struct drm_mode_object *drm_obj, struct seq_file **s) +{ + char *obj_name; + struct sde_fence *fc, *next; + struct fence *fence; + + if (!ctx || !drm_obj) { + SDE_ERROR("invalid input params\n"); + return; + } + + switch (drm_obj->type) { + case DRM_MODE_OBJECT_CRTC: + obj_name = "crtc"; + break; + case DRM_MODE_OBJECT_CONNECTOR: + obj_name = "connector"; + break; + default: + obj_name = "unknown"; + break; + } + + seq_printf(*s, "drm obj:%s id:%d type:0x%x done_count:%d commit_count:%d\n", + obj_name, drm_obj->id, drm_obj->type, ctx->done_count, + ctx->commit_count); + + spin_lock(&ctx->list_lock); + list_for_each_entry_safe(fc, next, &ctx->fence_list_head, fence_list) { + fence = &fc->base; + sde_fence_list_dump(fence, s); + } + spin_unlock(&ctx->list_lock); +} diff --git a/drivers/gpu/drm/msm/sde/sde_fence.h b/drivers/gpu/drm/msm/sde/sde_fence.h index 7891be45f138..7d7fd021727d 100644 --- a/drivers/gpu/drm/msm/sde/sde_fence.h +++ b/drivers/gpu/drm/msm/sde/sde_fence.h @@ -153,6 +153,22 @@ void sde_fence_signal(struct sde_fence_context *fence, ktime_t ts, void sde_fence_timeline_status(struct sde_fence_context *ctx, struct drm_mode_object *drm_obj); +/** + * sde_fence_timeline_dump - utility to dump fence list info in debugfs node + * @fence: Pointer fence container + * @drm_obj: Pointer to drm object associated with fence timeline + * @s: used to writing on debugfs node + */ +void sde_debugfs_timeline_dump(struct sde_fence_context *ctx, + struct drm_mode_object *drm_obj, struct seq_file **s); + +/** + * sde_fence_timeline_status - dumps fence timeline in debugfs node + * @fence: Pointer fence container + * @s: used to writing on debugfs node + */ +void sde_fence_list_dump(struct fence *fence, struct seq_file **s); + #else static inline void *sde_sync_get(uint64_t fd) { @@ -212,6 +228,18 @@ static inline void sde_fence_timeline_status(struct sde_fence_context *ctx, { /* do nothing */ } + +void sde_debugfs_timeline_dump(struct sde_fence_context *ctx, + struct drm_mode_object *drm_obj, struct seq_file **s) +{ + /* do nothing */ +} + +void sde_fence_list_dump(struct fence *fence, struct seq_file **s) +{ + /* do nothing */ +} + #endif /* IS_ENABLED(CONFIG_SW_SYNC) */ #endif /* _SDE_FENCE_H_ */ -- GitLab From 25b0542bb6a20a0f02b7755a3fcd99c848d39827 Mon Sep 17 00:00:00 2001 From: Shubhashree Dhar Date: Wed, 30 May 2018 15:42:04 +0530 Subject: [PATCH 631/855] msm/sde: Unregister input handler during encoder disable Flush and unregister input handler in encoder disable and register again in encoder enable. This is done to ensure that input handler doesn't work during suspend mode. Change-Id: I457a7e88bdf3bfd966da69edc81d14584dbeb784 Signed-off-by: Shubhashree Dhar --- drivers/gpu/drm/msm/sde/sde_encoder.c | 216 ++++++++++++++------------ 1 file changed, 119 insertions(+), 97 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 2ce8b2ece557..edad9acf5253 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -738,8 +738,8 @@ void sde_encoder_destroy(struct drm_encoder *drm_enc) mutex_destroy(&sde_enc->enc_lock); if (sde_enc->input_handler) { - input_unregister_handler(sde_enc->input_handler); kfree(sde_enc->input_handler); + sde_enc->input_handler = NULL; } kfree(sde_enc); @@ -2510,6 +2510,109 @@ void sde_encoder_control_te(struct drm_encoder *drm_enc, bool enable) } } +static int _sde_encoder_input_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) +{ + struct input_handle *handle; + int rc = 0; + + handle = kzalloc(sizeof(*handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = handler->name; + + rc = input_register_handle(handle); + if (rc) { + pr_err("failed to register input handle\n"); + goto error; + } + + rc = input_open_device(handle); + if (rc) { + pr_err("failed to open input device\n"); + goto error_unregister; + } + + return 0; + +error_unregister: + input_unregister_handle(handle); + +error: + kfree(handle); + + return rc; +} + +static void _sde_encoder_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +/** + * Structure for specifying event parameters on which to receive callbacks. + * This structure will trigger a callback in case of a touch event (specified by + * EV_ABS) where there is a change in X and Y coordinates, + */ +static const struct input_device_id sde_input_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_ABS) }, + .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = + BIT_MASK(ABS_MT_POSITION_X) | + BIT_MASK(ABS_MT_POSITION_Y) }, + }, + { }, +}; + +static int _sde_encoder_input_handler_register( + struct input_handler *input_handler) +{ + int rc = 0; + + rc = input_register_handler(input_handler); + if (rc) { + pr_err("input_register_handler failed, rc= %d\n", rc); + kfree(input_handler); + return rc; + } + + return rc; +} + +static int _sde_encoder_input_handler( + struct sde_encoder_virt *sde_enc) +{ + struct input_handler *input_handler = NULL; + int rc = 0; + + if (sde_enc->input_handler) { + SDE_ERROR_ENC(sde_enc, + "input_handle is active. unexpected\n"); + return -EINVAL; + } + + input_handler = kzalloc(sizeof(*sde_enc->input_handler), GFP_KERNEL); + if (!input_handler) + return -ENOMEM; + + input_handler->event = sde_encoder_input_event_handler; + input_handler->connect = _sde_encoder_input_connect; + input_handler->disconnect = _sde_encoder_input_disconnect; + input_handler->name = "sde"; + input_handler->id_table = sde_input_ids; + input_handler->private = sde_enc; + + sde_enc->input_handler = input_handler; + + return rc; +} + static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc) { struct sde_encoder_virt *sde_enc = NULL; @@ -2584,12 +2687,14 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) struct msm_compression_info *comp_info = NULL; struct drm_display_mode *cur_mode = NULL; struct msm_mode_info mode_info; + struct msm_display_info *disp_info; if (!drm_enc) { SDE_ERROR("invalid encoder\n"); return; } sde_enc = to_sde_encoder_virt(drm_enc); + disp_info = &sde_enc->disp_info; if (!sde_kms_power_resource_is_enabled(drm_enc->dev)) { SDE_ERROR("power resource is not enabled\n"); @@ -2627,6 +2732,14 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) return; } + if (sde_enc->input_handler) { + ret = _sde_encoder_input_handler_register( + sde_enc->input_handler); + if (ret) + SDE_ERROR( + "input handler registration failed, rc = %d\n", ret); + } + ret = sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_KICKOFF); if (ret) { SDE_ERROR_ENC(sde_enc, "sde resource control failed: %d\n", @@ -2705,6 +2818,11 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc) /* wait for idle */ sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); + kthread_flush_work(&sde_enc->input_event_work); + + if (sde_enc->input_handler) + input_unregister_handler(sde_enc->input_handler); + /* * For primary command mode encoders, execute the resource control * pre-stop operations before the physical encoders are disabled, to @@ -3633,102 +3751,6 @@ static void sde_encoder_input_event_work_handler(struct kthread_work *work) SDE_ENC_RC_EVENT_EARLY_WAKEUP); } -static int _sde_encoder_input_connect(struct input_handler *handler, - struct input_dev *dev, const struct input_device_id *id) -{ - struct input_handle *handle; - int rc = 0; - - handle = kzalloc(sizeof(*handle), GFP_KERNEL); - if (!handle) - return -ENOMEM; - - handle->dev = dev; - handle->handler = handler; - handle->name = handler->name; - - rc = input_register_handle(handle); - if (rc) { - pr_err("failed to register input handle\n"); - goto error; - } - - rc = input_open_device(handle); - if (rc) { - pr_err("failed to open input device\n"); - goto error_unregister; - } - - return 0; - -error_unregister: - input_unregister_handle(handle); - -error: - kfree(handle); - - return rc; -} - -static void _sde_encoder_input_disconnect(struct input_handle *handle) -{ - input_close_device(handle); - input_unregister_handle(handle); - kfree(handle); -} - -/** - * Structure for specifying event parameters on which to receive callbacks. - * This structure will trigger a callback in case of a touch event (specified by - * EV_ABS) where there is a change in X and Y coordinates, - */ -static const struct input_device_id sde_input_ids[] = { - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT, - .evbit = { BIT_MASK(EV_ABS) }, - .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = - BIT_MASK(ABS_MT_POSITION_X) | - BIT_MASK(ABS_MT_POSITION_Y) }, - }, - { }, -}; - -static int _sde_encoder_input_handler( - struct sde_encoder_virt *sde_enc) -{ - struct input_handler *input_handler = NULL; - int rc = 0; - - if (sde_enc->input_handler) { - SDE_ERROR_ENC(sde_enc, - "input_handle is active. unexpected\n"); - return -EINVAL; - } - - input_handler = kzalloc(sizeof(*sde_enc->input_handler), GFP_KERNEL); - if (!input_handler) - return -ENOMEM; - - input_handler->event = sde_encoder_input_event_handler; - input_handler->connect = _sde_encoder_input_connect; - input_handler->disconnect = _sde_encoder_input_disconnect; - input_handler->name = "sde"; - input_handler->id_table = sde_input_ids; - input_handler->private = sde_enc; - - rc = input_register_handler(input_handler); - if (rc) { - SDE_ERROR_ENC(sde_enc, - "input_register_handler failed, rc= %d\n", rc); - kfree(input_handler); - return rc; - } - - sde_enc->input_handler = input_handler; - - return rc; -} - static void sde_encoder_vsync_event_work_handler(struct kthread_work *work) { struct sde_encoder_virt *sde_enc = container_of(work, -- GitLab From 91e530b1265afe8aa0114ba05a69f2baede7e211 Mon Sep 17 00:00:00 2001 From: blong Date: Mon, 28 May 2018 11:23:05 +0800 Subject: [PATCH 632/855] arm64: enable MSM_TIMER_LEAP config There is potential rollover condition for CNTVCT and CNTPCT counters.enable the config to control the counter read to avoid rollover. Change-Id: Ie39a2401ee41440da87cc3327b1904cf6666cfdc CRs-Fixed: 1074621 Signed-off-by: Biao long --- arch/arm64/configs/msm8953-perf_defconfig | 1 + arch/arm64/configs/msm8953_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig index 1f539cb1e15b..a811f5e31abd 100644 --- a/arch/arm64/configs/msm8953-perf_defconfig +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -545,6 +545,7 @@ CONFIG_MSM_EXT_DISPLAY=y CONFIG_MSM_RMNET_BAM=y CONFIG_MSM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_TIMER_LEAP=y CONFIG_MAILBOX=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index 788512b67585..83e996f84e88 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -556,6 +556,7 @@ CONFIG_MSM_EXT_DISPLAY=y CONFIG_MSM_RMNET_BAM=y CONFIG_MSM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_TIMER_LEAP=y CONFIG_MAILBOX=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y -- GitLab From 0fb11cc508253f58c624938504f43be4f8c47bf4 Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Thu, 31 May 2018 13:57:31 +0800 Subject: [PATCH 633/855] arm64: Fix wrong type conversion in writeq_no_log Current code converts a 64 bit integer to 32 bit in writeq_relaxed_no_log. Fix that by change cpu_to_le32() to cpu_to_le64(). Change-Id: I6ccb4c3dd90d7d1c786daec746cd6974f2e42d7c Signed-off-by: Tingwei Zhang --- arch/arm64/include/asm/io.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h index 5c0c57e24a19..388a0ca36ea8 100644 --- a/arch/arm64/include/asm/io.h +++ b/arch/arm64/include/asm/io.h @@ -167,9 +167,9 @@ static inline u64 __raw_readq_no_log(const volatile void __iomem *addr) #define readq_relaxed_no_log(c) ({ u64 __v = le64_to_cpu((__force __le64)__raw_readq_no_log(c)); __v; }) #define writeb_relaxed_no_log(v, c) ((void)__raw_writeb_no_log((v), (c))) -#define writew_relaxed_no_log(v, c) ((void)__raw_writew_no_log((__force u16)cpu_to_le32(v), (c))) +#define writew_relaxed_no_log(v, c) ((void)__raw_writew_no_log((__force u16)cpu_to_le16(v), (c))) #define writel_relaxed_no_log(v, c) ((void)__raw_writel_no_log((__force u32)cpu_to_le32(v), (c))) -#define writeq_relaxed_no_log(v, c) ((void)__raw_writeq_no_log((__force u64)cpu_to_le32(v), (c))) +#define writeq_relaxed_no_log(v, c) ((void)__raw_writeq_no_log((__force u64)cpu_to_le64(v), (c))) /* * I/O memory access primitives. Reads are ordered relative to any -- GitLab From 06076c9516b048768e88f77b060b4ff5c35114ba Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Thu, 31 May 2018 14:12:44 +0800 Subject: [PATCH 634/855] soc: qcom: User resource pair number correctly The number of resource pairs conveyed by the HW starts at 0, i.e a value of 0x0 indicate 1 resource pair, 0x1 indicate two and so on. As such add 1 to the value of NUMRSPAIR for a better representation. Multiple 2 in save and restore operattion since it's number of pairs. Change-Id: I3a0999ee05ad6a24322195a001e9ce6e1685c6fb Signed-off-by: Tingwei Zhang --- drivers/soc/qcom/jtagv8-etm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/soc/qcom/jtagv8-etm.c b/drivers/soc/qcom/jtagv8-etm.c index 3f4b8bcc3408..23cbb7b3fb40 100644 --- a/drivers/soc/qcom/jtagv8-etm.c +++ b/drivers/soc/qcom/jtagv8-etm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -345,7 +345,7 @@ static inline void etm_mm_save_state(struct etm_ctx *etmdata) TRCCNTVRn(j)); } /* resource selection registers */ - for (j = 0; j < etmdata->nr_resource; j++) + for (j = 0; j < etmdata->nr_resource * 2; j++) etmdata->state[i++] = etm_readl(etmdata, TRCRSCTLRn(j)); /* comparator registers */ for (j = 0; j < etmdata->nr_addr_cmp * 2; j++) { @@ -448,7 +448,7 @@ static inline void etm_mm_restore_state(struct etm_ctx *etmdata) etm_writel(etmdata, etmdata->state[i++], TRCCNTVRn(j)); } /* resource selection registers */ - for (j = 0; j < etmdata->nr_resource; j++) + for (j = 0; j < etmdata->nr_resource * 2; j++) etm_writel(etmdata, etmdata->state[i++], TRCRSCTLRn(j)); /* comparator registers */ for (j = 0; j < etmdata->nr_addr_cmp * 2; j++) { @@ -932,7 +932,7 @@ static inline void etm_si_save_state(struct etm_ctx *etmdata) for (j = 0; j < etmdata->nr_cntr; j++) i = etm_read_crxr(etmdata->state, i, j); /* resource selection registers */ - for (j = 0; j < etmdata->nr_resource; j++) + for (j = 0; j < etmdata->nr_resource * 2; j++) i = etm_read_rsxr(etmdata->state, i, j + 2); /* comparator registers */ for (j = 0; j < etmdata->nr_addr_cmp * 2; j++) @@ -1387,7 +1387,7 @@ static inline void etm_si_restore_state(struct etm_ctx *etmdata) for (j = 0; j < etmdata->nr_cntr; j++) i = etm_write_crxr(etmdata->state, i, j); /* resource selection registers */ - for (j = 0; j < etmdata->nr_resource; j++) + for (j = 0; j < etmdata->nr_resource * 2; j++) i = etm_write_rsxr(etmdata->state, i, j + 2); /* comparator registers */ for (j = 0; j < etmdata->nr_addr_cmp * 2; j++) @@ -1496,7 +1496,7 @@ static void etm_init_arch_data(void *info) val = etm_readl(etmdata, TRCIDR4); etmdata->nr_addr_cmp = BMVAL(val, 0, 3); etmdata->nr_data_cmp = BMVAL(val, 4, 7); - etmdata->nr_resource = BMVAL(val, 16, 19); + etmdata->nr_resource = BMVAL(val, 16, 19) + 1; etmdata->nr_ss_cmp = BMVAL(val, 20, 23); etmdata->nr_ctxid_cmp = BMVAL(val, 24, 27); etmdata->nr_vmid_cmp = BMVAL(val, 28, 31); -- GitLab From 6463b4b9947ff041f18b89ddd8a163022597a0ea Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Fri, 25 May 2018 19:44:14 +0800 Subject: [PATCH 635/855] jtagv8: add jtagv8 snapshot This snapshot is taken as of msm-4.4 'commit a6ff4b8ab4ad ("ARM: dts: qcom: Remove lpm performance index for sdm660")' It adds two head file for jtagv8 arm support. Change-Id: I6a049dee89478b9a4ac0019dc15c857e2046541f Signed-off-by: Tingwei Zhang --- arch/arm/include/asm/etmv4x.h | 387 ++++++++++++++++++++++++ arch/arm/include/asm/hardware/debugv8.h | 247 +++++++++++++++ 2 files changed, 634 insertions(+) create mode 100644 arch/arm/include/asm/etmv4x.h create mode 100644 arch/arm/include/asm/hardware/debugv8.h diff --git a/arch/arm/include/asm/etmv4x.h b/arch/arm/include/asm/etmv4x.h new file mode 100644 index 000000000000..7ad0a926fdfe --- /dev/null +++ b/arch/arm/include/asm/etmv4x.h @@ -0,0 +1,387 @@ +/* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __ASM_ETMV4X_H +#define __ASM_ETMV4X_H + +#include + + +/* 32 bit register read for AArch32 */ +#define trc_readl(reg) RSYSL_##reg() +#define trc_readq(reg) RSYSL_##reg() + +/* 32 bit register write for AArch32 */ +#define trc_write(val, reg) WSYS_##reg(val) + +#define MRC(op0, op1, crn, crm, op2) \ +({ \ +uint32_t val; \ +asm volatile("mrc p"#op0", "#op1", %0, "#crn", "#crm", "#op2 : "=r" (val)); \ +val; \ +}) + +#define MCR(val, op0, op1, crn, crm, op2) \ +({ \ +asm volatile("mcr p"#op0", "#op1", %0, "#crn", "#crm", "#op2 : : "r" (val));\ +}) + +/* Clock and Power Management Register */ +#define RSYSL_CPMR_EL1() MRC(15, 7, c15, c0, 5) +#define WSYS_CPMR_EL1(val) MCR(val, 15, 7, c15, c0, 5) + +/* + * ETMv4 Registers + * + * Read only + * ETMAUTHSTATUS, ETMDEVARCH, ETMDEVID, ETMIDRn[0-13], ETMOSLSR, ETMSTATR + * + * Write only + * ETMOSLAR + */ +/* 32 bit registers */ +#define RSYSL_ETMAUTHSTATUS() MRC(14, 1, c7, c14, 6) +#define RSYSL_ETMAUXCTLR() MRC(14, 1, c0, c6, 0) +#define RSYSL_ETMCCCTLR() MRC(14, 1, c0, c14, 0) +#define RSYSL_ETMCIDCCTLR0() MRC(14, 1, c3, c0, 2) +#define RSYSL_ETMCNTCTLR0() MRC(14, 1, c0, c4, 5) +#define RSYSL_ETMCNTCTLR1() MRC(14, 1, c0, c5, 5) +#define RSYSL_ETMCNTCTLR2() MRC(14, 1, c0, c6, 5) +#define RSYSL_ETMCNTCTLR3() MRC(14, 1, c0, c7, 5) +#define RSYSL_ETMCNTRLDVR0() MRC(14, 1, c0, c0, 5) +#define RSYSL_ETMCNTRLDVR1() MRC(14, 1, c0, c1, 5) +#define RSYSL_ETMCNTRLDVR2() MRC(14, 1, c0, c2, 5) +#define RSYSL_ETMCNTRLDVR3() MRC(14, 1, c0, c3, 5) +#define RSYSL_ETMCNTVR0() MRC(14, 1, c0, c8, 5) +#define RSYSL_ETMCNTVR1() MRC(14, 1, c0, c9, 5) +#define RSYSL_ETMCNTVR2() MRC(14, 1, c0, c10, 5) +#define RSYSL_ETMCNTVR3() MRC(14, 1, c0, c11, 5) +#define RSYSL_ETMCONFIGR() MRC(14, 1, c0, c4, 0) +#define RSYSL_ETMDEVARCH() MRC(14, 1, c7, c15, 6) +#define RSYSL_ETMDEVID() MRC(14, 1, c7, c2, 7) +#define RSYSL_ETMEVENTCTL0R() MRC(14, 1, c0, c8, 0) +#define RSYSL_ETMEVENTCTL1R() MRC(14, 1, c0, c9, 0) +#define RSYSL_ETMEXTINSELR() MRC(14, 1, c0, c8, 4) +#define RSYSL_ETMIDR0() MRC(14, 1, c0, c8, 7) +#define RSYSL_ETMIDR1() MRC(14, 1, c0, c9, 7) +#define RSYSL_ETMIDR10() MRC(14, 1, c0, c2, 6) +#define RSYSL_ETMIDR11() MRC(14, 1, c0, c3, 6) +#define RSYSL_ETMIDR12() MRC(14, 1, c0, c4, 6) +#define RSYSL_ETMIDR13() MRC(14, 1, c0, c5, 6) +#define RSYSL_ETMIDR2() MRC(14, 1, c0, c10, 7) +#define RSYSL_ETMIDR3() MRC(14, 1, c0, c11, 7) +#define RSYSL_ETMIDR4() MRC(14, 1, c0, c12, 7) +#define RSYSL_ETMIDR5() MRC(14, 1, c0, c13, 7) +#define RSYSL_ETMIDR6() MRC(14, 1, c0, c14, 7) +#define RSYSL_ETMIDR7() MRC(14, 1, c0, c15, 7) +#define RSYSL_ETMIDR8() MRC(14, 1, c0, c0, 6) +#define RSYSL_ETMIDR9() MRC(14, 1, c0, c1, 6) +#define RSYSL_ETMIMSPEC0() MRC(14, 1, c0, c0, 7) +#define RSYSL_ETMOSLSR() MRC(14, 1, c1, c1, 4) +#define RSYSL_ETMPRGCTLR() MRC(14, 1, c0, c1, 0) +#define RSYSL_ETMRSCTLR10() MRC(14, 1, c1, c10, 0) +#define RSYSL_ETMRSCTLR11() MRC(14, 1, c1, c11, 0) +#define RSYSL_ETMRSCTLR12() MRC(14, 1, c1, c12, 0) +#define RSYSL_ETMRSCTLR13() MRC(14, 1, c1, c13, 0) +#define RSYSL_ETMRSCTLR14() MRC(14, 1, c1, c14, 0) +#define RSYSL_ETMRSCTLR15() MRC(14, 1, c1, c15, 0) +#define RSYSL_ETMRSCTLR2() MRC(14, 1, c1, c2, 0) +#define RSYSL_ETMRSCTLR3() MRC(14, 1, c1, c3, 0) +#define RSYSL_ETMRSCTLR4() MRC(14, 1, c1, c4, 0) +#define RSYSL_ETMRSCTLR5() MRC(14, 1, c1, c5, 0) +#define RSYSL_ETMRSCTLR6() MRC(14, 1, c1, c6, 0) +#define RSYSL_ETMRSCTLR7() MRC(14, 1, c1, c7, 0) +#define RSYSL_ETMRSCTLR8() MRC(14, 1, c1, c8, 0) +#define RSYSL_ETMRSCTLR9() MRC(14, 1, c1, c9, 0) +#define RSYSL_ETMRSCTLR16() MRC(14, 1, c1, c0, 1) +#define RSYSL_ETMRSCTLR17() MRC(14, 1, c1, c1, 1) +#define RSYSL_ETMRSCTLR18() MRC(14, 1, c1, c2, 1) +#define RSYSL_ETMRSCTLR19() MRC(14, 1, c1, c3, 1) +#define RSYSL_ETMRSCTLR20() MRC(14, 1, c1, c4, 1) +#define RSYSL_ETMRSCTLR21() MRC(14, 1, c1, c5, 1) +#define RSYSL_ETMRSCTLR22() MRC(14, 1, c1, c6, 1) +#define RSYSL_ETMRSCTLR23() MRC(14, 1, c1, c7, 1) +#define RSYSL_ETMRSCTLR24() MRC(14, 1, c1, c8, 1) +#define RSYSL_ETMRSCTLR25() MRC(14, 1, c1, c9, 1) +#define RSYSL_ETMRSCTLR26() MRC(14, 1, c1, c10, 1) +#define RSYSL_ETMRSCTLR27() MRC(14, 1, c1, c11, 1) +#define RSYSL_ETMRSCTLR28() MRC(14, 1, c1, c12, 1) +#define RSYSL_ETMRSCTLR29() MRC(14, 1, c1, c13, 1) +#define RSYSL_ETMRSCTLR30() MRC(14, 1, c1, c14, 1) +#define RSYSL_ETMRSCTLR31() MRC(14, 1, c1, c15, 1) +#define RSYSL_ETMSEQEVR0() MRC(14, 1, c0, c0, 4) +#define RSYSL_ETMSEQEVR1() MRC(14, 1, c0, c1, 4) +#define RSYSL_ETMSEQEVR2() MRC(14, 1, c0, c2, 4) +#define RSYSL_ETMSEQRSTEVR() MRC(14, 1, c0, c6, 4) +#define RSYSL_ETMSEQSTR() MRC(14, 1, c0, c7, 4) +#define RSYSL_ETMSTALLCTLR() MRC(14, 1, c0, c11, 0) +#define RSYSL_ETMSTATR() MRC(14, 1, c0, c3, 0) +#define RSYSL_ETMSYNCPR() MRC(14, 1, c0, c13, 0) +#define RSYSL_ETMTRACEIDR() MRC(14, 1, c0, c0, 1) +#define RSYSL_ETMTSCTLR() MRC(14, 1, c0, c12, 0) +#define RSYSL_ETMVICTLR() MRC(14, 1, c0, c0, 2) +#define RSYSL_ETMVIIECTLR() MRC(14, 1, c0, c1, 2) +#define RSYSL_ETMVISSCTLR() MRC(14, 1, c0, c2, 2) +#define RSYSL_ETMSSCCR0() MRC(14, 1, c1, c0, 2) +#define RSYSL_ETMSSCCR1() MRC(14, 1, c1, c1, 2) +#define RSYSL_ETMSSCCR2() MRC(14, 1, c1, c2, 2) +#define RSYSL_ETMSSCCR3() MRC(14, 1, c1, c3, 2) +#define RSYSL_ETMSSCCR4() MRC(14, 1, c1, c4, 2) +#define RSYSL_ETMSSCCR5() MRC(14, 1, c1, c5, 2) +#define RSYSL_ETMSSCCR6() MRC(14, 1, c1, c6, 2) +#define RSYSL_ETMSSCCR7() MRC(14, 1, c1, c7, 2) +#define RSYSL_ETMSSCSR0() MRC(14, 1, c1, c8, 2) +#define RSYSL_ETMSSCSR1() MRC(14, 1, c1, c9, 2) +#define RSYSL_ETMSSCSR2() MRC(14, 1, c1, c10, 2) +#define RSYSL_ETMSSCSR3() MRC(14, 1, c1, c11, 2) +#define RSYSL_ETMSSCSR4() MRC(14, 1, c1, c12, 2) +#define RSYSL_ETMSSCSR5() MRC(14, 1, c1, c13, 2) +#define RSYSL_ETMSSCSR6() MRC(14, 1, c1, c14, 2) +#define RSYSL_ETMSSCSR7() MRC(14, 1, c1, c15, 2) +#define RSYSL_ETMSSPCICR0() MRC(14, 1, c1, c0, 3) +#define RSYSL_ETMSSPCICR1() MRC(14, 1, c1, c1, 3) +#define RSYSL_ETMSSPCICR2() MRC(14, 1, c1, c2, 3) +#define RSYSL_ETMSSPCICR3() MRC(14, 1, c1, c3, 3) +#define RSYSL_ETMSSPCICR4() MRC(14, 1, c1, c4, 3) +#define RSYSL_ETMSSPCICR5() MRC(14, 1, c1, c5, 3) +#define RSYSL_ETMSSPCICR6() MRC(14, 1, c1, c6, 3) +#define RSYSL_ETMSSPCICR7() MRC(14, 1, c1, c7, 3) + +/* + * 64 bit registers, ignore the upper 32bit + * A read from a 32-bit register location using a 64-bit access result + * in the upper 32bits being return as RES0. + */ +#define RSYSL_ETMACATR0() MRC(14, 1, c2, c0, 2) +#define RSYSL_ETMACATR1() MRC(14, 1, c2, c2, 2) +#define RSYSL_ETMACATR2() MRC(14, 1, c2, c4, 2) +#define RSYSL_ETMACATR3() MRC(14, 1, c2, c6, 2) +#define RSYSL_ETMACATR4() MRC(14, 1, c2, c8, 2) +#define RSYSL_ETMACATR5() MRC(14, 1, c2, c10, 2) +#define RSYSL_ETMACATR6() MRC(14, 1, c2, c12, 2) +#define RSYSL_ETMACATR7() MRC(14, 1, c2, c14, 2) +#define RSYSL_ETMACATR8() MRC(14, 1, c2, c0, 3) +#define RSYSL_ETMACATR9() MRC(14, 1, c2, c2, 3) +#define RSYSL_ETMACATR10() MRC(14, 1, c2, c4, 3) +#define RSYSL_ETMACATR11() MRC(14, 1, c2, c6, 3) +#define RSYSL_ETMACATR12() MRC(14, 1, c2, c8, 3) +#define RSYSL_ETMACATR13() MRC(14, 1, c2, c10, 3) +#define RSYSL_ETMACATR14() MRC(14, 1, c2, c12, 3) +#define RSYSL_ETMACATR15() MRC(14, 1, c2, c14, 3) +#define RSYSL_ETMCIDCVR0() MRC(14, 1, c3, c0, 0) +#define RSYSL_ETMCIDCVR1() MRC(14, 1, c3, c2, 0) +#define RSYSL_ETMCIDCVR2() MRC(14, 1, c3, c4, 0) +#define RSYSL_ETMCIDCVR3() MRC(14, 1, c3, c6, 0) +#define RSYSL_ETMCIDCVR4() MRC(14, 1, c3, c8, 0) +#define RSYSL_ETMCIDCVR5() MRC(14, 1, c3, c10, 0) +#define RSYSL_ETMCIDCVR6() MRC(14, 1, c3, c12, 0) +#define RSYSL_ETMCIDCVR7() MRC(14, 1, c3, c14, 0) +#define RSYSL_ETMACVR0() MRC(14, 1, c2, c0, 0) +#define RSYSL_ETMACVR1() MRC(14, 1, c2, c2, 0) +#define RSYSL_ETMACVR2() MRC(14, 1, c2, c4, 0) +#define RSYSL_ETMACVR3() MRC(14, 1, c2, c6, 0) +#define RSYSL_ETMACVR4() MRC(14, 1, c2, c8, 0) +#define RSYSL_ETMACVR5() MRC(14, 1, c2, c10, 0) +#define RSYSL_ETMACVR6() MRC(14, 1, c2, c12, 0) +#define RSYSL_ETMACVR7() MRC(14, 1, c2, c14, 0) +#define RSYSL_ETMACVR8() MRC(14, 1, c2, c0, 1) +#define RSYSL_ETMACVR9() MRC(14, 1, c2, c2, 1) +#define RSYSL_ETMACVR10() MRC(14, 1, c2, c4, 1) +#define RSYSL_ETMACVR11() MRC(14, 1, c2, c6, 1) +#define RSYSL_ETMACVR12() MRC(14, 1, c2, c8, 1) +#define RSYSL_ETMACVR13() MRC(14, 1, c2, c10, 1) +#define RSYSL_ETMACVR14() MRC(14, 1, c2, c12, 1) +#define RSYSL_ETMACVR15() MRC(14, 1, c2, c14, 1) +#define RSYSL_ETMVMIDCVR0() MRC(14, 1, c3, c0, 1) +#define RSYSL_ETMVMIDCVR1() MRC(14, 1, c3, c2, 1) +#define RSYSL_ETMVMIDCVR2() MRC(14, 1, c3, c4, 1) +#define RSYSL_ETMVMIDCVR3() MRC(14, 1, c3, c6, 1) +#define RSYSL_ETMVMIDCVR4() MRC(14, 1, c3, c8, 1) +#define RSYSL_ETMVMIDCVR5() MRC(14, 1, c3, c10, 1) +#define RSYSL_ETMVMIDCVR6() MRC(14, 1, c3, c12, 1) +#define RSYSL_ETMVMIDCVR7() MRC(14, 1, c3, c14, 1) +#define RSYSL_ETMDVCVR0() MRC(14, 1, c2, c0, 4) +#define RSYSL_ETMDVCVR1() MRC(14, 1, c2, c4, 4) +#define RSYSL_ETMDVCVR2() MRC(14, 1, c2, c8, 4) +#define RSYSL_ETMDVCVR3() MRC(14, 1, c2, c12, 4) +#define RSYSL_ETMDVCVR4() MRC(14, 1, c2, c0, 5) +#define RSYSL_ETMDVCVR5() MRC(14, 1, c2, c4, 5) +#define RSYSL_ETMDVCVR6() MRC(14, 1, c2, c8, 5) +#define RSYSL_ETMDVCVR7() MRC(14, 1, c2, c12, 5) +#define RSYSL_ETMDVCMR0() MRC(14, 1, c2, c0, 6) +#define RSYSL_ETMDVCMR1() MRC(14, 1, c2, c4, 6) +#define RSYSL_ETMDVCMR2() MRC(14, 1, c2, c8, 6) +#define RSYSL_ETMDVCMR3() MRC(14, 1, c2, c12, 6) +#define RSYSL_ETMDVCMR4() MRC(14, 1, c2, c0, 7) +#define RSYSL_ETMDVCMR5() MRC(14, 1, c2, c4, 7) +#define RSYSL_ETMDVCMR6() MRC(14, 1, c2, c8, 7) +#define RSYSL_ETMDVCMR7() MRC(14, 1, c2, c12, 7) + +/* + * 32 and 64 bit registers + * A write to a 32-bit register location using a 64-bit access result + * in the upper 32bit of access + */ +#define WSYS_ETMAUXCTLR(val) MCR(val, 14, 1, c0, c6, 0) +#define WSYS_ETMACATR0(val) MCR(val, 14, 1, c2, c0, 2) +#define WSYS_ETMACATR1(val) MCR(val, 14, 1, c2, c2, 2) +#define WSYS_ETMACATR2(val) MCR(val, 14, 1, c2, c4, 2) +#define WSYS_ETMACATR3(val) MCR(val, 14, 1, c2, c6, 2) +#define WSYS_ETMACATR4(val) MCR(val, 14, 1, c2, c8, 2) +#define WSYS_ETMACATR5(val) MCR(val, 14, 1, c2, c10, 2) +#define WSYS_ETMACATR6(val) MCR(val, 14, 1, c2, c12, 2) +#define WSYS_ETMACATR7(val) MCR(val, 14, 1, c2, c14, 2) +#define WSYS_ETMACATR8(val) MCR(val, 14, 1, c2, c0, 3) +#define WSYS_ETMACATR9(val) MCR(val, 14, 1, c2, c2, 3) +#define WSYS_ETMACATR10(val) MCR(val, 14, 1, c2, c4, 3) +#define WSYS_ETMACATR11(val) MCR(val, 14, 1, c2, c6, 3) +#define WSYS_ETMACATR12(val) MCR(val, 14, 1, c2, c8, 3) +#define WSYS_ETMACATR13(val) MCR(val, 14, 1, c2, c10, 3) +#define WSYS_ETMACATR14(val) MCR(val, 14, 1, c2, c12, 3) +#define WSYS_ETMACATR15(val) MCR(val, 14, 1, c2, c14, 3) +#define WSYS_ETMACVR0(val) MCR(val, 14, 1, c2, c0, 0) +#define WSYS_ETMACVR1(val) MCR(val, 14, 1, c2, c2, 0) +#define WSYS_ETMACVR2(val) MCR(val, 14, 1, c2, c4, 0) +#define WSYS_ETMACVR3(val) MCR(val, 14, 1, c2, c6, 0) +#define WSYS_ETMACVR4(val) MCR(val, 14, 1, c2, c8, 0) +#define WSYS_ETMACVR5(val) MCR(val, 14, 1, c2, c10, 0) +#define WSYS_ETMACVR6(val) MCR(val, 14, 1, c2, c12, 0) +#define WSYS_ETMACVR7(val) MCR(val, 14, 1, c2, c14, 0) +#define WSYS_ETMACVR8(val) MCR(val, 14, 1, c2, c0, 1) +#define WSYS_ETMACVR9(val) MCR(val, 14, 1, c2, c2, 1) +#define WSYS_ETMACVR10(val) MCR(val, 14, 1, c2, c4, 1) +#define WSYS_ETMACVR11(val) MCR(val, 14, 1, c2, c6, 1) +#define WSYS_ETMACVR12(val) MCR(val, 14, 1, c2, c8, 1) +#define WSYS_ETMACVR13(val) MCR(val, 14, 1, c2, c10, 1) +#define WSYS_ETMACVR14(val) MCR(val, 14, 1, c2, c12, 1) +#define WSYS_ETMACVR15(val) MCR(val, 14, 1, c2, c14, 1) +#define WSYS_ETMCCCTLR(val) MCR(val, 14, 1, c0, c14, 0) +#define WSYS_ETMCIDCCTLR0(val) MCR(val, 14, 1, c3, c0, 2) +#define WSYS_ETMCIDCVR0(val) MCR(val, 14, 1, c3, c0, 0) +#define WSYS_ETMCIDCVR1(val) MCR(val, 14, 1, c3, c2, 0) +#define WSYS_ETMCIDCVR2(val) MCR(val, 14, 1, c3, c4, 0) +#define WSYS_ETMCIDCVR3(val) MCR(val, 14, 1, c3, c6, 0) +#define WSYS_ETMCIDCVR4(val) MCR(val, 14, 1, c3, c8, 0) +#define WSYS_ETMCIDCVR5(val) MCR(val, 14, 1, c3, c10, 0) +#define WSYS_ETMCIDCVR6(val) MCR(val, 14, 1, c3, c12, 0) +#define WSYS_ETMCIDCVR7(val) MCR(val, 14, 1, c3, c14, 0) +#define WSYS_ETMCNTCTLR0(val) MCR(val, 14, 1, c0, c4, 5) +#define WSYS_ETMCNTCTLR1(val) MCR(val, 14, 1, c0, c5, 5) +#define WSYS_ETMCNTCTLR2(val) MCR(val, 14, 1, c0, c6, 5) +#define WSYS_ETMCNTCTLR3(val) MCR(val, 14, 1, c0, c7, 5) +#define WSYS_ETMCNTRLDVR0(val) MCR(val, 14, 1, c0, c0, 5) +#define WSYS_ETMCNTRLDVR1(val) MCR(val, 14, 1, c0, c1, 5) +#define WSYS_ETMCNTRLDVR2(val) MCR(val, 14, 1, c0, c2, 5) +#define WSYS_ETMCNTRLDVR3(val) MCR(val, 14, 1, c0, c3, 5) +#define WSYS_ETMCNTVR0(val) MCR(val, 14, 1, c0, c8, 5) +#define WSYS_ETMCNTVR1(val) MCR(val, 14, 1, c0, c9, 5) +#define WSYS_ETMCNTVR2(val) MCR(val, 14, 1, c0, c10, 5) +#define WSYS_ETMCNTVR3(val) MCR(val, 14, 1, c0, c11, 5) +#define WSYS_ETMCONFIGR(val) MCR(val, 14, 1, c0, c4, 0) +#define WSYS_ETMEVENTCTL0R(val) MCR(val, 14, 1, c0, c8, 0) +#define WSYS_ETMEVENTCTL1R(val) MCR(val, 14, 1, c0, c9, 0) +#define WSYS_ETMEXTINSELR(val) MCR(val, 14, 1, c0, c8, 4) +#define WSYS_ETMIMSPEC0(val) MCR(val, 14, 1, c0, c0, 7) +#define WSYS_ETMOSLAR(val) MCR(val, 14, 1, c1, c0, 4) +#define WSYS_ETMPRGCTLR(val) MCR(val, 14, 1, c0, c1, 0) +#define WSYS_ETMRSCTLR10(val) MCR(val, 14, 1, c1, c10, 0) +#define WSYS_ETMRSCTLR11(val) MCR(val, 14, 1, c1, c11, 0) +#define WSYS_ETMRSCTLR12(val) MCR(val, 14, 1, c1, c12, 0) +#define WSYS_ETMRSCTLR13(val) MCR(val, 14, 1, c1, c13, 0) +#define WSYS_ETMRSCTLR14(val) MCR(val, 14, 1, c1, c14, 0) +#define WSYS_ETMRSCTLR15(val) MCR(val, 14, 1, c1, c15, 0) +#define WSYS_ETMRSCTLR2(val) MCR(val, 14, 1, c1, c2, 0) +#define WSYS_ETMRSCTLR3(val) MCR(val, 14, 1, c1, c3, 0) +#define WSYS_ETMRSCTLR4(val) MCR(val, 14, 1, c1, c4, 0) +#define WSYS_ETMRSCTLR5(val) MCR(val, 14, 1, c1, c5, 0) +#define WSYS_ETMRSCTLR6(val) MCR(val, 14, 1, c1, c6, 0) +#define WSYS_ETMRSCTLR7(val) MCR(val, 14, 1, c1, c7, 0) +#define WSYS_ETMRSCTLR8(val) MCR(val, 14, 1, c1, c8, 0) +#define WSYS_ETMRSCTLR9(val) MCR(val, 14, 1, c1, c9, 0) +#define WSYS_ETMRSCTLR16(val) MCR(val, 14, 1, c1, c0, 1) +#define WSYS_ETMRSCTLR17(val) MCR(val, 14, 1, c1, c1, 1) +#define WSYS_ETMRSCTLR18(val) MCR(val, 14, 1, c1, c2, 1) +#define WSYS_ETMRSCTLR19(val) MCR(val, 14, 1, c1, c3, 1) +#define WSYS_ETMRSCTLR20(val) MCR(val, 14, 1, c1, c4, 1) +#define WSYS_ETMRSCTLR21(val) MCR(val, 14, 1, c1, c5, 1) +#define WSYS_ETMRSCTLR22(val) MCR(val, 14, 1, c1, c6, 1) +#define WSYS_ETMRSCTLR23(val) MCR(val, 14, 1, c1, c7, 1) +#define WSYS_ETMRSCTLR24(val) MCR(val, 14, 1, c1, c8, 1) +#define WSYS_ETMRSCTLR25(val) MCR(val, 14, 1, c1, c9, 1) +#define WSYS_ETMRSCTLR26(val) MCR(val, 14, 1, c1, c10, 1) +#define WSYS_ETMRSCTLR27(val) MCR(val, 14, 1, c1, c11, 1) +#define WSYS_ETMRSCTLR28(val) MCR(val, 14, 1, c1, c12, 1) +#define WSYS_ETMRSCTLR29(val) MCR(val, 14, 1, c1, c13, 1) +#define WSYS_ETMRSCTLR30(val) MCR(val, 14, 1, c1, c14, 1) +#define WSYS_ETMRSCTLR31(val) MCR(val, 14, 1, c1, c15, 1) +#define WSYS_ETMSEQEVR0(val) MCR(val, 14, 1, c0, c0, 4) +#define WSYS_ETMSEQEVR1(val) MCR(val, 14, 1, c0, c1, 4) +#define WSYS_ETMSEQEVR2(val) MCR(val, 14, 1, c0, c2, 4) +#define WSYS_ETMSEQRSTEVR(val) MCR(val, 14, 1, c0, c6, 4) +#define WSYS_ETMSEQSTR(val) MCR(val, 14, 1, c0, c7, 4) +#define WSYS_ETMSTALLCTLR(val) MCR(val, 14, 1, c0, c11, 0) +#define WSYS_ETMSYNCPR(val) MCR(val, 14, 1, c0, c13, 0) +#define WSYS_ETMTRACEIDR(val) MCR(val, 14, 1, c0, c0, 1) +#define WSYS_ETMTSCTLR(val) MCR(val, 14, 1, c0, c12, 0) +#define WSYS_ETMVICTLR(val) MCR(val, 14, 1, c0, c0, 2) +#define WSYS_ETMVIIECTLR(val) MCR(val, 14, 1, c0, c1, 2) +#define WSYS_ETMVISSCTLR(val) MCR(val, 14, 1, c0, c2, 2) +#define WSYS_ETMVMIDCVR0(val) MCR(val, 14, 1, c3, c0, 1) +#define WSYS_ETMVMIDCVR1(val) MCR(val, 14, 1, c3, c2, 1) +#define WSYS_ETMVMIDCVR2(val) MCR(val, 14, 1, c3, c4, 1) +#define WSYS_ETMVMIDCVR3(val) MCR(val, 14, 1, c3, c6, 1) +#define WSYS_ETMVMIDCVR4(val) MCR(val, 14, 1, c3, c8, 1) +#define WSYS_ETMVMIDCVR5(val) MCR(val, 14, 1, c3, c10, 1) +#define WSYS_ETMVMIDCVR6(val) MCR(val, 14, 1, c3, c12, 1) +#define WSYS_ETMVMIDCVR7(val) MCR(val, 14, 1, c3, c14, 1) +#define WSYS_ETMDVCVR0(val) MCR(val, 14, 1, c2, c0, 4) +#define WSYS_ETMDVCVR1(val) MCR(val, 14, 1, c2, c4, 4) +#define WSYS_ETMDVCVR2(val) MCR(val, 14, 1, c2, c8, 4) +#define WSYS_ETMDVCVR3(val) MCR(val, 14, 1, c2, c12, 4) +#define WSYS_ETMDVCVR4(val) MCR(val, 14, 1, c2, c0, 5) +#define WSYS_ETMDVCVR5(val) MCR(val, 14, 1, c2, c4, 5) +#define WSYS_ETMDVCVR6(val) MCR(val, 14, 1, c2, c8, 5) +#define WSYS_ETMDVCVR7(val) MCR(val, 14, 1, c2, c12, 5) +#define WSYS_ETMDVCMR0(val) MCR(val, 14, 1, c2, c0, 6) +#define WSYS_ETMDVCMR1(val) MCR(val, 14, 1, c2, c4, 6) +#define WSYS_ETMDVCMR2(val) MCR(val, 14, 1, c2, c8, 6) +#define WSYS_ETMDVCMR3(val) MCR(val, 14, 1, c2, c12, 6) +#define WSYS_ETMDVCMR4(val) MCR(val, 14, 1, c2, c0, 7) +#define WSYS_ETMDVCMR5(val) MCR(val, 14, 1, c2, c4, 7) +#define WSYS_ETMDVCMR6(val) MCR(val, 14, 1, c2, c8, 7) +#define WSYS_ETMDVCMR7(val) MCR(val, 14, 1, c2, c12, 7) +#define WSYS_ETMSSCCR0(val) MCR(val, 14, 1, c1, c0, 2) +#define WSYS_ETMSSCCR1(val) MCR(val, 14, 1, c1, c1, 2) +#define WSYS_ETMSSCCR2(val) MCR(val, 14, 1, c1, c2, 2) +#define WSYS_ETMSSCCR3(val) MCR(val, 14, 1, c1, c3, 2) +#define WSYS_ETMSSCCR4(val) MCR(val, 14, 1, c1, c4, 2) +#define WSYS_ETMSSCCR5(val) MCR(val, 14, 1, c1, c5, 2) +#define WSYS_ETMSSCCR6(val) MCR(val, 14, 1, c1, c6, 2) +#define WSYS_ETMSSCCR7(val) MCR(val, 14, 1, c1, c7, 2) +#define WSYS_ETMSSCSR0(val) MCR(val, 14, 1, c1, c8, 2) +#define WSYS_ETMSSCSR1(val) MCR(val, 14, 1, c1, c9, 2) +#define WSYS_ETMSSCSR2(val) MCR(val, 14, 1, c1, c10, 2) +#define WSYS_ETMSSCSR3(val) MCR(val, 14, 1, c1, c11, 2) +#define WSYS_ETMSSCSR4(val) MCR(val, 14, 1, c1, c12, 2) +#define WSYS_ETMSSCSR5(val) MCR(val, 14, 1, c1, c13, 2) +#define WSYS_ETMSSCSR6(val) MCR(val, 14, 1, c1, c14, 2) +#define WSYS_ETMSSCSR7(val) MCR(val, 14, 1, c1, c15, 2) +#define WSYS_ETMSSPCICR0(val) MCR(val, 14, 1, c1, c0, 3) +#define WSYS_ETMSSPCICR1(val) MCR(val, 14, 1, c1, c1, 3) +#define WSYS_ETMSSPCICR2(val) MCR(val, 14, 1, c1, c2, 3) +#define WSYS_ETMSSPCICR3(val) MCR(val, 14, 1, c1, c3, 3) +#define WSYS_ETMSSPCICR4(val) MCR(val, 14, 1, c1, c4, 3) +#define WSYS_ETMSSPCICR5(val) MCR(val, 14, 1, c1, c5, 3) +#define WSYS_ETMSSPCICR6(val) MCR(val, 14, 1, c1, c6, 3) +#define WSYS_ETMSSPCICR7(val) MCR(val, 14, 1, c1, c7, 3) + +#endif diff --git a/arch/arm/include/asm/hardware/debugv8.h b/arch/arm/include/asm/hardware/debugv8.h new file mode 100644 index 000000000000..a8249cd1b8c5 --- /dev/null +++ b/arch/arm/include/asm/hardware/debugv8.h @@ -0,0 +1,247 @@ +/* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __ASM_HARDWARE_DEBUGV8_H +#define __ASM_HARDWARE_DEBUGV8_H + +#include + +/* Accessors for CP14 registers */ +#define dbg_read(reg) RCP14_##reg() +#define dbg_write(val, reg) WCP14_##reg(val) + +/* MRC14 registers */ +#define MRC14(op1, crn, crm, op2) \ +({ \ +uint32_t val; \ +asm volatile("mrc p14, "#op1", %0, "#crn", "#crm", "#op2 : "=r" (val)); \ +val; \ +}) + +/* MCR14 registers */ +#define MCR14(val, op1, crn, crm, op2) \ +({ \ +asm volatile("mcr p14, "#op1", %0, "#crn", "#crm", "#op2 : : "r" (val));\ +}) + +/* + * Debug Registers + * + * Read only + * DBGDIDR, DBGDSCRint, DBGDTRRXint, DBGDRAR, DBGOSLSR, DBGOSSRR, DBGDSAR, + * DBGAUTHSTATUS, DBGDEVID2, DBGDEVID1, DBGDEVID + * + * Write only + * DBGDTRTXint, DBGOSLAR + */ +#define RCP14_DBGDIDR() MRC14(0, c0, c0, 0) +#define RCP14_DBGDSCRint() MRC14(0, c0, c1, 0) +#define RCP14_DBGDCCINT() MRC14(0, c0, c2, 0) +#define RCP14_DBGDTRRXint() MRC14(0, c0, c5, 0) +#define RCP14_DBGWFAR() MRC14(0, c0, c6, 0) +#define RCP14_DBGVCR() MRC14(0, c0, c7, 0) +#define RCP14_DBGDTRRXext() MRC14(0, c0, c0, 2) +#define RCP14_DBGDSCRext() MRC14(0, c0, c2, 2) +#define RCP14_DBGDTRTXext() MRC14(0, c0, c3, 2) +#define RCP14_DBGOSECCR() MRC14(0, c0, c6, 2) +#define RCP14_DBGBVR0() MRC14(0, c0, c0, 4) +#define RCP14_DBGBVR1() MRC14(0, c0, c1, 4) +#define RCP14_DBGBVR2() MRC14(0, c0, c2, 4) +#define RCP14_DBGBVR3() MRC14(0, c0, c3, 4) +#define RCP14_DBGBVR4() MRC14(0, c0, c4, 4) +#define RCP14_DBGBVR5() MRC14(0, c0, c5, 4) +#define RCP14_DBGBVR6() MRC14(0, c0, c6, 4) +#define RCP14_DBGBVR7() MRC14(0, c0, c7, 4) +#define RCP14_DBGBVR8() MRC14(0, c0, c8, 4) +#define RCP14_DBGBVR9() MRC14(0, c0, c9, 4) +#define RCP14_DBGBVR10() MRC14(0, c0, c10, 4) +#define RCP14_DBGBVR11() MRC14(0, c0, c11, 4) +#define RCP14_DBGBVR12() MRC14(0, c0, c12, 4) +#define RCP14_DBGBVR13() MRC14(0, c0, c13, 4) +#define RCP14_DBGBVR14() MRC14(0, c0, c14, 4) +#define RCP14_DBGBVR15() MRC14(0, c0, c15, 4) +#define RCP14_DBGBCR0() MRC14(0, c0, c0, 5) +#define RCP14_DBGBCR1() MRC14(0, c0, c1, 5) +#define RCP14_DBGBCR2() MRC14(0, c0, c2, 5) +#define RCP14_DBGBCR3() MRC14(0, c0, c3, 5) +#define RCP14_DBGBCR4() MRC14(0, c0, c4, 5) +#define RCP14_DBGBCR5() MRC14(0, c0, c5, 5) +#define RCP14_DBGBCR6() MRC14(0, c0, c6, 5) +#define RCP14_DBGBCR7() MRC14(0, c0, c7, 5) +#define RCP14_DBGBCR8() MRC14(0, c0, c8, 5) +#define RCP14_DBGBCR9() MRC14(0, c0, c9, 5) +#define RCP14_DBGBCR10() MRC14(0, c0, c10, 5) +#define RCP14_DBGBCR11() MRC14(0, c0, c11, 5) +#define RCP14_DBGBCR12() MRC14(0, c0, c12, 5) +#define RCP14_DBGBCR13() MRC14(0, c0, c13, 5) +#define RCP14_DBGBCR14() MRC14(0, c0, c14, 5) +#define RCP14_DBGBCR15() MRC14(0, c0, c15, 5) +#define RCP14_DBGWVR0() MRC14(0, c0, c0, 6) +#define RCP14_DBGWVR1() MRC14(0, c0, c1, 6) +#define RCP14_DBGWVR2() MRC14(0, c0, c2, 6) +#define RCP14_DBGWVR3() MRC14(0, c0, c3, 6) +#define RCP14_DBGWVR4() MRC14(0, c0, c4, 6) +#define RCP14_DBGWVR5() MRC14(0, c0, c5, 6) +#define RCP14_DBGWVR6() MRC14(0, c0, c6, 6) +#define RCP14_DBGWVR7() MRC14(0, c0, c7, 6) +#define RCP14_DBGWVR8() MRC14(0, c0, c8, 6) +#define RCP14_DBGWVR9() MRC14(0, c0, c9, 6) +#define RCP14_DBGWVR10() MRC14(0, c0, c10, 6) +#define RCP14_DBGWVR11() MRC14(0, c0, c11, 6) +#define RCP14_DBGWVR12() MRC14(0, c0, c12, 6) +#define RCP14_DBGWVR13() MRC14(0, c0, c13, 6) +#define RCP14_DBGWVR14() MRC14(0, c0, c14, 6) +#define RCP14_DBGWVR15() MRC14(0, c0, c15, 6) +#define RCP14_DBGWCR0() MRC14(0, c0, c0, 7) +#define RCP14_DBGWCR1() MRC14(0, c0, c1, 7) +#define RCP14_DBGWCR2() MRC14(0, c0, c2, 7) +#define RCP14_DBGWCR3() MRC14(0, c0, c3, 7) +#define RCP14_DBGWCR4() MRC14(0, c0, c4, 7) +#define RCP14_DBGWCR5() MRC14(0, c0, c5, 7) +#define RCP14_DBGWCR6() MRC14(0, c0, c6, 7) +#define RCP14_DBGWCR7() MRC14(0, c0, c7, 7) +#define RCP14_DBGWCR8() MRC14(0, c0, c8, 7) +#define RCP14_DBGWCR9() MRC14(0, c0, c9, 7) +#define RCP14_DBGWCR10() MRC14(0, c0, c10, 7) +#define RCP14_DBGWCR11() MRC14(0, c0, c11, 7) +#define RCP14_DBGWCR12() MRC14(0, c0, c12, 7) +#define RCP14_DBGWCR13() MRC14(0, c0, c13, 7) +#define RCP14_DBGWCR14() MRC14(0, c0, c14, 7) +#define RCP14_DBGWCR15() MRC14(0, c0, c15, 7) +#define RCP14_DBGDRAR() MRC14(0, c1, c0, 0) +#define RCP14_DBGBXVR0() MRC14(0, c1, c0, 1) +#define RCP14_DBGBXVR1() MRC14(0, c1, c1, 1) +#define RCP14_DBGBXVR2() MRC14(0, c1, c2, 1) +#define RCP14_DBGBXVR3() MRC14(0, c1, c3, 1) +#define RCP14_DBGBXVR4() MRC14(0, c1, c4, 1) +#define RCP14_DBGBXVR5() MRC14(0, c1, c5, 1) +#define RCP14_DBGBXVR6() MRC14(0, c1, c6, 1) +#define RCP14_DBGBXVR7() MRC14(0, c1, c7, 1) +#define RCP14_DBGBXVR8() MRC14(0, c1, c8, 1) +#define RCP14_DBGBXVR9() MRC14(0, c1, c9, 1) +#define RCP14_DBGBXVR10() MRC14(0, c1, c10, 1) +#define RCP14_DBGBXVR11() MRC14(0, c1, c11, 1) +#define RCP14_DBGBXVR12() MRC14(0, c1, c12, 1) +#define RCP14_DBGBXVR13() MRC14(0, c1, c13, 1) +#define RCP14_DBGBXVR14() MRC14(0, c1, c14, 1) +#define RCP14_DBGBXVR15() MRC14(0, c1, c15, 1) +#define RCP14_DBGOSLSR() MRC14(0, c1, c1, 4) +#define RCP14_DBGOSSRR() MRC14(0, c1, c2, 4) +#define RCP14_DBGOSDLR() MRC14(0, c1, c3, 4) +#define RCP14_DBGPRCR() MRC14(0, c1, c4, 4) +#define RCP14_DBGPRSR() MRC14(0, c1, c5, 4) +#define RCP14_DBGDSAR() MRC14(0, c2, c0, 0) +#define RCP14_DBGITCTRL() MRC14(0, c7, c0, 4) +#define RCP14_DBGCLAIMSET() MRC14(0, c7, c8, 6) +#define RCP14_DBGCLAIMCLR() MRC14(0, c7, c9, 6) +#define RCP14_DBGAUTHSTATUS() MRC14(0, c7, c14, 6) +#define RCP14_DBGDEVID2() MRC14(0, c7, c0, 7) +#define RCP14_DBGDEVID1() MRC14(0, c7, c1, 7) +#define RCP14_DBGDEVID() MRC14(0, c7, c2, 7) + +#define WCP14_DBGDCCINT(val) MCR14(val, 0, c0, c2, 0) +#define WCP14_DBGDTRTXint(val) MCR14(val, 0, c0, c5, 0) +#define WCP14_DBGWFAR(val) MCR14(val, 0, c0, c6, 0) +#define WCP14_DBGVCR(val) MCR14(val, 0, c0, c7, 0) +#define WCP14_DBGDTRRXext(val) MCR14(val, 0, c0, c0, 2) +#define WCP14_DBGDSCRext(val) MCR14(val, 0, c0, c2, 2) +#define WCP14_DBGDTRTXext(val) MCR14(val, 0, c0, c3, 2) +#define WCP14_DBGOSECCR(val) MCR14(val, 0, c0, c6, 2) +#define WCP14_DBGBVR0(val) MCR14(val, 0, c0, c0, 4) +#define WCP14_DBGBVR1(val) MCR14(val, 0, c0, c1, 4) +#define WCP14_DBGBVR2(val) MCR14(val, 0, c0, c2, 4) +#define WCP14_DBGBVR3(val) MCR14(val, 0, c0, c3, 4) +#define WCP14_DBGBVR4(val) MCR14(val, 0, c0, c4, 4) +#define WCP14_DBGBVR5(val) MCR14(val, 0, c0, c5, 4) +#define WCP14_DBGBVR6(val) MCR14(val, 0, c0, c6, 4) +#define WCP14_DBGBVR7(val) MCR14(val, 0, c0, c7, 4) +#define WCP14_DBGBVR8(val) MCR14(val, 0, c0, c8, 4) +#define WCP14_DBGBVR9(val) MCR14(val, 0, c0, c9, 4) +#define WCP14_DBGBVR10(val) MCR14(val, 0, c0, c10, 4) +#define WCP14_DBGBVR11(val) MCR14(val, 0, c0, c11, 4) +#define WCP14_DBGBVR12(val) MCR14(val, 0, c0, c12, 4) +#define WCP14_DBGBVR13(val) MCR14(val, 0, c0, c13, 4) +#define WCP14_DBGBVR14(val) MCR14(val, 0, c0, c14, 4) +#define WCP14_DBGBVR15(val) MCR14(val, 0, c0, c15, 4) +#define WCP14_DBGBCR0(val) MCR14(val, 0, c0, c0, 5) +#define WCP14_DBGBCR1(val) MCR14(val, 0, c0, c1, 5) +#define WCP14_DBGBCR2(val) MCR14(val, 0, c0, c2, 5) +#define WCP14_DBGBCR3(val) MCR14(val, 0, c0, c3, 5) +#define WCP14_DBGBCR4(val) MCR14(val, 0, c0, c4, 5) +#define WCP14_DBGBCR5(val) MCR14(val, 0, c0, c5, 5) +#define WCP14_DBGBCR6(val) MCR14(val, 0, c0, c6, 5) +#define WCP14_DBGBCR7(val) MCR14(val, 0, c0, c7, 5) +#define WCP14_DBGBCR8(val) MCR14(val, 0, c0, c8, 5) +#define WCP14_DBGBCR9(val) MCR14(val, 0, c0, c9, 5) +#define WCP14_DBGBCR10(val) MCR14(val, 0, c0, c10, 5) +#define WCP14_DBGBCR11(val) MCR14(val, 0, c0, c11, 5) +#define WCP14_DBGBCR12(val) MCR14(val, 0, c0, c12, 5) +#define WCP14_DBGBCR13(val) MCR14(val, 0, c0, c13, 5) +#define WCP14_DBGBCR14(val) MCR14(val, 0, c0, c14, 5) +#define WCP14_DBGBCR15(val) MCR14(val, 0, c0, c15, 5) +#define WCP14_DBGWVR0(val) MCR14(val, 0, c0, c0, 6) +#define WCP14_DBGWVR1(val) MCR14(val, 0, c0, c1, 6) +#define WCP14_DBGWVR2(val) MCR14(val, 0, c0, c2, 6) +#define WCP14_DBGWVR3(val) MCR14(val, 0, c0, c3, 6) +#define WCP14_DBGWVR4(val) MCR14(val, 0, c0, c4, 6) +#define WCP14_DBGWVR5(val) MCR14(val, 0, c0, c5, 6) +#define WCP14_DBGWVR6(val) MCR14(val, 0, c0, c6, 6) +#define WCP14_DBGWVR7(val) MCR14(val, 0, c0, c7, 6) +#define WCP14_DBGWVR8(val) MCR14(val, 0, c0, c8, 6) +#define WCP14_DBGWVR9(val) MCR14(val, 0, c0, c9, 6) +#define WCP14_DBGWVR10(val) MCR14(val, 0, c0, c10, 6) +#define WCP14_DBGWVR11(val) MCR14(val, 0, c0, c11, 6) +#define WCP14_DBGWVR12(val) MCR14(val, 0, c0, c12, 6) +#define WCP14_DBGWVR13(val) MCR14(val, 0, c0, c13, 6) +#define WCP14_DBGWVR14(val) MCR14(val, 0, c0, c14, 6) +#define WCP14_DBGWVR15(val) MCR14(val, 0, c0, c15, 6) +#define WCP14_DBGWCR0(val) MCR14(val, 0, c0, c0, 7) +#define WCP14_DBGWCR1(val) MCR14(val, 0, c0, c1, 7) +#define WCP14_DBGWCR2(val) MCR14(val, 0, c0, c2, 7) +#define WCP14_DBGWCR3(val) MCR14(val, 0, c0, c3, 7) +#define WCP14_DBGWCR4(val) MCR14(val, 0, c0, c4, 7) +#define WCP14_DBGWCR5(val) MCR14(val, 0, c0, c5, 7) +#define WCP14_DBGWCR6(val) MCR14(val, 0, c0, c6, 7) +#define WCP14_DBGWCR7(val) MCR14(val, 0, c0, c7, 7) +#define WCP14_DBGWCR8(val) MCR14(val, 0, c0, c8, 7) +#define WCP14_DBGWCR9(val) MCR14(val, 0, c0, c9, 7) +#define WCP14_DBGWCR10(val) MCR14(val, 0, c0, c10, 7) +#define WCP14_DBGWCR11(val) MCR14(val, 0, c0, c11, 7) +#define WCP14_DBGWCR12(val) MCR14(val, 0, c0, c12, 7) +#define WCP14_DBGWCR13(val) MCR14(val, 0, c0, c13, 7) +#define WCP14_DBGWCR14(val) MCR14(val, 0, c0, c14, 7) +#define WCP14_DBGWCR15(val) MCR14(val, 0, c0, c15, 7) +#define WCP14_DBGBXVR0(val) MCR14(val, 0, c1, c0, 1) +#define WCP14_DBGBXVR1(val) MCR14(val, 0, c1, c1, 1) +#define WCP14_DBGBXVR2(val) MCR14(val, 0, c1, c2, 1) +#define WCP14_DBGBXVR3(val) MCR14(val, 0, c1, c3, 1) +#define WCP14_DBGBXVR4(val) MCR14(val, 0, c1, c4, 1) +#define WCP14_DBGBXVR5(val) MCR14(val, 0, c1, c5, 1) +#define WCP14_DBGBXVR6(val) MCR14(val, 0, c1, c6, 1) +#define WCP14_DBGBXVR7(val) MCR14(val, 0, c1, c7, 1) +#define WCP14_DBGBXVR8(val) MCR14(val, 0, c1, c8, 1) +#define WCP14_DBGBXVR9(val) MCR14(val, 0, c1, c9, 1) +#define WCP14_DBGBXVR10(val) MCR14(val, 0, c1, c10, 1) +#define WCP14_DBGBXVR11(val) MCR14(val, 0, c1, c11, 1) +#define WCP14_DBGBXVR12(val) MCR14(val, 0, c1, c12, 1) +#define WCP14_DBGBXVR13(val) MCR14(val, 0, c1, c13, 1) +#define WCP14_DBGBXVR14(val) MCR14(val, 0, c1, c14, 1) +#define WCP14_DBGBXVR15(val) MCR14(val, 0, c1, c15, 1) +#define WCP14_DBGOSLAR(val) MCR14(val, 0, c1, c0, 4) +#define WCP14_DBGOSSRR(val) MCR14(val, 0, c1, c2, 4) +#define WCP14_DBGOSDLR(val) MCR14(val, 0, c1, c3, 4) +#define WCP14_DBGPRCR(val) MCR14(val, 0, c1, c4, 4) +#define WCP14_DBGITCTRL(val) MCR14(val, 0, c7, c0, 4) +#define WCP14_DBGCLAIMSET(val) MCR14(val, 0, c7, c8, 6) +#define WCP14_DBGCLAIMCLR(val) MCR14(val, 0, c7, c9, 6) + +#endif -- GitLab From d6c5e3d8a21d19d79299801c296dea2253ed1a54 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Wed, 9 May 2018 19:00:02 +0530 Subject: [PATCH 636/855] clk: qcom: Add support for 8Mhz for mclk0 clock on SDM845 mclk0 clock is required to support 8MHz, so add support for the same. Change-Id: I58a98dffde4d50652ecb75f623959cadb32b6c27 Signed-off-by: Odelu Kukatla --- drivers/clk/qcom/camcc-sdm845.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c index 836c25c788f4..7f9ba032b660 100644 --- a/drivers/clk/qcom/camcc-sdm845.c +++ b/drivers/clk/qcom/camcc-sdm845.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -833,6 +833,7 @@ static struct clk_rcg2 cam_cc_lrme_clk_src = { }; static const struct freq_tbl ftbl_cam_cc_mclk0_clk_src[] = { + F(8000000, P_CAM_CC_PLL2_OUT_EVEN, 10, 1, 6), F(19200000, P_BI_TCXO, 1, 0, 0), F(24000000, P_CAM_CC_PLL2_OUT_EVEN, 10, 1, 2), F(33333333, P_CAM_CC_PLL0_OUT_EVEN, 2, 1, 9), -- GitLab From a71f43a679df9c0b9c95eeb8794df4ccdefaa729 Mon Sep 17 00:00:00 2001 From: Wenjun Zhang Date: Thu, 31 May 2018 03:16:16 -0400 Subject: [PATCH 637/855] ARM: dts: msm: Add HD+ panel with upscaling on SDM429 Add HD+ panel with upscaling to resolve flicker lines exist on the screen. Change-Id: Ib36d5242398884b4d11aaa925fe3eab0069bd2cb Signed-off-by: Wenjun Zhang --- .../qcom/dsi-panel-hx8399c-hd-plus-video.dtsi | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi index 237684e21537..91bf7229bb9e 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi @@ -40,21 +40,21 @@ b9 ff 83 99 39 01 00 00 00 00 02 d2 88 - 39 01 00 00 00 00 10 - b1 02 04 74 94 01 32 33 - 11 11 e6 5d 56 73 02 02 + 39 01 00 00 00 00 0c + b1 02 04 72 92 01 + 32 aa 11 11 52 57 39 01 00 00 00 00 10 b2 00 80 80 cc 05 07 5a - 11 10 10 00 1e 70 03 D4 + 11 10 10 00 1e 70 03 d4 39 01 00 00 00 00 2d - b4 00 ff 59 59 0c ac 00 - 00 0c 00 07 0a 00 28 07 - 08 0c 21 03 00 00 00 ae - 87 59 59 0c ac 00 00 0c - 00 07 0a 00 28 07 08 0c - 01 00 00 ae 01 + b4 00 ff 59 59 01 ab 00 + 00 09 00 03 05 00 28 03 + 0b 0d 21 03 02 00 0c a3 + 80 59 59 02 ab 00 00 09 + 00 03 05 00 28 03 0b 0d + 02 00 0c a3 01 39 01 00 00 05 00 22 - d3 00 00 01 01 00 00 10 + d3 00 0c 03 03 00 00 10 10 00 00 03 00 03 00 08 78 08 78 00 00 00 00 00 24 02 05 05 03 00 00 00 @@ -80,8 +80,8 @@ 39 01 00 00 00 00 02 bd 01 39 01 00 00 00 00 11 - d8 82 ea aa aa 82 ea aa - aa 82 ea aa aa 82 ea aa + d8 00 00 00 00 00 00 00 + 00 82 ea aa aa 82 ea aa aa 39 01 00 00 00 00 02 bd 02 @@ -90,25 +90,23 @@ 3f 39 01 00 00 00 00 02 bd 00 - 39 01 00 00 00 00 02 - dd 03 39 01 00 00 05 00 37 - e0 08 2a 39 35 74 7c 87 - 7f 84 8a 8e 91 93 96 9b - 9c 9e a5 a6 ae a1 af b2 - 5c 58 63 74 08 2a 39 35 - 74 7c 87 7f 84 8a 8e 91 - 93 96 9b 9c 9e a5 a6 ae - a1 af b2 5c 58 63 74 + e0 01 21 31 2d 66 6f 7b + 75 7a 81 86 89 8c 90 95 + 97 9a a1 a2 aa 9e ad b0 + 5b 57 63 7a 01 21 31 2d + 66 6f 7b 75 7a 81 86 89 + 8c 90 95 97 9a a1 a2 aa + 9e ad b0 5b 57 63 7a 39 01 00 00 00 00 03 b6 7e 7e 39 01 00 00 00 00 02 cc 08 - 39 01 00 00 00 00 06 - c7 00 08 00 01 08 - 39 01 00 00 00 00 03 - c0 25 5a - 05 01 00 00 78 00 02 11 00 + 39 01 00 00 00 00 02 + 35 00 + 39 01 00 00 00 00 02 + dd 03 + 05 01 00 00 96 00 02 11 00 05 01 00 00 14 00 02 29 00]; qcom,mdss-dsi-off-command = [ 05 01 00 00 14 00 02 28 00 -- GitLab From f25edfbb3d2114b5dbd7427e5a10e31e81abc789 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Thu, 31 May 2018 13:02:22 +0530 Subject: [PATCH 638/855] msm: ipa4: gsi: Remove WA of resetting gsi channel Remove second reset of gsi channel on IPA PROD end point, since the hardware level issue is fixed from gsi-2.0. Change-Id: Icc77577194f4124a6fd90b173af16f3bb51d73b6 Signed-off-by: Mohammed Javid --- drivers/platform/msm/gsi/gsi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index e80a1fbea1e6..1af34476651c 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -2236,6 +2236,10 @@ int gsi_reset_channel(unsigned long chan_hdl) BUG(); } + /* Hardware issue fixed from GSI 2.0 and no need for the WA */ + if (gsi_ctx->per.ver >= GSI_VER_2_0) + reset_done = true; + /* workaround: reset GSI producers again */ if (ctx->props.dir == GSI_CHAN_DIR_FROM_GSI && !reset_done) { usleep_range(GSI_RESET_WA_MIN_SLEEP, GSI_RESET_WA_MAX_SLEEP); -- GitLab From e1f3b149a61fe3b08f75b1640534b0df38375906 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Tue, 29 May 2018 09:51:06 +0530 Subject: [PATCH 639/855] trace: events: pdc: Correct trace print Correct order of prints for pdc pin and hwirq. Change-Id: I75c78e056d298614043e6e85ffb10d9fe2b1cfa4 Signed-off-by: Maulik Shah --- include/trace/events/pdc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/trace/events/pdc.h b/include/trace/events/pdc.h index 400e95989006..fca05480a31b 100644 --- a/include/trace/events/pdc.h +++ b/include/trace/events/pdc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -41,7 +41,7 @@ TRACE_EVENT(irq_pin_config, ), TP_printk("%s hwirq:%u pin:%u type:%u enable:%u", - __entry->func, __entry->pin, __entry->hwirq, __entry->type, + __entry->func, __entry->hwirq, __entry->pin, __entry->type, __entry->enable) ); -- GitLab From b6fc5800f92bfa80085da6c514836f7140d8abf1 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Thu, 31 May 2018 14:40:08 +0530 Subject: [PATCH 640/855] ARM: dts: msm: enable S/W JEITA and step charging for PMI632 charger Enable software based JEITA and step charging, this allows software to fine tune FCC and Float voltage of charger at different VBAT and temperature threshold. Change-Id: Ie112ed6b693ba24c4e821fbaaaadfa63d2b6cd5d Signed-off-by: Ashay Jaiswal --- arch/arm64/boot/dts/qcom/pmi632.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi index 65390cb1d56e..d77d55dc7de3 100644 --- a/arch/arm64/boot/dts/qcom/pmi632.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi @@ -316,6 +316,8 @@ qcom,auto-recharge-soc = <98>; qcom,chg-vadc = <&pmi632_vadc>; qcom,flash-disable-soc = <10>; + qcom,sw-jeita-enable; + qcom,step-charging-enable; qcom,thermal-mitigation = <3000000 2500000 2000000 1500000 -- GitLab From c794804cba0ef1027ea510a086d3a5f3edc13419 Mon Sep 17 00:00:00 2001 From: Samyukta Mogily Date: Tue, 29 May 2018 15:19:37 +0530 Subject: [PATCH 641/855] msm: camera: Changes to handle change in sensor data rate Changes to handle change in data rate, during change in sensor mode, to reconfigure snps to the new data rate. This fixes QVGA issue of camera failure on the first time switch to QVGA. Change-Id: I5a52c27aa00fa7497bca85b196dd71a296e8c6ac Signed-off-by: Samyukta Mogily --- .../msm/camera_v2/sensor/csiphy/msm_csiphy.c | 33 +++++++++++++------ .../msm/camera_v2/sensor/csiphy/msm_csiphy.h | 1 + 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c index 6fc8e1e87af2..fa3aceefd32b 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c @@ -218,6 +218,8 @@ static int msm_csiphy_snps_2_lane_config( } } + csiphy_dev->snps_programmed_data_rate = csiphy_params->data_rate; + if (mode == TWO_LANE_PHY_A) { msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_snps_reg. mipi_csiphy_sys_ctrl.data, @@ -322,8 +324,11 @@ static int msm_csiphy_snps_lane_config( mode = AGGREGATE_MODE; num_lanes = 4; if (csiphy_dev->snps_state != NOT_CONFIGURED) { - pr_err("%s: invalid request\n", __func__); - return -EINVAL; + if (csiphy_dev->snps_programmed_data_rate != + csiphy_params->data_rate) + pr_err("reconfiguring snps phy"); + else + return 0; } csiphy_dev->snps_state = CONFIGURED_AGGREGATE_MODE; clk_mux_reg &= ~0xff; @@ -332,34 +337,38 @@ static int msm_csiphy_snps_lane_config( } else if (lane_mask == LANE_MASK_PHY_A) { /* PHY A */ /* 2 lane config */ num_lanes = 2; + mode = TWO_LANE_PHY_A; if (csiphy_dev->snps_state == NOT_CONFIGURED) { - mode = TWO_LANE_PHY_A; csiphy_dev->snps_state = CONFIGURED_TWO_LANE_PHY_A; } else if (csiphy_dev->snps_state == CONFIGURED_TWO_LANE_PHY_B) { /* 2 lane + 2 lane config */ - mode = TWO_LANE_PHY_A; csiphy_dev->snps_state = CONFIGURED_COMBO_MODE; } else { - pr_err("%s: invalid request\n", __func__); - return -EINVAL; + if (csiphy_dev->snps_programmed_data_rate != + csiphy_params->data_rate) + pr_err("reconfiguring snps phy"); + else + return 0; } clk_mux_reg &= ~0xf; clk_mux_reg |= (uint32_t)csiphy_params->csid_core; } else if (lane_mask == LANE_MASK_PHY_B) { /* PHY B */ /* 2 lane config */ num_lanes = 2; + mode = TWO_LANE_PHY_B; if (csiphy_dev->snps_state == NOT_CONFIGURED) { - mode = TWO_LANE_PHY_B; csiphy_dev->snps_state = CONFIGURED_TWO_LANE_PHY_B; } else if (csiphy_dev->snps_state == CONFIGURED_TWO_LANE_PHY_A) { /* 2 lane + 2 lane config */ - mode = TWO_LANE_PHY_B; csiphy_dev->snps_state = CONFIGURED_COMBO_MODE; } else { - pr_err("%s: invalid request\n", __func__); - return -EINVAL; + if (csiphy_dev->snps_programmed_data_rate != + csiphy_params->data_rate) + pr_err("reconfiguring snps phy"); + else + return 0; } clk_mux_reg &= ~0xf0; clk_mux_reg |= csiphy_params->csid_core << 4; @@ -1660,6 +1669,7 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) csiphy_dev->hw_version); csiphy_dev->csiphy_state = CSIPHY_POWER_UP; csiphy_dev->snps_state = NOT_CONFIGURED; + csiphy_dev->snps_programmed_data_rate = 0; return 0; csiphy_enable_clk_fail: @@ -1766,6 +1776,7 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) csiphy_dev->hw_version); csiphy_dev->csiphy_state = CSIPHY_POWER_UP; csiphy_dev->snps_state = NOT_CONFIGURED; + csiphy_dev->snps_programmed_data_rate = 0; return 0; csiphy_enable_clk_fail: @@ -1915,6 +1926,7 @@ static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; csiphy_dev->snps_state = NOT_CONFIGURED; + csiphy_dev->snps_programmed_data_rate = 0; if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, CAM_AHB_SUSPEND_VOTE) < 0) @@ -2047,6 +2059,7 @@ static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; csiphy_dev->snps_state = NOT_CONFIGURED; + csiphy_dev->snps_programmed_data_rate = 0; if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, CAM_AHB_SUSPEND_VOTE) < 0) diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h index 79baf3c83214..41d20347a07d 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h @@ -250,6 +250,7 @@ struct csiphy_device { uint8_t is_snps_phy; enum snps_csiphy_state snps_state; uint8_t num_clk_irq_registers; + uint64_t snps_programmed_data_rate; }; #define VIDIOC_MSM_CSIPHY_RELEASE \ -- GitLab From b6efcb0394ffb0d51bae283fc9af5e2fe511d33f Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 14 Nov 2016 18:06:19 +0100 Subject: [PATCH 642/855] refcount_t: Introduce a special purpose refcount type Provide refcount_t, an atomic_t like primitive built just for refcounting. It provides saturation semantics such that overflow becomes impossible and thereby 'spurious' use-after-free is avoided. Change-Id: Id360e29bb9c19af8672726539d0d16c0f6d2be3f Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Signed-off-by: Ingo Molnar Git-commit: f405df5de3170c00e5c54f8b7cf4766044a032ba Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Srinivasa Rao Kuppala --- include/linux/refcount.h | 294 +++++++++++++++++++++++++++++++++++++++ lib/Kconfig.debug | 13 ++ 2 files changed, 307 insertions(+) create mode 100644 include/linux/refcount.h diff --git a/include/linux/refcount.h b/include/linux/refcount.h new file mode 100644 index 000000000000..600aadf9cca4 --- /dev/null +++ b/include/linux/refcount.h @@ -0,0 +1,294 @@ +#ifndef _LINUX_REFCOUNT_H +#define _LINUX_REFCOUNT_H + +/* + * Variant of atomic_t specialized for reference counts. + * + * The interface matches the atomic_t interface (to aid in porting) but only + * provides the few functions one should use for reference counting. + * + * It differs in that the counter saturates at UINT_MAX and will not move once + * there. This avoids wrapping the counter and causing 'spurious' + * use-after-free issues. + * + * Memory ordering rules are slightly relaxed wrt regular atomic_t functions + * and provide only what is strictly required for refcounts. + * + * The increments are fully relaxed; these will not provide ordering. The + * rationale is that whatever is used to obtain the object we're increasing the + * reference count on will provide the ordering. For locked data structures, + * its the lock acquire, for RCU/lockless data structures its the dependent + * load. + * + * Do note that inc_not_zero() provides a control dependency which will order + * future stores against the inc, this ensures we'll never modify the object + * if we did not in fact acquire a reference. + * + * The decrements will provide release order, such that all the prior loads and + * stores will be issued before, it also provides a control dependency, which + * will order us against the subsequent free(). + * + * The control dependency is against the load of the cmpxchg (ll/sc) that + * succeeded. This means the stores aren't fully ordered, but this is fine + * because the 1->0 transition indicates no concurrency. + * + * Note that the allocator is responsible for ordering things between free() + * and alloc(). + * + */ + +#include +#include +#include +#include + +#ifdef CONFIG_DEBUG_REFCOUNT +#define REFCOUNT_WARN(cond, str) WARN_ON(cond) +#define __refcount_check __must_check +#else +#define REFCOUNT_WARN(cond, str) (void)(cond) +#define __refcount_check +#endif + +typedef struct refcount_struct { + atomic_t refs; +} refcount_t; + +#define REFCOUNT_INIT(n) { .refs = ATOMIC_INIT(n), } + +static inline void refcount_set(refcount_t *r, unsigned int n) +{ + atomic_set(&r->refs, n); +} + +static inline unsigned int refcount_read(const refcount_t *r) +{ + return atomic_read(&r->refs); +} + +static inline __refcount_check +bool refcount_add_not_zero(unsigned int i, refcount_t *r) +{ + unsigned int old, new, val = atomic_read(&r->refs); + + for (;;) { + if (!val) + return false; + + if (unlikely(val == UINT_MAX)) + return true; + + new = val + i; + if (new < val) + new = UINT_MAX; + old = atomic_cmpxchg_relaxed(&r->refs, val, new); + if (old == val) + break; + + val = old; + } + + REFCOUNT_WARN(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); + + return true; +} + +static inline void refcount_add(unsigned int i, refcount_t *r) +{ + REFCOUNT_WARN(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n"); +} + +/* + * Similar to atomic_inc_not_zero(), will saturate at UINT_MAX and WARN. + * + * Provides no memory ordering, it is assumed the caller has guaranteed the + * object memory to be stable (RCU, etc.). It does provide a control dependency + * and thereby orders future stores. See the comment on top. + */ +static inline __refcount_check +bool refcount_inc_not_zero(refcount_t *r) +{ + unsigned int old, new, val = atomic_read(&r->refs); + + for (;;) { + new = val + 1; + + if (!val) + return false; + + if (unlikely(!new)) + return true; + + old = atomic_cmpxchg_relaxed(&r->refs, val, new); + if (old == val) + break; + + val = old; + } + + REFCOUNT_WARN(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); + + return true; +} + +/* + * Similar to atomic_inc(), will saturate at UINT_MAX and WARN. + * + * Provides no memory ordering, it is assumed the caller already has a + * reference on the object, will WARN when this is not so. + */ +static inline void refcount_inc(refcount_t *r) +{ + REFCOUNT_WARN(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n"); +} + +/* + * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to + * decrement when saturated at UINT_MAX. + * + * Provides release memory ordering, such that prior loads and stores are done + * before, and provides a control dependency such that free() must come after. + * See the comment on top. + */ +static inline __refcount_check +bool refcount_sub_and_test(unsigned int i, refcount_t *r) +{ + unsigned int old, new, val = atomic_read(&r->refs); + + for (;;) { + if (unlikely(val == UINT_MAX)) + return false; + + new = val - i; + if (new > val) { + REFCOUNT_WARN(new > val, "refcount_t: underflow; use-after-free.\n"); + return false; + } + + old = atomic_cmpxchg_release(&r->refs, val, new); + if (old == val) + break; + + val = old; + } + + return !new; +} + +static inline __refcount_check +bool refcount_dec_and_test(refcount_t *r) +{ + return refcount_sub_and_test(1, r); +} + +/* + * Similar to atomic_dec(), it will WARN on underflow and fail to decrement + * when saturated at UINT_MAX. + * + * Provides release memory ordering, such that prior loads and stores are done + * before. + */ +static inline +void refcount_dec(refcount_t *r) +{ + REFCOUNT_WARN(refcount_dec_and_test(r), "refcount_t: decrement hit 0; leaking memory.\n"); +} + +/* + * No atomic_t counterpart, it attempts a 1 -> 0 transition and returns the + * success thereof. + * + * Like all decrement operations, it provides release memory order and provides + * a control dependency. + * + * It can be used like a try-delete operator; this explicit case is provided + * and not cmpxchg in generic, because that would allow implementing unsafe + * operations. + */ +static inline __refcount_check +bool refcount_dec_if_one(refcount_t *r) +{ + return atomic_cmpxchg_release(&r->refs, 1, 0) == 1; +} + +/* + * No atomic_t counterpart, it decrements unless the value is 1, in which case + * it will return false. + * + * Was often done like: atomic_add_unless(&var, -1, 1) + */ +static inline __refcount_check +bool refcount_dec_not_one(refcount_t *r) +{ + unsigned int old, new, val = atomic_read(&r->refs); + + for (;;) { + if (unlikely(val == UINT_MAX)) + return true; + + if (val == 1) + return false; + + new = val - 1; + if (new > val) { + REFCOUNT_WARN(new > val, "refcount_t: underflow; use-after-free.\n"); + return true; + } + + old = atomic_cmpxchg_release(&r->refs, val, new); + if (old == val) + break; + + val = old; + } + + return true; +} + +/* + * Similar to atomic_dec_and_mutex_lock(), it will WARN on underflow and fail + * to decrement when saturated at UINT_MAX. + * + * Provides release memory ordering, such that prior loads and stores are done + * before, and provides a control dependency such that free() must come after. + * See the comment on top. + */ +static inline __refcount_check +bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock) +{ + if (refcount_dec_not_one(r)) + return false; + + mutex_lock(lock); + if (!refcount_dec_and_test(r)) { + mutex_unlock(lock); + return false; + } + + return true; +} + +/* + * Similar to atomic_dec_and_lock(), it will WARN on underflow and fail to + * decrement when saturated at UINT_MAX. + * + * Provides release memory ordering, such that prior loads and stores are done + * before, and provides a control dependency such that free() must come after. + * See the comment on top. + */ +static inline __refcount_check +bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock) +{ + if (refcount_dec_not_one(r)) + return false; + + spin_lock(lock); + if (!refcount_dec_and_test(r)) { + spin_unlock(lock); + return false; + } + + return true; +} + +#endif /* _LINUX_REFCOUNT_H */ diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 079d91ad4e2f..37641d1c1f86 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -707,6 +707,19 @@ source "lib/Kconfig.kmemcheck" source "lib/Kconfig.kasan" +config DEBUG_REFCOUNT + bool "Verbose refcount checks" + help + Say Y here if you want reference counters (refcount_t and kref) to + generate WARNs on dubious usage. Without this refcount_t will still + be a saturating counter and avoid Use-After-Free by turning it into + a resource leak Denial-Of-Service. + + Use of this option will increase kernel text size but will alert the + admin of potential abuse. + + If in doubt, say "N". + endmenu # "Memory Debugging" config ARCH_HAS_KCOV -- GitLab From 55be90d9cee016e84d7a6c370450fc687cd33384 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Thu, 31 May 2018 11:41:03 +0530 Subject: [PATCH 643/855] msm: ADSPRPC: handle 32 bit support Handle 32 bit support without any truncation. Add IOCTL calls for map and unmap for 64 bit separately. Change-Id: I077a0b4345a6c21a88d7a500aa5c9faf7193f620 Signed-off-by: Tharun Kumar Merugu --- drivers/char/adsprpc.c | 22 +++++++ drivers/char/adsprpc_compat.c | 108 +++++++++++++++++++++++++++++++++- drivers/char/adsprpc_shared.h | 15 +++++ 3 files changed, 144 insertions(+), 1 deletion(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 683c19bcc090..7d8605bfeb84 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -3259,6 +3259,28 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, if (err) goto bail; break; + case FASTRPC_IOCTL_MMAP_64: + K_COPY_FROM_USER(err, 0, &p.mmap, param, + sizeof(p.mmap)); + if (err) + goto bail; + VERIFY(err, 0 == (err = fastrpc_internal_mmap(fl, &p.mmap))); + if (err) + goto bail; + K_COPY_TO_USER(err, 0, param, &p.mmap, sizeof(p.mmap)); + if (err) + goto bail; + break; + case FASTRPC_IOCTL_MUNMAP_64: + K_COPY_FROM_USER(err, 0, &p.munmap, param, + sizeof(p.munmap)); + if (err) + goto bail; + VERIFY(err, 0 == (err = fastrpc_internal_munmap(fl, + &p.munmap))); + if (err) + goto bail; + break; case FASTRPC_IOCTL_MUNMAP_FD: K_COPY_FROM_USER(err, 0, &p.munmap_fd, param, sizeof(p.munmap_fd)); diff --git a/drivers/char/adsprpc_compat.c b/drivers/char/adsprpc_compat.c index 0f07483eaf1d..804cedade655 100644 --- a/drivers/char/adsprpc_compat.c +++ b/drivers/char/adsprpc_compat.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -39,6 +39,10 @@ _IOWR('R', 11, struct compat_fastrpc_ioctl_invoke_crc) #define COMPAT_FASTRPC_IOCTL_CONTROL \ _IOWR('R', 12, struct compat_fastrpc_ioctl_control) +#define COMPAT_FASTRPC_IOCTL_MMAP_64 \ + _IOWR('R', 14, struct compat_fastrpc_ioctl_mmap_64) +#define COMPAT_FASTRPC_IOCTL_MUNMAP_64 \ + _IOWR('R', 15, struct compat_fastrpc_ioctl_munmap_64) struct compat_remote_buf { compat_uptr_t pv; /* buffer pointer */ @@ -82,11 +86,24 @@ struct compat_fastrpc_ioctl_mmap { compat_uptr_t vaddrout; /* dsps virtual address */ }; +struct compat_fastrpc_ioctl_mmap_64 { + compat_int_t fd; /* ion fd */ + compat_uint_t flags; /* flags for dsp to map with */ + compat_u64 vaddrin; /* optional virtual address */ + compat_size_t size; /* size */ + compat_u64 vaddrout; /* dsps virtual address */ +}; + struct compat_fastrpc_ioctl_munmap { compat_uptr_t vaddrout; /* address to unmap */ compat_size_t size; /* size */ }; +struct compat_fastrpc_ioctl_munmap_64 { + compat_u64 vaddrout; /* address to unmap */ + compat_size_t size; /* size */ +}; + struct compat_fastrpc_ioctl_init { compat_uint_t flags; /* one of FASTRPC_INIT_* macros */ compat_uptr_t file; /* pointer to elf file */ @@ -206,6 +223,28 @@ static int compat_get_fastrpc_ioctl_mmap( return err; } +static int compat_get_fastrpc_ioctl_mmap_64( + struct compat_fastrpc_ioctl_mmap_64 __user *map32, + struct fastrpc_ioctl_mmap __user *map) +{ + compat_uint_t u; + compat_int_t i; + compat_size_t s; + compat_u64 p; + int err; + + err = get_user(i, &map32->fd); + err |= put_user(i, &map->fd); + err |= get_user(u, &map32->flags); + err |= put_user(u, &map->flags); + err |= get_user(p, &map32->vaddrin); + err |= put_user(p, &map->vaddrin); + err |= get_user(s, &map32->size); + err |= put_user(s, &map->size); + + return err; +} + static int compat_put_fastrpc_ioctl_mmap( struct compat_fastrpc_ioctl_mmap __user *map32, struct fastrpc_ioctl_mmap __user *map) @@ -219,6 +258,19 @@ static int compat_put_fastrpc_ioctl_mmap( return err; } +static int compat_put_fastrpc_ioctl_mmap_64( + struct compat_fastrpc_ioctl_mmap_64 __user *map32, + struct fastrpc_ioctl_mmap __user *map) +{ + compat_u64 p; + int err; + + err = get_user(p, &map->vaddrout); + err |= put_user(p, &map32->vaddrout); + + return err; +} + static int compat_get_fastrpc_ioctl_munmap( struct compat_fastrpc_ioctl_munmap __user *unmap32, struct fastrpc_ioctl_munmap __user *unmap) @@ -235,6 +287,22 @@ static int compat_get_fastrpc_ioctl_munmap( return err; } +static int compat_get_fastrpc_ioctl_munmap_64( + struct compat_fastrpc_ioctl_munmap_64 __user *unmap32, + struct fastrpc_ioctl_munmap __user *unmap) +{ + compat_u64 p; + compat_size_t s; + int err; + + err = get_user(p, &unmap32->vaddrout); + err |= put_user(p, &unmap->vaddrout); + err |= get_user(s, &unmap32->size); + err |= put_user(s, &unmap->size); + + return err; +} + static int compat_get_fastrpc_ioctl_perf( struct compat_fastrpc_ioctl_perf __user *perf32, struct fastrpc_ioctl_perf __user *perf) @@ -355,6 +423,27 @@ long compat_fastrpc_device_ioctl(struct file *filp, unsigned int cmd, VERIFY(err, 0 == compat_put_fastrpc_ioctl_mmap(map32, map)); return err; } + case COMPAT_FASTRPC_IOCTL_MMAP_64: + { + struct compat_fastrpc_ioctl_mmap_64 __user *map32; + struct fastrpc_ioctl_mmap __user *map; + long ret; + + map32 = compat_ptr(arg); + VERIFY(err, NULL != (map = compat_alloc_user_space( + sizeof(*map)))); + if (err) + return -EFAULT; + VERIFY(err, 0 == compat_get_fastrpc_ioctl_mmap_64(map32, map)); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_MMAP_64, + (unsigned long)map); + if (ret) + return ret; + VERIFY(err, 0 == compat_put_fastrpc_ioctl_mmap_64(map32, map)); + return err; + } case COMPAT_FASTRPC_IOCTL_MUNMAP: { struct compat_fastrpc_ioctl_munmap __user *unmap32; @@ -372,6 +461,23 @@ long compat_fastrpc_device_ioctl(struct file *filp, unsigned int cmd, return filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_MUNMAP, (unsigned long)unmap); } + case COMPAT_FASTRPC_IOCTL_MUNMAP_64: + { + struct compat_fastrpc_ioctl_munmap_64 __user *unmap32; + struct fastrpc_ioctl_munmap __user *unmap; + + unmap32 = compat_ptr(arg); + VERIFY(err, NULL != (unmap = compat_alloc_user_space( + sizeof(*unmap)))); + if (err) + return -EFAULT; + VERIFY(err, 0 == compat_get_fastrpc_ioctl_munmap_64(unmap32, + unmap)); + if (err) + return err; + return filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_MUNMAP_64, + (unsigned long)unmap); + } case COMPAT_FASTRPC_IOCTL_INIT: /* fall through */ case COMPAT_FASTRPC_IOCTL_INIT_ATTRS: diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h index de0dd01b96c8..952b87ca319b 100644 --- a/drivers/char/adsprpc_shared.h +++ b/drivers/char/adsprpc_shared.h @@ -19,6 +19,8 @@ #define FASTRPC_IOCTL_INVOKE _IOWR('R', 1, struct fastrpc_ioctl_invoke) #define FASTRPC_IOCTL_MMAP _IOWR('R', 2, struct fastrpc_ioctl_mmap) #define FASTRPC_IOCTL_MUNMAP _IOWR('R', 3, struct fastrpc_ioctl_munmap) +#define FASTRPC_IOCTL_MMAP_64 _IOWR('R', 14, struct fastrpc_ioctl_mmap_64) +#define FASTRPC_IOCTL_MUNMAP_64 _IOWR('R', 15, struct fastrpc_ioctl_munmap_64) #define FASTRPC_IOCTL_INVOKE_FD _IOWR('R', 4, struct fastrpc_ioctl_invoke_fd) #define FASTRPC_IOCTL_SETMODE _IOWR('R', 5, uint32_t) #define FASTRPC_IOCTL_INIT _IOWR('R', 6, struct fastrpc_ioctl_init) @@ -204,6 +206,11 @@ struct fastrpc_ioctl_munmap { size_t size; /* size */ }; +struct fastrpc_ioctl_munmap_64 { + uint64_t vaddrout; /* address to unmap */ + size_t size; /* size */ +}; + struct fastrpc_ioctl_mmap { int fd; /* ion fd */ uint32_t flags; /* flags for dsp to map with */ @@ -212,6 +219,14 @@ struct fastrpc_ioctl_mmap { uintptr_t vaddrout; /* dsps virtual address */ }; +struct fastrpc_ioctl_mmap_64 { + int fd; /* ion fd */ + uint32_t flags; /* flags for dsp to map with */ + uint64_t vaddrin; /* optional virtual address */ + size_t size; /* size */ + uint64_t vaddrout; /* dsps virtual address */ +}; + struct fastrpc_ioctl_munmap_fd { int fd; /* fd */ uint32_t flags; /* control flags */ -- GitLab From 993318c26dd2853220c2156eeb82876b5cbccd0b Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Fri, 27 Apr 2018 12:15:51 +0530 Subject: [PATCH 644/855] power: smb1390: Allow delayed probe of vadc node In some targets vadc list is populated after smb1390 probe is initiated. Allow delayed probe of vadc node in case of probe defer. Change-Id: Iaaef2b65cc82cfbcd05e42b6a9e9428dc1815723 Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/smb1390-charger.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/qcom/smb1390-charger.c b/drivers/power/supply/qcom/smb1390-charger.c index 55a1f457faee..d935d8fb52cf 100644 --- a/drivers/power/supply/qcom/smb1390-charger.c +++ b/drivers/power/supply/qcom/smb1390-charger.c @@ -722,14 +722,15 @@ static int smb1390_probe(struct platform_device *pdev) rc = smb1390_parse_dt(chip); if (rc < 0) { pr_err("Couldn't parse device tree rc=%d\n", rc); - goto out_work; + return rc; } chip->vadc_dev = qpnp_get_vadc(chip->dev, "smb"); if (IS_ERR(chip->vadc_dev)) { rc = PTR_ERR(chip->vadc_dev); - pr_err("Couldn't get vadc dev rc=%d\n", rc); - goto out_work; + if (rc != -EPROBE_DEFER) + pr_err("Couldn't get vadc dev rc=%d\n", rc); + return rc; } rc = smb1390_create_votables(chip); -- GitLab From b1e3702d26162214591d67c598fea9065de64473 Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Fri, 4 May 2018 16:01:07 +0530 Subject: [PATCH 645/855] power: smb1390: Remove HW INOV control for SMB1390 Allow SW control of INOV if SMB1390 is present. Change-Id: I11713d9e6ef5b81698dc858543d7155a131e9b2a Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/smb1390-charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/smb1390-charger.c b/drivers/power/supply/qcom/smb1390-charger.c index d935d8fb52cf..06b277379776 100644 --- a/drivers/power/supply/qcom/smb1390-charger.c +++ b/drivers/power/supply/qcom/smb1390-charger.c @@ -378,7 +378,6 @@ static int smb1390_disable_vote_cb(struct votable *votable, void *data, if (rc < 0) return rc; - vote(chip->hvdcp_hw_inov_dis_votable, CP_VOTER, false, 0); vote(chip->pl_disable_votable, CP_VOTER, false, 0); } else { vote(chip->hvdcp_hw_inov_dis_votable, CP_VOTER, true, 0); @@ -791,6 +790,7 @@ static int smb1390_remove(struct platform_device *pdev) /* explicitly disable charging */ vote(chip->disable_votable, USER_VOTER, true, 0); + vote(chip->hvdcp_hw_inov_dis_votable, CP_VOTER, false, 0); cancel_work(&chip->taper_work); cancel_work(&chip->status_change_work); smb1390_destroy_votables(chip); -- GitLab From fc4ee1f6ae3ff3da0c00d7b6d491f168f02afc57 Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Mon, 7 May 2018 19:55:43 +0530 Subject: [PATCH 646/855] power: smb1390: Add cp_awake votable to hold wake lock Add cp_awake votable to hold wake lock till charge pump is enabled to prevent i2c read/write failures. Change-Id: I69a973d16a90ff566374fe40cb7517c7b3b1e453 Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/smb1390-charger.c | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/power/supply/qcom/smb1390-charger.c b/drivers/power/supply/qcom/smb1390-charger.c index 06b277379776..91d215e301fd 100644 --- a/drivers/power/supply/qcom/smb1390-charger.c +++ b/drivers/power/supply/qcom/smb1390-charger.c @@ -100,6 +100,7 @@ struct smb1390 { struct regmap *regmap; struct notifier_block nb; struct class cp_class; + struct wakeup_source *cp_ws; /* work structs */ struct work_struct status_change_work; @@ -114,6 +115,7 @@ struct smb1390 { struct votable *pl_disable_votable; struct votable *fcc_votable; struct votable *hvdcp_hw_inov_dis_votable; + struct votable *cp_awake_votable; /* power supplies */ struct power_supply *usb_psy; @@ -379,9 +381,11 @@ static int smb1390_disable_vote_cb(struct votable *votable, void *data, return rc; vote(chip->pl_disable_votable, CP_VOTER, false, 0); + vote(chip->cp_awake_votable, CP_VOTER, false, 0); } else { vote(chip->hvdcp_hw_inov_dis_votable, CP_VOTER, true, 0); vote(chip->pl_disable_votable, CP_VOTER, true, 0); + vote(chip->cp_awake_votable, CP_VOTER, true, 0); rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, CMD_EN_SWITCHER_BIT, CMD_EN_SWITCHER_BIT); if (rc < 0) @@ -427,6 +431,20 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, return rc; } +static int smb1390_awake_vote_cb(struct votable *votable, void *data, + int awake, const char *client) +{ + struct smb1390 *chip = data; + + if (awake) + __pm_stay_awake(chip->cp_ws); + else + __pm_relax(chip->cp_ws); + + pr_debug("client: %s awake: %d\n", client, awake); + return 0; +} + static int smb1390_notifier_cb(struct notifier_block *nb, unsigned long event, void *data) { @@ -588,6 +606,11 @@ static int smb1390_create_votables(struct smb1390 *chip) if (IS_ERR(chip->ilim_votable)) return PTR_ERR(chip->ilim_votable); + chip->cp_awake_votable = create_votable("CP_AWAKE", VOTE_SET_ANY, + smb1390_awake_vote_cb, chip); + if (IS_ERR(chip->cp_awake_votable)) + return PTR_ERR(chip->cp_awake_votable); + return 0; } @@ -732,6 +755,10 @@ static int smb1390_probe(struct platform_device *pdev) return rc; } + chip->cp_ws = wakeup_source_register("qcom-chargepump"); + if (!chip->cp_ws) + return rc; + rc = smb1390_create_votables(chip); if (rc < 0) { pr_err("Couldn't create votables rc=%d\n", rc); @@ -778,6 +805,7 @@ static int smb1390_probe(struct platform_device *pdev) out_work: cancel_work(&chip->taper_work); cancel_work(&chip->status_change_work); + wakeup_source_unregister(chip->cp_ws); return rc; } @@ -793,6 +821,7 @@ static int smb1390_remove(struct platform_device *pdev) vote(chip->hvdcp_hw_inov_dis_votable, CP_VOTER, false, 0); cancel_work(&chip->taper_work); cancel_work(&chip->status_change_work); + wakeup_source_unregister(chip->cp_ws); smb1390_destroy_votables(chip); return 0; } -- GitLab From 36f48098230c4f64ad8f73223e22ae6da013a104 Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Fri, 27 Apr 2018 11:51:09 +0530 Subject: [PATCH 647/855] power: smb1390: Add cp_irq and toggle_switcher property Currently to prevent SMB1390 from getting stuck in disabled state on IREV IRQ, switcher is toggled. As an optimization to this workaround, voltage needs to be increment first before switcher toggling to break the latching of IREV IRQ status on WIN_UV. Add cp_irq and toggle_switcher property to allow userspace daemon to increment the voltage and initaite the switcher toggle. Change-Id: I11fbc5877a2df9ce4d0208c698b8758adae1d035 Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/smb1390-charger.c | 79 +++++++++++++-------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/drivers/power/supply/qcom/smb1390-charger.c b/drivers/power/supply/qcom/smb1390-charger.c index 91d215e301fd..a92c975273e9 100644 --- a/drivers/power/supply/qcom/smb1390-charger.c +++ b/drivers/power/supply/qcom/smb1390-charger.c @@ -82,6 +82,7 @@ #define FCC_VOTER "FCC_VOTER" #define ICL_VOTER "ICL_VOTER" #define USB_VOTER "USB_VOTER" +#define SWITCHER_TOGGLE_VOTER "SWITCHER_TOGGLE_VOTER" enum { SWITCHER_OFF_WINDOW_IRQ = 0, @@ -126,6 +127,7 @@ struct smb1390 { bool status_change_running; bool taper_work_running; int adc_channel; + int irq_status; }; struct smb_irq { @@ -206,44 +208,29 @@ static bool is_psy_voter_available(struct smb1390 *chip) return true; } -static irqreturn_t default_irq_handler(int irq, void *data) +static void cp_toggle_switcher(struct smb1390 *chip) { - struct smb1390 *chip = data; - int i; + vote(chip->disable_votable, SWITCHER_TOGGLE_VOTER, true, 0); - for (i = 0; i < NUM_IRQS; ++i) { - if (irq == chip->irqs[i]) - pr_debug("%s IRQ triggered\n", smb_irqs[i].name); - } + /* Delay for toggling switcher */ + usleep_range(20, 30); - kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE); - return IRQ_HANDLED; + vote(chip->disable_votable, SWITCHER_TOGGLE_VOTER, false, 0); + + return; } -static irqreturn_t irev_irq_handler(int irq, void *data) +static irqreturn_t default_irq_handler(int irq, void *data) { struct smb1390 *chip = data; - int rc; - - pr_debug("IREV IRQ triggered\n"); - - rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, - CMD_EN_SWITCHER_BIT, 0); - if (rc < 0) { - pr_err("Couldn't disable switcher by command mode, rc=%d\n", - rc); - goto out; - } + int i; - rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, - CMD_EN_SWITCHER_BIT, CMD_EN_SWITCHER_BIT); - if (rc < 0) { - pr_err("Couldn't enable switcher by command mode, rc=%d\n", - rc); - goto out; + for (i = 0; i < NUM_IRQS; ++i) { + if (irq == chip->irqs[i]) + pr_debug("%s IRQ triggered\n", smb_irqs[i].name); + chip->irq_status |= 1 << i; } -out: kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE); return IRQ_HANDLED; } @@ -266,7 +253,7 @@ static const struct smb_irq smb_irqs[] = { }, [IREV_IRQ] = { .name = "irev-fault", - .handler = irev_irq_handler, + .handler = default_irq_handler, .wake = true, }, [VPH_OV_HARD_IRQ] = { @@ -340,6 +327,38 @@ static ssize_t enable_store(struct class *c, struct class_attribute *attr, return count; } +static ssize_t cp_irq_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct smb1390 *chip = container_of(c, struct smb1390, cp_class); + int rc, val; + + rc = smb1390_read(chip, CORE_INT_RT_STS_REG, &val); + if (rc < 0) + return -EINVAL; + + val |= chip->irq_status; + chip->irq_status = 0; + + return snprintf(buf, PAGE_SIZE, "%x\n", val); +} + +static ssize_t toggle_switcher_store(struct class *c, + struct class_attribute *attr, const char *buf, + size_t count) +{ + struct smb1390 *chip = container_of(c, struct smb1390, cp_class); + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val) + cp_toggle_switcher(chip); + + return count; +} + static ssize_t die_temp_show(struct class *c, struct class_attribute *attr, char *buf) { @@ -360,6 +379,8 @@ static struct class_attribute cp_class_attrs[] = { __ATTR_RO(stat1), __ATTR_RO(stat2), __ATTR_RW(enable), + __ATTR_RO(cp_irq), + __ATTR_WO(toggle_switcher), __ATTR_RO(die_temp), __ATTR_NULL, }; -- GitLab From 03190ca43bfc0c02abc4142b72285fa2175efee8 Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Fri, 27 Apr 2018 12:46:17 +0530 Subject: [PATCH 648/855] ARM: dts: msm: Add smb1390 support Add smb1390 basic device specifications like the interrupt channels, pin control details and register address space. Change-Id: Icce2ecca63f4230eea9425ee2c4c598874f8ab74 Signed-off-by: Umang Agrawal --- arch/arm64/boot/dts/qcom/smb1390.dtsi | 61 +++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/smb1390.dtsi diff --git a/arch/arm64/boot/dts/qcom/smb1390.dtsi b/arch/arm64/boot/dts/qcom/smb1390.dtsi new file mode 100644 index 000000000000..92ac1034a2fe --- /dev/null +++ b/arch/arm64/boot/dts/qcom/smb1390.dtsi @@ -0,0 +1,61 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +smb1390: qcom,smb1390@10 { + compatible = "qcom,i2c-pmic"; + reg = <0x10>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "smb1390"; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x10>; + + smb1390_revid: qcom,revid { + compatible = "qcom,qpnp-revid"; + reg = <0x100>; + }; + + smb1390_charger: qcom,charge_pump { + compatible = "qcom,smb1390-charger"; + qcom,pmic-revid = <&smb1390_revid>; + interrupt-parent = <&smb1390>; + pinctrl-names = "default"; + pinctrl-0 = <&smb1390_die_temp_default>; + qcom,smb-vadc = <&pm8998_vadc>; + qcom,channel-num = <0x14>; + status = "disabled"; + + qcom,core { + interrupts = <0x10 0x0 IRQ_TYPE_EDGE_RISING>, + <0x10 0x1 IRQ_TYPE_EDGE_RISING>, + <0x10 0x2 IRQ_TYPE_EDGE_RISING>, + <0x10 0x3 IRQ_TYPE_EDGE_RISING>, + <0x10 0x4 IRQ_TYPE_EDGE_RISING>, + <0x10 0x5 IRQ_TYPE_EDGE_RISING>, + <0x10 0x6 IRQ_TYPE_EDGE_RISING>, + <0x10 0x7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "switcher-off-window", + "switcher-off-fault", + "tsd-fault", + "irev-fault", + "vph-ov-hard", + "vph-ov-soft", + "ilim", + "temp-alarm"; + }; + }; +}; -- GitLab From f55c5e0477c0c1efd6ce891679f320a474b9b22e Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Thu, 31 May 2018 17:27:24 +0300 Subject: [PATCH 649/855] msm: ipa3: fix qsb configuration for ipa4.0 Starting IPA 4.0, max outstanding reads for the DDR QMB need to be update to 12 instead of 8. Change-Id: I7d143bcb86799970d9b1b2fd89fd1668fa575f62 Signed-off-by: Ghanim Fodi --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index b3a7f98f6faf..61c81cdee037 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1991,10 +1991,13 @@ void ipa3_cfg_qsb(void) max_writes.qmb_1_max_writes = 2; if (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5) { - max_writes.qmb_1_max_writes = 4; max_reads.qmb_1_max_reads = 12; + max_writes.qmb_1_max_writes = 4; } + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) + max_reads.qmb_0_max_reads = 12; + ipahal_write_reg_fields(IPA_QSB_MAX_WRITES, &max_writes); ipahal_write_reg_fields(IPA_QSB_MAX_READS, &max_reads); } -- GitLab From 195858a1ff54d8e022a21548775be8252de07a81 Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Fri, 1 Jun 2018 02:30:34 +0530 Subject: [PATCH 650/855] defconfig: msm8937: Enable VTI config for v4 and v6 Enable VTI to give userspace (netd) the ability to create and update virtual interfaces. CRs-Fixed: 2214527 Change-Id: Ifdcd0e92b90f584a2c06fd1c4b96b86517dd0c5b Signed-off-by: Devi Sandeep Endluri V V --- arch/arm64/configs/msm8937-perf_defconfig | 2 ++ arch/arm64/configs/msm8937_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index 48d2becd6327..ac6cc3dd4c72 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -102,6 +102,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -113,6 +114,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig index acb4a258be59..ced9c40057b2 100644 --- a/arch/arm64/configs/msm8937_defconfig +++ b/arch/arm64/configs/msm8937_defconfig @@ -106,6 +106,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -117,6 +118,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y -- GitLab From 8843703e71cc2f762b58df35005c13193044a554 Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Fri, 1 Jun 2018 02:28:36 +0530 Subject: [PATCH 651/855] defconfig: msm8953: Enable VTI config for v4 and v6 Enable VTI to give userspace (netd) the ability to create and update virtual interfaces. CRs-Fixed: 2214527 Change-Id: Ib1d73b805ba54946491e5ea43b147449a979de9a Signed-off-by: Devi Sandeep Endluri V V --- arch/arm64/configs/msm8953-perf_defconfig | 2 ++ arch/arm64/configs/msm8953_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig index 1f539cb1e15b..b46317beb0bc 100644 --- a/arch/arm64/configs/msm8953-perf_defconfig +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -105,6 +105,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -116,6 +117,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index 788512b67585..22e3510f3ed8 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -109,6 +109,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -120,6 +121,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y -- GitLab From a9e72fecb4aa10aeb9a0f49a4a03f1c32513ad4c Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Fri, 1 Jun 2018 02:25:18 +0530 Subject: [PATCH 652/855] defconfig: sdm670: Enable VTI config for v4 and v6 Enable VTI to give userspace (netd) the ability to create and update virtual interfaces. CRs-Fixed: 2214527 Change-Id: I53f30e4574ca12901b2a21e76cf2bfbdaa4359a5 Signed-off-by: Devi Sandeep Endluri V V --- arch/arm64/configs/sdm670-perf_defconfig | 2 ++ arch/arm64/configs/sdm670_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig index 7b99783e032b..bf43e36e38b5 100644 --- a/arch/arm64/configs/sdm670-perf_defconfig +++ b/arch/arm64/configs/sdm670-perf_defconfig @@ -103,6 +103,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -115,6 +116,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig index 0c01944b6a35..72604a54b1ee 100644 --- a/arch/arm64/configs/sdm670_defconfig +++ b/arch/arm64/configs/sdm670_defconfig @@ -108,6 +108,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -120,6 +121,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y -- GitLab From 95867cc8ef8f0814a4c372c8fda10a66aa30eb51 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Mon, 28 May 2018 15:39:20 +0530 Subject: [PATCH 653/855] sched/cpupri: Exclude isolated CPUs from the lowest_mask The cpupri_find() returns the candidate CPUs which are running lower priority than the waking RT task in the lowest_mask. This contains isolated CPUs as well. Since the energy aware CPU selection skips isolated CPUs, no target CPU may be found if all unisolated CPUs are running higher priority RT tasks. In which case, we fallback to the default CPU selection algorithm and returns an isolated CPU. This decision is reversed by select_task_rq() and returns an unisolated CPU that is busy with other RT tasks. This RT task packing is desired behavior. However, RT push mechanism pushes the packed RT task to an isolated CPU. This can be avoided by excluding isolated CPUs from the lowest_mask returned by cpupri_find(). Change-Id: I75486b3935caf496a638d0333565beffc47fe249 Signed-off-by: Pavankumar Kondeti --- kernel/sched/cpupri.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c index 87bea1e2605e..aec86a2693cf 100644 --- a/kernel/sched/cpupri.c +++ b/kernel/sched/cpupri.c @@ -133,6 +133,8 @@ int cpupri_find(struct cpupri *cp, struct task_struct *p, if (lowest_mask) { cpumask_and(lowest_mask, tsk_cpus_allowed(p), vec->mask); + cpumask_andnot(lowest_mask, lowest_mask, + cpu_isolated_mask); if (drop_nopreempts) drop_nopreempt_cpus(lowest_mask); /* -- GitLab From b91a3bb3f8afaf1b582311d288bf5682002dd39a Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Wed, 30 May 2018 08:34:12 +0530 Subject: [PATCH 654/855] core_ctl: Isolate not_preferred CPUs first during max_cpus limiting When CPUs are limited via max_cpus tunable, core_ctl first try to isolate the non busy CPUs. During this, not_preferred CPUs are skipped. If more CPUs have to be isolated, CPUs are isolated in the sequential order without checking not_preferred hint. So we may end up keeping not_preferred CPUs active after this step. Add another step to isolate the not_preferred CPUs first during max_cpus limiting. Change-Id: If2c5c9d9c69718c1e586cd81c1af0ed0b5d13075 Signed-off-by: Pavankumar Kondeti --- kernel/sched/core_ctl.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c index 26c9cf4cc170..bd64b1a93bf8 100644 --- a/kernel/sched/core_ctl.c +++ b/kernel/sched/core_ctl.c @@ -789,6 +789,7 @@ static void try_to_isolate(struct cluster_data *cluster, unsigned int need) unsigned long flags; unsigned int num_cpus = cluster->num_cpus; unsigned int nr_isolated = 0; + bool first_pass = cluster->nr_not_preferred_cpus; /* * Protect against entry being removed (and added at tail) by other @@ -834,6 +835,7 @@ static void try_to_isolate(struct cluster_data *cluster, unsigned int need) cluster->nr_isolated_cpus += nr_isolated; spin_unlock_irqrestore(&state_lock, flags); +again: /* * If the number of active CPUs is within the limits, then * don't force isolation of any busy CPUs. @@ -853,6 +855,9 @@ static void try_to_isolate(struct cluster_data *cluster, unsigned int need) if (cluster->active_cpus <= cluster->max_cpus) break; + if (first_pass && !c->not_preferred) + continue; + spin_unlock_irqrestore(&state_lock, flags); pr_debug("Trying to isolate CPU%u\n", c->cpu); @@ -869,6 +874,10 @@ static void try_to_isolate(struct cluster_data *cluster, unsigned int need) cluster->nr_isolated_cpus += nr_isolated; spin_unlock_irqrestore(&state_lock, flags); + if (first_pass && cluster->active_cpus > cluster->max_cpus) { + first_pass = false; + goto again; + } } static void __try_to_unisolate(struct cluster_data *cluster, -- GitLab From 342c69e0595bd1f34b7de35eac7d0ce56f96ad65 Mon Sep 17 00:00:00 2001 From: Arun kumar Date: Tue, 29 May 2018 13:09:05 +0530 Subject: [PATCH 655/855] ARM: dts: msm: Add clk entry for NFC on all 8909w targets Add LNBBCLK3 pin clock entry for NFC on all 8909 wearable variants. Change-Id: Ia8b3769961745c0cad38f9888df5ead8aaf4e41b Signed-off-by: Arun kumar --- arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts | 5 ++++- arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts | 5 ++++- arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts b/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts index c5b7c25a6439..20878c02864f 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts +++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts @@ -158,8 +158,11 @@ interrupts = <50 0>; interrupt-names = "nfc_irq"; pinctrl-names = "nfc_active","nfc_suspend"; - pinctrl-0 = <&nfcw_int_active &nfcw_disable_active>; + pinctrl-0 = <&nfcw_int_active + &nfcw_disable_active + &nfc_clk_default>; pinctrl-1 = <&nfcw_int_suspend &nfcw_disable_suspend>; + clocks = <&clock_rpm clk_bb_clk3_pin>; clock-names = "ref_clk"; }; }; diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts index 5571f37a0c24..e7af39f46abf 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts @@ -177,8 +177,11 @@ interrupts = <50 0>; interrupt-names = "nfc_irq"; pinctrl-names = "nfc_active","nfc_suspend"; - pinctrl-0 = <&nfcw_int_active &nfcw_disable_active>; + pinctrl-0 = <&nfcw_int_active + &nfcw_disable_active + &nfc_clk_default>; pinctrl-1 = <&nfcw_int_suspend &nfcw_disable_suspend>; + clocks = <&clock_rpm clk_bb_clk3_pin>; clock-names = "ref_clk"; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts index f16c7a40e867..6f61dd4832ba 100644 --- a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts @@ -222,6 +222,7 @@ &nfcw_disable_active &nfc_clk_default>; pinctrl-1 = <&nfcw_int_suspend &nfcw_disable_suspend>; + clocks = <&clock_rpm clk_bb_clk3_pin>; clock-names = "ref_clk"; }; }; -- GitLab From 35b2e8cc1fde24db918163719311ce93bdcf690d Mon Sep 17 00:00:00 2001 From: "Reshetova, Elena" Date: Fri, 30 Jun 2017 13:08:10 +0300 Subject: [PATCH 656/855] net: convert packet_fanout.sk_ref from atomic_t to refcount_t refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova Signed-off-by: Hans Liljestrand Signed-off-by: Kees Cook Signed-off-by: David Windsor Signed-off-by: David S. Miller Change-Id: Ibcded37762b5421cb3b81ca19b1f13a101ac3958 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Git-commit: fb5c2c17a556d9b00798d6a6b9e624281ee2eb28 [dcagle@codeaurora.org: Change one more atomic ref to refcount] Signed-off-by: Dennis Cagle --- net/packet/af_packet.c | 10 +++++----- net/packet/internal.h | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 267db0d603bc..f15f08bfe8bb 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1685,7 +1685,7 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) match->flags = flags; INIT_LIST_HEAD(&match->list); spin_lock_init(&match->lock); - atomic_set(&match->sk_ref, 0); + refcount_set(&match->sk_ref, 0); fanout_init_data(match); match->prot_hook.type = po->prot_hook.type; match->prot_hook.dev = po->prot_hook.dev; @@ -1702,19 +1702,19 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) match->prot_hook.type == po->prot_hook.type && match->prot_hook.dev == po->prot_hook.dev) { err = -ENOSPC; - if (atomic_read(&match->sk_ref) < PACKET_FANOUT_MAX) { + if (refcount_read(&match->sk_ref) < PACKET_FANOUT_MAX) { __dev_remove_pack(&po->prot_hook); po->fanout = match; po->rollover = rollover; rollover = NULL; - atomic_inc(&match->sk_ref); + refcount_set(&match->sk_ref, refcount_read(&match->sk_ref) + 1); __fanout_link(sk, po); err = 0; } } spin_unlock(&po->bind_lock); - if (err && !atomic_read(&match->sk_ref)) { + if (err && !refcount_read(&match->sk_ref)) { list_del(&match->list); kfree(match); } @@ -1740,7 +1740,7 @@ static struct packet_fanout *fanout_release(struct sock *sk) if (f) { po->fanout = NULL; - if (atomic_dec_and_test(&f->sk_ref)) + if (refcount_dec_and_test(&f->sk_ref)) list_del(&f->list); else f = NULL; diff --git a/net/packet/internal.h b/net/packet/internal.h index d55bfc34d6b3..e76042f3ebd6 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -1,6 +1,8 @@ #ifndef __PACKET_INTERNAL_H__ #define __PACKET_INTERNAL_H__ +#include + struct packet_mclist { struct packet_mclist *next; int ifindex; @@ -86,7 +88,7 @@ struct packet_fanout { struct list_head list; struct sock *arr[PACKET_FANOUT_MAX]; spinlock_t lock; - atomic_t sk_ref; + refcount_t sk_ref; struct packet_type prot_hook ____cacheline_aligned_in_smp; }; -- GitLab From 803ca5d9025319f227d6c06581db595e553b7869 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 18 Nov 2016 13:40:45 +0100 Subject: [PATCH 657/855] cpufreq: Avoid using inactive policies There are two places in the cpufreq core in which low-level driver callbacks may be invoked for an inactive cpufreq policy, which isn't guaranteed to work in general. Both are due to possible races with CPU offline. First, in cpufreq_get(), the policy may become inactive after the check against policy->cpus in cpufreq_cpu_get() and before policy->rwsem is acquired, in which case using it going forward may not be correct. Second, an analogous situation is possible in cpufreq_update_policy(). Avoid using inactive policies by adding policy_is_inactive() checks to the code in the above places. Change-Id: Ifb10b31b2f56760f2bd795706a3000a884f96187 Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar Git-commit: 182e36af0663a1050c42d234a5bf36f084f8c28b Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Santosh Mardi --- drivers/cpufreq/cpufreq.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 8059ef9c7428..328cdf84ef9f 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1651,7 +1651,10 @@ unsigned int cpufreq_get(unsigned int cpu) if (policy) { down_read(&policy->rwsem); - ret_freq = __cpufreq_get(policy); + + if (!policy_is_inactive(policy)) + ret_freq = __cpufreq_get(policy); + up_read(&policy->rwsem); cpufreq_cpu_put(policy); @@ -2394,6 +2397,11 @@ int cpufreq_update_policy(unsigned int cpu) down_write(&policy->rwsem); + if (policy_is_inactive(policy)) { + ret = -ENODEV; + goto unlock; + } + pr_debug("updating policy for CPU %u\n", cpu); memcpy(&new_policy, policy, sizeof(*policy)); new_policy.min = policy->user_policy.min; -- GitLab From 93ce13269b5f8a3aa8a6a10caa8aee62daf1655d Mon Sep 17 00:00:00 2001 From: Santosh Mardi Date: Thu, 31 May 2018 16:20:40 +0530 Subject: [PATCH 658/855] defconfig: disable interactive governor on sdm439 target On 4.9 kernel interactive governor is not supported instead schedutil governor is being used. Disable interactive governor for sdm439 target. Change-Id: Id066dd53c71b31a7300f771f5cc04855bde7fda0 Signed-off-by: Santosh Mardi --- arch/arm/configs/msm8937-perf_defconfig | 1 - arch/arm/configs/msm8937_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index 09b6f0573822..11fcb5d719e0 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -75,7 +75,6 @@ CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_BOOST=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 1fefcc61693b..d7a8e2b3af80 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -78,7 +78,6 @@ CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_BOOST=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y -- GitLab From 86090ade9b7ce67e55bb34dcf88ae4f985f93ab1 Mon Sep 17 00:00:00 2001 From: kris_chen Date: Thu, 24 Nov 2016 21:18:15 +0800 Subject: [PATCH 659/855] muskie: fingerprint: add FPC kernel driver Adds FPC kernel driver files Bug:32875729 Change-Id: I642ef6fdd91f2d7a43b7f74045b50f689010edf4 commit fpc: fingerprint driver ("e17e8b1e28f5d52a5") Git-commit: f6a1ae75a80eae7c9f713bae17e8b1e28f5d52a5 Git-repo: https://android.googlesource.com/kernel/msm.git Signed-off-by: kris_chen [cang@codeaurora.org: resolve code compile errors] Signed-off-by: Can Guo --- .../devicetree/bindings/misc/fpc,fpc1028.txt | 85 +++ .../devicetree/bindings/vendor-prefixes.txt | 1 + drivers/misc/Kconfig | 1 + drivers/misc/Makefile | 1 + drivers/misc/fpr_FingerprintCard/Kconfig | 10 + drivers/misc/fpr_FingerprintCard/Makefile | 5 + .../fpc1020_platform_tee.c | 683 ++++++++++++++++++ 7 files changed, 786 insertions(+) create mode 100644 Documentation/devicetree/bindings/misc/fpc,fpc1028.txt create mode 100644 drivers/misc/fpr_FingerprintCard/Kconfig create mode 100644 drivers/misc/fpr_FingerprintCard/Makefile create mode 100644 drivers/misc/fpr_FingerprintCard/fpc1020_platform_tee.c diff --git a/Documentation/devicetree/bindings/misc/fpc,fpc1028.txt b/Documentation/devicetree/bindings/misc/fpc,fpc1028.txt new file mode 100644 index 000000000000..233c7cc73b64 --- /dev/null +++ b/Documentation/devicetree/bindings/misc/fpc,fpc1028.txt @@ -0,0 +1,85 @@ +Fingerprint Cards AB. Fpc1028 driver + +The fpc1028 fingerprint sensor is connected to the host processor via SPI. +The sensor will generates interrupts when the user touches the sensor. +The host controller is expected to read data over SPI and pass the data to +the rest of the system. + +This binding document describes the properties for this module. + +Properties: + +- compatible + Usage: required + Value type: + Definition: It must be "fpc,fpc1020" + +- interrupts + Usage: required + Value type: + Definition: Peripheral interrupt specifier. + +- interrupt-parent + Usage: required + Value type: + Definition: phandle of the interrupt controller which services the + summary interrupt. + +- fpc,gpio_rst + Usage: required + Value type: + Definition: GPIO which connecting to the reset pin of fpc1028 + +- fpc,gpio_irq + Usage: required + Value type: + Definition: Specifies the GPIO which connecting to the irq pin of fpc1028. + +- vcc_spi-supply + Usage: required + Value type: + Definition: The phandle of the regulator which supplies fpc1028 spi bus core. + +- vcc_io-supply + Usage: required + Value type: + Definition: The phandle of the regulator which supplies fpc1028 io pins. + +- vcc_ana-supply + Usage: required + Value type: + Definition: The phandle of the regulator which supplies fpc1028 analog circuit. + +- pinctrl-names: + Usage: required + Value type: + Definition: Pinctrl state names for each pin group configuration. + eg:"fpc1020_reset_reset", "fpc1020_reset_active", "fpc1020_irq_active". + refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" + +- pinctrl-n: + Usage: required + Value type: + Definition: pinctrl state for each pin group + refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" + + +Example: + + fpc1020 { + compatible = "fpc,fpc1020"; + interrupt-parent = <&tlmm>; + interrupts = <48 0>; + fpc,gpio_rst = <&tlmm 124 0x0>; + fpc,gpio_irq = <&tlmm 48 0>; + vcc_spi-supply = <&pm8953_l5>; + vdd_io-supply = <&pm8953_l5>; + vdd_ana-supply = <&pm8953_l5>; + fpc,enable-on-boot; + pinctrl-names = "fpc1020_reset_reset", + "fpc1020_reset_active", + "fpc1020_irq_active"; + pinctrl-0 = <&msm_gpio_124>; + pinctrl-1 = <&msm_gpio_124_output_high>; + pinctrl-2 = <&msm_gpio_48>; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index e1be5fda99b4..a22edb520505 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -103,6 +103,7 @@ ezchip EZchip Semiconductor fcs Fairchild Semiconductor firefly Firefly focaltech FocalTech Systems Co.,Ltd +fpc Fingerprint Cards AB. friendlyarm Guangzhou FriendlyARM Computer Tech Co., Ltd fsl Freescale Semiconductor ge General Electric Company diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index e3f4c3989870..a233173d5c79 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -825,4 +825,5 @@ source "drivers/misc/mic/Kconfig" source "drivers/misc/genwqe/Kconfig" source "drivers/misc/echo/Kconfig" source "drivers/misc/cxl/Kconfig" +source "drivers/misc/fpr_FingerprintCard/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index f1c94677a97e..8e5d0f61da4c 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o obj-$(CONFIG_CXL_BASE) += cxl/ obj-$(CONFIG_PANEL) += panel.o obj-$(CONFIG_QPNP_MISC) += qpnp-misc.o +obj-$(CONFIG_FPR_FPC) += fpr_FingerprintCard/ obj-$(CONFIG_MEMORY_STATE_TIME) += memory_state_time.o obj-$(CONFIG_UID_SYS_STATS) += uid_sys_stats.o diff --git a/drivers/misc/fpr_FingerprintCard/Kconfig b/drivers/misc/fpr_FingerprintCard/Kconfig new file mode 100644 index 000000000000..c9599e6bb4a3 --- /dev/null +++ b/drivers/misc/fpr_FingerprintCard/Kconfig @@ -0,0 +1,10 @@ +# +# FingerprintCard fingerprint driver +# +menu "FingerprintCard fingerprint driver" +config FPR_FPC + default n + tristate "FPC_BTP fingerprint sensor support" + depends on SPI_MASTER + +endmenu diff --git a/drivers/misc/fpr_FingerprintCard/Makefile b/drivers/misc/fpr_FingerprintCard/Makefile new file mode 100644 index 000000000000..96681eb834a6 --- /dev/null +++ b/drivers/misc/fpr_FingerprintCard/Makefile @@ -0,0 +1,5 @@ +# Makefile for FingerprintCard fingerprint driver + +fpc1020-objs := fpc1020_platform_tee.o +obj-$(CONFIG_FPR_FPC) += fpc1020.o + diff --git a/drivers/misc/fpr_FingerprintCard/fpc1020_platform_tee.c b/drivers/misc/fpr_FingerprintCard/fpc1020_platform_tee.c new file mode 100644 index 000000000000..887c8eb2f9ee --- /dev/null +++ b/drivers/misc/fpr_FingerprintCard/fpc1020_platform_tee.c @@ -0,0 +1,683 @@ +/* + * FPC1020 Fingerprint sensor device driver + * + * This driver will control the platform resources that the FPC fingerprint + * sensor needs to operate. The major things are probing the sensor to check + * that it is actually connected and let the Kernel know this and with that also + * enabling and disabling of regulators, controlling GPIOs such as sensor reset + * line, sensor IRQ line. + * + * The driver will expose most of its available functionality in sysfs which + * enables dynamic control of these features from eg. a user space process. + * + * The sensor's IRQ events will be pushed to Kernel's event handling system and + * are exposed in the drivers event node. + * + * This driver will NOT send any commands to the sensor it only controls the + * electrical parts. + * + * + * Copyright (c) 2015 Fingerprint Cards AB + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License Version 2 + * as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define FPC_TTW_HOLD_TIME 1000 +#define RESET_LOW_SLEEP_MIN_US 5000 +#define RESET_LOW_SLEEP_MAX_US (RESET_LOW_SLEEP_MIN_US + 100) +#define RESET_HIGH_SLEEP1_MIN_US 100 +#define RESET_HIGH_SLEEP1_MAX_US (RESET_HIGH_SLEEP1_MIN_US + 100) +#define RESET_HIGH_SLEEP2_MIN_US 5000 +#define RESET_HIGH_SLEEP2_MAX_US (RESET_HIGH_SLEEP2_MIN_US + 100) +#define PWR_ON_SLEEP_MIN_US 100 +#define PWR_ON_SLEEP_MAX_US (PWR_ON_SLEEP_MIN_US + 900) +#define NUM_PARAMS_REG_ENABLE_SET 2 + +#define RELEASE_WAKELOCK_W_V "release_wakelock_with_verification" +#define RELEASE_WAKELOCK "release_wakelock" +#define START_IRQS_RECEIVED_CNT "start_irqs_received_counter" + +static const char * const pctl_names[] = { + "fpc1020_reset_reset", + "fpc1020_reset_active", + "fpc1020_irq_active", +}; + +struct vreg_config { + char *name; + unsigned long vmin; + unsigned long vmax; + int ua_load; +}; + +static const struct vreg_config vreg_conf[] = { + { "vdd_ana", 1800000UL, 1800000UL, 6000, }, + { "vcc_spi", 1800000UL, 1800000UL, 10, }, + { "vdd_io", 1800000UL, 1800000UL, 6000, }, +}; + +struct fpc1020_data { + struct device *dev; + struct pinctrl *fingerprint_pinctrl; + struct pinctrl_state **pinctrl_state; + struct regulator **vreg; + struct wakeup_source ttw_wl; + struct mutex lock; /* To set/get exported values in sysfs */ + int irq_gpio; + int rst_gpio; + int nbr_irqs_received; + int nbr_irqs_received_counter_start; + bool prepared; + atomic_t wakeup_enabled; /* Used both in ISR and non-ISR */ +}; + +static int vreg_setup(struct fpc1020_data *fpc1020, const char *name, + bool enable) +{ + size_t i; + int rc; + struct regulator *vreg; + struct device *dev = fpc1020->dev; + + for (i = 0; i < ARRAY_SIZE(vreg_conf); i++) { + const char *n = vreg_conf[i].name; + + if (!memcmp(n, name, strlen(n))) + goto found; + } + + dev_err(dev, "Regulator %s not found\n", name); + + return -EINVAL; + +found: + vreg = fpc1020->vreg[i]; + if (enable) { + if (!vreg) { + vreg = devm_regulator_get(dev, name); + if (IS_ERR_OR_NULL(vreg)) { + dev_err(dev, "Unable to get %s\n", name); + return PTR_ERR(vreg); + } + } + + if (regulator_count_voltages(vreg) > 0) { + rc = regulator_set_voltage(vreg, vreg_conf[i].vmin, + vreg_conf[i].vmax); + if (rc) + dev_err(dev, + "Unable to set voltage on %s, %d\n", + name, rc); + } + + rc = regulator_set_load(vreg, vreg_conf[i].ua_load); + if (rc < 0) + dev_err(dev, "Unable to set current on %s, %d\n", + name, rc); + + rc = regulator_enable(vreg); + if (rc) { + dev_err(dev, "error enabling %s: %d\n", name, rc); + vreg = NULL; + } + fpc1020->vreg[i] = vreg; + } else { + if (vreg) { + if (regulator_is_enabled(vreg)) { + regulator_disable(vreg); + dev_dbg(dev, "disabled %s\n", name); + } + fpc1020->vreg[i] = NULL; + } + rc = 0; + } + + return rc; +} + +/* + * sysfs node for controlling clocks. + * + * This is disabled in platform variant of this driver but kept for + * backwards compatibility. Only prints a debug print that it is + * disabled. + */ +static ssize_t clk_enable_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + dev_dbg(dev, + "clk_enable sysfs node not enabled in platform driver\n"); + + return count; +} +static DEVICE_ATTR(clk_enable, 0200, NULL, clk_enable_set); + +/* + * Will try to select the set of pins (GPIOS) defined in a pin control node of + * the device tree named @p name. + * + * The node can contain several eg. GPIOs that is controlled when selecting it. + * The node may activate or deactivate the pins it contains, the action is + * defined in the device tree node itself and not here. The states used + * internally is fetched at probe time. + * + * @see pctl_names + * @see fpc1020_probe + */ +static int select_pin_ctl(struct fpc1020_data *fpc1020, const char *name) +{ + size_t i; + int rc; + struct device *dev = fpc1020->dev; + + for (i = 0; i < ARRAY_SIZE(pctl_names); i++) { + const char *n = pctl_names[i]; + + if (!memcmp(n, name, strlen(n))) { + rc = pinctrl_select_state(fpc1020->fingerprint_pinctrl, + fpc1020->pinctrl_state[i]); + if (rc) + dev_err(dev, "cannot select '%s'\n", name); + else + dev_dbg(dev, "Selected '%s'\n", name); + goto exit; + } + } + + rc = -EINVAL; + dev_err(dev, "%s:'%s' not found\n", __func__, name); + +exit: + return rc; +} + +static ssize_t pinctl_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + int rc; + + mutex_lock(&fpc1020->lock); + rc = select_pin_ctl(fpc1020, buf); + mutex_unlock(&fpc1020->lock); + + return rc ? rc : count; +} +static DEVICE_ATTR(pinctl_set, 0200, NULL, pinctl_set); + +static ssize_t regulator_enable_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + char op; + char name[16]; + int rc; + bool enable; + + if (sscanf(buf, "%15[^,],%c", name, &op) != NUM_PARAMS_REG_ENABLE_SET) + return -EINVAL; + if (op == 'e') + enable = true; + else if (op == 'd') + enable = false; + else + return -EINVAL; + + mutex_lock(&fpc1020->lock); + rc = vreg_setup(fpc1020, name, enable); + mutex_unlock(&fpc1020->lock); + + return rc ? rc : count; +} +static DEVICE_ATTR(regulator_enable, 0200, NULL, regulator_enable_set); + +static int hw_reset(struct fpc1020_data *fpc1020) +{ + int irq_gpio; + int rc; + + irq_gpio = gpio_get_value(fpc1020->irq_gpio); + + rc = select_pin_ctl(fpc1020, "fpc1020_reset_active"); + + if (rc) + goto exit; + + usleep_range(RESET_HIGH_SLEEP1_MIN_US, RESET_HIGH_SLEEP1_MAX_US); + + rc = select_pin_ctl(fpc1020, "fpc1020_reset_reset"); + + if (rc) + goto exit; + usleep_range(RESET_LOW_SLEEP_MIN_US, RESET_LOW_SLEEP_MAX_US); + + rc = select_pin_ctl(fpc1020, "fpc1020_reset_active"); + if (rc) + goto exit; + usleep_range(RESET_HIGH_SLEEP2_MIN_US, RESET_HIGH_SLEEP2_MAX_US); + + irq_gpio = gpio_get_value(fpc1020->irq_gpio); + +exit: + return rc; +} + +static ssize_t hw_reset_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc = -EINVAL; + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + + if (!memcmp(buf, "reset", strlen("reset"))) { + mutex_lock(&fpc1020->lock); + rc = hw_reset(fpc1020); + mutex_unlock(&fpc1020->lock); + } else { + return rc; + } + + return rc ? rc : count; +} +static DEVICE_ATTR(hw_reset, 0200, NULL, hw_reset_set); + +/* + * Will setup GPIOs, and regulators to correctly initialize the touch sensor to + * be ready for work. + * + * In the correct order according to the sensor spec this function will + * enable/disable regulators, and reset line, all to set the sensor in a + * correct power on or off state "electrical" wise. + * + * @see device_prepare_set + * @note This function will not send any commands to the sensor it will only + * control it "electrically". + */ +static int device_prepare(struct fpc1020_data *fpc1020, bool enable) +{ + int rc = 0; + + mutex_lock(&fpc1020->lock); + if (enable && !fpc1020->prepared) { + fpc1020->prepared = true; + select_pin_ctl(fpc1020, "fpc1020_reset_reset"); + + rc = vreg_setup(fpc1020, "vcc_spi", true); + if (rc) + goto exit; + + rc = vreg_setup(fpc1020, "vdd_io", true); + if (rc) + goto exit_1; + + rc = vreg_setup(fpc1020, "vdd_ana", true); + if (rc) + goto exit_2; + + usleep_range(PWR_ON_SLEEP_MIN_US, PWR_ON_SLEEP_MAX_US); + + (void)select_pin_ctl(fpc1020, "fpc1020_reset_active"); + } else if (!enable && fpc1020->prepared) { + rc = 0; + (void)select_pin_ctl(fpc1020, "fpc1020_reset_reset"); + + usleep_range(PWR_ON_SLEEP_MIN_US, PWR_ON_SLEEP_MAX_US); + + (void)vreg_setup(fpc1020, "vdd_ana", false); +exit_2: + (void)vreg_setup(fpc1020, "vdd_io", false); +exit_1: + (void)vreg_setup(fpc1020, "vcc_spi", false); +exit: + fpc1020->prepared = false; + } + + mutex_unlock(&fpc1020->lock); + + return rc; +} + +/* + * sysfs node to enable/disable (power up/power down) the touch sensor + * + * @see device_prepare + */ +static ssize_t device_prepare_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc; + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + + if (!memcmp(buf, "enable", strlen("enable"))) + rc = device_prepare(fpc1020, true); + else if (!memcmp(buf, "disable", strlen("disable"))) + rc = device_prepare(fpc1020, false); + else + return -EINVAL; + + return rc ? rc : count; +} +static DEVICE_ATTR(device_prepare, 0200, NULL, device_prepare_set); + +/** + * sysfs node for controlling whether the driver is allowed + * to wake up the platform on interrupt. + */ +static ssize_t wakeup_enable_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + ssize_t ret = count; + + mutex_lock(&fpc1020->lock); + if (!memcmp(buf, "enable", strlen("enable"))) + atomic_set(&fpc1020->wakeup_enabled, 1); + else if (!memcmp(buf, "disable", strlen("disable"))) + atomic_set(&fpc1020->wakeup_enabled, 0); + else + ret = -EINVAL; + mutex_unlock(&fpc1020->lock); + + return ret; +} +static DEVICE_ATTR(wakeup_enable, 0200, NULL, wakeup_enable_set); + + +/* + * sysfs node for controlling the wakelock. + */ +static ssize_t handle_wakelock_cmd(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + ssize_t ret = count; + + mutex_lock(&fpc1020->lock); + if (!memcmp(buf, RELEASE_WAKELOCK_W_V, + min(count, strlen(RELEASE_WAKELOCK_W_V)))) { + if (fpc1020->nbr_irqs_received_counter_start == + fpc1020->nbr_irqs_received) { + __pm_relax(&fpc1020->ttw_wl); + } else { + dev_dbg(dev, "Ignore releasing of wakelock %d != %d", + fpc1020->nbr_irqs_received_counter_start, + fpc1020->nbr_irqs_received); + } + } else if (!memcmp(buf, RELEASE_WAKELOCK, min(count, + strlen(RELEASE_WAKELOCK)))) { + __pm_relax(&fpc1020->ttw_wl); + } else if (!memcmp(buf, START_IRQS_RECEIVED_CNT, + min(count, strlen(START_IRQS_RECEIVED_CNT)))) { + fpc1020->nbr_irqs_received_counter_start = + fpc1020->nbr_irqs_received; + } else + ret = -EINVAL; + mutex_unlock(&fpc1020->lock); + + return ret; +} +static DEVICE_ATTR(handle_wakelock, 0200, NULL, handle_wakelock_cmd); + +/* + * sysf node to check the interrupt status of the sensor, the interrupt + * handler should perform sysf_notify to allow userland to poll the node. + */ +static ssize_t irq_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + int irq = gpio_get_value(fpc1020->irq_gpio); + + return scnprintf(buf, PAGE_SIZE, "%i\n", irq); +} + +/* + * writing to the irq node will just drop a printk message + * and return success, used for latency measurement. + */ +static ssize_t irq_ack(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + + dev_dbg(fpc1020->dev, "%s\n", __func__); + + return count; +} +static DEVICE_ATTR(irq, 0600 | 0200, irq_get, irq_ack); + +static struct attribute *attributes[] = { + &dev_attr_pinctl_set.attr, + &dev_attr_device_prepare.attr, + &dev_attr_regulator_enable.attr, + &dev_attr_hw_reset.attr, + &dev_attr_wakeup_enable.attr, + &dev_attr_handle_wakelock.attr, + &dev_attr_clk_enable.attr, + &dev_attr_irq.attr, + NULL +}; + +static const struct attribute_group attribute_group = { + .attrs = attributes, +}; + +static irqreturn_t fpc1020_irq_handler(int irq, void *handle) +{ + struct fpc1020_data *fpc1020 = handle; + + pr_info("fpc1020 irq handler: %s\n", __func__); + mutex_lock(&fpc1020->lock); + if (atomic_read(&fpc1020->wakeup_enabled)) { + fpc1020->nbr_irqs_received++; + __pm_wakeup_event(&fpc1020->ttw_wl, + msecs_to_jiffies(FPC_TTW_HOLD_TIME)); + } + mutex_unlock(&fpc1020->lock); + + sysfs_notify(&fpc1020->dev->kobj, NULL, dev_attr_irq.attr.name); + + return IRQ_HANDLED; +} + +static int fpc1020_request_named_gpio(struct fpc1020_data *fpc1020, + const char *label, int *gpio) +{ + struct device *dev = fpc1020->dev; + struct device_node *np = dev->of_node; + int rc; + + rc = of_get_named_gpio(np, label, 0); + + if (rc < 0) { + dev_err(dev, "failed to get '%s'\n", label); + return rc; + } + *gpio = rc; + + rc = devm_gpio_request(dev, *gpio, label); + if (rc) { + dev_err(dev, "failed to request gpio %d\n", *gpio); + return rc; + } + dev_dbg(dev, "%s %d\n", label, *gpio); + + return 0; +} + +static int fpc1020_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int rc = 0; + size_t i; + int irqf; + struct fpc1020_data *fpc1020 = devm_kzalloc(dev, sizeof(*fpc1020), + GFP_KERNEL); + if (!fpc1020) { + rc = -ENOMEM; + goto exit; + } + + + fpc1020->dev = dev; + platform_set_drvdata(pdev, fpc1020); + + rc = fpc1020_request_named_gpio(fpc1020, "fpc,gpio_irq", + &fpc1020->irq_gpio); + if (rc) + goto exit; + rc = fpc1020_request_named_gpio(fpc1020, "fpc,gpio_rst", + &fpc1020->rst_gpio); + if (rc) + goto exit; + + fpc1020->fingerprint_pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(fpc1020->fingerprint_pinctrl)) { + if (PTR_ERR(fpc1020->fingerprint_pinctrl) == -EPROBE_DEFER) { + dev_info(dev, "pinctrl not ready\n"); + rc = -EPROBE_DEFER; + goto exit; + } + dev_err(dev, "Target does not use pinctrl\n"); + fpc1020->fingerprint_pinctrl = NULL; + rc = -EINVAL; + goto exit; + } + + for (i = 0; i < ARRAY_SIZE(pctl_names); i++) { + const char *n = pctl_names[i]; + struct pinctrl_state *state = + pinctrl_lookup_state(fpc1020->fingerprint_pinctrl, n); + if (IS_ERR(state)) { + dev_err(dev, "cannot find '%s'\n", n); + rc = -EINVAL; + goto exit; + } + dev_info(dev, "found pin control %s\n", n); + fpc1020->pinctrl_state[i] = state; + } + + rc = select_pin_ctl(fpc1020, "fpc1020_reset_reset"); + if (rc) + goto exit; + rc = select_pin_ctl(fpc1020, "fpc1020_irq_active"); + if (rc) + goto exit; + + atomic_set(&fpc1020->wakeup_enabled, 0); + + irqf = IRQF_TRIGGER_RISING | IRQF_ONESHOT; + if (of_property_read_bool(dev->of_node, "fpc,enable-wakeup")) { + irqf |= IRQF_NO_SUSPEND; + device_init_wakeup(dev, 1); + } + + mutex_init(&fpc1020->lock); + rc = devm_request_threaded_irq(dev, gpio_to_irq(fpc1020->irq_gpio), + NULL, fpc1020_irq_handler, irqf, + dev_name(dev), fpc1020); + if (rc) { + dev_err(dev, "could not request irq %d\n", + gpio_to_irq(fpc1020->irq_gpio)); + goto exit; + } + + dev_info(dev, "requested irq %d\n", gpio_to_irq(fpc1020->irq_gpio)); + + /* Request that the interrupt should be wakeable */ + enable_irq_wake(gpio_to_irq(fpc1020->irq_gpio)); + + wakeup_source_init(&fpc1020->ttw_wl, "fpc_ttw_wl"); + + rc = sysfs_create_group(&dev->kobj, &attribute_group); + if (rc) { + dev_err(dev, "could not create sysfs\n"); + goto exit; + } + + if (of_property_read_bool(dev->of_node, "fpc,enable-on-boot")) { + dev_info(dev, "Enabling hardware\n"); + (void)device_prepare(fpc1020, true); + } + + rc = hw_reset(fpc1020); + + dev_info(dev, "%s: ok\n", __func__); + +exit: + return rc; +} + +static int fpc1020_remove(struct platform_device *pdev) +{ + struct fpc1020_data *fpc1020 = platform_get_drvdata(pdev); + + sysfs_remove_group(&pdev->dev.kobj, &attribute_group); + mutex_destroy(&fpc1020->lock); + wakeup_source_trash(&fpc1020->ttw_wl); + (void)vreg_setup(fpc1020, "vdd_ana", false); + (void)vreg_setup(fpc1020, "vdd_io", false); + (void)vreg_setup(fpc1020, "vcc_spi", false); + dev_info(&pdev->dev, "%s\n", __func__); + + return 0; +} + +static const struct of_device_id fpc1020_of_match[] = { + { .compatible = "fpc,fpc1020", }, + {} +}; +MODULE_DEVICE_TABLE(of, fpc1020_of_match); + +static struct platform_driver fpc1020_driver = { + .driver = { + .name = "fpc1020", + .owner = THIS_MODULE, + .of_match_table = fpc1020_of_match, + }, + .probe = fpc1020_probe, + .remove = fpc1020_remove, +}; + +static int __init fpc1020_init(void) +{ + int rc = platform_driver_register(&fpc1020_driver); + + if (!rc) + pr_info("%s OK\n", __func__); + else + pr_err("%s %d\n", __func__, rc); + + return rc; +} + +static void __exit fpc1020_exit(void) +{ + pr_info("%s\n", __func__); + platform_driver_unregister(&fpc1020_driver); +} + +module_init(fpc1020_init); +module_exit(fpc1020_exit); + + +MODULE_DESCRIPTION("FPC1020 Fingerprint sensor device driver."); +MODULE_LICENSE("GPL v2"); -- GitLab From fdfdd1576237bcf1be810255e6eb204176dab346 Mon Sep 17 00:00:00 2001 From: AnilKumar Chimata Date: Tue, 29 May 2018 18:53:14 +0530 Subject: [PATCH 660/855] ice: msm: Encrypt only userdata During the device encryption the vold daemon sends sectors to drivers. Encryption has to be done only for the data partition sectors which are passed from user space. Change-Id: I701359a11cfb1574192badb23b92fec5bf4ad488 Signed-off-by: AnilKumar Chimata --- drivers/crypto/msm/ice.c | 78 ++++++++++++++++-------------------- drivers/misc/qseecom.c | 13 ------ include/uapi/linux/qseecom.h | 10 ----- 3 files changed, 35 insertions(+), 66 deletions(-) diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index f15267eb69b8..18de64f6e9f0 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -77,6 +77,8 @@ static inline void pfk_clear_on_reset(void) #define QCOM_ICE_ENCRYPT 0x1 #define QCOM_ICE_DECRYPT 0x2 #define QCOM_SECT_LEN_IN_BYTE 512 +#define QCOM_UD_FOOTER_SIZE 0x4000 +#define QCOM_UD_FOOTER_SECS (QCOM_UD_FOOTER_SIZE / QCOM_SECT_LEN_IN_BYTE) struct ice_clk_info { struct list_head list; @@ -127,8 +129,6 @@ struct ice_device { }; static int ice_fde_flag; -static unsigned long userdata_start; -static unsigned long userdata_end; static struct ice_crypto_setting ice_data; static int qti_ice_setting_config(struct request *req, @@ -160,17 +160,21 @@ static int qti_ice_setting_config(struct request *req, memcpy(&setting->crypto_data, crypto_data, sizeof(setting->crypto_data)); - if (rq_data_dir(req) == WRITE && - (ice_fde_flag & QCOM_ICE_ENCRYPT)) - setting->encr_bypass = false; - else if (rq_data_dir(req) == READ && - (ice_fde_flag & QCOM_ICE_DECRYPT)) - setting->decr_bypass = false; - else { + switch (rq_data_dir(req)) { + case WRITE: + if (!ice_fde_flag || (ice_fde_flag & QCOM_ICE_ENCRYPT)) + setting->encr_bypass = false; + break; + case READ: + if (!ice_fde_flag || (ice_fde_flag & QCOM_ICE_DECRYPT)) + setting->decr_bypass = false; + break; + default: /* Should I say BUG_ON */ setting->encr_bypass = true; setting->decr_bypass = true; - pr_debug("%s direction unknown", __func__); + pr_debug("%s(): direction unknown\n", __func__); + break; } } @@ -184,26 +188,6 @@ void qcom_ice_set_fde_flag(int flag) } EXPORT_SYMBOL(qcom_ice_set_fde_flag); -int qcom_ice_set_fde_conf(sector_t s_sector, sector_t size, - int index, int mode) -{ - userdata_start = s_sector; - userdata_end = s_sector + size; - if (INT_MAX - s_sector < size) { - WARN_ON(1); - return -EINVAL; - } - ice_data.key_index = index; - ice_data.algo_mode = mode; - ice_data.key_size = ICE_CRYPTO_KEY_SIZE_256; - ice_data.key_mode = ICE_CRYPTO_USE_LUT_SW_KEY; - - pr_debug("%s sector info set start %lu end %lu\n", __func__, - userdata_start, userdata_end); - return 0; -} -EXPORT_SYMBOL(qcom_ice_set_fde_conf); - static int qcom_ice_enable_clocks(struct ice_device *, bool); #ifdef CONFIG_MSM_BUS_SCALING @@ -1490,6 +1474,7 @@ static int qcom_ice_config_start(struct platform_device *pdev, int ret = 0; bool is_pfe = false; sector_t data_size; + unsigned long sec_end = 0; if (!pdev || !req) { pr_err("%s: Invalid params passed\n", __func__); @@ -1528,19 +1513,26 @@ static int qcom_ice_config_start(struct platform_device *pdev, if (ice_fde_flag == 0) return 0; - if ((req->__sector >= userdata_start) && - (req->__sector < userdata_end)) { - /* - * Ugly hack to address non-block-size aligned userdata end address in - * eMMC based devices. - */ - data_size = req->__data_len/QCOM_SECT_LEN_IN_BYTE; - - if ((req->__sector + data_size) > userdata_end) - return 0; - else - return qti_ice_setting_config(req, pdev, - &ice_data, setting); + if (req->part && req->part->info && req->part->info->volname[0]) { + if (!strcmp(req->part->info->volname, "userdata")) { + sec_end = req->part->start_sect + req->part->nr_sects - + QCOM_UD_FOOTER_SECS; + if ((req->__sector >= req->part->start_sect) && + (req->__sector < sec_end)) { + /* + * Ugly hack to address non-block-size aligned + * userdata end address in eMMC based devices. + */ + data_size = req->__data_len / + QCOM_SECT_LEN_IN_BYTE; + + if ((req->__sector + data_size) > sec_end) + return 0; + else + return qti_ice_setting_config(req, pdev, + &ice_data, setting); + } + } } /* diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 2b31ed3f981d..d61f20e9cf63 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -6979,19 +6979,6 @@ static inline long qseecom_ioctl(struct file *file, break; } - case QSEECOM_IOCTL_SET_ENCDEC_INFO: { - struct qseecom_encdec_conf_t conf; - - ret = copy_from_user(&conf, argp, sizeof(conf)); - if (ret) { - pr_err("copy_from_user failed\n"); - return -EFAULT; - } - ret = qcom_ice_set_fde_conf(conf.start_sector, conf.fs_size, - conf.index, conf.mode); - break; - } - case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: { if ((data->listener.id == 0) || (data->type != QSEECOM_LISTENER_SERVICE)) { diff --git a/include/uapi/linux/qseecom.h b/include/uapi/linux/qseecom.h index f0a26b250b73..6de4c760b0ed 100644 --- a/include/uapi/linux/qseecom.h +++ b/include/uapi/linux/qseecom.h @@ -281,13 +281,6 @@ struct qseecom_ice_data_t { int flag; }; -struct qseecom_encdec_conf_t { - __le64 start_sector; - size_t fs_size; - int index; - int mode; -}; - #define SG_ENTRY_SZ sizeof(struct qseecom_sg_entry) #define SG_ENTRY_SZ_64BIT sizeof(struct qseecom_sg_entry_64bit) @@ -399,7 +392,4 @@ struct file; #define QSEECOM_IOCTL_SET_ICE_INFO \ _IOWR(QSEECOM_IOC_MAGIC, 43, struct qseecom_ice_data_t) -#define QSEECOM_IOCTL_SET_ENCDEC_INFO \ - _IOWR(QSEECOM_IOC_MAGIC, 44, struct qseecom_encdec_conf_t) - #endif /* _UAPI_QSEECOM_H_ */ -- GitLab From bd50050aecdb2e34df66c5cac9955927e48fa24a Mon Sep 17 00:00:00 2001 From: AnilKumar Chimata Date: Wed, 30 May 2018 06:25:26 +0530 Subject: [PATCH 661/855] Revert "block: Expose IOCTL to get partition start sector number" This reverts commit e959c1ce821c7ea4fe66e2f1449b3cdde2ccd25c. Sector information is identified by other means so this change is not needed. Change-Id: Ib9cd450085b22468853b5a4955f8760d67af51b1 Signed-off-by: AnilKumar Chimata --- block/ioctl.c | 2 -- include/uapi/linux/fs.h | 1 - 2 files changed, 3 deletions(-) diff --git a/block/ioctl.c b/block/ioctl.c index d4a78d0f05f6..c4555b1ff45a 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -564,8 +564,6 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, if ((size >> 9) > ~0UL) return -EFBIG; return put_ulong(arg, size >> 9); - case BLKGETSTPART: - return put_ulong(arg, bdev->bd_part->start_sect); case BLKGETSIZE64: return put_u64(arg, i_size_read(bdev->bd_inode)); case BLKTRACESTART: diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index dfcf37128ecb..fb1ec56e93fe 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -226,7 +226,6 @@ struct fsxattr { #define BLKSECDISCARD _IO(0x12,125) #define BLKROTATIONAL _IO(0x12,126) #define BLKZEROOUT _IO(0x12,127) -#define BLKGETSTPART _IO(0x12, 128) #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ #define FIBMAP _IO(0x00,1) /* bmap access */ -- GitLab From a38a69467ec8d5023360e9dce79363b82e4507dd Mon Sep 17 00:00:00 2001 From: AnilKumar Chimata Date: Wed, 30 May 2018 23:09:32 +0530 Subject: [PATCH 662/855] ice: Add code to support older implementation If ice_fde_flag is not configured which means older design is in-place. New logic is added to handle old scenario to avoid boot up issues. Change-Id: I0dce89c0665bdc41e0d6c50f0b1f777b22e4d4d5 Signed-off-by: AnilKumar Chimata --- drivers/crypto/msm/ice.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index 18de64f6e9f0..199d57353801 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -1470,10 +1470,12 @@ static int qcom_ice_config_start(struct platform_device *pdev, struct request *req, struct ice_data_setting *setting, bool async) { + struct ice_crypto_setting *crypto_data; struct ice_crypto_setting pfk_crypto_data = {0}; int ret = 0; bool is_pfe = false; sector_t data_size; + union map_info *info; unsigned long sec_end = 0; if (!pdev || !req) { @@ -1510,8 +1512,25 @@ static int qcom_ice_config_start(struct platform_device *pdev, &pfk_crypto_data, setting); } - if (ice_fde_flag == 0) + if (!ice_fde_flag) { + if (bio_flagged(req->bio, BIO_INLINECRYPT)) { + info = dm_get_rq_mapinfo(req); + if (!info) { + pr_debug("%s info not available in request\n", + __func__); + return 0; + } + crypto_data = (struct ice_crypto_setting *)info->ptr; + if (!crypto_data) { + pr_err("%s crypto_data not available in req\n", + __func__); + return -EINVAL; + } + return qti_ice_setting_config(req, pdev, + crypto_data, setting); + } return 0; + } if (req->part && req->part->info && req->part->info->volname[0]) { if (!strcmp(req->part->info->volname, "userdata")) { -- GitLab From 1896e93dc07b3ead01c209343869b5389a7c4f98 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Wed, 30 May 2018 12:34:05 +0530 Subject: [PATCH 663/855] phy: msm: usb: Add module param for PHY charger detection If Data lines are cut off from PMI and PMI still doing charger detection, then we get an extcon notification from PMI with charger type as USB_FLOAT. Add a module parameter which if set, will queue PHY based charger detection to notify actual charger type and current to PMI. Usage of the module param 'chg_detection_for_float_charger': echo Y > /sys/module/phy_msm_usb/parameters/chg_detection_for_float_charger Change-Id: Ibdd2e69ea47440d13ca845b0418da9c485e81d2e Signed-off-by: Ajay Agarwal --- drivers/usb/phy/phy-msm-usb.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 1550caee9886..a6326d5e0c88 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -273,6 +273,11 @@ static int dcp_max_current = IDEV_CHG_MAX; module_param(dcp_max_current, int, 0644); MODULE_PARM_DESC(dcp_max_current, "max current drawn for DCP charger"); +static bool chg_detection_for_float_charger; +module_param(chg_detection_for_float_charger, bool, 0644); +MODULE_PARM_DESC(chg_detection_for_float_charger, + "Whether to do PHY based charger detection for float chargers"); + static struct msm_otg *the_msm_otg; static bool debug_bus_voting_enabled; @@ -2974,10 +2979,20 @@ static void msm_otg_set_vbus_state(int online) set_bit(ID, &motg->inputs); } - if (test_bit(B_SESS_VLD, &motg->inputs) && - get_psy_type(motg) == POWER_SUPPLY_TYPE_UNKNOWN && - !motg->chg_detection) - motg->chg_detection = true; + /* + * Enable PHY based charger detection in 2 cases: + * 1. PMI not capable of doing charger detection and provides VBUS + * notification with UNKNOWN psy type. + * 2. Data lines have been cut off from PMI, in which case it provides + * VBUS notification with FLOAT psy type and we want to do PHY based + * charger detection by setting 'chg_detection_for_float_charger'. + */ + if (test_bit(B_SESS_VLD, &motg->inputs) && !motg->chg_detection) { + if ((get_psy_type(motg) == POWER_SUPPLY_TYPE_UNKNOWN) || + (get_psy_type(motg) == POWER_SUPPLY_TYPE_USB_FLOAT && + chg_detection_for_float_charger)) + motg->chg_detection = true; + } if (motg->chg_detection) queue_delayed_work(motg->otg_wq, &motg->chg_work, 0); -- GitLab From 9513e4e2dba51649404a3666abde0524aa2ae1fa Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Thu, 24 May 2018 11:56:19 +0530 Subject: [PATCH 664/855] usb: gsi: Fix USB CV L1 suspend test case failure in RNDIS composition As a part of Remote wakeup test case, in resume path gsi driver enabling rndis flow control for RNDIS case and starting the transfers. Followed by L1 test case is running and device sending NYET for L1 suspend command and failing the test case. During L1 suspend test case If requests are queued to the Hardware it will not allow the suspend. Added is_flow_ctrl_enable flag to ensure whether flow control enabled by the host with RNDIS_MSG_INIT before. If it is enabled before then only enable it gain from resume path. During CV tests host does not send RNDIS_MSG_INT to enable flow control and test will pass. Change-Id: Ifd567d910d6571ec3ac0c1eef2da1ee06d9c8fd5 Signed-off-by: Chandana Kishori Chiluveru --- drivers/usb/gadget/function/f_gsi.c | 12 +++++++++++- drivers/usb/gadget/function/f_gsi.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index d99092884ea5..d3799e599ad5 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -1681,6 +1681,12 @@ void gsi_rndis_flow_ctrl_enable(bool enable, struct rndis_params *param) } else { log_event_dbg("%s: posting HOST_READY\n", __func__); post_event(d_port, EVT_HOST_READY); + /* + * If host supports flow control with RNDIS_MSG_INIT then + * mark the flag to true. This flag will be used further to + * enable the flow control on resume path. + */ + gsi->host_supports_flow_control = true; } queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); @@ -2450,6 +2456,8 @@ static void gsi_disable(struct usb_function *f) gsi->data_interface_up = false; + gsi->host_supports_flow_control = false; + log_event_dbg("%s deactivated", gsi->function.name); if (is_ext_prot_ether(gsi->prot_id)) { @@ -2515,10 +2523,12 @@ static void gsi_resume(struct usb_function *f) /* * Linux host does not send RNDIS_MSG_INIT or non-zero * RNDIS_MESSAGE_PACKET_FILTER after performing bus resume. + * Check whether host supports flow_control are not. If yes * Trigger state machine explicitly on resume. */ if (gsi->prot_id == USB_PROT_RNDIS_IPA && - !usb_gsi_remote_wakeup_allowed(f)) + !usb_gsi_remote_wakeup_allowed(f) && + gsi->host_supports_flow_control) rndis_flow_control(gsi->params, false); post_event(&gsi->d_port, EVT_RESUMED); diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index 036b304501c4..cd146a02d07f 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -282,6 +282,7 @@ struct f_gsi { struct timer_list debugfs_rw_timer; u8 debugfs_rw_enable; u16 debugfs_rw_interval; + bool host_supports_flow_control; }; static inline struct f_gsi *func_to_gsi(struct usb_function *f) -- GitLab From 9a477737eae2046214c7da2e25d259db5085b097 Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Fri, 1 Jun 2018 16:00:01 +0530 Subject: [PATCH 665/855] extcon: usb-gpio: Queue detectable workqueue on resume Upon resume/restore queue detectable work irrespective of the device wakeup capability. This ensures that during pm_restore the dwc3-msm driver is notified correctly of the GPIO states before restore. Change-Id: Iff955de39d83f3fb55537eeaf65ea8eb014c5513 Signed-off-by: Sriharsha Allenki --- drivers/extcon/extcon-usb-gpio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index 2e093c3b4104..2b108fa40719 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -277,9 +277,8 @@ static int usb_extcon_resume(struct device *dev) if (info->vbus_gpiod) enable_irq(info->vbus_irq); - if (!device_may_wakeup(dev)) - queue_delayed_work(system_power_efficient_wq, - &info->wq_detcable, 0); + queue_delayed_work(system_power_efficient_wq, + &info->wq_detcable, 0); return ret; } -- GitLab From 8129f16f28ef3092e9aea64986706ce3e7bd9caa Mon Sep 17 00:00:00 2001 From: ramandeep trehan Date: Fri, 1 Jun 2018 16:53:50 +0530 Subject: [PATCH 666/855] msm8953: Enable config flag for File based Encryption File system flags for ext4 are required for HW based file encryption to work smoothly. Change-Id: I5617532bacf9a4f9fe947bb2fb77e3ec7d145026 Signed-off-by: ramandeep trehan --- arch/arm/configs/msm8953-perf_defconfig | 5 ++++- arch/arm/configs/msm8953_defconfig | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index 88e5e228444f..06e5360bfd87 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -595,6 +595,9 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y @@ -625,13 +628,13 @@ CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_CTI=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_HWEVENT=y +CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y -CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index adee9a59c051..07fc5b9d2961 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -611,6 +611,9 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y @@ -684,13 +687,13 @@ CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_CTI=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_HWEVENT=y +CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y -CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y -- GitLab From a3f2a0744704fab353e65c5c8ce8b48b82fea3b5 Mon Sep 17 00:00:00 2001 From: Santosh Mardi Date: Mon, 28 May 2018 12:57:17 +0530 Subject: [PATCH 667/855] defconfig: enable ondemand governor for sdxpoorwills Enable ondemand governor to scale cpu frequency based on the demand for sdxpoorwills target. Change-Id: Ie912d20606a64cf24b6f896b81c40ee1e2228bdc Signed-off-by: Santosh Mardi --- arch/arm/configs/sdxpoorwills-perf_defconfig | 2 ++ arch/arm/configs/sdxpoorwills_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig index 0e971d2df2f6..bab605911efd 100644 --- a/arch/arm/configs/sdxpoorwills-perf_defconfig +++ b/arch/arm/configs/sdxpoorwills-perf_defconfig @@ -32,7 +32,9 @@ CONFIG_AEABI=y CONFIG_CMA=y CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_BOOST=y CONFIG_CPU_FREQ_MSM=y CONFIG_CPU_IDLE=y CONFIG_VFP=y diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig index 52f3fdaad803..1ea6ba81f31a 100644 --- a/arch/arm/configs/sdxpoorwills_defconfig +++ b/arch/arm/configs/sdxpoorwills_defconfig @@ -34,7 +34,9 @@ CONFIG_AEABI=y CONFIG_CMA=y CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_BOOST=y CONFIG_CPU_FREQ_MSM=y CONFIG_CPU_IDLE=y CONFIG_VFP=y -- GitLab From 95f01410674a847bdc15867b82f95ccbabed9172 Mon Sep 17 00:00:00 2001 From: Santhosh Behara Date: Wed, 30 May 2018 17:12:50 +0530 Subject: [PATCH 668/855] msm: vidc: Limit HEIF encode changes to Encode path Limit calling get_hal_codec() only in Encoding usecase. Otherwise, it leads to error log in video decode usecase. CRs-Fixed: 2248840 Change-Id: I25425423a9d5f36584c4ef00e0dedb124aaf941a Signed-off-by: Santhosh Behara --- drivers/media/platform/msm/vidc/msm_vidc_common.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index f9bc79c87790..40c986211218 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -2406,8 +2406,9 @@ static void handle_ebd(enum hal_command_response cmd, void *data) } empty_buf_done = (struct vidc_hal_ebd *)&response->input_done; - if ((get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) == - HAL_VIDEO_CODEC_HEVC) && + if (inst->session_type == MSM_VIDC_ENCODER && + (get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) == + HAL_VIDEO_CODEC_HEVC) && (inst->img_grid_dimension > 0) && (empty_buf_done->input_tag < inst->tinfo.count - 1)) { dprintk(VIDC_DBG, "Wait for last tile. Current tile no: %d\n", @@ -4424,8 +4425,9 @@ int msm_comm_qbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf) for (c = 0; c < etbs.count; ++c) { struct vidc_frame_data *frame_data = &etbs.data[c]; - if (get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) == - HAL_VIDEO_CODEC_HEVC && + if (inst->session_type == MSM_VIDC_ENCODER && + get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) + == HAL_VIDEO_CODEC_HEVC && (inst->img_grid_dimension > 0)) { rc = msm_comm_qbuf_heic_tiles(inst, frame_data); if (rc) { -- GitLab From bc064dc94d51d05317bf90b00fbe6b3abba3c643 Mon Sep 17 00:00:00 2001 From: FMenziesENG Date: Thu, 31 May 2018 16:33:44 +0800 Subject: [PATCH 669/855] drivers:input:vl53l0x add some calibration interface of vl53l0x This change add STM vl53l0x sensor calibration test attribute for APQ8009 Robotics. VL53L0X is a ranging and gesture detection sensor through i2c in 400kb/s. Icm20602 driver can push the data to userspace by sysfs which is calibrate by the driver application. From: FMenziesENG Signed-off-by: FMenziesENG Signed-off-by: xuji Git-Commit: c0dbf64cfb95d5dbfa6e136e48dafd66b785354e Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git [chaojun@codeaurora.org: Add API to userspace through sysfs] Change-Id: I2e9afa07b22f9c9a9e1408859566a6312e2c8714 Signed-off-by: Chaojun Wang --- drivers/input/misc/vl53l0x/stmvl53l0x.h | 5 + .../input/misc/vl53l0x/stmvl53l0x_module.c | 134 +++++++++++++++++- 2 files changed, 136 insertions(+), 3 deletions(-) diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x.h b/drivers/input/misc/vl53l0x/stmvl53l0x.h index 1f15278d5418..1be251f5a38a 100644 --- a/drivers/input/misc/vl53l0x/stmvl53l0x.h +++ b/drivers/input/misc/vl53l0x/stmvl53l0x.h @@ -34,6 +34,7 @@ /* #define INT_POLLING_DELAY 20 */ /* if don't want to have output from dbg, comment out #DEBUG macro */ +#define DEBUG #ifdef DEBUG #define dbg(fmt, ...) \ printk(fmt, ##__VA_ARGS__) @@ -51,6 +52,8 @@ enum init_mode_e { NORMAL_MODE = 0, OFFSETCALIB_MODE = 1, XTALKCALIB_MODE = 2, + SPADCALIB_MODE = 3, + REFCALIB_MODE = 4, }; enum parameter_name_e { @@ -167,6 +170,8 @@ struct vl_data { /* Debug */ unsigned int enableDebug; uint8_t interrupt_received; + int32_t default_offset_calibration; + unsigned int default_xtalk_Compensation; }; /* diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c index ece245f24111..78ca6373554a 100644 --- a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c +++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c @@ -1026,6 +1026,107 @@ static DEVICE_ATTR(offset_cal, 0660/*S_IWUGO | S_IRUGO*/, stmvl53l0x_show_offset, stmvl53l0x_set_offset); +static ssize_t stmvl53l0x_set_spad(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) + +{ + struct vl_data *data = dev_get_drvdata(dev); + + stmvl53l0x_start(data, 3, SPADCALIB_MODE); + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(spad_cal, 0660/*S_IWUGO | S_IRUGO*/, + NULL, + stmvl53l0x_set_spad); + +static ssize_t stmvl53l0x_set_ref(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + + stmvl53l0x_start(data, 3, REFCALIB_MODE); + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(ref_cal, 0660/*S_IWUGO | S_IRUGO*/, + NULL, + stmvl53l0x_set_ref); + + +static ssize_t stmvl53l0x_show_OffsetCalibrationData(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + int32_t offset_calibration_data; + + papi_func_tbl->GetOffsetCalibrationDataMicroMeter(data, + &offset_calibration_data); + dbg("GetOffsetCalibrationDataMicroMeter = %ld\n", + offset_calibration_data); + return snprintf(buf, 2, "%ld\n", + offset_calibration_data); +} + +static ssize_t stmvl53l0x_set_OffsetCalibrationData(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + int32_t offset_calibration_data; + + kstrtoint(buf, 10, &offset_calibration_data); + papi_func_tbl->SetOffsetCalibrationDataMicroMeter(data, + offset_calibration_data); + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(set_offsetdata, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_OffsetCalibrationData, + stmvl53l0x_set_OffsetCalibrationData); + +static ssize_t stmvl53l0x_show_XTalkCompensationRateMegaCps(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + int32_t xtalk_compensation_rate; + + papi_func_tbl->GetXTalkCompensationRateMegaCps(data, + &xtalk_compensation_rate); + dbg("xtalk_compensation_rate = %ld\n", + xtalk_compensation_rate); + return snprintf(buf, 2, "%ld\n", xtalk_compensation_rate); + +} + +static ssize_t stmvl53l0x_set_XTalkCompensationRateMegaCps(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + unsigned int xtalk_compensation_rate; + + kstrtoint(buf, 10, &xtalk_compensation_rate); + papi_func_tbl->SetXTalkCompensationRateMegaCps(data, + xtalk_compensation_rate); + return count; + +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(set_xtalkdata, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_XTalkCompensationRateMegaCps, + stmvl53l0x_set_XTalkCompensationRateMegaCps); + + + static struct attribute *stmvl53l0x_attributes[] = { &dev_attr_enable_ps_sensor.attr, &dev_attr_enable_debug.attr, @@ -1035,6 +1136,10 @@ static struct attribute *stmvl53l0x_attributes[] = { &dev_attr_show_meter.attr, &dev_attr_xtalk_cal.attr, &dev_attr_offset_cal.attr, + &dev_attr_spad_cal.attr, + &dev_attr_ref_cal.attr, + &dev_attr_set_offsetdata.attr, + &dev_attr_set_xtalkdata.attr, NULL, }; @@ -1568,13 +1673,36 @@ static int stmvl53l0x_start(struct vl_data *data, uint8_t scaling, dbg("Offset calibration:%u\n", OffsetMicroMeter); return rc; } else if (mode == XTALKCALIB_MODE) { - unsigned int XTalkCompensationRateMegaCps; + unsigned int xtalk_compensation_rate_mega_cps; /*caltarget distance : 100mm and convert to */ /* fixed point 16 16 format */ papi_func_tbl->PerformXTalkCalibration(vl53l0x_dev, (data->xtalkCalDistance<<16), - &XTalkCompensationRateMegaCps); - dbg("Xtalk calibration:%u\n", XTalkCompensationRateMegaCps); + &xtalk_compensation_rate_mega_cps); + dbg("Xtalk calibration:%u\n", xtalk_compensation_rate_mega_cps); + return rc; + } else if (mode == SPADCALIB_MODE) { + uint32_t ref_spad_count; + uint8_t is_aperture_spads; + + papi_func_tbl->PerformRefSpadManagement( + vl53l0x_dev, + &ref_spad_count, + &is_aperture_spads); + dbg("SPAD calibration:%lu,%u\n", ref_spad_count, + (unsigned int)is_aperture_spads); + return rc; + } else if (mode == REFCALIB_MODE) { + uint8_t vhv_settings; + uint8_t phase_cal; + + papi_func_tbl->PerformRefCalibration( + vl53l0x_dev, + &vhv_settings, + &phase_cal); + dbg("Ref calibration:%u,%u\n", + (unsigned int)vhv_settings, + (unsigned int)phase_cal); return rc; } /* set up device parameters */ -- GitLab From ba331c807feb542bf15adebeae83d7a7bf97438c Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Sun, 3 Jun 2018 13:20:00 +0300 Subject: [PATCH 670/855] msm: ipa3: Fix some of IPA register names Fix some of IPA register names to match the H/W register names definitions. Change-Id: I8d85fa7b406b0898b18d7083b9a23abbb9d95ce2 Signed-off-by: Ghanim Fodi --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 14 ++++++------- .../msm/ipa/ipa_v3/ipahal/ipahal_reg.c | 20 ++++++++----------- .../msm/ipa/ipa_v3/ipahal/ipahal_reg.h | 9 ++++----- 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 61c81cdee037..554023ebfc60 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -5417,7 +5417,7 @@ static void ipa_gsi_setup_reg(void) * Before configuring the FIFOs need to unset bit 30 in the * spare register */ - ipahal_write_reg(IPA_SPARE_REG_1_OFST, + ipahal_write_reg(IPA_SPARE_REG_1, (IPA_SPARE_REG_1_VAL & (~(1 << 30)))); /* setup IPA_ENDP_GSI_CFG_TLV_n reg */ @@ -5434,7 +5434,7 @@ static void ipa_gsi_setup_reg(void) IPADBG("Config is true"); reg_val = (gsi_ep_info_cfg->ipa_if_tlv << 16) + start; start += gsi_ep_info_cfg->ipa_if_tlv; - ipahal_write_reg_n(IPA_ENDP_GSI_CFG_TLV_OFST_n, i, reg_val); + ipahal_write_reg_n(IPA_ENDP_GSI_CFG_TLV_n, i, reg_val); } /* setup IPA_ENDP_GSI_CFG_AOS_n reg */ @@ -5446,7 +5446,7 @@ static void ipa_gsi_setup_reg(void) continue; reg_val = (gsi_ep_info_cfg->ipa_if_aos << 16) + start; start += gsi_ep_info_cfg->ipa_if_aos; - ipahal_write_reg_n(IPA_ENDP_GSI_CFG_AOS_OFST_n, i, reg_val); + ipahal_write_reg_n(IPA_ENDP_GSI_CFG_AOS_n, i, reg_val); } /* setup IPA_ENDP_GSI_CFG1_n reg */ @@ -5458,7 +5458,7 @@ static void ipa_gsi_setup_reg(void) reg_val = (1 << 16) + ((u32)gsi_ep_info_cfg->ipa_gsi_chan_num << 8) + gsi_ep_info_cfg->ee; - ipahal_write_reg_n(IPA_ENDP_GSI_CFG1_OFST_n, i, reg_val); + ipahal_write_reg_n(IPA_ENDP_GSI_CFG1_n, i, reg_val); } /* @@ -5471,16 +5471,16 @@ static void ipa_gsi_setup_reg(void) if (!gsi_ep_info_cfg) continue; reg_val = 1 << 31; - ipahal_write_reg_n(IPA_ENDP_GSI_CFG2_OFST_n, i, reg_val); + ipahal_write_reg_n(IPA_ENDP_GSI_CFG2_n, i, reg_val); reg_val = 0; - ipahal_write_reg_n(IPA_ENDP_GSI_CFG2_OFST_n, i, reg_val); + ipahal_write_reg_n(IPA_ENDP_GSI_CFG2_n, i, reg_val); } /* * After configuring the FIFOs need to set bit 30 in the spare * register */ - ipahal_write_reg(IPA_SPARE_REG_1_OFST, + ipahal_write_reg(IPA_SPARE_REG_1, (IPA_SPARE_REG_1_VAL | (1 << 30))); } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c index 38132d294bbe..cc70ac1d955c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c @@ -134,11 +134,10 @@ static const char *ipareg_name_to_str[IPA_REG_MAX] = { __stringify(IPA_MBIM_DEAGGR_FEC_ATTR_EE_n), __stringify(IPA_GEN_DEAGGR_FEC_ATTR_EE_n), __stringify(IPA_GSI_CONF), - __stringify(IPA_ENDP_GSI_CFG1_OFST_n), - __stringify(IPA_ENDP_GSI_CFG2_OFST_n), - __stringify(IPA_ENDP_GSI_CFG_AOS_OFST_n), - __stringify(IPA_ENDP_GSI_CFG_TLV_OFST_n), - __stringify(IPA_SPARE_REG_1_OFST), + __stringify(IPA_ENDP_GSI_CFG1_n), + __stringify(IPA_ENDP_GSI_CFG2_n), + __stringify(IPA_ENDP_GSI_CFG_AOS_n), + __stringify(IPA_ENDP_GSI_CFG_TLV_n), }; static void ipareg_construct_dummy(enum ipahal_reg_name reg, @@ -1980,21 +1979,18 @@ static struct ipahal_reg_obj ipahal_reg_objs[IPA_HW_MAX][IPA_REG_MAX] = { [IPA_HW_v3_5][IPA_GSI_CONF] = { ipareg_construct_dummy, ipareg_parse_dummy, 0x00002790, 0x0, 0, 0, 0 }, - [IPA_HW_v3_5][IPA_ENDP_GSI_CFG1_OFST_n] = { + [IPA_HW_v3_5][IPA_ENDP_GSI_CFG1_n] = { ipareg_construct_dummy, ipareg_parse_dummy, 0x00002794, 0x4, 0, 0, 0 }, - [IPA_HW_v3_5][IPA_ENDP_GSI_CFG2_OFST_n] = { + [IPA_HW_v3_5][IPA_ENDP_GSI_CFG2_n] = { ipareg_construct_dummy, ipareg_parse_dummy, 0x00002A2C, 0x4, 0, 0, 0 }, - [IPA_HW_v3_5][IPA_ENDP_GSI_CFG_AOS_OFST_n] = { + [IPA_HW_v3_5][IPA_ENDP_GSI_CFG_AOS_n] = { ipareg_construct_dummy, ipareg_parse_dummy, 0x000029A8, 0x4, 0, 0, 0 }, - [IPA_HW_v3_5][IPA_ENDP_GSI_CFG_TLV_OFST_n] = { + [IPA_HW_v3_5][IPA_ENDP_GSI_CFG_TLV_n] = { ipareg_construct_dummy, ipareg_parse_dummy, 0x00002924, 0x4, 0, 0, 0 }, - [IPA_HW_v3_5][IPA_SPARE_REG_1_OFST] = { - ipareg_construct_dummy, ipareg_parse_dummy, - 0x00002780, 0x0, 0, 0, 0 }, /* IPAv4.0 */ [IPA_HW_v4_0][IPA_IRQ_SUSPEND_INFO_EE_n] = { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h index da5bbbfc62ef..ea741ba88e5d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h @@ -135,11 +135,10 @@ enum ipahal_reg_name { IPA_MBIM_DEAGGR_FEC_ATTR_EE_n, IPA_GEN_DEAGGR_FEC_ATTR_EE_n, IPA_GSI_CONF, - IPA_ENDP_GSI_CFG1_OFST_n, - IPA_ENDP_GSI_CFG2_OFST_n, - IPA_ENDP_GSI_CFG_AOS_OFST_n, - IPA_ENDP_GSI_CFG_TLV_OFST_n, - IPA_SPARE_REG_1_OFST, + IPA_ENDP_GSI_CFG1_n, + IPA_ENDP_GSI_CFG2_n, + IPA_ENDP_GSI_CFG_AOS_n, + IPA_ENDP_GSI_CFG_TLV_n, IPA_REG_MAX, }; -- GitLab From c450f9bebbe4aa4f7c71564ee8350355999cca3b Mon Sep 17 00:00:00 2001 From: Liangliang Lu Date: Sun, 3 Jun 2018 20:25:03 +0800 Subject: [PATCH 671/855] usb: gadget: f_rndis: Add 'wceis' flag to indicate 'Wireless' RNDIS The 'wceis' flag used to indicate the device as wireless controller. Set the default value is true as this is what we want in most of the cases. Change-Id: Idc03717526350421d94b9445333b36823a372aad Signed-off-by: Liangliang Lu --- drivers/usb/gadget/function/f_rndis.c | 28 +++++++++++ .../usb/gadget/function/u_ether_configfs.h | 46 +++++++++++++++++++ drivers/usb/gadget/function/u_rndis.h | 3 ++ 3 files changed, 77 insertions(+) diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index 814b4a3e4a5e..a75e5d346cfb 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -818,6 +818,27 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_data_intf.bInterfaceNumber = status; rndis_union_desc.bSlaveInterface0 = status; + if (rndis_opts->wceis) { + /* "Wireless" RNDIS; auto-detected by Windows */ + rndis_iad_descriptor.bFunctionClass = + USB_CLASS_WIRELESS_CONTROLLER; + rndis_iad_descriptor.bFunctionSubClass = 0x01; + rndis_iad_descriptor.bFunctionProtocol = 0x03; + rndis_control_intf.bInterfaceClass = + USB_CLASS_WIRELESS_CONTROLLER; + rndis_control_intf.bInterfaceSubClass = 0x01; + rndis_control_intf.bInterfaceProtocol = 0x03; + } else { + rndis_iad_descriptor.bFunctionClass = USB_CLASS_COMM; + rndis_iad_descriptor.bFunctionSubClass = + USB_CDC_SUBCLASS_ETHERNET; + rndis_iad_descriptor.bFunctionProtocol = USB_CDC_PROTO_NONE; + rndis_control_intf.bInterfaceClass = USB_CLASS_COMM; + rndis_control_intf.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM; + rndis_control_intf.bInterfaceProtocol = + USB_CDC_ACM_PROTO_VENDOR; + } + status = -ENODEV; /* allocate instance-specific endpoints */ @@ -950,11 +971,15 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(rndis); /* f_rndis_opts_ifname */ USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(rndis); +/* f_rndis_opts_wceis */ +USB_ETHERNET_CONFIGFS_ITEM_ATTR_WCEIS(rndis); + static struct configfs_attribute *rndis_attrs[] = { &rndis_opts_attr_dev_addr, &rndis_opts_attr_host_addr, &rndis_opts_attr_qmult, &rndis_opts_attr_ifname, + &rndis_opts_attr_wceis, NULL, }; @@ -1008,6 +1033,9 @@ static struct usb_function_instance *rndis_alloc_inst(void) } opts->rndis_interf_group = rndis_interf_group; + /* Enable "Wireless" RNDIS by default */ + opts->wceis = true; + return &opts->func_inst; } diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index 0468459a5c0f..1dd2ff41eb87 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -188,4 +188,50 @@ out: \ \ CONFIGFS_ATTR_RO(_f_##_opts_, ifname) +#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_WCEIS(_f_) \ + static ssize_t _f_##_opts_wceis_show(struct config_item *item, \ + char *page) \ + { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ + bool wceis; \ + \ + if (opts->bound == false) { \ + pr_err("Gadget function do not bind yet.\n"); \ + return -ENODEV; \ + } \ + \ + mutex_lock(&opts->lock); \ + wceis = opts->wceis; \ + mutex_unlock(&opts->lock); \ + return snprintf(page, PAGE_SIZE, "%d", wceis); \ + } \ + \ + static ssize_t _f_##_opts_wceis_store(struct config_item *item, \ + const char *page, size_t len)\ + { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ + bool wceis; \ + int ret; \ + \ + if (opts->bound == false) { \ + pr_err("Gadget function do not bind yet.\n"); \ + return -ENODEV; \ + } \ + \ + mutex_lock(&opts->lock); \ + \ + ret = kstrtobool(page, &wceis); \ + if (ret) \ + goto out; \ + \ + opts->wceis = wceis; \ + ret = len; \ +out: \ + mutex_unlock(&opts->lock); \ + \ + return ret; \ + } \ + \ + CONFIGFS_ATTR(_f_##_opts_, wceis) + #endif /* __U_ETHER_CONFIGFS_H */ diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h index 4e2ad04fe8d6..f829a5e00766 100644 --- a/drivers/usb/gadget/function/u_rndis.h +++ b/drivers/usb/gadget/function/u_rndis.h @@ -38,6 +38,9 @@ struct f_rndis_opts { */ struct mutex lock; int refcnt; + + /* "Wireless" RNDIS; auto-detected by Windows */ + bool wceis; }; void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net); -- GitLab From 2b6cd28773e9d189878252867bdf5d4c23fe40d3 Mon Sep 17 00:00:00 2001 From: Teng Fei Fan Date: Fri, 18 May 2018 18:10:01 +0800 Subject: [PATCH 672/855] ARM: dts: msm: move general DT entry to separate qrd sku dtsi files General configs can be include by different qrd overlay and non-overlay dts files. So added common dtsi file for sku1 and sku2 dtsi and move general configs into those common dtsi files. Change-Id: I04b486b576f58571de3ba76644314f08b68364e9 Signed-off-by: Teng Fei Fan --- .../dts/qcom/sdm670-camera-sensor-qrd.dtsi | 2 ++ .../boot/dts/qcom/sdm670-pmic-overlay.dtsi | 2 ++ .../boot/dts/qcom/sdm670-qrd-overlay.dts | 4 +-- arch/arm64/boot/dts/qcom/sdm670-qrd-sku1.dtsi | 14 ++++++++ .../boot/dts/qcom/sdm670-qrd-sku2-overlay.dts | 27 +--------------- arch/arm64/boot/dts/qcom/sdm670-qrd-sku2.dts | 23 ++----------- arch/arm64/boot/dts/qcom/sdm670-qrd-sku2.dtsi | 32 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm670-qrd.dts | 4 +-- arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi | 2 +- .../boot/dts/qcom/sdm710-qrd-overlay.dts | 8 +---- .../boot/dts/qcom/sdm710-qrd-sku2-overlay.dts | 27 +--------------- arch/arm64/boot/dts/qcom/sdm710-qrd-sku2.dts | 21 +----------- arch/arm64/boot/dts/qcom/sdm710-qrd.dts | 1 + 13 files changed, 62 insertions(+), 105 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/sdm670-qrd-sku1.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm670-qrd-sku2.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi index c8f7ac0da7d5..78047bd22f9e 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#include + &soc { led_flash_rear: qcom,camera-flash@0 { cell-index = <0>; diff --git a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi index 27be1fdf17fc..f63d442ce3b8 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi @@ -10,6 +10,8 @@ * GNU General Public License for more details. */ +#include + &pm660_0{ pm660_charger: qcom,qpnp-smb2 { compatible = "qcom,qpnp-smb2"; diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-qrd-overlay.dts index 36d485eb973d..67b5ebeeba51 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm670-qrd-overlay.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,7 +19,7 @@ #include #include -#include "sdm670-qrd.dtsi" +#include "sdm670-qrd-sku1.dtsi" / { model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L QRD"; diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd-sku1.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qrd-sku1.dtsi new file mode 100644 index 000000000000..2c1cde694122 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-qrd-sku1.dtsi @@ -0,0 +1,14 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sdm670-qrd.dtsi" +#include "sdm670-audio-overlay.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2-overlay.dts index 73d19094b6ca..d5edb36d071a 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2-overlay.dts @@ -13,13 +13,7 @@ /dts-v1/; /plugin/; -#include -#include -#include -#include -#include - -#include "sdm670-qrd.dtsi" +#include "sdm670-qrd-sku2.dtsi" / { model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L QRD SKU2"; @@ -30,22 +24,3 @@ <0x0001001b 0x0102001a 0x0 0x0>, <0x0001001b 0x0201011a 0x0 0x0>; }; - -&dsi_dual_nt36850_truly_cmd_display { - /delete-property/ qcom,dsi-display-active; -}; - -&dsi_hx8399_truly_cmd { - qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <4095>; - qcom,panel-mode-gpio = <&tlmm 76 0>; - qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; - qcom,platform-reset-gpio = <&tlmm 75 0>; - qcom,platform-te-gpio = <&tlmm 10 0>; -}; - -&dsi_hx8399_truly_cmd_display { - qcom,dsi-display-active; -}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2.dts b/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2.dts index 680bc17ccbaa..9f871c5dd0b6 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2.dts +++ b/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,7 +14,7 @@ /dts-v1/; #include "sdm670.dtsi" -#include "sdm670-qrd.dtsi" +#include "sdm670-qrd-sku2.dtsi" / { model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L QRD SKU2"; @@ -24,22 +24,3 @@ <0x0001001b 0x0102001a 0x0 0x0>, <0x0001001b 0x0201011a 0x0 0x0>; }; - -&dsi_dual_nt36850_truly_cmd_display { - /delete-property/ qcom,dsi-display-active; -}; - -&dsi_hx8399_truly_cmd { - qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <4095>; - qcom,panel-mode-gpio = <&tlmm 76 0>; - qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; - qcom,platform-reset-gpio = <&tlmm 75 0>; - qcom,platform-te-gpio = <&tlmm 10 0>; -}; - -&dsi_hx8399_truly_cmd_display { - qcom,dsi-display-active; -}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2.dtsi new file mode 100644 index 000000000000..cdb652e8c05d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2.dtsi @@ -0,0 +1,32 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "sdm670-qrd.dtsi" +#include "sdm670-audio-overlay.dtsi" + +&dsi_dual_nt36850_truly_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_hx8399_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_hx8399_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd.dts b/arch/arm64/boot/dts/qcom/sdm670-qrd.dts index c22afa42c201..318939fae89e 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sdm670-qrd.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,7 +14,7 @@ /dts-v1/; #include "sdm670.dtsi" -#include "sdm670-qrd.dtsi" +#include "sdm670-qrd-sku1.dtsi" / { model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L QRD"; diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi index 3b8b375ba006..5ff2c3260735 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi @@ -10,10 +10,10 @@ * GNU General Public License for more details. */ +#include #include #include "sdm670-camera-sensor-qrd.dtsi" #include "sdm670-pmic-overlay.dtsi" -#include "sdm670-audio-overlay.dtsi" #include "sdm670-sde-display.dtsi" &qupv3_se10_i2c { diff --git a/arch/arm64/boot/dts/qcom/sdm710-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm710-qrd-overlay.dts index 803616da696f..08c343353ba6 100644 --- a/arch/arm64/boot/dts/qcom/sdm710-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm710-qrd-overlay.dts @@ -13,13 +13,7 @@ /dts-v1/; /plugin/; -#include -#include -#include -#include -#include - -#include "sdm670-qrd.dtsi" +#include "sdm670-qrd-sku1.dtsi" / { model = "Qualcomm Technologies, Inc. SDM710 PM660 + PM660L QRD"; diff --git a/arch/arm64/boot/dts/qcom/sdm710-qrd-sku2-overlay.dts b/arch/arm64/boot/dts/qcom/sdm710-qrd-sku2-overlay.dts index ab3ce4ddb404..91891ba8c392 100644 --- a/arch/arm64/boot/dts/qcom/sdm710-qrd-sku2-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm710-qrd-sku2-overlay.dts @@ -13,13 +13,7 @@ /dts-v1/; /plugin/; -#include -#include -#include -#include -#include - -#include "sdm670-qrd.dtsi" +#include "sdm670-qrd-sku2.dtsi" / { model = "Qualcomm Technologies, Inc. SDM710 PM660 + PM660L QRD SKU2"; @@ -30,22 +24,3 @@ <0x0001001b 0x0102001a 0x0 0x0>, <0x0001001b 0x0201011a 0x0 0x0>; }; - -&dsi_dual_nt36850_truly_cmd_display { - /delete-property/ qcom,dsi-display-active; -}; - -&dsi_hx8399_truly_cmd { - qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <4095>; - qcom,panel-mode-gpio = <&tlmm 76 0>; - qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; - qcom,platform-reset-gpio = <&tlmm 75 0>; - qcom,platform-te-gpio = <&tlmm 10 0>; -}; - -&dsi_hx8399_truly_cmd_display { - qcom,dsi-display-active; -}; diff --git a/arch/arm64/boot/dts/qcom/sdm710-qrd-sku2.dts b/arch/arm64/boot/dts/qcom/sdm710-qrd-sku2.dts index 76b2862eba86..f674893eb7c5 100644 --- a/arch/arm64/boot/dts/qcom/sdm710-qrd-sku2.dts +++ b/arch/arm64/boot/dts/qcom/sdm710-qrd-sku2.dts @@ -14,7 +14,7 @@ /dts-v1/; #include "sdm710.dtsi" -#include "sdm670-qrd.dtsi" +#include "sdm670-qrd-sku2.dtsi" / { model = "Qualcomm Technologies, Inc. SDM710 PM660 + PM660L QRD SKU2"; @@ -24,22 +24,3 @@ <0x0001001b 0x0102001a 0x0 0x0>, <0x0001001b 0x0201011a 0x0 0x0>; }; - -&dsi_dual_nt36850_truly_cmd_display { - /delete-property/ qcom,dsi-display-active; -}; - -&dsi_hx8399_truly_cmd { - qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <4095>; - qcom,panel-mode-gpio = <&tlmm 76 0>; - qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; - qcom,platform-reset-gpio = <&tlmm 75 0>; - qcom,platform-te-gpio = <&tlmm 10 0>; -}; - -&dsi_hx8399_truly_cmd_display { - qcom,dsi-display-active; -}; diff --git a/arch/arm64/boot/dts/qcom/sdm710-qrd.dts b/arch/arm64/boot/dts/qcom/sdm710-qrd.dts index e3cb7cc82d4b..4eb414fa835c 100644 --- a/arch/arm64/boot/dts/qcom/sdm710-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sdm710-qrd.dts @@ -15,6 +15,7 @@ #include "sdm710.dtsi" #include "sdm670-qrd.dtsi" +#include "sdm670-audio-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. SDM710 PM660 + PM660L QRD"; -- GitLab From bc333fe6ac54fe39048f587df874b9371add4893 Mon Sep 17 00:00:00 2001 From: Teng Fei Fan Date: Fri, 18 May 2018 18:11:12 +0800 Subject: [PATCH 673/855] ARM: dts: msm: add sda670 hdk DT file Add sda670 hdk DT file to support new sda670 hdk device. Change-Id: I149751eb1c7bb298cca0fea3eb2397620bed3296 Signed-off-by: Teng Fei Fan --- .../devicetree/bindings/arm/msm/msm.txt | 1 + arch/arm64/boot/dts/qcom/Makefile | 3 ++ .../boot/dts/qcom/sda670-hdk-overlay.dts | 23 +++++++++++++ arch/arm64/boot/dts/qcom/sda670-hdk.dts | 24 ++++++++++++++ arch/arm64/boot/dts/qcom/sda670-hdk.dtsi | 32 +++++++++++++++++++ 5 files changed, 83 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sda670-hdk-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sda670-hdk.dts create mode 100644 arch/arm64/boot/dts/qcom/sda670-hdk.dtsi diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 9c2d64729ef3..9df16fb49443 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -326,6 +326,7 @@ compatible = "qcom,qcs605-cdp" compatible = "qcom,qcs605-mtp" compatible = "qcom,sda670-cdp" compatible = "qcom,sda670-mtp" +compatible = "qcom,sda670-hdk" compatible = "qcom,msm8952-rumi" compatible = "qcom,msm8952-sim" compatible = "qcom,msm8952-qrd" diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 4db459a3ad29..f9bc8e3596f8 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -135,6 +135,7 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sdm670-usbc-external-codec-pm660a-mtp-overlay.dtbo \ sda670-cdp-overlay.dtbo \ sda670-mtp-overlay.dtbo \ + sda670-hdk-overlay.dtbo \ sda670-pm660a-cdp-overlay.dtbo \ sda670-pm660a-mtp-overlay.dtbo \ sdm670-tasha-codec-cdp-overlay.dtbo \ @@ -194,6 +195,7 @@ sdm670-aqt1000-cdp-overlay.dtbo-base := sdm670.dtb sdm670-pm660a-aqt1000-cdp-overlay.dtbo-base := sdm670.dtb sda670-cdp-overlay.dtbo-base := sda670.dtb sda670-mtp-overlay.dtbo-base := sda670.dtb +sda670-hdk-overlay.dtbo-base := sda670.dtb sda670-pm660a-cdp-overlay.dtbo-base := sda670.dtb sda670-pm660a-mtp-overlay.dtbo-base := sda670.dtb qcs605-cdp-overlay.dtbo-base := qcs605.dtb @@ -245,6 +247,7 @@ dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \ sdm670-usbc-pm660a-cdp.dtb \ sdm670-usbc-pm660a-mtp.dtb \ sda670-mtp.dtb \ + sda670-hdk.dtb \ sda670-cdp.dtb \ sdm670-tasha-codec-cdp.dtb \ sdm670-pm660a-tasha-codec-cdp.dtb \ diff --git a/arch/arm64/boot/dts/qcom/sda670-hdk-overlay.dts b/arch/arm64/boot/dts/qcom/sda670-hdk-overlay.dts new file mode 100644 index 000000000000..a7299a4c6820 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670-hdk-overlay.dts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include "sda670-hdk.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA670 HDK"; + compatible = "qcom,sda670-hdk", "qcom,sda670", "qcom,hdk"; + qcom,board-id = <0x01001F 0x00>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda670-hdk.dts b/arch/arm64/boot/dts/qcom/sda670-hdk.dts new file mode 100644 index 000000000000..ed9eec905496 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670-hdk.dts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sda670.dtsi" +#include "sda670-hdk.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA670 HDK"; + compatible = "qcom,sda670-hdk", "qcom,sda670", "qcom,hdk"; + qcom,board-id = <0x01001F 0x00>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi b/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi new file mode 100644 index 000000000000..4daf8b4edd9a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi @@ -0,0 +1,32 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "sdm670-qrd.dtsi" +#include "sdm670-external-codec.dtsi" + +&dsi_dual_nt36850_truly_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_hx8399_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_hx8399_truly_cmd_display { + qcom,dsi-display-active; +}; -- GitLab From 50c1d57347d1c8f6007e1b515b2ea19210c9dbea Mon Sep 17 00:00:00 2001 From: blong Date: Tue, 29 May 2018 09:39:45 +0800 Subject: [PATCH 674/855] arm64: gettimeofday change for timer rollover condition Adding a check in gettimeofday api for timer rollover condition.arm64: gettimeofday change for timer rollover condition Change-Id: I50072fd95df1e4805c94e584b716893fad6fe0f7 CRs-Fixed: 1074621 Signed-off-by: Prasad Sodagudi Signed-off-by: Biao long --- arch/arm64/kernel/vdso/gettimeofday.S | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/kernel/vdso/gettimeofday.S b/arch/arm64/kernel/vdso/gettimeofday.S index c39872a7b03c..2bd7426ede32 100644 --- a/arch/arm64/kernel/vdso/gettimeofday.S +++ b/arch/arm64/kernel/vdso/gettimeofday.S @@ -66,7 +66,16 @@ x_tmp .req x8 .macro get_clock_shifted_nsec res, cycle_last, mult /* Read the virtual counter. */ isb +#if IS_ENABLED(CONFIG_MSM_TIMER_LEAP) +#define LEAST_32BITS 0x00000000FFFFFFFF +9999: + mrs x_tmp, cntvct_el0 + and \res, x_tmp, #LEAST_32BITS + eor \res, \res, #LEAST_32BITS + cbz \res, 9999b +#else mrs x_tmp, cntvct_el0 +#endif /* Calculate cycle delta and convert to ns. */ sub \res, x_tmp, \cycle_last /* We can only guarantee 56 bits of precision. */ -- GitLab From 677f03caa2c7c77f155b0ad6d8a2093a7d549417 Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Wed, 30 May 2018 13:39:15 +0530 Subject: [PATCH 675/855] ARM: dts: msm: Enable support for msm8953 ext codec Revert changes done as part of commit ab9743a9feb46 ("ARM: dts: msm: Add overlay support for msm8953 ext codec") to add nodes back in msm8953-ext-codec-mtp.dts Change-Id: Iccf5e50610bca4a9d2cbfdc37fa8fe69190ab0f5 Signed-off-by: Soumya Managoli --- .../boot/dts/qcom/msm8953-ext-codec-mtp.dts | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts index b80583e6907a..e3a5b4a2a1ac 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts +++ b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts @@ -25,3 +25,75 @@ qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; }; +&int_codec { + status = "disabled"; +}; + +&pmic_analog_codec { + status = "disabled"; +}; + +&wsa881x_i2c_f { + status = "disabled"; +}; + +&wsa881x_i2c_45 { + status = "disabled"; +}; + +&cdc_pri_mi2s_gpios { + status = "disabled"; +}; + +&wsa881x_analog_vi_gpio { + status = "disabled"; +}; + +&wsa881x_analog_clk_gpio { + status = "disabled"; +}; + +&wsa881x_analog_reset_gpio { + status = "disabled"; +}; + +&cdc_comp_gpios { + status = "disabled"; +}; + +&slim_msm { + status = "okay"; +}; + +&dai_slim { + status = "okay"; +}; + +&wcd9xxx_intc { + status = "okay"; +}; + +&clock_audio { + status = "okay"; +}; + +&wcd9335 { + status = "okay"; +}; + +&cdc_us_euro_sw { + status = "okay"; +}; + +&cdc_quin_mi2s_gpios { + status = "okay"; +}; + +&wcd_rst_gpio { + status = "okay"; +}; + +&ext_codec { + qcom,model = "msm8953-tasha-snd-card"; + status = "okay"; +}; -- GitLab From 1ccde330ba71d53e4c3c5061a2e89efedac74ca6 Mon Sep 17 00:00:00 2001 From: Teng Fei Fan Date: Fri, 25 May 2018 09:03:50 +0800 Subject: [PATCH 676/855] arm: psci: add psci_cpu_can_disable() function Some devices which support disable cpu0 can not disable cpu0, so add psci_cpu_can_disable() function to make all cpus can disable. Change-Id: Iaed4129abfc1283c6371bc11bbe5ae4e66317280 Signed-off-by: Teng Fei Fan --- arch/arm/kernel/psci_smp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/kernel/psci_smp.c b/arch/arm/kernel/psci_smp.c index 29286fbc211a..8ff6674def78 100644 --- a/arch/arm/kernel/psci_smp.c +++ b/arch/arm/kernel/psci_smp.c @@ -112,6 +112,12 @@ int psci_cpu_kill(unsigned int cpu) return 0; } +static bool psci_cpu_can_disable(unsigned int cpu) +{ + /*Hotplug of any CPU is supported*/ + return true; +} + #endif bool __init psci_smp_available(void) @@ -126,5 +132,6 @@ const struct smp_operations psci_smp_ops __initconst = { .cpu_disable = psci_cpu_disable, .cpu_die = psci_cpu_die, .cpu_kill = psci_cpu_kill, + .cpu_can_disable = psci_cpu_can_disable, #endif }; -- GitLab From 14d6ecf67175ecdda5b07e563b3bd2107a240cc9 Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Fri, 24 Feb 2017 14:56:11 -0800 Subject: [PATCH 677/855] mm: vmscan: scan dirty pages even in laptop mode Patch series "mm: vmscan: fix kswapd writeback regression". We noticed a regression on multiple hadoop workloads when moving from 3.10 to 4.0 and 4.6, which involves kswapd getting tangled up in page writeout, causing direct reclaim herds that also don't make progress. I tracked it down to the thrash avoidance efforts after 3.10 that make the kernel better at keeping use-once cache and use-many cache sorted on the inactive and active list, with more aggressive protection of the active list as long as there is inactive cache. Unfortunately, our workload's use-once cache is mostly from streaming writes. Waiting for writes to avoid potential reloads in the future is not a good tradeoff. These patches do the following: 1. Wake the flushers when kswapd sees a lump of dirty pages. It's possible to be below the dirty background limit and still have cache velocity push them through the LRU. So start a-flushin'. 2. Let kswapd only write pages that have been rotated twice. This makes sure we really tried to get all the clean pages on the inactive list before resorting to horrible LRU-order writeback. 3. Move rotating dirty pages off the inactive list. Instead of churning or waiting on page writeback, we'll go after clean active cache. This might lead to thrashing, but in this state memory demand outstrips IO speed anyway, and reads are faster than writes. Mel backported the series to 4.10-rc5 with one minor conflict and ran a couple of tests on it. Mix of read/write random workload didn't show anything interesting. Write-only database didn't show much difference in performance but there were slight reductions in IO -- probably in the noise. simoop did show big differences although not as big as Mel expected. This is Chris Mason's workload that similate the VM activity of hadoop. Mel won't go through the full details but over the samples measured during an hour it reported 4.10.0-rc5 4.10.0-rc5 vanilla johannes-v1r1 Amean p50-Read 21346531.56 ( 0.00%) 21697513.24 ( -1.64%) Amean p95-Read 24700518.40 ( 0.00%) 25743268.98 ( -4.22%) Amean p99-Read 27959842.13 ( 0.00%) 28963271.11 ( -3.59%) Amean p50-Write 1138.04 ( 0.00%) 989.82 ( 13.02%) Amean p95-Write 1106643.48 ( 0.00%) 12104.00 ( 98.91%) Amean p99-Write 1569213.22 ( 0.00%) 36343.38 ( 97.68%) Amean p50-Allocation 85159.82 ( 0.00%) 79120.70 ( 7.09%) Amean p95-Allocation 204222.58 ( 0.00%) 129018.43 ( 36.82%) Amean p99-Allocation 278070.04 ( 0.00%) 183354.43 ( 34.06%) Amean final-p50-Read 21266432.00 ( 0.00%) 21921792.00 ( -3.08%) Amean final-p95-Read 24870912.00 ( 0.00%) 26116096.00 ( -5.01%) Amean final-p99-Read 28147712.00 ( 0.00%) 29523968.00 ( -4.89%) Amean final-p50-Write 1130.00 ( 0.00%) 977.00 ( 13.54%) Amean final-p95-Write 1033216.00 ( 0.00%) 2980.00 ( 99.71%) Amean final-p99-Write 1517568.00 ( 0.00%) 32672.00 ( 97.85%) Amean final-p50-Allocation 86656.00 ( 0.00%) 78464.00 ( 9.45%) Amean final-p95-Allocation 211712.00 ( 0.00%) 116608.00 ( 44.92%) Amean final-p99-Allocation 287232.00 ( 0.00%) 168704.00 ( 41.27%) The latencies are actually completely horrific in comparison to 4.4 (and 4.10-rc5 is worse than 4.9 according to historical data for reasons Mel hasn't analysed yet). Still, 95% of write latency (p95-write) is halved by the series and allocation latency is way down. Direct reclaim activity is one fifth of what it was according to vmstats. Kswapd activity is higher but this is not necessarily surprising. Kswapd efficiency is unchanged at 99% (99% of pages scanned were reclaimed) but direct reclaim efficiency went from 77% to 99% In the vanilla kernel, 627MB of data was written back from reclaim context. With the series, no data was written back. With or without the patch, pages are being immediately reclaimed after writeback completes. However, with the patch, only 1/8th of the pages are reclaimed like this. This patch (of 5): We have an elaborate dirty/writeback throttling mechanism inside the reclaim scanner, but for that to work the pages have to go through shrink_page_list() and get counted for what they are. Otherwise, we mess up the LRU order and don't match reclaim speed to writeback. Especially during deactivation, there is never a reason to skip dirty pages; nothing is even trying to write them out from there. Don't mess up the LRU order for nothing, shuffle these pages along. Change-Id: I7c9ffbd44c20e41b39d2306797f6b98c1160c582 Link: http://lkml.kernel.org/r/20170123181641.23938-2-hannes@cmpxchg.org Signed-off-by: Johannes Weiner Acked-by: Minchan Kim Acked-by: Michal Hocko Acked-by: Mel Gorman Acked-by: Hillf Danton Cc: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Git-Commit: 1276ad68e2491d1ceeb65f55d790f9277593c459 Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git Signed-off-by: Vinayak Menon --- include/linux/mmzone.h | 2 -- mm/vmscan.c | 14 ++------------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 0c28c28a1147..815d0f41e288 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -245,8 +245,6 @@ struct lruvec { #define LRU_ALL_ANON (BIT(LRU_INACTIVE_ANON) | BIT(LRU_ACTIVE_ANON)) #define LRU_ALL ((1 << NR_LRU_LISTS) - 1) -/* Isolate clean file */ -#define ISOLATE_CLEAN ((__force isolate_mode_t)0x1) /* Isolate unmapped file */ #define ISOLATE_UNMAPPED ((__force isolate_mode_t)0x2) /* Isolate for asynchronous migration */ diff --git a/mm/vmscan.c b/mm/vmscan.c index c5b94d61bb02..99d5c9dae35b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -87,6 +87,7 @@ struct scan_control { /* The highest zone to isolate pages for reclaim from */ enum zone_type reclaim_idx; + /* Writepage batching in laptop mode; RECLAIM_WRITE */ unsigned int may_writepage:1; /* Can mapped pages be reclaimed? */ @@ -1416,13 +1417,10 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode) * wants to isolate pages it will be able to operate on without * blocking - clean pages for the most part. * - * ISOLATE_CLEAN means that only clean pages should be isolated. This - * is used by reclaim when it is cannot write to backing storage - * * ISOLATE_ASYNC_MIGRATE is used to indicate that it only wants to pages * that it is possible to migrate without blocking */ - if (mode & (ISOLATE_CLEAN|ISOLATE_ASYNC_MIGRATE)) { + if (mode & ISOLATE_ASYNC_MIGRATE) { /* All the caller can do on PageWriteback is block */ if (PageWriteback(page)) return ret; @@ -1430,10 +1428,6 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode) if (PageDirty(page)) { struct address_space *mapping; - /* ISOLATE_CLEAN means only clean pages */ - if (mode & ISOLATE_CLEAN) - return ret; - /* * Only pages without mappings or that have a * ->migratepage callback are possible to migrate @@ -1831,8 +1825,6 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec, if (!sc->may_unmap) isolate_mode |= ISOLATE_UNMAPPED; - if (!sc->may_writepage) - isolate_mode |= ISOLATE_CLEAN; spin_lock_irq(&pgdat->lru_lock); @@ -2020,8 +2012,6 @@ static void shrink_active_list(unsigned long nr_to_scan, if (!sc->may_unmap) isolate_mode |= ISOLATE_UNMAPPED; - if (!sc->may_writepage) - isolate_mode |= ISOLATE_CLEAN; spin_lock_irq(&pgdat->lru_lock); -- GitLab From 6098c674f20ec1dc5cf60860a27ea196ecf9b7e3 Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Fri, 24 Feb 2017 14:56:14 -0800 Subject: [PATCH 678/855] mm: vmscan: kick flushers when we encounter dirty pages on the LRU Memory pressure can put dirty pages at the end of the LRU without anybody running into dirty limits. Don't start writing individual pages from kswapd while the flushers might be asleep. Unlike the old direct reclaim flusher wakeup (removed in the next patch) that flushes the number of pages just scanned, this patch wakes the flushers for all outstanding dirty pages. That seemed to perform better in a synthetic test that pushes dirty pages to the end of the LRU and into reclaim, because we know LRU aging outstrips writeback already, and this way we give younger dirty pages a headstart rather than wait until reclaim runs into them as well. It also means less plugging and risk of exhausting the struct request pool from reclaim. There is a concern that this will cause temporary files that used to get dirtied and truncated before writeback to now get written to disk under memory pressure. If this turns out to be a real problem, we'll have to revisit this and tame the reclaim flusher wakeups. Change-Id: I6660962957d0bd1a5f1b1f9a93ac104af6045505 [hannes@cmpxchg.org: mention dirty expiration as a condition] Link: http://lkml.kernel.org/r/20170126174739.GA30636@cmpxchg.org Link: http://lkml.kernel.org/r/20170123181641.23938-3-hannes@cmpxchg.org Signed-off-by: Johannes Weiner Acked-by: Minchan Kim Acked-by: Michal Hocko Acked-by: Mel Gorman Acked-by: Hillf Danton Cc: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Git-Commit: 726d061fbd3658e4bfeffa1b8e82da97de2ca4dd Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git [vinmenon@codeaurora.org trivial merge conflict fixes] Signed-off-by: Vinayak Menon --- include/linux/writeback.h | 2 +- include/trace/events/writeback.h | 2 +- mm/vmscan.c | 18 +++++++++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 9a8eb836c410..3eed4f19247a 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -43,7 +43,7 @@ enum writeback_sync_modes { */ enum wb_reason { WB_REASON_BACKGROUND, - WB_REASON_TRY_TO_FREE_PAGES, + WB_REASON_VMSCAN, WB_REASON_SYNC, WB_REASON_PERIODIC, WB_REASON_LAPTOP_TIMER, diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h index 2ccd9ccbf9ef..7bd8783a590f 100644 --- a/include/trace/events/writeback.h +++ b/include/trace/events/writeback.h @@ -31,7 +31,7 @@ #define WB_WORK_REASON \ EM( WB_REASON_BACKGROUND, "background") \ - EM( WB_REASON_TRY_TO_FREE_PAGES, "try_to_free_pages") \ + EM( WB_REASON_VMSCAN, "vmscan") \ EM( WB_REASON_SYNC, "sync") \ EM( WB_REASON_PERIODIC, "periodic") \ EM( WB_REASON_LAPTOP_TIMER, "laptop_timer") \ diff --git a/mm/vmscan.c b/mm/vmscan.c index 99d5c9dae35b..d7f708290812 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1899,12 +1899,20 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec, /* * If dirty pages are scanned that are not queued for IO, it - * implies that flushers are not keeping up. In this case, flag - * the pgdat PGDAT_DIRTY and kswapd will start writing pages from - * reclaim context. + * implies that flushers are not doing their job. This can + * happen when memory pressure pushes dirty pages to the end of + * the LRU before the dirty limits are breached and the dirty + * data has expired. It can also happen when the proportion of + * dirty pages grows not through writes but through memory + * pressure reclaiming all the clean cache. And in some cases, + * the flushers simply cannot keep up with the allocation + * rate. Nudge the flusher threads in case they are asleep, but + * also allow kswapd to start writing pages during reclaim. */ - if (nr_unqueued_dirty == nr_taken) + if (nr_unqueued_dirty == nr_taken) { + wakeup_flusher_threads(0, WB_REASON_VMSCAN); set_bit(PGDAT_DIRTY, &pgdat->flags); + } /* * If kswapd scans pages marked marked for immediate @@ -2851,7 +2859,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, writeback_threshold = sc->nr_to_reclaim + sc->nr_to_reclaim / 2; if (total_scanned > writeback_threshold) { wakeup_flusher_threads(laptop_mode ? 0 : total_scanned, - WB_REASON_TRY_TO_FREE_PAGES); + WB_REASON_VMSCAN); sc->may_writepage = 1; } } while (--sc->priority >= 0); -- GitLab From 8830ab9af0384fde003c67c7f57d39ef4d697618 Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Fri, 24 Feb 2017 14:56:17 -0800 Subject: [PATCH 679/855] mm: vmscan: remove old flusher wakeup from direct reclaim path Direct reclaim has been replaced by kswapd reclaim in pretty much all common memory pressure situations, so this code most likely doesn't accomplish the described effect anymore. The previous patch wakes up flushers for all reclaimers when we encounter dirty pages at the tail end of the LRU. Remove the crufty old direct reclaim invocation. Change-Id: I093ab8056e9915b5faca8c3882529cab8278c3ea Link: http://lkml.kernel.org/r/20170123181641.23938-4-hannes@cmpxchg.org Signed-off-by: Johannes Weiner Acked-by: Minchan Kim Acked-by: Michal Hocko Acked-by: Hillf Danton Cc: Mel Gorman Cc: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Git-Commit: bbef938429f5b201f9972f399a04f01af1934cc2 Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git Signed-off-by: Vinayak Menon --- mm/vmscan.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index d7f708290812..85dcaadaeca5 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2821,8 +2821,6 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, struct scan_control *sc) { int initial_priority = sc->priority; - unsigned long total_scanned = 0; - unsigned long writeback_threshold; retry: delayacct_freepages_start(); @@ -2835,7 +2833,6 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, sc->nr_scanned = 0; shrink_zones(zonelist, sc); - total_scanned += sc->nr_scanned; if (sc->nr_reclaimed >= sc->nr_to_reclaim) break; @@ -2848,20 +2845,6 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, */ if (sc->priority < DEF_PRIORITY - 2) sc->may_writepage = 1; - - /* - * Try to write back as many pages as we just scanned. This - * tends to cause slow streaming writers to write data to the - * disk smoothly, at the dirtying rate, which is nice. But - * that's undesirable in laptop mode, where we *want* lumpy - * writeout. So in laptop mode, write out the whole world. - */ - writeback_threshold = sc->nr_to_reclaim + sc->nr_to_reclaim / 2; - if (total_scanned > writeback_threshold) { - wakeup_flusher_threads(laptop_mode ? 0 : total_scanned, - WB_REASON_VMSCAN); - sc->may_writepage = 1; - } } while (--sc->priority >= 0); delayacct_freepages_end(); -- GitLab From 319400b17c70c0a57447f6acd2c699142c83ff13 Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Fri, 24 Feb 2017 14:56:20 -0800 Subject: [PATCH 680/855] mm: vmscan: only write dirty pages that the scanner has seen twice Dirty pages can easily reach the end of the LRU while there are still clean pages to reclaim around. Don't let kswapd write them back just because there are a lot of them. It costs more CPU to find the clean pages, but that's almost certainly better than to disrupt writeback from the flushers with LRU-order single-page writes from reclaim. And the flushers have been woken up by that point, so we spend IO capacity on flushing and CPU capacity on finding the clean cache. Only start writing dirty pages if they have cycled around the LRU twice now and STILL haven't been queued on the IO device. It's possible that the dirty pages are so sparsely distributed across different bdis, inodes, memory cgroups, that the flushers take forever to get to the ones we want reclaimed. Once we see them twice on the LRU, we know that's the quicker way to find them, so do LRU writeback. Change-Id: I22ba520bdbe4bdc8a726cf92da9c3d211ebfcaf8 Link: http://lkml.kernel.org/r/20170123181641.23938-5-hannes@cmpxchg.org Signed-off-by: Johannes Weiner Acked-by: Minchan Kim Acked-by: Michal Hocko Acked-by: Mel Gorman Acked-by: Hillf Danton Cc: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Git-Commit: 4eda48235011d6965f5229f8955ddcd355311570 Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git [vinmenon@codeaurora.org: trivial merge conflict fixes] Signed-off-by: Vinayak Menon --- mm/vmscan.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 85dcaadaeca5..065568a75282 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1154,14 +1154,18 @@ static unsigned long shrink_page_list(struct list_head *page_list, if (PageDirty(page)) { /* - * Only kswapd can writeback filesystem pages to - * avoid risk of stack overflow but only writeback - * if many dirty pages have been encountered. + * Only kswapd can writeback filesystem pages + * to avoid risk of stack overflow. But avoid + * injecting inefficient single-page IO into + * flusher writeback as much as possible: only + * write pages when we've encountered many + * dirty pages, and when we've already scanned + * the rest of the LRU for clean pages and see + * the same dirty pages again (PageReclaim). */ if (page_is_file_cache(page) && - (!current_is_kswapd() || - (pgdat && - !test_bit(PGDAT_DIRTY, &pgdat->flags)))) { + (!current_is_kswapd() || !PageReclaim(page) || + !test_bit(PGDAT_DIRTY, &pgdat->flags))) { /* * Immediately reclaim when written back. * Similar in principal to deactivate_page() -- GitLab From 6b25f41c930b5b8743908925860489fce98af81a Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Fri, 24 Feb 2017 14:56:23 -0800 Subject: [PATCH 681/855] mm: vmscan: move dirty pages out of the way until they're flushed We noticed a performance regression when moving hadoop workloads from 3.10 kernels to 4.0 and 4.6. This is accompanied by increased pageout activity initiated by kswapd as well as frequent bursts of allocation stalls and direct reclaim scans. Even lowering the dirty ratios to the equivalent of less than 1% of memory would not eliminate the issue, suggesting that dirty pages concentrate where the scanner is looking. This can be traced back to recent efforts of thrash avoidance. Where 3.10 would not detect refaulting pages and continuously supply clean cache to the inactive list, a thrashing workload on 4.0+ will detect and activate refaulting pages right away, distilling used-once pages on the inactive list much more effectively. This is by design, and it makes sense for clean cache. But for the most part our workload's cache faults are refaults and its use-once cache is from streaming writes. We end up with most of the inactive list dirty, and we don't go after the active cache as long as we have use-once pages around. But waiting for writes to avoid reclaiming clean cache that *might* refault is a bad trade-off. Even if the refaults happen, reads are faster than writes. Before getting bogged down on writeback, reclaim should first look at *all* cache in the system, even active cache. To accomplish this, activate pages that are dirty or under writeback when they reach the end of the inactive LRU. The pages are marked for immediate reclaim, meaning they'll get moved back to the inactive LRU tail as soon as they're written back and become reclaimable. But in the meantime, by reducing the inactive list to only immediately reclaimable pages, we allow the scanner to deactivate and refill the inactive list with clean cache from the active list tail to guarantee forward progress. Change-Id: I5c53d9d1bf773baa6ab99360d5afd99cac966356 [hannes@cmpxchg.org: update comment] Link: http://lkml.kernel.org/r/20170202191957.22872-8-hannes@cmpxchg.org Link: http://lkml.kernel.org/r/20170123181641.23938-6-hannes@cmpxchg.org Signed-off-by: Johannes Weiner Acked-by: Minchan Kim Acked-by: Michal Hocko Acked-by: Hillf Danton Cc: Mel Gorman Cc: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Git-Commit: c55e8d035b28b2867e68b0e2d0eee2c0f1016b43 Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git Signed-off-by: Vinayak Menon --- include/linux/mm_inline.h | 7 +++++++ mm/swap.c | 9 +++++---- mm/vmscan.c | 15 ++++++++++++--- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h index 41d376e7116d..e030a68ead7e 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h @@ -50,6 +50,13 @@ static __always_inline void add_page_to_lru_list(struct page *page, list_add(&page->lru, &lruvec->lists[lru]); } +static __always_inline void add_page_to_lru_list_tail(struct page *page, + struct lruvec *lruvec, enum lru_list lru) +{ + update_lru_size(lruvec, lru, page_zonenum(page), hpage_nr_pages(page)); + list_add_tail(&page->lru, &lruvec->lists[lru]); +} + static __always_inline void del_page_from_lru_list(struct page *page, struct lruvec *lruvec, enum lru_list lru) { diff --git a/mm/swap.c b/mm/swap.c index 4dcf852e1e6d..6f22754d6d55 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -208,9 +208,10 @@ static void pagevec_move_tail_fn(struct page *page, struct lruvec *lruvec, { int *pgmoved = arg; - if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { - enum lru_list lru = page_lru_base_type(page); - list_move_tail(&page->lru, &lruvec->lists[lru]); + if (PageLRU(page) && !PageUnevictable(page)) { + del_page_from_lru_list(page, lruvec, page_lru(page)); + ClearPageActive(page); + add_page_to_lru_list_tail(page, lruvec, page_lru(page)); (*pgmoved)++; } } @@ -234,7 +235,7 @@ static void pagevec_move_tail(struct pagevec *pvec) */ void rotate_reclaimable_page(struct page *page) { - if (!PageLocked(page) && !PageDirty(page) && !PageActive(page) && + if (!PageLocked(page) && !PageDirty(page) && !PageUnevictable(page) && PageLRU(page)) { struct pagevec *pvec; unsigned long flags; diff --git a/mm/vmscan.c b/mm/vmscan.c index 065568a75282..1f2d4a42cf07 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1058,6 +1058,15 @@ static unsigned long shrink_page_list(struct list_head *page_list, * throttling so we could easily OOM just because too many * pages are in writeback and there is nothing else to * reclaim. Wait for the writeback to complete. + * + * In cases 1) and 2) we activate the pages to get them out of + * the way while we continue scanning for clean pages on the + * inactive list and refilling from the active list. The + * observation here is that waiting for disk writes is more + * expensive than potentially causing reloads down the line. + * Since they're marked for immediate reclaim, they won't put + * memory pressure on the cache working set any longer than it + * takes to write them to disk. */ if (PageWriteback(page)) { /* Case 1 above */ @@ -1065,7 +1074,7 @@ static unsigned long shrink_page_list(struct list_head *page_list, PageReclaim(page) && (pgdat && test_bit(PGDAT_WRITEBACK, &pgdat->flags))) { nr_immediate++; - goto keep_locked; + goto activate_locked; /* Case 2 above */ } else if (sane_reclaim(sc) || @@ -1083,7 +1092,7 @@ static unsigned long shrink_page_list(struct list_head *page_list, */ SetPageReclaim(page); nr_writeback++; - goto keep_locked; + goto activate_locked; /* Case 3 above */ } else { @@ -1175,7 +1184,7 @@ static unsigned long shrink_page_list(struct list_head *page_list, inc_node_page_state(page, NR_VMSCAN_IMMEDIATE); SetPageReclaim(page); - goto keep_locked; + goto activate_locked; } if (references == PAGEREF_RECLAIM_CLEAN) -- GitLab From 62aec017c5ffe7b32bc086b3ba46646b228ee6f2 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Mon, 4 Jun 2018 15:53:33 +0530 Subject: [PATCH 682/855] f_gsi: Bail out if suspend event is pending before enabling data path When cable is connected, following sequence is expected to happen: set_alt() ->ipa_connect_channels()->ipa_data_path(). As part of ipa_data_path(), endpoints will be enabled and start ringing Doorbell to GSI. If suspend interrupt is received after this, it stops ringing Doorbell to GSI and suspends path to GSI by calling xdci_suspend(). If suspend is received before enablement of data path as part of connect handling, driver does enable GSI endpoints and starts ringing Doorbell to GSI. This is not expected and resulting in USB controller accessing invalid memory and causing SMMU fault. Fix it by bailing out data path enablement if suspend event is pending. Change-Id: I1603e4c675f85abff284c385c96230f1fb54231e Signed-off-by: Vijayavardhan Vennapusa --- drivers/usb/gadget/function/f_gsi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 4bdfadfa63ac..e2f9ed34cd8a 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -666,6 +666,11 @@ static void ipa_work_handler(struct work_struct *w) log_event_dbg("%s: ST_CON_IN_PROG_EVT_HOST_READY", __func__); } else if (event == EVT_CONNECTED) { + if (peek_event(d_port) == EVT_SUSPEND) { + log_event_dbg("%s: ST_CON_IN_PROG_EVT_SUSPEND", + __func__); + break; + } ipa_data_path_enable(d_port); d_port->sm_state = STATE_CONNECTED; log_event_dbg("%s: ST_CON_IN_PROG_EVT_CON %d", -- GitLab From 9575aef291d75d6885385992438c6fda51c98093 Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Mon, 4 Jun 2018 16:18:00 +0530 Subject: [PATCH 683/855] soc: qcom: socinfo: add support for sxr1120 Add support for getting soc-id and dummy handle on sxr1120. Change-Id: Ibcba4703f3c0daee90f12ec64868df2e175777d3 Signed-off-by: Kaushal Kumar --- drivers/soc/qcom/socinfo.c | 7 +++++++ include/soc/qcom/socinfo.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index e02bf8409088..de7cc0d2eed3 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -599,6 +599,9 @@ static struct msm_soc_info cpu_of_id[] = { /* SDM710 ID */ [360] = {MSM_CPU_SDM710, "SDM710"}, + /* SXR1120 ID */ + [370] = {MSM_CPU_SXR1120, "SXR1120"}, + /* 8953 ID */ [293] = {MSM_CPU_8953, "MSM8953"}, [304] = {MSM_CPU_8953, "APQ8053"}, @@ -1544,6 +1547,10 @@ static void * __init setup_dummy_socinfo(void) dummy_socinfo.id = 347; strlcpy(dummy_socinfo.build_id, "qcs605 - ", sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_sxr1120()) { + dummy_socinfo.id = 370; + strlcpy(dummy_socinfo.build_id, "sxr1120 - ", + sizeof(dummy_socinfo.build_id)); } else if (early_machine_is_mdm9650()) { dummy_socinfo.id = 286; strlcpy(dummy_socinfo.build_id, "mdm9650 - ", diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h index 5f496a8a39a8..3d24964aa751 100644 --- a/include/soc/qcom/socinfo.h +++ b/include/soc/qcom/socinfo.h @@ -108,6 +108,8 @@ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sda670") #define early_machine_is_sdm710() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm670") +#define early_machine_is_sxr1120() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sxr1120") #define early_machine_is_msm8953() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8953") #define early_machine_is_msm8937() \ @@ -172,6 +174,7 @@ #define early_machine_is_qcs605() 0 #define early_machine_is_sda670() 0 #define early_machine_is_sdm710() 0 +#define early_machine_is_sxr1120() 0 #define early_machine_is_msm8953() 0 #define early_machine_is_msm8937() 0 #define early_machine_is_sdm450() 0 @@ -246,6 +249,7 @@ enum msm_cpu { MSM_CPU_QCS605, MSM_CPU_SDA670, MSM_CPU_SDM710, + MSM_CPU_SXR1120, MSM_CPU_8953, MSM_CPU_SDM450, MSM_CPU_SDM632, -- GitLab From 82ed83452a019ce39fec382d37557a22001c311c Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Thu, 22 Mar 2018 16:17:42 -0700 Subject: [PATCH 684/855] mm/vmscan: wake up flushers for legacy cgroups too Commit 726d061fbd36 ("mm: vmscan: kick flushers when we encounter dirty pages on the LRU") added flusher invocation to shrink_inactive_list() when many dirty pages on the LRU are encountered. However, shrink_inactive_list() doesn't wake up flushers for legacy cgroup reclaim, so the next commit bbef938429f5 ("mm: vmscan: remove old flusher wakeup from direct reclaim path") removed the only source of flusher's wake up in legacy mem cgroup reclaim path. This leads to premature OOM if there is too many dirty pages in cgroup: # mkdir /sys/fs/cgroup/memory/test # echo $$ > /sys/fs/cgroup/memory/test/tasks # echo 50M > /sys/fs/cgroup/memory/test/memory.limit_in_bytes # dd if=/dev/zero of=tmp_file bs=1M count=100 Killed dd invoked oom-killer: gfp_mask=0x14000c0(GFP_KERNEL), nodemask=(null), order=0, oom_score_adj=0 Call Trace: dump_stack+0x46/0x65 dump_header+0x6b/0x2ac oom_kill_process+0x21c/0x4a0 out_of_memory+0x2a5/0x4b0 mem_cgroup_out_of_memory+0x3b/0x60 mem_cgroup_oom_synchronize+0x2ed/0x330 pagefault_out_of_memory+0x24/0x54 __do_page_fault+0x521/0x540 page_fault+0x45/0x50 Task in /test killed as a result of limit of /test memory: usage 51200kB, limit 51200kB, failcnt 73 memory+swap: usage 51200kB, limit 9007199254740988kB, failcnt 0 kmem: usage 296kB, limit 9007199254740988kB, failcnt 0 Memory cgroup stats for /test: cache:49632KB rss:1056KB rss_huge:0KB shmem:0KB mapped_file:0KB dirty:49500KB writeback:0KB swap:0KB inactive_anon:0KB active_anon:1168KB inactive_file:24760KB active_file:24960KB unevictable:0KB Memory cgroup out of memory: Kill process 3861 (bash) score 88 or sacrifice child Killed process 3876 (dd) total-vm:8484kB, anon-rss:1052kB, file-rss:1720kB, shmem-rss:0kB oom_reaper: reaped process 3876 (dd), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB Wake up flushers in legacy cgroup reclaim too. Change-Id: I46e55a2dafe2aa5ef84ae62e91bba770bdf33d97 Link: http://lkml.kernel.org/r/20180315164553.17856-1-aryabinin@virtuozzo.com Fixes: bbef938429f5 ("mm: vmscan: remove old flusher wakeup from direct reclaim path") Signed-off-by: Andrey Ryabinin Tested-by: Shakeel Butt Acked-by: Michal Hocko Cc: Mel Gorman Cc: Tejun Heo Cc: Johannes Weiner Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Git-Commit: 1c610d5f93c709df56787f50b3576704ac271826 Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git [vinmenon@codeaurora.org: trivial merge conflict fixes, changes due to wakeup_flusher_threads api difference] Signed-off-by: Vinayak Menon --- mm/vmscan.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 1f2d4a42cf07..c8e300c37673 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1898,6 +1898,20 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec, if (nr_writeback && nr_writeback == nr_taken) set_bit(PGDAT_WRITEBACK, &pgdat->flags); + /* + * If dirty pages are scanned that are not queued for IO, it + * implies that flushers are not doing their job. This can + * happen when memory pressure pushes dirty pages to the end of + * the LRU before the dirty limits are breached and the dirty + * data has expired. It can also happen when the proportion of + * dirty pages grows not through writes but through memory + * pressure reclaiming all the clean cache. And in some cases, + * the flushers simply cannot keep up with the allocation + * rate. Nudge the flusher threads in case they are asleep. + */ + if (nr_unqueued_dirty == nr_taken) + wakeup_flusher_threads(0, WB_REASON_VMSCAN); + /* * Legacy memcg will stall in page writeback so avoid forcibly * stalling here. @@ -1910,22 +1924,9 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec, if (nr_dirty && nr_dirty == nr_congested) set_bit(PGDAT_CONGESTED, &pgdat->flags); - /* - * If dirty pages are scanned that are not queued for IO, it - * implies that flushers are not doing their job. This can - * happen when memory pressure pushes dirty pages to the end of - * the LRU before the dirty limits are breached and the dirty - * data has expired. It can also happen when the proportion of - * dirty pages grows not through writes but through memory - * pressure reclaiming all the clean cache. And in some cases, - * the flushers simply cannot keep up with the allocation - * rate. Nudge the flusher threads in case they are asleep, but - * also allow kswapd to start writing pages during reclaim. - */ - if (nr_unqueued_dirty == nr_taken) { - wakeup_flusher_threads(0, WB_REASON_VMSCAN); + /* Allow kswapd to start writing pages during reclaim. */ + if (nr_unqueued_dirty == nr_taken) set_bit(PGDAT_DIRTY, &pgdat->flags); - } /* * If kswapd scans pages marked marked for immediate -- GitLab From 6c742c0c278d8b196567b97c7f6241aebab0cb27 Mon Sep 17 00:00:00 2001 From: Padmanabhan Komanduru Date: Mon, 4 Jun 2018 18:05:52 +0530 Subject: [PATCH 685/855] ARM: dts: msm: add support for NT35695b FHD panel for SDM439 MTP Add support for NT35695b truly FHD command mode and video mode panel on SDM439 MTP. Change-Id: I8dbbe979607c9c4298d905fe44c9a0d2adba6244 Signed-off-by: Padmanabhan Komanduru --- arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi | 315 +++++++++++++++++++++++ 1 file changed, 315 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi index 0336d8255c4a..7a61a7aedf56 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi @@ -229,6 +229,321 @@ "dfps_immediate_porch_mode_vfp"; }; +&dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <2>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = + [15 01 00 00 10 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 03 55 + 15 01 00 00 00 00 02 05 50 + 15 01 00 00 00 00 02 06 a8 + 15 01 00 00 00 00 02 07 ad + 15 01 00 00 00 00 02 08 0c + 15 01 00 00 00 00 02 0b aa + 15 01 00 00 00 00 02 0c aa + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f b3 + 15 01 00 00 00 00 02 11 28 + 15 01 00 00 00 00 02 12 10 + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 4a + 15 01 00 00 00 00 02 15 12 + 15 01 00 00 00 00 02 16 12 + 15 01 00 00 00 00 02 30 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 58 82 + 15 01 00 00 00 00 02 59 00 + 15 01 00 00 00 00 02 5a 02 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 82 + 15 01 00 00 00 00 02 5d 80 + 15 01 00 00 00 00 02 5e 02 + 15 01 00 00 00 00 02 5f 00 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 89 + 15 01 00 00 00 00 02 04 8a + 15 01 00 00 00 00 02 05 0f + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 1c + 15 01 00 00 00 00 02 09 00 + 15 01 00 00 00 00 02 0a 00 + 15 01 00 00 00 00 02 0b 00 + 15 01 00 00 00 00 02 0c 00 + 15 01 00 00 00 00 02 0d 13 + 15 01 00 00 00 00 02 0e 15 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 01 + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 89 + 15 01 00 00 00 00 02 14 8a + 15 01 00 00 00 00 02 15 0f + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 1c + 15 01 00 00 00 00 02 19 00 + 15 01 00 00 00 00 02 1a 00 + 15 01 00 00 00 00 02 1b 00 + 15 01 00 00 00 00 02 1c 00 + 15 01 00 00 00 00 02 1d 13 + 15 01 00 00 00 00 02 1e 15 + 15 01 00 00 00 00 02 1f 17 + 15 01 00 00 00 00 02 20 00 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 55 25 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 93 06 + 15 01 00 00 00 00 02 94 06 + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b 0f + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 21 + 15 01 00 00 00 00 02 b7 22 + 15 01 00 00 00 00 02 b8 07 + 15 01 00 00 00 00 02 b9 07 + 15 01 00 00 00 00 02 ba 22 + 15 01 00 00 00 00 02 bd 20 + 15 01 00 00 00 00 02 be 07 + 15 01 00 00 00 00 02 bf 07 + 15 01 00 00 00 00 02 c1 6d + 15 01 00 00 00 00 02 c4 24 + 15 01 00 00 00 00 02 e3 00 + 15 01 00 00 00 00 02 ec 00 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 14 + 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-timings-phy-12nm = [17 0a 0f 06 03 08 06 0e]; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>; + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-max-error-count = <3>; + /delete-node/ qcom,mdss-dsi-display-timings; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-v-back-porch = <2>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = + [15 01 00 00 10 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 03 55 + 15 01 00 00 00 00 02 05 50 + 15 01 00 00 00 00 02 06 a8 + 15 01 00 00 00 00 02 07 ad + 15 01 00 00 00 00 02 08 0c + 15 01 00 00 00 00 02 0b aa + 15 01 00 00 00 00 02 0c aa + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f b3 + 15 01 00 00 00 00 02 11 28 + 15 01 00 00 00 00 02 12 10 + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 4a + 15 01 00 00 00 00 02 15 12 + 15 01 00 00 00 00 02 16 12 + 15 01 00 00 00 00 02 30 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 58 82 + 15 01 00 00 00 00 02 59 00 + 15 01 00 00 00 00 02 5a 02 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 82 + 15 01 00 00 00 00 02 5d 80 + 15 01 00 00 00 00 02 5e 02 + 15 01 00 00 00 00 02 5f 00 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 89 + 15 01 00 00 00 00 02 04 8a + 15 01 00 00 00 00 02 05 0f + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 1c + 15 01 00 00 00 00 02 09 00 + 15 01 00 00 00 00 02 0a 00 + 15 01 00 00 00 00 02 0b 00 + 15 01 00 00 00 00 02 0c 00 + 15 01 00 00 00 00 02 0d 13 + 15 01 00 00 00 00 02 0e 15 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 01 + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 89 + 15 01 00 00 00 00 02 14 8a + 15 01 00 00 00 00 02 15 0f + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 1c + 15 01 00 00 00 00 02 19 00 + 15 01 00 00 00 00 02 1a 00 + 15 01 00 00 00 00 02 1b 00 + 15 01 00 00 00 00 02 1c 00 + 15 01 00 00 00 00 02 1d 13 + 15 01 00 00 00 00 02 1e 15 + 15 01 00 00 00 00 02 1f 17 + 15 01 00 00 00 00 02 20 00 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 55 25 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 93 06 + 15 01 00 00 00 00 02 94 06 + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b 0f + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 21 + 15 01 00 00 00 00 02 b7 22 + 15 01 00 00 00 00 02 b8 07 + 15 01 00 00 00 00 02 b9 07 + 15 01 00 00 00 00 02 ba 22 + 15 01 00 00 00 00 02 bd 20 + 15 01 00 00 00 00 02 be 07 + 15 01 00 00 00 00 02 bf 07 + 15 01 00 00 00 00 02 c1 6d + 15 01 00 00 00 00 02 c4 24 + 15 01 00 00 00 00 02 e3 00 + 15 01 00 00 00 00 02 ec 00 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bb 03 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 + 14 00 02 28 00 05 01 00 00 78 00 + 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-timings-phy-12nm = [17 0a 0f 06 03 08 06 0e]; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>; + /delete-node/ qcom,mdss-dsi-display-timings; +}; + &i2c_2 { #include "smb1355.dtsi" }; -- GitLab From 46884417a33b5e7485eb2fa085275e6bc0a13a8c Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Mon, 4 Jun 2018 21:25:49 +0530 Subject: [PATCH 686/855] diag: Update event id for WLAN, RRC The patch adds new event ids for RRC events, WLAN host scan and WLAN PE Diag set antenna. Change-Id: Ib62e97a903407f0249d2eb40fc5463cc45103873 Signed-off-by: Manoj Prabhu B --- include/linux/diagchar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h index d9912e07b7a9..62f4fa8b4e50 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.h @@ -146,7 +146,7 @@ * a new RANGE of SSIDs to the msg_mask_tbl. */ #define MSG_MASK_TBL_CNT 26 -#define APPS_EVENT_LAST_ID 0x0C5B +#define APPS_EVENT_LAST_ID 0xC7A #define MSG_SSID_0 0 #define MSG_SSID_0_LAST 125 -- GitLab From c1426be3fd0aac1c85ba0270fb8cdd84e67094cd Mon Sep 17 00:00:00 2001 From: Venkataraman Nerellapalli Date: Wed, 9 May 2018 09:26:48 +0530 Subject: [PATCH 687/855] ARM: dts: msm: Add device tree support for apq8009-lat-v1.0 Add initial device tree support for apq8009 lat-v1.0 platform. Change-Id: Iad7a3be8aefb03f4e291dc34926f6d29bd39fac4 Signed-off-by: c_vnerel --- arch/arm64/boot/dts/qcom/Makefile | 3 +- arch/arm64/boot/dts/qcom/apq8009-lat-v1.0.dts | 145 ++++++++++++++++++ 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/qcom/apq8009-lat-v1.0.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 9cfb7cb79769..9c3bb387785d 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -451,7 +451,8 @@ dtb-$(CONFIG_ARCH_MSM8909) += msm8909w-bg-wtp-v2.dtb \ apq8009w-bg-alpha.dtb \ apq8009-mtp-wcd9326-refboard.dtb \ apq8009-robot-som-refboard.dtb \ - apq8009-dragon.dtb + apq8009-dragon.dtb \ + apq8009-lat-v1.0.dtb dtb-$(CONFIG_ARCH_SDM450) += sdm450-rcm.dtb \ sdm450-cdp.dtb \ diff --git a/arch/arm64/boot/dts/qcom/apq8009-lat-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8009-lat-v1.0.dts new file mode 100644 index 000000000000..f81e369355b7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8009-lat-v1.0.dts @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8909-mtp.dtsi" +#include "8909-pm8916.dtsi" +#include "msm8909-pm8916-mtp.dtsi" +#include "apq8009-audio-external_codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8009-lat-v1.0 Board"; + compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; + qcom,msm-id = <265 2>; + qcom,board-id= <10 0x1>; + + bluetooth: bt_qca9379 { + compatible = "qca,qca9379"; + qca,bt-reset-gpio = <&msm_gpio 47 0x0>; /* BT_EN */ + }; +}; + +&soc { + ext-codec { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + }; + + sound-9335 { + status = "disabled"; + }; + + i2c@78b8000 { + wcd9xxx_codec@d { + status = "disabled"; + }; + }; + + vph_pwr_vreg: vph_pwr_vreg { + compatible = "regulator-fixed"; + status = "ok"; + regulator-name = "vph_pwr"; + regulator-always-on; + }; + + mdss_mdp: qcom,mdss_mdp@1a00000 { + status = "disabled"; + }; + + qcom,msm-thermal { + qcom,core-control-mask = <0xa>; + qcom,freq-mitigation-value = <1190400>; + qcom,freq-mitigation-control-mask = <0x05>; + }; +}; + +&sdhc_2 { + status = "disabled"; +}; + +&usb_otg { + interrupts = <0 134 0>, <0 140 0>, <0 136 0>; + interrupt-names = "core_irq", "async_irq", "phy_irq"; + qcom,hsusb-otg-mode = <3>; + qcom,phy-id-high-as-peripheral; + vbus_otg-supply = <&vph_pwr_vreg>; +}; + +&external_image_mem { + reg = <0x0 0x87a00000 0x0 0x0600000>; +}; + +&modem_adsp_mem { + reg = <0x0 0x88000000 0x0 0x01e00000>; +}; + +&peripheral_mem { + reg = <0x0 0x89e00000 0x0 0x0700000>; +}; + +&i2c_4 { + smb1360_otg_supply: smb1360-chg-fg@14 { + compatible = "qcom,smb1360-chg-fg"; + reg = <0x14>; + interrupt-parent = <&msm_gpio>; + interrupts = <58 8>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>; + qcom,charging-disabled; + qcom,empty-soc-disabled; + qcom,chg-inhibit-disabled; + qcom,float-voltage-mv = <4200>; + qcom,iterm-ma = <200>; + qcom,recharge-thresh-mv = <100>; + qcom,thermal-mitigation = <1500 700 600 0>; + regulator-name = "smb1360_otg_vreg"; + status= "disabled"; + }; +}; + +&firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor_fstab: vendor { + fsmgr_flags = "wait,slotselect"; + }; + /delete-node/ system; + }; + }; +}; + +&pm8916_chg { + status = "ok"; +}; + +&pm8916_bms { + status = "ok"; +}; -- GitLab From 231452b6361c3c18b3eb20fa8512535d73401211 Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Fri, 1 Jun 2018 02:23:02 +0530 Subject: [PATCH 688/855] defconfig: sdm845: Enable VTI config for v4 and v6 Enable VTI to give userspace (netd) the ability to create and update virtual interfaces. CRs-Fixed: 2214527 Change-Id: I3a25a318abb06a3321cf91366eda96c1e33190af Signed-off-by: Devi Sandeep Endluri V V --- arch/arm64/configs/sdm845-perf_defconfig | 2 ++ arch/arm64/configs/sdm845_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig index a0a703193008..dceaafdbd89d 100644 --- a/arch/arm64/configs/sdm845-perf_defconfig +++ b/arch/arm64/configs/sdm845-perf_defconfig @@ -102,6 +102,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -114,6 +115,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig index 41959a6586fd..946e4f4c26d9 100644 --- a/arch/arm64/configs/sdm845_defconfig +++ b/arch/arm64/configs/sdm845_defconfig @@ -105,6 +105,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -117,6 +118,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y -- GitLab From e8d097b17fd3721a07a7ebdc8a75459bd47a918a Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Thu, 10 May 2018 15:44:56 -0700 Subject: [PATCH 689/855] msm:ipa3: fix the header table gap issue Move those deleted entries to the free list to avoid the gap in hdr tbl list. Change-Id: I5f5b6ec845e6b7e52c7079c2a3200a8290616951 Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c | 111 ++++++++-------------- drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c | 106 ++++++++------------- 2 files changed, 80 insertions(+), 137 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c index 324125783220..61c3a7164bc0 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c @@ -1249,8 +1249,9 @@ int ipa2_reset_hdr(bool user_only) struct ipa_hdr_offset_entry *off_next; struct ipa_hdr_proc_ctx_offset_entry *ctx_off_entry; struct ipa_hdr_proc_ctx_offset_entry *ctx_off_next; - int i, end = 0; - bool user_rule = false; + struct ipa_hdr_tbl *htbl = &ipa_ctx->hdr_tbl; + struct ipa_hdr_proc_ctx_tbl *htbl_proc = &ipa_ctx->hdr_proc_ctx_tbl; + int i; /* * issue a reset on the routing module since routing rules point to @@ -1288,9 +1289,6 @@ int ipa2_reset_hdr(bool user_only) return -EFAULT; } - if (entry->ipacm_installed) - user_rule = true; - if (!user_only || entry->ipacm_installed) { if (entry->is_hdr_proc_ctx) { dma_unmap_single(ipa_ctx->pdev, @@ -1298,9 +1296,15 @@ int ipa2_reset_hdr(bool user_only) entry->hdr_len, DMA_TO_DEVICE); entry->proc_ctx = NULL; + } else { + /* move the offset entry to free list */ + entry->offset_entry->ipacm_installed = 0; + list_move(&entry->offset_entry->link, + &htbl->head_free_offset_list[ + entry->offset_entry->bin]); } list_del(&entry->link); - ipa_ctx->hdr_tbl.hdr_cnt--; + htbl->hdr_cnt--; entry->ref_cnt = 0; entry->cookie = 0; @@ -1309,53 +1313,37 @@ int ipa2_reset_hdr(bool user_only) kmem_cache_free(ipa_ctx->hdr_cache, entry); } } - for (i = 0; i < IPA_HDR_BIN_MAX; i++) { - list_for_each_entry_safe(off_entry, off_next, - &ipa_ctx->hdr_tbl.head_offset_list[i], - link) { - - /* - * do not remove the default exception header which is - * at offset 0 - */ - if (off_entry->offset == 0) - continue; - if (!user_only || - off_entry->ipacm_installed) { + /* only clean up offset_list and free_offset_list on global reset */ + if (!user_only) { + for (i = 0; i < IPA_HDR_BIN_MAX; i++) { + list_for_each_entry_safe(off_entry, off_next, + &ipa_ctx->hdr_tbl.head_offset_list[i], + link) { + /** + * do not remove the default exception + * header which is at offset 0 + */ + if (off_entry->offset == 0) + continue; list_del(&off_entry->link); kmem_cache_free(ipa_ctx->hdr_offset_cache, off_entry); - } else { - if (off_entry->offset + - ipa_hdr_bin_sz[off_entry->bin] > end) { - end = off_entry->offset + - ipa_hdr_bin_sz[off_entry->bin]; - IPADBG("replace end = %d\n", end); - } } - } - list_for_each_entry_safe(off_entry, off_next, + list_for_each_entry_safe(off_entry, off_next, &ipa_ctx->hdr_tbl.head_free_offset_list[i], link) { - - if (!user_only || - off_entry->ipacm_installed) { list_del(&off_entry->link); kmem_cache_free(ipa_ctx->hdr_offset_cache, off_entry); } } + /* there is one header of size 8 */ + ipa_ctx->hdr_tbl.end = 8; + ipa_ctx->hdr_tbl.hdr_cnt = 1; } - IPADBG("hdr_tbl.end = %d\n", end); - if (user_rule) { - ipa_ctx->hdr_tbl.end = end; - IPADBG("hdr_tbl.end = %d\n", end); - } IPADBG("reset hdr proc ctx\n"); - user_rule = false; - end = 0; list_for_each_entry_safe( ctx_entry, ctx_next, @@ -1364,17 +1352,18 @@ int ipa2_reset_hdr(bool user_only) if (ipa_id_find(ctx_entry->id) == NULL) { mutex_unlock(&ipa_ctx->lock); - WARN_ON(1); + WARN_ON_RATELIMIT_IPA(1); return -EFAULT; } - if (entry->ipacm_installed) - user_rule = true; - if (!user_only || ctx_entry->ipacm_installed) { + /* move the offset entry to appropriate free list */ + list_move(&ctx_entry->offset_entry->link, + &htbl_proc->head_free_offset_list[ + ctx_entry->offset_entry->bin]); list_del(&ctx_entry->link); - ipa_ctx->hdr_proc_ctx_tbl.proc_ctx_cnt--; + htbl_proc->proc_ctx_cnt--; ctx_entry->ref_cnt = 0; ctx_entry->cookie = 0; @@ -1384,48 +1373,30 @@ int ipa2_reset_hdr(bool user_only) ctx_entry); } } - for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) { - list_for_each_entry_safe(ctx_off_entry, ctx_off_next, + /* only clean up offset_list and free_offset_list on global reset */ + if (!user_only) { + for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) { + list_for_each_entry_safe(ctx_off_entry, ctx_off_next, &ipa_ctx->hdr_proc_ctx_tbl.head_offset_list[i], link) { - - if (!user_only || - ctx_off_entry->ipacm_installed) { list_del(&ctx_off_entry->link); kmem_cache_free( ipa_ctx->hdr_proc_ctx_offset_cache, ctx_off_entry); - } else { - if (ctx_off_entry->offset + - ipa_hdr_bin_sz[ctx_off_entry->bin] - > end) { - end = ctx_off_entry->offset + - ipa_hdr_bin_sz[ctx_off_entry->bin]; - IPADBG("replace hdr_proc as %d\n", end); - } } - } - list_for_each_entry_safe(ctx_off_entry, ctx_off_next, - &ipa_ctx->hdr_proc_ctx_tbl.head_free_offset_list[i], - link) { - - if (!user_only || - ctx_off_entry->ipacm_installed) { + list_for_each_entry_safe(ctx_off_entry, ctx_off_next, + &ipa_ctx->hdr_proc_ctx_tbl. + head_free_offset_list[i], link) { list_del(&ctx_off_entry->link); kmem_cache_free( ipa_ctx->hdr_proc_ctx_offset_cache, ctx_off_entry); } } + ipa_ctx->hdr_proc_ctx_tbl.end = 0; + ipa_ctx->hdr_proc_ctx_tbl.proc_ctx_cnt = 0; } - IPADBG("hdr_proc_tbl.end = %d\n", end); - if (user_rule) { - ipa_ctx->hdr_proc_ctx_tbl.end = end; - IPADBG("hdr_proc_tbl.end = %d\n", end); - } - mutex_unlock(&ipa_ctx->lock); - /* commit the change to IPA-HW */ if (ipa_ctx->ctrl->ipa_commit_hdr()) { IPAERR_RL("fail to commit hdr\n"); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c index 41965398792a..4eb8edb1c11a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c @@ -996,8 +996,9 @@ int ipa3_reset_hdr(bool user_only) struct ipa_hdr_offset_entry *off_next; struct ipa3_hdr_proc_ctx_offset_entry *ctx_off_entry; struct ipa3_hdr_proc_ctx_offset_entry *ctx_off_next; - int i, end = 0; - bool user_rule = false; + struct ipa3_hdr_tbl *htbl = &ipa3_ctx->hdr_tbl; + struct ipa3_hdr_proc_ctx_tbl *htbl_proc = &ipa3_ctx->hdr_proc_ctx_tbl; + int i; /* * issue a reset on the routing module since routing rules point to @@ -1035,9 +1036,6 @@ int ipa3_reset_hdr(bool user_only) return -EFAULT; } - if (entry->ipacm_installed) - user_rule = true; - if (!user_only || entry->ipacm_installed) { if (entry->is_hdr_proc_ctx) { dma_unmap_single(ipa3_ctx->pdev, @@ -1045,9 +1043,15 @@ int ipa3_reset_hdr(bool user_only) entry->hdr_len, DMA_TO_DEVICE); entry->proc_ctx = NULL; + } else { + /* move the offset entry to free list */ + entry->offset_entry->ipacm_installed = 0; + list_move(&entry->offset_entry->link, + &htbl->head_free_offset_list[ + entry->offset_entry->bin]); } list_del(&entry->link); - ipa3_ctx->hdr_tbl.hdr_cnt--; + htbl->hdr_cnt--; entry->ref_cnt = 0; entry->cookie = 0; @@ -1056,53 +1060,37 @@ int ipa3_reset_hdr(bool user_only) kmem_cache_free(ipa3_ctx->hdr_cache, entry); } } - for (i = 0; i < IPA_HDR_BIN_MAX; i++) { - list_for_each_entry_safe(off_entry, off_next, + + /* only clean up offset_list and free_offset_list on global reset */ + if (!user_only) { + for (i = 0; i < IPA_HDR_BIN_MAX; i++) { + list_for_each_entry_safe(off_entry, off_next, &ipa3_ctx->hdr_tbl.head_offset_list[i], link) { - - /* - * do not remove the default exception header which is - * at offset 0 - */ - if (off_entry->offset == 0) - continue; - - if (!user_only || - off_entry->ipacm_installed) { + /** + * do not remove the default exception + * header which is at offset 0 + */ + if (off_entry->offset == 0) + continue; list_del(&off_entry->link); kmem_cache_free(ipa3_ctx->hdr_offset_cache, off_entry); - } else { - if (off_entry->offset + - ipa_hdr_bin_sz[off_entry->bin] > end) { - end = off_entry->offset + - ipa_hdr_bin_sz[off_entry->bin]; - IPADBG("replace end = %d\n", end); - } } - } - list_for_each_entry_safe(off_entry, off_next, + list_for_each_entry_safe(off_entry, off_next, &ipa3_ctx->hdr_tbl.head_free_offset_list[i], link) { - - if (!user_only || - off_entry->ipacm_installed) { list_del(&off_entry->link); kmem_cache_free(ipa3_ctx->hdr_offset_cache, off_entry); } } + /* there is one header of size 8 */ + ipa3_ctx->hdr_tbl.end = 8; + ipa3_ctx->hdr_tbl.hdr_cnt = 1; } - IPADBG("hdr_tbl.end = %d\n", end); - if (user_rule) { - ipa3_ctx->hdr_tbl.end = end; - IPADBG("hdr_tbl.end = %d\n", end); - } IPADBG("reset hdr proc ctx\n"); - user_rule = false; - end = 0; list_for_each_entry_safe( ctx_entry, ctx_next, @@ -1115,13 +1103,14 @@ int ipa3_reset_hdr(bool user_only) return -EFAULT; } - if (entry->ipacm_installed) - user_rule = true; - if (!user_only || ctx_entry->ipacm_installed) { + /* move the offset entry to appropriate free list */ + list_move(&ctx_entry->offset_entry->link, + &htbl_proc->head_free_offset_list[ + ctx_entry->offset_entry->bin]); list_del(&ctx_entry->link); - ipa3_ctx->hdr_proc_ctx_tbl.proc_ctx_cnt--; + htbl_proc->proc_ctx_cnt--; ctx_entry->ref_cnt = 0; ctx_entry->cookie = 0; @@ -1131,45 +1120,28 @@ int ipa3_reset_hdr(bool user_only) ctx_entry); } } - for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) { - list_for_each_entry_safe(ctx_off_entry, ctx_off_next, + /* only clean up offset_list and free_offset_list on global reset */ + if (!user_only) { + for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) { + list_for_each_entry_safe(ctx_off_entry, ctx_off_next, &ipa3_ctx->hdr_proc_ctx_tbl.head_offset_list[i], link) { - - if (!user_only || - ctx_off_entry->ipacm_installed) { list_del(&ctx_off_entry->link); kmem_cache_free( ipa3_ctx->hdr_proc_ctx_offset_cache, ctx_off_entry); - } else { - if (ctx_off_entry->offset + - ipa_hdr_bin_sz[ctx_off_entry->bin] - > end) { - end = ctx_off_entry->offset + - ipa_hdr_bin_sz[ctx_off_entry->bin]; - IPADBG("replace hdr_proc as %d\n", end); - } } - } - list_for_each_entry_safe(ctx_off_entry, ctx_off_next, - &ipa3_ctx->hdr_proc_ctx_tbl.head_free_offset_list[i], - link) { - - if (!user_only || - ctx_off_entry->ipacm_installed) { + list_for_each_entry_safe(ctx_off_entry, ctx_off_next, + &ipa3_ctx->hdr_proc_ctx_tbl. + head_free_offset_list[i], link) { list_del(&ctx_off_entry->link); kmem_cache_free( ipa3_ctx->hdr_proc_ctx_offset_cache, ctx_off_entry); } } - } - - IPADBG("hdr_proc_tbl.end = %d\n", end); - if (user_rule) { - ipa3_ctx->hdr_proc_ctx_tbl.end = end; - IPADBG("hdr_proc_tbl.end = %d\n", end); + ipa3_ctx->hdr_proc_ctx_tbl.end = 0; + ipa3_ctx->hdr_proc_ctx_tbl.proc_ctx_cnt = 0; } /* commit the change to IPA-HW */ -- GitLab From d926057c595162155cec352d2c232cfa264589f9 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Tue, 29 May 2018 16:48:37 -0700 Subject: [PATCH 690/855] msm: camera: vfe: Update logic to set axi bandwidth vote Apply bandwidth update by finding max bw request in last few frames. Change-Id: I46dd6fa299f34d833e7fb07971aa558737436acb Signed-off-by: Vishalsingh Hajeri --- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 105 ++++++++---------- 1 file changed, 48 insertions(+), 57 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index 5d6045bb3e08..be0ca184113c 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -34,11 +34,12 @@ struct cam_vfe_top_ver2_priv { struct cam_vfe_top_ver2_common_data common_data; struct cam_isp_resource_node mux_rsrc[CAM_VFE_TOP_VER2_MUX_MAX]; unsigned long hw_clk_rate; - struct cam_axi_vote to_be_applied_axi_vote; struct cam_axi_vote applied_axi_vote; - uint32_t counter_to_update_axi_vote; struct cam_axi_vote req_axi_vote[CAM_VFE_TOP_VER2_MUX_MAX]; unsigned long req_clk_rate[CAM_VFE_TOP_VER2_MUX_MAX]; + struct cam_axi_vote last_vote[CAM_VFE_TOP_VER2_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES]; + uint32_t last_counter; enum cam_vfe_bw_control_action axi_vote_control[CAM_VFE_TOP_VER2_MUX_MAX]; }; @@ -128,6 +129,7 @@ static int cam_vfe_top_set_axi_bw_vote( bool start_stop) { struct cam_axi_vote sum = {0, 0}; + struct cam_axi_vote to_be_applied_axi_vote = {0, 0}; int i, rc = 0; struct cam_hw_soc_info *soc_info = top_priv->common_data.soc_info; @@ -156,6 +158,11 @@ static int cam_vfe_top_set_axi_bw_vote( sum.uncompressed_bw, sum.compressed_bw); + top_priv->last_vote[top_priv->last_counter] = sum; + top_priv->last_counter = (top_priv->last_counter + 1) % + (CAM_VFE_TOP_VER2_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); + if ((top_priv->applied_axi_vote.uncompressed_bw == sum.uncompressed_bw) && (top_priv->applied_axi_vote.compressed_bw == @@ -163,77 +170,60 @@ static int cam_vfe_top_set_axi_bw_vote( CAM_DBG(CAM_ISP, "BW config unchanged %llu %llu", top_priv->applied_axi_vote.uncompressed_bw, top_priv->applied_axi_vote.compressed_bw); - top_priv->counter_to_update_axi_vote = 0; return 0; } - if ((top_priv->to_be_applied_axi_vote.uncompressed_bw != - sum.uncompressed_bw) || - (top_priv->to_be_applied_axi_vote.compressed_bw != - sum.compressed_bw)) { - // we got a new bw value to apply - top_priv->counter_to_update_axi_vote = 0; - - top_priv->to_be_applied_axi_vote.uncompressed_bw = - sum.uncompressed_bw; - top_priv->to_be_applied_axi_vote.compressed_bw = - sum.compressed_bw; - } - if (start_stop == true) { - CAM_DBG(CAM_ISP, - "New bw in start/stop, applying bw now, counter=%d", - top_priv->counter_to_update_axi_vote); - top_priv->counter_to_update_axi_vote = 0; - apply_bw_update = true; - } else if ((top_priv->to_be_applied_axi_vote.uncompressed_bw < - top_priv->applied_axi_vote.uncompressed_bw) || - (top_priv->to_be_applied_axi_vote.compressed_bw < - top_priv->applied_axi_vote.compressed_bw)) { - if (top_priv->counter_to_update_axi_vote >= + /* need to vote current request immediately */ + to_be_applied_axi_vote = sum; + /* Reset everything, we can start afresh */ + memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) * (CAM_VFE_TOP_VER2_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)) { - CAM_DBG(CAM_ISP, - "New bw is less, applying bw now, counter=%d", - top_priv->counter_to_update_axi_vote); - top_priv->counter_to_update_axi_vote = 0; - apply_bw_update = true; - } else { - CAM_DBG(CAM_ISP, - "New bw is less, Defer applying bw, counter=%d", - top_priv->counter_to_update_axi_vote); - - top_priv->counter_to_update_axi_vote++; - apply_bw_update = false; - } + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)); + top_priv->last_counter = 0; + top_priv->last_vote[top_priv->last_counter] = sum; + top_priv->last_counter = (top_priv->last_counter + 1) % + (CAM_VFE_TOP_VER2_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); } else { - CAM_DBG(CAM_ISP, - "New bw is more, applying bw now, counter=%d", - top_priv->counter_to_update_axi_vote); - top_priv->counter_to_update_axi_vote = 0; - apply_bw_update = true; + /* + * Find max bw request in last few frames. This will the bw + *that we want to vote to CPAS now. + */ + for (i = 0; i < (CAM_VFE_TOP_VER2_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); i++) { + if (to_be_applied_axi_vote.compressed_bw < + top_priv->last_vote[i].compressed_bw) + to_be_applied_axi_vote.compressed_bw = + top_priv->last_vote[i].compressed_bw; + + if (to_be_applied_axi_vote.uncompressed_bw < + top_priv->last_vote[i].uncompressed_bw) + to_be_applied_axi_vote.uncompressed_bw = + top_priv->last_vote[i].uncompressed_bw; + } } - CAM_DBG(CAM_ISP, - "counter=%d, apply_bw_update=%d", - top_priv->counter_to_update_axi_vote, - apply_bw_update); + if ((to_be_applied_axi_vote.uncompressed_bw != + top_priv->applied_axi_vote.uncompressed_bw) || + (to_be_applied_axi_vote.compressed_bw != + top_priv->applied_axi_vote.compressed_bw)) + apply_bw_update = true; + + CAM_DBG(CAM_ISP, "apply_bw_update=%d", apply_bw_update); if (apply_bw_update == true) { rc = cam_cpas_update_axi_vote( soc_private->cpas_handle, - &top_priv->to_be_applied_axi_vote); + &to_be_applied_axi_vote); if (!rc) { top_priv->applied_axi_vote.uncompressed_bw = - top_priv-> - to_be_applied_axi_vote.uncompressed_bw; + to_be_applied_axi_vote.uncompressed_bw; top_priv->applied_axi_vote.compressed_bw = - top_priv-> to_be_applied_axi_vote.compressed_bw; } else { CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc); } - top_priv->counter_to_update_axi_vote = 0; } return rc; @@ -706,11 +696,12 @@ int cam_vfe_top_ver2_init( } vfe_top->top_priv = top_priv; top_priv->hw_clk_rate = 0; - top_priv->to_be_applied_axi_vote.compressed_bw = 0; - top_priv->to_be_applied_axi_vote.uncompressed_bw = 0; top_priv->applied_axi_vote.compressed_bw = 0; top_priv->applied_axi_vote.uncompressed_bw = 0; - top_priv->counter_to_update_axi_vote = 0; + memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) * + (CAM_VFE_TOP_VER2_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)); + top_priv->last_counter = 0; for (i = 0, j = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { top_priv->mux_rsrc[i].res_type = CAM_ISP_RESOURCE_VFE_IN; -- GitLab From 754479ca3de0bf4405fa8f177b2bbd22827d9840 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 4 Jun 2018 14:52:42 -0700 Subject: [PATCH 691/855] msm: camera: smmu: Handle driver probe failure As part of the driver probe if we fail to populate arm smmu context banks this change will deallocate the memory for these banks and set the context bank count to zero. Change-Id: I642c69d2189954a21cb00b512ebf035c094efe68 Signed-off-by: Karthik Anantha Ram --- drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c index 0d03df0b48ed..c46ebe4d6f62 100644 --- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c @@ -3333,6 +3333,7 @@ static int cam_smmu_probe(struct platform_device *pdev) rc = cam_populate_smmu_context_banks(dev, CAM_ARM_SMMU); if (rc < 0) { CAM_ERR(CAM_SMMU, "Error: populating context banks"); + cam_smmu_release_cb(pdev); return -ENOMEM; } return rc; -- GitLab From c1597fe2f288c0edd85cf2ddf10b6542c269d5f4 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Mon, 4 Jun 2018 14:23:56 -0700 Subject: [PATCH 692/855] Revert "of: Make CONFIG_OF_KOBJ configurable" This reverts commit 27a4b773d5b47cd2ab871e62366b6b1e3709dba6. Needed to reapply patch with correct author. Change-Id: Idc60caea86f71486fbde3d89548599160bb6c41a Signed-off-by: Patrick Daly --- arch/arm/configs/msm8953-batcam-perf_defconfig | 1 - arch/arm/configs/msm8953-batcam_defconfig | 1 - drivers/of/Kconfig | 6 ------ 3 files changed, 8 deletions(-) diff --git a/arch/arm/configs/msm8953-batcam-perf_defconfig b/arch/arm/configs/msm8953-batcam-perf_defconfig index 5b886a825e5a..0ced38902ebd 100644 --- a/arch/arm/configs/msm8953-batcam-perf_defconfig +++ b/arch/arm/configs/msm8953-batcam-perf_defconfig @@ -77,7 +77,6 @@ CONFIG_NET=y CONFIG_UNIX=y CONFIG_INET=y CONFIG_DMA_CMA=y -# CONFIG_OF_KOBJ is not set CONFIG_QSEECOM=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y diff --git a/arch/arm/configs/msm8953-batcam_defconfig b/arch/arm/configs/msm8953-batcam_defconfig index dc6688c79b6b..892b234c7a9e 100644 --- a/arch/arm/configs/msm8953-batcam_defconfig +++ b/arch/arm/configs/msm8953-batcam_defconfig @@ -76,7 +76,6 @@ CONFIG_NET=y CONFIG_UNIX=y CONFIG_INET=y CONFIG_DMA_CMA=y -# CONFIG_OF_KOBJ is not set CONFIG_QSEECOM=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 0a963b179105..e4304e70a6d3 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -47,13 +47,7 @@ config OF_PROMTREE bool config OF_KOBJ - bool "Display devicetree in sysfs" def_bool SYSFS - help - Some embedded platforms have no need to display the devicetree - nodes and properties in sysfs. Disabling this option will save - a small amount of memory, as well as decrease boot time. By - default this option will be enabled if SYSFS is enabled. # Hardly any platforms need this. It is safe to select, but only do so if you # need it. -- GitLab From e37510f31bfe70e9dd31f5057662975b41a4e719 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Mon, 4 Jun 2018 14:24:20 -0700 Subject: [PATCH 693/855] Revert "of: make kobject and bin_attribute support configurable" This reverts commit fc00691916c11b7931e076c10236e8e4f21702ac. Needed to reapply patch with correct author. Change-Id: Ie78728b51c1d62157c68383f536ad4d4cd20b998 Signed-off-by: Patrick Daly --- drivers/of/Kconfig | 4 - drivers/of/Makefile | 1 - drivers/of/base.c | 133 ++++++++++++++++++++++++++++++++ drivers/of/dynamic.c | 22 ++++++ drivers/of/kobj.c | 165 ---------------------------------------- drivers/of/of_private.h | 23 ------ include/linux/of.h | 22 +++--- 7 files changed, 167 insertions(+), 203 deletions(-) delete mode 100644 drivers/of/kobj.c diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index e4304e70a6d3..52a297d5560a 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -46,14 +46,10 @@ config OF_EARLY_FLATTREE config OF_PROMTREE bool -config OF_KOBJ - def_bool SYSFS - # Hardly any platforms need this. It is safe to select, but only do so if you # need it. config OF_DYNAMIC bool "Support for dynamic device trees" if OF_UNITTEST - select OF_KOBJ help On some platforms, the device tree can be manipulated at runtime. While this option is selected automatically on such platforms, you diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 760b730347d2..b2f474a8f5be 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,5 +1,4 @@ obj-y = base.o device.o platform.o -obj-$(CONFIG_OF_KOBJ) += kobj.o obj-$(CONFIG_OF_DYNAMIC) += dynamic.o obj-$(CONFIG_OF_FLATTREE) += fdt.o obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o diff --git a/drivers/of/base.c b/drivers/of/base.c index 0dc31cfe1526..23a6d36a69af 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -98,6 +98,108 @@ int __weak of_node_to_nid(struct device_node *np) } #endif +#ifndef CONFIG_OF_DYNAMIC +static void of_node_release(struct kobject *kobj) +{ + /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ +} +#endif /* CONFIG_OF_DYNAMIC */ + +struct kobj_type of_node_ktype = { + .release = of_node_release, +}; + +static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t offset, size_t count) +{ + struct property *pp = container_of(bin_attr, struct property, attr); + return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length); +} + +/* always return newly allocated name, caller must free after use */ +static const char *safe_name(struct kobject *kobj, const char *orig_name) +{ + const char *name = orig_name; + struct kernfs_node *kn; + int i = 0; + + /* don't be a hero. After 16 tries give up */ + while (i < 16 && (kn = sysfs_get_dirent(kobj->sd, name))) { + sysfs_put(kn); + if (name != orig_name) + kfree(name); + name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i); + } + + if (name == orig_name) { + name = kstrdup(orig_name, GFP_KERNEL); + } else { + pr_warn("Duplicate name in %s, renamed to \"%s\"\n", + kobject_name(kobj), name); + } + return name; +} + +int __of_add_property_sysfs(struct device_node *np, struct property *pp) +{ + int rc; + + /* Important: Don't leak passwords */ + bool secure = strncmp(pp->name, "security-", 9) == 0; + + if (!IS_ENABLED(CONFIG_SYSFS)) + return 0; + + if (!of_kset || !of_node_is_attached(np)) + return 0; + + sysfs_bin_attr_init(&pp->attr); + pp->attr.attr.name = safe_name(&np->kobj, pp->name); + pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO; + pp->attr.size = secure ? 0 : pp->length; + pp->attr.read = of_node_property_read; + + rc = sysfs_create_bin_file(&np->kobj, &pp->attr); + WARN(rc, "error adding attribute %s to node %s\n", pp->name, np->full_name); + return rc; +} + +int __of_attach_node_sysfs(struct device_node *np) +{ + const char *name; + struct kobject *parent; + struct property *pp; + int rc; + + if (!IS_ENABLED(CONFIG_SYSFS)) + return 0; + + if (!of_kset) + return 0; + + np->kobj.kset = of_kset; + if (!np->parent) { + /* Nodes without parents are new top level trees */ + name = safe_name(&of_kset->kobj, "base"); + parent = NULL; + } else { + name = safe_name(&np->parent->kobj, kbasename(np->full_name)); + parent = &np->parent->kobj; + } + if (!name) + return -ENOMEM; + rc = kobject_add(&np->kobj, parent, "%s", name); + kfree(name); + if (rc) + return rc; + + for_each_property_of_node(np, pp) + __of_add_property_sysfs(np, pp); + + return 0; +} + static struct device_node **phandle_cache; static u32 phandle_cache_mask; @@ -1919,6 +2021,22 @@ int __of_remove_property(struct device_node *np, struct property *prop) return 0; } +void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop) +{ + sysfs_remove_bin_file(&np->kobj, &prop->attr); + kfree(prop->attr.attr.name); +} + +void __of_remove_property_sysfs(struct device_node *np, struct property *prop) +{ + if (!IS_ENABLED(CONFIG_SYSFS)) + return; + + /* at early boot, bail here and defer setup to of_init() */ + if (of_kset && of_node_is_attached(np)) + __of_sysfs_remove_bin_file(np, prop); +} + /** * of_remove_property - Remove a property from a node. * @@ -1978,6 +2096,21 @@ int __of_update_property(struct device_node *np, struct property *newprop, return 0; } +void __of_update_property_sysfs(struct device_node *np, struct property *newprop, + struct property *oldprop) +{ + if (!IS_ENABLED(CONFIG_SYSFS)) + return; + + /* At early boot, bail out and defer setup to of_init() */ + if (!of_kset) + return; + + if (oldprop) + __of_sysfs_remove_bin_file(np, oldprop); + __of_add_property_sysfs(np, newprop); +} + /* * of_update_property - Update a property in a node, if the property does * not exist, add it. diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index 765ba6e996a7..dc91a1b4c78c 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -48,6 +48,28 @@ void of_node_put(struct device_node *node) } EXPORT_SYMBOL(of_node_put); +void __of_detach_node_sysfs(struct device_node *np) +{ + struct property *pp; + + if (!IS_ENABLED(CONFIG_SYSFS)) + return; + + BUG_ON(!of_node_is_initialized(np)); + if (!of_kset) + return; + + /* only remove properties if on sysfs */ + if (of_node_is_attached(np)) { + for_each_property_of_node(np, pp) + __of_sysfs_remove_bin_file(np, pp); + kobject_del(&np->kobj); + } + + /* finally remove the kobj_init ref */ + of_node_put(np); +} + static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); int of_reconfig_notifier_register(struct notifier_block *nb) diff --git a/drivers/of/kobj.c b/drivers/of/kobj.c deleted file mode 100644 index 662f79e04bea..000000000000 --- a/drivers/of/kobj.c +++ /dev/null @@ -1,165 +0,0 @@ -#include -#include - -#include "of_private.h" - -/* true when node is initialized */ -static int of_node_is_initialized(struct device_node *node) -{ - return node && node->kobj.state_initialized; -} - -/* true when node is attached (i.e. present on sysfs) */ -int of_node_is_attached(struct device_node *node) -{ - return node && node->kobj.state_in_sysfs; -} - - -#ifndef CONFIG_OF_DYNAMIC -static void of_node_release(struct kobject *kobj) -{ - /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ -} -#endif /* CONFIG_OF_DYNAMIC */ - -struct kobj_type of_node_ktype = { - .release = of_node_release, -}; - -static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, - loff_t offset, size_t count) -{ - struct property *pp = container_of(bin_attr, struct property, attr); - return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length); -} - -/* always return newly allocated name, caller must free after use */ -static const char *safe_name(struct kobject *kobj, const char *orig_name) -{ - const char *name = orig_name; - struct kernfs_node *kn; - int i = 0; - - /* don't be a hero. After 16 tries give up */ - while (i < 16 && name && (kn = sysfs_get_dirent(kobj->sd, name))) { - sysfs_put(kn); - if (name != orig_name) - kfree(name); - name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i); - } - - if (name == orig_name) { - name = kstrdup(orig_name, GFP_KERNEL); - } else { - pr_warn("Duplicate name in %s, renamed to \"%s\"\n", - kobject_name(kobj), name); - } - return name; -} - -int __of_add_property_sysfs(struct device_node *np, struct property *pp) -{ - int rc; - - /* Important: Don't leak passwords */ - bool secure = strncmp(pp->name, "security-", 9) == 0; - - if (!IS_ENABLED(CONFIG_SYSFS)) - return 0; - - if (!of_kset || !of_node_is_attached(np)) - return 0; - - sysfs_bin_attr_init(&pp->attr); - pp->attr.attr.name = safe_name(&np->kobj, pp->name); - pp->attr.attr.mode = secure ? 0400 : 0444; - pp->attr.size = secure ? 0 : pp->length; - pp->attr.read = of_node_property_read; - - rc = sysfs_create_bin_file(&np->kobj, &pp->attr); - WARN(rc, "error adding attribute %s to node %s\n", pp->name, - np->full_name); - return rc; -} - -void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop) -{ - if (!IS_ENABLED(CONFIG_SYSFS)) - return; - - sysfs_remove_bin_file(&np->kobj, &prop->attr); - kfree(prop->attr.attr.name); -} - -void __of_remove_property_sysfs(struct device_node *np, struct property *prop) -{ - /* at early boot, bail here and defer setup to of_init() */ - if (of_kset && of_node_is_attached(np)) - __of_sysfs_remove_bin_file(np, prop); -} - -void __of_update_property_sysfs(struct device_node *np, struct property *newprop, - struct property *oldprop) -{ - /* At early boot, bail out and defer setup to of_init() */ - if (!of_kset) - return; - - if (oldprop) - __of_sysfs_remove_bin_file(np, oldprop); - __of_add_property_sysfs(np, newprop); -} - -int __of_attach_node_sysfs(struct device_node *np) -{ - const char *name; - struct kobject *parent; - struct property *pp; - int rc; - - if (!of_kset) - return 0; - - np->kobj.kset = of_kset; - if (!np->parent) { - /* Nodes without parents are new top level trees */ - name = safe_name(&of_kset->kobj, "base"); - parent = NULL; - } else { - name = safe_name(&np->parent->kobj, kbasename(np->full_name)); - parent = &np->parent->kobj; - } - if (!name) - return -ENOMEM; - rc = kobject_add(&np->kobj, parent, "%s", name); - kfree(name); - if (rc) - return rc; - - for_each_property_of_node(np, pp) - __of_add_property_sysfs(np, pp); - - return 0; -} - -void __of_detach_node_sysfs(struct device_node *np) -{ - struct property *pp; - - BUG_ON(!of_node_is_initialized(np)); - if (!of_kset) - return; - - /* only remove properties if on sysfs */ - if (of_node_is_attached(np)) { - for_each_property_of_node(np, pp) - __of_sysfs_remove_bin_file(np, pp); - kobject_del(&np->kobj); - } - - /* finally remove the kobj_init ref */ - of_node_put(np); -} - diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index eb811185448c..61acd6bbd1aa 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -49,29 +49,6 @@ static inline int of_property_notify(int action, struct device_node *np, } #endif /* CONFIG_OF_DYNAMIC */ -#if defined(CONFIG_OF_KOBJ) -int of_node_is_attached(struct device_node *node); -int __of_add_property_sysfs(struct device_node *np, struct property *pp); -void __of_remove_property_sysfs(struct device_node *np, struct property *prop); -void __of_update_property_sysfs(struct device_node *np, struct property *newprop, - struct property *oldprop); -int __of_attach_node_sysfs(struct device_node *np); -void __of_detach_node_sysfs(struct device_node *np); -#else -static inline int __of_add_property_sysfs(struct device_node *np, struct property *pp) -{ - return 0; -} -static inline void __of_remove_property_sysfs(struct device_node *np, struct property *prop) {} -static inline void __of_update_property_sysfs(struct device_node *np, - struct property *newprop, struct property *oldprop) {} -static inline int __of_attach_node_sysfs(struct device_node *np) -{ - return 0; -} -static inline void __of_detach_node_sysfs(struct device_node *np) {} -#endif - /** * General utilities for working with live trees. * diff --git a/include/linux/of.h b/include/linux/of.h index e44e9a33ebae..3dcf853c4b14 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -39,9 +39,7 @@ struct property { struct property *next; unsigned long _flags; unsigned int unique_id; -#if defined(CONFIG_OF_KOBJ) struct bin_attribute attr; -#endif }; #if defined(CONFIG_SPARC) @@ -60,9 +58,7 @@ struct device_node { struct device_node *parent; struct device_node *child; struct device_node *sibling; -#if defined(CONFIG_OF_KOBJ) struct kobject kobj; -#endif unsigned long _flags; void *data; #if defined(CONFIG_SPARC) @@ -106,17 +102,23 @@ struct of_reconfig_data { extern struct kobj_type of_node_ktype; static inline void of_node_init(struct device_node *node) { -#if defined(CONFIG_OF_KOBJ) kobject_init(&node->kobj, &of_node_ktype); -#endif node->fwnode.type = FWNODE_OF; } -#if defined(CONFIG_OF_KOBJ) #define of_node_kobj(n) (&(n)->kobj) -#else -#define of_node_kobj(n) NULL -#endif + +/* true when node is initialized */ +static inline int of_node_is_initialized(struct device_node *node) +{ + return node && node->kobj.state_initialized; +} + +/* true when node is attached (i.e. present on sysfs) */ +static inline int of_node_is_attached(struct device_node *node) +{ + return node && node->kobj.state_in_sysfs; +} #ifdef CONFIG_OF_DYNAMIC extern struct device_node *of_node_get(struct device_node *node); -- GitLab From c8650716321c9f5a7911de9581c5708ce46f4ffe Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 4 Oct 2017 14:09:40 -0500 Subject: [PATCH 694/855] of: make kobject and bin_attribute support configurable Having device_nodes be kobjects is only needed if sysfs or OF_DYNAMIC is enabled. Otherwise, having a kobject in struct device_node is unnecessary bloat in minimal kernel configurations. Likewise, bin_attribute is only needed in struct property when sysfs is enabled, so we can make it configurable too. Change-Id: I94f7f67c24980a424bb7dc725174fed9ac55ea4f Tested-by: Nicolas Pitre Reviewed-by: Frank Rowand Acked-by: Grant Likely Signed-off-by: Rob Herring Git-Commit: b56b5528f5b3c3d47e7c0ca67318c45e980d93f0 Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git [pdaly: removed %pOF printf format as it is not backported added NULL check in safe_name()] Signed-off-by: Patrick Daly --- drivers/of/Kconfig | 4 + drivers/of/Makefile | 1 + drivers/of/base.c | 133 -------------------------------- drivers/of/dynamic.c | 22 ------ drivers/of/kobj.c | 165 ++++++++++++++++++++++++++++++++++++++++ drivers/of/of_private.h | 23 ++++++ include/linux/of.h | 22 +++--- 7 files changed, 203 insertions(+), 167 deletions(-) create mode 100644 drivers/of/kobj.c diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 52a297d5560a..e4304e70a6d3 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -46,10 +46,14 @@ config OF_EARLY_FLATTREE config OF_PROMTREE bool +config OF_KOBJ + def_bool SYSFS + # Hardly any platforms need this. It is safe to select, but only do so if you # need it. config OF_DYNAMIC bool "Support for dynamic device trees" if OF_UNITTEST + select OF_KOBJ help On some platforms, the device tree can be manipulated at runtime. While this option is selected automatically on such platforms, you diff --git a/drivers/of/Makefile b/drivers/of/Makefile index b2f474a8f5be..760b730347d2 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,4 +1,5 @@ obj-y = base.o device.o platform.o +obj-$(CONFIG_OF_KOBJ) += kobj.o obj-$(CONFIG_OF_DYNAMIC) += dynamic.o obj-$(CONFIG_OF_FLATTREE) += fdt.o obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o diff --git a/drivers/of/base.c b/drivers/of/base.c index 23a6d36a69af..0dc31cfe1526 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -98,108 +98,6 @@ int __weak of_node_to_nid(struct device_node *np) } #endif -#ifndef CONFIG_OF_DYNAMIC -static void of_node_release(struct kobject *kobj) -{ - /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ -} -#endif /* CONFIG_OF_DYNAMIC */ - -struct kobj_type of_node_ktype = { - .release = of_node_release, -}; - -static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, - loff_t offset, size_t count) -{ - struct property *pp = container_of(bin_attr, struct property, attr); - return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length); -} - -/* always return newly allocated name, caller must free after use */ -static const char *safe_name(struct kobject *kobj, const char *orig_name) -{ - const char *name = orig_name; - struct kernfs_node *kn; - int i = 0; - - /* don't be a hero. After 16 tries give up */ - while (i < 16 && (kn = sysfs_get_dirent(kobj->sd, name))) { - sysfs_put(kn); - if (name != orig_name) - kfree(name); - name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i); - } - - if (name == orig_name) { - name = kstrdup(orig_name, GFP_KERNEL); - } else { - pr_warn("Duplicate name in %s, renamed to \"%s\"\n", - kobject_name(kobj), name); - } - return name; -} - -int __of_add_property_sysfs(struct device_node *np, struct property *pp) -{ - int rc; - - /* Important: Don't leak passwords */ - bool secure = strncmp(pp->name, "security-", 9) == 0; - - if (!IS_ENABLED(CONFIG_SYSFS)) - return 0; - - if (!of_kset || !of_node_is_attached(np)) - return 0; - - sysfs_bin_attr_init(&pp->attr); - pp->attr.attr.name = safe_name(&np->kobj, pp->name); - pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO; - pp->attr.size = secure ? 0 : pp->length; - pp->attr.read = of_node_property_read; - - rc = sysfs_create_bin_file(&np->kobj, &pp->attr); - WARN(rc, "error adding attribute %s to node %s\n", pp->name, np->full_name); - return rc; -} - -int __of_attach_node_sysfs(struct device_node *np) -{ - const char *name; - struct kobject *parent; - struct property *pp; - int rc; - - if (!IS_ENABLED(CONFIG_SYSFS)) - return 0; - - if (!of_kset) - return 0; - - np->kobj.kset = of_kset; - if (!np->parent) { - /* Nodes without parents are new top level trees */ - name = safe_name(&of_kset->kobj, "base"); - parent = NULL; - } else { - name = safe_name(&np->parent->kobj, kbasename(np->full_name)); - parent = &np->parent->kobj; - } - if (!name) - return -ENOMEM; - rc = kobject_add(&np->kobj, parent, "%s", name); - kfree(name); - if (rc) - return rc; - - for_each_property_of_node(np, pp) - __of_add_property_sysfs(np, pp); - - return 0; -} - static struct device_node **phandle_cache; static u32 phandle_cache_mask; @@ -2021,22 +1919,6 @@ int __of_remove_property(struct device_node *np, struct property *prop) return 0; } -void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop) -{ - sysfs_remove_bin_file(&np->kobj, &prop->attr); - kfree(prop->attr.attr.name); -} - -void __of_remove_property_sysfs(struct device_node *np, struct property *prop) -{ - if (!IS_ENABLED(CONFIG_SYSFS)) - return; - - /* at early boot, bail here and defer setup to of_init() */ - if (of_kset && of_node_is_attached(np)) - __of_sysfs_remove_bin_file(np, prop); -} - /** * of_remove_property - Remove a property from a node. * @@ -2096,21 +1978,6 @@ int __of_update_property(struct device_node *np, struct property *newprop, return 0; } -void __of_update_property_sysfs(struct device_node *np, struct property *newprop, - struct property *oldprop) -{ - if (!IS_ENABLED(CONFIG_SYSFS)) - return; - - /* At early boot, bail out and defer setup to of_init() */ - if (!of_kset) - return; - - if (oldprop) - __of_sysfs_remove_bin_file(np, oldprop); - __of_add_property_sysfs(np, newprop); -} - /* * of_update_property - Update a property in a node, if the property does * not exist, add it. diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index dc91a1b4c78c..765ba6e996a7 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -48,28 +48,6 @@ void of_node_put(struct device_node *node) } EXPORT_SYMBOL(of_node_put); -void __of_detach_node_sysfs(struct device_node *np) -{ - struct property *pp; - - if (!IS_ENABLED(CONFIG_SYSFS)) - return; - - BUG_ON(!of_node_is_initialized(np)); - if (!of_kset) - return; - - /* only remove properties if on sysfs */ - if (of_node_is_attached(np)) { - for_each_property_of_node(np, pp) - __of_sysfs_remove_bin_file(np, pp); - kobject_del(&np->kobj); - } - - /* finally remove the kobj_init ref */ - of_node_put(np); -} - static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); int of_reconfig_notifier_register(struct notifier_block *nb) diff --git a/drivers/of/kobj.c b/drivers/of/kobj.c new file mode 100644 index 000000000000..662f79e04bea --- /dev/null +++ b/drivers/of/kobj.c @@ -0,0 +1,165 @@ +#include +#include + +#include "of_private.h" + +/* true when node is initialized */ +static int of_node_is_initialized(struct device_node *node) +{ + return node && node->kobj.state_initialized; +} + +/* true when node is attached (i.e. present on sysfs) */ +int of_node_is_attached(struct device_node *node) +{ + return node && node->kobj.state_in_sysfs; +} + + +#ifndef CONFIG_OF_DYNAMIC +static void of_node_release(struct kobject *kobj) +{ + /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ +} +#endif /* CONFIG_OF_DYNAMIC */ + +struct kobj_type of_node_ktype = { + .release = of_node_release, +}; + +static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t offset, size_t count) +{ + struct property *pp = container_of(bin_attr, struct property, attr); + return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length); +} + +/* always return newly allocated name, caller must free after use */ +static const char *safe_name(struct kobject *kobj, const char *orig_name) +{ + const char *name = orig_name; + struct kernfs_node *kn; + int i = 0; + + /* don't be a hero. After 16 tries give up */ + while (i < 16 && name && (kn = sysfs_get_dirent(kobj->sd, name))) { + sysfs_put(kn); + if (name != orig_name) + kfree(name); + name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i); + } + + if (name == orig_name) { + name = kstrdup(orig_name, GFP_KERNEL); + } else { + pr_warn("Duplicate name in %s, renamed to \"%s\"\n", + kobject_name(kobj), name); + } + return name; +} + +int __of_add_property_sysfs(struct device_node *np, struct property *pp) +{ + int rc; + + /* Important: Don't leak passwords */ + bool secure = strncmp(pp->name, "security-", 9) == 0; + + if (!IS_ENABLED(CONFIG_SYSFS)) + return 0; + + if (!of_kset || !of_node_is_attached(np)) + return 0; + + sysfs_bin_attr_init(&pp->attr); + pp->attr.attr.name = safe_name(&np->kobj, pp->name); + pp->attr.attr.mode = secure ? 0400 : 0444; + pp->attr.size = secure ? 0 : pp->length; + pp->attr.read = of_node_property_read; + + rc = sysfs_create_bin_file(&np->kobj, &pp->attr); + WARN(rc, "error adding attribute %s to node %s\n", pp->name, + np->full_name); + return rc; +} + +void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop) +{ + if (!IS_ENABLED(CONFIG_SYSFS)) + return; + + sysfs_remove_bin_file(&np->kobj, &prop->attr); + kfree(prop->attr.attr.name); +} + +void __of_remove_property_sysfs(struct device_node *np, struct property *prop) +{ + /* at early boot, bail here and defer setup to of_init() */ + if (of_kset && of_node_is_attached(np)) + __of_sysfs_remove_bin_file(np, prop); +} + +void __of_update_property_sysfs(struct device_node *np, struct property *newprop, + struct property *oldprop) +{ + /* At early boot, bail out and defer setup to of_init() */ + if (!of_kset) + return; + + if (oldprop) + __of_sysfs_remove_bin_file(np, oldprop); + __of_add_property_sysfs(np, newprop); +} + +int __of_attach_node_sysfs(struct device_node *np) +{ + const char *name; + struct kobject *parent; + struct property *pp; + int rc; + + if (!of_kset) + return 0; + + np->kobj.kset = of_kset; + if (!np->parent) { + /* Nodes without parents are new top level trees */ + name = safe_name(&of_kset->kobj, "base"); + parent = NULL; + } else { + name = safe_name(&np->parent->kobj, kbasename(np->full_name)); + parent = &np->parent->kobj; + } + if (!name) + return -ENOMEM; + rc = kobject_add(&np->kobj, parent, "%s", name); + kfree(name); + if (rc) + return rc; + + for_each_property_of_node(np, pp) + __of_add_property_sysfs(np, pp); + + return 0; +} + +void __of_detach_node_sysfs(struct device_node *np) +{ + struct property *pp; + + BUG_ON(!of_node_is_initialized(np)); + if (!of_kset) + return; + + /* only remove properties if on sysfs */ + if (of_node_is_attached(np)) { + for_each_property_of_node(np, pp) + __of_sysfs_remove_bin_file(np, pp); + kobject_del(&np->kobj); + } + + /* finally remove the kobj_init ref */ + of_node_put(np); +} + diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index 61acd6bbd1aa..eb811185448c 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -49,6 +49,29 @@ static inline int of_property_notify(int action, struct device_node *np, } #endif /* CONFIG_OF_DYNAMIC */ +#if defined(CONFIG_OF_KOBJ) +int of_node_is_attached(struct device_node *node); +int __of_add_property_sysfs(struct device_node *np, struct property *pp); +void __of_remove_property_sysfs(struct device_node *np, struct property *prop); +void __of_update_property_sysfs(struct device_node *np, struct property *newprop, + struct property *oldprop); +int __of_attach_node_sysfs(struct device_node *np); +void __of_detach_node_sysfs(struct device_node *np); +#else +static inline int __of_add_property_sysfs(struct device_node *np, struct property *pp) +{ + return 0; +} +static inline void __of_remove_property_sysfs(struct device_node *np, struct property *prop) {} +static inline void __of_update_property_sysfs(struct device_node *np, + struct property *newprop, struct property *oldprop) {} +static inline int __of_attach_node_sysfs(struct device_node *np) +{ + return 0; +} +static inline void __of_detach_node_sysfs(struct device_node *np) {} +#endif + /** * General utilities for working with live trees. * diff --git a/include/linux/of.h b/include/linux/of.h index 3dcf853c4b14..e44e9a33ebae 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -39,7 +39,9 @@ struct property { struct property *next; unsigned long _flags; unsigned int unique_id; +#if defined(CONFIG_OF_KOBJ) struct bin_attribute attr; +#endif }; #if defined(CONFIG_SPARC) @@ -58,7 +60,9 @@ struct device_node { struct device_node *parent; struct device_node *child; struct device_node *sibling; +#if defined(CONFIG_OF_KOBJ) struct kobject kobj; +#endif unsigned long _flags; void *data; #if defined(CONFIG_SPARC) @@ -102,23 +106,17 @@ struct of_reconfig_data { extern struct kobj_type of_node_ktype; static inline void of_node_init(struct device_node *node) { +#if defined(CONFIG_OF_KOBJ) kobject_init(&node->kobj, &of_node_ktype); +#endif node->fwnode.type = FWNODE_OF; } +#if defined(CONFIG_OF_KOBJ) #define of_node_kobj(n) (&(n)->kobj) - -/* true when node is initialized */ -static inline int of_node_is_initialized(struct device_node *node) -{ - return node && node->kobj.state_initialized; -} - -/* true when node is attached (i.e. present on sysfs) */ -static inline int of_node_is_attached(struct device_node *node) -{ - return node && node->kobj.state_in_sysfs; -} +#else +#define of_node_kobj(n) NULL +#endif #ifdef CONFIG_OF_DYNAMIC extern struct device_node *of_node_get(struct device_node *node); -- GitLab From 70a9d895b17036ab8e041d452645565a7530a297 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Fri, 25 May 2018 12:38:25 -0700 Subject: [PATCH 695/855] of: Make CONFIG_OF_KOBJ configurable Add help text in order to allow this option to be selectable from menuconfig. Change-Id: I5755037ba3488fc1eff83d68148c5b417d6fccb9 Signed-off-by: Patrick Daly --- drivers/of/Kconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index e4304e70a6d3..0a963b179105 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -47,7 +47,13 @@ config OF_PROMTREE bool config OF_KOBJ + bool "Display devicetree in sysfs" def_bool SYSFS + help + Some embedded platforms have no need to display the devicetree + nodes and properties in sysfs. Disabling this option will save + a small amount of memory, as well as decrease boot time. By + default this option will be enabled if SYSFS is enabled. # Hardly any platforms need this. It is safe to select, but only do so if you # need it. -- GitLab From 2a9878c42d19df721866022f4d1d8c049552464e Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Wed, 16 May 2018 19:16:40 -0700 Subject: [PATCH 696/855] defconfig: msm8953-batcam: Enable performance optimizations Disabling CONFIG_OF_KOBJ causes no sysfs entries to be created for devicetree nodes or properties. Change-Id: I7c6be6dbac9ef7f7f6cc629154ec36456da71133 Signed-off-by: Patrick Daly --- arch/arm/configs/msm8953-batcam-perf_defconfig | 1 + arch/arm/configs/msm8953-batcam_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/msm8953-batcam-perf_defconfig b/arch/arm/configs/msm8953-batcam-perf_defconfig index 0ced38902ebd..5b886a825e5a 100644 --- a/arch/arm/configs/msm8953-batcam-perf_defconfig +++ b/arch/arm/configs/msm8953-batcam-perf_defconfig @@ -77,6 +77,7 @@ CONFIG_NET=y CONFIG_UNIX=y CONFIG_INET=y CONFIG_DMA_CMA=y +# CONFIG_OF_KOBJ is not set CONFIG_QSEECOM=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y diff --git a/arch/arm/configs/msm8953-batcam_defconfig b/arch/arm/configs/msm8953-batcam_defconfig index 892b234c7a9e..dc6688c79b6b 100644 --- a/arch/arm/configs/msm8953-batcam_defconfig +++ b/arch/arm/configs/msm8953-batcam_defconfig @@ -76,6 +76,7 @@ CONFIG_NET=y CONFIG_UNIX=y CONFIG_INET=y CONFIG_DMA_CMA=y +# CONFIG_OF_KOBJ is not set CONFIG_QSEECOM=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y -- GitLab From 9910e89b27224fbddbf7d15d307597e13d9b9258 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Mon, 4 Jun 2018 16:17:33 -0700 Subject: [PATCH 697/855] msm: camera: context: Add null check on context pointer Check for context pointer being null, before accessing its members. Change-Id: I778c44e743edddcddf0f2fd6fd49336dfe00baf0 Signed-off-by: Vishalsingh Hajeri --- drivers/media/platform/msm/camera/cam_core/cam_context.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.c b/drivers/media/platform/msm/camera/cam_core/cam_context.c index 8beffc4903fa..891b73872e23 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_context.c +++ b/drivers/media/platform/msm/camera/cam_core/cam_context.c @@ -355,7 +355,7 @@ int cam_context_handle_start_dev(struct cam_context *ctx, { int rc = 0; - if (!ctx->state_machine) { + if (!ctx || !ctx->state_machine) { CAM_ERR(CAM_CORE, "Context is not ready"); return -EINVAL; } @@ -384,7 +384,7 @@ int cam_context_handle_stop_dev(struct cam_context *ctx, { int rc = 0; - if (!ctx->state_machine) { + if (!ctx || !ctx->state_machine) { CAM_ERR(CAM_CORE, "Context is not ready"); return -EINVAL; } -- GitLab From c7ab2215a4208126abcb43738f371e0f09d2e45b Mon Sep 17 00:00:00 2001 From: Gan Guo Date: Fri, 11 May 2018 09:29:58 +0800 Subject: [PATCH 698/855] ARM: dts: msm: add fpc1028 dtsi config for QRD439 Add pinctrl, gpio, irq, rst settings for fpc fingerprint sensor for sdm439 QRD device. Change-Id: I058ee8b6fce53511de455c1b0ea2e9ecac6e1f5a Signed-off-by: Gan Guo --- arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi | 82 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi | 18 ++++ 2 files changed, 100 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi index 86e41a31b3de..a730287332e8 100644 --- a/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi @@ -319,6 +319,88 @@ }; }; + spi7 { + spi7_default: spi7_default { + mux { + pins = "gpio85", "gpio86", "gpio88"; + function = "blsp_spi7"; + }; + + config { + pins = "gpio85", "gpio86", "gpio88"; + drive-strength = <16>; + bias-disable = <0>; + }; + }; + + spi7_sleep: spi7_sleep { + mux { + pins = "gpio85", "gpio86", "gpio88"; + function = "blsp_spi7"; + }; + + config { + pins = "gpio85", "gpio86", "gpio88"; + drive-strength = <16>; + bias-disable = <0>; + }; + }; + spi7_cs0_active: cs0_active { + mux { + pins = "gpio87"; + function = "blsp_spi7_cs0"; + }; + + config { + pins = "gpio87"; + drive-strength = <2>; + bias-disable = <0>; + }; + }; + }; + + fpc_reset_int { + fpc_reset_low: reset_low { + mux { + pins = "gpio124"; + function = "fpc_reset_gpio_low"; + }; + + config { + pins = "gpio124"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + fpc_reset_high: reset_high { + mux { + pins = "gpio124"; + function = "fpc_reset_gpio_high"; + }; + + config { + pins = "gpio124"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + + fpc_int_low: int_low { + mux { + pins = "gpio48"; + }; + config { + pins = "gpio48"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + }; + wcnss_pmux_5wire { /* Active configuration of bus pins */ wcnss_default: wcnss_default { diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi index 5097b7f5ea58..5b3caf7b05ce 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi @@ -141,6 +141,24 @@ gpio-key,wakeup; }; }; + + fpc1020 { + compatible = "fpc,fpc1020"; + interrupt-parent = <&tlmm>; + interrupts = <48 0>; + fpc,gpio_rst = <&tlmm 124 0x0>; + fpc,gpio_irq = <&tlmm 48 0>; + vcc_spi-supply = <&pm8953_l5>; + vdd_io-supply = <&pm8953_l5>; + vdd_ana-supply = <&pm8953_l5>; + fpc,enable-on-boot; + pinctrl-names = "fpc1020_reset_reset", + "fpc1020_reset_active", + "fpc1020_irq_active"; + pinctrl-0 = <&fpc_reset_low>; + pinctrl-1 = <&fpc_reset_high>; + pinctrl-2 = <&fpc_int_low>; + }; }; &tlmm { -- GitLab From 26d71617bfa37a7eb5244c9ea0cc783e1ea39644 Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Fri, 1 Jun 2018 15:22:38 +0530 Subject: [PATCH 699/855] ARM: dts: msm: Add USB device node for 8053 APQ IOT MTP Add gpio_usbdetect node to select USB mode based on GPIO state and define pinctrl settings for the GPIO. Change-Id: Ibcb9c55207a5791153545495c102f6eaa7706471 Signed-off-by: Sriharsha Allenki --- arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts | 9 +++++++++ arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi | 14 ++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts b/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts index 9f0edda5e3ed..8782001f5cd6 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts +++ b/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts @@ -86,3 +86,12 @@ qcom,model = "msm8953-tasha-snd-card"; status = "okay"; }; + +&soc { + usb_detect: usb_detect { + compatible = "linux,extcon-usb-gpio"; + pintctrl-names = "default"; + pinctrl-0 = <&ssusb_mode_sel>; + id-gpio = <&tlmm 12 0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi index cc3c39226616..e8de4ef7cbce 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi @@ -1731,5 +1731,19 @@ bias-disable; }; }; + + ssusb_mode_sel: ssusb_mode_sel { + mux { + pins = "gpio12"; + function = "gpio"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; + bias-disable; + input-disable; + }; + }; }; }; -- GitLab From d8fedf9cbed364f4b00f3f87b3829ee4724105a7 Mon Sep 17 00:00:00 2001 From: Sundara Vinayagam Date: Wed, 16 May 2018 20:49:26 +0530 Subject: [PATCH 700/855] defconfig: msm: Remove unwanted configs for msm8909w Remove unwanted configs for msm8909w for device bootup. Change-Id: Ife316a20314e010b3baf73bb7a3a6f0968f527a9 Signed-off-by: Sundara Vinayagam --- arch/arm/configs/msm8909w_defconfig | 79 +++++------------------------ 1 file changed, 12 insertions(+), 67 deletions(-) diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index 2eb602bab1a5..3c600374239e 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -6,7 +6,6 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_SCHED_WALT=y CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y @@ -18,7 +17,6 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y @@ -29,12 +27,18 @@ CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y CONFIG_DEFAULT_USE_ENERGY_AWARE=y CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set CONFIG_PROFILING=y -CONFIG_OPROFILE=y +CONFIG_OPROFILE=m CONFIG_CC_STACKPROTECTOR_REGULAR=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -50,11 +54,11 @@ CONFIG_SMP=y CONFIG_SCHED_MC=y CONFIG_PREEMPT=y CONFIG_AEABI=y -CONFIG_HIGHMEM=y CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_PROCESS_RECLAIM=y CONFIG_SECCOMP=y CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y @@ -65,12 +69,10 @@ CONFIG_KERNEL_MODE_NEON=y CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 -CONFIG_PM_DEBUG=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM_USER=y -CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -111,14 +113,13 @@ CONFIG_NF_CT_NETLINK=y CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y CONFIG_NETFILTER_XT_TARGET_CONNMARK=y CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_CT=y CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_NETFILTER_XT_TARGET_MARK=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y @@ -128,7 +129,6 @@ CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y CONFIG_NETFILTER_XT_MATCH_DSCP=y -CONFIG_NETFILTER_XT_MATCH_ESP=y CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y CONFIG_NETFILTER_XT_MATCH_HELPER=y CONFIG_NETFILTER_XT_MATCH_IPRANGE=y @@ -150,6 +150,7 @@ CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_DUP_IPV4=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y @@ -168,14 +169,13 @@ CONFIG_IP_NF_ARPTABLES=y CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_DUP_IPV6=y CONFIG_IP6_NF_IPTABLES=y CONFIG_IP6_NF_MATCH_RPFILTER=y CONFIG_IP6_NF_FILTER=y CONFIG_IP6_NF_TARGET_REJECT=y CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y -CONFIG_BRIDGE_NF_EBTABLES=y -CONFIG_BRIDGE_EBT_BROUTE=y CONFIG_L2TP=y CONFIG_L2TP_DEBUGFS=y CONFIG_L2TP_V3=y @@ -185,8 +185,6 @@ CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_HTB=y CONFIG_NET_SCH_PRIO=y -CONFIG_NET_SCH_MULTIQ=y -CONFIG_NET_SCH_INGRESS=y CONFIG_NET_CLS_FW=y CONFIG_NET_CLS_U32=y CONFIG_CLS_U32_MARK=y @@ -199,8 +197,6 @@ CONFIG_NET_EMATCH_META=y CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y CONFIG_NET_ACT_GACT=y -CONFIG_NET_ACT_MIRRED=y -CONFIG_NET_ACT_SKBEDIT=y CONFIG_DNS_RESOLVER=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y @@ -219,26 +215,11 @@ CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y -CONFIG_MEMORY_STATE_TIME=y CONFIG_QPNP_MISC=y -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_SG=y -CONFIG_CHR_DEV_SCH=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y -CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y @@ -262,7 +243,6 @@ CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y -CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v26=y @@ -343,25 +323,7 @@ CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y CONFIG_SND_SOC=y CONFIG_UHID=y -CONFIG_HID_A4TECH=y -CONFIG_HID_APPLE=y -CONFIG_HID_BELKIN=y -CONFIG_HID_CHERRY=y -CONFIG_HID_CHICONY=y -CONFIG_HID_CYPRESS=y -CONFIG_HID_ELECOM=y -CONFIG_HID_EZKEY=y -CONFIG_HID_KENSINGTON=y -CONFIG_HID_LOGITECH=y -CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MICROSOFT=y -CONFIG_HID_MONTEREY=y -CONFIG_HID_MULTITOUCH=y -CONFIG_USB_DWC3=y -CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y @@ -369,15 +331,10 @@ CONFIG_USB_GADGET_VBUS_DRAW=500 CONFIG_USB_CI13XXX_MSM=y CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_SERIAL=y -CONFIG_USB_CONFIGFS_ACM=y CONFIG_USB_CONFIGFS_NCM=y -CONFIG_USB_CONFIGFS_ECM=y CONFIG_USB_CONFIGFS_RMNET_BAM=y -CONFIG_USB_CONFIGFS_EEM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y -CONFIG_USB_CONFIGFS_F_MTP=y -CONFIG_USB_CONFIGFS_F_PTP=y CONFIG_USB_CONFIGFS_F_ACC=y CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y CONFIG_USB_CONFIGFS_UEVENT=y @@ -386,7 +343,6 @@ CONFIG_USB_CONFIGFS_F_HID=y CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_USB_CONFIGFS_F_CCID=y -CONFIG_USB_CONFIGFS_F_GSI=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_RING_BUFFER=y @@ -477,15 +433,12 @@ CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_ECRYPT_FS=y @@ -500,15 +453,7 @@ CONFIG_PAGE_OWNER=y CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_PAGEALLOC=y -CONFIG_SLUB_DEBUG_PANIC_ON=y CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y -CONFIG_DEBUG_OBJECTS=y -CONFIG_DEBUG_OBJECTS_FREE=y -CONFIG_DEBUG_OBJECTS_TIMERS=y -CONFIG_DEBUG_OBJECTS_WORK=y -CONFIG_DEBUG_OBJECTS_RCU_HEAD=y -CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y -CONFIG_SLUB_DEBUG_ON=y CONFIG_DEBUG_KMEMLEAK=y CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y -- GitLab From 182de61679280255e9e6a847d3ac479d365e674b Mon Sep 17 00:00:00 2001 From: "Chinkit Kumar,Kirti Kumar Parmar" Date: Thu, 10 May 2018 14:36:53 +0530 Subject: [PATCH 701/855] defconfig: msm: adding few configurations for LE MSM8909 Initial snapshot of msm8909w defconfig has been taken from msm-4.9 kernel version @ commit c8d46f862919 ("defconfig: msm: Enable Blackghost PIL driver and BG features on msm8909w"). Aligining the kernel configuration of LE with msm8909w_defconfig. Enabled: CONFIG_CC_OPTIMIZE_FOR_SIZE, CONFIG_OPROFILE, CONFIG_CC_STACKPROTECTOR_REGULAR, CONFIG_PROCESS_RECLAIM, CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG, CONFIG_DIAG_CHAR, CONFIG_DIAG_USES_SMD, CONFIG_USB_CONFIGFS_NCM, CONFIG_USB_CONFIGFS_RMNET_BAM, CONFIG_USB_CONFIGFS_MASS_STORAGE, CONFIG_IPA, CONFIG_RMNET_IPA, CONFIG_MSM_TZ_SMMU, CONFIG_MSM_PIL_SSR_GENERIC, CONFIG_MSM_PIL_MSS_QDSP6V5, CONFIG_MSM_BAM_DMUX, CONFIG_CORESIGHT_LINK_AND_SINK_TMC, CONFIG_CORESIGHT_SINK_TPIU, CONFIG_CORESIGHT_SOURCE_ETM3X, CONFIG_CORESIGHT_QCOM_REPLICATOR, CONFIG_CORESIGHT_DBGUI, CONFIG_CRYPTO_DEV_QCE, CONFIG_CRYPTO_DEV_QCEDEV Disabled: CONFIG_CC_STACKPROTECTOR_STRONG, CONFIG_CRYPTO_CTR, CONFIG_CRYPTO_XTS Change-Id: I7b513479926c6c90d9c0d9600b5a0a167dccb4ff Signed-off-by: Chinkit Kumar,Kirti Kumar Parmar --- arch/arm/configs/msm8909-perf_defconfig | 31 +++++++++++++++-- arch/arm/configs/msm8909_defconfig | 46 +++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 1eaf4ffc03ce..3abf9cd133cc 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -31,13 +31,15 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set # CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y # CONFIG_MEMBARRIER is not set CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_OPROFILE=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y CONFIG_ARCH_MMAP_RND_BITS=16 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -57,6 +59,7 @@ CONFIG_HIGHMEM=y CONFIG_CMA=y CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_PROCESS_RECLAIM=y CONFIG_SECCOMP=y CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y @@ -145,6 +148,7 @@ CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -263,6 +267,7 @@ CONFIG_CNSS=y CONFIG_CNSS_SDIO=y CONFIG_CLD_HL_SDIO_CORE=y CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=y CONFIG_KEYBOARD_GPIO=y CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y @@ -272,6 +277,8 @@ CONFIG_INPUT_UINPUT=y CONFIG_SERIAL_MSM=y CONFIG_SERIAL_MSM_CONSOLE=y CONFIG_SERIAL_MSM_SMD=y +CONFIG_DIAG_CHAR=y +CONFIG_DIAG_USES_SMD=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_SMD_PKT=y @@ -350,6 +357,9 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_GADGET=y CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_GADGET=y @@ -359,6 +369,9 @@ CONFIG_USB_GADGET_VBUS_DRAW=500 CONFIG_USB_CI13XXX_MSM=y CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_RMNET_BAM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y CONFIG_USB_CONFIGFS_UEVENT=y CONFIG_USB_CONFIGFS_F_DIAG=y @@ -391,6 +404,8 @@ CONFIG_ASHMEM=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_ION=y CONFIG_ION_MSM=y +CONFIG_IPA=y +CONFIG_RMNET_IPA=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_REVID=y @@ -412,6 +427,7 @@ CONFIG_MSM_SMEM=y CONFIG_MSM_SMD=y CONFIG_MSM_SMD_DEBUG=y CONFIG_MSM_GLINK=y +CONFIG_MSM_TZ_SMMU=y CONFIG_MSM_GLINK_LOOPBACK_SERVER=y CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y CONFIG_MSM_GLINK_SPI_XPRT=y @@ -423,9 +439,12 @@ CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_GLINK_PKT=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_MSM_EVENT_TIMER=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_BAM_DMUX=y CONFIG_CNSS_CRYPTO=y CONFIG_PWM=y CONFIG_PWM_QPNP=y @@ -470,8 +489,13 @@ CONFIG_PANIC_ON_DATA_CORRUPTION=y CONFIG_PID_IN_CONTEXTIDR=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SINK_TPIU=y +CONFIG_CORESIGHT_SOURCE_ETM3X=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_QCOM_REPLICATOR=y +CONFIG_CORESIGHT_DBGUI=y CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y @@ -486,13 +510,14 @@ CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_SECURITY_APPARMOR=y CONFIG_DEFAULT_SECURITY_DAC=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XTS=y CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_CRC32=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCE=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_OTA_CRYPTO=y CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM_CRYPTO=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index 5e6a68b97b7b..27be6df96e63 100644 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -27,11 +27,14 @@ CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y CONFIG_DEFAULT_USE_ENERGY_AWARE=y CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y CONFIG_EMBEDDED=y CONFIG_PROFILING=y -CONFIG_OPROFILE=y +CONFIG_OPROFILE=m +CONFIG_KPROBES=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y @@ -138,6 +141,7 @@ CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -257,16 +261,25 @@ CONFIG_CNSS=y CONFIG_CNSS_SDIO=y CONFIG_CLD_HL_SDIO_CORE=y CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=y CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set CONFIG_SERIAL_MSM=y CONFIG_SERIAL_MSM_CONSOLE=y CONFIG_SERIAL_MSM_HS=y CONFIG_SERIAL_MSM_SMD=y +CONFIG_DIAG_CHAR=y +CONFIG_DIAG_USES_SMD=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_SMD_PKT=y @@ -340,11 +353,16 @@ CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MONTEREY=y CONFIG_HID_MULTITOUCH=y -CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_GADGET=y +CONFIG_USB_SERIAL=y +CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_GADGET=y @@ -354,7 +372,12 @@ CONFIG_USB_GADGET_VBUS_DRAW=500 CONFIG_USB_CI13XXX_MSM=y CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_RMNET_BAM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y CONFIG_USB_CONFIGFS_UEVENT=y CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_USB_CONFIGFS_F_CDEV=y @@ -386,6 +409,8 @@ CONFIG_ASHMEM=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_ION=y CONFIG_ION_MSM=y +CONFIG_IPA=y +CONFIG_RMNET_IPA=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_REVID=y @@ -407,6 +432,7 @@ CONFIG_MSM_SMEM=y CONFIG_MSM_SMD=y CONFIG_MSM_SMD_DEBUG=y CONFIG_MSM_GLINK=y +CONFIG_MSM_TZ_SMMU=y CONFIG_MSM_GLINK_LOOPBACK_SERVER=y CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y CONFIG_MSM_GLINK_SPI_XPRT=y @@ -418,10 +444,14 @@ CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_GLINK_PKT=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_MSM_EVENT_TIMER=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_BAM_DMUX=y CONFIG_CNSS_CRYPTO=y +CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_QTI_MPM=y @@ -435,13 +465,16 @@ CONFIG_EXT3_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y @@ -466,6 +499,7 @@ CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y CONFIG_DEBUG_STACK_USAGE=y CONFIG_DEBUG_MEMORY_INIT=y CONFIG_LOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y # CONFIG_DETECT_HUNG_TASK is not set CONFIG_WQ_WATCHDOG=y CONFIG_PANIC_TIMEOUT=5 @@ -496,8 +530,13 @@ CONFIG_DEBUG_USER=y CONFIG_PID_IN_CONTEXTIDR=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SINK_TPIU=y +CONFIG_CORESIGHT_SOURCE_ETM3X=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_QCOM_REPLICATOR=y +CONFIG_CORESIGHT_DBGUI=y CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y @@ -515,10 +554,13 @@ CONFIG_DEFAULT_SECURITY_DAC=y CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XTS=y CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_CRC32=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_OTA_CRYPTO=y CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM_CRYPTO=y -- GitLab From 7f179c9c7addcd90b4c593440142922a197c3878 Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Tue, 29 May 2018 10:57:57 +0530 Subject: [PATCH 702/855] diag: Enhance IPC logging for diag CNTL channel The patch enables to track the control channel buffer status, reception of feature mask and error case of not queueing a read on socket by use of debug logs. Change-Id: Ibd9bd9a09f6519e31874f8794df3df875e931d25 Signed-off-by: Manoj Prabhu B --- drivers/char/diag/diag_ipc_logging.h | 3 +- drivers/char/diag/diagfwd_cntl.c | 257 +++++++++++++++++++------ drivers/char/diag/diagfwd_peripheral.c | 24 ++- 3 files changed, 223 insertions(+), 61 deletions(-) diff --git a/drivers/char/diag/diag_ipc_logging.h b/drivers/char/diag/diag_ipc_logging.h index b9958a433c46..4b8dd1b12c1c 100644 --- a/drivers/char/diag/diag_ipc_logging.h +++ b/drivers/char/diag/diag_ipc_logging.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -24,6 +24,7 @@ #define DIAG_DEBUG_MASKS 0x0010 #define DIAG_DEBUG_POWER 0x0020 #define DIAG_DEBUG_BRIDGE 0x0040 +#define DIAG_DEBUG_CONTROL 0x0080 #define DIAG_DEBUG diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index 8d47ee38cb7d..6f81bfdbafe0 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -45,8 +45,11 @@ static void diag_mask_update_work_fn(struct work_struct *work) void diag_cntl_channel_open(struct diagfwd_info *p_info) { - if (!p_info) + if (!p_info) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid fwd_info structure\n"); return; + } driver->mask_update |= PERIPHERAL_MASK(p_info->peripheral); queue_work(driver->cntl_wq, &driver->mask_update_work); diag_notify_md_client(p_info->peripheral, DIAG_STATUS_OPEN); @@ -56,12 +59,18 @@ void diag_cntl_channel_close(struct diagfwd_info *p_info) { uint8_t peripheral; - if (!p_info) + if (!p_info) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid fwd_info structure\n"); return; + } peripheral = p_info->peripheral; - if (peripheral >= NUM_PERIPHERALS) + if (peripheral >= NUM_PERIPHERALS) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid peripheral (%d)\n", peripheral); return; + } driver->feature[peripheral].sent_feature_mask = 0; driver->feature[peripheral].rcvd_feature_mask = 0; @@ -87,8 +96,11 @@ static void diag_stm_update_work_fn(struct work_struct *work) driver->stm_peripheral = 0; mutex_unlock(&driver->cntl_lock); - if (peripheral_mask == 0) + if (peripheral_mask == 0) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Empty Peripheral mask\n"); return; + } for (i = 0; i < NUM_PERIPHERALS; i++) { if (!driver->feature[i].stm_support) @@ -111,11 +123,18 @@ void diag_notify_md_client(uint8_t peripheral, int data) struct pid *pid_struct; struct task_struct *result; - if (peripheral > NUM_PERIPHERALS) + if (peripheral > NUM_PERIPHERALS) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid peripheral (%d)\n", peripheral); return; + } - if (driver->logging_mode != DIAG_MEMORY_DEVICE_MODE) + if (driver->logging_mode != DIAG_MEMORY_DEVICE_MODE) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid logging_mode (%d)\n", + driver->logging_mode); return; + } mutex_lock(&driver->md_session_lock); memset(&info, 0, sizeof(struct siginfo)); @@ -171,8 +190,12 @@ static void process_pd_status(uint8_t *buf, uint32_t len, uint32_t pd; int status = DIAG_STATUS_CLOSED; - if (!buf || peripheral >= NUM_PERIPHERALS || len < sizeof(*pd_msg)) + if (!buf || peripheral >= NUM_PERIPHERALS || len < sizeof(*pd_msg)) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d, pd_msg_len = %d\n", + !buf, peripheral, len, (int)sizeof(*pd_msg)); return; + } pd_msg = (struct diag_ctrl_msg_pd_status *)buf; pd = pd_msg->pd_id; @@ -182,8 +205,11 @@ static void process_pd_status(uint8_t *buf, uint32_t len, static void enable_stm_feature(uint8_t peripheral) { - if (peripheral >= NUM_PERIPHERALS) + if (peripheral >= NUM_PERIPHERALS) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid peripheral (%d)\n", peripheral); return; + } mutex_lock(&driver->cntl_lock); driver->feature[peripheral].stm_support = ENABLE_STM; @@ -195,8 +221,11 @@ static void enable_stm_feature(uint8_t peripheral) static void enable_socket_feature(uint8_t peripheral) { - if (peripheral >= NUM_PERIPHERALS) + if (peripheral >= NUM_PERIPHERALS) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid peripheral (%d)\n", peripheral); return; + } if (driver->supports_sockets) driver->feature[peripheral].sockets_enabled = 1; @@ -206,8 +235,11 @@ static void enable_socket_feature(uint8_t peripheral) static void process_hdlc_encoding_feature(uint8_t peripheral) { - if (peripheral >= NUM_PERIPHERALS) + if (peripheral >= NUM_PERIPHERALS) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid peripheral (%d)\n", peripheral); return; + } if (driver->supports_apps_hdlc_encoding) { driver->feature[peripheral].encode_hdlc = @@ -220,8 +252,11 @@ static void process_hdlc_encoding_feature(uint8_t peripheral) static void process_upd_header_untagging_feature(uint8_t peripheral) { - if (peripheral >= NUM_PERIPHERALS) + if (peripheral >= NUM_PERIPHERALS) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid peripheral (%d)\n", peripheral); return; + } if (driver->supports_apps_header_untagging) { driver->feature[peripheral].untag_header = @@ -247,8 +282,16 @@ static void process_command_deregistration(uint8_t *buf, uint32_t len, * Perform Basic sanity. The len field is the size of the data payload. * This doesn't include the header size. */ - if (!buf || peripheral >= NUM_PERIPHERALS || len == 0) + if (!buf || peripheral >= NUM_PERIPHERALS || len == 0) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d\n", + !buf, peripheral, len); return; + } + + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag:peripheral(%d) command deregistration packet processing started\n", + peripheral); dereg = (struct diag_ctrl_cmd_dereg *)ptr; ptr += header_len; @@ -256,8 +299,8 @@ static void process_command_deregistration(uint8_t *buf, uint32_t len, read_len += header_len - (2 * sizeof(uint32_t)); if (dereg->count_entries == 0) { - pr_debug("diag: In %s, received reg tbl with no entries\n", - __func__); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: received reg tbl with no entries\n"); return; } @@ -276,6 +319,9 @@ static void process_command_deregistration(uint8_t *buf, uint32_t len, pr_err("diag: In %s, reading less than available, read_len: %d, len: %d count: %d\n", __func__, read_len, len, dereg->count_entries); } + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag:peripheral(%d) command deregistration packet processing complete\n", + peripheral); } static void process_command_registration(uint8_t *buf, uint32_t len, uint8_t peripheral) @@ -292,8 +338,15 @@ static void process_command_registration(uint8_t *buf, uint32_t len, * Perform Basic sanity. The len field is the size of the data payload. * This doesn't include the header size. */ - if (!buf || peripheral >= NUM_PERIPHERALS || len == 0) + if (!buf || peripheral >= NUM_PERIPHERALS || len == 0) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d\n", + !buf, peripheral, len); return; + } + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag: peripheral(%d) command registration packet processing started\n", + peripheral); reg = (struct diag_ctrl_cmd_reg *)ptr; ptr += header_len; @@ -301,7 +354,8 @@ static void process_command_registration(uint8_t *buf, uint32_t len, read_len += header_len - (2 * sizeof(uint32_t)); if (reg->count_entries == 0) { - pr_debug("diag: In %s, received reg tbl with no entries\n", + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: In %s, received reg tbl with no entries\n", __func__); return; } @@ -321,6 +375,9 @@ static void process_command_registration(uint8_t *buf, uint32_t len, pr_err("diag: In %s, reading less than available, read_len: %d, len: %d count: %d\n", __func__, read_len, len, reg->count_entries); } + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag: peripheral(%d) command registration packet processing complete\n", + peripheral); } static void diag_close_transport_work_fn(struct work_struct *work) @@ -347,8 +404,11 @@ static void diag_close_transport_work_fn(struct work_struct *work) static void process_socket_feature(uint8_t peripheral) { - if (peripheral >= NUM_PERIPHERALS) + if (peripheral >= NUM_PERIPHERALS) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid peripheral (%d)\n", peripheral); return; + } mutex_lock(&driver->cntl_lock); driver->close_transport |= PERIPHERAL_MASK(peripheral); @@ -379,15 +439,20 @@ static void process_incoming_feature_mask(uint8_t *buf, uint32_t len, uint32_t feature_mask = 0; uint8_t *ptr = buf; - if (!buf || peripheral >= NUM_PERIPHERALS || len == 0) + if (!buf || peripheral >= NUM_PERIPHERALS || len == 0) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d\n", + !buf, peripheral, len); return; + } header = (struct diag_ctrl_feature_mask *)ptr; ptr += header_len; feature_mask_len = header->feature_mask_len; if (feature_mask_len == 0) { - pr_debug("diag: In %s, received invalid feature mask from peripheral %d\n", + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: In %s, received invalid feature mask from peripheral %d\n", __func__, peripheral); return; } @@ -400,6 +465,8 @@ static void process_incoming_feature_mask(uint8_t *buf, uint32_t len, diag_cmd_remove_reg_by_proc(peripheral); driver->feature[peripheral].rcvd_feature_mask = 1; + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag: Received feature mask for peripheral %d\n", peripheral); for (i = 0; i < feature_mask_len && read_len < len; i++) { feature_mask = *(uint8_t *)ptr; @@ -431,6 +498,10 @@ static void process_incoming_feature_mask(uint8_t *buf, uint32_t len, process_socket_feature(peripheral); process_log_on_demand_feature(peripheral); + + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag: Peripheral(%d) feature mask is processed\n", + peripheral); } static void process_last_event_report(uint8_t *buf, uint32_t len, @@ -442,14 +513,23 @@ static void process_last_event_report(uint8_t *buf, uint32_t len, uint32_t pkt_len = sizeof(uint32_t) + sizeof(uint16_t); uint16_t event_size = 0; - if (!buf || peripheral >= NUM_PERIPHERALS || len != pkt_len) + if (!buf || peripheral >= NUM_PERIPHERALS || len != pkt_len) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d, pkt_len = %d\n", + !buf, peripheral, len, pkt_len); return; + } + + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag:started processing last event report for peripheral (%d)\n", + peripheral); mutex_lock(&event_mask.lock); header = (struct diag_ctrl_last_event_report *)ptr; event_size = ((header->event_last_id / 8) + 1); if (event_size >= driver->event_mask_size) { - pr_debug("diag: In %s, receiving event mask size more that Apps can handle\n", + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag: In %s, receiving event mask size more that Apps can handle\n", __func__); temp = krealloc(driver->event_mask->ptr, event_size, GFP_KERNEL); @@ -467,6 +547,9 @@ static void process_last_event_report(uint8_t *buf, uint32_t len, driver->last_event_id = header->event_last_id; err: mutex_unlock(&event_mask.lock); + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag: last event report processed for peripheral (%d)\n", + peripheral); } static void process_log_range_report(uint8_t *buf, uint32_t len, @@ -480,8 +563,15 @@ static void process_log_range_report(uint8_t *buf, uint32_t len, struct diag_ctrl_log_range *log_range = NULL; struct diag_log_mask_t *mask_ptr = NULL; - if (!buf || peripheral >= NUM_PERIPHERALS || len < 0) + if (!buf || peripheral >= NUM_PERIPHERALS || len < 0) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d\n", + !buf, peripheral, len); return; + } + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag:started processing log range report for peripheral(%d)\n", + peripheral); header = (struct diag_ctrl_log_range_report *)ptr; ptr += header_len; @@ -507,6 +597,9 @@ static void process_log_range_report(uint8_t *buf, uint32_t len, mask_ptr->range = LOG_ITEMS_TO_SIZE(log_range->num_items); mutex_unlock(&(mask_ptr->lock)); } + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag: log range report processed for peripheral (%d)\n", + peripheral); } static int update_msg_mask_tbl_entry(struct diag_msg_mask_t *mask, @@ -514,8 +607,12 @@ static int update_msg_mask_tbl_entry(struct diag_msg_mask_t *mask, { uint32_t temp_range; - if (!mask || !range) + if (!mask || !range) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid %s\n", + (!mask ? "mask" : (!range ? "range" : " "))); return -EIO; + } if (range->ssid_last < range->ssid_first) { pr_err("diag: In %s, invalid ssid range, first: %d, last: %d\n", __func__, range->ssid_first, range->ssid_last); @@ -547,8 +644,16 @@ static void process_ssid_range_report(uint8_t *buf, uint32_t len, uint8_t *temp = NULL; uint32_t min_len = header_len - sizeof(struct diag_ctrl_pkt_header_t); - if (!buf || peripheral >= NUM_PERIPHERALS || len < min_len) + if (!buf || peripheral >= NUM_PERIPHERALS || len < min_len) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d, min_len = %d\n", + !buf, peripheral, len, min_len); return; + } + + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag: started processing ssid range for peripheral (%d)\n", + peripheral); header = (struct diag_ctrl_ssid_range_report *)ptr; ptr += header_len; @@ -600,6 +705,9 @@ static void process_ssid_range_report(uint8_t *buf, uint32_t len, driver->msg_mask_tbl_count += 1; } mutex_unlock(&driver->msg_mask_lock); + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag: processed ssid range for peripheral(%d)\n", + peripheral); } static void diag_build_time_mask_update(uint8_t *buf, @@ -616,8 +724,12 @@ static void diag_build_time_mask_update(uint8_t *buf, uint32_t *dest_ptr = NULL; struct diag_msg_mask_t *build_mask = NULL; - if (!range || !buf) + if (!range || !buf) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid %s\n", + (!range ? "range" : (!buf ? "buf" : " "))); return; + } if (range->ssid_last < range->ssid_first) { pr_err("diag: In %s, invalid ssid range, first: %d, last: %d\n", @@ -679,8 +791,16 @@ static void process_build_mask_report(uint8_t *buf, uint32_t len, struct diag_ctrl_build_mask_report *header = NULL; struct diag_ssid_range_t *range = NULL; - if (!buf || peripheral >= NUM_PERIPHERALS || len < header_len) + if (!buf || peripheral >= NUM_PERIPHERALS || len < header_len) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid parameters:(!buf) = %d, peripheral = %d, len = %d, header_len = %d\n", + !buf, peripheral, len, header_len); return; + } + + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag: started processing build mask for peripheral(%d)\n", + peripheral); header = (struct diag_ctrl_build_mask_report *)ptr; ptr += header_len; @@ -696,6 +816,8 @@ static void process_build_mask_report(uint8_t *buf, uint32_t len, ptr += num_items * sizeof(uint32_t); read_len += num_items * sizeof(uint32_t); } + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag: processing build mask complete (%d)\n", peripheral); } int diag_add_diag_id_to_list(uint8_t diag_id, char *process_name, @@ -703,8 +825,12 @@ int diag_add_diag_id_to_list(uint8_t diag_id, char *process_name, { struct diag_id_tbl_t *new_item = NULL; - if (!process_name || diag_id == 0) + if (!process_name || diag_id == 0) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid parameters: !process_name = %d, diag_id = %d\n", + !process_name, diag_id); return -EINVAL; + } new_item = kzalloc(sizeof(struct diag_id_tbl_t), GFP_KERNEL); if (!new_item) @@ -734,8 +860,10 @@ int diag_query_diag_id(char *process_name, uint8_t *diag_id) struct list_head *temp; struct diag_id_tbl_t *item = NULL; - if (!process_name || !diag_id) + if (!process_name || !diag_id) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag: Invalid parameters\n"); return -EINVAL; + } mutex_lock(&driver->diag_id_mutex); list_for_each_safe(start, temp, &driver->diag_id_list) { @@ -762,8 +890,12 @@ static void process_diagid(uint8_t *buf, uint32_t len, uint8_t local_diag_id = 0; uint8_t new_request = 0, i = 0, ch_type = 0; - if (!buf || len == 0 || peripheral >= NUM_PERIPHERALS) + if (!buf || len == 0 || peripheral >= NUM_PERIPHERALS) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Invalid parameters: !buf = %d, len = %d, peripheral = %d\n", + !buf, len, peripheral); return; + } header = (struct diag_ctrl_diagid *)buf; process_name = (char *)&header->process_name; @@ -841,7 +973,7 @@ static void process_diagid(uint8_t *buf, uint32_t len, fwd_info = &peripheral_info[TYPE_DATA][peripheral]; diagfwd_buffers_init(fwd_info); DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag: diag_id sent = %d to peripheral = %d with diag_id = %d for %s :\n", + "diag: diag_id sent = %d to peripheral = %d with diag_id = %d for %s\n", driver->diag_id_sent[peripheral], peripheral, ctrl_pkt.diag_id, process_name); } @@ -855,8 +987,10 @@ void diag_cntl_process_read_data(struct diagfwd_info *p_info, void *buf, uint8_t *ptr = buf; struct diag_ctrl_pkt_header_t *ctrl_pkt = NULL; - if (!buf || len <= 0 || !p_info) + if (!buf || len <= 0 || !p_info) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag: Invalid parameters\n"); return; + } if (reg_dirty & PERIPHERAL_MASK(p_info->peripheral)) { pr_err_ratelimited("diag: dropping command registration from peripheral %d\n", @@ -866,6 +1000,9 @@ void diag_cntl_process_read_data(struct diagfwd_info *p_info, void *buf, while (read_len + header_len < len) { ctrl_pkt = (struct diag_ctrl_pkt_header_t *)ptr; + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag:peripheral: %d: pkt_id: %d\n", + p_info->peripheral, ctrl_pkt->pkt_id); switch (ctrl_pkt->pkt_id) { case DIAG_CTRL_MSG_REG: process_command_registration(ptr, ctrl_pkt->len, @@ -904,12 +1041,15 @@ void diag_cntl_process_read_data(struct diagfwd_info *p_info, void *buf, p_info->peripheral); break; default: - pr_debug("diag: Control packet %d not supported\n", - ctrl_pkt->pkt_id); + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag: Control packet %d not supported\n", + ctrl_pkt->pkt_id); } ptr += header_len + ctrl_pkt->len; read_len += header_len + ctrl_pkt->len; } + DIAG_LOG(DIAG_DEBUG_CONTROL, + "diag: control packet processing complete\n"); } static int diag_compute_real_time(int idx) @@ -1127,15 +1267,16 @@ void diag_real_time_work_fn(struct work_struct *work) for (i = 0; i < DIAG_NUM_PROC; i++) { temp_real_time = diag_compute_real_time(i); if (temp_real_time == driver->real_time_mode[i]) { - pr_debug("diag: did not update real time mode on proc %d, already in the req mode %d", + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: did not update real time mode on proc %d, already in the req mode %d\n", i, temp_real_time); continue; } if (i == DIAG_LOCAL_PROC) { if (!send_update) { - pr_debug("diag: In %s, cannot send real time mode pkt since one of the periperhal is in buffering mode\n", - __func__); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: cannot send real time mode pkt since one of the periperhal is in buffering mode\n"); break; } for (j = 0; j < NUM_PERIPHERALS; j++) @@ -1169,7 +1310,8 @@ void diag_real_time_work_fn(struct work_struct *work) temp_real_time = MODE_NONREALTIME; } if (temp_real_time == driver->real_time_mode[i]) { - pr_debug("diag: did not update real time mode on proc %d, already in the req mode %d", + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: did not update real time mode on proc %d, already in the req mode %d\n", i, temp_real_time); continue; } @@ -1204,8 +1346,8 @@ static int __diag_send_real_time_update(uint8_t peripheral, int real_time, if (!driver->diagfwd_cntl[peripheral] || !driver->diagfwd_cntl[peripheral]->ch_open) { - pr_debug("diag: In %s, control channel is not open, p: %d\n", - __func__, peripheral); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: control channel is not open, p: %d\n", peripheral); return err; } @@ -1317,8 +1459,9 @@ int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params) } if (!driver->feature[peripheral].peripheral_buffering) { - pr_debug("diag: In %s, peripheral %d doesn't support buffering\n", - __func__, peripheral); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: peripheral %d doesn't support buffering\n", + peripheral); driver->buffering_flag[params->peripheral] = 0; return -EIO; } @@ -1383,8 +1526,9 @@ int diag_send_stm_state(uint8_t peripheral, uint8_t stm_control_data) if (!driver->diagfwd_cntl[peripheral] || !driver->diagfwd_cntl[peripheral]->ch_open) { - pr_debug("diag: In %s, control channel is not open, p: %d\n", - __func__, peripheral); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: control channel is not open, p: %d\n", + peripheral); return -ENODEV; } @@ -1413,15 +1557,17 @@ int diag_send_peripheral_drain_immediate(uint8_t pd, struct diag_ctrl_drain_immediate_v2 ctrl_pkt_v2; if (!driver->feature[peripheral].peripheral_buffering) { - pr_debug("diag: In %s, peripheral %d doesn't support buffering\n", - __func__, peripheral); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: peripheral %d doesn't support buffering\n", + peripheral); return -EINVAL; } if (!driver->diagfwd_cntl[peripheral] || !driver->diagfwd_cntl[peripheral]->ch_open) { - pr_debug("diag: In %s, control channel is not open, p: %d\n", - __func__, peripheral); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: control channel is not open, p: %d\n", + peripheral); return -ENODEV; } @@ -1478,8 +1624,9 @@ int diag_send_buffering_tx_mode_pkt(uint8_t peripheral, } if (!driver->feature[peripheral].peripheral_buffering) { - pr_debug("diag: In %s, peripheral %d doesn't support buffering\n", - __func__, peripheral); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: peripheral %d doesn't support buffering\n", + peripheral); return -EINVAL; } @@ -1557,15 +1704,17 @@ int diag_send_buffering_wm_values(uint8_t peripheral, } if (!driver->feature[peripheral].peripheral_buffering) { - pr_debug("diag: In %s, peripheral %d doesn't support buffering\n", - __func__, peripheral); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: peripheral %d doesn't support buffering\n", + peripheral); return -EINVAL; } if (!driver->diagfwd_cntl[peripheral] || !driver->diagfwd_cntl[peripheral]->ch_open) { - pr_debug("diag: In %s, control channel is not open, p: %d\n", - __func__, peripheral); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: control channel is not open, p: %d\n", + peripheral); return -ENODEV; } diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 7225dc2c7b1d..2022e7be73b5 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -723,6 +723,7 @@ static void diagfwd_cntl_read_done(struct diagfwd_info *fwd_info, unsigned char *buf, int len) { if (!fwd_info) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag: Invalid fwd_info\n"); diag_ws_release(); return; } @@ -743,8 +744,12 @@ static void diagfwd_cntl_read_done(struct diagfwd_info *fwd_info, */ diag_ws_on_copy_fail(DIAG_WS_MUX); /* Reset the buffer in_busy value after processing the data */ - if (fwd_info->buf_1) + if (fwd_info->buf_1) { atomic_set(&fwd_info->buf_1->in_busy, 0); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Buffer 1 for core PD is marked free, p: %d, t: %d\n", + fwd_info->peripheral, fwd_info->type); + } diagfwd_queue_read(fwd_info); diagfwd_queue_read(&peripheral_info[TYPE_DATA][fwd_info->peripheral]); @@ -769,8 +774,12 @@ static void diagfwd_dci_read_done(struct diagfwd_info *fwd_info, diag_dci_process_peripheral_data(fwd_info, (void *)buf, len); /* Reset the buffer in_busy value after processing the data */ - if (fwd_info->buf_1) + if (fwd_info->buf_1) { atomic_set(&fwd_info->buf_1->in_busy, 0); + DIAG_LOG(DIAG_DEBUG_DCI, + "Buffer 1 for core PD is marked free, p: %d, t: %d\n", + fwd_info->peripheral, fwd_info->type); + } diagfwd_queue_read(fwd_info); } @@ -1638,13 +1647,15 @@ void diagfwd_channel_read(struct diagfwd_info *fwd_info) struct diagfwd_buf_t *temp_buf = NULL; if (!fwd_info) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag: Invalid fwd_info\n"); diag_ws_release(); return; } if (!fwd_info->inited || !atomic_read(&fwd_info->opened)) { - pr_debug("diag: In %s, p: %d, t: %d, inited: %d, opened: %d ch_open: %d\n", - __func__, fwd_info->peripheral, fwd_info->type, + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: p: %d, t: %d, inited: %d, opened: %d, ch_open: %d\n", + fwd_info->peripheral, fwd_info->type, fwd_info->inited, atomic_read(&fwd_info->opened), fwd_info->ch_open); diag_ws_release(); @@ -1680,8 +1691,9 @@ void diagfwd_channel_read(struct diagfwd_info *fwd_info) atomic_set(&temp_buf->in_busy, 1); } } else { - pr_debug("diag: In %s, both buffers are empty for p: %d, t: %d\n", - __func__, fwd_info->peripheral, fwd_info->type); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: both buffers are busy for p: %d, t: %d\n", + fwd_info->peripheral, fwd_info->type); } if (!read_buf) { -- GitLab From 3abee2fad3ba1db03f09515b73352dd8c556b1a7 Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Fri, 4 May 2018 15:52:50 +0530 Subject: [PATCH 703/855] power: qpnp-smb2: Add dt property to disable STAT SW_OVERRIDE Add boolean device tree property to disable STAT pin SW_OVERRIDE default configuration. This is required for enabling main charger control over enable/disable of slave charger. STAT pin SW override is disabled by default in case of presence of parallel charger. But for SMB1390 case, it is required to define this property to explicitly disable STAT pin SW override in order to enable the charge pump. Change-Id: I4539ffbe5c6f1135c212fb7fa13a802020798093 Signed-off-by: Umang Agrawal --- .../bindings/power/supply/qcom/qpnp-smb2.txt | 6 ++++++ drivers/power/supply/qcom/qpnp-smb2.c | 13 +++++++++++++ drivers/power/supply/qcom/smb-lib.h | 1 + 3 files changed, 20 insertions(+) diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt index afa800900508..9de24c3378c4 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt @@ -193,6 +193,12 @@ Charger specific properties: to be get from these properties defined in battery profile: qcom,step-chg-ranges, qcom,jeita-fcc-ranges, qcom,jeita-fv-ranges. +- qcom,disable-stat-sw-override + Usage: optional + Value type: bool + Definition: Boolean flag which when present disables STAT pin default software + override configuration. + ============================================= Second Level Nodes - SMB2 Charger Peripherals ============================================= diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 5df241fe8fd9..617ef624a71b 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -331,6 +331,9 @@ static int smb2_parse_dt(struct smb2 *chip) if (rc < 0) chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS; + chg->disable_stat_sw_override = of_property_read_bool(node, + "qcom,disable-stat-sw-override"); + return 0; } @@ -1837,6 +1840,16 @@ static int smb2_init_hw(struct smb2 *chip) } } + if (chg->disable_stat_sw_override) { + rc = smblib_masked_write(chg, STAT_CFG_REG, + STAT_SW_OVERRIDE_CFG_BIT, 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't disable STAT SW override rc=%d\n", + rc); + return rc; + } + } + return rc; } diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index dc8cbc7b67d7..455b5a4c7641 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -353,6 +353,7 @@ struct smb_charger { bool use_extcon; bool otg_present; bool is_audio_adapter; + bool disable_stat_sw_override; /* workaround flag */ u32 wa_flags; -- GitLab From d4165d14ea6c4dda1baad6ccb1e4dc9412677e35 Mon Sep 17 00:00:00 2001 From: Shubhashree Dhar Date: Mon, 4 Jun 2018 15:13:26 +0530 Subject: [PATCH 704/855] drm/msm/sde: add debugfs node in dpu driver to give fps Add debugfs node on crtc to get fps value at runtime. The calculation is time based where in dpu driver counts number of frames transferred for every 1 second. Change-Id: Ic6ba615cc0b394fd09f5953a7d26c9af8be3559d Signed-off-by: Shubhashree Dhar --- drivers/gpu/drm/msm/sde/sde_crtc.c | 89 ++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/sde/sde_crtc.h | 7 +++ 2 files changed, 96 insertions(+) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 95034154813b..c9d6eece0f68 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -79,6 +79,12 @@ static struct sde_crtc_custom_events custom_events[] = { #define MISR_BUFF_SIZE 256 +/* + * Time period for fps calculation in micro seconds. + * Default value is set to 1 sec. + */ +#define CRTC_TIME_PERIOD_CALC_FPS_US 1000000 + static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc) { struct msm_drm_private *priv; @@ -125,6 +131,37 @@ static inline int _sde_crtc_power_enable(struct sde_crtc *sde_crtc, bool enable) enable); } +/* + * sde_crtc_calc_fps() - Calculates fps value. + * @sde_crtc : CRTC structure + * + * This function is called at frame done. It counts the number + * of frames done for every 1 sec. Stores the value in measured_fps. + * measured_fps value is 10 times the calculated fps value. + * For example, measured_fps= 594 for calculated fps of 59.4 + */ +static void sde_crtc_calc_fps(struct sde_crtc *sde_crtc) +{ + ktime_t current_time_us; + u64 fps, diff_us; + + current_time_us = ktime_get(); + diff_us = (u64)ktime_us_delta(current_time_us, + sde_crtc->fps_info.last_sampled_time_us); + sde_crtc->fps_info.frame_count++; + + if (diff_us >= CRTC_TIME_PERIOD_CALC_FPS_US) { + fps = ((u64)sde_crtc->fps_info.frame_count) * 10000000; + do_div(fps, diff_us); + sde_crtc->fps_info.measured_fps = (unsigned int)fps; + SDE_DEBUG(" FPS for crtc%d is %d.%d\n", + sde_crtc->base.base.id, (unsigned int)fps/10, + (unsigned int)fps%10); + sde_crtc->fps_info.last_sampled_time_us = current_time_us; + sde_crtc->fps_info.frame_count = 0; + } +} + /** * _sde_crtc_rp_to_crtc - get crtc from resource pool object * @rp: Pointer to resource pool @@ -601,6 +638,50 @@ static void _sde_crtc_deinit_events(struct sde_crtc *sde_crtc) return; } +static int _sde_debugfs_fps_status_show(struct seq_file *s, void *data) +{ + struct sde_crtc *sde_crtc; + unsigned int fps_int, fps_float; + ktime_t current_time_us; + u64 fps, diff_us; + + if (!s || !s->private) { + SDE_ERROR("invalid input param(s)\n"); + return -EAGAIN; + } + + sde_crtc = s->private; + + current_time_us = ktime_get(); + diff_us = (u64)ktime_us_delta(current_time_us, + sde_crtc->fps_info.last_sampled_time_us); + + if (diff_us >= CRTC_TIME_PERIOD_CALC_FPS_US) { + fps = ((u64)sde_crtc->fps_info.frame_count) * 10000000; + do_div(fps, diff_us); + sde_crtc->fps_info.measured_fps = (unsigned int)fps; + sde_crtc->fps_info.last_sampled_time_us = current_time_us; + sde_crtc->fps_info.frame_count = 0; + SDE_DEBUG("Measured FPS for crtc%d is %d.%d\n", + sde_crtc->base.base.id, (unsigned int)fps/10, + (unsigned int)fps%10); + } + + fps_int = (unsigned int) sde_crtc->fps_info.measured_fps; + fps_float = do_div(fps_int, 10); + + seq_printf(s, "fps: %d.%d\n", fps_int, fps_float); + + return 0; +} + + +static int _sde_debugfs_fps_status(struct inode *inode, struct file *file) +{ + return single_open(file, _sde_debugfs_fps_status_show, + inode->i_private); +} + static ssize_t vsync_event_show(struct device *device, struct device_attribute *attr, char *buf) { @@ -3687,6 +3768,8 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, SDE_ATRACE_BEGIN("wait_for_frame_done_event"); ret = _sde_crtc_wait_for_frame_done(crtc); SDE_ATRACE_END("wait_for_frame_done_event"); + sde_crtc_calc_fps(sde_crtc); + if (ret) { SDE_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", crtc->base.id, @@ -5779,6 +5862,10 @@ static int _sde_crtc_init_debugfs(struct drm_crtc *crtc) .open = _sde_debugfs_fence_status, .read = seq_read, }; + static const struct file_operations debugfs_fps_fops = { + .open = _sde_debugfs_fps_status, + .read = seq_read, + }; if (!crtc) return -EINVAL; @@ -5805,6 +5892,8 @@ static int _sde_crtc_init_debugfs(struct drm_crtc *crtc) sde_crtc, &debugfs_misr_fops); debugfs_create_file("fence_status", 0400, sde_crtc->debugfs_root, sde_crtc, &debugfs_fence_fops); + debugfs_create_file("fps", 0400, sde_crtc->debugfs_root, + sde_crtc, &debugfs_fps_fops); return 0; } diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index 53b8df94c151..c02a81ea1b1e 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -136,6 +136,12 @@ struct sde_crtc_event { void *usr; }; +struct sde_crtc_fps_info { + u32 frame_count; + ktime_t last_sampled_time_us; + u32 measured_fps; +}; + /* * Maximum number of free event structures to cache */ @@ -232,6 +238,7 @@ struct sde_crtc { u64 play_count; ktime_t vblank_cb_time; ktime_t vblank_last_cb_time; + struct sde_crtc_fps_info fps_info; struct device *sysfs_dev; struct kernfs_node *vsync_event_sf; bool vblank_requested; -- GitLab From 996cd776baa4d90fcaee8897a37d048de80fcb3f Mon Sep 17 00:00:00 2001 From: Santosh Mardi Date: Tue, 5 Jun 2018 11:34:50 +0530 Subject: [PATCH 705/855] devfreq: suppress platform driver bind / unbind feature. For arm-memlat and bimc-hwmon platform driver does not support the manual bind / unbind feature through sysfs, when the governor is registered and started. Suppress the bind / unbind calls using driver attribute. Change-Id: I8287012e1e6931d80953382f3d625223315cec85 Signed-off-by: Santosh Mardi --- drivers/devfreq/arm-memlat-mon.c | 1 + drivers/devfreq/bimc-bwmon.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c index 81f7c162b069..fe249e7e16d1 100644 --- a/drivers/devfreq/arm-memlat-mon.c +++ b/drivers/devfreq/arm-memlat-mon.c @@ -420,6 +420,7 @@ static struct platform_driver arm_memlat_mon_driver = { .driver = { .name = "arm-memlat-mon", .of_match_table = memlat_match_table, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/devfreq/bimc-bwmon.c b/drivers/devfreq/bimc-bwmon.c index 33e16261983c..d2aaffbfd60d 100644 --- a/drivers/devfreq/bimc-bwmon.c +++ b/drivers/devfreq/bimc-bwmon.c @@ -1128,6 +1128,7 @@ static struct platform_driver bimc_bwmon_driver = { .driver = { .name = "bimc-bwmon", .of_match_table = bimc_bwmon_match_table, + .suppress_bind_attrs = true, }, }; -- GitLab From 59759255314140dd2d9a9b3072f4488f9f66c482 Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Thu, 19 Apr 2018 14:42:44 +0530 Subject: [PATCH 706/855] mmc: card: WARN_ON in cmdq completion context Due to command queuing, there is a possibility of servicing completion of multiple requests from hw irq context. So in this case, hw irq will launch softirq for all requests which were completed (irrespective of whether it was success or failure). If one of the requests failed, then the softirq corresponding to error ed request will set current cmdq state to CMDQ_STATE_ERR. Because of this, subsequent completion softirqs for successful requests will BUG_ON. We should let higher layers know of completion of successful requests. Hence change the BUG_ON to WARN_ON and skip blk_end_request() only if the corresponding request has an error (instead of checking if the cmdq state is in error) Change-Id: Ieb7f9d12ba04b6ab6499bf29f3716b0ddfb880fb Signed-off-by: Pradeep P V K --- drivers/mmc/card/block.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 2405ae35291d..e1cced6375fe 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -3630,7 +3630,7 @@ void mmc_blk_cmdq_complete_rq(struct request *rq) * or disable state so cannot receive any completion of * other requests. */ - BUG_ON(test_bit(CMDQ_STATE_ERR, &ctx_info->curr_state)); + WARN_ON(test_bit(CMDQ_STATE_ERR, &ctx_info->curr_state)); /* clear pending request */ BUG_ON(!test_and_clear_bit(cmdq_req->tag, @@ -3664,7 +3664,7 @@ void mmc_blk_cmdq_complete_rq(struct request *rq) out: mmc_cmdq_clk_scaling_stop_busy(host, true, is_dcmd); - if (!test_bit(CMDQ_STATE_ERR, &ctx_info->curr_state)) { + if (!(err || cmdq_req->resp_err)) { mmc_host_clk_release(host); wake_up(&ctx_info->wait); mmc_put_card(host->card); -- GitLab From e23e5addcf82f7dccfc04e0011aae1da4434084c Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 3 Apr 2018 09:03:28 +0800 Subject: [PATCH 707/855] pwm: pwm-qti-lpg: Add support for LUT pattern control through SDAM In some PMICs, the LUT patterns and the LPG ramp configurations can be stored in the shared direct access memory (SDAM) module instead of LUT peripheral. Add support for configuring and using LUT pattern from SDAM. Change-Id: I24b8b13c0c3109d7acab5e00c0fbc30438076a76 Signed-off-by: Fenglin Wu --- .../devicetree/bindings/pwm/pwm-qti-lpg.txt | 143 +++++- drivers/pwm/pwm-qti-lpg.c | 444 +++++++++++++++++- 2 files changed, 535 insertions(+), 52 deletions(-) diff --git a/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt index ddd90e134a16..2a84dd6986de 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt @@ -20,7 +20,8 @@ device module in Qualcomm Technologies, Inc. PMIC chips. Value type: Definition: The name of the register defined in the reg property. It must have "lpg-base", "lut-base" is optional but - it's required if any LPG channels support LUT mode. + it's required if any LPG channels support LUT mode + with a LUT module. - #pwm-cells: Usage: required @@ -30,14 +31,47 @@ device module in Qualcomm Technologies, Inc. PMIC chips. the PWM channel ID indexed from 0, and the second cell is the PWM default period in nanoseconds. +- nvmem-names: + Usage: optional + Value type: + Definition: The nvmem device name for the SDAM module where the LUT + pattern is stored. It must be "ppg_sdam". This property + is required only when LUT mode is supported with a SDAM + module instead of a LUT module. + +- nvmem: + Usage: optional + Value type: + Definition: Phandle of the nvmem device to access the LUT stored + in the SDAM module. This property is required only when + LUT mode is supported and the LUT pattern is stored in a + SDAM module instead of a LUT module. + +- qcom,pbs-client + Usage: optional + Value type: + Definition: Phandle of the PBS client used for sending the PBS + trigger. This property is required when LUT mode is + supported and the LUT pattern is stored in a SDAM + module instead of a LUT module. + +- qcom,lut-sdam-base: + Usage: optional + Value type: + Definition: The register base of the LUT entries stored in SDAM. This + property is required only when LUT mode is supported and + the LUT pattern is stored in a SDAM module instead of a + LUT module. + - qcom,lut-patterns: Usage: optional Value type: Definition: Duty ratios in percentages for LPG working at LUT mode. These duty ratios will be translated into PWM values - and stored in LUT module. The LUT module has resource - to store 47 PWM values at max and shared for all LPG - channels. This property is required if any LPG channels + and stored in LUT or SDAM module shared for all LPG + channels. The LUT module has resource to store 47 PWM + values at max while SDAM module can store upto 64 PWM + values. This property is required if any LPG channels support LUT mode. Subnode is optional if LUT mode is not required, it's required if any LPG @@ -54,31 +88,37 @@ parameters needs to be configured for that channel. range is 1 - 8. Maximum value depends on the number of channels supported on PMIC. +- qcom,lpg-sdam-base: + Usage: optional + Value type: + Definition: Register base address for LPG configuration in SDAM for + the LPG channel specified under "qcom,lpg-chan-id". + This property is required if LUT mode is supported with + a SDAM module. + - qcom,ramp-step-ms: Usage: required Value type: Definition: The step duration in milliseconds for LPG staying at each - duty specified in the LUT pattern. Allowed range is - 1 - 511. + duty specified in the LUT pattern. Allowed range: + 1 - 511 when LUT module is used, and 8 - 2000 when SDAM + is used. - qcom,ramp-high-index: Usage: required Value type: Definition: The high index of the LUT pattern where LPG ends up - ramping to. Allowed range is 1 - 47. + ramping to. Allowed range: 1 - 47 when LUT module + is used, and 1 - 64 when SDAM module is used. - qcom,ramp-low-index: Usage: required Value type: Definition: The low index of the LUT pattern from where LPG begins - ramping from. Allowed range is 0 - 46. - -- qcom,ramp-from-low-to-high: - Usage: optional - Value type: - Definition: The flag to specify the LPG ramping direction. The ramping - direction is from low index to high index of the LUT - pattern if it's specified. + ramping from. The ramp-low-index should be always less + than ramp-high-index when SDAM module is used. Allowed + range: 0 - 46 when LUT module is used, and 0 - 63 when + SDAM module is used. - qcom,ramp-pattern-repeat: Usage: optional @@ -86,36 +126,48 @@ parameters needs to be configured for that channel. Definition: The flag to specify if LPG would be ramping with the LUT pattern repeatedly. +- qcom,ramp-from-low-to-high: + Usage: optional + Value type: + Definition: The flag to specify the LPG ramping direction. The ramping + direction is from low index to high index of the LUT + pattern if it's specified. This property is not required + when SDAM module is used. + - qcom,ramp-toggle: Usage: optional Value type: Definition: The flag to specify if LPG would toggle the LUT pattern in ramping. If toggling enabled, LPG would return to the low index when high index is reached, or return to the high - index when low index is reached. + index when low index is reached. This property is not + required when SDAM module is used. - qcom,ramp-pause-hi-count: Usage: optional Value type: Definition: The step count that LPG stop the output when it ramped up - to the high index of the LUT. + to the high index of the LUT. This property is not + required when SDAM module is used. - qcom,ramp-pause-lo-count: Usage: optional Value type: Definition: The step count that LPG stop the output when it ramped up - to the low index of the LUT. -Example: + to the low index of the LUT. This property is not + required when SDAM module is used. + +Example when LUT pattern is stored in a LUT module: - pmi8998_lpg: lpg@b100 { + pm8150l_lpg: lpg@b100 { compatible = "qcom,pwm-lpg"; reg = <0xb100 0x600>, <0xb000 0x100>; reg-names = "lpg-base", "lut-base"; #pwm-cells = <2>; qcom,lut-patterns = <0 14 28 42 56 70 84 100 100 84 70 56 42 28 14 0>; - lpg@3 { - qcom,lpg-chan-id = <3>; + lpg@1 { + qcom,lpg-chan-id = <1>; qcom,ramp-step-ms = <200>; qcom,ramp-pause-hi-count = <10>; qcom,ramp-pause-lo-count = <10>; @@ -124,8 +176,8 @@ Example: qcom,ramp-from-low-to-high; qcom,ramp-pattern-repeat; }; - lpg@4 { - qcom,lpg-chan-id = <4>; + lpg@2 { + qcom,lpg-chan-id = <2>; qcom,ramp-step-ms = <200>; qcom,ramp-pause-hi-count = <10>; qcom,ramp-pause-lo-count = <10>; @@ -134,8 +186,8 @@ Example: qcom,ramp-from-low-to-high; qcom,ramp-pattern-repeat; }; - lpg@5 { - qcom,lpg-chan-id = <5>; + lpg@3 { + qcom,lpg-chan-id = <3>; qcom,ramp-step-ms = <200>; qcom,ramp-pause-hi-count = <10>; qcom,ramp-pause-lo-count = <10>; @@ -145,3 +197,42 @@ Example: qcom,ramp-pattern-repeat; }; }; + +Example when LUT pattern is stored in a SDAM module: + + pmi632_lpg: lpg@b100 { + compatible = "qcom,pwm-lpg"; + reg = <0xb100 0x600>; + reg-names = "lpg-base"; + #pwm-cells = <2>; + nvmem-names = "ppg_sdam"; + nvmem = <&sdam7>; + qcom,pbs-client = <&pbs_client_3>; + qcom,lut-sdam-base = <0x80>; + qcom,lut-patterns = <0 14 28 42 56 70 84 100 + 100 84 70 56 42 28 14 0>; + lpg@1 { + qcom,lpg-chan-id = <1>; + qcom,ramp-step-ms = <200>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <15>; + qcom,ramp-pattern-repeat; + qcom,lpg-sdam-base = <0x48>: + }; + lpg@2 { + qcom,lpg-chan-id = <2>; + qcom,ramp-step-ms = <200>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <15>; + qcom,ramp-pattern-repeat; + qcom,lpg-sdam-base = <0x56>; + }; + lpg@3 { + qcom,lpg-chan-id = <3>; + qcom,ramp-step-ms = <200>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <15>; + qcom,ramp-pattern-repeat; + qcom,lpg-sdam-base = <0x64>; + }; + }; diff --git a/drivers/pwm/pwm-qti-lpg.c b/drivers/pwm/pwm-qti-lpg.c index 31f5204e330b..d24bef10c1d7 100644 --- a/drivers/pwm/pwm-qti-lpg.c +++ b/drivers/pwm/pwm-qti-lpg.c @@ -19,10 +19,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -105,6 +107,34 @@ #define LPG_LUT_VALUE_MSB_MASK BIT(0) #define LPG_LUT_COUNT_MAX 47 +/* LPG config settings in SDAM */ +#define SDAM_REG_PBS_SEQ_EN 0x42 +#define PBS_SW_TRG_BIT BIT(0) + +#define SDAM_REG_RAMP_STEP_DURATION 0x47 + +#define SDAM_LUT_EN_OFFSET 0x0 +#define SDAM_PATTERN_CONFIG_OFFSET 0x1 +#define SDAM_END_INDEX_OFFSET 0x3 +#define SDAM_START_INDEX_OFFSET 0x4 +#define SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET 0x6 + +/* SDAM_REG_LUT_EN */ +#define SDAM_LUT_EN_BIT BIT(0) + +/* SDAM_REG_PATTERN_CONFIG */ +#define SDAM_PATTERN_LOOP_ENABLE BIT(3) +#define SDAM_PATTERN_RAMP_TOGGLE BIT(2) +#define SDAM_PATTERN_EN_PAUSE_END BIT(1) +#define SDAM_PATTERN_EN_PAUSE_START BIT(0) + +/* SDAM_REG_PAUSE_MULTIPLIER */ +#define SDAM_PAUSE_START_SHIFT 4 +#define SDAM_PAUSE_START_MASK GENMASK(7, 4) +#define SDAM_PAUSE_END_MASK GENMASK(3, 0) + +#define SDAM_LUT_COUNT_MAX 64 + enum lpg_src { LUT_PATTERN = 0, PWM_VALUE, @@ -151,6 +181,7 @@ struct qpnp_lpg_channel { u32 lpg_idx; u32 reg_base; u32 max_pattern_length; + u32 lpg_sdam_base; u8 src_sel; u8 subtype; bool lut_written; @@ -165,7 +196,11 @@ struct qpnp_lpg_chip { struct qpnp_lpg_channel *lpgs; struct qpnp_lpg_lut *lut; struct mutex bus_lock; + struct nvmem_device *sdam_nvmem; + struct device_node *pbs_dev_node; u32 num_lpgs; + unsigned long pbs_en_bitmap; + bool use_sdam; }; static int qpnp_lpg_read(struct qpnp_lpg_channel *lpg, u16 addr, u8 *val) @@ -192,7 +227,7 @@ static int qpnp_lpg_write(struct qpnp_lpg_channel *lpg, u16 addr, u8 val) mutex_lock(&lpg->chip->bus_lock); rc = regmap_write(lpg->chip->regmap, lpg->reg_base + addr, val); if (rc < 0) - dev_err(lpg->chip->dev, "Write addr 0x%x with value %d failed, rc=%d\n", + dev_err(lpg->chip->dev, "Write addr 0x%x with value 0x%x failed, rc=%d\n", lpg->reg_base + addr, val, rc); mutex_unlock(&lpg->chip->bus_lock); @@ -245,6 +280,90 @@ static int qpnp_lut_masked_write(struct qpnp_lpg_lut *lut, return rc; } +static int qpnp_sdam_write(struct qpnp_lpg_chip *chip, u16 addr, u8 val) +{ + int rc; + + mutex_lock(&chip->bus_lock); + rc = nvmem_device_write(chip->sdam_nvmem, addr, 1, &val); + if (rc < 0) + dev_err(chip->dev, "write SDAM add 0x%x failed, rc=%d\n", + addr, rc); + + mutex_unlock(&chip->bus_lock); + + return rc > 0 ? 0 : rc; +} + +static int qpnp_lpg_sdam_write(struct qpnp_lpg_channel *lpg, u16 addr, u8 val) +{ + struct qpnp_lpg_chip *chip = lpg->chip; + int rc; + + mutex_lock(&chip->bus_lock); + rc = nvmem_device_write(chip->sdam_nvmem, + lpg->lpg_sdam_base + addr, 1, &val); + if (rc < 0) + dev_err(chip->dev, "write SDAM add 0x%x failed, rc=%d\n", + lpg->lpg_sdam_base + addr, rc); + + mutex_unlock(&chip->bus_lock); + + return rc > 0 ? 0 : rc; +} + +static int qpnp_lpg_sdam_masked_write(struct qpnp_lpg_channel *lpg, + u16 addr, u8 mask, u8 val) +{ + int rc; + u8 tmp; + struct qpnp_lpg_chip *chip = lpg->chip; + + mutex_lock(&chip->bus_lock); + + rc = nvmem_device_read(chip->sdam_nvmem, + lpg->lpg_sdam_base + addr, 1, &tmp); + if (rc < 0) { + dev_err(chip->dev, "Read SDAM addr %d failed, rc=%d\n", + lpg->lpg_sdam_base + addr, rc); + goto unlock; + } + + tmp = tmp & ~mask; + tmp |= val & mask; + rc = nvmem_device_write(chip->sdam_nvmem, + lpg->lpg_sdam_base + addr, 1, &tmp); + if (rc < 0) + dev_err(chip->dev, "write SDAM addr %d failed, rc=%d\n", + lpg->lpg_sdam_base + addr, rc); + +unlock: + mutex_unlock(&chip->bus_lock); + + return rc > 0 ? 0 : rc; +} + +static int qpnp_lut_sdam_write(struct qpnp_lpg_lut *lut, + u16 addr, u8 *val, size_t length) +{ + struct qpnp_lpg_chip *chip = lut->chip; + int rc; + + if (addr >= SDAM_LUT_COUNT_MAX) + return -EINVAL; + + mutex_lock(&chip->bus_lock); + rc = nvmem_device_write(chip->sdam_nvmem, + lut->reg_base + addr, length, val); + if (rc < 0) + dev_err(chip->dev, "write SDAM addr %d failed, rc=%d\n", + lut->reg_base + addr, rc); + + mutex_unlock(&chip->bus_lock); + + return rc > 0 ? 0 : rc; +} + static struct qpnp_lpg_channel *pwm_dev_to_qpnp_lpg(struct pwm_chip *pwm_chip, struct pwm_device *pwm) { @@ -365,14 +484,111 @@ static int qpnp_lpg_set_pwm_config(struct qpnp_lpg_channel *lpg) return rc; } +static int qpnp_lpg_set_sdam_lut_pattern(struct qpnp_lpg_channel *lpg, + unsigned int *pattern, unsigned int length) +{ + struct qpnp_lpg_lut *lut = lpg->chip->lut; + int i, rc = 0; + u8 val[SDAM_LUT_COUNT_MAX + 1], addr; + + if (length > lpg->max_pattern_length) { + dev_err(lpg->chip->dev, "new pattern length (%d) larger than predefined (%d)\n", + length, lpg->max_pattern_length); + return -EINVAL; + } + + /* Program LUT pattern */ + mutex_lock(&lut->lock); + addr = lpg->ramp_config.lo_idx; + for (i = 0; i < length; i++) + val[i] = pattern[i] * 255 / 100; + + rc = qpnp_lut_sdam_write(lut, addr, val, length); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write pattern in SDAM failed, rc=%d", + rc); + goto unlock; + } + + lpg->ramp_config.pattern_length = length; +unlock: + mutex_unlock(&lut->lock); + + return rc; +} + +static int qpnp_lpg_set_sdam_ramp_config(struct qpnp_lpg_channel *lpg) +{ + struct lpg_ramp_config *ramp = &lpg->ramp_config; + u8 addr, mask, val; + int rc = 0; + + /* clear PBS scatchpad register */ + val = 0; + rc = qpnp_lpg_sdam_write(lpg, + SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET, val); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET failed, rc=%d\n", + rc); + return rc; + } + + /* Set ramp step duration, one WAIT_TICK is 7.8ms */ + val = (ramp->step_ms * 1000 / 7800) & 0xff; + if (val > 0) + val--; + addr = SDAM_REG_RAMP_STEP_DURATION; + rc = qpnp_sdam_write(lpg->chip, addr, val); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write SDAM_REG_RAMP_STEP_DURATION failed, rc=%d\n", + rc); + return rc; + } + + /* Set hi_idx and lo_idx */ + rc = qpnp_lpg_sdam_write(lpg, SDAM_END_INDEX_OFFSET, ramp->hi_idx); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write SDAM_REG_END_INDEX failed, rc=%d\n", + rc); + return rc; + } + + rc = qpnp_lpg_sdam_write(lpg, SDAM_START_INDEX_OFFSET, + ramp->lo_idx); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write SDAM_REG_START_INDEX failed, rc=%d\n", + rc); + return rc; + } + + /* Set LPG_PATTERN_CONFIG */ + addr = SDAM_PATTERN_CONFIG_OFFSET; + mask = SDAM_PATTERN_LOOP_ENABLE; + val = 0; + if (ramp->pattern_repeat) + val |= SDAM_PATTERN_LOOP_ENABLE; + + rc = qpnp_lpg_sdam_masked_write(lpg, addr, mask, val); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write SDAM_REG_PATTERN_CONFIG failed, rc=%d\n", + rc); + return rc; + } + + return rc; +} + static int qpnp_lpg_set_lut_pattern(struct qpnp_lpg_channel *lpg, unsigned int *pattern, unsigned int length) { struct qpnp_lpg_lut *lut = lpg->chip->lut; + u16 full_duty_value, pwm_values[SDAM_LUT_COUNT_MAX + 1] = {0}; int i, rc = 0; - u16 full_duty_value, pwm_values[LPG_LUT_COUNT_MAX + 1] = {0}; u8 lsb, msb, addr; + if (lpg->chip->use_sdam) + return qpnp_lpg_set_sdam_lut_pattern(lpg, pattern, length); + if (length > lpg->max_pattern_length) { dev_err(lpg->chip->dev, "new pattern length (%d) larger than predefined (%d)\n", length, lpg->max_pattern_length); @@ -426,6 +642,9 @@ static int qpnp_lpg_set_ramp_config(struct qpnp_lpg_channel *lpg) u8 lsb, msb, addr, mask, val; int rc = 0; + if (lpg->chip->use_sdam) + return qpnp_lpg_set_sdam_ramp_config(lpg); + /* Set ramp step duration */ lsb = ramp->step_ms & 0xff; msb = ramp->step_ms >> 8; @@ -507,6 +726,8 @@ static int qpnp_lpg_set_ramp_config(struct qpnp_lpg_channel *lpg) static void __qpnp_lpg_calc_pwm_period(int period_ns, struct lpg_pwm_config *pwm_config) { + struct qpnp_lpg_channel *lpg = container_of(pwm_config, + struct qpnp_lpg_channel, pwm_config); struct lpg_pwm_config configs[NUM_PWM_SIZE]; int i, j, m, n; int tmp1, tmp2; @@ -522,7 +743,12 @@ static void __qpnp_lpg_calc_pwm_period(int period_ns, * * Searching the closest settings for the requested PWM period. */ - for (n = 0; n < ARRAY_SIZE(pwm_size); n++) { + if (lpg->chip->use_sdam) + /* SDAM pattern control can only use 9 bit resolution */ + n = 1; + else + n = 0; + for (; n < ARRAY_SIZE(pwm_size); n++) { pwm_clk_period_ns = period_ns >> pwm_size[n]; for (i = ARRAY_SIZE(clk_freq_hz) - 1; i >= 0; i--) { for (j = 0; j < ARRAY_SIZE(clk_prediv); j++) { @@ -654,6 +880,45 @@ static int qpnp_lpg_pwm_config(struct pwm_chip *pwm_chip, return rc; } +static int qpnp_lpg_pbs_trigger_enable(struct qpnp_lpg_channel *lpg, bool en) +{ + struct qpnp_lpg_chip *chip = lpg->chip; + int rc = 0; + + if (en) { + if (chip->pbs_en_bitmap == 0) { + rc = qpnp_sdam_write(chip, SDAM_REG_PBS_SEQ_EN, + PBS_SW_TRG_BIT); + if (rc < 0) { + dev_err(chip->dev, "Write SDAM_REG_PBS_SEQ_EN failed, rc=%d\n", + rc); + return rc; + } + + rc = qpnp_pbs_trigger_event(chip->pbs_dev_node, + PBS_SW_TRG_BIT); + if (rc < 0) { + dev_err(chip->dev, "Failed to trigger PBS, rc=%d\n", + rc); + return rc; + } + } + set_bit(lpg->lpg_idx, &chip->pbs_en_bitmap); + } else { + clear_bit(lpg->lpg_idx, &chip->pbs_en_bitmap); + if (chip->pbs_en_bitmap == 0) { + rc = qpnp_sdam_write(chip, SDAM_REG_PBS_SEQ_EN, 0); + if (rc < 0) { + dev_err(chip->dev, "Write SDAM_REG_PBS_SEQ_EN failed, rc=%d\n", + rc); + return rc; + } + } + } + + return rc; +} + static int qpnp_lpg_pwm_src_enable(struct qpnp_lpg_channel *lpg, bool en) { struct qpnp_lpg_chip *chip = lpg->chip; @@ -665,7 +930,7 @@ static int qpnp_lpg_pwm_src_enable(struct qpnp_lpg_channel *lpg, bool en) LPG_EN_RAMP_GEN_MASK; val = lpg->src_sel << LPG_PWM_SRC_SELECT_SHIFT; - if (lpg->src_sel == LUT_PATTERN) + if (lpg->src_sel == LUT_PATTERN && !chip->use_sdam) val |= 1 << LPG_EN_RAMP_GEN_SHIFT; if (en) @@ -678,6 +943,27 @@ static int qpnp_lpg_pwm_src_enable(struct qpnp_lpg_channel *lpg, bool en) return rc; } + if (chip->use_sdam) { + if (lpg->src_sel == LUT_PATTERN && en) { + val = SDAM_LUT_EN_BIT; + en = true; + } else { + val = 0; + en = false; + } + + rc = qpnp_lpg_sdam_write(lpg, SDAM_LUT_EN_OFFSET, val); + if (rc < 0) { + dev_err(chip->dev, "Write SDAM_REG_LUT_EN failed, rc=%d\n", + rc); + return rc; + } + + qpnp_lpg_pbs_trigger_enable(lpg, en); + + return rc; + } + if (lpg->src_sel == LUT_PATTERN && en) { mutex_lock(&lut->lock); val = 1 << lpg->lpg_idx; @@ -697,6 +983,7 @@ static int qpnp_lpg_pwm_set_output_type(struct pwm_chip *pwm_chip, struct qpnp_lpg_channel *lpg; enum lpg_src src_sel; int rc; + bool is_enabled; lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm); if (lpg == NULL) { @@ -714,6 +1001,23 @@ static int qpnp_lpg_pwm_set_output_type(struct pwm_chip *pwm_chip, if (src_sel == lpg->src_sel) return 0; + is_enabled = pwm_is_enabled(pwm); + if (is_enabled) { + /* + * Disable the channel first then enable it later to make + * sure the output type is changed successfully. This is + * especially useful in SDAM use case to stop the PBS + * sequence when changing the PWM output type from + * MODULATED to FIXED. + */ + rc = qpnp_lpg_pwm_src_enable(lpg, false); + if (rc < 0) { + dev_err(pwm_chip->dev, "Enable PWM output failed for channel %d, rc=%d\n", + lpg->lpg_idx, rc); + return rc; + } + } + if (src_sel == LUT_PATTERN) { /* program LUT if it's never been programmed */ if (!lpg->lut_written) { @@ -738,7 +1042,14 @@ static int qpnp_lpg_pwm_set_output_type(struct pwm_chip *pwm_chip, lpg->src_sel = src_sel; - if (pwm_is_enabled(pwm)) { + if (is_enabled) { + rc = qpnp_lpg_set_pwm_config(lpg); + if (rc < 0) { + dev_err(pwm_chip->dev, "Config PWM failed for channel %d, rc=%d\n", + lpg->lpg_idx, rc); + return rc; + } + rc = qpnp_lpg_pwm_src_enable(lpg, true); if (rc < 0) { dev_err(pwm_chip->dev, "Enable PWM output failed for channel %d, rc=%d\n", @@ -979,7 +1290,7 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) struct qpnp_lpg_channel *lpg; struct lpg_ramp_config *ramp; int rc = 0, i; - u32 base, length, lpg_chan_id, tmp; + u32 base, length, lpg_chan_id, tmp, max_count; const __be32 *addr; addr = of_get_address(chip->dev->of_node, 0, NULL, NULL); @@ -1010,18 +1321,47 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) } } - addr = of_get_address(chip->dev->of_node, 1, NULL, NULL); - if (!addr) { - pr_debug("NO LUT address assigned\n"); - return 0; - } - chip->lut = devm_kmalloc(chip->dev, sizeof(*chip->lut), GFP_KERNEL); if (!chip->lut) return -ENOMEM; + chip->sdam_nvmem = devm_nvmem_device_get(chip->dev, "ppg_sdam"); + if (IS_ERR_OR_NULL(chip->sdam_nvmem)) { + if (PTR_ERR(chip->sdam_nvmem) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + addr = of_get_address(chip->dev->of_node, 1, NULL, NULL); + if (!addr) { + pr_debug("NO LUT address assigned\n"); + devm_kfree(chip->dev, chip->lut); + chip->lut = NULL; + return 0; + } + + chip->lut->reg_base = be32_to_cpu(*addr); + max_count = LPG_LUT_COUNT_MAX; + } else { + chip->use_sdam = true; + chip->pbs_dev_node = of_parse_phandle(chip->dev->of_node, + "qcom,pbs-client", 0); + if (!chip->pbs_dev_node) { + dev_err(chip->dev, "Missing qcom,pbs-client property\n"); + return -EINVAL; + } + + rc = of_property_read_u32(chip->dev->of_node, + "qcom,lut-sdam-base", + &chip->lut->reg_base); + if (rc < 0) { + dev_err(chip->dev, "Read qcom,lut-sdam-base failed, rc=%d\n", + rc); + return rc; + } + + max_count = SDAM_LUT_COUNT_MAX; + } + chip->lut->chip = chip; - chip->lut->reg_base = be32_to_cpu(*addr); mutex_init(&chip->lut->lock); rc = of_property_count_elems_of_size(chip->dev->of_node, @@ -1033,13 +1373,13 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) } length = rc; - if (length > LPG_LUT_COUNT_MAX) { + if (length > max_count) { dev_err(chip->dev, "qcom,lut-patterns length %d exceed max %d\n", - length, LPG_LUT_COUNT_MAX); + length, max_count); return -EINVAL; } - chip->lut->pattern = devm_kcalloc(chip->dev, LPG_LUT_COUNT_MAX, + chip->lut->pattern = devm_kcalloc(chip->dev, max_count, sizeof(*chip->lut->pattern), GFP_KERNEL); if (!chip->lut->pattern) return -ENOMEM; @@ -1066,12 +1406,24 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) return rc; } - if (lpg_chan_id > chip->num_lpgs) { + if (lpg_chan_id < 1 || lpg_chan_id > chip->num_lpgs) { dev_err(chip->dev, "lpg-chann-id %d is out of range 1~%d\n", lpg_chan_id, chip->num_lpgs); return -EINVAL; } + if (chip->use_sdam) { + rc = of_property_read_u32(child, + "qcom,lpg-sdam-base", + &tmp); + if (rc < 0) { + dev_err(chip->dev, "get qcom,lpg-sdam-base failed for lpg%d, rc=%d\n", + lpg_chan_id, rc); + return rc; + } + chip->lpgs[lpg_chan_id - 1].lpg_sdam_base = tmp; + } + /* lpg channel id is indexed from 1 in hardware */ lpg = &chip->lpgs[lpg_chan_id - 1]; ramp = &lpg->ramp_config; @@ -1091,9 +1443,9 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) return rc; } ramp->lo_idx = (u8)tmp; - if (ramp->lo_idx >= LPG_LUT_COUNT_MAX) { + if (ramp->lo_idx >= max_count) { dev_err(chip->dev, "qcom,ramp-low-index should less than max %d\n", - LPG_LUT_COUNT_MAX); + max_count); return -EINVAL; } @@ -1105,14 +1457,14 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) } ramp->hi_idx = (u8)tmp; - if (ramp->hi_idx > LPG_LUT_COUNT_MAX) { + if (ramp->hi_idx > max_count) { dev_err(chip->dev, "qcom,ramp-high-index shouldn't exceed max %d\n", - LPG_LUT_COUNT_MAX); + max_count); return -EINVAL; } - if (ramp->hi_idx <= ramp->lo_idx) { - dev_err(chip->dev, "high-index(%d) should be larger than low-index(%d)\n", + if (chip->use_sdam && ramp->hi_idx <= ramp->lo_idx) { + dev_err(chip->dev, "high-index(%d) should be larger than low-index(%d) when SDAM used\n", ramp->hi_idx, ramp->lo_idx); return -EINVAL; } @@ -1121,6 +1473,12 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) ramp->pattern = &chip->lut->pattern[ramp->lo_idx]; lpg->max_pattern_length = ramp->pattern_length; + ramp->pattern_repeat = of_property_read_bool(child, + "qcom,ramp-pattern-repeat"); + + if (chip->use_sdam) + continue; + rc = of_property_read_u32(child, "qcom,ramp-pause-hi-count", &tmp); if (rc < 0) @@ -1138,9 +1496,6 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) ramp->ramp_dir_low_to_hi = of_property_read_bool(child, "qcom,ramp-from-low-to-high"); - ramp->pattern_repeat = of_property_read_bool(child, - "qcom,ramp-pattern-repeat"); - ramp->toggle = of_property_read_bool(child, "qcom,ramp-toggle"); } @@ -1148,6 +1503,36 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) return 0; } +static int qpnp_lpg_sdam_hw_init(struct qpnp_lpg_chip *chip) +{ + struct qpnp_lpg_channel *lpg; + int i, rc = 0; + + if (!chip->use_sdam) + return 0; + + for (i = 0; i < chip->num_lpgs; i++) { + lpg = &chip->lpgs[i]; + if (lpg->lpg_sdam_base != 0) { + rc = qpnp_lpg_sdam_write(lpg, SDAM_LUT_EN_OFFSET, 0); + if (rc < 0) { + dev_err(chip->dev, "Write SDAM_REG_LUT_EN failed, rc=%d\n", + rc); + return rc; + } + rc = qpnp_lpg_sdam_write(lpg, + SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET, 0); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write SDAM_REG_PBS_SCRATCH_LUT_COUNTER failed, rc=%d\n", + rc); + return rc; + } + } + } + + return rc; +} + static int qpnp_lpg_probe(struct platform_device *pdev) { int rc; @@ -1172,6 +1557,13 @@ static int qpnp_lpg_probe(struct platform_device *pdev) goto err_out; } + rc = qpnp_lpg_sdam_hw_init(chip); + if (rc < 0) { + dev_err(chip->dev, "SDAM HW init failed, rc=%d\n", + rc); + goto err_out; + } + dev_set_drvdata(chip->dev, chip); chip->pwm_chip.dev = chip->dev; chip->pwm_chip.base = -1; -- GitLab From 0a6dfff0a32c9a355b5f910cb51d30b214142c89 Mon Sep 17 00:00:00 2001 From: Jayant Shekhar Date: Tue, 5 Jun 2018 12:43:06 +0530 Subject: [PATCH 708/855] drm/msm/sde: Prevent multiple unblank event trigger In cases such as dynamic fps, resolution switch, currently unblank event is triggered every time when new modeset is required. Trigger the event only when active changed. Change-Id: I6387f576a804999f1e916a1852a4c21719de9e91 Signed-off-by: Jayant Shekhar --- drivers/gpu/drm/msm/msm_atomic.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 8ffe0449f712..e445098f1bed 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -462,12 +462,15 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev, DRM_DEBUG_ATOMIC("enabling [ENCODER:%d:%s]\n", encoder->base.id, encoder->name); - blank = MSM_DRM_BLANK_UNBLANK; - notifier_data.data = ␣ - notifier_data.id = - connector->state->crtc->index; - msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK, + if (connector->state->crtc->state->active_changed) { + blank = MSM_DRM_BLANK_UNBLANK; + notifier_data.data = ␣ + notifier_data.id = + connector->state->crtc->index; + DRM_DEBUG_ATOMIC("Notify early unblank\n"); + msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK, ¬ifier_data); + } /* * Each encoder has at most one connector (since we always steal * it away), so we won't call enable hooks twice. @@ -512,8 +515,11 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev, encoder->base.id, encoder->name); drm_bridge_enable(encoder->bridge); - msm_drm_notifier_call_chain(MSM_DRM_EVENT_BLANK, + if (connector->state->crtc->state->active_changed) { + DRM_DEBUG_ATOMIC("Notify unblank\n"); + msm_drm_notifier_call_chain(MSM_DRM_EVENT_BLANK, ¬ifier_data); + } } SDE_ATRACE_END("msm_enable"); } -- GitLab From 9b4d0765f62f9c71a56b81af353e9bf7446185dd Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Mon, 4 Jun 2018 19:52:23 +0530 Subject: [PATCH 709/855] power: qpnp-qg: Add ESR estimation Add support for online ESR (equivalent series resistance) estimation for the battery. It is currently enabled during charge. The QG driver periodically (configurable) fires ESR pulses and calculates the ESR. The ESR is qualified and filtered before passing it to the userspace for further processing. The processed values from userspace are stored back into SDAM for subsequent reboots. While at it, also add a few DT properties for ESR and update the capacity learning default values. Change-Id: Ic343f0d8a0109020fe384089355cfbe9a92f9a78 Signed-off-by: Anirudh Ghayal --- .../bindings/power/supply/qcom/qpnp-qg.txt | 33 ++ drivers/power/supply/qcom/qg-core.h | 20 + drivers/power/supply/qcom/qg-defs.h | 3 + drivers/power/supply/qcom/qg-reg.h | 36 +- drivers/power/supply/qcom/qg-sdam.c | 20 + drivers/power/supply/qcom/qg-sdam.h | 4 + drivers/power/supply/qcom/qg-util.c | 16 + drivers/power/supply/qcom/qg-util.h | 1 + drivers/power/supply/qcom/qpnp-qg.c | 556 +++++++++++++++--- include/uapi/linux/qg.h | 12 +- 10 files changed, 618 insertions(+), 83 deletions(-) diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt index afeb65dc86d0..43e7380b0c03 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt @@ -262,6 +262,39 @@ First Level Node - QGAUGE device capacity learning cycle. If this is not specified, then the default value is 0. Unit is in decipercentage. +- qcom,esr-disable + Usage: optional + Value type: + Definition: Boolean property to disable ESR estimation. If not defined + ESR estimation stays enabled for charge-cycles. + +- qcom,esr-discharge-enable + Usage: optional + Value type: + Definition: Boolean property to enable ESR estimation during discharge. + Only valid if 'qcom,esr-disable' is not defined. + +- qcom,esr-qual-current-ua + Usage: optional + Value type: + Definition: Minimum current differential in uA to qualify an ESR + reading as valid. If not defined the value defaults + to 130mA. + +- qcom,esr-qual-vbatt-uv + Usage: optional + Value type: + Definition: Minimum vbatt differential in uV to qualify an ESR + reading as valid. If not defined the value defaults + to 7mV. + +- qcom,esr-disable-soc + Usage: optional + Value type: + Definition: Minimum battery SOC below which ESR will not be + attempted by QG. If not defined the value defaults + to 10%. + ========================================================== Second Level Nodes - Peripherals managed by QGAUGE driver ========================================================== diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index a1aeac2b86ef..b2c8b892c938 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -14,6 +14,7 @@ #include #include "fg-alg.h" +#include "qg-defs.h" struct qg_batt_props { const char *batt_type_str; @@ -50,10 +51,24 @@ struct qg_dt { int rbat_conn_mohm; int ignore_shutdown_soc_secs; int cold_temp_threshold; + int esr_qual_i_ua; + int esr_qual_v_uv; + int esr_disable_soc; bool hold_soc_while_full; bool linearize_soc; bool cl_disable; bool cl_feedback_on; + bool esr_disable; + bool esr_discharge_enable; +}; + +struct qg_esr_data { + u32 pre_esr_v; + u32 pre_esr_i; + u32 post_esr_v; + u32 post_esr_i; + u32 esr; + bool valid; }; struct qpnp_qg { @@ -87,6 +102,7 @@ struct qpnp_qg { struct power_supply *batt_psy; struct power_supply *usb_psy; struct power_supply *parallel_psy; + struct qg_esr_data esr_data[QG_MAX_ESR_COUNT]; /* status variable */ u32 *debug_mask; @@ -103,9 +119,12 @@ struct qpnp_qg { int charge_status; int charge_type; int next_wakeup_ms; + u32 fifo_done_count; u32 wa_flags; u32 seq_no; u32 charge_counter_uah; + u32 esr_avg; + u32 esr_last; ktime_t last_user_update_time; ktime_t last_fifo_update_time; @@ -147,6 +166,7 @@ enum debug_mask { QG_DEBUG_BUS_READ = BIT(8), QG_DEBUG_BUS_WRITE = BIT(9), QG_DEBUG_ALG_CL = BIT(10), + QG_DEBUG_ESR = BIT(11), }; enum qg_irq { diff --git a/drivers/power/supply/qcom/qg-defs.h b/drivers/power/supply/qcom/qg-defs.h index 2061208ad55c..02a193fc3461 100644 --- a/drivers/power/supply/qcom/qg-defs.h +++ b/drivers/power/supply/qcom/qg-defs.h @@ -44,6 +44,9 @@ #define UV_TO_DECIUV(a) (a / 100) #define DECIUV_TO_UV(a) (a * 100) +#define QG_MAX_ESR_COUNT 10 +#define QG_MIN_ESR_COUNT 2 + #define CAP(min, max, value) \ ((min > value) ? min : ((value > max) ? max : value)) diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h index 66f9be11a7df..d586a721d8b7 100644 --- a/drivers/power/supply/qcom/qg-reg.h +++ b/drivers/power/supply/qcom/qg-reg.h @@ -18,6 +18,7 @@ #define QG_STATUS1_REG 0x08 #define BATTERY_PRESENT_BIT BIT(0) +#define ESR_MEAS_DONE_BIT BIT(4) #define QG_STATUS2_REG 0x09 #define GOOD_OCV_BIT BIT(1) @@ -25,6 +26,9 @@ #define QG_STATUS3_REG 0x0A #define COUNT_FIFO_RT_MASK GENMASK(3, 0) +#define QG_STATUS4_REG 0x0B +#define ESR_MEAS_IN_PROGRESS_BIT BIT(4) + #define QG_INT_RT_STS_REG 0x10 #define FIFO_UPDATE_DONE_RT_STS_BIT BIT(3) #define VBAT_LOW_INT_RT_STS_BIT BIT(1) @@ -60,11 +64,19 @@ #define QG_S3_ENTRY_IBAT_THRESHOLD_REG 0x5E #define QG_S3_EXIT_IBAT_THRESHOLD_REG 0x5F +#define QG_ESR_MEAS_TRIG_REG 0x68 +#define HW_ESR_MEAS_START_BIT BIT(0) + #define QG_S7_PON_OCV_V_DATA0_REG 0x70 #define QG_S7_PON_OCV_I_DATA0_REG 0x72 #define QG_S3_GOOD_OCV_V_DATA0_REG 0x74 #define QG_S3_GOOD_OCV_I_DATA0_REG 0x76 +#define QG_PRE_ESR_V_DATA0_REG 0x78 +#define QG_PRE_ESR_I_DATA0_REG 0x7A +#define QG_POST_ESR_V_DATA0_REG 0x7C +#define QG_POST_ESR_I_DATA0_REG 0x7E + #define QG_V_ACCUM_DATA0_RT_REG 0x88 #define QG_I_ACCUM_DATA0_RT_REG 0x8B #define QG_ACCUM_CNT_RT_REG 0x8E @@ -80,15 +92,19 @@ #define QG_LAST_S3_SLEEP_V_DATA0_REG 0xCC /* SDAM offsets */ -#define QG_SDAM_VALID_OFFSET 0x46 -#define QG_SDAM_SOC_OFFSET 0x47 -#define QG_SDAM_TEMP_OFFSET 0x48 -#define QG_SDAM_RBAT_OFFSET 0x4A -#define QG_SDAM_OCV_OFFSET 0x4C -#define QG_SDAM_IBAT_OFFSET 0x50 -#define QG_SDAM_TIME_OFFSET 0x54 -#define QG_SDAM_CYCLE_COUNT_OFFSET 0x58 -#define QG_SDAM_LEARNED_CAPACITY_OFFSET 0x68 -#define QG_SDAM_PON_OCV_OFFSET 0x7C +#define QG_SDAM_VALID_OFFSET 0x46 /* 1-byte 0x46 */ +#define QG_SDAM_SOC_OFFSET 0x47 /* 1-byte 0x47 */ +#define QG_SDAM_TEMP_OFFSET 0x48 /* 2-byte 0x48-0x49 */ +#define QG_SDAM_RBAT_OFFSET 0x4A /* 2-byte 0x4A-0x4B */ +#define QG_SDAM_OCV_OFFSET 0x4C /* 4-byte 0x4C-0x4F */ +#define QG_SDAM_IBAT_OFFSET 0x50 /* 4-byte 0x50-0x53 */ +#define QG_SDAM_TIME_OFFSET 0x54 /* 4-byte 0x54-0x57 */ +#define QG_SDAM_CYCLE_COUNT_OFFSET 0x58 /* 16-byte 0x58-0x67 */ +#define QG_SDAM_LEARNED_CAPACITY_OFFSET 0x68 /* 2-byte 0x68-0x69 */ +#define QG_SDAM_ESR_CHARGE_DELTA_OFFSET 0x6A /* 4-byte 0x6A-0x6D */ +#define QG_SDAM_ESR_DISCHARGE_DELTA_OFFSET 0x6E /* 4-byte 0x6E-0x71 */ +#define QG_SDAM_ESR_CHARGE_SF_OFFSET 0x72 /* 2-byte 0x72-0x73 */ +#define QG_SDAM_ESR_DISCHARGE_SF_OFFSET 0x74 /* 2-byte 0x74-0x75 */ +#define QG_SDAM_PON_OCV_OFFSET 0x7C /* 2-byte 0x7C-0x7D */ #endif diff --git a/drivers/power/supply/qcom/qg-sdam.c b/drivers/power/supply/qcom/qg-sdam.c index 7bc4afac1b44..e7ffcb592dfb 100644 --- a/drivers/power/supply/qcom/qg-sdam.c +++ b/drivers/power/supply/qcom/qg-sdam.c @@ -68,6 +68,26 @@ static struct qg_sdam_info sdam_info[] = { .offset = QG_SDAM_PON_OCV_OFFSET, .length = 2, }, + [SDAM_ESR_CHARGE_DELTA] = { + .name = "SDAM_ESR_CHARGE_DELTA", + .offset = QG_SDAM_ESR_CHARGE_DELTA_OFFSET, + .length = 4, + }, + [SDAM_ESR_DISCHARGE_DELTA] = { + .name = "SDAM_ESR_DISCHARGE_DELTA", + .offset = QG_SDAM_ESR_DISCHARGE_DELTA_OFFSET, + .length = 4, + }, + [SDAM_ESR_CHARGE_SF] = { + .name = "SDAM_ESR_CHARGE_SF_OFFSET", + .offset = QG_SDAM_ESR_CHARGE_SF_OFFSET, + .length = 2, + }, + [SDAM_ESR_DISCHARGE_SF] = { + .name = "SDAM_ESR_DISCHARGE_SF_OFFSET", + .offset = QG_SDAM_ESR_DISCHARGE_SF_OFFSET, + .length = 2, + }, }; int qg_sdam_write(u8 param, u32 data) diff --git a/drivers/power/supply/qcom/qg-sdam.h b/drivers/power/supply/qcom/qg-sdam.h index 10e684f8ec40..45218a83776e 100644 --- a/drivers/power/supply/qcom/qg-sdam.h +++ b/drivers/power/supply/qcom/qg-sdam.h @@ -24,6 +24,10 @@ enum qg_sdam_param { SDAM_IBAT_UA, SDAM_TIME_SEC, SDAM_PON_OCV_UV, + SDAM_ESR_CHARGE_DELTA, + SDAM_ESR_DISCHARGE_DELTA, + SDAM_ESR_CHARGE_SF, + SDAM_ESR_DISCHARGE_SF, SDAM_MAX, }; diff --git a/drivers/power/supply/qcom/qg-util.c b/drivers/power/supply/qcom/qg-util.c index d354799f9209..824d9146057c 100644 --- a/drivers/power/supply/qcom/qg-util.c +++ b/drivers/power/supply/qcom/qg-util.c @@ -111,6 +111,22 @@ int qg_masked_write(struct qpnp_qg *chip, int addr, u32 mask, u32 val) return rc; } +int qg_read_raw_data(struct qpnp_qg *chip, int addr, u32 *data) +{ + int rc; + u8 reg[2] = {0}; + + rc = qg_read(chip, chip->qg_base + addr, ®[0], 2); + if (rc < 0) { + pr_err("Failed to read QG addr %d rc=%d\n", addr, rc); + return rc; + } + + *data = reg[0] | (reg[1] << 8); + + return rc; +} + int get_fifo_length(struct qpnp_qg *chip, u32 *fifo_length, bool rt) { int rc; diff --git a/drivers/power/supply/qcom/qg-util.h b/drivers/power/supply/qcom/qg-util.h index 385c9e072562..bb17afb4f5be 100644 --- a/drivers/power/supply/qcom/qg-util.h +++ b/drivers/power/supply/qcom/qg-util.h @@ -15,6 +15,7 @@ int qg_read(struct qpnp_qg *chip, u32 addr, u8 *val, int len); int qg_write(struct qpnp_qg *chip, u32 addr, u8 *val, int len); int qg_masked_write(struct qpnp_qg *chip, int addr, u32 mask, u32 val); +int qg_read_raw_data(struct qpnp_qg *chip, int addr, u32 *data); int get_fifo_length(struct qpnp_qg *chip, u32 *fifo_length, bool rt); int get_sample_count(struct qpnp_qg *chip, u32 *sample_count); int get_sample_interval(struct qpnp_qg *chip, u32 *sample_interval); diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 5a0682c3d421..0ee5c302b462 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -43,6 +43,16 @@ module_param_named( debug_mask, qg_debug_mask, int, 0600 ); +static int qg_esr_mod_count = 10; +module_param_named( + esr_mod_count, qg_esr_mod_count, int, 0600 +); + +static int qg_esr_count = 5; +module_param_named( + esr_count, qg_esr_count, int, 0600 +); + static bool is_battery_present(struct qpnp_qg *chip) { u8 reg = 0; @@ -228,7 +238,7 @@ static bool is_batt_available(struct qpnp_qg *chip) return true; } -static int qg_update_sdam_params(struct qpnp_qg *chip) +static int qg_store_soc_params(struct qpnp_qg *chip) { int rc, batt_temp = 0, i; unsigned long rtc_sec = 0; @@ -245,13 +255,11 @@ static int qg_update_sdam_params(struct qpnp_qg *chip) else chip->sdam_data[SDAM_TEMP] = (u32)batt_temp; - rc = qg_sdam_write_all(chip->sdam_data); - if (rc < 0) - pr_err("Failed to write to SDAM rc=%d\n", rc); - - for (i = 0; i < SDAM_MAX; i++) + for (i = 0; i <= SDAM_TIME_SEC; i++) { + rc |= qg_sdam_write(i, chip->sdam_data[i]); qg_dbg(chip, QG_DEBUG_STATUS, "SDAM write param %d value=%d\n", i, chip->sdam_data[i]); + } return rc; } @@ -433,6 +441,87 @@ static int qg_process_rt_fifo(struct qpnp_qg *chip) return rc; } +#define MIN_FIFO_FULL_TIME_MS 12000 +static int process_rt_fifo_data(struct qpnp_qg *chip, + bool vbat_low, bool update_smb) +{ + int rc = 0; + ktime_t now = ktime_get(); + s64 time_delta; + + /* + * Reject the FIFO read event if there are back-to-back requests + * This is done to gaurantee that there is always a minimum FIFO + * data to be processed, ignore this if vbat_low is set. + */ + time_delta = ktime_ms_delta(now, chip->last_user_update_time); + + qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms vbat_low=%d\n", + time_delta, vbat_low); + + if (time_delta > MIN_FIFO_FULL_TIME_MS || vbat_low || update_smb) { + rc = qg_master_hold(chip, true); + if (rc < 0) { + pr_err("Failed to hold master, rc=%d\n", rc); + goto done; + } + + rc = qg_process_rt_fifo(chip); + if (rc < 0) { + pr_err("Failed to process FIFO real-time, rc=%d\n", rc); + goto done; + } + + if (vbat_low) { + /* change FIFO length */ + rc = qg_update_fifo_length(chip, + chip->dt.s2_vbat_low_fifo_length); + if (rc < 0) + goto done; + + qg_dbg(chip, QG_DEBUG_STATUS, + "FIFO length updated to %d vbat_low=%d\n", + chip->dt.s2_vbat_low_fifo_length, + vbat_low); + } + + if (update_smb) { + rc = qg_masked_write(chip, chip->qg_base + + QG_MODE_CTL1_REG, PARALLEL_IBAT_SENSE_EN_BIT, + chip->parallel_enabled ? + PARALLEL_IBAT_SENSE_EN_BIT : 0); + if (rc < 0) { + pr_err("Failed to update SMB_EN, rc=%d\n", rc); + goto done; + } + qg_dbg(chip, QG_DEBUG_STATUS, "Parallel SENSE %d\n", + chip->parallel_enabled); + } + + rc = qg_master_hold(chip, false); + if (rc < 0) { + pr_err("Failed to release master, rc=%d\n", rc); + goto done; + } + /* FIFOs restarted */ + chip->last_fifo_update_time = ktime_get(); + + /* signal the read thread */ + chip->data_ready = true; + wake_up_interruptible(&chip->qg_wait_q); + chip->last_user_update_time = now; + + /* vote to stay awake until userspace reads data */ + vote(chip->awake_votable, FIFO_RT_DONE_VOTER, true, 0); + } else { + qg_dbg(chip, QG_DEBUG_FIFO, "FIFO processing too early time_delta=%lld\n", + time_delta); + } +done: + qg_master_hold(chip, false); + return rc; +} + #define VBAT_LOW_HYST_UV 50000 /* 50mV */ static int qg_vbat_low_wa(struct qpnp_qg *chip) { @@ -561,82 +650,353 @@ static int qg_vbat_thresholds_config(struct qpnp_qg *chip) return rc; } -#define MIN_FIFO_FULL_TIME_MS 12000 -static int process_rt_fifo_data(struct qpnp_qg *chip, - bool vbat_low, bool update_smb) +static void qg_retrieve_esr_params(struct qpnp_qg *chip) { - int rc = 0; - ktime_t now = ktime_get(); - s64 time_delta; + u32 data = 0; + int rc; + + rc = qg_sdam_read(SDAM_ESR_CHARGE_DELTA, &data); + if (!rc && data) { + chip->kdata.param[QG_ESR_CHARGE_DELTA].data = data; + chip->kdata.param[QG_ESR_CHARGE_DELTA].valid = true; + qg_dbg(chip, QG_DEBUG_ESR, + "ESR_CHARGE_DELTA SDAM=%d\n", data); + } else if (rc < 0) { + pr_err("Failed to read ESR_CHARGE_DELTA rc=%d\n", rc); + } + + rc = qg_sdam_read(SDAM_ESR_DISCHARGE_DELTA, &data); + if (!rc && data) { + chip->kdata.param[QG_ESR_DISCHARGE_DELTA].data = data; + chip->kdata.param[QG_ESR_DISCHARGE_DELTA].valid = true; + qg_dbg(chip, QG_DEBUG_ESR, + "ESR_DISCHARGE_DELTA SDAM=%d\n", data); + } else if (rc < 0) { + pr_err("Failed to read ESR_DISCHARGE_DELTA rc=%d\n", rc); + } + + rc = qg_sdam_read(SDAM_ESR_CHARGE_SF, &data); + if (!rc && data) { + chip->kdata.param[QG_ESR_CHARGE_SF].data = data; + chip->kdata.param[QG_ESR_CHARGE_SF].valid = true; + qg_dbg(chip, QG_DEBUG_ESR, + "ESR_CHARGE_SF SDAM=%d\n", data); + } else if (rc < 0) { + pr_err("Failed to read ESR_CHARGE_SF rc=%d\n", rc); + } + + rc = qg_sdam_read(SDAM_ESR_DISCHARGE_SF, &data); + if (!rc && data) { + chip->kdata.param[QG_ESR_DISCHARGE_SF].data = data; + chip->kdata.param[QG_ESR_DISCHARGE_SF].valid = true; + qg_dbg(chip, QG_DEBUG_ESR, + "ESR_DISCHARGE_SF SDAM=%d\n", data); + } else if (rc < 0) { + pr_err("Failed to read ESR_DISCHARGE_SF rc=%d\n", rc); + } +} + +static void qg_store_esr_params(struct qpnp_qg *chip) +{ + unsigned int esr; + + if (chip->udata.param[QG_ESR_CHARGE_DELTA].valid) { + esr = chip->udata.param[QG_ESR_CHARGE_DELTA].data; + qg_sdam_write(SDAM_ESR_CHARGE_DELTA, esr); + qg_dbg(chip, QG_DEBUG_ESR, + "SDAM store ESR_CHARGE_DELTA=%d\n", esr); + } + + if (chip->udata.param[QG_ESR_DISCHARGE_DELTA].valid) { + esr = chip->udata.param[QG_ESR_DISCHARGE_DELTA].data; + qg_sdam_write(SDAM_ESR_DISCHARGE_DELTA, esr); + qg_dbg(chip, QG_DEBUG_ESR, + "SDAM store ESR_DISCHARGE_DELTA=%d\n", esr); + } + + if (chip->udata.param[QG_ESR_CHARGE_SF].valid) { + esr = chip->udata.param[QG_ESR_CHARGE_SF].data; + qg_sdam_write(SDAM_ESR_CHARGE_SF, esr); + qg_dbg(chip, QG_DEBUG_ESR, + "SDAM store ESR_CHARGE_SF=%d\n", esr); + } + + if (chip->udata.param[QG_ESR_DISCHARGE_SF].valid) { + esr = chip->udata.param[QG_ESR_DISCHARGE_SF].data; + qg_sdam_write(SDAM_ESR_DISCHARGE_SF, esr); + qg_dbg(chip, QG_DEBUG_ESR, + "SDAM store ESR_DISCHARGE_SF=%d\n", esr); + } +} + +#define MAX_ESR_RETRY_COUNT 10 +#define ESR_SD_PERCENT 10 +static int qg_process_esr_data(struct qpnp_qg *chip) +{ + int i; + int pre_i, post_i, pre_v, post_v, first_pre_i = 0; + int diff_v, diff_i, esr_avg = 0, count = 0; + + for (i = 0; i < qg_esr_count; i++) { + if (!chip->esr_data[i].valid) + continue; + + pre_i = chip->esr_data[i].pre_esr_i; + pre_v = chip->esr_data[i].pre_esr_v; + post_i = chip->esr_data[i].post_esr_i; + post_v = chip->esr_data[i].post_esr_v; + + /* + * Check if any of the pre/post readings have changed + * signs by comparing it with the first valid + * pre_i value. + */ + if (!first_pre_i) + first_pre_i = pre_i; + + if ((first_pre_i < 0 && pre_i > 0) || + (first_pre_i > 0 && post_i < 0) || + (first_pre_i < 0 && post_i > 0)) { + qg_dbg(chip, QG_DEBUG_ESR, + "ESR-sign mismatch %d reject all data\n", i); + esr_avg = count = 0; + break; + } + + /* calculate ESR */ + diff_v = abs(post_v - pre_v); + diff_i = abs(post_i - pre_i); + + if (!diff_v || !diff_i || + (diff_i < chip->dt.esr_qual_i_ua) || + (diff_v < chip->dt.esr_qual_v_uv)) { + qg_dbg(chip, QG_DEBUG_ESR, + "ESR (%d) V/I %duA %duV fails qualification\n", + i, diff_i, diff_v); + chip->esr_data[i].valid = false; + continue; + } + + chip->esr_data[i].esr = + DIV_ROUND_CLOSEST(diff_v * 1000, diff_i); + qg_dbg(chip, QG_DEBUG_ESR, + "ESR qualified: i=%d pre_i=%d pre_v=%d post_i=%d post_v=%d esr_diff_v=%d esr_diff_i=%d esr=%d\n", + i, pre_i, pre_v, post_i, post_v, + diff_v, diff_i, chip->esr_data[i].esr); + + esr_avg += chip->esr_data[i].esr; + count++; + } + + if (!count) { + qg_dbg(chip, QG_DEBUG_ESR, + "No ESR samples qualified, ESR not found\n"); + chip->esr_avg = 0; + return 0; + } + + esr_avg /= count; + qg_dbg(chip, QG_DEBUG_ESR, + "ESR all sample average=%d count=%d apply_SD=%d\n", + esr_avg, count, (esr_avg * ESR_SD_PERCENT) / 100); /* - * Reject the FIFO read event if there are back-to-back requests - * This is done to gaurantee that there is always a minimum FIFO - * data to be processed, ignore this if vbat_low is set. + * Reject ESR samples which do not fall in + * 10% the standard-deviation */ - time_delta = ktime_ms_delta(now, chip->last_user_update_time); + count = 0; + for (i = 0; i < qg_esr_count; i++) { + if (!chip->esr_data[i].valid) + continue; + + if ((abs(chip->esr_data[i].esr - esr_avg) <= + (esr_avg * ESR_SD_PERCENT) / 100)) { + /* valid ESR */ + chip->esr_avg += chip->esr_data[i].esr; + count++; + qg_dbg(chip, QG_DEBUG_ESR, + "Valid ESR after SD (%d) %d mOhm\n", + i, chip->esr_data[i].esr); + } else { + qg_dbg(chip, QG_DEBUG_ESR, + "ESR (%d) %d falls-out of SD(%d)\n", + i, chip->esr_data[i].esr, ESR_SD_PERCENT); + } + } - qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms vbat_low=%d\n", - time_delta, vbat_low); + if (count >= QG_MIN_ESR_COUNT) { + chip->esr_avg /= count; + qg_dbg(chip, QG_DEBUG_ESR, "Average estimated ESR %d mOhm\n", + chip->esr_avg); + } else { + qg_dbg(chip, QG_DEBUG_ESR, + "Not enough ESR samples, ESR not found\n"); + chip->esr_avg = 0; + } - if (time_delta > MIN_FIFO_FULL_TIME_MS || vbat_low || update_smb) { - rc = qg_master_hold(chip, true); - if (rc < 0) { - pr_err("Failed to hold master, rc=%d\n", rc); - goto done; - } + return 0; +} - rc = qg_process_rt_fifo(chip); +static int qg_esr_estimate(struct qpnp_qg *chip) +{ + int rc, i, ibat; + u8 esr_done_count, reg0 = 0, reg1 = 0; + bool is_charging = false; + + if (chip->dt.esr_disable) + return 0; + + /* + * Charge - enable ESR estimation only during fast-charging. + * Discharge - enable ESR estimation only if enabled via DT. + */ + if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING && + chip->charge_type != POWER_SUPPLY_CHARGE_TYPE_FAST) { + qg_dbg(chip, QG_DEBUG_ESR, + "Skip ESR, Not in fast-charge (CC)\n"); + return 0; + } + + if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING && + !chip->dt.esr_discharge_enable) + return 0; + + if (chip->batt_soc != INT_MIN && (chip->batt_soc < + chip->dt.esr_disable_soc)) { + qg_dbg(chip, QG_DEBUG_ESR, + "Skip ESR, batt-soc below %d\n", + chip->dt.esr_disable_soc); + return 0; + } + + qg_dbg(chip, QG_DEBUG_ESR, "FIFO done count=%d ESR mod count=%d\n", + chip->fifo_done_count, qg_esr_mod_count); + + if ((chip->fifo_done_count % qg_esr_mod_count) != 0) + return 0; + + if (qg_esr_count > QG_MAX_ESR_COUNT) + qg_esr_count = QG_MAX_ESR_COUNT; + + if (qg_esr_count < QG_MIN_ESR_COUNT) + qg_esr_count = QG_MIN_ESR_COUNT; + + /* clear all data */ + chip->esr_avg = 0; + memset(&chip->esr_data, 0, sizeof(chip->esr_data)); + + rc = qg_master_hold(chip, true); + if (rc < 0) { + pr_err("Failed to hold master, rc=%d\n", rc); + goto done; + } + + for (i = 0; i < qg_esr_count; i++) { + /* Fire ESR measurement */ + rc = qg_masked_write(chip, + chip->qg_base + QG_ESR_MEAS_TRIG_REG, + HW_ESR_MEAS_START_BIT, HW_ESR_MEAS_START_BIT); if (rc < 0) { - pr_err("Failed to process FIFO real-time, rc=%d\n", rc); - goto done; + pr_err("Failed to start ESR rc=%d\n", rc); + continue; } - if (vbat_low) { - /* change FIFO length */ - rc = qg_update_fifo_length(chip, - chip->dt.s2_vbat_low_fifo_length); + esr_done_count = reg0 = reg1 = 0; + do { + /* delay for ESR processing to complete */ + msleep(50); + + esr_done_count++; + + rc = qg_read(chip, + chip->qg_base + QG_STATUS1_REG, ®0, 1); + if (rc < 0) + continue; + + rc = qg_read(chip, + chip->qg_base + QG_STATUS4_REG, ®1, 1); + if (rc < 0) + continue; + + /* check ESR-done status */ + if (!(reg1 & ESR_MEAS_IN_PROGRESS_BIT) && + (reg0 & ESR_MEAS_DONE_BIT)) { + qg_dbg(chip, QG_DEBUG_ESR, + "ESR measurement done %d count %d\n", + i, esr_done_count); + break; + } + } while (esr_done_count < MAX_ESR_RETRY_COUNT); + + if (esr_done_count == MAX_ESR_RETRY_COUNT) { + pr_err("Failed to get ESR done for %d iteration\n", i); + continue; + } else { + /* found a valid ESR, read pre-post data */ + rc = qg_read_raw_data(chip, QG_PRE_ESR_V_DATA0_REG, + &chip->esr_data[i].pre_esr_v); if (rc < 0) goto done; - qg_dbg(chip, QG_DEBUG_STATUS, - "FIFO length updated to %d vbat_low=%d\n", - chip->dt.s2_vbat_low_fifo_length, - vbat_low); - } + rc = qg_read_raw_data(chip, QG_PRE_ESR_I_DATA0_REG, + &chip->esr_data[i].pre_esr_i); + if (rc < 0) + goto done; - if (update_smb) { - rc = qg_masked_write(chip, chip->qg_base + - QG_MODE_CTL1_REG, PARALLEL_IBAT_SENSE_EN_BIT, - chip->parallel_enabled ? - PARALLEL_IBAT_SENSE_EN_BIT : 0); - if (rc < 0) { - pr_err("Failed to update SMB_EN, rc=%d\n", rc); + rc = qg_read_raw_data(chip, QG_POST_ESR_V_DATA0_REG, + &chip->esr_data[i].post_esr_v); + if (rc < 0) goto done; - } - qg_dbg(chip, QG_DEBUG_STATUS, "Parallel SENSE %d\n", - chip->parallel_enabled); - } - rc = qg_master_hold(chip, false); - if (rc < 0) { - pr_err("Failed to release master, rc=%d\n", rc); - goto done; + rc = qg_read_raw_data(chip, QG_POST_ESR_I_DATA0_REG, + &chip->esr_data[i].post_esr_i); + if (rc < 0) + goto done; + + chip->esr_data[i].pre_esr_v = + V_RAW_TO_UV(chip->esr_data[i].pre_esr_v); + ibat = sign_extend32(chip->esr_data[i].pre_esr_i, 15); + chip->esr_data[i].pre_esr_i = I_RAW_TO_UA(ibat); + chip->esr_data[i].post_esr_v = + V_RAW_TO_UV(chip->esr_data[i].post_esr_v); + ibat = sign_extend32(chip->esr_data[i].post_esr_i, 15); + chip->esr_data[i].post_esr_i = I_RAW_TO_UA(ibat); + + chip->esr_data[i].valid = true; + + if ((int)chip->esr_data[i].pre_esr_i < 0) + is_charging = true; + + qg_dbg(chip, QG_DEBUG_ESR, + "ESR values for %d iteration pre_v=%d pre_i=%d post_v=%d post_i=%d\n", + i, chip->esr_data[i].pre_esr_v, + (int)chip->esr_data[i].pre_esr_i, + chip->esr_data[i].post_esr_v, + (int)chip->esr_data[i].post_esr_i); } - /* FIFOs restarted */ - chip->last_fifo_update_time = ktime_get(); + /* delay before the next ESR measurement */ + msleep(200); + } - /* signal the read thread */ - chip->data_ready = true; - wake_up_interruptible(&chip->qg_wait_q); - chip->last_user_update_time = now; + rc = qg_process_esr_data(chip); + if (rc < 0) + pr_err("Failed to process ESR data rc=%d\n", rc); - /* vote to stay awake until userspace reads data */ - vote(chip->awake_votable, FIFO_RT_DONE_VOTER, true, 0); - } else { - qg_dbg(chip, QG_DEBUG_FIFO, "FIFO processing too early time_delta=%lld\n", - time_delta); + rc = qg_master_hold(chip, false); + if (rc < 0) { + pr_err("Failed to release master, rc=%d\n", rc); + goto done; } + + if (chip->esr_avg) { + chip->kdata.param[QG_ESR].data = chip->esr_avg; + chip->kdata.param[QG_ESR].valid = true; + qg_dbg(chip, QG_DEBUG_ESR, "ESR_SW=%d during %s\n", + chip->esr_avg, is_charging ? "CHARGE" : "DISCHARGE"); + qg_retrieve_esr_params(chip); + } + + return 0; done: qg_master_hold(chip, false); return rc; @@ -669,7 +1029,7 @@ static void process_udata_work(struct work_struct *work) chip->udata.param[QG_RBAT_MOHM].data; chip->sdam_data[SDAM_VALID] = 1; - rc = qg_update_sdam_params(chip); + rc = qg_store_soc_params(chip); if (rc < 0) pr_err("Failed to update SDAM params, rc=%d\n", rc); } @@ -678,6 +1038,12 @@ static void process_udata_work(struct work_struct *work) chip->charge_counter_uah = chip->udata.param[QG_CHARGE_COUNTER].data; + if (chip->udata.param[QG_ESR].valid) + chip->esr_last = chip->udata.param[QG_ESR].data; + + if (!chip->dt.esr_disable) + qg_store_esr_params(chip); + vote(chip->awake_votable, UDATA_READY_VOTER, false, 0); } @@ -717,6 +1083,9 @@ static irqreturn_t qg_fifo_update_done_handler(int irq, void *data) goto done; } + if (++chip->fifo_done_count == U32_MAX) + chip->fifo_done_count = 0; + rc = qg_vbat_thresholds_config(chip); if (rc < 0) pr_err("Failed to apply VBAT EMPTY config rc=%d\n", rc); @@ -727,6 +1096,12 @@ static irqreturn_t qg_fifo_update_done_handler(int irq, void *data) goto done; } + rc = qg_esr_estimate(chip); + if (rc < 0) { + pr_err("Failed to estimate ESR, rc=%d\n", rc); + goto done; + } + rc = get_fifo_done_time(chip, false, &hw_delta_ms); if (rc < 0) hw_delta_ms = 0; @@ -794,7 +1169,7 @@ static irqreturn_t qg_vbat_empty_handler(int irq, void *data) chip->sdam_data[SDAM_OCV_UV] = ocv_uv; chip->sdam_data[SDAM_VALID] = 1; - qg_update_sdam_params(chip); + qg_store_soc_params(chip); if (chip->qg_psy) power_supply_changed(chip->qg_psy); @@ -1265,6 +1640,9 @@ static int qg_psy_get_property(struct power_supply *psy, if (!rc) pval->intval *= 1000; break; + case POWER_SUPPLY_PROP_RESISTANCE_NOW: + pval->intval = chip->esr_last; + break; case POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE: pval->intval = chip->dt.rbat_conn_mohm; break; @@ -1336,6 +1714,7 @@ static enum power_supply_property qg_psy_props[] = { POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_RESISTANCE, POWER_SUPPLY_PROP_RESISTANCE_ID, + POWER_SUPPLY_PROP_RESISTANCE_NOW, POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE, POWER_SUPPLY_PROP_DEBUG_BATTERY, POWER_SUPPLY_PROP_BATTERY_TYPE, @@ -1480,6 +1859,13 @@ static void qg_status_change_work(struct work_struct *work) goto out; } + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_TYPE, &prop); + if (rc < 0) + pr_err("Failed to get charge-type, rc=%d\n", rc); + else + chip->charge_type = prop.intval; + rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, &prop); if (rc < 0) @@ -1996,7 +2382,7 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) if (rc < 0) pr_err("Failed to update MSOC register rc=%d\n", rc); - rc = qg_update_sdam_params(chip); + rc = qg_store_soc_params(chip); if (rc < 0) pr_err("Failed to update sdam params rc=%d\n", rc); @@ -2224,6 +2610,10 @@ static int qg_post_init(struct qpnp_qg *chip) QG_INIT_STATE_IRQ_DISABLE, true, 0); } + /* restore ESR data */ + if (!chip->dt.esr_disable) + qg_retrieve_esr_params(chip); + return 0; } @@ -2373,10 +2763,13 @@ static int qg_alg_init(struct qpnp_qg *chip) #define DEFAULT_CL_MAX_START_SOC 15 #define DEFAULT_CL_MIN_TEMP_DECIDEGC 150 #define DEFAULT_CL_MAX_TEMP_DECIDEGC 500 -#define DEFAULT_CL_MAX_INC_DECIPERC 5 -#define DEFAULT_CL_MAX_DEC_DECIPERC 100 -#define DEFAULT_CL_MIN_LIM_DECIPERC 0 -#define DEFAULT_CL_MAX_LIM_DECIPERC 0 +#define DEFAULT_CL_MAX_INC_DECIPERC 10 +#define DEFAULT_CL_MAX_DEC_DECIPERC 20 +#define DEFAULT_CL_MIN_LIM_DECIPERC 500 +#define DEFAULT_CL_MAX_LIM_DECIPERC 100 +#define DEFAULT_ESR_QUAL_CURRENT_UA 130000 +#define DEFAULT_ESR_QUAL_VBAT_UV 7000 +#define DEFAULT_ESR_DISABLE_SOC 1000 static int qg_parse_dt(struct qpnp_qg *chip) { int rc = 0; @@ -2570,6 +2963,31 @@ static int qg_parse_dt(struct qpnp_qg *chip) else chip->dt.rbat_conn_mohm = temp; + /* esr */ + chip->dt.esr_disable = of_property_read_bool(node, + "qcom,esr-disable"); + + chip->dt.esr_discharge_enable = of_property_read_bool(node, + "qcom,esr-discharge-enable"); + + rc = of_property_read_u32(node, "qcom,esr-qual-current-ua", &temp); + if (rc < 0) + chip->dt.esr_qual_i_ua = DEFAULT_ESR_QUAL_CURRENT_UA; + else + chip->dt.esr_qual_i_ua = temp; + + rc = of_property_read_u32(node, "qcom,esr-qual-vbatt-uv", &temp); + if (rc < 0) + chip->dt.esr_qual_v_uv = DEFAULT_ESR_QUAL_VBAT_UV; + else + chip->dt.esr_qual_v_uv = temp; + + rc = of_property_read_u32(node, "qcom,esr-disable-soc", &temp); + if (rc < 0) + chip->dt.esr_disable_soc = DEFAULT_ESR_DISABLE_SOC; + else + chip->dt.esr_disable_soc = temp * 100; + /* Capacity learning params*/ if (!chip->dt.cl_disable) { chip->dt.cl_feedback_on = of_property_read_bool(node, diff --git a/include/uapi/linux/qg.h b/include/uapi/linux/qg.h index 2c7b49af873d..d338db9d8786 100644 --- a/include/uapi/linux/qg.h +++ b/include/uapi/linux/qg.h @@ -14,10 +14,10 @@ enum qg { QG_FIFO_TIME_DELTA, QG_BATT_SOC, QG_CC_SOC, - QG_RESERVED_3, - QG_RESERVED_4, - QG_RESERVED_5, - QG_RESERVED_6, + QG_ESR_CHARGE_DELTA, + QG_ESR_DISCHARGE_DELTA, + QG_ESR_CHARGE_SF, + QG_ESR_DISCHARGE_SF, QG_RESERVED_7, QG_RESERVED_8, QG_RESERVED_9, @@ -27,6 +27,10 @@ enum qg { #define QG_BATT_SOC QG_BATT_SOC #define QG_CC_SOC QG_CC_SOC +#define QG_ESR_CHARGE_DELTA QG_ESR_CHARGE_DELTA +#define QG_ESR_DISCHARGE_DELTA QG_ESR_DISCHARGE_DELTA +#define QG_ESR_CHARGE_SF QG_ESR_CHARGE_SF +#define QG_ESR_DISCHARGE_SF QG_ESR_DISCHARGE_SF struct fifo_data { unsigned int v; -- GitLab From 754419b6eae2a673d5b38e157f04af4608549b93 Mon Sep 17 00:00:00 2001 From: Pratham Pratap Date: Mon, 4 Jun 2018 10:18:25 +0530 Subject: [PATCH 710/855] usb: gadget: f_cdev: Send zero length packets in modem data calls The USB protocol requires zero length packets to be sent when the data transmission ends on a USB packet size boundary. This fix enables sending zero length packets when required. Change-Id: I0269ec7ff25c82000f2a5bc4adb449bc0231c66c Signed-off-by: Pratham Pratap --- drivers/usb/gadget/function/f_cdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 4d4f0396f89d..a7166e24bbad 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -1256,6 +1256,7 @@ ssize_t f_cdev_write(struct file *file, ret = -EFAULT; } else { req->length = xfer_size; + req->zero = 1; ret = usb_ep_queue(in, req, GFP_KERNEL); if (ret) { pr_err("EP QUEUE failed:%d\n", ret); -- GitLab From 6df7a42a60b5e3698260f7c1fff7c8466e58e275 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Tue, 29 May 2018 14:56:28 +0530 Subject: [PATCH 711/855] drivers: thermal: Fix zone passive counter update not accounted correctly Thermal framework resets all thermal zone passive counter during resume path. But governors are not checking this while handling mitigation. If mitigation is already applied prior to suspend and it stays same post suspend, governor assumes it is already mitigated and passive counter is already updated. But in resume path, it resets passive counter prior to each thermal zone update. For sensor which doesn't support clear interrupt and relies on thermal framework to clear, can lead to a case where thermal zone is always in mitigated state even though thermal zone temperature is in below clear trip. Update stepwise and low limits governor logic for passive counter update for resume scenario. Change-Id: I055deb5c2a79e032a41bcbbe097221d0b892946a Signed-off-by: Manaf Meethalavalappu Pallikunhi --- drivers/thermal/gov_low_limits.c | 25 ++++++++++++++++++------- drivers/thermal/step_wise.c | 30 ++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/drivers/thermal/gov_low_limits.c b/drivers/thermal/gov_low_limits.c index 278869c70a46..d02ea2614895 100644 --- a/drivers/thermal/gov_low_limits.c +++ b/drivers/thermal/gov_low_limits.c @@ -62,19 +62,30 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n", old_target, (int)instance->target); - if (old_target == instance->target) + if (instance->initialized && old_target == instance->target) continue; - if (old_target == THERMAL_NO_TARGET && + if (!instance->initialized) { + if (instance->target != THERMAL_NO_TARGET) { + trace_thermal_zone_trip(tz, trip, trip_type, + true); + tz->passive += 1; + } + } else { + if (old_target == THERMAL_NO_TARGET && instance->target != THERMAL_NO_TARGET) { - trace_thermal_zone_trip(tz, trip, trip_type, true); - tz->passive += 1; - } else if (old_target != THERMAL_NO_TARGET && + trace_thermal_zone_trip(tz, trip, trip_type, + true); + tz->passive += 1; + } else if (old_target != THERMAL_NO_TARGET && instance->target == THERMAL_NO_TARGET) { - trace_thermal_zone_trip(tz, trip, trip_type, false); - tz->passive -= 1; + trace_thermal_zone_trip(tz, trip, trip_type, + false); + tz->passive -= 1; + } } + instance->initialized = true; instance->cdev->updated = false; /* cdev needs update */ } diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c index 4bbb47aab15d..4d75f6b0b442 100644 --- a/drivers/thermal/step_wise.c +++ b/drivers/thermal/step_wise.c @@ -190,16 +190,26 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) if (instance->initialized && old_target == instance->target) continue; - /* Activate a passive thermal instance */ - if (old_target == THERMAL_NO_TARGET && - instance->target != THERMAL_NO_TARGET) { - update_passive_instance(tz, trip_type, 1); - trace_thermal_zone_trip(tz, trip, trip_type, true); - /* Deactivate a passive thermal instance */ - } else if (old_target != THERMAL_NO_TARGET && - instance->target == THERMAL_NO_TARGET) { - update_passive_instance(tz, trip_type, -1); - trace_thermal_zone_trip(tz, trip, trip_type, false); + if (!instance->initialized) { + if (instance->target != THERMAL_NO_TARGET) { + trace_thermal_zone_trip(tz, trip, trip_type, + true); + update_passive_instance(tz, trip_type, 1); + } + } else { + /* Activate a passive thermal instance */ + if (old_target == THERMAL_NO_TARGET && + instance->target != THERMAL_NO_TARGET) { + trace_thermal_zone_trip(tz, trip, trip_type, + true); + update_passive_instance(tz, trip_type, 1); + /* Deactivate a passive thermal instance */ + } else if (old_target != THERMAL_NO_TARGET && + instance->target == THERMAL_NO_TARGET) { + trace_thermal_zone_trip(tz, trip, trip_type, + false); + update_passive_instance(tz, trip_type, -1); + } } instance->initialized = true; -- GitLab From b7498c25c1aa484fb1ac2780e08ca6ef9ac3f9c9 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Fri, 25 May 2018 05:44:29 +0530 Subject: [PATCH 712/855] drivers: cpu_cooling: Remove cooling list lock during post suspend handling There is a possible deadlock scenario in cpu cooling device when thermal core isolation condition, core hotplug and resume contexts are running concurrently. Core hotplug context takes hotplug framework lock and waiting for cpu cooling list lock and the same time the post suspend context is holding cpu cooling list lock and waiting for hotplug framework lock to isolate core due to thermal condition. Since cpu cooling device list addition and deletion are not a frequent call and addition is done once during boot. So it is not expected to mutate cpu cooling device list on post boot. Remove cooling list lock safely from post suspend path to avoid this dead lock scenario. Change-Id: Iec02a3050082ad28826989062e9f3717d50cd3fd Signed-off-by: Manaf Meethalavalappu Pallikunhi --- drivers/thermal/cpu_cooling.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 2c4a63a880d4..02f93f4a1c4b 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -224,7 +224,7 @@ EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); static int cpufreq_cooling_pm_notify(struct notifier_block *nb, unsigned long mode, void *_unused) { - struct cpufreq_cooling_device *cpufreq_dev; + struct cpufreq_cooling_device *cpufreq_dev, *next; unsigned int cpu; switch (mode) { @@ -236,8 +236,8 @@ static int cpufreq_cooling_pm_notify(struct notifier_block *nb, case PM_POST_HIBERNATION: case PM_POST_RESTORE: case PM_POST_SUSPEND: - mutex_lock(&cooling_list_lock); - list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { + list_for_each_entry_safe(cpufreq_dev, next, &cpufreq_dev_list, + node) { mutex_lock(&core_isolate_lock); if (cpufreq_dev->cpufreq_state == cpufreq_dev->max_level) { @@ -259,7 +259,6 @@ static int cpufreq_cooling_pm_notify(struct notifier_block *nb, } mutex_unlock(&core_isolate_lock); } - mutex_unlock(&cooling_list_lock); atomic_set(&in_suspend, 0); break; -- GitLab From d42a40efccb31f3d9f0f4cd2b6d6a7b3ba268f5b Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Fri, 1 Jun 2018 19:06:53 +0530 Subject: [PATCH 713/855] kernel: power: qos: remove check for core isolation while cluster LPMs Since all cores in a cluster are in isolation, PMQoS latency constraint set by clock driver to switch PLL is ignored. So, Cluster enter to L2PC and SPM is trying to disable the PLL and at same time clock driver trying to switch the PLL from other cluster which leads to the synchronization issues. Fix is although all cores are in isolation, honor PMQoS request for cluster LPMs. Change-Id: I4296e16ef4e9046d1fbe3b7378e9f61a2f11c74d Signed-off-by: Raghavendra Kakarla --- kernel/power/qos.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 0469d8033bd6..d6a0b0ffffb1 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -478,8 +478,6 @@ int pm_qos_request_for_cpumask(int pm_qos_class, struct cpumask *mask) val = c->default_value; for_each_cpu(cpu, mask) { - if (cpu_isolated(cpu)) - continue; switch (c->type) { case PM_QOS_MIN: -- GitLab From d70fa152072e0923130d10688aa4536bdf2ada75 Mon Sep 17 00:00:00 2001 From: Dilip Kota Date: Fri, 18 May 2018 14:26:23 +0530 Subject: [PATCH 714/855] spi: spi-geni-qcom: Add support for SE DMA mode Add support for SE DMA data transfer mode. Each SE has its own DMA core that the driver can setup data transfers. This change also adds support to run in FIFO mode if transfer length is less than FIFO size else in SE-DMA mode. This is applicable for non-shared SEs only, meaning SE is assigned only to HLOS use. Change-Id: I0dfd9e8a81a13f3de6fd8eb73e73d25166e4a282 Signed-off-by: Dilip Kota --- drivers/spi/spi-geni-qcom.c | 182 ++++++++++++++++++++++++++---------- 1 file changed, 133 insertions(+), 49 deletions(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index dfa387c24fed..5998c206ccb8 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -311,7 +311,7 @@ static int select_xfer_mode(struct spi_master *spi, struct spi_message *spi_msg) { struct spi_geni_master *mas = spi_master_get_devdata(spi); - int mode = FIFO_MODE; + int mode = SE_DMA; int fifo_disable = (geni_read_reg(mas->base, GENI_IF_FIFO_DISABLE_RO) & FIFO_IF_DISABLE); bool dma_chan_valid = @@ -325,10 +325,10 @@ static int select_xfer_mode(struct spi_master *spi, */ if (fifo_disable && !dma_chan_valid) mode = -EINVAL; + else if (!fifo_disable) + mode = SE_DMA; else if (dma_chan_valid) mode = GSI_DMA; - else - mode = FIFO_MODE; return mode; } @@ -715,25 +715,20 @@ static int spi_geni_prepare_message(struct spi_master *spi, mas->cur_xfer_mode = select_xfer_mode(spi, spi_msg); - if (mas->cur_xfer_mode == FIFO_MODE) { - geni_se_select_mode(mas->base, FIFO_MODE); - reinit_completion(&mas->xfer_done); - ret = setup_fifo_params(spi_msg->spi, spi); + if (mas->cur_xfer_mode < 0) { + dev_err(mas->dev, "%s: Couldn't select mode %d", __func__, + mas->cur_xfer_mode); + ret = -EINVAL; } else if (mas->cur_xfer_mode == GSI_DMA) { - mas->num_tx_eot = 0; - mas->num_rx_eot = 0; - mas->num_xfers = 0; - reinit_completion(&mas->tx_cb); - reinit_completion(&mas->rx_cb); memset(mas->gsi, 0, (sizeof(struct spi_geni_gsi) * NUM_SPI_XFER)); geni_se_select_mode(mas->base, GSI_DMA); ret = spi_geni_map_buf(mas, spi_msg); } else { - dev_err(mas->dev, "%s: Couldn't select mode %d", __func__, - mas->cur_xfer_mode); - ret = -EINVAL; + geni_se_select_mode(mas->base, mas->cur_xfer_mode); + ret = setup_fifo_params(spi_msg->spi, spi); } + return ret; } @@ -965,26 +960,64 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, geni_write_reg(trans_len, mas->base, SE_SPI_RX_TRANS_LEN); mas->rx_rem_bytes = xfer->len; } + + if (trans_len > (mas->tx_fifo_depth * mas->tx_fifo_width)) { + if (mas->cur_xfer_mode != SE_DMA) { + mas->cur_xfer_mode = SE_DMA; + geni_se_select_mode(mas->base, mas->cur_xfer_mode); + } + } else { + if (mas->cur_xfer_mode != FIFO_MODE) { + mas->cur_xfer_mode = FIFO_MODE; + geni_se_select_mode(mas->base, mas->cur_xfer_mode); + } + } + geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG); geni_setup_m_cmd(mas->base, m_cmd, m_param); GENI_SE_DBG(mas->ipc, false, mas->dev, - "%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x cs %d\n", + "%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x cs%d mode%d\n", __func__, trans_len, xfer->len, spi_tx_cfg, m_cmd, - xfer->cs_change); - if (m_cmd & SPI_TX_ONLY) - geni_write_reg(mas->tx_wm, mas->base, SE_GENI_TX_WATERMARK_REG); + xfer->cs_change, mas->cur_xfer_mode); + if ((m_cmd & SPI_RX_ONLY) && (mas->cur_xfer_mode == SE_DMA)) { + int ret = 0; + + ret = geni_se_rx_dma_prep(mas->wrapper_dev, mas->base, + xfer->rx_buf, xfer->len, &xfer->rx_dma); + if (ret) + GENI_SE_ERR(mas->ipc, true, mas->dev, + "Failed to setup Rx dma %d\n", ret); + } + if (m_cmd & SPI_TX_ONLY) { + if (mas->cur_xfer_mode == FIFO_MODE) { + geni_write_reg(mas->tx_wm, mas->base, + SE_GENI_TX_WATERMARK_REG); + } else if (mas->cur_xfer_mode == SE_DMA) { + int ret = 0; + + ret = geni_se_tx_dma_prep(mas->wrapper_dev, mas->base, + (void *)xfer->tx_buf, xfer->len, + &xfer->tx_dma); + if (ret) + GENI_SE_ERR(mas->ipc, true, mas->dev, + "Failed to setup tx dma %d\n", ret); + } + } + /* Ensure all writes are done before the WM interrupt */ mb(); } -static void handle_fifo_timeout(struct spi_geni_master *mas) +static void handle_fifo_timeout(struct spi_geni_master *mas, + struct spi_transfer *xfer) { unsigned long timeout; geni_se_dump_dbg_regs(&mas->spi_rsc, mas->base, mas->ipc); reinit_completion(&mas->xfer_done); geni_cancel_m_cmd(mas->base); - geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG); + if (mas->cur_xfer_mode == FIFO_MODE) + geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG); /* Ensure cmd cancel is written */ mb(); timeout = wait_for_completion_timeout(&mas->xfer_done, HZ); @@ -999,6 +1032,15 @@ static void handle_fifo_timeout(struct spi_geni_master *mas) dev_err(mas->dev, "Failed to cancel/abort m_cmd\n"); } + if (mas->cur_xfer_mode == SE_DMA) { + if (xfer->tx_buf) + geni_se_tx_dma_unprep(mas->wrapper_dev, + xfer->tx_dma, xfer->len); + if (xfer->rx_buf) + geni_se_rx_dma_unprep(mas->wrapper_dev, + xfer->rx_dma, xfer->len); + } + } static int spi_geni_transfer_one(struct spi_master *spi, @@ -1014,7 +1056,8 @@ static int spi_geni_transfer_one(struct spi_master *spi, return -EINVAL; } - if (mas->cur_xfer_mode == FIFO_MODE) { + if (mas->cur_xfer_mode != GSI_DMA) { + reinit_completion(&mas->xfer_done); setup_fifo_xfer(xfer, mas, slv->mode, spi); timeout = wait_for_completion_timeout(&mas->xfer_done, msecs_to_jiffies(SPI_XFER_TIMEOUT_MS)); @@ -1028,7 +1071,22 @@ static int spi_geni_transfer_one(struct spi_master *spi, ret = -ETIMEDOUT; goto err_fifo_geni_transfer_one; } + + if (mas->cur_xfer_mode == SE_DMA) { + if (xfer->tx_buf) + geni_se_tx_dma_unprep(mas->wrapper_dev, + xfer->tx_dma, xfer->len); + if (xfer->rx_buf) + geni_se_rx_dma_unprep(mas->wrapper_dev, + xfer->rx_dma, xfer->len); + } } else { + mas->num_tx_eot = 0; + mas->num_rx_eot = 0; + mas->num_xfers = 0; + reinit_completion(&mas->tx_cb); + reinit_completion(&mas->rx_cb); + setup_gsi_xfer(xfer, mas, slv, spi); if ((mas->num_xfers >= NUM_SPI_XFER) || (list_is_last(&xfer->transfer_list, @@ -1072,7 +1130,7 @@ static int spi_geni_transfer_one(struct spi_master *spi, dmaengine_terminate_all(mas->tx); return ret; err_fifo_geni_transfer_one: - handle_fifo_timeout(mas); + handle_fifo_timeout(mas, xfer); return ret; } @@ -1188,33 +1246,59 @@ static irqreturn_t geni_spi_irq(int irq, void *dev) goto exit_geni_spi_irq; } m_irq = geni_read_reg(mas->base, SE_GENI_M_IRQ_STATUS); - if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN)) - geni_spi_handle_rx(mas); - - if ((m_irq & M_TX_FIFO_WATERMARK_EN)) - geni_spi_handle_tx(mas); - - if ((m_irq & M_CMD_DONE_EN) || (m_irq & M_CMD_CANCEL_EN) || - (m_irq & M_CMD_ABORT_EN)) { - complete(&mas->xfer_done); - /* - * If this happens, then a CMD_DONE came before all the buffer - * bytes were sent out. This is unusual, log this condition and - * disable the WM interrupt to prevent the system from stalling - * due an interrupt storm. - * If this happens when all Rx bytes haven't been received, log - * the condition. - */ - if (mas->tx_rem_bytes) { - geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG); - GENI_SE_DBG(mas->ipc, false, mas->dev, - "%s:Premature Done.tx_rem%d bpw%d\n", - __func__, mas->tx_rem_bytes, mas->cur_word_len); + if (mas->cur_xfer_mode == FIFO_MODE) { + if ((m_irq & M_RX_FIFO_WATERMARK_EN) || + (m_irq & M_RX_FIFO_LAST_EN)) + geni_spi_handle_rx(mas); + + if ((m_irq & M_TX_FIFO_WATERMARK_EN)) + geni_spi_handle_tx(mas); + + if ((m_irq & M_CMD_DONE_EN) || (m_irq & M_CMD_CANCEL_EN) || + (m_irq & M_CMD_ABORT_EN)) { + complete(&mas->xfer_done); + /* + * If this happens, then a CMD_DONE came before all the + * buffer bytes were sent out. This is unusual, log this + * condition and disable the WM interrupt to prevent the + * system from stalling due an interrupt storm. + * If this happens when all Rx bytes haven't been + * received, log the condition. + */ + if (mas->tx_rem_bytes) { + geni_write_reg(0, mas->base, + SE_GENI_TX_WATERMARK_REG); + GENI_SE_DBG(mas->ipc, false, mas->dev, + "%s:Premature Done.tx_rem%d bpw%d\n", + __func__, mas->tx_rem_bytes, + mas->cur_word_len); + } + if (mas->rx_rem_bytes) + GENI_SE_DBG(mas->ipc, false, mas->dev, + "%s:Premature Done.rx_rem%d bpw%d\n", + __func__, mas->rx_rem_bytes, + mas->cur_word_len); } - if (mas->rx_rem_bytes) - GENI_SE_DBG(mas->ipc, false, mas->dev, - "%s:Premature Done.rx_rem%d bpw%d\n", - __func__, mas->rx_rem_bytes, mas->cur_word_len); + } else if (mas->cur_xfer_mode == SE_DMA) { + u32 dma_tx_status = geni_read_reg(mas->base, + SE_DMA_TX_IRQ_STAT); + u32 dma_rx_status = geni_read_reg(mas->base, + SE_DMA_RX_IRQ_STAT); + + if (dma_tx_status) + geni_write_reg(dma_tx_status, mas->base, + SE_DMA_TX_IRQ_CLR); + if (dma_rx_status) + geni_write_reg(dma_rx_status, mas->base, + SE_DMA_RX_IRQ_CLR); + if (dma_tx_status & TX_DMA_DONE) + mas->tx_rem_bytes = 0; + if (dma_rx_status & RX_DMA_DONE) + mas->rx_rem_bytes = 0; + if (!mas->tx_rem_bytes && !mas->rx_rem_bytes) + complete(&mas->xfer_done); + if ((m_irq & M_CMD_CANCEL_EN) || (m_irq & M_CMD_ABORT_EN)) + complete(&mas->xfer_done); } exit_geni_spi_irq: geni_write_reg(m_irq, mas->base, SE_GENI_M_IRQ_CLEAR); -- GitLab From 4f8b483c9d20cbf7fa0fe545391715d052146692 Mon Sep 17 00:00:00 2001 From: Amir Levy Date: Tue, 5 Jun 2018 15:48:03 +0300 Subject: [PATCH 715/855] msm: ipa4: add IOCTL for bridge to vlan mapping IPACM needs info about bridge association with VLANs. Add an IOCTL to send this info to IPACM. Change-Id: Ifeaec348339cd9dd7cf6b507346b61f570861bfc Signed-off-by: Amir Levy --- drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c | 2 + drivers/platform/msm/ipa/ipa_v3/ipa.c | 91 +++++++++++++------ drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c | 2 + include/uapi/linux/msm_ipa.h | 33 ++++++- 4 files changed, 101 insertions(+), 27 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c index 953469aef7a9..c2f7aae63a12 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c @@ -89,6 +89,8 @@ const char *ipa_event_name[] = { __stringify(DEL_L2TP_VLAN_MAPPING), __stringify(IPA_PER_CLIENT_STATS_CONNECT_EVENT), __stringify(IPA_PER_CLIENT_STATS_DISCONNECT_EVENT), + __stringify(ADD_BRIDGE_VLAN_MAPPING), + __stringify(DEL_BRIDGE_VLAN_MAPPING), }; const char *ipa_hdr_l2_type_name[] = { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index d64f89b375be..82c8709faf27 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -499,10 +499,15 @@ static void ipa3_vlan_l2tp_msg_free_cb(void *buff, u32 len, u32 type) return; } - if (type != ADD_VLAN_IFACE && - type != DEL_VLAN_IFACE && - type != ADD_L2TP_VLAN_MAPPING && - type != DEL_L2TP_VLAN_MAPPING) { + switch (type) { + case ADD_VLAN_IFACE: + case DEL_VLAN_IFACE: + case ADD_L2TP_VLAN_MAPPING: + case DEL_L2TP_VLAN_MAPPING: + case ADD_BRIDGE_VLAN_MAPPING: + case DEL_BRIDGE_VLAN_MAPPING: + break; + default: IPAERR("Wrong type given. buff %pK type %d\n", buff, type); return; } @@ -515,10 +520,17 @@ static int ipa3_send_vlan_l2tp_msg(unsigned long usr_param, uint8_t msg_type) int retval; struct ipa_ioc_vlan_iface_info *vlan_info; struct ipa_ioc_l2tp_vlan_mapping_info *mapping_info; + struct ipa_ioc_bridge_vlan_mapping_info *bridge_vlan_info; struct ipa_msg_meta msg_meta; + void *buff; + + IPADBG("type %d\n", msg_type); + + memset(&msg_meta, 0, sizeof(msg_meta)); + msg_meta.msg_type = msg_type; - if (msg_type == ADD_VLAN_IFACE || - msg_type == DEL_VLAN_IFACE) { + if ((msg_type == ADD_VLAN_IFACE) || + (msg_type == DEL_VLAN_IFACE)) { vlan_info = kzalloc(sizeof(struct ipa_ioc_vlan_iface_info), GFP_KERNEL); if (!vlan_info) { @@ -532,18 +544,10 @@ static int ipa3_send_vlan_l2tp_msg(unsigned long usr_param, uint8_t msg_type) return -EFAULT; } - memset(&msg_meta, 0, sizeof(msg_meta)); - msg_meta.msg_type = msg_type; msg_meta.msg_len = sizeof(struct ipa_ioc_vlan_iface_info); - retval = ipa3_send_msg(&msg_meta, vlan_info, - ipa3_vlan_l2tp_msg_free_cb); - if (retval) { - IPAERR("ipa3_send_msg failed: %d\n", retval); - kfree(vlan_info); - return retval; - } - } else if (msg_type == ADD_L2TP_VLAN_MAPPING || - msg_type == DEL_L2TP_VLAN_MAPPING) { + buff = vlan_info; + } else if ((msg_type == ADD_L2TP_VLAN_MAPPING) || + (msg_type == DEL_L2TP_VLAN_MAPPING)) { mapping_info = kzalloc(sizeof(struct ipa_ioc_l2tp_vlan_mapping_info), GFP_KERNEL); if (!mapping_info) { @@ -558,22 +562,46 @@ static int ipa3_send_vlan_l2tp_msg(unsigned long usr_param, uint8_t msg_type) return -EFAULT; } - memset(&msg_meta, 0, sizeof(msg_meta)); - msg_meta.msg_type = msg_type; msg_meta.msg_len = sizeof(struct ipa_ioc_l2tp_vlan_mapping_info); - retval = ipa3_send_msg(&msg_meta, mapping_info, - ipa3_vlan_l2tp_msg_free_cb); - if (retval) { - IPAERR("ipa3_send_msg failed: %d\n", retval); - kfree(mapping_info); - return retval; + buff = mapping_info; + } else if ((msg_type == ADD_BRIDGE_VLAN_MAPPING) || + (msg_type == DEL_BRIDGE_VLAN_MAPPING)) { + bridge_vlan_info = kzalloc( + sizeof(struct ipa_ioc_bridge_vlan_mapping_info), + GFP_KERNEL); + if (!bridge_vlan_info) { + IPAERR("no memory\n"); + return -ENOMEM; + } + + if (copy_from_user((u8 *)bridge_vlan_info, + (void __user *)usr_param, + sizeof(struct ipa_ioc_bridge_vlan_mapping_info))) { + kfree(bridge_vlan_info); + IPAERR("copy from user failed\n"); + return -EFAULT; } + + msg_meta.msg_len = sizeof(struct + ipa_ioc_bridge_vlan_mapping_info); + buff = bridge_vlan_info; } else { IPAERR("Unexpected event\n"); return -EFAULT; } + retval = ipa3_send_msg(&msg_meta, buff, + ipa3_vlan_l2tp_msg_free_cb); + if (retval) { + IPAERR("ipa3_send_msg failed: %d, msg_type %d\n", + retval, + msg_type); + kfree(buff); + return retval; + } + IPADBG("exit\n"); + return 0; } @@ -1726,7 +1754,18 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; } break; - + case IPA_IOC_ADD_BRIDGE_VLAN_MAPPING: + if (ipa3_send_vlan_l2tp_msg(arg, ADD_BRIDGE_VLAN_MAPPING)) { + retval = -EFAULT; + break; + } + break; + case IPA_IOC_DEL_BRIDGE_VLAN_MAPPING: + if (ipa3_send_vlan_l2tp_msg(arg, DEL_BRIDGE_VLAN_MAPPING)) { + retval = -EFAULT; + break; + } + break; case IPA_IOC_ADD_L2TP_VLAN_MAPPING: if (ipa3_send_vlan_l2tp_msg(arg, ADD_L2TP_VLAN_MAPPING)) { retval = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index 4751c75db38d..e10383c88a51 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -73,6 +73,8 @@ const char *ipa3_event_name[] = { __stringify(DEL_L2TP_VLAN_MAPPING), __stringify(IPA_PER_CLIENT_STATS_CONNECT_EVENT), __stringify(IPA_PER_CLIENT_STATS_DISCONNECT_EVENT), + __stringify(ADD_BRIDGE_VLAN_MAPPING), + __stringify(DEL_BRIDGE_VLAN_MAPPING), }; const char *ipa3_hdr_l2_type_name[] = { diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 1c39dafa68d4..be4cb02f7e34 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -98,6 +98,8 @@ #define IPA_IOCTL_CLEANUP 56 #define IPA_IOCTL_QUERY_WLAN_CLIENT 57 #define IPA_IOCTL_GET_VLAN_MODE 58 +#define IPA_IOCTL_ADD_BRIDGE_VLAN_MAPPING 59 +#define IPA_IOCTL_DEL_BRIDGE_VLAN_MAPPING 60 /** * max size of the header to be inserted @@ -512,7 +514,13 @@ enum ipa_per_client_stats_event { IPA_PER_CLIENT_STATS_EVENT_MAX }; -#define IPA_EVENT_MAX_NUM (IPA_PER_CLIENT_STATS_EVENT_MAX) +enum ipa_vlan_bridge_event { + ADD_BRIDGE_VLAN_MAPPING = IPA_PER_CLIENT_STATS_EVENT_MAX, + DEL_BRIDGE_VLAN_MAPPING, + BRIDGE_VLAN_MAPPING_MAX +}; + +#define IPA_EVENT_MAX_NUM (BRIDGE_VLAN_MAPPING_MAX) #define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM) /** @@ -1871,6 +1879,20 @@ struct ipa_ioc_get_vlan_mode { uint32_t is_vlan_mode; }; +/** + * struct ipa_ioc_bridge_vlan_mapping_info - vlan to bridge mapping info + * @bridge_name: bridge interface name + * @vlan_id: vlan ID bridge is mapped to + * @bridge_ipv4: bridge interface ipv4 address + * @subnet_mask: bridge interface subnet mask + */ +struct ipa_ioc_bridge_vlan_mapping_info { + char bridge_name[IPA_RESOURCE_NAME_MAX]; + uint16_t vlan_id; + uint32_t bridge_ipv4; + uint32_t subnet_mask; +}; + /** * actual IOCTLs supported by IPA driver */ @@ -2056,6 +2078,15 @@ struct ipa_ioc_get_vlan_mode { #define IPA_IOC_GET_VLAN_MODE _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_GET_VLAN_MODE, \ struct ipa_ioc_get_vlan_mode *) + +#define IPA_IOC_ADD_BRIDGE_VLAN_MAPPING _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_ADD_BRIDGE_VLAN_MAPPING, \ + struct ipa_ioc_bridge_vlan_mapping_info) + +#define IPA_IOC_DEL_BRIDGE_VLAN_MAPPING _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_DEL_BRIDGE_VLAN_MAPPING, \ + struct ipa_ioc_bridge_vlan_mapping_info) + /* * unique magic number of the Tethering bridge ioctls */ -- GitLab From 90cb5ecd7cfd28c3d98b11ead4dbb0426742bfca Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Fri, 25 May 2018 12:58:10 +0530 Subject: [PATCH 716/855] clk: msm: Add delay of 50uSec before polling lock_detect status Some PLL HWs require an additional delay for the PLL lock detect to stabilize after being brought out of reset and SW to poll for lock detect status. Add delay of 50uSec before polling lock_det bit by introducing new pll ops. Also if PLL fails to lock, record additional PLL debug information in the kernel log before panic(). Change-Id: I1b04dccc8d3c3e45d4aa7a3c1c60311331e490fa Signed-off-by: Odelu Kukatla --- drivers/clk/msm/clock-pll.c | 101 ++++++++++++++++++++++++++++++----- include/soc/qcom/clock-pll.h | 4 +- 2 files changed, 92 insertions(+), 13 deletions(-) diff --git a/drivers/clk/msm/clock-pll.c b/drivers/clk/msm/clock-pll.c index 26c04e561444..381c8db9f7d5 100644 --- a/drivers/clk/msm/clock-pll.c +++ b/drivers/clk/msm/clock-pll.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -217,13 +217,46 @@ static void __pll_config_reg(void __iomem *pll_config, struct pll_freq_tbl *f, writel_relaxed(regval, pll_config); } +static void pll_wait_for_lock(struct pll_clk *pll) +{ + int count; + u32 mode = readl_relaxed(PLL_MODE_REG(pll)); + u32 lockmask = pll->masks.lock_mask ?: PLL_LOCKED_BIT; + u32 status_reg, user_reg, l_reg, m_reg, n_reg, config_reg; + + /* Wait for pll to lock. */ + for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) { + if (readl_relaxed(PLL_STATUS_REG(pll)) & lockmask) + break; + udelay(1); + } + + if (!(readl_relaxed(PLL_STATUS_REG(pll)) & lockmask)) { + mode = readl_relaxed(PLL_MODE_REG(pll)); + status_reg = readl_relaxed(PLL_STATUS_REG(pll)); + user_reg = readl_relaxed(PLL_CONFIG_REG(pll)); + config_reg = readl_relaxed(PLL_CFG_CTL_REG(pll)); + l_reg = readl_relaxed(PLL_L_REG(pll)); + m_reg = readl_relaxed(PLL_M_REG(pll)); + n_reg = readl_relaxed(PLL_N_REG(pll)); + pr_err("count = %d\n", (int)count); + pr_err("mode register is 0x%x\n", mode); + pr_err("status register is 0x%x\n", status_reg); + pr_err("user control register is 0x%x\n", user_reg); + pr_err("config control register is 0x%x\n", config_reg); + pr_err("L value register is 0x%x\n", l_reg); + pr_err("M value register is 0x%x\n", m_reg); + pr_err("N value control register is 0x%x\n", n_reg); + panic("PLL %s didn't lock after enabling it!\n", + pll->c.dbg_name); + } +} + static int sr2_pll_clk_enable(struct clk *c) { unsigned long flags; struct pll_clk *pll = to_pll_clk(c); - int ret = 0, count; u32 mode = readl_relaxed(PLL_MODE_REG(pll)); - u32 lockmask = pll->masks.lock_mask ?: PLL_LOCKED_BIT; spin_lock_irqsave(&pll_reg_lock, flags); @@ -245,15 +278,50 @@ static int sr2_pll_clk_enable(struct clk *c) mode |= PLL_RESET_N; writel_relaxed(mode, PLL_MODE_REG(pll)); - /* Wait for pll to lock. */ - for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) { - if (readl_relaxed(PLL_STATUS_REG(pll)) & lockmask) - break; - udelay(1); - } + pll_wait_for_lock(pll); - if (!(readl_relaxed(PLL_STATUS_REG(pll)) & lockmask)) - pr_err("PLL %s didn't lock after enabling it!\n", c->dbg_name); + /* Enable PLL output. */ + mode |= PLL_OUTCTRL; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* Ensure that the write above goes through before returning. */ + mb(); + + spin_unlock_irqrestore(&pll_reg_lock, flags); + return 0; +} + +static int acpu_pll_clk_enable(struct clk *c) +{ + unsigned long flags; + struct pll_clk *pll = to_pll_clk(c); + u32 mode = readl_relaxed(PLL_MODE_REG(pll)); + + spin_lock_irqsave(&pll_reg_lock, flags); + + spm_event(pll->spm_ctrl.spm_base, pll->spm_ctrl.offset, + pll->spm_ctrl.event_bit, false); + + /* Disable PLL bypass mode. */ + mode |= PLL_BYPASSNL; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* + * H/W requires a 5us delay between disabling the bypass and + * de-asserting the reset. Delay 10us just to be safe. + */ + mb(); + udelay(10); + + /* De-assert active-low PLL reset. */ + mode |= PLL_RESET_N; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* PLL H/W requires a 50uSec delay before polling lock_detect. */ + mb(); + udelay(50); + + pll_wait_for_lock(pll); /* Enable PLL output. */ mode |= PLL_OUTCTRL; @@ -263,7 +331,7 @@ static int sr2_pll_clk_enable(struct clk *c) mb(); spin_unlock_irqrestore(&pll_reg_lock, flags); - return ret; + return 0; } void __variable_rate_pll_init(struct clk *c) @@ -886,6 +954,15 @@ const struct clk_ops clk_ops_sr2_pll = { .list_registers = local_pll_clk_list_registers, }; +const struct clk_ops clk_ops_acpu_pll = { + .enable = acpu_pll_clk_enable, + .disable = local_pll_clk_disable, + .set_rate = local_pll_clk_set_rate, + .round_rate = local_pll_clk_round_rate, + .handoff = local_pll_clk_handoff, + .list_registers = local_pll_clk_list_registers, +}; + const struct clk_ops clk_ops_variable_rate_pll_hwfsm = { .enable = variable_rate_pll_clk_enable_hwfsm, .disable = variable_rate_pll_clk_disable_hwfsm, diff --git a/include/soc/qcom/clock-pll.h b/include/soc/qcom/clock-pll.h index 1865e3ce7e8a..dd7e186d0c5d 100644 --- a/include/soc/qcom/clock-pll.h +++ b/include/soc/qcom/clock-pll.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2012-2015, 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 2017-2018, The Linux Foundation. + * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -174,6 +175,7 @@ struct pll_clk { extern const struct clk_ops clk_ops_local_pll; extern const struct clk_ops clk_ops_sr2_pll; +extern const struct clk_ops clk_ops_acpu_pll; extern const struct clk_ops clk_ops_variable_rate_pll; extern const struct clk_ops clk_ops_variable_rate_pll_hwfsm; -- GitLab From 3e82fd3dbab7655ec22fe9d0f6cb349bb76b231a Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Tue, 5 Jun 2018 12:08:53 +0530 Subject: [PATCH 717/855] clk: msm: Update pll clock ops for SDM439/SDM429 pll hardware on SDM439/429 requires 50uSec to stabilise after it has been brought out of reset. Update pll clock ops where we add 50uSec delay before polling pll lock status. Change-Id: Ib2b7c5c5be3fbb0ab64b5f9c06d6aaaede479a32 Signed-off-by: Odelu Kukatla --- drivers/clk/msm/clock-gcc-8952.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/clk/msm/clock-gcc-8952.c b/drivers/clk/msm/clock-gcc-8952.c index 6d7727f8dbe9..d471138a1874 100644 --- a/drivers/clk/msm/clock-gcc-8952.c +++ b/drivers/clk/msm/clock-gcc-8952.c @@ -216,6 +216,7 @@ static struct pll_clk a53ss_c0_pll = { .config_reg = (void __iomem *)APCS_C0_PLL_USER_CTL, .status_reg = (void __iomem *)APCS_C0_PLL_STATUS, .freq_tbl = apcs_c0_pll_freq, + .config_ctl_reg = (void __iomem *)APCS_C0_PLL_CONFIG_CTL, .masks = { .vco_mask = BM(29, 28), .pre_div_mask = BIT(12), @@ -283,6 +284,7 @@ static struct pll_clk a53ss_c1_pll = { .config_reg = (void __iomem *)APCS_C1_PLL_USER_CTL, .status_reg = (void __iomem *)APCS_C1_PLL_STATUS, .freq_tbl = apcs_c1_pll_freq, + .config_ctl_reg = (void __iomem *)APCS_C1_PLL_CONFIG_CTL, .masks = { .vco_mask = BM(29, 28), .pre_div_mask = BIT(12), @@ -4407,6 +4409,11 @@ static int msm_gcc_probe(struct platform_device *pdev) if (compat_bin2 || compat_bin4 || compat_bin5) nbases = APCS_C0_PLL_BASE; + if (compat_bin5 || compat_bin6) { + a53ss_c0_pll.c.ops = &clk_ops_acpu_pll; + a53ss_c1_pll.c.ops = &clk_ops_acpu_pll; + } + ret = get_mmio_addr(pdev, nbases); if (ret) return ret; -- GitLab From c2fc5c9d91e6dc45a633c94f855493668dfd181e Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Tue, 22 May 2018 19:10:14 +0530 Subject: [PATCH 718/855] pinctrl: qcom: spmi-gpio: Fix the GPIO strength mapping The SPMI based PMICs have the HIGH and LOW GPIO output strength mappings interchanged, fix them. Keep the mapping same for older SSBI based PMICs. CRs-Fixed: 2246473 Change-Id: I4ec78469c436b54642ee67108943c82fba46e1c4 Signed-off-by: Anirudh Ghayal --- drivers/pinctrl/qcom/pinctrl-spmi-gpio.c | 4 ++-- drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c | 4 ++-- include/dt-bindings/pinctrl/qcom,pmic-gpio.h | 9 +++++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index 0991a99ebea4..bdce49b46f35 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -529,7 +529,7 @@ static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin, pad->pullup = arg; break; case PMIC_GPIO_CONF_STRENGTH: - if (arg > PMIC_GPIO_STRENGTH_LOW) + if (arg > PMIC_GPIO_STRENGTH_HIGH) return -EINVAL; pad->strength = arg; break; diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c index d3f5501d17ee..a562ed7e2ff8 100644 --- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Sony Mobile Communications AB. - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -365,7 +365,7 @@ static int pm8xxx_pin_config_set(struct pinctrl_dev *pctldev, banks |= BIT(0); break; case PM8XXX_QCOM_DRIVE_STRENGH: - if (arg > PMIC_GPIO_STRENGTH_LOW) { + if (arg > PM8921_GPIO_STRENGTH_LOW) { dev_err(pctrl->dev, "invalid drive strength\n"); return -EINVAL; } diff --git a/include/dt-bindings/pinctrl/qcom,pmic-gpio.h b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h index 64e2dc7183f3..7ac6f1631098 100644 --- a/include/dt-bindings/pinctrl/qcom,pmic-gpio.h +++ b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h @@ -11,9 +11,14 @@ #define PMIC_GPIO_PULL_UP_1P5_30 3 #define PMIC_GPIO_STRENGTH_NO 0 -#define PMIC_GPIO_STRENGTH_HIGH 1 +#define PMIC_GPIO_STRENGTH_LOW 1 #define PMIC_GPIO_STRENGTH_MED 2 -#define PMIC_GPIO_STRENGTH_LOW 3 +#define PMIC_GPIO_STRENGTH_HIGH 3 + +#define PM8921_GPIO_STRENGTH_NO 0 +#define PM8921_GPIO_STRENGTH_HIGH 1 +#define PM8921_GPIO_STRENGTH_MED 2 +#define PM8921_GPIO_STRENGTH_LOW 3 /* * Note: PM8018 GPIO3 and GPIO4 are supporting -- GitLab From 2d62b7a063968e4637ff8a9c11f80e6dabc3e111 Mon Sep 17 00:00:00 2001 From: Raviteja Tamatam Date: Tue, 5 Jun 2018 21:35:13 +0530 Subject: [PATCH 719/855] drm/msm/sde: validate de-interlace and scalar concurrency In de-interlace video plus scalar concurrency case- pipe fetch, unpack output and scalar block input number of lines should match. Otherwise, it will lead to hang. Added check to validate this condition. Change-Id: I00453dda36b5291948b99d0f0a89105b6875c039 Signed-off-by: Raviteja Tamatam --- drivers/gpu/drm/msm/sde/sde_plane.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c index 2e465999d76f..dc55ad53626b 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ b/drivers/gpu/drm/msm/sde/sde_plane.c @@ -3449,6 +3449,25 @@ static int _sde_plane_validate_scaler_v2(struct sde_plane *psde, src_w, src_h); return -EINVAL; } + + /* + * SSPP fetch , unpack output and QSEED3 input lines need + * to match for Y plane + */ + if (i == 0 && + (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) & + BIT(SDE_DRM_DEINTERLACE)) && + ((pstate->scaler3_cfg.src_height[i] != (src_h/2)) || + (pstate->pixel_ext.roi_h[i] != (src_h/2)))) { + SDE_ERROR_PLANE(psde, + "de-interlace fail roi[%d] %d/%d, src %dx%d, src %dx%d\n", + i, pstate->pixel_ext.roi_w[i], + pstate->pixel_ext.roi_h[i], + pstate->scaler3_cfg.src_width[i], + pstate->scaler3_cfg.src_height[i], + src_w, src_h); + return -EINVAL; + } } pstate->scaler_check_state = SDE_PLANE_SCLCHECK_SCALER_V2; -- GitLab From 5d02be98b0695991f0a22d2d6c3de9573f2be922 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Tue, 29 May 2018 16:17:29 -0700 Subject: [PATCH 720/855] qseecom: fix a race condition when loading TA Userspace and kernel clients may load a same TA at the same time. To fix potential race condition, first kernel side need to release mutex before sleep when failed to do ion allocation from QSEECOM_TA heap. Besides, since kernel client may fail to load TA if this TA is just being loaded by userspace client when mutex is released, it need to recheck if this TA exists if TA loading error code is TA already loaded. Change-Id: Ie6af9c67b867dfae7b25e4ade6948dea67e476d6 Signed-off-by: Zhen Kong --- drivers/misc/qseecom.c | 19 +++++++++++++++---- include/soc/qcom/qseecomi.h | 3 ++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 2b31ed3f981d..f0799b569642 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -4061,8 +4061,11 @@ static int __qseecom_allocate_img_data(struct ion_handle **pihandle, int retry = 0; do { - if (retry++) + if (retry++) { + mutex_unlock(&app_access_lock); msleep(QSEECOM_TA_ION_ALLOCATE_DELAY); + mutex_lock(&app_access_lock); + } ihandle = ion_alloc(qseecom.ion_clnt, fw_size, SZ_4K, ION_HEAP(ION_QSECOM_TA_HEAP_ID), 0); } while (IS_ERR_OR_NULL(ihandle) && @@ -4212,8 +4215,12 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname, ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, &resp, sizeof(resp)); if (ret) { - pr_err("scm_call to load failed : ret %d\n", ret); - ret = -EIO; + pr_err("scm_call to load failed : ret %d, result %x\n", + ret, resp.result); + if (resp.result == QSEOS_RESULT_FAIL_APP_ALREADY_LOADED) + ret = -EEXIST; + else + ret = -EIO; goto exit_disable_clk_vote; } @@ -4465,6 +4472,7 @@ int qseecom_start_app(struct qseecom_handle **handle, } mutex_lock(&app_access_lock); +recheck: app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND; strlcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE); ret = __qseecom_check_app_exists(app_ireq, &app_id); @@ -4494,7 +4502,10 @@ int qseecom_start_app(struct qseecom_handle **handle, pr_debug("%s: Loading app for the first time'\n", qseecom.pdev->init_name); ret = __qseecom_load_fw(data, app_name, &app_id); - if (ret < 0) + if (ret == -EEXIST) { + pr_err("recheck if TA %s is loaded\n", app_name); + goto recheck; + } else if (ret < 0) goto exit_ion_free; } data->client.app_id = app_id; diff --git a/include/soc/qcom/qseecomi.h b/include/soc/qcom/qseecomi.h index a7d4190fe2a2..d24916840bd0 100644 --- a/include/soc/qcom/qseecomi.h +++ b/include/soc/qcom/qseecomi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,6 +19,7 @@ #define QSEECOM_KEY_ID_SIZE 32 #define QSEOS_RESULT_FAIL_SEND_CMD_NO_THREAD -19 /*0xFFFFFFED*/ +#define QSEOS_RESULT_FAIL_APP_ALREADY_LOADED -38 /*0xFFFFFFDA*/ #define QSEOS_RESULT_FAIL_UNSUPPORTED_CE_PIPE -63 #define QSEOS_RESULT_FAIL_KS_OP -64 #define QSEOS_RESULT_FAIL_KEY_ID_EXISTS -65 -- GitLab From b24dae2dbb2bdfbb7d6e489fecbc02a3d9e6faf9 Mon Sep 17 00:00:00 2001 From: Junzhe Zou Date: Wed, 23 May 2018 17:44:40 -0700 Subject: [PATCH 721/855] msm: camera: isp: check the length of in port resource Free the IFE resource if the buffer size is not enough. Change-Id: If7e358675eb6ce70a9ae9baacb279b3d17b71669 Signed-off-by: Junzhe Zou Signed-off-by: Vishalsingh Hajeri --- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 12c37863a3a5..c1aa501e229d 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1367,6 +1367,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, uint32_t num_rdi_port_per_in = 0; uint32_t total_pix_port = 0; uint32_t total_rdi_port = 0; + uint32_t in_port_length = 0; CAM_DBG(CAM_ISP, "Enter..."); @@ -1427,9 +1428,27 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, isp_resource[i].res_hdl, isp_resource[i].length); + in_port_length = sizeof(struct cam_isp_in_port_info); + + if (in_port_length > isp_resource[i].length) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + rc = -EINVAL; + goto free_res; + } + in_port = memdup_user((void __user *)isp_resource[i].res_hdl, isp_resource[i].length); if (!IS_ERR(in_port)) { + in_port_length = sizeof(struct cam_isp_in_port_info) + + (in_port->num_out_res - 1) * + sizeof(struct cam_isp_out_port_info); + if (in_port_length > isp_resource[i].length) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + rc = -EINVAL; + kfree(in_port); + goto free_res; + } + rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port, &num_pix_port_per_in, &num_rdi_port_per_in); total_pix_port += num_pix_port_per_in; -- GitLab From 00a28e9d2400f184b093e3361b7a21a002950f03 Mon Sep 17 00:00:00 2001 From: Jayant Shekhar Date: Mon, 4 Jun 2018 12:15:23 +0530 Subject: [PATCH 722/855] drm/msm/sde: queue display failure work to event thread There are possibilities of deadlock if esd trigger work is queued to display thread. There is a corner case where during bridge disable, display thread is waiting for esd trigger work to complete to cancel esd thread, while esd trigger work is blocked on display thread. To fix this queue esd trigger work to event thread. Below is the call stack of both threads: ESD thread ---------- __switch_to+0xb8/0xec kthread_flush_work+0xdc/0x150 sde_encoder_display_failure_notification+0xc0/0x1e8 _sde_connector_report_panel_dead.part.8+0x6c/0xd4 sde_connector_check_status_work+0x10c/0x1d4 process_one_work+0x168/0x468 worker_thread+0x140/0x460 kthread+0xf4/0x108 ret_from_fork+0x10/0x50 0xffffffffffffffff Commit thread ------------- __switch_to+0xb8/0xec flush_work+0x44/0x68 __cancel_work_timer+0x138/0x1e0 cancel_delayed_work_sync+0x24/0x30 sde_connector_schedule_status_work.part.16+0xc0/0x114 _sde_connector_update_power_locked+0x1c4/0x224 _sde_connector_update_dirty_properties+0x80/0x100 sde_connector_helper_bridge_disable+0x24/0x100 dsi_bridge_disable+0x30/0x98 drm_bridge_disable+0x128/0x144 msm_atomic_helper_commit_modeset_disables+0x148/0x578 complete_commit+0x74/0x668 _msm_drm_commit_work_cb+0x4c/0x1c4 kthread_worker_fn+0xc0/0x1e4 kthread+0xf4/0x108 ret_from_fork+0x10/0x50 0xffffffffffffffff Change-Id: Ifd95664113857fd5c06098a3a2f87f28c1975513 Signed-off-by: Jayant Shekhar --- drivers/gpu/drm/msm/sde/sde_connector.c | 8 ++++++++ drivers/gpu/drm/msm/sde/sde_encoder.c | 19 ++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index 07d1ad7394c0..ab1d86b8ede6 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -1769,6 +1769,14 @@ static void _sde_connector_report_panel_dead(struct sde_connector *conn) if (!conn) return; + /* Panel dead notification can come: + * 1) ESD thread + * 2) Commit thread (if TE stops coming) + * So such case, avoid failure notification twice. + */ + if (conn->panel_dead) + return; + conn->panel_dead = true; event.type = DRM_EVENT_PANEL_DEAD; event.length = sizeof(bool); diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 2ce8b2ece557..1dcf21f31c29 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -4878,7 +4878,7 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder) int sde_encoder_display_failure_notification(struct drm_encoder *enc) { - struct msm_drm_thread *disp_thread = NULL; + struct msm_drm_thread *event_thread = NULL; struct msm_drm_private *priv = NULL; struct sde_encoder_virt *sde_enc = NULL; @@ -4890,7 +4890,7 @@ int sde_encoder_display_failure_notification(struct drm_encoder *enc) priv = enc->dev->dev_private; sde_enc = to_sde_encoder_virt(enc); if (!sde_enc->crtc || (sde_enc->crtc->index - >= ARRAY_SIZE(priv->disp_thread))) { + >= ARRAY_SIZE(priv->event_thread))) { SDE_DEBUG_ENC(sde_enc, "invalid cached CRTC: %d or crtc index: %d\n", sde_enc->crtc == NULL, @@ -4900,15 +4900,12 @@ int sde_encoder_display_failure_notification(struct drm_encoder *enc) SDE_EVT32_VERBOSE(DRMID(enc)); - disp_thread = &priv->disp_thread[sde_enc->crtc->index]; - if (current->tgid == disp_thread->thread->tgid) { - sde_encoder_resource_control(&sde_enc->base, - SDE_ENC_RC_EVENT_KICKOFF); - } else { - kthread_queue_work(&disp_thread->worker, - &sde_enc->esd_trigger_work); - kthread_flush_work(&sde_enc->esd_trigger_work); - } + event_thread = &priv->event_thread[sde_enc->crtc->index]; + + kthread_queue_work(&event_thread->worker, + &sde_enc->esd_trigger_work); + kthread_flush_work(&sde_enc->esd_trigger_work); + /** * panel may stop generating te signal (vsync) during esd failure. rsc * hardware may hang without vsync. Avoid rsc hang by generating the -- GitLab From 52f818cc22f563af8b13fe77a37a1814684e4cef Mon Sep 17 00:00:00 2001 From: Manoj Kumar AVM Date: Tue, 9 May 2017 14:08:10 -0700 Subject: [PATCH 723/855] drm/msm: make msm_drm.h uapi header safe for C++ fixes the C++ related compilation issues. CRs-Fixed: 2038080 Change-Id: If6b4f379eb27f3de6153b8666f733c0b8245851f Signed-off-by: Manoj Kumar AVM --- include/uapi/drm/msm_drm.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index d0341cdebd01..4b26cba14965 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -180,8 +180,12 @@ struct drm_msm_gem_cpu_fini { */ struct drm_msm_gem_submit_reloc { __u32 submit_offset; /* in, offset from submit_bo */ - __u32 or; /* in, value OR'd with result */ - __s32 shift; /* in, amount of left shift (can be negative) */ +#ifdef __cplusplus + __u32 or_val; +#else + __u32 or; /* in, value OR'd with result */ +#endif + __s32 shift; /* in, amount of left shift (can be negative) */ __u32 reloc_idx; /* in, index of reloc_bo buffer */ __u64 reloc_offset; /* in, offset from start of reloc_bo */ }; -- GitLab From 895f606ecdc18c4ff3763d247846c34dc8c8bffd Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Tue, 15 May 2018 21:41:58 +0530 Subject: [PATCH 724/855] ARM: dts: msm: Update CX VDD restriction vote for MSM8937/SDM439 Update cold temperature VDD CX restriction vote based on latest recommendation for MSM8937/SDM439. Change-Id: Ib1cdafc2b2a891146ea8ed649943cac1c5c38cab Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi | 2 +- arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi index 44bdfc9d315b..d6f24d94ec55 100644 --- a/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi @@ -62,7 +62,7 @@ pm8937_cx_cdev: regulator-cx-cdev { compatible = "qcom,regulator-cooling-device"; regulator-cdev-supply = <&pm8937_s2_floor_level>; - regulator-levels = ; #cooling-cells = <2>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi index 4c4c4bd34a81..b97e66e60abe 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi @@ -67,7 +67,7 @@ pm8953_cx_cdev: regulator-cx-cdev { compatible = "qcom,regulator-cooling-device"; regulator-cdev-supply = <&pm8953_s2_floor_level>; - regulator-levels = ; #cooling-cells = <2>; }; -- GitLab From 311a184a639ba7144630d604697c11d104c919e6 Mon Sep 17 00:00:00 2001 From: Jayant Shekhar Date: Mon, 29 May 2017 16:26:50 +0530 Subject: [PATCH 725/855] msm: mdss: Change IOMMU map sequence for splash Currently PA to VA mapping is not working with existing sequence. Correct the sequence as below: - set DOMAIN_ATTR_EARLY_MAP attr to 1 - attach iommu - perform mapping - set DOMAIN_ATTR_EARLY_MAP to 0 Change-Id: Ieabb91cc69641bb41ca5a3ff5783dd55385490e6 Signed-off-by: Jayant Shekhar --- .../video/fbdev/msm/mdss_mdp_splash_logo.c | 45 ++++++++++++------- drivers/video/fbdev/msm/mdss_smmu.c | 21 +++++++++ drivers/video/fbdev/msm/mdss_smmu.h | 5 +++ 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c index 44817c3f8e06..cf1950198aff 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c +++ b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c @@ -149,7 +149,7 @@ static int mdss_mdp_splash_iommu_attach(struct msm_fb_data_type *mfd) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); struct mdss_data_type *mdata = mdss_mdp_get_mdata(); - int rc, ret; + int ret; /* * iommu dynamic attach for following conditions. @@ -166,26 +166,41 @@ static int mdss_mdp_splash_iommu_attach(struct msm_fb_data_type *mfd) return -EPERM; } - rc = mdss_smmu_map(MDSS_IOMMU_DOMAIN_UNSECURE, + /* + * Putting handoff pending to false to ensure smmu attach happens + * with early flag attribute + */ + mdata->handoff_pending = false; + + ret = mdss_smmu_set_attribute(MDSS_IOMMU_DOMAIN_UNSECURE, EARLY_MAP, 1); + if (ret) { + pr_debug("mdss set attribute failed for early map\n"); + goto end; + } + + ret = mdss_iommu_ctrl(1); + if (IS_ERR_VALUE((unsigned long)ret)) { + pr_err("mdss iommu attach failed\n"); + goto end; + } + + ret = mdss_smmu_map(MDSS_IOMMU_DOMAIN_UNSECURE, mdp5_data->splash_mem_addr, mdp5_data->splash_mem_addr, mdp5_data->splash_mem_size, IOMMU_READ | IOMMU_NOEXEC); - if (rc) { - pr_debug("iommu memory mapping failed rc=%d\n", rc); + if (ret) { + pr_err("iommu memory mapping failed ret=%d\n", ret); } else { - ret = mdss_iommu_ctrl(1); - if (IS_ERR_VALUE((unsigned long)ret)) { - pr_err("mdss iommu attach failed\n"); - mdss_smmu_unmap(MDSS_IOMMU_DOMAIN_UNSECURE, - mdp5_data->splash_mem_addr, - mdp5_data->splash_mem_size); - } else { - mfd->splash_info.iommu_dynamic_attached = true; - } + pr_debug("iommu map passed for PA=VA\n"); + mfd->splash_info.iommu_dynamic_attached = true; } - return rc; + ret = mdss_smmu_set_attribute(MDSS_IOMMU_DOMAIN_UNSECURE, EARLY_MAP, 0); +end: + mdata->handoff_pending = true; + + return ret; } static void mdss_mdp_splash_unmap_splash_mem(struct msm_fb_data_type *mfd) @@ -193,12 +208,10 @@ static void mdss_mdp_splash_unmap_splash_mem(struct msm_fb_data_type *mfd) struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); if (mfd->splash_info.iommu_dynamic_attached) { - mdss_smmu_unmap(MDSS_IOMMU_DOMAIN_UNSECURE, mdp5_data->splash_mem_addr, mdp5_data->splash_mem_size); mdss_iommu_ctrl(0); - mfd->splash_info.iommu_dynamic_attached = false; } } diff --git a/drivers/video/fbdev/msm/mdss_smmu.c b/drivers/video/fbdev/msm/mdss_smmu.c index 972c8dec9336..7be8900815ae 100644 --- a/drivers/video/fbdev/msm/mdss_smmu.c +++ b/drivers/video/fbdev/msm/mdss_smmu.c @@ -180,6 +180,27 @@ static int mdss_smmu_enable_power(struct mdss_smmu_client *mdss_smmu, return rc; } +int mdss_smmu_set_attribute(int domain, int flag, int val) +{ + int rc = 0, domain_attr = 0; + struct mdss_smmu_client *mdss_smmu = mdss_smmu_get_cb(domain); + + if (!mdss_smmu) { + pr_err("not able to get smmu context\n"); + return -EINVAL; + } + + if (flag == EARLY_MAP) + domain_attr = DOMAIN_ATTR_EARLY_MAP; + else + goto end; + + rc = iommu_domain_set_attr(mdss_smmu->mmu_mapping->domain, + domain_attr, &val); +end: + return rc; +} + /* * mdss_smmu_v2_attach() * diff --git a/drivers/video/fbdev/msm/mdss_smmu.h b/drivers/video/fbdev/msm/mdss_smmu.h index 091af3be487f..97f0933ed032 100644 --- a/drivers/video/fbdev/msm/mdss_smmu.h +++ b/drivers/video/fbdev/msm/mdss_smmu.h @@ -42,6 +42,11 @@ struct mdss_smmu_domain { void mdss_smmu_register(struct device *dev); int mdss_smmu_init(struct mdss_data_type *mdata, struct device *dev); +int mdss_smmu_set_attribute(int domain, int flag, int val); + +enum smmu_attributes { + EARLY_MAP +}; static inline int mdss_smmu_dma_data_direction(int dir) { -- GitLab From 410cb11a08ecc99212c96e06ec425609970af0b1 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Sun, 27 May 2018 23:20:18 -0700 Subject: [PATCH 726/855] power: smb5: Fix ICL for SDP with non-compliant cable Currently, ICL for SDP is set 100mA if PMIC5 is connected with a legacy non-compliant cable, while it is supposed to be 500mA per PMIC5 spec. Correct it. CRs-Fixed: 2249471 Change-Id: Ib60c798a6122dad9016b788dc79969666ce44aca Signed-off-by: Harry Yang --- drivers/power/supply/qcom/smb5-lib.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 9f395619092e..3669a456917e 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -894,9 +894,10 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) goto set_mode; /* configure current */ - if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) - || (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)) - && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) { + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB + && (chg->typec_legacy + || chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT + || chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)) { rc = set_sdp_current(chg, icl_ua); if (rc < 0) { smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc); -- GitLab From 91a5042ed1f77ae1f7d1e09585395009ed060efa Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Tue, 22 May 2018 11:01:19 -0700 Subject: [PATCH 727/855] power: smb5: update APSD result in USBIN_PLUGIN IRQ The variable real_charge_type is a cached value to reflect the real connected charger type based on APSD results. However, it is not updated when APSD result status gets cleared on charger removal, the moment when USBIN_PLUGIN_RT_STS goes low on unplug. As a result, some times, charger type remains even after a charger is removed. Fix it by updating real_charge_type in USBIN_PLUGIN IRQ. Change-Id: I008aa466ef83c12a38d3d2a2d81c736d14d019c9 Signed-off-by: Harry Yang --- drivers/power/supply/qcom/smb5-lib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 3669a456917e..4bf07a14228a 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -2790,6 +2790,8 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) rc = smblib_request_dpdm(chg, false); if (rc < 0) smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); + + smblib_update_usb_type(chg); } if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) -- GitLab From 877b3904793a443f5c548cf95fb4fd2d70fa0dca Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Fri, 18 May 2018 14:31:28 +0530 Subject: [PATCH 728/855] clk: qcom: Support to add hardware clocks to of_clk_hw_provider Currently the hardware clocks are added from each clock controller individually and are not added to the of_clk_provider. But there could be clocks which are required by clients to be used. Add the hardware clocks to the of_clk_hw_provide list. Change-Id: Id88823b03ece283bf9fcb5bcaaf382210e60d0d6 Signed-off-by: Taniya Das Signed-off-by: Odelu Kukatla --- drivers/clk/qcom/common.c | 23 +++++++++++++++++++++-- drivers/clk/qcom/common.h | 4 +++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index d426691d8c64..316ac3966e99 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2013-2014, 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, 2017-2018, + * The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -30,7 +31,9 @@ struct qcom_cc { struct qcom_reset_controller reset; struct clk_regmap **rclks; + struct clk_hw **hwclks; size_t num_rclks; + size_t num_hwclks; }; const @@ -182,11 +185,14 @@ static struct clk_hw *qcom_cc_clk_hw_get(struct of_phandle_args *clkspec, struct qcom_cc *cc = data; unsigned int idx = clkspec->args[0]; - if (idx >= cc->num_rclks) { + if (idx >= cc->num_rclks + cc->num_hwclks) { pr_err("invalid index %u\n", idx); return ERR_PTR(-EINVAL); } + if (idx < cc->num_hwclks && cc->hwclks[idx]) + return cc->hwclks[idx]; + return cc->rclks[idx] ? &cc->rclks[idx]->hw : ERR_PTR(-ENOENT); } @@ -199,7 +205,9 @@ int qcom_cc_really_probe(struct platform_device *pdev, struct qcom_cc *cc; struct gdsc_desc *scd; size_t num_clks = desc->num_clks; + size_t num_hwclks = desc->num_hwclks; struct clk_regmap **rclks = desc->clks; + struct clk_hw **hwclks = desc->hwclks; cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL); if (!cc) @@ -207,6 +215,17 @@ int qcom_cc_really_probe(struct platform_device *pdev, cc->rclks = rclks; cc->num_rclks = num_clks; + cc->hwclks = hwclks; + cc->num_hwclks = num_hwclks; + + for (i = 0; i < num_hwclks; i++) { + if (!hwclks[i]) + continue; + + ret = devm_clk_hw_register(dev, hwclks[i]); + if (ret) + return ret; + } for (i = 0; i < num_clks; i++) { if (!rclks[i]) diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index 5e26763d153f..29c46970f5b0 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -28,7 +28,9 @@ struct parent_map; struct qcom_cc_desc { const struct regmap_config *config; struct clk_regmap **clks; + struct clk_hw **hwclks; size_t num_clks; + size_t num_hwclks; const struct qcom_reset_map *resets; size_t num_resets; struct gdsc **gdscs; -- GitLab From 79014da51d9babe781d24dff077d2b67b137c0eb Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Thu, 31 May 2018 22:22:07 +0530 Subject: [PATCH 729/855] diag: Prevent accessing uninitialized diag_md_info member The patch prevents accessing uninitialized diag_md_info struct with a check on variable set only upon structure initialization. Change-Id: Ie0b5ece24fbacfabac876aa4bf2295354374ed57 Signed-off-by: Manoj Prabhu B --- drivers/char/diag/diag_memorydevice.c | 16 +++++++++++++++- drivers/char/diag/diag_memorydevice.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c index 55b1b4961eeb..c00fbfc0324b 100644 --- a/drivers/char/diag/diag_memorydevice.c +++ b/drivers/char/diag/diag_memorydevice.c @@ -37,6 +37,7 @@ struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = { .ctx = 0, .mempool = POOL_TYPE_MUX_APPS, .num_tbl_entries = 0, + .md_info_inited = 0, .tbl = NULL, .ops = NULL, }, @@ -46,6 +47,7 @@ struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = { .ctx = 0, .mempool = POOL_TYPE_MDM_MUX, .num_tbl_entries = 0, + .md_info_inited = 0, .tbl = NULL, .ops = NULL, }, @@ -54,6 +56,7 @@ struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = { .ctx = 0, .mempool = POOL_TYPE_MDM2_MUX, .num_tbl_entries = 0, + .md_info_inited = 0, .tbl = NULL, .ops = NULL, }, @@ -62,6 +65,7 @@ struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = { .ctx = 0, .mempool = POOL_TYPE_QSC_MUX, .num_tbl_entries = 0, + .md_info_inited = 0, .tbl = NULL, .ops = NULL, } @@ -85,6 +89,8 @@ void diag_md_open_all(void) for (i = 0; i < NUM_DIAG_MD_DEV; i++) { ch = &diag_md[i]; + if (!ch->md_info_inited) + continue; if (ch->ops && ch->ops->open) ch->ops->open(ch->ctx, DIAG_MEMORY_DEVICE_MODE); } @@ -99,6 +105,8 @@ void diag_md_close_all(void) for (i = 0; i < NUM_DIAG_MD_DEV; i++) { ch = &diag_md[i]; + if (!ch->md_info_inited) + continue; if (ch->ops && ch->ops->close) ch->ops->close(ch->ctx, DIAG_MEMORY_DEVICE_MODE); @@ -155,7 +163,7 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) mutex_unlock(&driver->md_session_lock); ch = &diag_md[id]; - if (!ch) + if (!ch || !ch->md_info_inited) return -EINVAL; spin_lock_irqsave(&ch->lock, flags); @@ -232,6 +240,8 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size, for (i = 0; i < NUM_DIAG_MD_DEV && !err; i++) { ch = &diag_md[i]; + if (!ch->md_info_inited) + continue; for (j = 0; j < ch->num_tbl_entries && !err; j++) { entry = &ch->tbl[j]; if (entry->len <= 0 || entry->buf == NULL) @@ -352,6 +362,8 @@ int diag_md_close_peripheral(int id, uint8_t peripheral) return -EINVAL; ch = &diag_md[id]; + if (!ch || !ch->md_info_inited) + return -EINVAL; spin_lock_irqsave(&ch->lock, flags); for (i = 0; i < ch->num_tbl_entries && !found; i++) { @@ -399,6 +411,7 @@ int diag_md_init(void) ch->tbl[j].ctx = 0; } spin_lock_init(&(ch->lock)); + ch->md_info_inited = 1; } return 0; @@ -427,6 +440,7 @@ int diag_md_mdm_init(void) ch->tbl[j].ctx = 0; } spin_lock_init(&(ch->lock)); + ch->md_info_inited = 1; } return 0; diff --git a/drivers/char/diag/diag_memorydevice.h b/drivers/char/diag/diag_memorydevice.h index 9b4aa392233d..4d65dedfdb58 100644 --- a/drivers/char/diag/diag_memorydevice.h +++ b/drivers/char/diag/diag_memorydevice.h @@ -38,6 +38,7 @@ struct diag_md_info { int ctx; int mempool; int num_tbl_entries; + int md_info_inited; spinlock_t lock; struct diag_buf_tbl_t *tbl; struct diag_mux_ops *ops; -- GitLab From 85d364364ad1ff15713f40ebad4f119bc45bb8c5 Mon Sep 17 00:00:00 2001 From: Yogesh Lal Date: Wed, 25 Oct 2017 18:18:27 +0530 Subject: [PATCH 730/855] lowmemorykiller: add a knob to turn on/off the feature Add an option to turn on/off lowmemorykiller so that userspace can enable or disable lowmemorykiller as per requirement. Change-Id: I539f7e23cdf5540e536569f0a582c9e7fe79c3c4 Signed-off-by: Yogesh Lal Signed-off-by: Naitik Bharadiya --- drivers/staging/android/lowmemorykiller.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index a1602e4e9f87..027094f4ed32 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -63,6 +63,10 @@ #define CREATE_TRACE_POINTS #include "trace/lowmemorykiller.h" +/* to enable lowmemorykiller */ +static int enable_lmk = 1; +module_param_named(enable_lmk, enable_lmk, int, 0644); + static u32 lowmem_debug_level = 1; static short lowmem_adj[6] = { 0, @@ -93,6 +97,9 @@ static unsigned long lowmem_deathpending_timeout; static unsigned long lowmem_count(struct shrinker *s, struct shrink_control *sc) { + if (!enable_lmk) + return 0; + return global_node_page_state(NR_ACTIVE_ANON) + global_node_page_state(NR_ACTIVE_FILE) + global_node_page_state(NR_INACTIVE_ANON) + -- GitLab From a02db2c6d326dd9a2295eaa8e8a6a79eaef07339 Mon Sep 17 00:00:00 2001 From: Kalyan Thota Date: Fri, 27 Apr 2018 11:39:18 +0530 Subject: [PATCH 731/855] drm/msm/sde: Allow selection of panel TE GPIOs to source pingpong blocks Allow separate GPIO configurability such that secondary pingpong can choose which panel GPIO can be sourced to its pingpong TE. Change-Id: I72b77267a3830cd052beebf545b4bdcd1ecea6da Signed-off-by: Kalyan Thota --- Documentation/devicetree/bindings/display/msm/sde.txt | 3 +++ drivers/gpu/drm/msm/sde/sde_encoder.c | 5 +++-- drivers/gpu/drm/msm/sde/sde_hw_catalog.c | 6 ++++++ drivers/gpu/drm/msm/sde/sde_hw_catalog.h | 1 + 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/sde.txt b/Documentation/devicetree/bindings/display/msm/sde.txt index 0589165d18be..15f1e93c0d69 100644 --- a/Documentation/devicetree/bindings/display/msm/sde.txt +++ b/Documentation/devicetree/bindings/display/msm/sde.txt @@ -103,6 +103,8 @@ Optional properties: - qcom,sde-dsc-size: A u32 value indicates the address range for each dsc. - qcom,sde-cdm-size: A u32 value indicates the address range for each cdm. - qcom,sde-pp-size: A u32 value indicates the address range for each pingpong. +- qcom,sde-te-source: Array of GPIO sources indicating which pingpong TE is + sourced to which panel TE gpio. - qcom,sde-wb-size: A u32 value indicates the address range for each writeback. - qcom,sde-len: A u32 entry for SDE address range. - qcom,sde-intf-max-prefetch-lines: Array of u32 values for max prefetch lines on @@ -502,6 +504,7 @@ Example: qcom,sde-pp-off = <0x00071000 0x00071800 0x00072000 0x00072800>; qcom,sde-pp-slave = <0x0 0x0 0x0 0x0>; + qcom,sde-te-source = <0x0 0x1 0x0 0x0>; qcom,sde-cdm-off = <0x0007a200>; qcom,sde-dsc-off = <0x00081000 0x00081400>; qcom,sde-intf-max-prefetch-lines = <0x15 0x15 0x15 0x15>; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 2ce8b2ece557..2cc9bf4fcc0e 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -1489,12 +1489,13 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, vsync_cfg.pp_count = sde_enc->num_phys_encs; vsync_cfg.frame_rate = mode_info.frame_rate; + vsync_cfg.vsync_source = + sde_enc->cur_master->hw_pp->caps->te_source; if (is_dummy) vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_1; else if (disp_info->is_te_using_watchdog_timer) vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0; - else - vsync_cfg.vsync_source = SDE_VSYNC0_SOURCE_GPIO; + vsync_cfg.is_dummy = is_dummy; hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index 475f8d08cc41..baec526f4d31 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -249,6 +249,7 @@ enum { DITHER_OFF, DITHER_LEN, DITHER_VER, + TE_SOURCE, PP_PROP_MAX, }; @@ -589,6 +590,7 @@ static struct sde_prop_type pp_prop[] = { {DITHER_OFF, "qcom,sde-dither-off", false, PROP_TYPE_U32_ARRAY}, {DITHER_LEN, "qcom,sde-dither-size", false, PROP_TYPE_U32}, {DITHER_VER, "qcom,sde-dither-version", false, PROP_TYPE_U32}, + {TE_SOURCE, "qcom,sde-te-source", false, PROP_TYPE_U32_ARRAY}, }; static struct sde_prop_type dsc_prop[] = { @@ -2628,6 +2630,10 @@ static int sde_pp_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) snprintf(pp->name, SDE_HW_BLK_NAME_LEN, "pingpong_%u", pp->id - PINGPONG_0); pp->len = PROP_VALUE_ACCESS(prop_value, PP_LEN, 0); + pp->te_source = PROP_VALUE_ACCESS(prop_value, TE_SOURCE, i); + if (!prop_exists[TE_SOURCE] || + pp->te_source > SDE_VSYNC_SOURCE_WD_TIMER_0) + pp->te_source = SDE_VSYNC0_SOURCE_GPIO; sblk->te.base = PROP_VALUE_ACCESS(prop_value, TE_OFF, i); sblk->te.id = SDE_PINGPONG_TE; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h index 65919e9bfbf2..52bdc785bfb5 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h @@ -653,6 +653,7 @@ struct sde_ds_cfg { */ struct sde_pingpong_cfg { SDE_HW_BLK_INFO; + u32 te_source; const struct sde_pingpong_sub_blks *sblk; }; -- GitLab From bd26ca592a5b7d330b894ff62bb1f93137e12dad Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Tue, 5 Jun 2018 13:41:05 +0800 Subject: [PATCH 732/855] ARM: dts: msm: bringup bluetooth for sdxpoorwills enable BT UART blsp1_uart2b and configure BT RFKILL CRs-Fixed: 2254144 Change-Id: I44286fb5a911216269245931e1d1246efba18e8d Signed-off-by: Zijun Hu --- arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dts | 4 ++++ arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dts index 6909ef586586..6c6e64065f47 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dts @@ -28,3 +28,7 @@ &cnss_sdio { status = "okay"; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi index d447724fb66a..16f933f687ce 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi @@ -36,3 +36,11 @@ /delete-property/ qcom,devfreq,freq-table; /delete-property/ cd-gpios; }; + +&soc { + bluetooth: bt_qca6174 { + compatible = "qca,qca6174"; + qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */ + qca,bt-vdd-pa-supply = <&vreg_wlan>; + }; +}; -- GitLab From 1cf767aee2a965c1d020e4892db4bd29cd62dbb8 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Thu, 15 Feb 2018 15:45:26 +0530 Subject: [PATCH 733/855] clk: qcom: Add voter clocks for gcc_aggre_ufs_phy_axi_clk for SDM670 Voter clock support for gcc_aggre_ufs_phy_axi_clk is required as eMMC and UFS drivers need to vote for the clock concurrently. Change-Id: I145cf1610d54f6cd8fc2657389ecb8aae44a9875 Signed-off-by: Odelu Kukatla --- drivers/clk/qcom/gcc-sdm845.c | 22 +- include/dt-bindings/clock/qcom,gcc-sdm845.h | 412 ++++++++++---------- 2 files changed, 219 insertions(+), 215 deletions(-) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index 555b8bd603e9..7ea5d9d50d7a 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -35,6 +35,7 @@ #include "reset.h" #include "clk-alpha-pll.h" #include "vdd-level-sdm845.h" +#include "clk-voter.h" #define GCC_MMSS_MISC 0x09FFC #define GCC_GPU_MISC 0x71028 @@ -1505,6 +1506,11 @@ static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { }, }; +static DEFINE_CLK_VOTER(ufs_phy_axi_emmc_vote_clk, + gcc_aggre_ufs_phy_axi_clk, 0); +static DEFINE_CLK_VOTER(ufs_phy_axi_ufs_vote_clk, + gcc_aggre_ufs_phy_axi_clk, 0); + static struct clk_branch gcc_aggre_ufs_phy_axi_hw_ctl_clk = { .halt_reg = 0x82024, .clkr = { @@ -3780,6 +3786,8 @@ struct clk_hw *gcc_sdm845_hws[] = { [MEASURE_ONLY_CNOC_CLK] = &measure_only_cnoc_clk.hw, [MEASURE_ONLY_BIMC_CLK] = &measure_only_bimc_clk.hw, [MEASURE_ONLY_IPA_2X_CLK] = &measure_only_ipa_2x_clk.hw, + [UFS_PHY_AXI_EMMC_VOTE_CLK] = &ufs_phy_axi_emmc_vote_clk.hw, + [UFS_PHY_AXI_UFS_VOTE_CLK] = &ufs_phy_axi_ufs_vote_clk.hw, }; static struct clk_regmap *gcc_sdm845_clocks[] = { @@ -4061,6 +4069,8 @@ static const struct qcom_cc_desc gcc_sdm845_desc = { .config = &gcc_sdm845_regmap_config, .clks = gcc_sdm845_clocks, .num_clks = ARRAY_SIZE(gcc_sdm845_clocks), + .hwclks = gcc_sdm845_hws, + .num_hwclks = ARRAY_SIZE(gcc_sdm845_hws), .resets = gcc_sdm845_resets, .num_resets = ARRAY_SIZE(gcc_sdm845_resets), }; @@ -4279,9 +4289,8 @@ static int gcc_sdm845_fixup(struct platform_device *pdev) static int gcc_sdm845_probe(struct platform_device *pdev) { - struct clk *clk; struct regmap *regmap; - int i, ret = 0; + int ret = 0; regmap = qcom_cc_map(pdev, &gcc_sdm845_desc); if (IS_ERR(regmap)) @@ -4307,13 +4316,6 @@ static int gcc_sdm845_probe(struct platform_device *pdev) if (ret) return ret; - /* Register the dummy measurement clocks */ - for (i = 0; i < ARRAY_SIZE(gcc_sdm845_hws); i++) { - clk = devm_clk_register(&pdev->dev, gcc_sdm845_hws[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - } - ret = qcom_cc_really_probe(pdev, &gcc_sdm845_desc, regmap); if (ret) { dev_err(&pdev->dev, "Failed to register GCC clocks\n"); diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h index c8696dfc0539..6da90d0dd184 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdm845.h +++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,205 +14,213 @@ #ifndef _DT_BINDINGS_CLK_MSM_GCC_SDM845_H #define _DT_BINDINGS_CLK_MSM_GCC_SDM845_H +/* Dummy clocks for rate measurement */ +#define MEASURE_ONLY_SNOC_CLK 0 +#define MEASURE_ONLY_CNOC_CLK 1 +#define MEASURE_ONLY_BIMC_CLK 2 +#define MEASURE_ONLY_IPA_2X_CLK 3 +#define UFS_PHY_AXI_EMMC_VOTE_CLK 4 +#define UFS_PHY_AXI_UFS_VOTE_CLK 5 + /* GCC clock registers */ -#define GCC_AGGRE_NOC_PCIE_TBU_CLK 0 -#define GCC_AGGRE_UFS_CARD_AXI_CLK 1 -#define GCC_AGGRE_UFS_PHY_AXI_CLK 2 -#define GCC_AGGRE_USB3_PRIM_AXI_CLK 3 -#define GCC_AGGRE_USB3_SEC_AXI_CLK 4 -#define GCC_BOOT_ROM_AHB_CLK 5 -#define GCC_CAMERA_AHB_CLK 6 -#define GCC_CAMERA_AXI_CLK 7 -#define GCC_CAMERA_XO_CLK 8 -#define GCC_CE1_AHB_CLK 9 -#define GCC_CE1_AXI_CLK 10 -#define GCC_CE1_CLK 11 -#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 12 -#define GCC_CFG_NOC_USB3_SEC_AXI_CLK 13 -#define GCC_CPUSS_AHB_CLK 14 -#define GCC_CPUSS_AHB_CLK_SRC 15 -#define GCC_CPUSS_DVM_BUS_CLK 16 -#define GCC_CPUSS_GNOC_CLK 17 -#define GCC_CPUSS_RBCPR_CLK 18 -#define GCC_CPUSS_RBCPR_CLK_SRC 19 -#define GCC_DDRSS_GPU_AXI_CLK 20 -#define GCC_DISP_AHB_CLK 21 -#define GCC_DISP_AXI_CLK 22 -#define GCC_DISP_GPLL0_CLK_SRC 23 -#define GCC_DISP_GPLL0_DIV_CLK_SRC 24 -#define GCC_DISP_XO_CLK 25 -#define GCC_GP1_CLK 26 -#define GCC_GP1_CLK_SRC 27 -#define GCC_GP2_CLK 28 -#define GCC_GP2_CLK_SRC 29 -#define GCC_GP3_CLK 30 -#define GCC_GP3_CLK_SRC 31 -#define GCC_GPU_CFG_AHB_CLK 32 -#define GCC_GPU_GPLL0_CLK_SRC 33 -#define GCC_GPU_GPLL0_DIV_CLK_SRC 34 -#define GCC_GPU_MEMNOC_GFX_CLK 35 -#define GCC_GPU_SNOC_DVM_GFX_CLK 36 -#define GCC_MSS_AXIS2_CLK 37 -#define GCC_MSS_CFG_AHB_CLK 38 -#define GCC_MSS_GPLL0_DIV_CLK_SRC 39 -#define GCC_MSS_MFAB_AXIS_CLK 40 -#define GCC_MSS_Q6_MEMNOC_AXI_CLK 41 -#define GCC_MSS_SNOC_AXI_CLK 42 -#define GCC_PCIE_0_AUX_CLK 43 -#define GCC_PCIE_0_AUX_CLK_SRC 44 -#define GCC_PCIE_0_CFG_AHB_CLK 45 -#define GCC_PCIE_0_CLKREF_CLK 46 -#define GCC_PCIE_0_MSTR_AXI_CLK 47 -#define GCC_PCIE_0_PIPE_CLK 48 -#define GCC_PCIE_0_SLV_AXI_CLK 49 -#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 50 -#define GCC_PCIE_1_AUX_CLK 51 -#define GCC_PCIE_1_AUX_CLK_SRC 52 -#define GCC_PCIE_1_CFG_AHB_CLK 53 -#define GCC_PCIE_1_CLKREF_CLK 54 -#define GCC_PCIE_1_MSTR_AXI_CLK 55 -#define GCC_PCIE_1_PIPE_CLK 56 -#define GCC_PCIE_1_SLV_AXI_CLK 57 -#define GCC_PCIE_1_SLV_Q2A_AXI_CLK 58 -#define GCC_PCIE_PHY_AUX_CLK 59 -#define GCC_PCIE_PHY_REFGEN_CLK 60 -#define GCC_PCIE_PHY_REFGEN_CLK_SRC 61 -#define GCC_PDM2_CLK 62 -#define GCC_PDM2_CLK_SRC 63 -#define GCC_PDM_AHB_CLK 64 -#define GCC_PDM_XO4_CLK 65 -#define GCC_PRNG_AHB_CLK 66 -#define GCC_QMIP_CAMERA_AHB_CLK 67 -#define GCC_QMIP_DISP_AHB_CLK 68 -#define GCC_QMIP_VIDEO_AHB_CLK 69 -#define GCC_QUPV3_WRAP0_S0_CLK 70 -#define GCC_QUPV3_WRAP0_S0_CLK_SRC 71 -#define GCC_QUPV3_WRAP0_S1_CLK 72 -#define GCC_QUPV3_WRAP0_S1_CLK_SRC 73 -#define GCC_QUPV3_WRAP0_S2_CLK 74 -#define GCC_QUPV3_WRAP0_S2_CLK_SRC 75 -#define GCC_QUPV3_WRAP0_S3_CLK 76 -#define GCC_QUPV3_WRAP0_S3_CLK_SRC 77 -#define GCC_QUPV3_WRAP0_S4_CLK 78 -#define GCC_QUPV3_WRAP0_S4_CLK_SRC 79 -#define GCC_QUPV3_WRAP0_S5_CLK 80 -#define GCC_QUPV3_WRAP0_S5_CLK_SRC 81 -#define GCC_QUPV3_WRAP0_S6_CLK 82 -#define GCC_QUPV3_WRAP0_S6_CLK_SRC 83 -#define GCC_QUPV3_WRAP0_S7_CLK 84 -#define GCC_QUPV3_WRAP0_S7_CLK_SRC 85 -#define GCC_QUPV3_WRAP1_S0_CLK 86 -#define GCC_QUPV3_WRAP1_S0_CLK_SRC 87 -#define GCC_QUPV3_WRAP1_S1_CLK 88 -#define GCC_QUPV3_WRAP1_S1_CLK_SRC 89 -#define GCC_QUPV3_WRAP1_S2_CLK 90 -#define GCC_QUPV3_WRAP1_S2_CLK_SRC 91 -#define GCC_QUPV3_WRAP1_S3_CLK 92 -#define GCC_QUPV3_WRAP1_S3_CLK_SRC 93 -#define GCC_QUPV3_WRAP1_S4_CLK 94 -#define GCC_QUPV3_WRAP1_S4_CLK_SRC 95 -#define GCC_QUPV3_WRAP1_S5_CLK 96 -#define GCC_QUPV3_WRAP1_S5_CLK_SRC 97 -#define GCC_QUPV3_WRAP1_S6_CLK 98 -#define GCC_QUPV3_WRAP1_S6_CLK_SRC 99 -#define GCC_QUPV3_WRAP1_S7_CLK 100 -#define GCC_QUPV3_WRAP1_S7_CLK_SRC 101 -#define GCC_QUPV3_WRAP_0_M_AHB_CLK 102 -#define GCC_QUPV3_WRAP_0_S_AHB_CLK 103 -#define GCC_QUPV3_WRAP_1_M_AHB_CLK 104 -#define GCC_QUPV3_WRAP_1_S_AHB_CLK 105 -#define GCC_SDCC2_AHB_CLK 106 -#define GCC_SDCC2_APPS_CLK 107 -#define GCC_SDCC2_APPS_CLK_SRC 108 -#define GCC_SDCC4_AHB_CLK 109 -#define GCC_SDCC4_APPS_CLK 110 -#define GCC_SDCC4_APPS_CLK_SRC 111 -#define GCC_SYS_NOC_CPUSS_AHB_CLK 112 -#define GCC_TSIF_AHB_CLK 113 -#define GCC_TSIF_INACTIVITY_TIMERS_CLK 114 -#define GCC_TSIF_REF_CLK 115 -#define GCC_TSIF_REF_CLK_SRC 116 -#define GCC_UFS_CARD_AHB_CLK 117 -#define GCC_UFS_CARD_AXI_CLK 118 -#define GCC_UFS_CARD_AXI_CLK_SRC 119 -#define GCC_UFS_CARD_CLKREF_CLK 120 -#define GCC_UFS_CARD_ICE_CORE_CLK 121 -#define GCC_UFS_CARD_ICE_CORE_CLK_SRC 122 -#define GCC_UFS_CARD_PHY_AUX_CLK 123 -#define GCC_UFS_CARD_PHY_AUX_CLK_SRC 124 -#define GCC_UFS_CARD_RX_SYMBOL_0_CLK 125 -#define GCC_UFS_CARD_RX_SYMBOL_1_CLK 126 -#define GCC_UFS_CARD_TX_SYMBOL_0_CLK 127 -#define GCC_UFS_CARD_UNIPRO_CORE_CLK 128 -#define GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC 129 -#define GCC_UFS_MEM_CLKREF_CLK 130 -#define GCC_UFS_PHY_AHB_CLK 131 -#define GCC_UFS_PHY_AXI_CLK 132 -#define GCC_UFS_PHY_AXI_CLK_SRC 133 -#define GCC_UFS_PHY_ICE_CORE_CLK 134 -#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 135 -#define GCC_UFS_PHY_PHY_AUX_CLK 136 -#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 137 -#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 138 -#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 139 -#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 140 -#define GCC_UFS_PHY_UNIPRO_CORE_CLK 141 -#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 142 -#define GCC_USB30_PRIM_MASTER_CLK 143 -#define GCC_USB30_PRIM_MASTER_CLK_SRC 144 -#define GCC_USB30_PRIM_MOCK_UTMI_CLK 145 -#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 146 -#define GCC_USB30_PRIM_SLEEP_CLK 147 -#define GCC_USB30_SEC_MASTER_CLK 148 -#define GCC_USB30_SEC_MASTER_CLK_SRC 149 -#define GCC_USB30_SEC_MOCK_UTMI_CLK 150 -#define GCC_USB30_SEC_MOCK_UTMI_CLK_SRC 151 -#define GCC_USB30_SEC_SLEEP_CLK 152 -#define GCC_USB3_PRIM_CLKREF_CLK 153 -#define GCC_USB3_PRIM_PHY_AUX_CLK 154 -#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 155 -#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 156 -#define GCC_USB3_PRIM_PHY_PIPE_CLK 157 -#define GCC_USB3_SEC_CLKREF_CLK 158 -#define GCC_USB3_SEC_PHY_AUX_CLK 159 -#define GCC_USB3_SEC_PHY_AUX_CLK_SRC 160 -#define GCC_USB3_SEC_PHY_COM_AUX_CLK 161 -#define GCC_USB3_SEC_PHY_PIPE_CLK 162 -#define GCC_USB_PHY_CFG_AHB2PHY_CLK 163 -#define GCC_VIDEO_AHB_CLK 164 -#define GCC_VIDEO_AXI_CLK 165 -#define GCC_VIDEO_XO_CLK 166 -#define GPLL0 167 -#define GPLL0_OUT_EVEN 168 -#define GPLL0_OUT_MAIN 169 -#define GCC_UFS_CARD_AXI_HW_CTL_CLK 170 -#define GCC_UFS_PHY_AXI_HW_CTL_CLK 171 -#define GCC_UFS_CARD_UNIPRO_CORE_HW_CTL_CLK 172 -#define GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK 173 -#define GCC_UFS_CARD_ICE_CORE_HW_CTL_CLK 174 -#define GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK 175 -#define GCC_AGGRE_UFS_CARD_AXI_HW_CTL_CLK 176 -#define GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK 177 -#define GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK 178 -#define GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK 179 -#define GCC_GPU_IREF_CLK 180 -#define GCC_SDCC1_AHB_CLK 181 -#define GCC_SDCC1_APPS_CLK 182 -#define GCC_SDCC1_ICE_CORE_CLK 183 -#define GCC_SDCC1_APPS_CLK_SRC 184 -#define GCC_SDCC1_ICE_CORE_CLK_SRC 185 -#define GCC_APC_VS_CLK 186 -#define GCC_GPU_VS_CLK 187 -#define GCC_MSS_VS_CLK 188 -#define GCC_VDDA_VS_CLK 189 -#define GCC_VDDCX_VS_CLK 190 -#define GCC_VDDMX_VS_CLK 191 -#define GCC_VS_CTRL_AHB_CLK 192 -#define GCC_VS_CTRL_CLK 193 -#define GCC_VS_CTRL_CLK_SRC 194 -#define GCC_VSENSOR_CLK_SRC 195 -#define GPLL4 196 -#define GPLL6 197 +#define GCC_AGGRE_NOC_PCIE_TBU_CLK 6 +#define GCC_AGGRE_UFS_CARD_AXI_CLK 7 +#define GCC_AGGRE_UFS_PHY_AXI_CLK 8 +#define GCC_AGGRE_USB3_PRIM_AXI_CLK 9 +#define GCC_AGGRE_USB3_SEC_AXI_CLK 10 +#define GCC_BOOT_ROM_AHB_CLK 11 +#define GCC_CAMERA_AHB_CLK 12 +#define GCC_CAMERA_AXI_CLK 13 +#define GCC_CAMERA_XO_CLK 14 +#define GCC_CE1_AHB_CLK 15 +#define GCC_CE1_AXI_CLK 16 +#define GCC_CE1_CLK 17 +#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 18 +#define GCC_CFG_NOC_USB3_SEC_AXI_CLK 19 +#define GCC_CPUSS_AHB_CLK 20 +#define GCC_CPUSS_AHB_CLK_SRC 21 +#define GCC_CPUSS_DVM_BUS_CLK 22 +#define GCC_CPUSS_GNOC_CLK 23 +#define GCC_CPUSS_RBCPR_CLK 24 +#define GCC_CPUSS_RBCPR_CLK_SRC 25 +#define GCC_DDRSS_GPU_AXI_CLK 26 +#define GCC_DISP_AHB_CLK 27 +#define GCC_DISP_AXI_CLK 28 +#define GCC_DISP_GPLL0_CLK_SRC 29 +#define GCC_DISP_GPLL0_DIV_CLK_SRC 30 +#define GCC_DISP_XO_CLK 31 +#define GCC_GP1_CLK 32 +#define GCC_GP1_CLK_SRC 33 +#define GCC_GP2_CLK 34 +#define GCC_GP2_CLK_SRC 35 +#define GCC_GP3_CLK 36 +#define GCC_GP3_CLK_SRC 37 +#define GCC_GPU_CFG_AHB_CLK 38 +#define GCC_GPU_GPLL0_CLK_SRC 39 +#define GCC_GPU_GPLL0_DIV_CLK_SRC 40 +#define GCC_GPU_MEMNOC_GFX_CLK 41 +#define GCC_GPU_SNOC_DVM_GFX_CLK 42 +#define GCC_MSS_AXIS2_CLK 43 +#define GCC_MSS_CFG_AHB_CLK 44 +#define GCC_MSS_GPLL0_DIV_CLK_SRC 45 +#define GCC_MSS_MFAB_AXIS_CLK 46 +#define GCC_MSS_Q6_MEMNOC_AXI_CLK 47 +#define GCC_MSS_SNOC_AXI_CLK 48 +#define GCC_PCIE_0_AUX_CLK 49 +#define GCC_PCIE_0_AUX_CLK_SRC 50 +#define GCC_PCIE_0_CFG_AHB_CLK 51 +#define GCC_PCIE_0_CLKREF_CLK 52 +#define GCC_PCIE_0_MSTR_AXI_CLK 53 +#define GCC_PCIE_0_PIPE_CLK 54 +#define GCC_PCIE_0_SLV_AXI_CLK 55 +#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 56 +#define GCC_PCIE_1_AUX_CLK 57 +#define GCC_PCIE_1_AUX_CLK_SRC 58 +#define GCC_PCIE_1_CFG_AHB_CLK 59 +#define GCC_PCIE_1_CLKREF_CLK 60 +#define GCC_PCIE_1_MSTR_AXI_CLK 61 +#define GCC_PCIE_1_PIPE_CLK 62 +#define GCC_PCIE_1_SLV_AXI_CLK 63 +#define GCC_PCIE_1_SLV_Q2A_AXI_CLK 64 +#define GCC_PCIE_PHY_AUX_CLK 65 +#define GCC_PCIE_PHY_REFGEN_CLK 66 +#define GCC_PCIE_PHY_REFGEN_CLK_SRC 67 +#define GCC_PDM2_CLK 68 +#define GCC_PDM2_CLK_SRC 69 +#define GCC_PDM_AHB_CLK 70 +#define GCC_PDM_XO4_CLK 71 +#define GCC_PRNG_AHB_CLK 72 +#define GCC_QMIP_CAMERA_AHB_CLK 73 +#define GCC_QMIP_DISP_AHB_CLK 74 +#define GCC_QMIP_VIDEO_AHB_CLK 75 +#define GCC_QUPV3_WRAP0_S0_CLK 76 +#define GCC_QUPV3_WRAP0_S0_CLK_SRC 77 +#define GCC_QUPV3_WRAP0_S1_CLK 78 +#define GCC_QUPV3_WRAP0_S1_CLK_SRC 79 +#define GCC_QUPV3_WRAP0_S2_CLK 80 +#define GCC_QUPV3_WRAP0_S2_CLK_SRC 81 +#define GCC_QUPV3_WRAP0_S3_CLK 82 +#define GCC_QUPV3_WRAP0_S3_CLK_SRC 83 +#define GCC_QUPV3_WRAP0_S4_CLK 84 +#define GCC_QUPV3_WRAP0_S4_CLK_SRC 85 +#define GCC_QUPV3_WRAP0_S5_CLK 86 +#define GCC_QUPV3_WRAP0_S5_CLK_SRC 87 +#define GCC_QUPV3_WRAP0_S6_CLK 88 +#define GCC_QUPV3_WRAP0_S6_CLK_SRC 89 +#define GCC_QUPV3_WRAP0_S7_CLK 90 +#define GCC_QUPV3_WRAP0_S7_CLK_SRC 91 +#define GCC_QUPV3_WRAP1_S0_CLK 92 +#define GCC_QUPV3_WRAP1_S0_CLK_SRC 93 +#define GCC_QUPV3_WRAP1_S1_CLK 94 +#define GCC_QUPV3_WRAP1_S1_CLK_SRC 95 +#define GCC_QUPV3_WRAP1_S2_CLK 96 +#define GCC_QUPV3_WRAP1_S2_CLK_SRC 97 +#define GCC_QUPV3_WRAP1_S3_CLK 98 +#define GCC_QUPV3_WRAP1_S3_CLK_SRC 99 +#define GCC_QUPV3_WRAP1_S4_CLK 100 +#define GCC_QUPV3_WRAP1_S4_CLK_SRC 101 +#define GCC_QUPV3_WRAP1_S5_CLK 102 +#define GCC_QUPV3_WRAP1_S5_CLK_SRC 103 +#define GCC_QUPV3_WRAP1_S6_CLK 104 +#define GCC_QUPV3_WRAP1_S6_CLK_SRC 105 +#define GCC_QUPV3_WRAP1_S7_CLK 106 +#define GCC_QUPV3_WRAP1_S7_CLK_SRC 107 +#define GCC_QUPV3_WRAP_0_M_AHB_CLK 108 +#define GCC_QUPV3_WRAP_0_S_AHB_CLK 109 +#define GCC_QUPV3_WRAP_1_M_AHB_CLK 110 +#define GCC_QUPV3_WRAP_1_S_AHB_CLK 111 +#define GCC_SDCC2_AHB_CLK 112 +#define GCC_SDCC2_APPS_CLK 113 +#define GCC_SDCC2_APPS_CLK_SRC 114 +#define GCC_SDCC4_AHB_CLK 115 +#define GCC_SDCC4_APPS_CLK 116 +#define GCC_SDCC4_APPS_CLK_SRC 117 +#define GCC_SYS_NOC_CPUSS_AHB_CLK 118 +#define GCC_TSIF_AHB_CLK 119 +#define GCC_TSIF_INACTIVITY_TIMERS_CLK 120 +#define GCC_TSIF_REF_CLK 121 +#define GCC_TSIF_REF_CLK_SRC 122 +#define GCC_UFS_CARD_AHB_CLK 123 +#define GCC_UFS_CARD_AXI_CLK 124 +#define GCC_UFS_CARD_AXI_CLK_SRC 125 +#define GCC_UFS_CARD_CLKREF_CLK 126 +#define GCC_UFS_CARD_ICE_CORE_CLK 127 +#define GCC_UFS_CARD_ICE_CORE_CLK_SRC 128 +#define GCC_UFS_CARD_PHY_AUX_CLK 129 +#define GCC_UFS_CARD_PHY_AUX_CLK_SRC 130 +#define GCC_UFS_CARD_RX_SYMBOL_0_CLK 131 +#define GCC_UFS_CARD_RX_SYMBOL_1_CLK 132 +#define GCC_UFS_CARD_TX_SYMBOL_0_CLK 133 +#define GCC_UFS_CARD_UNIPRO_CORE_CLK 134 +#define GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC 135 +#define GCC_UFS_MEM_CLKREF_CLK 136 +#define GCC_UFS_PHY_AHB_CLK 137 +#define GCC_UFS_PHY_AXI_CLK 138 +#define GCC_UFS_PHY_AXI_CLK_SRC 139 +#define GCC_UFS_PHY_ICE_CORE_CLK 140 +#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 141 +#define GCC_UFS_PHY_PHY_AUX_CLK 142 +#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 143 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 144 +#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 145 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 146 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK 147 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 148 +#define GCC_USB30_PRIM_MASTER_CLK 149 +#define GCC_USB30_PRIM_MASTER_CLK_SRC 150 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK 151 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 152 +#define GCC_USB30_PRIM_SLEEP_CLK 153 +#define GCC_USB30_SEC_MASTER_CLK 154 +#define GCC_USB30_SEC_MASTER_CLK_SRC 155 +#define GCC_USB30_SEC_MOCK_UTMI_CLK 156 +#define GCC_USB30_SEC_MOCK_UTMI_CLK_SRC 157 +#define GCC_USB30_SEC_SLEEP_CLK 158 +#define GCC_USB3_PRIM_CLKREF_CLK 159 +#define GCC_USB3_PRIM_PHY_AUX_CLK 160 +#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 161 +#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 162 +#define GCC_USB3_PRIM_PHY_PIPE_CLK 163 +#define GCC_USB3_SEC_CLKREF_CLK 164 +#define GCC_USB3_SEC_PHY_AUX_CLK 165 +#define GCC_USB3_SEC_PHY_AUX_CLK_SRC 166 +#define GCC_USB3_SEC_PHY_COM_AUX_CLK 167 +#define GCC_USB3_SEC_PHY_PIPE_CLK 168 +#define GCC_USB_PHY_CFG_AHB2PHY_CLK 169 +#define GCC_VIDEO_AHB_CLK 170 +#define GCC_VIDEO_AXI_CLK 171 +#define GCC_VIDEO_XO_CLK 172 +#define GPLL0 173 +#define GPLL0_OUT_EVEN 174 +#define GPLL0_OUT_MAIN 175 +#define GCC_UFS_CARD_AXI_HW_CTL_CLK 176 +#define GCC_UFS_PHY_AXI_HW_CTL_CLK 177 +#define GCC_UFS_CARD_UNIPRO_CORE_HW_CTL_CLK 178 +#define GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK 179 +#define GCC_UFS_CARD_ICE_CORE_HW_CTL_CLK 180 +#define GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK 181 +#define GCC_AGGRE_UFS_CARD_AXI_HW_CTL_CLK 182 +#define GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK 183 +#define GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK 184 +#define GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK 185 +#define GCC_GPU_IREF_CLK 186 +#define GCC_SDCC1_AHB_CLK 187 +#define GCC_SDCC1_APPS_CLK 188 +#define GCC_SDCC1_ICE_CORE_CLK 189 +#define GCC_SDCC1_APPS_CLK_SRC 190 +#define GCC_SDCC1_ICE_CORE_CLK_SRC 191 +#define GCC_APC_VS_CLK 192 +#define GCC_GPU_VS_CLK 193 +#define GCC_MSS_VS_CLK 194 +#define GCC_VDDA_VS_CLK 195 +#define GCC_VDDCX_VS_CLK 196 +#define GCC_VDDMX_VS_CLK 197 +#define GCC_VS_CTRL_AHB_CLK 198 +#define GCC_VS_CTRL_CLK 199 +#define GCC_VS_CTRL_CLK_SRC 200 +#define GCC_VSENSOR_CLK_SRC 201 +#define GPLL4 202 +#define GPLL6 203 /* GCC reset clocks */ #define GCC_MMSS_BCR 0 @@ -243,10 +251,4 @@ #define GCC_PCIE_1_PHY_BCR 25 #define GCC_SDCC1_BCR 26 -/* Dummy clocks for rate measurement */ -#define MEASURE_ONLY_SNOC_CLK 0 -#define MEASURE_ONLY_CNOC_CLK 1 -#define MEASURE_ONLY_BIMC_CLK 2 -#define MEASURE_ONLY_IPA_2X_CLK 3 - #endif -- GitLab From 2cfb5b5bf27ea226ca152ebc8e7f1041581882b9 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Wed, 6 Jun 2018 17:22:22 +0530 Subject: [PATCH 734/855] clk: msm: Change the driver init level to late_initcall_sync Change the cpu driver init level to late_initcall_sync so that cpu driver is initialized after lpm driver is probed. Change-Id: Ic4e2273b281d7a13eedba99650c0ef967d19401d Signed-off-by: Odelu Kukatla --- drivers/clk/msm/clock-cpu-8939.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/msm/clock-cpu-8939.c b/drivers/clk/msm/clock-cpu-8939.c index 5ba6bd07957f..5b8b8f3fe7bb 100644 --- a/drivers/clk/msm/clock-cpu-8939.c +++ b/drivers/clk/msm/clock-cpu-8939.c @@ -999,7 +999,7 @@ static int __init clock_cpu_lpm_get_latency(void) return rc; } -late_initcall(clock_cpu_lpm_get_latency); +late_initcall_sync(clock_cpu_lpm_get_latency); #define APCS_C0_PLL 0xb116000 #define C0_PLL_MODE 0x0 -- GitLab From 9a2eb4b6edab1e19992c9a14cc221a4174d6e9c9 Mon Sep 17 00:00:00 2001 From: Venkatesh Yadav Abbarapu Date: Mon, 28 May 2018 21:30:35 +0530 Subject: [PATCH 735/855] msm: platsmp: snapshot of the smp ops Add smp related files like platsmp, headsmp and hotplug. Copied from the below caf link https://www.codeaurora.org/cgit/quic/la/kernel/msm-3.18/ tree/arch/arm/mach-msm?h=caf/3.10/msm-3.10 &id=5724b421fc2db7413048fe5b18135d481d68597a Change-Id: I20560df247c9adacdbb92711fd0945d0ae9c7e08 Signed-off-by: Venkatesh Yadav Abbarapu Git-commit: 0fe30edd5c4a0a3a3506e565946ab13f716cadda Git-repo: https://source.codeaurora.org/quic/la/kernel/msm-4.9 [sundvi@codeaurora.org: using only hotplug source change] Signed-off-by: Sundara Vinayagam Signed-off-by: Chinkit Kumar,Kirti Kumar Parmar --- arch/arm/mach-qcom/hotplug.c | 148 +++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 arch/arm/mach-qcom/hotplug.c diff --git a/arch/arm/mach-qcom/hotplug.c b/arch/arm/mach-qcom/hotplug.c new file mode 100644 index 000000000000..d5505e572bb0 --- /dev/null +++ b/arch/arm/mach-qcom/hotplug.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * Copyright (c) 2011-2014, 2016, 2018, The Linux Foundation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +static cpumask_t cpu_dying_mask; + +static DEFINE_PER_CPU(unsigned int, warm_boot_flag); + +static inline void cpu_enter_lowpower(void) +{ +} + +static inline void cpu_leave_lowpower(void) +{ +} + +static inline void platform_do_lowpower(unsigned int cpu, int *spurious) +{ + /* Just enter wfi for now. TODO: Properly shut off the cpu. */ + for (;;) { + + lpm_cpu_hotplug_enter(cpu); + if (pen_release == cpu_logical_map(cpu)) { + /* + * OK, proper wakeup, we're done + */ + break; + } + + /* + * getting here, means that we have come out of WFI without + * having been woken up - this shouldn't happen + * + * The trouble is, letting people know about this is not really + * possible, since we are currently running incoherently, and + * therefore cannot safely call printk() or anything else + * Read the pending interrupts to understand why we woke up + */ +#ifdef CONFIG_MSM_PM + gic_show_pending_irq(); +#endif + (*spurious)++; + } +} + +int msm_cpu_kill(unsigned int cpu) +{ + int ret = 0; + + if (cpumask_test_and_clear_cpu(cpu, &cpu_dying_mask)) + ret = msm_pm_wait_cpu_shutdown(cpu); + + return ret ? 0 : 1; +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void __ref msm_cpu_die(unsigned int cpu) +{ + int spurious = 0; + + if (unlikely(cpu != smp_processor_id())) { + pr_crit("%s: running on %u, should be %u\n", + __func__, smp_processor_id(), cpu); + WARN_ON(cpu); + } + /* + * we're ready for shutdown now, so do it + */ + cpu_enter_lowpower(); + platform_do_lowpower(cpu, &spurious); + + pr_debug("CPU%u: %s: normal wakeup\n", cpu, __func__); + cpu_leave_lowpower(); + + if (spurious) + pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); +} + +static int hotplug_dying_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + switch (action & (~CPU_TASKS_FROZEN)) { + case CPU_DYING: + cpumask_set_cpu((unsigned long)hcpu, &cpu_dying_mask); + break; + default: + break; + } + + return NOTIFY_OK; +} +static struct notifier_block hotplug_dying_notifier = { + .notifier_call = hotplug_dying_callback, +}; + +int msm_platform_secondary_init(unsigned int cpu) +{ + int ret; + unsigned int *warm_boot = &__get_cpu_var(warm_boot_flag); + + if (!(*warm_boot)) { + *warm_boot = 1; + /* + * All CPU0 boots are considered warm boots (restore needed) + * since CPU0 is the system boot CPU and never cold-booted + * by the kernel. + */ + if (cpu) + return 0; + } + msm_jtag_restore_state(); +#if defined(CONFIG_VFP) && defined(CONFIG_CPU_PM) + vfp_pm_resume(); +#endif + ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false); + + return ret; +} + +static int __init init_hotplug_dying(void) +{ + return register_hotcpu_notifier(&hotplug_dying_notifier); +} +early_initcall(init_hotplug_dying); -- GitLab From f936802626f061e2ca731cd1f768b4f65b19c7f3 Mon Sep 17 00:00:00 2001 From: Raja Mallik Date: Sat, 21 Apr 2018 14:14:55 +0530 Subject: [PATCH 736/855] ARM: qcom: Add MSM Legacy hotplug low power mode APIs Add low power mode support for hotplug CPUs. Remove pen release logic, forloop & gic pending irqs print from legacy hotplug code. Remove vfp_resume call as current vfp module has pm notifiers. Add 'cpu_can_disable' smp callback to enable hotplug support for bootcore CPU Change-Id: Ic830bbea1260c34bd383d7c07e2c6fef05677ded Signed-off-by: Chinkit Kumar,Kirti Kumar Parmar --- arch/arm/mach-qcom/Makefile | 1 + arch/arm/mach-qcom/hotplug.c | 87 ++++++++++-------------------------- arch/arm/mach-qcom/platsmp.c | 17 +++++++ include/soc/qcom/pm-legacy.h | 4 ++ 4 files changed, 46 insertions(+), 63 deletions(-) diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile index 5b93fa335ab2..2f26f392741e 100644 --- a/arch/arm/mach-qcom/Makefile +++ b/arch/arm/mach-qcom/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_USE_OF) += board-dt.o obj-$(CONFIG_SMP) += platsmp.o +obj-$(CONFIG_MSM_PM_LEGACY) +=hotplug.o obj-$(CONFIG_ARCH_SDXPOORWILLS) += board-poorwills.o obj-$(CONFIG_ARCH_MSM8953) += board-msm8953.o obj-$(CONFIG_ARCH_MSM8937) += board-msm8937.o diff --git a/arch/arm/mach-qcom/hotplug.c b/arch/arm/mach-qcom/hotplug.c index d5505e572bb0..c038f4be115a 100644 --- a/arch/arm/mach-qcom/hotplug.c +++ b/arch/arm/mach-qcom/hotplug.c @@ -12,18 +12,13 @@ #include #include #include -#include #include -#include -#include - +#include #include -#include - +#include "platsmp.h" #include static cpumask_t cpu_dying_mask; - static DEFINE_PER_CPU(unsigned int, warm_boot_flag); static inline void cpu_enter_lowpower(void) @@ -34,36 +29,18 @@ static inline void cpu_leave_lowpower(void) { } -static inline void platform_do_lowpower(unsigned int cpu, int *spurious) +static inline void platform_do_lowpower(unsigned int cpu) { - /* Just enter wfi for now. TODO: Properly shut off the cpu. */ - for (;;) { - - lpm_cpu_hotplug_enter(cpu); - if (pen_release == cpu_logical_map(cpu)) { - /* - * OK, proper wakeup, we're done - */ - break; - } - - /* - * getting here, means that we have come out of WFI without - * having been woken up - this shouldn't happen - * - * The trouble is, letting people know about this is not really - * possible, since we are currently running incoherently, and - * therefore cannot safely call printk() or anything else - * Read the pending interrupts to understand why we woke up - */ -#ifdef CONFIG_MSM_PM - gic_show_pending_irq(); -#endif - (*spurious)++; - } + lpm_cpu_hotplug_enter(cpu); + /* + * getting here, means that we have come out of low power mode + * without having been woken up - this shouldn't happen + * + */ + pr_err("%s: CPU%u has failed to Hotplug\n", __func__, cpu); } -int msm_cpu_kill(unsigned int cpu) +int qcom_cpu_kill_legacy(unsigned int cpu) { int ret = 0; @@ -78,10 +55,8 @@ int msm_cpu_kill(unsigned int cpu) * * Called with IRQs disabled */ -void __ref msm_cpu_die(unsigned int cpu) +void __ref qcom_cpu_die_legacy(unsigned int cpu) { - int spurious = 0; - if (unlikely(cpu != smp_processor_id())) { pr_crit("%s: running on %u, should be %u\n", __func__, smp_processor_id(), cpu); @@ -91,36 +66,16 @@ void __ref msm_cpu_die(unsigned int cpu) * we're ready for shutdown now, so do it */ cpu_enter_lowpower(); - platform_do_lowpower(cpu, &spurious); + platform_do_lowpower(cpu); pr_debug("CPU%u: %s: normal wakeup\n", cpu, __func__); cpu_leave_lowpower(); - - if (spurious) - pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); -} - -static int hotplug_dying_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - switch (action & (~CPU_TASKS_FROZEN)) { - case CPU_DYING: - cpumask_set_cpu((unsigned long)hcpu, &cpu_dying_mask); - break; - default: - break; - } - - return NOTIFY_OK; } -static struct notifier_block hotplug_dying_notifier = { - .notifier_call = hotplug_dying_callback, -}; int msm_platform_secondary_init(unsigned int cpu) { int ret; - unsigned int *warm_boot = &__get_cpu_var(warm_boot_flag); + unsigned int *warm_boot = this_cpu_ptr(&warm_boot_flag); if (!(*warm_boot)) { *warm_boot = 1; @@ -133,16 +88,22 @@ int msm_platform_secondary_init(unsigned int cpu) return 0; } msm_jtag_restore_state(); -#if defined(CONFIG_VFP) && defined(CONFIG_CPU_PM) - vfp_pm_resume(); -#endif ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false); return ret; } +static int hotplug_dying_cpu(unsigned int cpu) +{ + cpumask_set_cpu(cpu, &cpu_dying_mask); + return 0; +} + static int __init init_hotplug_dying(void) { - return register_hotcpu_notifier(&hotplug_dying_notifier); + cpuhp_setup_state(CPUHP_AP_QCOM_SLEEP_STARTING, + "AP_QCOM_HOTPLUG_STARTING", NULL, hotplug_dying_cpu); + + return 0; } early_initcall(init_hotplug_dying); diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c index c422ac3e6544..803804d64231 100644 --- a/arch/arm/mach-qcom/platsmp.c +++ b/arch/arm/mach-qcom/platsmp.c @@ -22,6 +22,9 @@ #include #include #include "platsmp.h" +#ifdef CONFIG_MSM_PM_LEGACY +#include +#endif #define MSM_APCS_IDR 0x0B011030 @@ -62,10 +65,18 @@ static void qcom_cpu_die(unsigned int cpu) { wfi(); } + +static bool qcom_cpu_can_disable(unsigned int cpu) +{ + return true; /*Hotplug of any CPU is supported */ +} #endif static void qcom_secondary_init(unsigned int cpu) { +#ifdef CONFIG_MSM_PM_LEGACY + WARN_ON(msm_platform_secondary_init(cpu)); +#endif /* * Synchronise with the boot thread. */ @@ -472,7 +483,13 @@ struct smp_operations msm8909_smp_ops __initdata = { .smp_secondary_init = qcom_secondary_init, .smp_boot_secondary = msm8909_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU +#ifdef CONFIG_MSM_PM_LEGACY + .cpu_die = qcom_cpu_die_legacy, + .cpu_kill = qcom_cpu_kill_legacy, +#else .cpu_die = qcom_cpu_die, +#endif + .cpu_can_disable = qcom_cpu_can_disable, #endif }; diff --git a/include/soc/qcom/pm-legacy.h b/include/soc/qcom/pm-legacy.h index 7fdb0cdc4cb5..0ae5d7b3a4d9 100644 --- a/include/soc/qcom/pm-legacy.h +++ b/include/soc/qcom/pm-legacy.h @@ -179,9 +179,13 @@ static inline int lpm_get_latency(struct latency_level *level, #endif #ifdef CONFIG_HOTPLUG_CPU +void qcom_cpu_die_legacy(unsigned int cpu); +int qcom_cpu_kill_legacy(unsigned int cpu); int msm_platform_secondary_init(unsigned int cpu); #else static inline int msm_platform_secondary_init(unsigned int cpu) { return 0; } +static inline void qcom_cpu_die_legacy(unsigned int cpu) {} +static inline int qcom_cpu_kill_legacy(unsigned int cpu) { return 0; } #endif enum msm_pm_time_stats_id { -- GitLab From 90792c070cdf46024da3324865bf47cfc44d1003 Mon Sep 17 00:00:00 2001 From: Vamshi Krishna B V Date: Mon, 28 May 2018 22:47:06 +0530 Subject: [PATCH 737/855] power: fg-alg: Add support for TTF and TTE calculation Add support for Time to full (TTF) and Time to empty (TTE) calculations in fg-alg.c that can be used by FG and QG drivers. CRs-Fixed: 2254530 Change-Id: I28e21da30911a8d879f176ae3ff8736aed807020 Signed-off-by: Vamshi Krishna B V --- drivers/power/supply/qcom/fg-alg.c | 531 +++++++++++++++++++++++++++++ drivers/power/supply/qcom/fg-alg.h | 57 ++++ 2 files changed, 588 insertions(+) diff --git a/drivers/power/supply/qcom/fg-alg.c b/drivers/power/supply/qcom/fg-alg.c index 129af7b51236..4003679a345d 100644 --- a/drivers/power/supply/qcom/fg-alg.c +++ b/drivers/power/supply/qcom/fg-alg.c @@ -16,12 +16,38 @@ #include #include #include +#include +#include #include "fg-alg.h" #define FULL_SOC_RAW 255 #define FULL_BATT_SOC GENMASK(31, 0) #define CAPACITY_DELTA_DECIPCT 500 +#define CENTI_ICORRECT_C0 105 +#define CENTI_ICORRECT_C1 20 + +#define HOURS_TO_SECONDS 3600 +#define OCV_SLOPE_UV 10869 +#define MILLI_UNIT 1000 +#define MICRO_UNIT 1000000 +#define NANO_UNIT 1000000000 + +#define DEFAULT_TTF_RUN_PERIOD_MS 10000 +#define DEFAULT_TTF_ITERM_DELTA_MA 200 + +static const struct ttf_pt ttf_ln_table[] = { + { 1000, 0 }, + { 2000, 693 }, + { 4000, 1386 }, + { 6000, 1792 }, + { 8000, 2079 }, + { 16000, 2773 }, + { 32000, 3466 }, + { 64000, 4159 }, + { 128000, 4852 }, +}; + /* Cycle counter APIs */ /** @@ -670,3 +696,508 @@ int cap_learning_init(struct cap_learning *cl) mutex_init(&cl->lock); return 0; } + +/* Time to full/empty algorithm helper functions */ + +static void ttf_circ_buf_add(struct ttf_circ_buf *buf, int val) +{ + buf->arr[buf->head] = val; + buf->head = (buf->head + 1) % ARRAY_SIZE(buf->arr); + buf->size = min(++buf->size, (int)ARRAY_SIZE(buf->arr)); +} + +static void ttf_circ_buf_clr(struct ttf_circ_buf *buf) +{ + buf->size = 0; + buf->head = 0; + memset(buf->arr, 0, sizeof(buf->arr)); +} + +static int cmp_int(const void *a, const void *b) +{ + return *(int *)a - *(int *)b; +} + +static int ttf_circ_buf_median(struct ttf_circ_buf *buf, int *median) +{ + int *temp; + + if (buf->size == 0) + return -ENODATA; + + if (buf->size == 1) { + *median = buf->arr[0]; + return 0; + } + + temp = kmalloc_array(buf->size, sizeof(*temp), GFP_KERNEL); + if (!temp) + return -ENOMEM; + + memcpy(temp, buf->arr, buf->size * sizeof(*temp)); + sort(temp, buf->size, sizeof(*temp), cmp_int, NULL); + + if (buf->size % 2) + *median = temp[buf->size / 2]; + else + *median = (temp[buf->size / 2 - 1] + temp[buf->size / 2]) / 2; + + kfree(temp); + return 0; +} + +static int ttf_lerp(const struct ttf_pt *pts, size_t tablesize, + s32 input, s32 *output) +{ + int i; + s64 temp; + + if (pts == NULL) { + pr_err("Table is NULL\n"); + return -EINVAL; + } + + if (tablesize < 1) { + pr_err("Table has no entries\n"); + return -ENOENT; + } + + if (tablesize == 1) { + *output = pts[0].y; + return 0; + } + + if (pts[0].x > pts[1].x) { + pr_err("Table is not in acending order\n"); + return -EINVAL; + } + + if (input <= pts[0].x) { + *output = pts[0].y; + return 0; + } + + if (input >= pts[tablesize - 1].x) { + *output = pts[tablesize - 1].y; + return 0; + } + + for (i = 1; i < tablesize; i++) { + if (input >= pts[i].x) + continue; + + temp = ((s64)pts[i].y - pts[i - 1].y) * + ((s64)input - pts[i - 1].x); + temp = div_s64(temp, pts[i].x - pts[i - 1].x); + *output = temp + pts[i - 1].y; + return 0; + } + + return -EINVAL; +} + +static int get_time_to_full_locked(struct ttf *ttf, int *val) +{ + int rc, ibatt_avg, vbatt_avg, rbatt = 0, msoc = 0, act_cap_mah = 0, + i_cc2cv = 0, soc_cc2cv, tau, divisor, iterm = 0, ttf_mode = 0, + i, soc_per_step, msoc_this_step, msoc_next_step, + ibatt_this_step, t_predicted_this_step, ttf_slope, + t_predicted_cv, t_predicted = 0, charge_type = 0, + float_volt_uv = 0; + s64 delta_ms; + + rc = ttf->get_ttf_param(ttf->data, TTF_MSOC, &msoc); + if (rc < 0) { + pr_err("failed to get msoc rc=%d\n", rc); + return rc; + } + pr_debug("TTF: msoc=%d\n", msoc); + + /* the battery is considered full if the SOC is 100% */ + if (msoc >= 100) { + *val = 0; + return 0; + } + + rc = ttf->get_ttf_param(ttf->data, TTF_MODE, &ttf_mode); + + /* when switching TTF algorithms the TTF needs to be reset */ + if (ttf->mode != ttf_mode) { + ttf_circ_buf_clr(&ttf->ibatt); + ttf_circ_buf_clr(&ttf->vbatt); + ttf->last_ttf = 0; + ttf->last_ms = 0; + ttf->mode = ttf_mode; + } + + /* at least 10 samples are required to produce a stable IBATT */ + if (ttf->ibatt.size < MAX_TTF_SAMPLES) { + *val = -1; + return 0; + } + + rc = ttf_circ_buf_median(&ttf->ibatt, &ibatt_avg); + if (rc < 0) { + pr_err("failed to get IBATT AVG rc=%d\n", rc); + return rc; + } + + rc = ttf_circ_buf_median(&ttf->vbatt, &vbatt_avg); + if (rc < 0) { + pr_err("failed to get VBATT AVG rc=%d\n", rc); + return rc; + } + + ibatt_avg = -ibatt_avg / MILLI_UNIT; + vbatt_avg /= MILLI_UNIT; + + rc = ttf->get_ttf_param(ttf->data, TTF_ITERM, &iterm); + if (rc < 0) { + pr_err("failed to get iterm rc=%d\n", rc); + return rc; + } + /* clamp ibatt_avg to iterm */ + if (ibatt_avg < abs(iterm)) + ibatt_avg = abs(iterm); + + rc = ttf->get_ttf_param(ttf->data, TTF_RBATT, &rbatt); + if (rc < 0) { + pr_err("failed to get battery resistance rc=%d\n", rc); + return rc; + } + rbatt /= MILLI_UNIT; + + rc = ttf->get_ttf_param(ttf->data, TTF_FCC, &act_cap_mah); + if (rc < 0) { + pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc); + return rc; + } + + pr_debug(" TTF: ibatt_avg=%d vbatt_avg=%d rbatt=%d act_cap_mah=%d\n", + ibatt_avg, vbatt_avg, rbatt, act_cap_mah); + + rc = ttf->get_ttf_param(ttf->data, TTF_VFLOAT, &float_volt_uv); + if (rc < 0) { + pr_err("failed to get float_volt_uv rc=%d\n", rc); + return rc; + } + + rc = ttf->get_ttf_param(ttf->data, TTF_CHG_TYPE, &charge_type); + if (rc < 0) { + pr_err("failed to get charge_type rc=%d\n", rc); + return rc; + } + /* estimated battery current at the CC to CV transition */ + switch (ttf->mode) { + case TTF_MODE_NORMAL: + i_cc2cv = ibatt_avg * vbatt_avg / + max(MILLI_UNIT, float_volt_uv / MILLI_UNIT); + break; + case TTF_MODE_QNOVO: + i_cc2cv = min( + ttf->cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT, + ibatt_avg * vbatt_avg / + max(MILLI_UNIT, float_volt_uv / MILLI_UNIT)); + break; + default: + pr_err("TTF mode %d is not supported\n", ttf->mode); + break; + } + pr_debug("TTF: i_cc2cv=%d\n", i_cc2cv); + + /* if we are already in CV state then we can skip estimating CC */ + if (charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER) + goto cv_estimate; + + /* estimated SOC at the CC to CV transition */ + soc_cc2cv = DIV_ROUND_CLOSEST(rbatt * i_cc2cv, OCV_SLOPE_UV); + soc_cc2cv = 100 - soc_cc2cv; + pr_debug("TTF: soc_cc2cv=%d\n", soc_cc2cv); + + switch (ttf->mode) { + case TTF_MODE_NORMAL: + if (soc_cc2cv - msoc <= 0) + goto cv_estimate; + + divisor = max(100, (ibatt_avg + i_cc2cv) / 2 * 100); + t_predicted = div_s64((s64)act_cap_mah * (soc_cc2cv - msoc) * + HOURS_TO_SECONDS, divisor); + break; + case TTF_MODE_QNOVO: + soc_per_step = 100 / MAX_CC_STEPS; + for (i = msoc / soc_per_step; i < MAX_CC_STEPS - 1; ++i) { + msoc_next_step = (i + 1) * soc_per_step; + if (i == msoc / soc_per_step) + msoc_this_step = msoc; + else + msoc_this_step = i * soc_per_step; + + /* scale ibatt by 85% to account for discharge pulses */ + ibatt_this_step = min( + ttf->cc_step.arr[i] / MILLI_UNIT, + ibatt_avg) * 85 / 100; + divisor = max(100, ibatt_this_step * 100); + t_predicted_this_step = div_s64((s64)act_cap_mah * + (msoc_next_step - msoc_this_step) * + HOURS_TO_SECONDS, divisor); + t_predicted += t_predicted_this_step; + pr_debug("TTF: [%d, %d] ma=%d t=%d\n", + msoc_this_step, msoc_next_step, + ibatt_this_step, t_predicted_this_step); + } + break; + default: + pr_err("TTF mode %d is not supported\n", ttf->mode); + break; + } + +cv_estimate: + pr_debug("TTF: t_predicted_cc=%d\n", t_predicted); + + iterm = max(100, abs(iterm) + ttf->iterm_delta); + pr_debug("TTF: iterm=%d\n", iterm); + + if (charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER) + tau = max(MILLI_UNIT, ibatt_avg * MILLI_UNIT / iterm); + else + tau = max(MILLI_UNIT, i_cc2cv * MILLI_UNIT / iterm); + + rc = ttf_lerp(ttf_ln_table, ARRAY_SIZE(ttf_ln_table), tau, &tau); + if (rc < 0) { + pr_err("failed to interpolate tau rc=%d\n", rc); + return rc; + } + + /* tau is scaled linearly from 95% to 100% SOC */ + if (msoc >= 95) + tau = tau * 2 * (100 - msoc) / 10; + + pr_debug("TTF: tau=%d\n", tau); + t_predicted_cv = div_s64((s64)act_cap_mah * rbatt * tau * + HOURS_TO_SECONDS, NANO_UNIT); + pr_debug("TTF: t_predicted_cv=%d\n", t_predicted_cv); + t_predicted += t_predicted_cv; + + pr_debug("TTF: t_predicted_prefilter=%d\n", t_predicted); + if (ttf->last_ms != 0) { + delta_ms = ktime_ms_delta(ktime_get_boottime(), + ms_to_ktime(ttf->last_ms)); + if (delta_ms > 10000) { + ttf_slope = div64_s64( + ((s64)t_predicted - ttf->last_ttf) * + MICRO_UNIT, delta_ms); + if (ttf_slope > -100) + ttf_slope = -100; + else if (ttf_slope < -2000) + ttf_slope = -2000; + + t_predicted = div_s64( + (s64)ttf_slope * delta_ms, MICRO_UNIT) + + ttf->last_ttf; + pr_debug("TTF: ttf_slope=%d\n", ttf_slope); + } else { + t_predicted = ttf->last_ttf; + } + } + + /* clamp the ttf to 0 */ + if (t_predicted < 0) + t_predicted = 0; + + pr_debug("TTF: t_predicted_postfilter=%d\n", t_predicted); + *val = t_predicted; + return 0; +} + +/** + * ttf_get_time_to_full - + * @ttf: ttf object + * @val: Average time to full returned to the caller + * + * Get Average time to full the battery based on current soc, rbatt + * battery voltage and charge current etc. + */ +int ttf_get_time_to_full(struct ttf *ttf, int *val) +{ + int rc; + + mutex_lock(&ttf->lock); + rc = get_time_to_full_locked(ttf, val); + mutex_unlock(&ttf->lock); + + return rc; +} + +static void ttf_work(struct work_struct *work) +{ + struct ttf *ttf = container_of(work, + struct ttf, ttf_work.work); + int rc, ibatt_now, vbatt_now, ttf_now, charge_status; + ktime_t ktime_now; + + mutex_lock(&ttf->lock); + rc = ttf->get_ttf_param(ttf->data, TTF_CHG_STATUS, &charge_status); + if (rc < 0) { + pr_err("failed to get charge_status rc=%d\n", rc); + goto end_work; + } + if (charge_status != POWER_SUPPLY_STATUS_CHARGING && + charge_status != POWER_SUPPLY_STATUS_DISCHARGING) + goto end_work; + + rc = ttf->get_ttf_param(ttf->data, TTF_IBAT, &ibatt_now); + if (rc < 0) { + pr_err("failed to get battery current, rc=%d\n", rc); + goto end_work; + } + + rc = ttf->get_ttf_param(ttf->data, TTF_VBAT, &vbatt_now); + if (rc < 0) { + pr_err("failed to get battery voltage, rc=%d\n", rc); + goto end_work; + } + + ttf_circ_buf_add(&ttf->ibatt, ibatt_now); + ttf_circ_buf_add(&ttf->vbatt, vbatt_now); + + if (charge_status == POWER_SUPPLY_STATUS_CHARGING) { + rc = get_time_to_full_locked(ttf, &ttf_now); + if (rc < 0) { + pr_err("failed to get ttf, rc=%d\n", rc); + goto end_work; + } + + /* keep the wake lock and prime the IBATT and VBATT buffers */ + if (ttf_now < 0) { + /* delay for one FG cycle */ + schedule_delayed_work(&ttf->ttf_work, + msecs_to_jiffies(1000)); + mutex_unlock(&ttf->lock); + return; + } + + /* update the TTF reference point every minute */ + ktime_now = ktime_get_boottime(); + if (ktime_ms_delta(ktime_now, + ms_to_ktime(ttf->last_ms)) > 60000 || + ttf->last_ms == 0) { + ttf->last_ttf = ttf_now; + ttf->last_ms = ktime_to_ms(ktime_now); + } + } + + /* recurse every 10 seconds */ + schedule_delayed_work(&ttf->ttf_work, msecs_to_jiffies(ttf->period_ms)); +end_work: + ttf->awake_voter(ttf->data, false); + mutex_unlock(&ttf->lock); +} + +/** + * ttf_get_time_to_empty - + * @ttf: ttf object + * @val: Average time to empty returned to the caller + * + * Get Average time to empty the battery based on current soc + * and average battery current. + */ +int ttf_get_time_to_empty(struct ttf *ttf, int *val) +{ + int rc, ibatt_avg, msoc, act_cap_mah, divisor; + + rc = ttf_circ_buf_median(&ttf->ibatt, &ibatt_avg); + if (rc < 0) { + /* try to get instantaneous current */ + rc = ttf->get_ttf_param(ttf->data, TTF_IBAT, &ibatt_avg); + if (rc < 0) { + pr_err("failed to get battery current, rc=%d\n", rc); + return rc; + } + } + + ibatt_avg /= MILLI_UNIT; + /* clamp ibatt_avg to 100mA */ + if (ibatt_avg < 100) + ibatt_avg = 100; + + rc = ttf->get_ttf_param(ttf->data, TTF_MSOC, &msoc); + if (rc < 0) { + pr_err("Error in getting capacity, rc=%d\n", rc); + return rc; + } + + rc = ttf->get_ttf_param(ttf->data, TTF_FCC, &act_cap_mah); + if (rc < 0) { + pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc); + return rc; + } + + divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc; + divisor = ibatt_avg * divisor / 100; + divisor = max(100, divisor); + *val = act_cap_mah * msoc * HOURS_TO_SECONDS / divisor; + return 0; +} + +/** + * ttf_update - + * @ttf: ttf object + * @input_present: Indicator for input presence + * + * Called by FG/QG driver when there is a state change (Charging status, SOC) + * + */ +void ttf_update(struct ttf *ttf, bool input_present) +{ + int delay_ms; + + if (ttf->input_present == input_present) + return; + + ttf->input_present = input_present; + if (input_present) + /* wait 35 seconds for the input to settle */ + delay_ms = 35000; + else + /* wait 5 seconds for current to settle during discharge */ + delay_ms = 5000; + + ttf->awake_voter(ttf->data, true); + cancel_delayed_work_sync(&ttf->ttf_work); + mutex_lock(&ttf->lock); + ttf_circ_buf_clr(&ttf->ibatt); + ttf_circ_buf_clr(&ttf->vbatt); + ttf->last_ttf = 0; + ttf->last_ms = 0; + mutex_unlock(&ttf->lock); + schedule_delayed_work(&ttf->ttf_work, msecs_to_jiffies(delay_ms)); +} + +/** + * ttf_tte_init - + * @ttf: Time to full object + * + * FG/QG have to call this during driver probe to validate the required + * parameters after allocating ttf object. + * + */ +int ttf_tte_init(struct ttf *ttf) +{ + if (!ttf) + return -ENODEV; + + if (!ttf->awake_voter || !ttf->get_ttf_param) { + pr_err("Insufficient functions for supporting ttf\n"); + return -EINVAL; + } + + if (!ttf->iterm_delta) + ttf->iterm_delta = DEFAULT_TTF_ITERM_DELTA_MA; + if (!ttf->period_ms) + ttf->period_ms = DEFAULT_TTF_RUN_PERIOD_MS; + + mutex_init(&ttf->lock); + INIT_DELAYED_WORK(&ttf->ttf_work, ttf_work); + + return 0; +} diff --git a/drivers/power/supply/qcom/fg-alg.h b/drivers/power/supply/qcom/fg-alg.h index 7c2500720297..70183ba3cd78 100644 --- a/drivers/power/supply/qcom/fg-alg.h +++ b/drivers/power/supply/qcom/fg-alg.h @@ -15,6 +15,8 @@ #define BUCKET_COUNT 8 #define BUCKET_SOC_PCT (256 / BUCKET_COUNT) +#define MAX_CC_STEPS 20 +#define MAX_TTF_SAMPLES 10 struct cycle_counter { void *data; @@ -58,6 +60,57 @@ struct cap_learning { int (*prime_cc_soc)(void *data, u32 cc_soc_sw); }; +enum ttf_mode { + TTF_MODE_NORMAL = 0, + TTF_MODE_QNOVO, +}; + +enum ttf_param { + TTF_MSOC = 0, + TTF_VBAT, + TTF_IBAT, + TTF_FCC, + TTF_MODE, + TTF_ITERM, + TTF_RBATT, + TTF_VFLOAT, + TTF_CHG_TYPE, + TTF_CHG_STATUS, +}; + +struct ttf_circ_buf { + int arr[MAX_TTF_SAMPLES]; + int size; + int head; +}; + +struct ttf_cc_step_data { + int arr[MAX_CC_STEPS]; + int sel; +}; + +struct ttf_pt { + s32 x; + s32 y; +}; + +struct ttf { + void *data; + struct ttf_circ_buf ibatt; + struct ttf_circ_buf vbatt; + struct ttf_cc_step_data cc_step; + struct mutex lock; + int mode; + int last_ttf; + int input_present; + int iterm_delta; + int period_ms; + s64 last_ms; + struct delayed_work ttf_work; + int (*get_ttf_param)(void *data, enum ttf_param, int *val); + int (*awake_voter)(void *data, bool vote); +}; + int restore_cycle_count(struct cycle_counter *counter); void clear_cycle_count(struct cycle_counter *counter); void cycle_count_update(struct cycle_counter *counter, int batt_soc, @@ -72,5 +125,9 @@ void cap_learning_update(struct cap_learning *cl, int batt_temp, int cap_learning_init(struct cap_learning *cl); int cap_learning_post_profile_init(struct cap_learning *cl, int64_t nom_cap_uah); +void ttf_update(struct ttf *ttf, bool input_present); +int ttf_get_time_to_empty(struct ttf *ttf, int *val); +int ttf_get_time_to_full(struct ttf *ttf, int *val); +int ttf_tte_init(struct ttf *ttf); #endif -- GitLab From 16b4b35144fdc5f5e847bfd81cdb8d3b8551a290 Mon Sep 17 00:00:00 2001 From: Sundara Vinayagam Date: Tue, 15 May 2018 17:13:10 +0530 Subject: [PATCH 738/855] msm: camera: Add camera support for apq8009 Initial snapshot of camera drivers are taken from msm-3.18 kernel version @ 'commit cb28f8462e97 ("Merge PM / devfreq: memlat: Remove kfree() on probe fails")'. Make required changes in camera drivers to support camera modules on apq8009. Change-Id: I3324684bcb866a9c67c1ba53d24fabd2bd98be43 Signed-off-by: Sundara Vinayagam --- drivers/media/platform/msm/camera_v2/Kconfig | 11 +- .../msm/camera_v2/common/msm_camera_tz_util.c | 2 - .../media/platform/msm/camera_v2/isp/Makefile | 5 + .../platform/msm/camera_v2/isp/msm_buf_mgr.c | 15 +- .../platform/msm/camera_v2/isp/msm_isp32.c | 587 +++-- .../platform/msm/camera_v2/isp/msm_isp_32.c | 557 +++++ .../platform/msm/camera_v2/isp/msm_isp_32.h | 599 +++++ .../msm/camera_v2/isp/msm_isp_axi_util_32.c | 2095 +++++++++++++++++ .../msm/camera_v2/isp/msm_isp_axi_util_32.h | 72 + .../msm/camera_v2/isp/msm_isp_stats_util_32.c | 709 ++++++ .../msm/camera_v2/isp/msm_isp_stats_util_32.h | 29 + .../msm/camera_v2/isp/msm_isp_util_32.c | 1939 +++++++++++++++ .../msm/camera_v2/isp/msm_isp_util_32.h | 84 + .../platform/msm/camera_v2/ispif/Makefile | 4 + .../msm/camera_v2/ispif/msm_ispif_32.c | 1581 +++++++++++++ .../msm/camera_v2/ispif/msm_ispif_32.h | 69 + .../camera_v2/sensor/actuator/msm_actuator.c | 8 +- .../msm/camera_v2/sensor/csid/msm_csid.c | 3 +- .../msm/camera_v2/sensor/csiphy/msm_csiphy.c | 5 +- .../camera_v2/sensor/io/msm_camera_tz_i2c.c | 1 - .../msm/camera_v2/sensor/msm_sensor_driver.c | 2 +- drivers/media/platform/msm/vidc/msm_venc.c | 2 +- include/media/msmb_isp.h | 13 + include/uapi/media/msmb_isp.h | 65 +- 24 files changed, 8192 insertions(+), 265 deletions(-) create mode 100644 drivers/media/platform/msm/camera_v2/isp/msm_isp_32.c create mode 100644 drivers/media/platform/msm/camera_v2/isp/msm_isp_32.h create mode 100644 drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c create mode 100644 drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.h create mode 100644 drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util_32.c create mode 100644 drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util_32.h create mode 100644 drivers/media/platform/msm/camera_v2/isp/msm_isp_util_32.c create mode 100644 drivers/media/platform/msm/camera_v2/isp/msm_isp_util_32.h create mode 100644 drivers/media/platform/msm/camera_v2/ispif/msm_ispif_32.c create mode 100644 drivers/media/platform/msm/camera_v2/ispif/msm_ispif_32.h diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig index cabc61251013..e5439d85357c 100644 --- a/drivers/media/platform/msm/camera_v2/Kconfig +++ b/drivers/media/platform/msm/camera_v2/Kconfig @@ -95,13 +95,22 @@ config MSM_EEPROM and also provides support for writing data in case of FLASH ROM. Currently supports I2C, CCI and SPI protocol +config MSM_ISP_V1 + bool "QTI MSM Image Signal Processing interface support" + depends on MSMB_CAMERA + ---help--- + Enable support for Image Signal Processing interface module. + This module acts as a crossbar between CSID and VFE. Output + of any CID of CSID can be routed to of pix or raw + data interface in VFE. + config MSM_ISPIF bool "QTI MSM Image Signal Processing interface support" depends on MSMB_CAMERA ---help--- Enable support for Image Signal Processing interface module. This module acts as a crossbar between CSID and VFE. Output - of any CID of CSID can be routed to of of pix or raw + of any CID of CSID can be routed to of pix or raw data interface in VFE. config MSM_ISPIF_V1 diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_tz_util.c b/drivers/media/platform/msm/camera_v2/common/msm_camera_tz_util.c index 22f489166ede..d32a0f27dc9d 100644 --- a/drivers/media/platform/msm/camera_v2/common/msm_camera_tz_util.c +++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_tz_util.c @@ -20,8 +20,6 @@ #define EMPTY_QSEECOM_HANDLE NULL #define QSEECOM_SBUFF_SIZE SZ_128K -#define MSM_CAMERA_TZ_UTIL_VERBOSE - #define MSM_CAMERA_TZ_BOOT_PROTECTED (false) /* Update version major number in case the HLOS-TA interface is changed*/ diff --git a/drivers/media/platform/msm/camera_v2/isp/Makefile b/drivers/media/platform/msm/camera_v2/isp/Makefile index 621d81d381a1..d36b1e2d598d 100644 --- a/drivers/media/platform/msm/camera_v2/isp/Makefile +++ b/drivers/media/platform/msm/camera_v2/isp/Makefile @@ -1,5 +1,10 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v2 ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io ccflags-y += -Idrivers/media/platform/msm/camera_v2/common/ +ifeq ($(CONFIG_MSM_ISP_V1),y) +obj-$(CONFIG_MSMB_CAMERA) += msm_isp_32.o msm_buf_mgr.o msm_isp_util_32.o msm_isp_axi_util_32.o msm_isp_stats_util_32.o +obj-$(CONFIG_MSMB_CAMERA) += msm_isp32.o +else obj-$(CONFIG_MSMB_CAMERA) += msm_buf_mgr.o msm_isp_util.o msm_isp_axi_util.o msm_isp_stats_util.o obj-$(CONFIG_MSMB_CAMERA) += msm_isp48.o msm_isp47.o msm_isp46.o msm_isp44.o msm_isp40.o msm_isp.o +endif diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c index 691b492dd52f..6196a8c2b34d 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c @@ -189,7 +189,9 @@ static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr, int i, rc = -1; int ret; struct msm_isp_buffer_mapped_info *mapped_info; +#ifndef CONFIG_MSM_ISP_V1 uint32_t accu_length = 0; +#endif struct msm_isp_bufq *bufq = NULL; bufq = msm_isp_get_bufq(buf_mgr, buf_info->bufq_handle); @@ -228,8 +230,12 @@ static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr, goto get_phy_err; } +#ifdef CONFIG_MSM_ISP_V1 + mapped_info->paddr += qbuf_buf->planes[i].offset; +#else mapped_info->paddr += accu_length; accu_length += qbuf_buf->planes[i].length; +#endif CDBG("%s: plane: %d addr:%pK\n", __func__, i, (void *)mapped_info->paddr); @@ -732,10 +738,17 @@ static int msm_isp_buf_divert(struct msm_isp_buf_mgr *buf_mgr, spin_lock_irqsave(&bufq->bufq_lock, flags); buf_info->frame_id = frame_id; +#ifdef CONFIG_MSM_ISP_V1 + if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED) { + buf_info->state = MSM_ISP_BUFFER_STATE_DIVERTED; + buf_info->tv = tv; + } +#else if (BUF_SRC(bufq->stream_id) == MSM_ISP_BUFFER_SRC_NATIVE) { buf_info->state = MSM_ISP_BUFFER_STATE_DIVERTED; buf_info->tv = tv; } +#endif spin_unlock_irqrestore(&bufq->bufq_lock, flags); return 0; } @@ -1077,7 +1090,6 @@ static void msm_isp_release_all_bufq( } } - /** * msm_isp_buf_put_scratch() - Release scratch buffers * @buf_mgr: The buffer structure for h/w @@ -1220,7 +1232,6 @@ int msm_isp_smmu_attach(struct msm_isp_buf_mgr *buf_mgr, return rc; } - static int msm_isp_init_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr, const char *ctx_name) { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c index 6da1360a5fcc..a95917c76902 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c @@ -12,21 +12,15 @@ #include #include - #include "msm_isp32.h" -#include "msm_isp_util.h" -#include "msm_isp_axi_util.h" -#include "msm_isp_stats_util.h" -#include "msm_isp.h" +#include "msm_isp_util_32.h" +#include "msm_isp_axi_util_32.h" +#include "msm_isp_stats_util_32.h" +#include "msm_isp_32.h" #include "msm.h" #include "msm_camera_io_util.h" -static const struct platform_device_id msm_vfe32_dev_id[] = { - {"msm_vfe32", (kernel_ulong_t) &vfe32_hw_info}, - {} -}; - -#define VFE32_BURST_LEN 2 +#define VFE32_BURST_LEN 3 #define VFE32_UB_SIZE 1024 #define VFE32_UB_SIZE_32KB 2048 #define VFE32_EQUAL_SLICE_UB 194 @@ -36,7 +30,7 @@ static const struct platform_device_id msm_vfe32_dev_id[] = { #define VFE32_XBAR_BASE(idx) (0x40 + 0x4 * (idx / 4)) #define VFE32_XBAR_SHIFT(idx) ((idx % 4) * 8) #define VFE32_PING_PONG_BASE(wm, ping_pong) \ - (VFE32_WM_BASE(wm) + 0x4 * (1 + ((~ping_pong) & 0x1))) + (VFE32_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1))) static uint8_t stats_pingpong_offset_map[] = { 7, 8, 9, 10, 11, 12, 13}; @@ -60,16 +54,6 @@ static struct msm_cam_clk_info msm_vfe32_2_clk_info[] = { {"csi_vfe_clk", -1}, }; -static uint32_t msm_vfe32_ub_reg_offset(struct vfe_device *vfe_dev, int idx) -{ - return (VFE32_WM_BASE(idx) + 0x10); -} - -static uint32_t msm_vfe32_get_ub_size(struct vfe_device *vfe_dev) -{ - return MSM_ISP32_TOTAL_WM_UB; -} - static int32_t msm_vfe32_init_qos_parms(struct vfe_device *vfe_dev, struct msm_vfe_hw_init_parms *qos_parms, struct msm_vfe_hw_init_parms *ds_parms) @@ -284,8 +268,6 @@ static int msm_vfe32_init_hardware(struct vfe_device *vfe_dev) pr_err("%s: vfe ioremap failed\n", __func__); goto vfe_remap_failed; } - vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = - vfe_dev->vfe_base; vfe_dev->vfe_vbif_base = ioremap(vfe_dev->vfe_vbif_mem->start, resource_size(vfe_dev->vfe_vbif_mem)); @@ -330,14 +312,12 @@ static int msm_vfe32_init_hardware(struct vfe_device *vfe_dev) static void msm_vfe32_release_hardware(struct vfe_device *vfe_dev) { - msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x1C); - msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x20); - disable_irq(vfe_dev->vfe_irq->start); free_irq(vfe_dev->vfe_irq->start, vfe_dev); tasklet_kill(&vfe_dev->vfe_tasklet); - msm_isp_flush_tasklet(vfe_dev); iounmap(vfe_dev->vfe_vbif_base); vfe_dev->vfe_vbif_base = NULL; + iounmap(vfe_dev->vfe_base); + vfe_dev->vfe_base = NULL; if (vfe_dev->vfe_clk_idx == 1) msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info, vfe_dev->vfe_clk, @@ -346,9 +326,6 @@ static void msm_vfe32_release_hardware(struct vfe_device *vfe_dev) msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_2_clk_info, vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_2_clk_info), 0); - vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = NULL; - iounmap(vfe_dev->vfe_base); - vfe_dev->vfe_base = NULL; kfree(vfe_dev->vfe_clk); regulator_disable(vfe_dev->fs_vfe); msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); @@ -369,7 +346,6 @@ static void msm_vfe32_init_hardware_reg(struct vfe_device *vfe_dev) ds_parms.entries = "ds-entries"; ds_parms.regs = "ds-regs"; ds_parms.settings = "ds-settings"; - msm_vfe32_init_qos_parms(vfe_dev, &qos_parms, &ds_parms); msm_vfe32_init_vbif_parms(vfe_dev, &vbif_parms); @@ -381,6 +357,11 @@ static void msm_vfe32_init_hardware_reg(struct vfe_device *vfe_dev) msm_camera_io_w_mb(0x1CFFFFFF, vfe_dev->vfe_base + 0x20); msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24); msm_camera_io_w_mb(0x1FFFFFFF, vfe_dev->vfe_base + 0x28); + msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x6FC); + msm_camera_io_w(0x10000000, vfe_dev->vfe_base + VFE32_RDI_BASE(1)); + msm_camera_io_w(0x10000000, vfe_dev->vfe_base + VFE32_RDI_BASE(2)); + msm_camera_io_w(0x0, vfe_dev->vfe_base + VFE32_XBAR_BASE(0)); + msm_camera_io_w(0x0, vfe_dev->vfe_base + VFE32_XBAR_BASE(4)); } @@ -396,13 +377,30 @@ static void msm_vfe32_clear_status_reg(struct vfe_device *vfe_dev) static void msm_vfe32_process_reset_irq(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1) { - if (irq_status1 & BIT(23)) + if (irq_status1 & BIT(23)) { + if (vfe_dev->vfe_reset_timeout_processed == 1) { + pr_err("%s:vfe reset was processed.\n", __func__); + return; + } complete(&vfe_dev->reset_complete); + } } static void msm_vfe32_process_halt_irq(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1) { + if (irq_status1 & (1 << 24)) + msm_camera_io_w_mb(0, vfe_dev->vfe_base + 0x1D8); +} + +static void msm_vfe32_process_epoch_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + if (!(irq_status0 & 0x18)) + return; + if (irq_status0 & (1 << 3)) + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); } static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev, @@ -416,10 +414,12 @@ static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev, ISP_DBG("%s: SOF IRQ\n", __func__); if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - stream_count == 0) { + pix_stream_count == 0) { msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); - msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0, ts); - msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0); + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev, + (1 << VFE_PIX_0)); + msm_isp_update_framedrop_reg(vfe_dev, (1 << VFE_PIX_0)); } } } @@ -485,7 +485,20 @@ static void msm_vfe32_process_violation_status(struct vfe_device *vfe_dev) static void msm_vfe32_get_overflow_mask(uint32_t *overflow_mask) { - *overflow_mask = 0x0; + *overflow_mask = 0x003FFF7E; +} + +static void msm_vfe32_get_rdi_wm_mask(struct vfe_device *vfe_dev, + uint32_t *rdi_wm_mask) +{ + *rdi_wm_mask = vfe_dev->axi_data.rdi_wm_mask; +} + +static void msm_vfe32_get_irq_mask(struct vfe_device *vfe_dev, + uint32_t *irq0_mask, uint32_t *irq1_mask) +{ + *irq0_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + *irq1_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20); } static void msm_vfe32_process_error_status(struct vfe_device *vfe_dev) @@ -571,7 +584,7 @@ static void msm_vfe32_process_error_status(struct vfe_device *vfe_dev) pr_err("%s: axi error\n", __func__); } -static void msm_vfe32_read_and_clear_irq_status(struct vfe_device *vfe_dev, +static void msm_vfe32_read_irq_status(struct vfe_device *vfe_dev, uint32_t *irq_status0, uint32_t *irq_status1) { *irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); @@ -589,122 +602,127 @@ static void msm_vfe32_read_and_clear_irq_status(struct vfe_device *vfe_dev, msm_camera_io_r(vfe_dev->vfe_base + 0x7B4); } -static void msm_vfe32_read_irq_status(struct vfe_device *vfe_dev, - uint32_t *irq_status0, uint32_t irq_status1) -{ - *irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); - *irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x30); -} - static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1, struct msm_isp_timestamp *ts) { - uint32_t rdi_status; - enum msm_vfe_input_src i; + uint8_t input_src = 0x0; if (!(irq_status0 & 0x20) && !(irq_status1 & 0x1C000000)) return; if (irq_status0 & BIT(5)) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, - VFE_PIX_0); - if (vfe_dev->axi_data.stream_update[VFE_PIX_0]) { - rdi_status = msm_camera_io_r(vfe_dev->vfe_base + - VFE32_XBAR_BASE(0)); - rdi_status |= msm_camera_io_r(vfe_dev->vfe_base + - VFE32_XBAR_BASE(4)); - - if ((rdi_status & BIT(7)) && (!(irq_status0 & 0x20))) - return; - } - msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, - MSM_ISP_COMP_IRQ_REG_UPD); + msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); + input_src |= (1 << VFE_PIX_0); + } + if (irq_status1 & BIT(26)) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_0, ts); + input_src |= (1 << VFE_RAW_0); + } + if (irq_status1 & BIT(27)) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_1, ts); + input_src |= (1 << VFE_RAW_1); + } + if (irq_status1 & BIT(28)) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_2, ts); + input_src |= (1 << VFE_RAW_2); } - for (i = VFE_RAW_0; i <= VFE_RAW_2; i++) { - if (irq_status1 & BIT(26 + (i - VFE_RAW_0))) { - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts); - msm_isp_axi_stream_update(vfe_dev, i, ts); - msm_isp_update_framedrop_reg(vfe_dev, i); - - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, - i); + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev, input_src); + if (atomic_read(&vfe_dev->stats_data.stats_update)) + msm_isp_stats_stream_update(vfe_dev); + if (vfe_dev->axi_data.stream_update || + atomic_read(&vfe_dev->stats_data.stats_update)) { + if (input_src & (1 << VFE_PIX_0)) { + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev, (1 << VFE_PIX_0)); } } - + msm_isp_update_framedrop_reg(vfe_dev, input_src); + msm_isp_update_stats_framedrop_reg(vfe_dev); msm_isp_update_error_frame_count(vfe_dev); + if ((input_src & (1 << VFE_RAW_0)) || + (input_src & (1 << VFE_RAW_1)) || + (input_src & (1 << VFE_RAW_2))) { + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev, input_src); + } + return; } -static void msm_vfe32_process_epoch_irq(struct vfe_device *vfe_dev, - uint32_t irq_status0, uint32_t irq_status1, - struct msm_isp_timestamp *ts) +static void msm_vfe32_reg_update( + struct vfe_device *vfe_dev, uint32_t input_src) { - /* Not supported */ -} - -static void msm_vfe32_reg_update(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src) -{ - if (vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) { - msm_camera_io_w_mb(0xF, - vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0] - + 0x260); - msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x260); - } else if (!vfe_dev->is_split) { - msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x260); - } + msm_camera_io_w_mb(input_src, vfe_dev->vfe_base + 0x260); } static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev, uint32_t first_start, uint32_t blocking) { - init_completion(&vfe_dev->reset_complete); - msm_camera_io_w_mb(0x3FF, vfe_dev->vfe_base + 0x4); - return wait_for_completion_timeout( - &vfe_dev->reset_complete, msecs_to_jiffies(50)); + long rc = 0; + uint32_t irq_status1; + + if (blocking) { + init_completion(&vfe_dev->reset_complete); + msm_camera_io_w_mb(0x3FF, vfe_dev->vfe_base + 0x4); + vfe_dev->vfe_reset_timeout_processed = 0; + rc = wait_for_completion_timeout( + &vfe_dev->reset_complete, msecs_to_jiffies(500)); + } else { + msm_camera_io_w_mb(0x3FF, vfe_dev->vfe_base + 0x4); + } + + if (blocking && rc <= 0) { + /*read ISP status register*/ + irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x30); + pr_err("%s: handling vfe reset time out error. irq_status1 0x%x\n", + __func__, irq_status1); + if (irq_status1 & BIT(23)) { + pr_err("%s: vfe reset has done actually\n", __func__); + vfe_dev->vfe_reset_timeout_processed = 1; + return 1; + } + } + return rc; } static void msm_vfe32_axi_reload_wm( - struct vfe_device *vfe_dev, void __iomem *vfe_base, - uint32_t reload_mask) + struct vfe_device *vfe_dev, uint32_t reload_mask) { if (!vfe_dev->pdev->dev.of_node) { /*vfe32 A-family: 8960*/ - msm_camera_io_w_mb(reload_mask, vfe_base + 0x38); + msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x38); } else { /*vfe32 B-family: 8610*/ - msm_camera_io_w(0x0, vfe_base + 0x24); - msm_camera_io_w(0x0, vfe_base + 0x28); - msm_camera_io_w(0x0, vfe_base + 0x20); - msm_camera_io_w_mb(0x1, vfe_base + 0x18); - msm_camera_io_w(0x9AAAAAAA, vfe_base + 0x600); - msm_camera_io_w(reload_mask, vfe_base + 0x38); + msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x28); + msm_camera_io_w(0x1C800000, vfe_dev->vfe_base + 0x20); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x18); + msm_camera_io_w(0x9AAAAAAA, vfe_dev->vfe_base + 0x600); + msm_camera_io_w(reload_mask, vfe_dev->vfe_base + 0x38); } } -static void msm_vfe32_axi_enable_wm(void __iomem *vfe_base, +static void msm_vfe32_axi_enable_wm(struct vfe_device *vfe_dev, uint8_t wm_idx, uint8_t enable) { uint32_t val = msm_camera_io_r( - vfe_base + VFE32_WM_BASE(wm_idx)); + vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx)); if (enable) val |= 0x1; else val &= ~0x1; msm_camera_io_w_mb(val, - vfe_base + VFE32_WM_BASE(wm_idx)); + vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx)); } static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index[vfe_idx]; + stream_info->comp_mask_index; uint32_t irq_mask; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34); @@ -721,9 +739,7 @@ static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe32_axi_clear_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); - uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index[vfe_idx]; + uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; uint32_t irq_mask; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34); @@ -739,10 +755,9 @@ static void msm_vfe32_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t irq_mask; - int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask |= BIT(stream_info->wm[vfe_idx][0] + 6); + irq_mask |= BIT(stream_info->wm[0] + 6); msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); } @@ -750,31 +765,40 @@ static void msm_vfe32_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t irq_mask; - int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask &= ~BIT(stream_info->wm[vfe_idx][0] + 6); + irq_mask &= ~BIT(stream_info->wm[0] + 6); msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); } static void msm_vfe32_cfg_framedrop(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, - uint32_t framedrop_period) + struct msm_vfe_axi_stream *stream_info) { - void __iomem *vfe_base = vfe_dev->vfe_base; + uint32_t framedrop_pattern = 0, framedrop_period = 0; + + if (stream_info->runtime_init_frame_drop == 0) { + framedrop_pattern = stream_info->framedrop_pattern; + framedrop_period = stream_info->framedrop_period; + } + + if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_burst_frame_count == 0) { + framedrop_pattern = 0; + framedrop_period = 0; + } if (stream_info->stream_src == PIX_ENCODER) { - msm_camera_io_w(framedrop_period - 1, vfe_base + 0x504); - msm_camera_io_w(framedrop_period - 1, vfe_base + 0x508); - msm_camera_io_w(framedrop_pattern, vfe_base + 0x50C); - msm_camera_io_w(framedrop_pattern, vfe_base + 0x510); + msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x504); + msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x508); + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x50C); + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x510); } else if (stream_info->stream_src == PIX_VIEWFINDER) { - msm_camera_io_w(framedrop_period - 1, vfe_base + 0x514); - msm_camera_io_w(framedrop_period - 1, vfe_base + 0x518); - msm_camera_io_w(framedrop_pattern, vfe_base + 0x51C); - msm_camera_io_w(framedrop_pattern, vfe_base + 0x520); + msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x514); + msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x518); + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x51C); + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x520); } - msm_camera_io_w_mb(0x1, vfe_base + 0x260); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x260); } static void msm_vfe32_clear_framedrop(struct vfe_device *vfe_dev, @@ -877,6 +901,7 @@ static void msm_vfe32_cfg_fetch_engine(struct vfe_device *vfe_dev, struct msm_vfe_pix_cfg *pix_cfg) { pr_err("%s: Fetch engine not supported\n", __func__); + return; } static void msm_vfe32_cfg_camif(struct vfe_device *vfe_dev, @@ -924,6 +949,7 @@ static void msm_vfe32_cfg_input_mux(struct vfe_device *vfe_dev, pr_err("%s: Unsupported input mux %d\n", __func__, pix_cfg->input_mux); } + return; } static void msm_vfe32_update_camif_state( @@ -938,19 +964,20 @@ static void msm_vfe32_update_camif_state( if (update_state == ENABLE_CAMIF) { val = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - val |= 0x1; + val |= 0x19; msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x1C); - + msm_camera_io_w_mb(0xA, vfe_dev->vfe_base + 0x200); val = msm_camera_io_r(vfe_dev->vfe_base + 0x1E4); bus_en = ((vfe_dev->axi_data.src_info[ VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); vfe_en = ((vfe_dev->axi_data.src_info[ - VFE_PIX_0].stream_count > 0) ? 1 : 0); + VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); val &= 0xFFFFFF3F; val = val | bus_en << 7 | vfe_en << 6; msm_camera_io_w(val, vfe_dev->vfe_base + 0x1E4); + msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x1E0); msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1E0); vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1; } else if (update_state == DISABLE_CAMIF) { @@ -990,17 +1017,16 @@ static void msm_vfe32_axi_cfg_wm_reg( uint8_t plane_idx) { uint32_t val; - int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); - uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); + uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]); if (!stream_info->frame_based) { /*WR_IMAGE_SIZE*/ val = ((msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[vfe_idx][plane_idx]. + stream_info->plane_cfg[plane_idx]. output_width)+1)/2 - 1) << 16 | - (stream_info->plane_cfg[vfe_idx][plane_idx]. + (stream_info->plane_cfg[plane_idx]. output_height - 1); msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10); @@ -1008,9 +1034,9 @@ static void msm_vfe32_axi_cfg_wm_reg( val = msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[vfe_idx][plane_idx]. + stream_info->plane_cfg[plane_idx]. output_stride) << 16 | - (stream_info->plane_cfg[vfe_idx][plane_idx]. + (stream_info->plane_cfg[plane_idx]. output_height - 1) << 4 | VFE32_BURST_LEN; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); } else { @@ -1018,12 +1044,13 @@ static void msm_vfe32_axi_cfg_wm_reg( val = msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[vfe_idx][plane_idx]. + stream_info->plane_cfg[plane_idx]. output_width) << 16 | - (stream_info->plane_cfg[vfe_idx][plane_idx]. + (stream_info->plane_cfg[plane_idx]. output_height - 1) << 4 | VFE32_BURST_LEN; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); } + return; } static void msm_vfe32_axi_clear_wm_reg( @@ -1031,22 +1058,24 @@ static void msm_vfe32_axi_clear_wm_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { uint32_t val = 0; - int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); - uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); + uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]); + + /* FRAME BASED */ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base); /*WR_IMAGE_SIZE*/ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10); /*WR_BUFFER_CFG*/ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + return; } static void msm_vfe32_axi_cfg_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[vfe_idx][plane_idx]; - uint8_t wm = stream_info->wm[vfe_idx][plane_idx]; + &stream_info->plane_cfg[plane_idx]; + uint8_t wm = stream_info->wm[plane_idx]; uint32_t xbar_cfg = 0; uint32_t xbar_reg_cfg = 0; @@ -1093,14 +1122,14 @@ static void msm_vfe32_axi_cfg_wm_xbar_reg( xbar_reg_cfg &= ~(0xFF << VFE32_XBAR_SHIFT(wm)); xbar_reg_cfg |= (xbar_cfg << VFE32_XBAR_SHIFT(wm)); msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); + return; } static void msm_vfe32_axi_clear_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); - uint8_t wm = stream_info->wm[vfe_idx][plane_idx]; + uint8_t wm = stream_info->wm[plane_idx]; uint32_t xbar_reg_cfg = 0; xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); @@ -1108,21 +1137,95 @@ static void msm_vfe32_axi_clear_wm_xbar_reg( msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); } -static void msm_vfe32_update_ping_pong_addr(void __iomem *vfe_base, - uint8_t wm_idx, uint32_t pingpong_bit, dma_addr_t paddr, - int32_t buf_size) +static void msm_vfe32_cfg_axi_ub_equal_default(struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t total_image_size = 0; + uint32_t num_used_wms = 0; + uint32_t prop_size = 0; + uint32_t wm_ub_size; + uint64_t delta; + + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i] > 0) { + num_used_wms++; + total_image_size += axi_data->wm_image_size[i]; + } + } + prop_size = MSM_ISP32_TOTAL_WM_UB - + axi_data->hw_info->min_wm_ub * num_used_wms; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i]) { + delta = + (uint64_t)(axi_data->wm_image_size[i] * + prop_size); + do_div(delta, total_image_size); + wm_ub_size = axi_data->hw_info->min_wm_ub + + (uint32_t)delta; + msm_camera_io_w(ub_offset << 16 | + (wm_ub_size - 1), vfe_dev->vfe_base + + VFE32_WM_BASE(i) + 0xC); + ub_offset += wm_ub_size; + } else { + msm_camera_io_w(0, + vfe_dev->vfe_base + VFE32_WM_BASE(i) + 0xC); + } + } +} + +static void msm_vfe32_cfg_axi_ub_equal_slicing(struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + uint32_t final_ub_slice_size; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (ub_offset + VFE32_EQUAL_SLICE_UB > VFE32_AXI_SLICE_UB) { + final_ub_slice_size = VFE32_AXI_SLICE_UB - ub_offset; + msm_camera_io_w(ub_offset << 16 | + (final_ub_slice_size - 1), vfe_dev->vfe_base + + VFE32_WM_BASE(i) + 0xC); + ub_offset += final_ub_slice_size; + } else { + msm_camera_io_w(ub_offset << 16 | + (VFE32_EQUAL_SLICE_UB - 1), vfe_dev->vfe_base + + VFE32_WM_BASE(i) + 0xC); + ub_offset += VFE32_EQUAL_SLICE_UB; + } + } +} + +static void msm_vfe32_cfg_axi_ub(struct vfe_device *vfe_dev) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + axi_data->wm_ub_cfg_policy = MSM_WM_UB_CFG_DEFAULT; + if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING) + msm_vfe32_cfg_axi_ub_equal_slicing(vfe_dev); + else + msm_vfe32_cfg_axi_ub_equal_default(vfe_dev); +} + +static void msm_vfe32_update_ping_pong_addr(struct vfe_device *vfe_dev, + uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr) { uint32_t paddr32 = (paddr & 0xFFFFFFFF); - msm_camera_io_w(paddr32, vfe_base + - VFE32_PING_PONG_BASE(wm_idx, pingpong_bit)); + msm_camera_io_w(paddr32, vfe_dev->vfe_base + + VFE32_PING_PONG_BASE(wm_idx, pingpong_status)); } static int msm_vfe32_axi_halt(struct vfe_device *vfe_dev, uint32_t blocking) { - uint32_t halt_mask; uint32_t axi_busy_flag = true; + /* Keep only halt and restart mask */ + msm_camera_io_w(0x01800000, vfe_dev->vfe_base + 0x20); + /*Clear IRQ Status */ + msm_camera_io_w(0xFE7FFFFF, vfe_dev->vfe_base + 0x28); msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1D8); while (axi_busy_flag) { if (msm_camera_io_r( @@ -1130,10 +1233,27 @@ static int msm_vfe32_axi_halt(struct vfe_device *vfe_dev, uint32_t blocking) axi_busy_flag = false; } msm_camera_io_w_mb(0, vfe_dev->vfe_base + 0x1D8); - halt_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20); - halt_mask &= 0xFEFFFFFF; - /* Disable AXI IRQ */ - msm_camera_io_w_mb(halt_mask, vfe_dev->vfe_base + 0x20); + return 0; +} + +static int msm_vfe32_axi_restart(struct vfe_device *vfe_dev, + uint32_t blocking, uint32_t enable_camif) +{ + vfe_dev->hw_info->vfe_ops.core_ops.restore_irq_mask(vfe_dev); + + /*Clear IRQ Status */ + msm_camera_io_w(0xFE7FFFFF, vfe_dev->vfe_base + 0x28); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1D8); + msm_camera_io_w_mb(0xA, vfe_dev->vfe_base + 0x200); + /* Start AXI */ + msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x1D8); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); + atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW); + if (enable_camif) { + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, ENABLE_CAMIF); + } return 0; } @@ -1187,20 +1307,36 @@ static int msm_vfe32_stats_check_streams( } static void msm_vfe32_stats_cfg_comp_mask(struct vfe_device *vfe_dev, - uint32_t stats_mask, uint8_t comp_idx, uint8_t enable) + uint32_t stats_mask, uint8_t enable) { + uint32_t i = 0; + atomic_t *stats_comp; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + + stats_mask = stats_mask & 0x7F; + + for (i = 0; + i < vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; i++) { + stats_comp = &stats_data->stats_comp_mask[i]; + if (enable) + atomic_add(stats_mask, stats_comp); + else + atomic_sub(stats_mask, stats_comp); + ISP_DBG("%s: comp_mask: %x\n", + __func__, atomic_read(&stats_data->stats_comp_mask[i])); + } + return; } static void msm_vfe32_stats_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, - stream_info); uint32_t irq_mask; irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask |= BIT(STATS_IDX(stream_info->stream_handle[vfe_idx]) + 13); + irq_mask |= BIT(STATS_IDX(stream_info->stream_handle) + 13); msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); + return; } static void msm_vfe32_stats_clear_wm_irq_mask(struct vfe_device *vfe_dev, @@ -1211,18 +1347,21 @@ static void msm_vfe32_stats_clear_wm_irq_mask(struct vfe_device *vfe_dev, irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); irq_mask &= ~(BIT(STATS_IDX(stream_info->stream_handle) + 13)); msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); + return; } static void msm_vfe32_stats_cfg_wm_reg(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { /*Nothing to configure for VFE3.x*/ + return; } static void msm_vfe32_stats_clear_wm_reg(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { /*Nothing to configure for VFE3.x*/ + return; } static void msm_vfe32_stats_cfg_ub(struct vfe_device *vfe_dev) @@ -1247,12 +1386,7 @@ static void msm_vfe32_stats_cfg_ub(struct vfe_device *vfe_dev) msm_camera_io_w(ub_offset << 16 | (ub_size[i] - 1), vfe_dev->vfe_base + VFE32_STATS_BASE(i) + 0x8); } -} - -static bool msm_vfe32_is_module_cfg_lock_needed( - uint32_t reg_offset) -{ - return false; + return; } static void msm_vfe32_stats_enable_module(struct vfe_device *vfe_dev, @@ -1294,15 +1428,13 @@ static void msm_vfe32_stats_enable_module(struct vfe_device *vfe_dev, static void msm_vfe32_stats_update_ping_pong_addr(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, - dma_addr_t paddr, uint32_t buf_sz) + dma_addr_t paddr) { - void __iomem *vfe_base = vfe_dev->vfe_base; - int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, - stream_info); uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); - msm_camera_io_w(paddr32, vfe_base + + int stats_idx = STATS_IDX(stream_info->stream_handle); + + msm_camera_io_w(paddr32, vfe_dev->vfe_base + VFE32_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); } @@ -1361,28 +1493,6 @@ static int msm_vfe32_get_platform_data(struct vfe_device *vfe_dev) goto vfe_no_resource; } - if (!vfe_dev->pdev->dev.of_node) - vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe_imgwr"); - else - vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe"); - - if (!vfe_dev->iommu_ctx[0]) { - pr_err("%s: no iommux ctx resource?\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - - if (!vfe_dev->pdev->dev.of_node) - vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe_misc"); - else - vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe"); - - if (!vfe_dev->iommu_ctx[1]) { - pr_err("%s: no iommux ctx resource?\n", __func__); - rc = -ENODEV; - goto vfe_no_resource; - } - vfe_no_resource: return rc; } @@ -1394,13 +1504,27 @@ static void msm_vfe32_get_error_mask(uint32_t *error_mask0, *error_mask1 = 0x007FFFFF; } -struct msm_vfe_axi_hardware_info msm_vfe32_axi_hw_info = { - .num_wm = 5, + +static void msm_vfe32_restore_irq_mask(struct vfe_device *vfe_dev) +{ + msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask0, + vfe_dev->vfe_base + 0x1C); + msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask1, + vfe_dev->vfe_base + 0x20); +} + +static void msm_vfe32_get_halt_restart_mask(uint32_t *irq0_mask, + uint32_t *irq1_mask) +{ + *irq1_mask = 0x01800000; +} + +static struct msm_vfe_axi_hardware_info msm_vfe32_axi_hw_info = { + .num_wm = 6, .num_comp_mask = 3, .num_rdi = 3, .num_rdi_master = 3, .min_wm_ub = 64, - .scratch_buf_range = SZ_32M, }; static struct msm_vfe_stats_hardware_info msm_vfe32_stats_hw_info = { @@ -1412,7 +1536,22 @@ static struct msm_vfe_stats_hardware_info msm_vfe32_stats_hw_info = { 1 << MSM_ISP_STATS_SKIN | 1 << MSM_ISP_STATS_BHIST, .stats_ping_pong_offset = stats_pingpong_offset_map, .num_stats_type = VFE32_NUM_STATS_TYPE, - .num_stats_comp_mask = 0, + .num_stats_comp_mask = 1, +}; + +static struct v4l2_subdev_core_ops msm_vfe32_subdev_core_ops = { + .ioctl = msm_isp_ioctl, + .subscribe_event = msm_isp_subscribe_event, + .unsubscribe_event = msm_isp_unsubscribe_event, +}; + +static struct v4l2_subdev_ops msm_vfe32_subdev_ops = { + .core = &msm_vfe32_subdev_core_ops, +}; + +static struct v4l2_subdev_internal_ops msm_vfe32_internal_ops = { + .open = msm_isp_open_node, + .close = msm_isp_close_node, }; struct msm_vfe_hardware_info vfe32_hw_info = { @@ -1421,16 +1560,14 @@ struct msm_vfe_hardware_info vfe32_hw_info = { .vfe_clk_idx = VFE32_CLK_IDX, .vfe_ops = { .irq_ops = { - .read_and_clear_irq_status = - msm_vfe32_read_and_clear_irq_status, .read_irq_status = msm_vfe32_read_irq_status, .process_camif_irq = msm_vfe32_process_camif_irq, .process_reset_irq = msm_vfe32_process_reset_irq, .process_halt_irq = msm_vfe32_process_halt_irq, .process_reg_update = msm_vfe32_process_reg_update, + .process_epoch_irq = msm_vfe32_process_epoch_irq, .process_axi_irq = msm_isp_process_axi_irq, .process_stats_irq = msm_isp_process_stats_irq, - .process_epoch_irq = msm_vfe32_process_epoch_irq, }, .axi_ops = { .reload_wm = msm_vfe32_axi_reload_wm, @@ -1446,15 +1583,14 @@ struct msm_vfe_hardware_info vfe32_hw_info = { .clear_wm_reg = msm_vfe32_axi_clear_wm_reg, .cfg_wm_xbar_reg = msm_vfe32_axi_cfg_wm_xbar_reg, .clear_wm_xbar_reg = msm_vfe32_axi_clear_wm_xbar_reg, - .cfg_ub = msm_vfe47_cfg_axi_ub, + .cfg_ub = msm_vfe32_cfg_axi_ub, .update_ping_pong_addr = msm_vfe32_update_ping_pong_addr, .get_comp_mask = msm_vfe32_get_comp_mask, .get_wm_mask = msm_vfe32_get_wm_mask, .get_pingpong_status = msm_vfe32_get_pingpong_status, .halt = msm_vfe32_axi_halt, - .ub_reg_offset = msm_vfe40_ub_reg_offset, - .get_ub_size = msm_vfe40_get_ub_size, + .restart = msm_vfe32_axi_restart, }, .core_ops = { .reg_update = msm_vfe32_reg_update, @@ -1469,13 +1605,13 @@ struct msm_vfe_hardware_info vfe32_hw_info = { .release_hw = msm_vfe32_release_hardware, .get_platform_data = msm_vfe32_get_platform_data, .get_error_mask = msm_vfe32_get_error_mask, - .process_error_status = msm_vfe32_process_error_status, .get_overflow_mask = msm_vfe32_get_overflow_mask, - .is_module_cfg_lock_needed = - msm_vfe32_is_module_cfg_lock_needed, - .ahb_clk_cfg = NULL, - .set_bus_err_ign_mask = NULL, - .get_bus_err_mask = NULL, + .get_rdi_wm_mask = msm_vfe32_get_rdi_wm_mask, + .get_irq_mask = msm_vfe32_get_irq_mask, + .restore_irq_mask = msm_vfe32_restore_irq_mask, + .get_halt_restart_mask = + msm_vfe32_get_halt_restart_mask, + .process_error_status = msm_vfe32_process_error_status, }, .stats_ops = { .get_stats_idx = msm_vfe32_get_stats_idx, @@ -1493,47 +1629,12 @@ struct msm_vfe_hardware_info vfe32_hw_info = { .get_wm_mask = msm_vfe32_stats_get_wm_mask, .get_frame_id = msm_vfe32_stats_get_frame_id, .get_pingpong_status = msm_vfe32_get_pingpong_status, - .enable_stats_wm = NULL, }, }, .dmi_reg_offset = 0x5A0, .axi_hw_info = &msm_vfe32_axi_hw_info, .stats_hw_info = &msm_vfe32_stats_hw_info, + .subdev_ops = &msm_vfe32_subdev_ops, + .subdev_internal_ops = &msm_vfe32_internal_ops, }; EXPORT_SYMBOL(vfe32_hw_info); - -static const struct of_device_id msm_vfe32_dt_match[] = { - { - .compatible = "qcom,vfe32", - .data = &vfe32_hw_info, - }, - {} -}; - -MODULE_DEVICE_TABLE(of, msm_vfe32_dt_match); - -static struct platform_driver vfe32_driver = { - .probe = vfe_hw_probe, - .driver = { - .name = "msm_vfe32", - .owner = THIS_MODULE, - .of_match_table = msm_vfe32_dt_match, - }, - .id_table = msm_vfe32_dev_id, -}; - -static int __init msm_vfe32_init_module(void) -{ - return platform_driver_register(&vfe32_driver); -} - -static void __exit msm_vfe32_exit_module(void) -{ - platform_driver_unregister(&vfe32_driver); -} - -module_init(msm_vfe32_init_module); -module_exit(msm_vfe32_exit_module); -MODULE_DESCRIPTION("MSM VFE32 driver"); -MODULE_LICENSE("GPL v2"); - diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_32.c new file mode 100644 index 000000000000..eada5fa125aa --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_32.c @@ -0,0 +1,557 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_isp_32.h" +#include "msm_isp_util_32.h" +#include "msm_isp_axi_util_32.h" +#include "msm_isp_stats_util_32.h" +#include "msm_sd.h" +#include "msm_isp32.h" + +static struct msm_sd_req_vb2_q vfe_vb2_ops; + +static const struct of_device_id msm_vfe_dt_match[] = { + { + .compatible = "qcom,vfe32", + .data = &vfe32_hw_info, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_vfe_dt_match); + +static const struct platform_device_id msm_vfe_dev_id[] = { + {"msm_vfe32", (kernel_ulong_t) &vfe32_hw_info}, + {} +}; +#define MAX_OVERFLOW_COUNTERS 29 +#define OVERFLOW_LENGTH 1024 +#define OVERFLOW_BUFFER_LENGTH 64 +static char stat_line[OVERFLOW_LENGTH]; + +static struct msm_isp_buf_mgr vfe_buf_mgr; +static int msm_isp_enable_debugfs(struct vfe_device *vfe_dev, + struct msm_isp_bw_req_info *isp_req_hist); +static char *stats_str[MAX_OVERFLOW_COUNTERS] = { + "imgmaster0_overflow_cnt", + "imgmaster1_overflow_cnt", + "imgmaster2_overflow_cnt", + "imgmaster3_overflow_cnt", + "imgmaster4_overflow_cnt", + "imgmaster5_overflow_cnt", + "imgmaster6_overflow_cnt", + "be_overflow_cnt", + "bg_overflow_cnt", + "bf_overflow_cnt", + "awb_overflow_cnt", + "rs_overflow_cnt", + "cs_overflow_cnt", + "ihist_overflow_cnt", + "skinbhist_overflow_cnt", + "bfscale_overflow_cnt", + "ISP_VFE0_client_info.active", + "ISP_VFE0_client_info.ab", + "ISP_VFE0_client_info.ib", + "ISP_VFE1_client_info.active", + "ISP_VFE1_client_info.ab", + "ISP_VFE1_client_info.ib", + "ISP_CPP_client_info.active", + "ISP_CPP_client_info.ab", + "ISP_CPP_client_info.ib", + "ISP_last_overflow.ab", + "ISP_last_overflow.ib", + "ISP_VFE_CLK_RATE", + "ISP_CPP_CLK_RATE", +}; + +#define MAX_DEPTH_BW_REQ_HISTORY 25 +#define MAX_BW_HISTORY_BUFF_LEN 6144 +#define MAX_BW_HISTORY_LINE_BUFF_LEN 512 + +#define MAX_UB_INFO_BUFF_LEN 1024 +#define MAX_UB_INFO_LINE_BUFF_LEN 256 + +static struct msm_isp_bw_req_info + msm_isp_bw_request_history[MAX_DEPTH_BW_REQ_HISTORY]; +static int msm_isp_bw_request_history_idx; +static char bw_request_history_buff[MAX_BW_HISTORY_BUFF_LEN]; +static char ub_info_buffer[MAX_UB_INFO_BUFF_LEN]; +static spinlock_t req_history_lock; +static int vfe_debugfs_statistics_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t vfe_debugfs_statistics_read(struct file *t_file, + char __user *t_char, size_t t_size_t, loff_t *t_loff_t) +{ + int i; + uint64_t *ptr; + char buffer[OVERFLOW_BUFFER_LENGTH] = {0}; + struct vfe_device *vfe_dev = (struct vfe_device *) + t_file->private_data; + struct msm_isp_statistics *stats = vfe_dev->stats; + + memset(stat_line, 0, sizeof(stat_line)); + msm_isp_util_get_bandwidth_stats(vfe_dev, stats); + ptr = (uint64_t *)(stats); + for (i = 0; i < MAX_OVERFLOW_COUNTERS; i++) { + strlcat(stat_line, stats_str[i], sizeof(stat_line)); + strlcat(stat_line, " ", sizeof(stat_line)); + snprintf(buffer, sizeof(buffer), "%llu", ptr[i]); + strlcat(stat_line, buffer, sizeof(stat_line)); + strlcat(stat_line, "\r\n", sizeof(stat_line)); + } + return simple_read_from_buffer(t_char, t_size_t, + t_loff_t, stat_line, strlen(stat_line)); +} + +static ssize_t vfe_debugfs_statistics_write(struct file *t_file, + const char __user *t_char, size_t t_size_t, loff_t *t_loff_t) +{ + struct vfe_device *vfe_dev = (struct vfe_device *) + t_file->private_data; + struct msm_isp_statistics *stats = vfe_dev->stats; + + memset(stats, 0, sizeof(struct msm_isp_statistics)); + + return sizeof(struct msm_isp_statistics); +} + +static int bw_history_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t bw_history_read(struct file *t_file, char __user *t_char, + size_t t_size_t, loff_t *t_loff_t) +{ + int i; + char *out_buffer = bw_request_history_buff; + char line_buffer[MAX_BW_HISTORY_LINE_BUFF_LEN] = {0}; + struct msm_isp_bw_req_info *isp_req_hist = + (struct msm_isp_bw_req_info *) t_file->private_data; + + memset(out_buffer, 0, MAX_BW_HISTORY_BUFF_LEN); + + snprintf(line_buffer, sizeof(line_buffer), + "Bus bandwidth request history in chronological order:\n"); + strlcat(out_buffer, line_buffer, sizeof(bw_request_history_buff)); + + snprintf(line_buffer, sizeof(line_buffer), + "MSM_ISP_MIN_AB = %u, MSM_ISP_MIN_IB = %u\n\n", + MSM_ISP_MIN_AB, MSM_ISP_MIN_IB); + strlcat(out_buffer, line_buffer, sizeof(bw_request_history_buff)); + + for (i = 0; i < MAX_DEPTH_BW_REQ_HISTORY; i++) { + snprintf(line_buffer, sizeof(line_buffer), + "idx = %d, client = %u, timestamp = %llu, ab = %llu, ib = %llu\n" + "ISP0.active = %x, ISP0.ab = %llu, ISP0.ib = %llu\n" + "ISP1.active = %x, ISP1.ab = %llu, ISP1.ib = %llu\n" + "CPP.active = %x, CPP.ab = %llu, CPP.ib = %llu\n\n", + i, isp_req_hist[i].client, isp_req_hist[i].timestamp, + isp_req_hist[i].total_ab, isp_req_hist[i].total_ib, + isp_req_hist[i].client_info[0].active, + isp_req_hist[i].client_info[0].ab, + isp_req_hist[i].client_info[0].ib, + isp_req_hist[i].client_info[1].active, + isp_req_hist[i].client_info[1].ab, + isp_req_hist[i].client_info[1].ib, + isp_req_hist[i].client_info[2].active, + isp_req_hist[i].client_info[2].ab, + isp_req_hist[i].client_info[2].ib); + strlcat(out_buffer, line_buffer, + sizeof(bw_request_history_buff)); + } + return simple_read_from_buffer(t_char, t_size_t, + t_loff_t, out_buffer, strlen(out_buffer)); +} + +static ssize_t bw_history_write(struct file *t_file, + const char __user *t_char, size_t t_size_t, loff_t *t_loff_t) +{ + struct msm_isp_bw_req_info *isp_req_hist = + (struct msm_isp_bw_req_info *) t_file->private_data; + + memset(isp_req_hist, 0, sizeof(msm_isp_bw_request_history)); + msm_isp_bw_request_history_idx = 0; + return sizeof(msm_isp_bw_request_history); +} + +static int ub_info_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t ub_info_read(struct file *t_file, char __user *t_char, + size_t t_size_t, loff_t *t_loff_t) +{ + int i; + char *out_buffer = ub_info_buffer; + char line_buffer[MAX_UB_INFO_LINE_BUFF_LEN] = {0}; + struct vfe_device *vfe_dev = + (struct vfe_device *) t_file->private_data; + struct msm_isp_ub_info *ub_info = vfe_dev->ub_info; + + memset(out_buffer, 0, MAX_UB_INFO_LINE_BUFF_LEN); + snprintf(line_buffer, sizeof(line_buffer), + "wm_ub_policy_type = %d\n" + "num_wm = %d\n" + "wm_ub = %d\n", + ub_info->policy, ub_info->num_wm, ub_info->wm_ub); + strlcat(out_buffer, line_buffer, + sizeof(ub_info_buffer)); + for (i = 0; i < ub_info->num_wm; i++) { + snprintf(line_buffer, sizeof(line_buffer), + "data[%d] = 0x%x, addr[%d] = 0x%llx\n", + i, ub_info->data[i], i, ub_info->addr[i]); + strlcat(out_buffer, line_buffer, + sizeof(ub_info_buffer)); + } + + return simple_read_from_buffer(t_char, t_size_t, + t_loff_t, out_buffer, strlen(out_buffer)); +} + +static ssize_t ub_info_write(struct file *t_file, + const char __user *t_char, size_t t_size_t, loff_t *t_loff_t) +{ + struct vfe_device *vfe_dev = + (struct vfe_device *) t_file->private_data; + struct msm_isp_ub_info *ub_info = vfe_dev->ub_info; + + memset(ub_info, 0, sizeof(struct msm_isp_ub_info)); + + return sizeof(struct msm_isp_ub_info); +} + +static const struct file_operations vfe_debugfs_error = { + .open = vfe_debugfs_statistics_open, + .read = vfe_debugfs_statistics_read, + .write = vfe_debugfs_statistics_write, +}; + +static const struct file_operations bw_history_ops = { + .open = bw_history_open, + .read = bw_history_read, + .write = bw_history_write, +}; + +static const struct file_operations ub_info_ops = { + .open = ub_info_open, + .read = ub_info_read, + .write = ub_info_write, +}; + +static int msm_isp_enable_debugfs(struct vfe_device *vfe_dev, + struct msm_isp_bw_req_info *isp_req_hist) +{ + struct dentry *debugfs_base; + char dirname[32] = {0}; + + snprintf(dirname, sizeof(dirname), "msm_isp%d", vfe_dev->pdev->id); + debugfs_base = debugfs_create_dir(dirname, NULL); + if (!debugfs_base) + return -ENOMEM; + if (!debugfs_create_file("stats", 0644, debugfs_base, + vfe_dev, &vfe_debugfs_error)) + return -ENOMEM; + + if (!debugfs_create_file("bw_req_history", 0644, + debugfs_base, isp_req_hist, &bw_history_ops)) + return -ENOMEM; + + if (!debugfs_create_file("ub_info", 0644, + debugfs_base, vfe_dev, &ub_info_ops)) + return -ENOMEM; + + return 0; +} + +void msm_isp_update_req_history(uint32_t client, uint64_t ab, + uint64_t ib, + struct msm_isp_bandwidth_info *client_info, + unsigned long long ts) +{ + int i; + + spin_lock(&req_history_lock); + msm_isp_bw_request_history[msm_isp_bw_request_history_idx].client = + client; + msm_isp_bw_request_history[msm_isp_bw_request_history_idx].timestamp = + ts; + msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ab = + ab; + msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ib = + ib; + + for (i = 0; i < MAX_ISP_CLIENT; i++) { + msm_isp_bw_request_history[msm_isp_bw_request_history_idx]. + client_info[i].active = client_info[i].active; + msm_isp_bw_request_history[msm_isp_bw_request_history_idx]. + client_info[i].ab = client_info[i].ab; + msm_isp_bw_request_history[msm_isp_bw_request_history_idx]. + client_info[i].ib = client_info[i].ib; + } + + msm_isp_bw_request_history_idx = (msm_isp_bw_request_history_idx + 1) + % MAX_DEPTH_BW_REQ_HISTORY; + spin_unlock(&req_history_lock); +} + +#ifdef CONFIG_COMPAT +static long msm_isp_dqevent(struct file *file, struct v4l2_fh *vfh, void *arg) +{ + long rc; + + if (is_compat_task()) { + struct msm_isp32_event_data32 *event_data32; + struct msm_isp32_event_data *event_data; + struct v4l2_event isp_event; + struct v4l2_event *isp_event_user; + + memset(&isp_event, 0, sizeof(isp_event)); + rc = v4l2_event_dequeue(vfh, &isp_event, + file->f_flags & O_NONBLOCK); + if (rc) + return rc; + event_data = (struct msm_isp32_event_data *) + isp_event.u.data; + isp_event_user = (struct v4l2_event *)arg; + memcpy(isp_event_user, &isp_event, + sizeof(*isp_event_user)); + event_data32 = (struct msm_isp32_event_data32 *) + isp_event_user->u.data; + memset(event_data32, 0, + sizeof(struct msm_isp32_event_data32)); + event_data32->timestamp.tv_sec = + event_data->timestamp.tv_sec; + event_data32->timestamp.tv_usec = + event_data->timestamp.tv_usec; + event_data32->mono_timestamp.tv_sec = + event_data->mono_timestamp.tv_sec; + event_data32->mono_timestamp.tv_usec = + event_data->mono_timestamp.tv_usec; + event_data32->input_intf = event_data->input_intf; + event_data32->frame_id = event_data->frame_id; + memcpy(&(event_data32->u), &(event_data->u), + sizeof(event_data32->u)); + } else { + rc = v4l2_event_dequeue(vfh, arg, + file->f_flags & O_NONBLOCK); + } + return rc; +} +#else +static long msm_isp_dqevent(struct file *file, struct v4l2_fh *vfh, void *arg) +{ + return v4l2_event_dequeue(vfh, arg, + file->f_flags & O_NONBLOCK); +} +#endif + +static long msm_isp_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + struct v4l2_fh *vfh = file->private_data; + + switch (cmd) { + case VIDIOC_DQEVENT: { + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) + return -ENOIOCTLCMD; + return msm_isp_dqevent(file, vfh, arg); + } + break; + case VIDIOC_SUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); + + case VIDIOC_UNSUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); + + default: + return v4l2_subdev_call(sd, core, ioctl, cmd, arg); + } +} + +static long msm_isp_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, msm_isp_subdev_do_ioctl); +} + +static struct v4l2_file_operations msm_isp_v4l2_subdev_fops = { +#ifdef CONFIG_COMPAT + .compat_ioctl32 = msm_isp_subdev_fops_ioctl, +#endif + .unlocked_ioctl = msm_isp_subdev_fops_ioctl +}; + +static int vfe_probe(struct platform_device *pdev) +{ + struct vfe_device *vfe_dev; + /*struct msm_cam_subdev_info sd_info;*/ + const struct of_device_id *match_dev; + int rc = 0; + + vfe_dev = kzalloc(sizeof(struct vfe_device), GFP_KERNEL); + if (!vfe_dev) { + rc = -ENOMEM; + goto end; + } + vfe_dev->stats = kzalloc(sizeof(struct msm_isp_statistics), GFP_KERNEL); + if (!vfe_dev->stats) { + rc = -ENOMEM; + goto probe_fail1; + } + + vfe_dev->ub_info = kzalloc(sizeof(struct msm_isp_ub_info), GFP_KERNEL); + if (!vfe_dev->ub_info) { + rc = -ENOMEM; + goto probe_fail2; + } + if (pdev->dev.of_node) { + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + match_dev = of_match_device(msm_vfe_dt_match, &pdev->dev); + if (!match_dev) { + pr_err("%s: No vfe hardware info\n", __func__); + rc = -EINVAL; + goto probe_fail3; + } + vfe_dev->hw_info = + (struct msm_vfe_hardware_info *) match_dev->data; + } else { + vfe_dev->hw_info = (struct msm_vfe_hardware_info *) + platform_get_device_id(pdev)->driver_data; + } + + if (!vfe_dev->hw_info) { + pr_err("%s: No vfe hardware info\n", __func__); + rc = -EINVAL; + goto probe_fail3; + } + ISP_DBG("%s: device id = %d\n", __func__, pdev->id); + + vfe_dev->pdev = pdev; + rc = vfe_dev->hw_info->vfe_ops.core_ops.get_platform_data(vfe_dev); + if (rc < 0) { + pr_err("%s: failed to get platform resources\n", __func__); + rc = -ENOMEM; + goto probe_fail3; + } + + INIT_LIST_HEAD(&vfe_dev->tasklet_q); + tasklet_init(&vfe_dev->vfe_tasklet, + msm_isp_do_tasklet, (unsigned long)vfe_dev); + + v4l2_subdev_init(&vfe_dev->subdev.sd, vfe_dev->hw_info->subdev_ops); + vfe_dev->subdev.sd.internal_ops = + vfe_dev->hw_info->subdev_internal_ops; + snprintf(vfe_dev->subdev.sd.name, + ARRAY_SIZE(vfe_dev->subdev.sd.name), + "vfe"); + vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + v4l2_set_subdevdata(&vfe_dev->subdev.sd, vfe_dev); + platform_set_drvdata(pdev, &vfe_dev->subdev.sd); + mutex_init(&vfe_dev->realtime_mutex); + mutex_init(&vfe_dev->core_mutex); + spin_lock_init(&vfe_dev->tasklet_lock); + spin_lock_init(&vfe_dev->shared_data_lock); + spin_lock_init(&req_history_lock); + media_entity_pads_init(&vfe_dev->subdev.sd.entity, 0, NULL); + vfe_dev->subdev.sd.entity.function = MSM_CAMERA_SUBDEV_VFE; + vfe_dev->subdev.sd.entity.name = pdev->name; + vfe_dev->subdev.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x2; + rc = msm_sd_register(&vfe_dev->subdev); + if (rc != 0) { + pr_err("%s: msm_sd_register error = %d\n", __func__, rc); + goto probe_fail3; + } + + msm_isp_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; + msm_isp_v4l2_subdev_fops.open = v4l2_subdev_fops.open; + msm_isp_v4l2_subdev_fops.release = v4l2_subdev_fops.release; + msm_isp_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; + + vfe_dev->subdev.sd.devnode->fops = &msm_isp_v4l2_subdev_fops; + + vfe_dev->buf_mgr = &vfe_buf_mgr; + v4l2_subdev_notify(&vfe_dev->subdev.sd, + MSM_SD_NOTIFY_REQ_CB, &vfe_vb2_ops); + rc = msm_isp_create_isp_buf_mgr(vfe_dev->buf_mgr, + &vfe_vb2_ops, &pdev->dev, + vfe_dev->hw_info->axi_hw_info->scratch_buf_range); + if (rc < 0) { + pr_err("%s: Unable to create buffer manager\n", __func__); + rc = -EINVAL; + goto probe_fail3; + } + msm_isp_enable_debugfs(vfe_dev, msm_isp_bw_request_history); + + vfe_dev->buf_mgr->init_done = 1; + vfe_dev->vfe_open_cnt = 0; + return rc; + +probe_fail3: + kfree(vfe_dev->ub_info); +probe_fail2: + kfree(vfe_dev->stats); +probe_fail1: + kfree(vfe_dev); +end: + return rc; +} + +static struct platform_driver vfe_driver = { + .probe = vfe_probe, + .driver = { + .name = "msm_vfe", + .owner = THIS_MODULE, + .of_match_table = msm_vfe_dt_match, + }, + .id_table = msm_vfe_dev_id, +}; + +static int __init msm_vfe_init_module(void) +{ + return platform_driver_register(&vfe_driver); +} + +static void __exit msm_vfe_exit_module(void) +{ + platform_driver_unregister(&vfe_driver); +} + +module_init(msm_vfe_init_module); +module_exit(msm_vfe_exit_module); +MODULE_DESCRIPTION("MSM VFE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_32.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_32.h new file mode 100644 index 000000000000..cbe92faa876c --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_32.h @@ -0,0 +1,599 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MSM_VFE_H__ +#define __MSM_VFE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_buf_mgr.h" + +#define VFE40_8974V1_VERSION 0x10000018 +#define VFE40_8974V2_VERSION 0x1001001A +#define VFE40_8974V3_VERSION 0x1001001B +#define VFE40_8x26_VERSION 0x20000013 +#define VFE40_8x26V2_VERSION 0x20010014 +#define VFE40_8916_VERSION 0x10030000 +#define VFE40_8939_VERSION 0x10040000 +#define VFE32_8909_VERSION 0x30600 + +#define MAX_IOMMU_CTX 2 +#define MAX_NUM_WM 7 +#define MAX_NUM_RDI 3 +#define MAX_NUM_RDI_MASTER 3 +#define MAX_NUM_COMPOSITE_MASK 4 +#define MAX_NUM_STATS_COMP_MASK 2 +#define MAX_INIT_FRAME_DROP 31 +#define ISP_Q2 (1 << 2) +#define ISP_Q10 (1 << 10) + +#define VFE_PING_FLAG 0xFFFFFFFF +#define VFE_PONG_FLAG 0x0 + +#define VFE_MAX_CFG_TIMEOUT 3000 +#define VFE_CLK_INFO_MAX 16 +#define STATS_COMP_BIT_MASK 0xFF0000 + +#define MSM_ISP_MIN_AB 11000000 +#define MSM_ISP_MIN_IB 11000000 + +struct vfe_device; +struct msm_vfe_axi_stream; +struct msm_vfe_stats_stream; + +struct vfe_subscribe_info { + struct v4l2_fh *vfh; + uint32_t active; +}; + +enum msm_isp_pack_fmt { + QCOM, + MIPI, + DPCM6, + DPCM8, + PLAIN8, + PLAIN16, + MAX_ISP_PACK_FMT, +}; + +enum msm_isp_camif_update_state { + NO_UPDATE, + ENABLE_CAMIF, + DISABLE_CAMIF, + DISABLE_CAMIF_IMMEDIATELY +}; + +struct msm_isp_timestamp { + /*Monotonic clock for v4l2 buffer*/ + struct timeval buf_time; + /*Monotonic clock for VT */ + struct timeval vt_time; + /*Wall clock for userspace event*/ + struct timeval event_time; +}; + +struct msm_vfe_irq_ops { + void (*read_irq_status)(struct vfe_device *vfe_dev, + uint32_t *irq_status0, uint32_t *irq_status1); + void (*process_reg_update)(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); + void (*process_epoch_irq)(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); + void (*process_reset_irq)(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1); + void (*process_halt_irq)(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1); + void (*process_camif_irq)(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); + void (*process_axi_irq)(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); + void (*process_stats_irq)(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); +}; + +struct msm_vfe_axi_ops { + void (*reload_wm)(struct vfe_device *vfe_dev, + uint32_t reload_mask); + void (*enable_wm)(struct vfe_device *vfe_dev, + uint8_t wm_idx, uint8_t enable); + int32_t (*cfg_io_format)(struct vfe_device *vfe_dev, + enum msm_vfe_axi_stream_src stream_src, + uint32_t io_format); + void (*cfg_framedrop)(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*clear_framedrop)(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*cfg_comp_mask)(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*clear_comp_mask)(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*cfg_wm_irq_mask)(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*clear_wm_irq_mask)(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + + void (*cfg_wm_reg)(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx); + void (*clear_wm_reg)(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx); + + void (*cfg_wm_xbar_reg)(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx); + void (*clear_wm_xbar_reg)(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx); + + void (*cfg_ub)(struct vfe_device *vfe_dev); + + void (*update_ping_pong_addr)(struct vfe_device *vfe_dev, + uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr); + + uint32_t (*get_wm_mask)(uint32_t irq_status0, uint32_t irq_status1); + uint32_t (*get_comp_mask)(uint32_t irq_status0, uint32_t irq_status1); + uint32_t (*get_pingpong_status)(struct vfe_device *vfe_dev); + int (*halt)(struct vfe_device *vfe_dev, uint32_t blocking); + int (*restart)(struct vfe_device *vfe_dev, uint32_t blocking, + uint32_t enable_camif); + void (*update_cgc_override)(struct vfe_device *vfe_dev, + uint8_t wm_idx, uint8_t cgc_override); +}; + +struct msm_vfe_core_ops { + void (*reg_update)(struct vfe_device *vfe_dev, uint32_t input_src); + long (*reset_hw)(struct vfe_device *vfe_dev, uint32_t first_start, + uint32_t blocking_call); + int (*init_hw)(struct vfe_device *vfe_dev); + void (*init_hw_reg)(struct vfe_device *vfe_dev); + void (*clear_status_reg)(struct vfe_device *vfe_dev); + void (*release_hw)(struct vfe_device *vfe_dev); + void (*cfg_input_mux)(struct vfe_device *vfe_dev, + struct msm_vfe_pix_cfg *pix_cfg); + int (*start_fetch_eng)(struct vfe_device *vfe_dev, + void *arg); + void (*update_camif_state)(struct vfe_device *vfe_dev, + enum msm_isp_camif_update_state update_state); + void (*cfg_rdi_reg)(struct vfe_device *vfe_dev, + struct msm_vfe_rdi_cfg *rdi_cfg, + enum msm_vfe_input_src input_src); + int (*get_platform_data)(struct vfe_device *vfe_dev); + void (*get_error_mask)(uint32_t *error_mask0, uint32_t *error_mask1); + void (*process_error_status)(struct vfe_device *vfe_dev); + void (*get_overflow_mask)(uint32_t *overflow_mask); + void (*get_irq_mask)(struct vfe_device *vfe_dev, + uint32_t *irq0_mask, uint32_t *irq1_mask); + void (*restore_irq_mask)(struct vfe_device *vfe_dev); + void (*get_halt_restart_mask)(uint32_t *irq0_mask, + uint32_t *irq1_mask); + void (*get_rdi_wm_mask)(struct vfe_device *vfe_dev, + uint32_t *rdi_wm_mask); +}; +struct msm_vfe_stats_ops { + int (*get_stats_idx)(enum msm_isp_stats_type stats_type); + int (*check_streams)(struct msm_vfe_stats_stream *stream_info); + void (*cfg_framedrop)(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + void (*clear_framedrop)(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + void (*cfg_comp_mask)(struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable); + void (*cfg_wm_irq_mask)(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + void (*clear_wm_irq_mask)(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + + void (*cfg_wm_reg)(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + void (*clear_wm_reg)(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + + void (*cfg_ub)(struct vfe_device *vfe_dev); + + void (*enable_module)(struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable); + + void (*update_ping_pong_addr)(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info, + uint32_t pingpong_status, dma_addr_t paddr); + + uint32_t (*get_frame_id)(struct vfe_device *vfe_dev); + uint32_t (*get_wm_mask)(uint32_t irq_status0, uint32_t irq_status1); + uint32_t (*get_comp_mask)(uint32_t irq_status0, uint32_t irq_status1); + uint32_t (*get_pingpong_status)(struct vfe_device *vfe_dev); + + void (*update_cgc_override)(struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable); +}; + +struct msm_vfe_ops { + struct msm_vfe_irq_ops irq_ops; + struct msm_vfe_axi_ops axi_ops; + struct msm_vfe_core_ops core_ops; + struct msm_vfe_stats_ops stats_ops; +}; + +struct msm_vfe_hardware_info { + int num_iommu_ctx; + /* secure iommu ctx nums */ + int num_iommu_secure_ctx; + int vfe_clk_idx; + struct msm_vfe_ops vfe_ops; + struct msm_vfe_axi_hardware_info *axi_hw_info; + struct msm_vfe_stats_hardware_info *stats_hw_info; + struct v4l2_subdev_internal_ops *subdev_internal_ops; + struct v4l2_subdev_ops *subdev_ops; + uint32_t dmi_reg_offset; +}; + +struct msm_vfe_axi_hardware_info { + uint8_t num_wm; + uint8_t num_rdi; + uint8_t num_rdi_master; + uint8_t num_comp_mask; + uint32_t min_wm_ub; + uint32_t scratch_buf_range; +}; + +enum msm_vfe_axi_state { + AVAILABLE, + INACTIVE, + ACTIVE, + PAUSED, + START_PENDING, + STOP_PENDING, + PAUSE_PENDING, + RESUME_PENDING, + STARTING, + STOPPING, + PAUSING, + RESUMING, +}; + +enum msm_vfe_axi_cfg_update_state { + NO_AXI_CFG_UPDATE, + APPLYING_UPDATE_RESUME, + UPDATE_REQUESTED, +}; + +#define VFE_NO_DROP 0xFFFFFFFF +#define VFE_DROP_EVERY_2FRAME 0x55555555 +#define VFE_DROP_EVERY_4FRAME 0x11111111 +#define VFE_DROP_EVERY_8FRAME 0x01010101 +#define VFE_DROP_EVERY_16FRAME 0x00010001 +#define VFE_DROP_EVERY_32FRAME 0x00000001 + +enum msm_vfe_axi_stream_type { + CONTINUOUS_STREAM, + BURST_STREAM, +}; + +struct msm_vfe_axi_stream { + uint32_t frame_id; + enum msm_vfe_axi_state state; + enum msm_vfe_axi_stream_src stream_src; + uint8_t num_planes; + uint8_t wm[MAX_PLANES_PER_STREAM]; + uint32_t output_format;/*Planar/RAW/Misc*/ + struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM]; + uint8_t comp_mask_index; + struct msm_isp_buffer *buf[2]; + uint32_t session_id; + uint32_t stream_id; + uint32_t bufq_handle; + uint32_t bufq_scratch_handle; + uint32_t controllable_output; + uint32_t stream_handle; + uint32_t request_frm_num; + uint8_t buf_divert; + enum msm_vfe_axi_stream_type stream_type; + uint32_t frame_based; + enum msm_vfe_frame_skip_pattern frame_skip_pattern; + uint32_t framedrop_period; + uint32_t framedrop_pattern; + uint32_t num_burst_capture;/*number of frame to capture*/ + uint32_t init_frame_drop; + uint32_t burst_frame_count;/*number of sof before burst stop*/ + uint8_t framedrop_update; + spinlock_t lock; + + /*Bandwidth calculation info*/ + uint32_t max_width; + /*Based on format plane size in Q2. e.g NV12 = 1.5*/ + uint32_t format_factor; + uint32_t bandwidth; + + /*Run time update variables*/ + uint32_t runtime_init_frame_drop; + uint32_t runtime_burst_frame_count;/*number of sof before burst stop*/ + uint32_t runtime_num_burst_capture; + uint8_t runtime_framedrop_update; + uint8_t runtime_framedrop_update_burst; + uint32_t runtime_output_format; + enum msm_stream_memory_input_t memory_input; +}; + +struct msm_vfe_axi_composite_info { + uint32_t stream_handle; + uint32_t stream_composite_mask; +}; + +struct msm_vfe_src_info { + uint32_t frame_id; + uint8_t active; + uint8_t pix_stream_count; + uint8_t raw_stream_count; + enum msm_vfe_inputmux input_mux; + uint32_t width; + long pixel_clock; + uint32_t input_format;/*V4L2 pix format with bayer pattern*/ + uint32_t last_updt_frm_id; +}; + +struct msm_vfe_fetch_engine_info { + uint32_t session_id; + uint32_t stream_id; + uint32_t bufq_handle; + uint32_t buf_idx; + uint8_t is_busy; +}; + +enum msm_wm_ub_cfg_type { + MSM_WM_UB_CFG_DEFAULT, + MSM_WM_UB_EQUAL_SLICING, + MSM_WM_UB_CFG_MAX_NUM +}; + +struct msm_vfe_axi_shared_data { + struct msm_vfe_axi_hardware_info *hw_info; + struct msm_vfe_axi_stream stream_info[VFE_AXI_SRC_MAX]; + uint32_t free_wm[MAX_NUM_WM]; + uint32_t wm_image_size[MAX_NUM_WM]; + enum msm_wm_ub_cfg_type wm_ub_cfg_policy; + uint8_t num_used_wm; + uint8_t num_active_stream; + uint8_t num_rdi_stream; + uint8_t num_pix_stream; + uint32_t rdi_wm_mask; + struct msm_vfe_axi_composite_info + composite_info[MAX_NUM_COMPOSITE_MASK]; + uint8_t num_used_composite_mask; + uint32_t stream_update; + atomic_t axi_cfg_update; + enum msm_isp_camif_update_state pipeline_update; + struct msm_vfe_src_info src_info[VFE_SRC_MAX]; + uint16_t stream_handle_cnt; + uint32_t event_mask; +}; + +struct msm_vfe_stats_hardware_info { + uint32_t stats_capability_mask; + uint8_t *stats_ping_pong_offset; + uint8_t num_stats_type; + uint8_t num_stats_comp_mask; +}; + +enum msm_vfe_stats_state { + STATS_AVAILABLE, + STATS_INACTIVE, + STATS_ACTIVE, + STATS_START_PENDING, + STATS_STOP_PENDING, + STATS_STARTING, + STATS_STOPPING, +}; + +struct msm_vfe_stats_stream { + uint32_t session_id; + uint32_t stream_id; + uint32_t stream_handle; + uint32_t composite_flag; + enum msm_isp_stats_type stats_type; + enum msm_vfe_stats_state state; + uint32_t framedrop_pattern; + uint32_t framedrop_period; + uint32_t irq_subsample_pattern; + uint32_t init_stats_frame_drop; + + uint32_t buffer_offset; + struct msm_isp_buffer *buf[2]; + uint32_t bufq_handle; +}; + +struct msm_vfe_stats_shared_data { + struct msm_vfe_stats_stream stream_info[MSM_ISP_STATS_MAX]; + uint8_t num_active_stream; + atomic_t stats_comp_mask[MAX_NUM_STATS_COMP_MASK]; + uint32_t reg_mask; + uint16_t stream_handle_cnt; + atomic_t stats_update; +}; + +struct msm_vfe_tasklet_queue_cmd { + struct list_head list; + uint32_t vfeInterruptStatus0; + uint32_t vfeInterruptStatus1; + struct msm_isp_timestamp ts; + uint8_t cmd_used; +}; + +#define MSM_VFE_TASKLETQ_SIZE 200 + +enum msm_vfe_overflow_state { + NO_OVERFLOW, + OVERFLOW_DETECTED, + HALT_REQUESTED, + RESTART_REQUESTED, +}; + +struct msm_vfe_error_info { + atomic_t overflow_state; + uint32_t overflow_recover_irq_mask0; + uint32_t overflow_recover_irq_mask1; + uint32_t error_mask0; + uint32_t error_mask1; + uint32_t violation_status; + uint32_t camif_status; + uint32_t stream_framedrop_count[MAX_NUM_STREAM]; + uint32_t stats_framedrop_count[MSM_ISP_STATS_MAX]; + uint32_t info_dump_frame_count; + uint32_t error_count; +}; + +struct msm_isp_statistics { + int64_t imagemaster0_overflow; + int64_t imagemaster1_overflow; + int64_t imagemaster2_overflow; + int64_t imagemaster3_overflow; + int64_t imagemaster4_overflow; + int64_t imagemaster5_overflow; + int64_t imagemaster6_overflow; + int64_t be_overflow; + int64_t bg_overflow; + int64_t bf_overflow; + int64_t awb_overflow; + int64_t rs_overflow; + int64_t cs_overflow; + int64_t ihist_overflow; + int64_t skinbhist_overflow; + int64_t bfscale_overflow; + + int64_t isp_vfe0_active; + int64_t isp_vfe0_ab; + int64_t isp_vfe0_ib; + + int64_t isp_vfe1_active; + int64_t isp_vfe1_ab; + int64_t isp_vfe1_ib; + + int64_t isp_cpp_active; + int64_t isp_cpp_ab; + int64_t isp_cpp_ib; + + int64_t last_overflow_ab; + int64_t last_overflow_ib; + + int64_t vfe_clk_rate; + int64_t cpp_clk_rate; +}; + +enum msm_isp_hw_client { + ISP_VFE0, + ISP_VFE1, + ISP_CPP, + MAX_ISP_CLIENT, +}; + +struct msm_isp_bandwidth_info { + uint32_t active; + uint64_t ab; + uint64_t ib; +}; + +struct msm_isp_bw_req_info { + uint32_t client; + unsigned long long timestamp; + uint64_t total_ab; + uint64_t total_ib; + struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT]; +}; + +#define MSM_ISP_MAX_WM 7 +struct msm_isp_ub_info { + enum msm_wm_ub_cfg_type policy; + uint8_t num_wm; + uint32_t wm_ub; + uint32_t data[MSM_ISP_MAX_WM]; + uint64_t addr[MSM_ISP_MAX_WM]; +}; + +struct msm_vfe_hw_init_parms { + const char *entries; + const char *regs; + const char *settings; +}; + +struct vfe_device { + struct platform_device *pdev; + struct msm_sd_subdev subdev; + struct resource *vfe_irq; + struct resource *vfe_mem; + struct resource *vfe_vbif_mem; + struct resource *vfe_io; + struct resource *vfe_vbif_io; + void __iomem *vfe_base; + void __iomem *vfe_vbif_base; + + struct device *iommu_ctx[MAX_IOMMU_CTX]; + /*Add secure context banks*/ + struct device *iommu_secure_ctx[MAX_IOMMU_CTX]; + + struct regulator *fs_vfe; + struct clk **vfe_clk; + uint32_t num_clk; + + uint32_t bus_perf_client; + + struct completion reset_complete; + struct completion halt_complete; + struct completion stream_config_complete; + struct completion stats_config_complete; + struct mutex realtime_mutex; + struct mutex core_mutex; + + atomic_t irq_cnt; + uint8_t taskletq_idx; + spinlock_t tasklet_lock; + spinlock_t shared_data_lock; + struct list_head tasklet_q; + struct tasklet_struct vfe_tasklet; + struct msm_vfe_tasklet_queue_cmd + tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE]; + + uint32_t vfe_hw_version; + struct msm_vfe_hardware_info *hw_info; + struct msm_vfe_axi_shared_data axi_data; + struct msm_vfe_stats_shared_data stats_data; + struct msm_vfe_error_info error_info; + struct msm_isp_buf_mgr *buf_mgr; + int dump_reg; + int vfe_clk_idx; + uint32_t vfe_open_cnt; + uint8_t vt_enable; + uint8_t ignore_error; + struct msm_isp_statistics *stats; + struct msm_vfe_fetch_engine_info fetch_engine_info; + uint64_t msm_isp_last_overflow_ab; + uint64_t msm_isp_last_overflow_ib; + uint64_t msm_isp_vfe_clk_rate; + struct msm_isp_ub_info *ub_info; + uint32_t vfe_ub_policy; + uint32_t isp_sof_debug; + uint8_t reset_pending; + uint32_t bus_util_factor; + uint8_t vfe_reset_timeout_processed; +}; + +#endif diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c new file mode 100644 index 000000000000..55a10ca7e559 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c @@ -0,0 +1,2095 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include "msm_isp_util_32.h" +#include "msm_isp_axi_util_32.h" + +#define SRC_TO_INTF(src) \ + ((src < RDI_INTF_0 || src == VFE_AXI_SRC_MAX) ? VFE_PIX_0 : \ + (VFE_RAW_0 + src - RDI_INTF_0)) + +#define HANDLE_TO_IDX(handle) (handle & 0xFF) + +int msm_isp_axi_create_stream( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe32_axi_stream_request_cmd *stream_cfg_cmd) +{ + uint32_t i = stream_cfg_cmd->stream_src; + + if (i >= VFE_AXI_SRC_MAX) { + pr_err("%s:%d invalid stream_src %d\n", __func__, __LINE__, + stream_cfg_cmd->stream_src); + return -EINVAL; + } + + if ((axi_data->stream_handle_cnt << 8) == 0) + axi_data->stream_handle_cnt++; + + stream_cfg_cmd->axi_stream_handle = + (++axi_data->stream_handle_cnt) << 8 | i; + + memset(&axi_data->stream_info[i], 0, + sizeof(struct msm_vfe_axi_stream)); + spin_lock_init(&axi_data->stream_info[i].lock); + axi_data->stream_info[i].session_id = stream_cfg_cmd->session_id; + axi_data->stream_info[i].stream_id = stream_cfg_cmd->stream_id; + axi_data->stream_info[i].buf_divert = stream_cfg_cmd->buf_divert; + axi_data->stream_info[i].state = INACTIVE; + axi_data->stream_info[i].stream_handle = + stream_cfg_cmd->axi_stream_handle; + axi_data->stream_info[i].controllable_output = + stream_cfg_cmd->controllable_output; + if (stream_cfg_cmd->controllable_output) + stream_cfg_cmd->frame_skip_pattern = SKIP_ALL; + return 0; +} + +void msm_isp_axi_destroy_stream( + struct msm_vfe_axi_shared_data *axi_data, int stream_idx) +{ + if (axi_data->stream_info[stream_idx].state != AVAILABLE) { + axi_data->stream_info[stream_idx].state = AVAILABLE; + axi_data->stream_info[stream_idx].stream_handle = 0; + } else { + pr_err("%s: stream does not exist\n", __func__); + } +} + +int msm_isp_validate_axi_request(struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe32_axi_stream_request_cmd *stream_cfg_cmd) +{ + int rc = -1, i; + struct msm_vfe_axi_stream *stream_info = NULL; + + if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) < MAX_NUM_STREAM) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; + } else { + pr_err("%s: Invalid axi_stream_handle\n", __func__); + return rc; + } + + if (!stream_info) { + pr_err("%s: Stream info is NULL\n", __func__); + return -EINVAL; + } + + switch (stream_cfg_cmd->output_format) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_SBGGR14: + case V4L2_PIX_FMT_SGBRG14: + case V4L2_PIX_FMT_SGRBG14: + case V4L2_PIX_FMT_SRGGB14: + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + case V4L2_PIX_FMT_QBGGR14: + case V4L2_PIX_FMT_QGBRG14: + case V4L2_PIX_FMT_QGRBG14: + case V4L2_PIX_FMT_QRGGB14: + case V4L2_PIX_FMT_P16BGGR10: + case V4L2_PIX_FMT_P16GBRG10: + case V4L2_PIX_FMT_P16GRBG10: + case V4L2_PIX_FMT_P16RGGB10: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_META: + stream_info->num_planes = 1; + stream_info->format_factor = ISP_Q2; + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV41: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + stream_info->num_planes = 2; + stream_info->format_factor = 1.5 * ISP_Q2; + break; + /*TD: Add more image format*/ + default: + msm_isp_print_fourcc_error(__func__, + stream_cfg_cmd->output_format); + return rc; + } + + if (axi_data->hw_info->num_wm - axi_data->num_used_wm < + stream_info->num_planes) { + pr_err("%s: No free write masters\n", __func__); + return rc; + } + + if ((stream_info->num_planes > 1) && + (axi_data->hw_info->num_comp_mask - + axi_data->num_used_composite_mask < 1)) { + pr_err("%s: No free composite mask\n", __func__); + return rc; + } + + if (stream_cfg_cmd->init_frame_drop >= MAX_INIT_FRAME_DROP) { + pr_err("%s: Invalid skip pattern\n", __func__); + return rc; + } + + if (stream_cfg_cmd->frame_skip_pattern >= MAX_SKIP) { + pr_err("%s: Invalid skip pattern\n", __func__); + return rc; + } + + for (i = 0; i < stream_info->num_planes; i++) { + stream_info->plane_cfg[i] = stream_cfg_cmd->plane_cfg[i]; + stream_info->max_width = max(stream_info->max_width, + stream_cfg_cmd->plane_cfg[i].output_width); + } + + stream_info->output_format = stream_cfg_cmd->output_format; + stream_info->runtime_output_format = stream_info->output_format; + stream_info->stream_src = stream_cfg_cmd->stream_src; + stream_info->frame_based = stream_cfg_cmd->frame_base; + return 0; +} + +static uint32_t msm_isp_axi_get_plane_size( + struct msm_vfe_axi_stream *stream_info, int plane_idx) +{ + uint32_t size = 0; + struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg; + + switch (stream_info->output_format) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_META: + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + /* TODO: fix me */ + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + case V4L2_PIX_FMT_SBGGR14: + case V4L2_PIX_FMT_SGBRG14: + case V4L2_PIX_FMT_SGRBG14: + case V4L2_PIX_FMT_SRGGB14: + case V4L2_PIX_FMT_QBGGR14: + case V4L2_PIX_FMT_QGBRG14: + case V4L2_PIX_FMT_QGRBG14: + case V4L2_PIX_FMT_QRGGB14: + /* TODO: fix me */ + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_P16BGGR10: + case V4L2_PIX_FMT_P16GBRG10: + case V4L2_PIX_FMT_P16GRBG10: + case V4L2_PIX_FMT_P16RGGB10: + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + if (plane_cfg[plane_idx].output_plane_format == Y_PLANE) + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + else + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV41: + if (plane_cfg[plane_idx].output_plane_format == Y_PLANE) + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + else + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + /*TD: Add more image format*/ + default: + msm_isp_print_fourcc_error(__func__, + stream_info->output_format); + break; + } + return size; +} + +void msm_isp_axi_reserve_wm(struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + int i, j; + + for (i = 0; i < stream_info->num_planes; i++) { + for (j = 0; j < axi_data->hw_info->num_wm; j++) { + if (!axi_data->free_wm[j]) { + axi_data->free_wm[j] = + stream_info->stream_handle; + axi_data->wm_image_size[j] = + msm_isp_axi_get_plane_size( + stream_info, i); + axi_data->num_used_wm++; + break; + } + } + stream_info->wm[i] = j; + } +} + +void msm_isp_axi_free_wm(struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + + for (i = 0; i < stream_info->num_planes; i++) { + axi_data->free_wm[stream_info->wm[i]] = 0; + axi_data->num_used_wm--; + } + if (stream_info->stream_src <= IDEAL_RAW) + axi_data->num_pix_stream++; + else if (stream_info->stream_src < VFE_AXI_SRC_MAX) + axi_data->num_rdi_stream++; +} + +void msm_isp_axi_reserve_comp_mask( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + uint8_t comp_mask = 0; + + for (i = 0; i < stream_info->num_planes; i++) + comp_mask |= 1 << stream_info->wm[i]; + + for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) { + if (!axi_data->composite_info[i].stream_handle) { + axi_data->composite_info[i].stream_handle = + stream_info->stream_handle; + axi_data->composite_info[i]. + stream_composite_mask = comp_mask; + axi_data->num_used_composite_mask++; + break; + } + } + stream_info->comp_mask_index = i; +} + +static void msm_isp_axi_free_comp_mask(struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + axi_data->composite_info[stream_info->comp_mask_index]. + stream_composite_mask = 0; + axi_data->composite_info[stream_info->comp_mask_index]. + stream_handle = 0; + axi_data->num_used_composite_mask--; +} + +static int msm_isp_axi_get_bufq_handles( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int rc = 0; + + if (stream_info->stream_id & ISP_SCRATCH_BUF_BIT) { + stream_info->bufq_handle = + vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, stream_info->session_id, + stream_info->stream_id & ~ISP_SCRATCH_BUF_BIT); + if (stream_info->bufq_handle == 0) { + pr_err("%s: Stream 0x%x has no valid buffer queue\n", + __func__, (unsigned int)stream_info->stream_id); + rc = -EINVAL; + return rc; + } + + stream_info->bufq_scratch_handle = + vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, stream_info->session_id, + stream_info->stream_id); + if (stream_info->bufq_scratch_handle == 0) { + pr_err("%s: Stream 0x%x has no valid buffer queue\n", + __func__, (unsigned int)stream_info->stream_id); + rc = -EINVAL; + return rc; + } + } else { + stream_info->bufq_handle = + vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, stream_info->session_id, + stream_info->stream_id); + if (stream_info->bufq_handle == 0) { + pr_err("%s: Stream 0x%x has no valid buffer queue\n", + __func__, (unsigned int)stream_info->stream_id); + rc = -EINVAL; + return rc; + } + } + return rc; +} + +int msm_isp_axi_check_stream_state( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +{ + int rc = 0, i; + unsigned long flags; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; + enum msm_vfe_axi_state valid_state = + (stream_cfg_cmd->cmd == START_STREAM) ? INACTIVE : ACTIVE; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return -EINVAL; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= + MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + spin_lock_irqsave(&stream_info->lock, flags); + if (stream_info->state != valid_state) { + if ((stream_info->state == PAUSING || + stream_info->state == PAUSED || + stream_info->state == RESUME_PENDING || + stream_info->state == RESUMING) && + (stream_cfg_cmd->cmd == STOP_STREAM || + stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) { + stream_info->state = ACTIVE; + } else { + pr_err("%s: Invalid stream state: %d\n", + __func__, stream_info->state); + spin_unlock_irqrestore( + &stream_info->lock, flags); + rc = -EINVAL; + break; + } + } + spin_unlock_irqrestore(&stream_info->lock, flags); + + if (stream_cfg_cmd->cmd == START_STREAM) { + rc = msm_isp_axi_get_bufq_handles(vfe_dev, stream_info); + if (rc) + break; + } + } + return rc; +} + +void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev, + uint8_t input_src) +{ + int i; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; + + for (i = 0; i < MAX_NUM_STREAM; i++) { + stream_info = &axi_data->stream_info[i]; + if (stream_info->state != ACTIVE) + continue; + + if (stream_info->runtime_framedrop_update) { + stream_info->runtime_init_frame_drop--; + if (stream_info->runtime_init_frame_drop == 0) { + stream_info->runtime_framedrop_update = 0; + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_framedrop(vfe_dev, stream_info); + } + } + if (stream_info->stream_type == BURST_STREAM && + ((1 << SRC_TO_INTF(stream_info->stream_src)) & + input_src)) { + if (stream_info->runtime_framedrop_update_burst) { + stream_info->runtime_framedrop_update_burst = 0; + stream_info->runtime_burst_frame_count = + stream_info->runtime_init_frame_drop + + (stream_info->runtime_num_burst_capture - + 1) * + (stream_info->framedrop_period + 1) + 1; + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_framedrop(vfe_dev, stream_info); + } else { + stream_info->runtime_burst_frame_count--; + if (stream_info-> + runtime_burst_frame_count == 0) { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_framedrop(vfe_dev, stream_info); + } + } + } + } +} + +void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + stream_info->runtime_init_frame_drop = stream_info->init_frame_drop; + stream_info->runtime_burst_frame_count = + stream_info->burst_frame_count; + stream_info->runtime_num_burst_capture = + stream_info->num_burst_capture; + stream_info->runtime_framedrop_update = stream_info->framedrop_update; + vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop(vfe_dev, stream_info); +} + +void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, + enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts) +{ + struct msm_isp32_event_data event_data; + + memset(&event_data, 0, sizeof(event_data)); + switch (event_type) { + case ISP_EVENT_SOF: + if ((frame_src == VFE_PIX_0) && (vfe_dev->isp_sof_debug < 5)) { + pr_err("%s: PIX0 frame id: %u\n", __func__, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id); + vfe_dev->isp_sof_debug++; + } + vfe_dev->axi_data.src_info[frame_src].frame_id++; + if (vfe_dev->axi_data.src_info[frame_src].frame_id == 0) + vfe_dev->axi_data.src_info[frame_src].frame_id = 1; + ISP_DBG("%s: frame_src %d frame id: %u\n", __func__, + frame_src, + vfe_dev->axi_data.src_info[frame_src].frame_id); + break; + case ISP_EVENT_REG_UPDATE: + vfe_dev->axi_data.src_info[frame_src].last_updt_frm_id = 0; + break; + default: + break; + } + + event_data.input_intf = frame_src; + event_data.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id; + event_data.timestamp = ts->event_time; + event_data.mono_timestamp = ts->buf_time; + msm_isp_send_event(vfe_dev, event_type | frame_src, &event_data); +} + +void msm_isp_calculate_framedrop( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe32_axi_stream_request_cmd *stream_cfg_cmd) +{ + uint32_t framedrop_period = 0; + struct msm_vfe_axi_stream *stream_info = NULL; + + if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) < MAX_NUM_STREAM) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; + } else { + pr_err("%s: Invalid stream handle", __func__); + return; + } + if (!stream_info) { + pr_err("%s: Stream info is NULL\n", __func__); + return; + } + + framedrop_period = msm_isp_get_framedrop_period( + stream_cfg_cmd->frame_skip_pattern); + stream_info->frame_skip_pattern = + stream_cfg_cmd->frame_skip_pattern; + if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL) + stream_info->framedrop_pattern = 0x0; + else + stream_info->framedrop_pattern = 0x1; + stream_info->framedrop_period = framedrop_period - 1; + + if (stream_cfg_cmd->init_frame_drop < framedrop_period) { + stream_info->framedrop_pattern <<= + stream_cfg_cmd->init_frame_drop; + stream_info->init_frame_drop = 0; + stream_info->framedrop_update = 0; + } else { + stream_info->init_frame_drop = stream_cfg_cmd->init_frame_drop; + stream_info->framedrop_update = 1; + } + + if (stream_cfg_cmd->burst_count > 0) { + stream_info->stream_type = BURST_STREAM; + stream_info->num_burst_capture = + stream_cfg_cmd->burst_count; + stream_info->burst_frame_count = + stream_cfg_cmd->init_frame_drop + + (stream_cfg_cmd->burst_count - 1) * + framedrop_period + 1; + } else { + stream_info->stream_type = CONTINUOUS_STREAM; + stream_info->burst_frame_count = 0; + stream_info->num_burst_capture = 0; + } +} + +static void msm_isp_calculate_bandwidth( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + int bpp = 0; + + if (stream_info->stream_src < RDI_INTF_0) { + stream_info->bandwidth = + (axi_data->src_info[VFE_PIX_0].pixel_clock / + axi_data->src_info[VFE_PIX_0].width) * + stream_info->max_width; + stream_info->bandwidth = (unsigned long)stream_info->bandwidth * + stream_info->format_factor / ISP_Q2; + } else { + int rdi = SRC_TO_INTF(stream_info->stream_src); + + bpp = msm_isp_get_bit_per_pixel(stream_info->output_format); + if (rdi < VFE_SRC_MAX) + stream_info->bandwidth = + (axi_data->src_info[rdi].pixel_clock / 8) * bpp; + else + pr_err("%s: Invalid rdi interface\n", __func__); + } +} + +#ifdef CONFIG_MSM_AVTIMER +void msm_isp_start_avtimer(void) +{ + avcs_core_open(); + avcs_core_disable_power_collapse(1); +} + +static inline void msm_isp_get_avtimer_ts( + struct msm_isp_timestamp *time_stamp) +{ + int rc = 0; + uint32_t avtimer_usec = 0; + uint64_t avtimer_tick = 0; + + rc = avcs_core_query_timer(&avtimer_tick); + if (rc < 0) { + pr_err("%s: Error: Invalid AVTimer Tick, rc=%d\n", + __func__, rc); + /* In case of error return zero AVTimer Tick Value */ + time_stamp->vt_time.tv_sec = 0; + time_stamp->vt_time.tv_usec = 0; + } else { + avtimer_usec = do_div(avtimer_tick, USEC_PER_SEC); + time_stamp->vt_time.tv_sec = (uint32_t)(avtimer_tick); + time_stamp->vt_time.tv_usec = avtimer_usec; + pr_debug("%s: AVTimer TS = %u:%u\n", __func__, + (uint32_t)(avtimer_tick), avtimer_usec); + } +} +#else +void msm_isp_start_avtimer(void) +{ + pr_err("AV Timer is not supported\n"); +} + +inline void msm_isp_get_avtimer_ts( + struct msm_isp_timestamp *time_stamp) +{ + pr_err_ratelimited("%s: Error: AVTimer driver not available\n", + __func__); + time_stamp->vt_time.tv_sec = 0; + time_stamp->vt_time.tv_usec = 0; +} +#endif + +int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0, i; + uint32_t io_format = 0; + struct msm_vfe32_axi_stream_request_cmd *stream_cfg_cmd = arg; + struct msm_vfe_axi_stream *stream_info; + + rc = msm_isp_axi_create_stream( + &vfe_dev->axi_data, stream_cfg_cmd); + if (rc) { + pr_err("%s: create stream failed\n", __func__); + return rc; + } + + rc = msm_isp_validate_axi_request( + &vfe_dev->axi_data, stream_cfg_cmd); + if (rc) { + pr_err("%s: Request validation failed\n", __func__); + if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) < + MAX_NUM_STREAM) + msm_isp_axi_destroy_stream(&vfe_dev->axi_data, + HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)); + return rc; + } + stream_info = &vfe_dev->axi_data. + stream_info[HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; + if (!stream_info) { + pr_err("%s: can not find stream handle %x\n", __func__, + stream_cfg_cmd->axi_stream_handle); + return -EINVAL; + } + + stream_info->memory_input = stream_cfg_cmd->memory_input; + + msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_info); + + if (stream_info->stream_src < RDI_INTF_0) { + io_format = vfe_dev->axi_data.src_info[VFE_PIX_0].input_format; + if (stream_info->stream_src == CAMIF_RAW || + stream_info->stream_src == IDEAL_RAW) { + if (stream_info->stream_src == CAMIF_RAW && + io_format != stream_info->output_format) + pr_debug("%s: Overriding input format\n", + __func__); + + io_format = stream_info->output_format; + } + rc = vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format( + vfe_dev, stream_info->stream_src, io_format); + if (rc) { + pr_err("%s: cfg io format failed\n", __func__); + msm_isp_axi_free_wm(&vfe_dev->axi_data, + stream_info); + msm_isp_axi_destroy_stream(&vfe_dev->axi_data, + HANDLE_TO_IDX( + stream_cfg_cmd->axi_stream_handle)); + return rc; + } + } + + msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd); + if (stream_cfg_cmd->vt_enable && !vfe_dev->vt_enable) { + vfe_dev->vt_enable = stream_cfg_cmd->vt_enable; + msm_isp_start_avtimer(); + } + if (stream_info->num_planes > 1) { + msm_isp_axi_reserve_comp_mask( + &vfe_dev->axi_data, stream_info); + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_comp_mask(vfe_dev, stream_info); + } else { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_irq_mask(vfe_dev, stream_info); + } + + for (i = 0; i < stream_info->num_planes; i++) { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_reg(vfe_dev, stream_info, i); + + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_xbar_reg(vfe_dev, stream_info, i); + } + return rc; +} + +int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0, i; + struct msm_vfe_axi_stream_release_cmd *stream_release_cmd = arg; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_stream_cfg_cmd stream_cfg; + + + if (HANDLE_TO_IDX(stream_release_cmd->stream_handle) >= + MAX_NUM_STREAM) { + pr_err("%s: Invalid stream handle\n", __func__); + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_release_cmd->stream_handle)]; + if (stream_info->state == AVAILABLE) { + pr_err("%s: Stream already released\n", __func__); + return -EINVAL; + } else if (stream_info->state != INACTIVE) { + stream_cfg.cmd = STOP_STREAM; + stream_cfg.num_streams = 1; + stream_cfg.stream_handle[0] = stream_release_cmd->stream_handle; + msm_isp_cfg_axi_stream(vfe_dev, (void *) &stream_cfg); + } + + for (i = 0; i < stream_info->num_planes; i++) { + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_wm_reg(vfe_dev, stream_info, i); + + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_wm_xbar_reg(vfe_dev, stream_info, i); + } + + if (stream_info->num_planes > 1) { + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_comp_mask(vfe_dev, stream_info); + msm_isp_axi_free_comp_mask(&vfe_dev->axi_data, stream_info); + } else { + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_wm_irq_mask(vfe_dev, stream_info); + } + + vfe_dev->hw_info->vfe_ops.axi_ops.clear_framedrop(vfe_dev, stream_info); + msm_isp_axi_free_wm(axi_data, stream_info); + + msm_isp_axi_destroy_stream(&vfe_dev->axi_data, + HANDLE_TO_IDX(stream_release_cmd->stream_handle)); + + return rc; +} + +static void msm_isp_axi_stream_enable_cfg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + if (stream_info->state == INACTIVE) + return; + for (i = 0; i < stream_info->num_planes; i++) { + if (stream_info->state == START_PENDING || + stream_info->state == RESUME_PENDING) { + vfe_dev->hw_info->vfe_ops.axi_ops. + enable_wm(vfe_dev, stream_info->wm[i], 1); + } else { + vfe_dev->hw_info->vfe_ops.axi_ops. + enable_wm(vfe_dev, stream_info->wm[i], 0); + /* Issue a reg update for Raw Snapshot Case + * since we dont have reg update ack + */ + if (stream_info->stream_src == CAMIF_RAW || + stream_info->stream_src == IDEAL_RAW) { + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev, (1 << VFE_PIX_0)); + } + } + } + + if (stream_info->state == START_PENDING) + axi_data->num_active_stream++; + else if (stream_info->state == STOP_PENDING) + axi_data->num_active_stream--; +} + +void msm_isp_axi_stream_update(struct vfe_device *vfe_dev, uint8_t input_src) +{ + int i; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + for (i = 0; i < MAX_NUM_STREAM; i++) { + if (axi_data->stream_info[i].state == START_PENDING || + axi_data->stream_info[i].state == + STOP_PENDING) { + if ((1 << + SRC_TO_INTF(axi_data->stream_info[i]. + stream_src)) & + input_src) { + msm_isp_axi_stream_enable_cfg( + vfe_dev, &axi_data->stream_info[i]); + axi_data->stream_info[i].state = + axi_data->stream_info[i].state == + START_PENDING ? STARTING : STOPPING; + } + } else if (axi_data->stream_info[i].state == STARTING || + axi_data->stream_info[i].state == STOPPING) { + if ((1 << + SRC_TO_INTF(axi_data->stream_info[i]. + stream_src)) & + input_src) { + axi_data->stream_info[i].state = + axi_data->stream_info[i].state == STARTING ? + ACTIVE : INACTIVE; + vfe_dev->axi_data.stream_update--; + } + } + } + + if (vfe_dev->axi_data.pipeline_update == DISABLE_CAMIF || + (vfe_dev->axi_data.pipeline_update == + DISABLE_CAMIF_IMMEDIATELY)) { + vfe_dev->hw_info->vfe_ops.stats_ops. + enable_module(vfe_dev, 0xFF, 0); + vfe_dev->axi_data.pipeline_update = NO_UPDATE; + } + + if (vfe_dev->axi_data.stream_update == 0) + complete(&vfe_dev->stream_config_complete); +} + +static void msm_isp_reload_ping_pong_offset(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int i, j; + uint32_t flag; + struct msm_isp_buffer *buf; + + for (i = 0; i < 2; i++) { + buf = stream_info->buf[i]; + if (!buf) + continue; + flag = i ? VFE_PONG_FLAG : VFE_PING_FLAG; + for (j = 0; j < stream_info->num_planes; j++) { + vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( + vfe_dev, stream_info->wm[j], flag, + buf->mapped_info[j].paddr + + stream_info->plane_cfg[j].plane_addr_offset); + } + } +} + +void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev) +{ + int i, j; + uint32_t update_state; + unsigned long flags; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; + + for (i = 0; i < MAX_NUM_STREAM; i++) { + stream_info = &axi_data->stream_info[i]; + if (stream_info->stream_type == BURST_STREAM || + stream_info->state == AVAILABLE) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + if (stream_info->state == PAUSING) { + /*AXI Stopped, apply update*/ + stream_info->state = PAUSED; + msm_isp_reload_ping_pong_offset(vfe_dev, stream_info); + for (j = 0; j < stream_info->num_planes; j++) + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_reg(vfe_dev, stream_info, j); + /*Resume AXI*/ + stream_info->state = RESUME_PENDING; + msm_isp_axi_stream_enable_cfg( + vfe_dev, &axi_data->stream_info[i]); + stream_info->state = RESUMING; + } else if (stream_info->state == RESUMING) { + stream_info->runtime_output_format = + stream_info->output_format; + stream_info->state = ACTIVE; + } + spin_unlock_irqrestore(&stream_info->lock, flags); + } + + update_state = atomic_dec_return(&axi_data->axi_cfg_update); +} + +static void msm_isp_cfg_pong_address(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + struct msm_isp_buffer *buf = stream_info->buf[0]; + + for (i = 0; i < stream_info->num_planes; i++) + vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( + vfe_dev, stream_info->wm[i], + VFE_PONG_FLAG, buf->mapped_info[i].paddr + + stream_info->plane_cfg[i].plane_addr_offset); + stream_info->buf[1] = buf; +} + +static void msm_isp_get_done_buf(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status, + struct msm_isp_buffer **done_buf) +{ + uint32_t pingpong_bit = 0, i; + + pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); + for (i = 0; i < stream_info->num_planes; i++) { + if (pingpong_bit != + (~(pingpong_status >> stream_info->wm[i]) & 0x1)) { + pr_debug("%s: Write master ping pong mismatch. Status: 0x%x\n", + __func__, pingpong_status); + } + } + + *done_buf = stream_info->buf[pingpong_bit]; + + if (stream_info->controllable_output) { + stream_info->buf[pingpong_bit] = NULL; + stream_info->request_frm_num--; + } +} + +static int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status, + uint32_t pingpong_bit) +{ + int i, rc = -1; + struct msm_isp_buffer *buf = NULL; + uint32_t bufq_handle = 0, frame_id = 0; + uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + + if (stream_idx >= MAX_NUM_STREAM) { + pr_err("%s: Invalid stream_idx", __func__); + return rc; + } + + if (stream_info->controllable_output && !stream_info->request_frm_num) + return 0; + + frame_id = vfe_dev->axi_data. + src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id; + if (frame_id && stream_info->frame_id && + stream_info->frame_id == frame_id) { + /* This could happen if reg update ack is delayed */ + pr_err("%s: Duplicate frame streamId:%d stream_fid:%d frame_id:%d\n", + __func__, stream_info->stream_id, stream_info->frame_id, + frame_id); + vfe_dev->error_info.stream_framedrop_count[stream_idx]++; + return rc; + } + + bufq_handle = stream_info->bufq_handle; + if (SRC_TO_INTF(stream_info->stream_src) < VFE_SRC_MAX) + rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, + vfe_dev->pdev->id, bufq_handle, + MSM_ISP_INVALID_BUF_INDEX, &buf); + else { + pr_err("%s: Invalid stream index\n", __func__); + rc = -1; + } + + if (rc < 0) { + vfe_dev->error_info.stream_framedrop_count[stream_idx]++; + return rc; + } + + if (buf->num_planes != stream_info->num_planes) { + pr_err("%s: Invalid buffer\n", __func__); + rc = -EINVAL; + goto buf_error; + } + + for (i = 0; i < stream_info->num_planes; i++) + vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( + vfe_dev, stream_info->wm[i], + pingpong_status, buf->mapped_info[i].paddr + + stream_info->plane_cfg[i].plane_addr_offset); + + stream_info->buf[pingpong_bit] = buf; + + return 0; +buf_error: + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + return rc; +} + +static void msm_isp_process_done_buf(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, struct msm_isp_buffer *buf, + struct msm_isp_timestamp *ts) +{ + int rc; + struct msm_isp32_event_data buf_event; + struct timeval *time_stamp; + uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + uint32_t frame_id; + uint32_t buf_src; + + memset(&buf_event, 0, sizeof(buf_event)); + + if (stream_idx >= MAX_NUM_STREAM) { + pr_err("%s: Invalid stream_idx", __func__); + return; + } + + if (SRC_TO_INTF(stream_info->stream_src) < VFE_SRC_MAX) + frame_id = vfe_dev->axi_data. + src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id; + else { + pr_err("%s: Invalid stream index, put buf back to vb2 queue\n", + __func__); + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + return; + } + + if (buf && ts) { + if (vfe_dev->vt_enable) { + msm_isp_get_avtimer_ts(ts); + time_stamp = &ts->vt_time; + } else + time_stamp = &ts->buf_time; + + rc = vfe_dev->buf_mgr->ops->get_buf_src(vfe_dev->buf_mgr, + buf->bufq_handle, &buf_src); + if (stream_info->buf_divert && rc == 0 && + buf_src != MSM_ISP_BUFFER_SRC_SCRATCH) { + rc = vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx, + time_stamp, frame_id); + /* Buf divert return value represent whether the buf + * can be diverted. A positive return value means + * other ISP hardware is still processing the frame. + */ + if (rc == 0) { + buf_event.input_intf = + SRC_TO_INTF(stream_info->stream_src); + buf_event.frame_id = frame_id; + buf_event.timestamp = *time_stamp; + buf_event.u.buf_done.session_id = + stream_info->session_id; + buf_event.u.buf_done.stream_id = + stream_info->stream_id; + buf_event.u.buf_done.handle = + stream_info->bufq_handle; + buf_event.u.buf_done.buf_idx = buf->buf_idx; + buf_event.u.buf_done.output_format = + stream_info->runtime_output_format; + msm_isp_send_event(vfe_dev, + ISP_EVENT_BUF_DIVERT + stream_idx, + &buf_event); + } + } else { + buf_event.input_intf = + SRC_TO_INTF(stream_info->stream_src); + buf_event.frame_id = frame_id; + buf_event.timestamp = ts->buf_time; + buf_event.u.buf_done.session_id = + stream_info->session_id; + buf_event.u.buf_done.stream_id = + stream_info->stream_id; + buf_event.u.buf_done.output_format = + stream_info->runtime_output_format; + msm_isp_send_event(vfe_dev, + ISP_EVENT_BUF_DONE, &buf_event); + vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx, + time_stamp, frame_id, + stream_info->runtime_output_format); + } + } +} + +static enum msm_isp_camif_update_state + msm_isp_get_camif_update_state(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +{ + int i; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint8_t pix_stream_cnt = 0, cur_pix_stream_cnt; + + cur_pix_stream_cnt = + axi_data->src_info[VFE_PIX_0].pix_stream_count + + axi_data->src_info[VFE_PIX_0].raw_stream_count; + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = + &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + if (stream_info->stream_src < RDI_INTF_0) + pix_stream_cnt++; + } + + if ((pix_stream_cnt) && + (axi_data->src_info[VFE_PIX_0].input_mux != EXTERNAL_READ)) { + + if (cur_pix_stream_cnt == 0 && pix_stream_cnt && + stream_cfg_cmd->cmd == START_STREAM) + return ENABLE_CAMIF; + else if (cur_pix_stream_cnt && + (cur_pix_stream_cnt - pix_stream_cnt) == 0 && + stream_cfg_cmd->cmd == STOP_STREAM) + return DISABLE_CAMIF; + else if (cur_pix_stream_cnt && + (cur_pix_stream_cnt - pix_stream_cnt) == 0 && + stream_cfg_cmd->cmd == STOP_IMMEDIATELY) + return DISABLE_CAMIF_IMMEDIATELY; + } + + return NO_UPDATE; +} + +static void msm_isp_update_camif_output_count( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +{ + int i; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= + MAX_NUM_STREAM) { + return; + } + stream_info = + &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + if (stream_info->stream_src >= RDI_INTF_0) + continue; + if (stream_info->stream_src == PIX_ENCODER || + stream_info->stream_src == PIX_VIEWFINDER || + stream_info->stream_src == PIX_VIDEO || + stream_info->stream_src == IDEAL_RAW) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_PIX_0]. + pix_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_PIX_0]. + pix_stream_count--; + } else if (stream_info->stream_src == CAMIF_RAW) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count--; + } + } +} + + +static void msm_isp_update_rdi_output_count( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +{ + int i; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) + > MAX_NUM_STREAM) + return; + stream_info = + &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + if (stream_info->stream_src < RDI_INTF_0) + continue; + if (stream_info->stream_src == RDI_INTF_0) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_RAW_0]. + raw_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_RAW_0]. + raw_stream_count--; + } else if (stream_info->stream_src == RDI_INTF_1) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_RAW_1]. + raw_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_RAW_1]. + raw_stream_count--; + } else if (stream_info->stream_src == RDI_INTF_2) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_RAW_2]. + raw_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_RAW_2]. + raw_stream_count--; + } + + } +} + +static uint8_t msm_isp_get_curr_stream_cnt( + struct vfe_device *vfe_dev) +{ + uint8_t curr_stream_cnt = 0; + + curr_stream_cnt = vfe_dev->axi_data.src_info[VFE_RAW_0]. + raw_stream_count + + vfe_dev->axi_data.src_info[VFE_RAW_1]. + raw_stream_count + + vfe_dev->axi_data.src_info[VFE_RAW_2]. + raw_stream_count + + vfe_dev->axi_data.src_info[VFE_PIX_0]. + pix_stream_count + + vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count; + return curr_stream_cnt; +} + +/*Factor in Q2 format*/ +#define ISP_DEFAULT_FORMAT_FACTOR 6 +#define ISP_BUS_UTILIZATION_FACTOR 1536 /* 1.5 in Q10 format */ +static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev) +{ + int i, rc = 0; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint64_t total_pix_bandwidth = 0, total_rdi_bandwidth = 0; + uint32_t num_pix_streams = 0; + uint32_t num_rdi_streams = 0; + uint32_t total_streams = 0; + uint64_t total_bandwidth = 0; + uint32_t bus_util_factor = ISP_BUS_UTILIZATION_FACTOR; + + for (i = 0; i < MAX_NUM_STREAM; i++) { + stream_info = &axi_data->stream_info[i]; + if (stream_info->state == ACTIVE || + stream_info->state == START_PENDING) { + if (stream_info->stream_src < RDI_INTF_0) { + total_pix_bandwidth += stream_info->bandwidth; + num_pix_streams++; + } else { + total_rdi_bandwidth += stream_info->bandwidth; + num_rdi_streams++; + } + } + } + total_bandwidth = total_pix_bandwidth + total_rdi_bandwidth; + total_streams = num_pix_streams + num_rdi_streams; + if (vfe_dev->bus_util_factor) + bus_util_factor = vfe_dev->bus_util_factor; + ISP_DBG("%s: bus_util_factor = %u\n", __func__, bus_util_factor); + + if (total_streams == 1) + rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, + total_bandwidth, + (total_bandwidth * bus_util_factor / ISP_Q10)); + else + rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, + (total_bandwidth + MSM_ISP_MIN_AB), (total_bandwidth * + bus_util_factor / ISP_Q10 + MSM_ISP_MIN_IB)); + if (rc < 0) + pr_err("%s: update failed\n", __func__); + + return rc; +} + +static int msm_isp_axi_wait_for_cfg_done(struct vfe_device *vfe_dev, + enum msm_isp_camif_update_state camif_update) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&vfe_dev->shared_data_lock, flags); + init_completion(&vfe_dev->stream_config_complete); + vfe_dev->axi_data.pipeline_update = camif_update; + spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags); + rc = wait_for_completion_timeout( + &vfe_dev->stream_config_complete, + msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); + if (rc == 0) { + pr_err("%s: wait timeout\n", __func__); + rc = -1; + } else { + rc = 0; + } + return rc; +} + +static int msm_isp_init_stream_ping_pong_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int rc = 0; + /*Set address for both PING & PONG register */ + rc = msm_isp_cfg_ping_pong_address(vfe_dev, + stream_info, VFE_PING_FLAG, 0); + if (rc < 0) { + pr_err("%s: No free buffer for ping\n", + __func__); + return rc; + } + + /* For burst stream of one capture, only one buffer + * is allocated. Duplicate ping buffer address to pong + * buffer to ensure hardware write to a valid address + */ + if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_num_burst_capture <= 1) { + msm_isp_cfg_pong_address(vfe_dev, stream_info); + } else { + rc = msm_isp_cfg_ping_pong_address(vfe_dev, + stream_info, VFE_PONG_FLAG, 1); + if (rc < 0) { + pr_err("%s: No free buffer for pong\n", + __func__); + return rc; + } + } + return rc; +} + +static void msm_isp_deinit_stream_ping_pong_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + + for (i = 0; i < 2; i++) { + struct msm_isp_buffer *buf; + + buf = stream_info->buf[i]; + if (buf) { + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + } + } +} + +static void msm_isp_get_stream_wm_mask( + struct msm_vfe_axi_stream *stream_info, + uint32_t *wm_reload_mask) +{ + int i; + + for (i = 0; i < stream_info->num_planes; i++) + *wm_reload_mask |= (1 << stream_info->wm[i]); +} + +int msm_isp_axi_halt(struct vfe_device *vfe_dev, + struct msm_vfe_axi_halt_cmd *halt_cmd) +{ + int rc = 0; + + if (halt_cmd->overflow_detected) { + /*Store current IRQ mask*/ + if (vfe_dev->error_info.overflow_recover_irq_mask0 == 0) { + vfe_dev->hw_info->vfe_ops.core_ops.get_irq_mask(vfe_dev, + &vfe_dev->error_info.overflow_recover_irq_mask0, + &vfe_dev->error_info.overflow_recover_irq_mask1); + } + atomic_set(&vfe_dev->error_info.overflow_state, + OVERFLOW_DETECTED); + } + + rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); + + if (halt_cmd->stop_camif) { + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY); + } + + return rc; +} + +int msm_isp_axi_reset(struct vfe_device *vfe_dev, + struct msm_vfe_axi_reset_cmd *reset_cmd) +{ + int rc = 0, i, j; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_timestamp timestamp; + + if (!reset_cmd) { + pr_err("%s: NULL pointer reset cmd %pK\n", __func__, reset_cmd); + rc = -1; + return rc; + } + + msm_isp_get_timestamp(×tamp, vfe_dev); + rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, + 0, reset_cmd->blocking); + + for (i = 0, j = 0; j < axi_data->num_active_stream && + i < MAX_NUM_STREAM; i++, j++) { + stream_info = &axi_data->stream_info[i]; + if (stream_info->stream_src >= VFE_AXI_SRC_MAX) { + rc = -1; + pr_err("%s invalid stream src = %d\n", __func__, + stream_info->stream_src); + break; + } + if (stream_info->state != ACTIVE) { + j--; + continue; + } + + bufq = vfe_dev->buf_mgr->ops->get_bufq(vfe_dev->buf_mgr, + stream_info->bufq_handle); + if (!bufq) { + pr_err("%s: bufq null %pK by handle %x\n", __func__, + bufq, stream_info->bufq_handle); + continue; + } + + if (bufq->buf_type != ISP_SHARE_BUF) { + msm_isp_deinit_stream_ping_pong_reg(vfe_dev, + stream_info); + } else { + vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, + stream_info->bufq_handle, + MSM_ISP_BUFFER_FLUSH_ALL, + ×tamp.buf_time, + reset_cmd->frame_id); + } + axi_data->src_info[SRC_TO_INTF(stream_info->stream_src)]. + frame_id = reset_cmd->frame_id; + msm_isp_reset_burst_count_and_frame_drop(vfe_dev, stream_info); + } + + if (rc < 0) + pr_err("%s Error! reset hw Timed out\n", __func__); + + return rc; +} + +int msm_isp_axi_restart(struct vfe_device *vfe_dev, + struct msm_vfe_axi_restart_cmd *restart_cmd) +{ + int rc = 0, i, j; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t wm_reload_mask = 0x0; + + for (i = 0, j = 0; j < axi_data->num_active_stream && + i < MAX_NUM_STREAM; i++, j++) { + stream_info = &axi_data->stream_info[i]; + if (stream_info->state != ACTIVE) { + j--; + continue; + } + msm_isp_get_stream_wm_mask(stream_info, &wm_reload_mask); + msm_isp_init_stream_ping_pong_reg(vfe_dev, stream_info); + } + + vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, wm_reload_mask); + rc = vfe_dev->hw_info->vfe_ops.axi_ops.restart(vfe_dev, 0, + restart_cmd->enable_camif); + if (rc < 0) + pr_err("%s Error restarting HW\n", __func__); + + return rc; +} + +static int msm_isp_axi_update_cgc_override(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, + uint8_t cgc_override) +{ + int i = 0, j = 0; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return -EINVAL; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= + MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + for (j = 0; j < stream_info->num_planes; j++) { + if (vfe_dev->hw_info->vfe_ops.axi_ops. + update_cgc_override) + vfe_dev->hw_info->vfe_ops.axi_ops. + update_cgc_override(vfe_dev, + stream_info->wm[j], cgc_override); + } + } + return 0; +} + +static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, + enum msm_isp_camif_update_state camif_update) +{ + int i, rc = 0; + uint8_t src_state, wait_for_complete = 0; + uint32_t wm_reload_mask = 0x0; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint8_t init_frm_drop = 0; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return -EINVAL; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= + MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + if (SRC_TO_INTF(stream_info->stream_src) < VFE_SRC_MAX) + src_state = axi_data->src_info[ + SRC_TO_INTF(stream_info->stream_src)].active; + else { + pr_err("%s: invalid src info index\n", __func__); + return -EINVAL; + } + + msm_isp_calculate_bandwidth(axi_data, stream_info); + msm_isp_reset_framedrop(vfe_dev, stream_info); + init_frm_drop = stream_info->init_frame_drop; + msm_isp_get_stream_wm_mask(stream_info, &wm_reload_mask); + rc = msm_isp_init_stream_ping_pong_reg(vfe_dev, stream_info); + if (rc < 0) { + pr_err("%s: No buffer for stream %d\n", + __func__, + HANDLE_TO_IDX( + stream_cfg_cmd->stream_handle[i])); + return rc; + } + + stream_info->state = START_PENDING; + if (src_state) { + wait_for_complete = 1; + } else { + if (vfe_dev->dump_reg) + msm_camera_io_dump_2(vfe_dev->vfe_base, 0x900); + + /*Configure AXI start bits to start immediately*/ + msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info); + stream_info->state = ACTIVE; + } + if (SRC_TO_INTF(stream_info->stream_src) != VFE_PIX_0 && + stream_info->stream_src < VFE_AXI_SRC_MAX) { + vfe_dev->axi_data.src_info[SRC_TO_INTF( + stream_info->stream_src)].frame_id = + init_frm_drop; + } + } + msm_isp_update_stream_bandwidth(vfe_dev); + vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, wm_reload_mask); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); + msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd); + if (camif_update == ENABLE_CAMIF) { + atomic_set(&vfe_dev->error_info.overflow_state, + NO_OVERFLOW); + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = 0; + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, camif_update); + } + + if (wait_for_complete) { + vfe_dev->axi_data.stream_update = stream_cfg_cmd->num_streams; + rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update); + } + + return rc; +} + +static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, + enum msm_isp_camif_update_state camif_update) +{ + int i, rc = 0; + uint8_t wait_for_complete_for_this_stream = 0, cur_stream_cnt = 0; + uint8_t wait_for_complete = 0; + struct msm_vfe_axi_stream *stream_info = NULL; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + int ext_read = + axi_data->src_info[VFE_PIX_0].input_mux == EXTERNAL_READ; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM || + stream_cfg_cmd->num_streams == 0) + return -EINVAL; + + msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); + msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd); + cur_stream_cnt = msm_isp_get_curr_stream_cnt(vfe_dev); + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= + MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + wait_for_complete_for_this_stream = 0; + stream_info->state = STOP_PENDING; + if (stream_info->stream_src == CAMIF_RAW || + stream_info->stream_src == IDEAL_RAW) { + /* We dont get reg update IRQ for raw snapshot + * so frame skip cant be ocnfigured + */ + if ((camif_update != DISABLE_CAMIF_IMMEDIATELY) && + (!ext_read)) + wait_for_complete_for_this_stream = 1; + } else if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_num_burst_capture == 0) { + /* Configure AXI writemasters to stop immediately + * since for burst case, write masters already skip + * all frames. + */ + if (stream_info->stream_src == RDI_INTF_0 || + stream_info->stream_src == RDI_INTF_1 || + stream_info->stream_src == RDI_INTF_2) + wait_for_complete_for_this_stream = 1; + } else { + if ((camif_update != DISABLE_CAMIF_IMMEDIATELY) && + (!ext_read) && + !(stream_info->stream_src == RDI_INTF_0 || + stream_info->stream_src == RDI_INTF_1 || + stream_info->stream_src == RDI_INTF_2)) + wait_for_complete_for_this_stream = 1; + } + if (!wait_for_complete_for_this_stream) { + msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info); + stream_info->state = INACTIVE; + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev, 0xF); + } + wait_for_complete |= wait_for_complete_for_this_stream; + } + if (wait_for_complete) { + vfe_dev->axi_data.stream_update = stream_cfg_cmd->num_streams; + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev, 0xF); + rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update); + if (rc < 0) { + pr_err("%s: wait for config done failed\n", __func__); + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX( + stream_cfg_cmd->stream_handle[i])]; + stream_info->state = STOP_PENDING; + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev, 0xF); + msm_isp_axi_stream_enable_cfg( + vfe_dev, stream_info); + stream_info->state = INACTIVE; + } + } + } + if (camif_update == DISABLE_CAMIF) { + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF); + } else if ((camif_update == DISABLE_CAMIF_IMMEDIATELY) || + (ext_read)) { + /*during stop immediately, stop output then stop input*/ + if (!ext_read) + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, + DISABLE_CAMIF_IMMEDIATELY); + } + if (cur_stream_cnt == 0) { + vfe_dev->ignore_error = 1; + vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); + vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 1, 1); + vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); + vfe_dev->ignore_error = 0; + } + msm_isp_update_stream_bandwidth(vfe_dev); + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + msm_isp_deinit_stream_ping_pong_reg(vfe_dev, stream_info); + } + + return rc; +} + + +int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd = arg; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + enum msm_isp_camif_update_state camif_update; + + rc = msm_isp_axi_check_stream_state(vfe_dev, stream_cfg_cmd); + if (rc < 0) { + pr_err("%s: Invalid stream state\n", __func__); + return rc; + } + + if (axi_data->num_active_stream == 0) { + /*Configure UB*/ + vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev); + } + camif_update = msm_isp_get_camif_update_state(vfe_dev, stream_cfg_cmd); + + if (stream_cfg_cmd->cmd == START_STREAM) { + msm_isp_axi_update_cgc_override(vfe_dev, stream_cfg_cmd, 1); + + rc = msm_isp_start_axi_stream( + vfe_dev, stream_cfg_cmd, camif_update); + } else { + rc = msm_isp_stop_axi_stream( + vfe_dev, stream_cfg_cmd, camif_update); + + msm_isp_axi_update_cgc_override(vfe_dev, stream_cfg_cmd, 0); + } + + if (rc < 0) + pr_err("%s: start/stop stream failed\n", __func__); + return rc; +} + +static int msm_isp_request_frame(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint32_t request_frm_num) +{ + struct msm_vfe32_axi_stream_request_cmd stream_cfg_cmd; + int rc = 0; + uint32_t pingpong_status, pingpong_bit, wm_reload_mask = 0x0; + + if (!stream_info->controllable_output) + return 0; + + if (!request_frm_num) { + pr_err("%s: Invalid frame request.\n", __func__); + return -EINVAL; + } + + stream_info->request_frm_num += request_frm_num; + + stream_cfg_cmd.axi_stream_handle = stream_info->stream_handle; + stream_cfg_cmd.frame_skip_pattern = NO_SKIP; + stream_cfg_cmd.init_frame_drop = 0; + stream_cfg_cmd.burst_count = stream_info->request_frm_num; + msm_isp_calculate_framedrop(&vfe_dev->axi_data, &stream_cfg_cmd); + msm_isp_reset_framedrop(vfe_dev, stream_info); + + if (stream_info->request_frm_num != request_frm_num) { + pingpong_status = + vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status( + vfe_dev); + pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); + + if (!stream_info->buf[pingpong_bit]) { + rc = msm_isp_cfg_ping_pong_address(vfe_dev, stream_info, + pingpong_status, pingpong_bit); + if (rc) { + pr_err("%s:%d fail to set ping pong address\n", + __func__, __LINE__); + return rc; + } + } + + if (!stream_info->buf[!pingpong_bit] && request_frm_num > 1) { + rc = msm_isp_cfg_ping_pong_address(vfe_dev, stream_info, + ~pingpong_status, !pingpong_bit); + if (rc) { + pr_err("%s:%d fail to set ping pong address\n", + __func__, __LINE__); + return rc; + } + } + } else { + if (!stream_info->buf[0]) { + rc = msm_isp_cfg_ping_pong_address(vfe_dev, stream_info, + VFE_PING_FLAG, 0); + if (rc) { + pr_err("%s:%d fail to set ping pong address\n", + __func__, __LINE__); + return rc; + } + } + + if (!stream_info->buf[1] && request_frm_num > 1) { + rc = msm_isp_cfg_ping_pong_address(vfe_dev, stream_info, + VFE_PONG_FLAG, 1); + if (rc) { + pr_err("%s:%d fail to set ping pong address\n", + __func__, __LINE__); + return rc; + } + } + + msm_isp_get_stream_wm_mask(stream_info, &wm_reload_mask); + vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, + wm_reload_mask); + } + + return rc; +} + +int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0, i, j; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream_update_cmd *update_cmd = arg; + struct msm_vfe_axi_stream_cfg_update_info *update_info; + uint32_t frame_id; + struct msm_isp_timestamp timestamp; + + if (update_cmd->update_type == UPDATE_STREAM_AXI_CONFIG && + atomic_read(&axi_data->axi_cfg_update)) { + pr_err("%s: AXI stream config updating\n", __func__); + return -EBUSY; + } + + /*num_stream is uint32 and update_info[] bound by MAX_NUM_STREAM*/ + if (update_cmd->num_streams > MAX_NUM_STREAM) + return -EINVAL; + + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = &update_cmd->update_info[i]; + /*check array reference bounds*/ + if (HANDLE_TO_IDX(update_info->stream_handle) >= + MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(update_info->stream_handle)]; + if (stream_info->state != ACTIVE && + stream_info->state != INACTIVE) { + pr_err("%s: Invalid stream state\n", __func__); + return -EINVAL; + } + } + + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = &update_cmd->update_info[i]; + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(update_info->stream_handle)]; + + switch (update_cmd->update_type) { + case ENABLE_STREAM_BUF_DIVERT: + stream_info->buf_divert = 1; + break; + case DISABLE_STREAM_BUF_DIVERT: + msm_isp_get_timestamp(×tamp, vfe_dev); + stream_info->buf_divert = 0; + frame_id = vfe_dev->axi_data. + src_info[SRC_TO_INTF( + stream_info->stream_src)]. + frame_id; + vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, + stream_info->bufq_handle, + MSM_ISP_BUFFER_FLUSH_DIVERTED, + ×tamp.buf_time, frame_id); + break; + case UPDATE_STREAM_FRAMEDROP_PATTERN: { + uint32_t framedrop_period = + msm_isp_get_framedrop_period( + update_info->skip_pattern); + if (update_info->skip_pattern == SKIP_ALL) + stream_info->framedrop_pattern = 0x0; + else + stream_info->framedrop_pattern = 0x1; + stream_info->framedrop_period = framedrop_period - 1; + if (stream_info->stream_type == BURST_STREAM) { + stream_info->runtime_framedrop_update_burst = 1; + } else { + stream_info->runtime_init_frame_drop = 0; + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_framedrop(vfe_dev, stream_info); + } + break; + } + case UPDATE_STREAM_AXI_CONFIG: { + for (j = 0; j < stream_info->num_planes; j++) { + stream_info->plane_cfg[j] = + update_info->plane_cfg[j]; + } + stream_info->output_format = update_info->output_format; + if (stream_info->state == ACTIVE) { + stream_info->state = PAUSE_PENDING; + msm_isp_axi_stream_enable_cfg( + vfe_dev, stream_info); + stream_info->state = PAUSING; + atomic_set(&axi_data->axi_cfg_update, + UPDATE_REQUESTED); + } else { + for (j = 0; j < stream_info->num_planes; j++) + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_reg(vfe_dev, stream_info, j); + stream_info->runtime_output_format = + stream_info->output_format; + } + break; + } + case UPDATE_STREAM_REQUEST_FRAMES: { + rc = msm_isp_request_frame(vfe_dev, stream_info, + update_info->frame_id); + if (rc) + pr_err("%s failed to request frame!\n", + __func__); + break; + } + default: + pr_err("%s: Invalid update type\n", __func__); + return -EINVAL; + } + } + return rc; +} + +void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + int i, rc = 0; + struct msm_isp_buffer *done_buf = NULL; + uint32_t comp_mask = 0, wm_mask = 0; + uint32_t pingpong_status, stream_idx; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_composite_info *comp_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t pingpong_bit = 0, frame_id = 0; + + comp_mask = vfe_dev->hw_info->vfe_ops.axi_ops. + get_comp_mask(irq_status0, irq_status1); + wm_mask = vfe_dev->hw_info->vfe_ops.axi_ops. + get_wm_mask(irq_status0, irq_status1); + if (!(comp_mask || wm_mask)) + return; + + ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0); + pingpong_status = + vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(vfe_dev); + for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) { + rc = 0; + comp_info = &axi_data->composite_info[i]; + if (comp_mask & (1 << i)) { + stream_idx = HANDLE_TO_IDX(comp_info->stream_handle); + if ((!comp_info->stream_handle) || + (stream_idx >= MAX_NUM_STREAM)) { + pr_err("%s: Invalid handle for composite irq\n", + __func__); + } else { + stream_idx = + HANDLE_TO_IDX(comp_info->stream_handle); + stream_info = + &axi_data->stream_info[stream_idx]; + + pingpong_bit = (~(pingpong_status >> + stream_info->wm[0]) & 0x1); + + if (stream_info->stream_type == BURST_STREAM) + stream_info-> + runtime_num_burst_capture--; + + msm_isp_get_done_buf(vfe_dev, stream_info, + pingpong_status, &done_buf); + if (stream_info->stream_type == + CONTINUOUS_STREAM || + stream_info-> + runtime_num_burst_capture > 1) { + rc = msm_isp_cfg_ping_pong_address( + vfe_dev, stream_info, + pingpong_status, + pingpong_bit); + } + frame_id = vfe_dev->axi_data. + src_info[SRC_TO_INTF( + stream_info->stream_src)]. + frame_id; + stream_info->frame_id = frame_id; + ISP_DBG("%s: stream id:%d frame id:%d\n", + __func__, stream_info->stream_id, + stream_info->frame_id); + if (done_buf && !rc) + msm_isp_process_done_buf(vfe_dev, + stream_info, done_buf, ts); + } + } + wm_mask &= ~(comp_info->stream_composite_mask); + } + + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (wm_mask & (1 << i)) { + stream_idx = HANDLE_TO_IDX(axi_data->free_wm[i]); + if ((!axi_data->free_wm[i]) || + (stream_idx >= MAX_NUM_STREAM)) { + pr_err("%s: Invalid handle for wm irq\n", + __func__); + continue; + } + stream_info = &axi_data->stream_info[stream_idx]; + + pingpong_bit = (~(pingpong_status >> + stream_info->wm[0]) & 0x1); + + if (stream_info->stream_type == BURST_STREAM) + stream_info->runtime_num_burst_capture--; + + msm_isp_get_done_buf(vfe_dev, stream_info, + pingpong_status, &done_buf); + if (stream_info->stream_type == CONTINUOUS_STREAM || + stream_info->runtime_num_burst_capture > 1) { + rc = msm_isp_cfg_ping_pong_address(vfe_dev, + stream_info, pingpong_status, + pingpong_bit); + } + stream_info->frame_id = frame_id; + ISP_DBG("%s: stream id:%d frame id:%d\n", + __func__, stream_info->stream_id, + stream_info->frame_id); + if (done_buf && !rc) + msm_isp_process_done_buf(vfe_dev, + stream_info, done_buf, ts); + } + } +} +int msm_isp_user_buf_done(struct vfe_device *vfe_dev, + struct msm_isp32_event_data *buf_cmd) +{ + int rc = 0; + struct msm_isp32_event_data buf_event; + + memset(&buf_event, 0, sizeof(buf_event)); + buf_event.input_intf = buf_cmd->input_intf; + buf_event.frame_id = buf_cmd->frame_id; + buf_event.timestamp = buf_cmd->timestamp; + buf_event.u.buf_done.session_id = + buf_cmd->u.buf_done.session_id; + buf_event.u.buf_done.stream_id = + buf_cmd->u.buf_done.stream_id; + buf_event.u.buf_done.output_format = + buf_cmd->u.buf_done.output_format; + buf_event.u.buf_done.buf_idx = + buf_cmd->u.buf_done.buf_idx; + buf_event.u.buf_done.handle = + buf_cmd->u.buf_done.handle; + + vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr, + buf_event.u.buf_done.handle, + buf_event.u.buf_done.buf_idx, + &buf_event.timestamp, buf_event.frame_id, + buf_event.u.buf_done.output_format); + return rc; +} diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.h new file mode 100644 index 000000000000..5d89a8481602 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.h @@ -0,0 +1,72 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __MSM_ISP_AXI_UTIL_H__ +#define __MSM_ISP_AXI_UTIL_H__ + +#include "msm_isp_32.h" + +int msm_isp_axi_create_stream( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe32_axi_stream_request_cmd *stream_cfg_cmd); + +void msm_isp_axi_destroy_stream( + struct msm_vfe_axi_shared_data *axi_data, int stream_idx); + +int msm_isp_validate_axi_request( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe32_axi_stream_request_cmd *stream_cfg_cmd); + +void msm_isp_axi_reserve_wm( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info); + +void msm_isp_axi_reserve_comp_mask( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info); + +int msm_isp_axi_check_stream_state( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd); + +void msm_isp_calculate_framedrop( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe32_axi_stream_request_cmd *stream_cfg_cmd); +void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + +void msm_isp_start_avtimer(void); +int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg); +void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev); +int msm_isp_axi_halt(struct vfe_device *vfe_dev, + struct msm_vfe_axi_halt_cmd *halt_cmd); +int msm_isp_axi_reset(struct vfe_device *vfe_dev, + struct msm_vfe_axi_reset_cmd *reset_cmd); +int msm_isp_axi_restart(struct vfe_device *vfe_dev, + struct msm_vfe_axi_restart_cmd *restart_cmd); +int msm_isp_user_buf_done(struct vfe_device *vfe_dev, + struct msm_isp32_event_data *buf_cmd); +void msm_isp_axi_stream_update(struct vfe_device *vfe_dev, + uint8_t input_src); + +void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev, + uint8_t input_src); +void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, + enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts); +void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); +void msm_isp_axi_free_wm(struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info); +#endif /* __MSM_ISP_AXI_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util_32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util_32.c new file mode 100644 index 000000000000..8273298cdda6 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util_32.c @@ -0,0 +1,709 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include "msm_isp_util_32.h" +#include "msm_isp_stats_util_32.h" + +static int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, + struct msm_isp_buffer **done_buf) +{ + int rc = -1; + struct msm_isp_buffer *buf; + uint32_t pingpong_bit = 0; + uint32_t bufq_handle = stream_info->bufq_handle; + uint32_t stats_pingpong_offset; + uint32_t stats_idx = STATS_IDX(stream_info->stream_handle); + + if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type || + stats_idx >= MSM_ISP_STATS_MAX) { + pr_err("%s Invalid stats index %d", __func__, stats_idx); + return -EINVAL; + } + + stats_pingpong_offset = + vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[ + stats_idx]; + + pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1); + rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, + vfe_dev->pdev->id, bufq_handle, + MSM_ISP_INVALID_BUF_INDEX, &buf); + if (rc < 0) { + vfe_dev->error_info.stats_framedrop_count[stats_idx]++; + return rc; + } + + if (buf->num_planes != 1) { + pr_err("%s: Invalid buffer\n", __func__); + rc = -EINVAL; + goto buf_error; + } + + vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr( + vfe_dev, stream_info, + pingpong_status, buf->mapped_info[0].paddr + + stream_info->buffer_offset); + + if (stream_info->buf[pingpong_bit] && done_buf) + *done_buf = stream_info->buf[pingpong_bit]; + + stream_info->buf[pingpong_bit] = buf; + return 0; +buf_error: + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + return rc; +} + +void msm_isp_process_stats_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + int i, j, rc; + struct msm_isp32_event_data buf_event; + struct msm_isp_stats_event *stats_event = &buf_event.u.stats; + struct msm_isp_buffer *done_buf; + struct msm_vfe_stats_stream *stream_info = NULL; + uint32_t pingpong_status; + uint32_t comp_stats_type_mask = 0, atomic_stats_mask = 0; + uint32_t stats_comp_mask = 0, stats_irq_mask = 0; + uint32_t num_stats_comp_mask = + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; + stats_comp_mask = vfe_dev->hw_info->vfe_ops.stats_ops. + get_comp_mask(irq_status0, irq_status1); + stats_irq_mask = vfe_dev->hw_info->vfe_ops.stats_ops. + get_wm_mask(irq_status0, irq_status1); + if (!(stats_comp_mask || stats_irq_mask)) + return; + ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0); + + /* + * If any of composite mask is set, clear irq bits from mask, + * they will be restored by comp mask + */ + if (stats_comp_mask) { + for (j = 0; j < num_stats_comp_mask; j++) { + stats_irq_mask &= ~atomic_read( + &vfe_dev->stats_data.stats_comp_mask[j]); + } + } + + for (j = 0; j < num_stats_comp_mask; j++) { + atomic_stats_mask = atomic_read( + &vfe_dev->stats_data.stats_comp_mask[j]); + if (!stats_comp_mask) { + stats_irq_mask &= ~atomic_stats_mask; + } else { + /* restore irq bits from composite mask */ + if (stats_comp_mask & (1 << j)) + stats_irq_mask |= atomic_stats_mask; + } + /* if no irq bits set from this composite mask continue*/ + if (!stats_irq_mask) + continue; + memset(&buf_event, 0, sizeof(struct msm_isp32_event_data)); + buf_event.timestamp = ts->event_time; + buf_event.frame_id = + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; + buf_event.input_intf = VFE_PIX_0; + pingpong_status = vfe_dev->hw_info-> + vfe_ops.stats_ops.get_pingpong_status(vfe_dev); + + for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; + i++) { + if (!(stats_irq_mask & (1 << i))) + continue; + + stats_irq_mask &= ~(1 << i); + stream_info = &vfe_dev->stats_data.stream_info[i]; + done_buf = NULL; + msm_isp_stats_cfg_ping_pong_address(vfe_dev, + stream_info, pingpong_status, &done_buf); + if (done_buf) { + rc = vfe_dev->buf_mgr->ops->buf_divert( + vfe_dev->buf_mgr, done_buf->bufq_handle, + done_buf->buf_idx, &ts->buf_time, + vfe_dev->axi_data. + src_info[VFE_PIX_0].frame_id); + if (rc != 0) + continue; + + stats_event->stats_buf_idxs + [stream_info->stats_type] = + done_buf->buf_idx; + if (!stream_info->composite_flag) { + stats_event->stats_mask = + 1 << stream_info->stats_type; + ISP_DBG("%s: stats frameid: 0x%x %d\n", + __func__, buf_event.frame_id, + stream_info->stats_type); + msm_isp_send_event(vfe_dev, + ISP_EVENT_STATS_NOTIFY + + stream_info->stats_type, + &buf_event); + } else { + comp_stats_type_mask |= + 1 << stream_info->stats_type; + } + } + } + + if (comp_stats_type_mask) { + ISP_DBG("%s: comp_stats frameid: 0x%x, 0x%x\n", + __func__, buf_event.frame_id, + comp_stats_type_mask); + stats_event->stats_mask = comp_stats_type_mask; + msm_isp_send_event(vfe_dev, + ISP_EVENT_COMP_STATS_NOTIFY, &buf_event); + comp_stats_type_mask = 0; + } + } +} + +int msm_isp_stats_create_stream(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream_request_cmd *stream_req_cmd) +{ + int rc = -1; + struct msm_vfe_stats_stream *stream_info = NULL; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + uint32_t stats_idx; + + if (!(vfe_dev->hw_info->stats_hw_info->stats_capability_mask & + (1 << stream_req_cmd->stats_type))) { + pr_err("%s: Stats type not supported\n", __func__); + return rc; + } + + stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops. + get_stats_idx(stream_req_cmd->stats_type); + + if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, stats_idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[stats_idx]; + if (stream_info->state != STATS_AVAILABLE) { + pr_err("%s: Stats already requested\n", __func__); + return rc; + } + + if (stream_req_cmd->framedrop_pattern >= MAX_SKIP) { + pr_err("%s: Invalid framedrop pattern\n", __func__); + return rc; + } + + if (stream_req_cmd->irq_subsample_pattern >= MAX_SKIP) { + pr_err("%s: Invalid irq subsample pattern\n", __func__); + return rc; + } + + stream_info->session_id = stream_req_cmd->session_id; + stream_info->stream_id = stream_req_cmd->stream_id; + stream_info->composite_flag = stream_req_cmd->composite_flag; + stream_info->stats_type = stream_req_cmd->stats_type; + stream_info->buffer_offset = stream_req_cmd->buffer_offset; + stream_info->framedrop_pattern = stream_req_cmd->framedrop_pattern; + stream_info->init_stats_frame_drop = stream_req_cmd->init_frame_drop; + stream_info->irq_subsample_pattern = + stream_req_cmd->irq_subsample_pattern; + stream_info->state = STATS_INACTIVE; + + if ((vfe_dev->stats_data.stream_handle_cnt << 8) == 0) + vfe_dev->stats_data.stream_handle_cnt++; + + stream_req_cmd->stream_handle = + (++vfe_dev->stats_data.stream_handle_cnt) << 8 | stats_idx; + + stream_info->stream_handle = stream_req_cmd->stream_handle; + return 0; +} + +int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = -1; + struct msm_vfe_stats_stream_request_cmd *stream_req_cmd = arg; + struct msm_vfe_stats_stream *stream_info = NULL; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + uint32_t framedrop_period; + uint32_t stats_idx; + + rc = msm_isp_stats_create_stream(vfe_dev, stream_req_cmd); + if (rc < 0) { + pr_err("%s: create stream failed\n", __func__); + return rc; + } + + stats_idx = STATS_IDX(stream_req_cmd->stream_handle); + + if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, stats_idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[stats_idx]; + + framedrop_period = msm_isp_get_framedrop_period( + stream_req_cmd->framedrop_pattern); + + if (stream_req_cmd->framedrop_pattern == SKIP_ALL) + stream_info->framedrop_pattern = 0x0; + else + stream_info->framedrop_pattern = 0x1; + stream_info->framedrop_period = framedrop_period - 1; + + if (!stream_info->composite_flag) + vfe_dev->hw_info->vfe_ops.stats_ops. + cfg_wm_irq_mask(vfe_dev, stream_info); + + if (stream_info->init_stats_frame_drop == 0) + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev, + stream_info); + + return rc; +} + +int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = -1; + struct msm_vfe_stats_stream_cfg_cmd stream_cfg_cmd; + struct msm_vfe_stats_stream_release_cmd *stream_release_cmd = arg; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + int stats_idx = STATS_IDX(stream_release_cmd->stream_handle); + struct msm_vfe_stats_stream *stream_info = NULL; + + if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, stats_idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[stats_idx]; + if (stream_info->state == STATS_AVAILABLE) { + pr_err("%s: stream already release\n", __func__); + return rc; + } else if (stream_info->state != STATS_INACTIVE) { + stream_cfg_cmd.enable = 0; + stream_cfg_cmd.num_streams = 1; + stream_cfg_cmd.stream_handle[0] = + stream_release_cmd->stream_handle; + rc = msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd); + } + + if (!stream_info->composite_flag) + vfe_dev->hw_info->vfe_ops.stats_ops. + clear_wm_irq_mask(vfe_dev, stream_info); + + vfe_dev->hw_info->vfe_ops.stats_ops.clear_wm_reg(vfe_dev, stream_info); + memset(stream_info, 0, sizeof(struct msm_vfe_stats_stream)); + return 0; +} + +static int msm_isp_init_stats_ping_pong_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int rc = 0; + + stream_info->bufq_handle = + vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, stream_info->session_id, + stream_info->stream_id); + if (stream_info->bufq_handle == 0) { + pr_err("%s: no buf configured for stream: 0x%x\n", + __func__, stream_info->stream_handle); + return -EINVAL; + } + + rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, + stream_info, VFE_PING_FLAG, NULL); + if (rc < 0) { + pr_err("%s: No free buffer for ping\n", __func__); + return rc; + } + rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, + stream_info, VFE_PONG_FLAG, NULL); + if (rc < 0) { + pr_err("%s: No free buffer for pong\n", __func__); + return rc; + } + return rc; +} + +static void msm_isp_deinit_stats_ping_pong_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int i; + struct msm_isp_buffer *buf; + + for (i = 0; i < 2; i++) { + buf = stream_info->buf[i]; + if (buf) + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + } +} + +void msm_isp_update_stats_framedrop_reg(struct vfe_device *vfe_dev) +{ + int i; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + struct msm_vfe_stats_stream *stream_info = NULL; + + for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) { + stream_info = &stats_data->stream_info[i]; + if (stream_info->state != STATS_ACTIVE) + continue; + + if (stream_info->init_stats_frame_drop) { + stream_info->init_stats_frame_drop--; + if (stream_info->init_stats_frame_drop == 0) { + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg( + vfe_dev, stream_info); + } + } + } +} + +void msm_isp_stats_stream_update(struct vfe_device *vfe_dev) +{ + int i; + uint32_t stats_mask = 0, comp_stats_mask = 0; + uint32_t enable = 0; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + + for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) { + if (stats_data->stream_info[i].state == STATS_START_PENDING || + stats_data->stream_info[i].state == + STATS_STOP_PENDING) { + stats_mask |= i; + enable = stats_data->stream_info[i].state == + STATS_START_PENDING ? 1 : 0; + stats_data->stream_info[i].state = + stats_data->stream_info[i].state == + STATS_START_PENDING ? + STATS_STARTING : STATS_STOPPING; + vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( + vfe_dev, BIT(i), enable); + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( + vfe_dev, BIT(i), enable); + } else if (stats_data->stream_info[i].state == STATS_STARTING || + stats_data->stream_info[i].state == STATS_STOPPING) { + if (stats_data->stream_info[i].composite_flag) + comp_stats_mask |= i; + stats_data->stream_info[i].state = + stats_data->stream_info[i].state == + STATS_STARTING ? STATS_ACTIVE : STATS_INACTIVE; + } + } + atomic_sub(1, &stats_data->stats_update); + if (!atomic_read(&stats_data->stats_update)) + complete(&vfe_dev->stats_config_complete); +} + +static int msm_isp_stats_wait_for_cfg_done(struct vfe_device *vfe_dev) +{ + int rc; + + init_completion(&vfe_dev->stats_config_complete); + atomic_set(&vfe_dev->stats_data.stats_update, 2); + rc = wait_for_completion_timeout( + &vfe_dev->stats_config_complete, + msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); + if (rc == 0) { + pr_err("%s: wait timeout\n", __func__); + rc = -1; + } else { + rc = 0; + } + return rc; +} + +static int msm_isp_stats_update_cgc_override(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) +{ + int i; + uint32_t stats_mask = 0, idx; + + if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) { + pr_err("%s invalid num_streams %d\n", __func__, + stream_cfg_cmd->num_streams); + return -EINVAL; + } + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); + + if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, idx); + return -EINVAL; + } + stats_mask |= 1 << idx; + } + + if (vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override) { + vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override( + vfe_dev, stats_mask, stream_cfg_cmd->enable); + } + return 0; +} + +static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) +{ + int i, rc = 0; + uint32_t stats_mask = 0, idx; + uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; + uint32_t num_stats_comp_mask = 0; + struct msm_vfe_stats_stream *stream_info; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + + if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) { + pr_err("%s invalid num_streams %d\n", __func__, + stream_cfg_cmd->num_streams); + return -EINVAL; + } + + num_stats_comp_mask = + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; + rc = vfe_dev->hw_info->vfe_ops.stats_ops.check_streams( + stats_data->stream_info); + if (rc < 0) + return rc; + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); + + if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[idx]; + if (stream_info->stream_handle != + stream_cfg_cmd->stream_handle[i]) { + pr_err("%s: Invalid stream handle: 0x%x received\n", + __func__, stream_cfg_cmd->stream_handle[i]); + continue; + } + + if (stream_info->composite_flag > num_stats_comp_mask) { + pr_err("%s: comp grp %d exceed max %d\n", + __func__, stream_info->composite_flag, + num_stats_comp_mask); + return -EINVAL; + } + rc = msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info); + if (rc < 0) { + pr_err("%s: No buffer for stream%d type:%d stmID:0x%x\n", + __func__, idx, stream_info->stats_type, + stream_info->stream_id); + return rc; + } + + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) + stream_info->state = STATS_START_PENDING; + else + stream_info->state = STATS_ACTIVE; + + stats_data->num_active_stream++; + stats_mask |= 1 << idx; + + if (stream_info->composite_flag > 0) + comp_stats_mask[stream_info->composite_flag-1] |= + 1 << idx; + + ISP_DBG("%s: stats_mask %x %x active streams %d\n", + __func__, comp_stats_mask[0], + comp_stats_mask[1], + stats_data->num_active_stream); + + } + + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { + rc = msm_isp_stats_wait_for_cfg_done(vfe_dev); + } else { + vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( + vfe_dev, stats_mask, stream_cfg_cmd->enable); + for (i = 0; i < num_stats_comp_mask; i++) { + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( + vfe_dev, comp_stats_mask[i], 1); + } + } + return rc; +} + +static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) +{ + int i, rc = 0; + uint32_t stats_mask = 0, idx; + uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; + uint32_t num_stats_comp_mask = 0; + struct msm_vfe_stats_stream *stream_info; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + + num_stats_comp_mask = + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + + idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); + + if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[idx]; + if (stream_info->stream_handle != + stream_cfg_cmd->stream_handle[i]) { + pr_err("%s: Invalid stream handle: 0x%x received\n", + __func__, stream_cfg_cmd->stream_handle[i]); + continue; + } + + if (stream_info->composite_flag > num_stats_comp_mask) { + pr_err("%s: comp grp %d exceed max %d\n", + __func__, stream_info->composite_flag, + num_stats_comp_mask); + return -EINVAL; + } + + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) + stream_info->state = STATS_STOP_PENDING; + else + stream_info->state = STATS_INACTIVE; + + stats_data->num_active_stream--; + stats_mask |= 1 << idx; + + if (stream_info->composite_flag > 0) + comp_stats_mask[stream_info->composite_flag-1] |= + 1 << idx; + + ISP_DBG("%s: stats_mask %x %x active streams %d\n", + __func__, comp_stats_mask[0], + comp_stats_mask[1], + stats_data->num_active_stream); + } + + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { + rc = msm_isp_stats_wait_for_cfg_done(vfe_dev); + } else { + vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( + vfe_dev, stats_mask, stream_cfg_cmd->enable); + for (i = 0; i < num_stats_comp_mask; i++) { + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( + vfe_dev, comp_stats_mask[i], 0); + } + } + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); + + if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[idx]; + msm_isp_deinit_stats_ping_pong_reg(vfe_dev, stream_info); + } + return rc; +} + +int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg; + + if (vfe_dev->stats_data.num_active_stream == 0) + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev); + + if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) { + pr_err("%s invalid num_streams %d\n", __func__, + stream_cfg_cmd->num_streams); + return -EINVAL; + } + + if (stream_cfg_cmd->enable) { + msm_isp_stats_update_cgc_override(vfe_dev, stream_cfg_cmd); + + rc = msm_isp_start_stats_stream(vfe_dev, stream_cfg_cmd); + } else { + rc = msm_isp_stop_stats_stream(vfe_dev, stream_cfg_cmd); + + msm_isp_stats_update_cgc_override(vfe_dev, stream_cfg_cmd); + } + + return rc; +} + +int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0, i; + struct msm_vfe_stats_stream *stream_info; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + struct msm_vfe_axi_stream_update_cmd *update_cmd = arg; + struct msm_vfe_axi_stream_cfg_update_info *update_info = NULL; + + /*validate request*/ + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = &update_cmd->update_info[i]; + /*check array reference bounds*/ + if (STATS_IDX(update_info->stream_handle) + > vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s: stats idx %d out of bound!", __func__, + STATS_IDX(update_info->stream_handle)); + return -EINVAL; + } + } + + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = &update_cmd->update_info[i]; + stream_info = &stats_data->stream_info[ + STATS_IDX(update_info->stream_handle)]; + if (stream_info->stream_handle != + update_info->stream_handle) { + pr_err("%s: stats stream handle %x %x mismatch!\n", + __func__, stream_info->stream_handle, + update_info->stream_handle); + continue; + } + + switch (update_cmd->update_type) { + case UPDATE_STREAM_STATS_FRAMEDROP_PATTERN: { + uint32_t framedrop_period = + msm_isp_get_framedrop_period( + update_info->skip_pattern); + if (update_info->skip_pattern == SKIP_ALL) + stream_info->framedrop_pattern = 0x0; + else + stream_info->framedrop_pattern = 0x1; + stream_info->framedrop_period = framedrop_period - 1; + if (stream_info->init_stats_frame_drop == 0) + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg( + vfe_dev, stream_info); + break; + } + + default: + pr_err("%s: Invalid update type\n", __func__); + return -EINVAL; + } + } + return rc; +} diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util_32.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util_32.h new file mode 100644 index 000000000000..11c0c28bcbe9 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util_32.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __MSM_ISP_STATS_UTIL_H__ +#define __MSM_ISP_STATS_UTIL_H__ + +#include "msm_isp_32.h" +#define STATS_IDX(idx) (idx & 0xFF) + +void msm_isp_process_stats_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); +int msm_isp_stats_create_stream(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream_request_cmd *stream_req_cmd); +void msm_isp_stats_stream_update(struct vfe_device *vfe_dev); +int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg); +void msm_isp_update_stats_framedrop_reg(struct vfe_device *vfe_dev); +#endif /* __MSM_ISP_STATS_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util_32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util_32.c new file mode 100644 index 000000000000..f6ca41cd9211 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util_32.c @@ -0,0 +1,1939 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include + +#include "msm.h" +#include "msm_isp_util_32.h" +#include "msm_isp_axi_util_32.h" +#include "msm_isp_stats_util_32.h" +#include "msm_camera_io_util.h" +#include "cam_smmu_api.h" + +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif + +#define MAX_ISP_V4l2_EVENTS 100 +#define MAX_ISP_REG_LIST 100 +static DEFINE_MUTEX(bandwidth_mgr_mutex); +static struct msm_isp_bandwidth_mgr isp_bandwidth_mgr; + +static uint64_t msm_isp_cpp_clk_rate; + +#define VFE40_8974V2_VERSION 0x1001001A +static struct msm_bus_vectors msm_isp_init_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors msm_isp_ping_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = MSM_ISP_MIN_AB, + .ib = MSM_ISP_MIN_IB, + }, +}; + +static struct msm_bus_vectors msm_isp_pong_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = MSM_ISP_MIN_AB, + .ib = MSM_ISP_MIN_IB, + }, +}; + +static struct msm_bus_paths msm_isp_bus_client_config[] = { + { + ARRAY_SIZE(msm_isp_init_vectors), + msm_isp_init_vectors, + }, + { + ARRAY_SIZE(msm_isp_ping_vectors), + msm_isp_ping_vectors, + }, + { + ARRAY_SIZE(msm_isp_pong_vectors), + msm_isp_pong_vectors, + }, +}; + +static struct msm_bus_scale_pdata msm_isp_bus_client_pdata = { + msm_isp_bus_client_config, + NULL, + ARRAY_SIZE(msm_isp_bus_client_config), + .name = "msm_camera_isp", + 0, +}; + + +void msm_camera_io_dump_2(void __iomem *addr, int size) +{ + char line_str[128], *p_str; + int i; + u32 __iomem *p = (u32 __iomem *) addr; + u32 data; + + pr_err("%s: %pK %d\n", __func__, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size/4; i++) { + if (i % 4 == 0) { +#ifdef CONFIG_COMPAT + snprintf(p_str, 20, "%016lx: ", (unsigned long) p); + p_str += 18; +#else + snprintf(p_str, 12, "%08lx: ", (unsigned long) p); + p_str += 10; +#endif + } + data = readl_relaxed(p++); + snprintf(p_str, 12, "%08x ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + pr_err("%s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + pr_err("%s\n", line_str); +} + +void msm_isp_print_fourcc_error(const char *origin, uint32_t fourcc_format) +{ + int i; + char text[5]; + + text[4] = '\0'; + for (i = 0; i < 4; i++) { + text[i] = (char)(((fourcc_format) >> (i * 8)) & 0xFF); + if ((text[i] < '0') || (text[i] > 'z')) { + pr_err("%s: Invalid output format %d (unprintable)\n", + origin, fourcc_format); + return; + } + } + pr_err("%s: Invalid output format %s\n", + origin, text); +} + +int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client) +{ + int rc = 0; + + mutex_lock(&bandwidth_mgr_mutex); + isp_bandwidth_mgr.client_info[client].active = 1; + if (isp_bandwidth_mgr.use_count++) { + mutex_unlock(&bandwidth_mgr_mutex); + return rc; + } + isp_bandwidth_mgr.bus_client = + msm_bus_scale_register_client(&msm_isp_bus_client_pdata); + if (!isp_bandwidth_mgr.bus_client) { + pr_err("%s: client register failed\n", __func__); + mutex_unlock(&bandwidth_mgr_mutex); + return -EINVAL; + } + + isp_bandwidth_mgr.bus_vector_active_idx = 1; + msm_bus_scale_client_update_request( + isp_bandwidth_mgr.bus_client, + isp_bandwidth_mgr.bus_vector_active_idx); + + mutex_unlock(&bandwidth_mgr_mutex); + return 0; +} + +int msm_isp_update_bandwidth(enum msm_isp_hw_client client, + uint64_t ab, uint64_t ib) +{ + int i; + struct msm_bus_paths *path; + + mutex_lock(&bandwidth_mgr_mutex); + if (!isp_bandwidth_mgr.use_count || + !isp_bandwidth_mgr.bus_client) { + pr_err("%s:error bandwidth manager inactive use_cnt:%d bus_clnt:%d\n", + __func__, isp_bandwidth_mgr.use_count, + isp_bandwidth_mgr.bus_client); + return -EINVAL; + } + + isp_bandwidth_mgr.client_info[client].ab = ab; + isp_bandwidth_mgr.client_info[client].ib = ib; + ALT_VECTOR_IDX(isp_bandwidth_mgr.bus_vector_active_idx); + path = + &(msm_isp_bus_client_pdata.usecase[ + isp_bandwidth_mgr.bus_vector_active_idx]); + path->vectors[0].ab = 0; + path->vectors[0].ib = 0; + for (i = 0; i < MAX_ISP_CLIENT; i++) { + if (isp_bandwidth_mgr.client_info[i].active) { + path->vectors[0].ab += + isp_bandwidth_mgr.client_info[i].ab; + path->vectors[0].ib += + isp_bandwidth_mgr.client_info[i].ib; + } + } + ISP_DBG("%s: Total AB = %llu IB = %llu\n", __func__, + path->vectors[0].ab, path->vectors[0].ib); + msm_bus_scale_client_update_request(isp_bandwidth_mgr.bus_client, + isp_bandwidth_mgr.bus_vector_active_idx); + /* Insert into circular buffer */ + msm_isp_update_req_history(isp_bandwidth_mgr.bus_client, + path->vectors[0].ab, + path->vectors[0].ib, + isp_bandwidth_mgr.client_info, + sched_clock()); + mutex_unlock(&bandwidth_mgr_mutex); + return 0; +} + +void msm_isp_deinit_bandwidth_mgr(enum msm_isp_hw_client client) +{ + if (client >= MAX_ISP_CLIENT) { + pr_err("invalid Client id %d", client); + return; + } + mutex_lock(&bandwidth_mgr_mutex); + memset(&isp_bandwidth_mgr.client_info[client], 0, + sizeof(struct msm_isp_bandwidth_info)); + if (--isp_bandwidth_mgr.use_count) { + mutex_unlock(&bandwidth_mgr_mutex); + return; + } + + if (!isp_bandwidth_mgr.bus_client) { + pr_err("%s:%d error: bus client invalid\n", __func__, __LINE__); + mutex_unlock(&bandwidth_mgr_mutex); + return; + } + + msm_bus_scale_client_update_request( + isp_bandwidth_mgr.bus_client, 0); + msm_bus_scale_unregister_client(isp_bandwidth_mgr.bus_client); + isp_bandwidth_mgr.bus_client = 0; + mutex_unlock(&bandwidth_mgr_mutex); +} + +void msm_isp_util_get_bandwidth_stats(struct vfe_device *vfe_dev, + struct msm_isp_statistics *stats) +{ + stats->isp_vfe0_active = isp_bandwidth_mgr.client_info[ISP_VFE0].active; + stats->isp_vfe0_ab = isp_bandwidth_mgr.client_info[ISP_VFE0].ab; + stats->isp_vfe0_ib = isp_bandwidth_mgr.client_info[ISP_VFE0].ib; + + stats->isp_vfe1_active = isp_bandwidth_mgr.client_info[ISP_VFE1].active; + stats->isp_vfe1_ab = isp_bandwidth_mgr.client_info[ISP_VFE1].ab; + stats->isp_vfe1_ib = isp_bandwidth_mgr.client_info[ISP_VFE1].ib; + + stats->isp_cpp_active = isp_bandwidth_mgr.client_info[ISP_CPP].active; + stats->isp_cpp_ab = isp_bandwidth_mgr.client_info[ISP_CPP].ab; + stats->isp_cpp_ib = isp_bandwidth_mgr.client_info[ISP_CPP].ib; + stats->last_overflow_ab = vfe_dev->msm_isp_last_overflow_ab; + stats->last_overflow_ib = vfe_dev->msm_isp_last_overflow_ib; + stats->vfe_clk_rate = vfe_dev->msm_isp_vfe_clk_rate; + stats->cpp_clk_rate = msm_isp_cpp_clk_rate; +} + +void msm_isp_util_update_last_overflow_ab_ib(struct vfe_device *vfe_dev) +{ + struct msm_bus_paths *path; + path = &(msm_isp_bus_client_pdata.usecase[ + isp_bandwidth_mgr.bus_vector_active_idx]); + vfe_dev->msm_isp_last_overflow_ab = path->vectors[0].ab; + vfe_dev->msm_isp_last_overflow_ib = path->vectors[0].ib; +} + +void msm_isp_util_update_clk_rate(long clock_rate) +{ + msm_isp_cpp_clk_rate = clock_rate; +} + +uint32_t msm_isp_get_framedrop_period( + enum msm_vfe_frame_skip_pattern frame_skip_pattern) +{ + switch (frame_skip_pattern) { + case NO_SKIP: + case EVERY_2FRAME: + case EVERY_3FRAME: + case EVERY_4FRAME: + case EVERY_5FRAME: + case EVERY_6FRAME: + case EVERY_7FRAME: + case EVERY_8FRAME: + return frame_skip_pattern + 1; + case EVERY_16FRAME: + return 16; + case EVERY_32FRAME: + return 32; + case SKIP_ALL: + return 1; + default: + return 1; + } + return 1; +} + +int msm_isp_get_clk_info(struct vfe_device *vfe_dev, + struct platform_device *pdev, struct msm_cam_clk_info *vfe_clk_info) +{ + int i, count, rc; + uint32_t rates[VFE_CLK_INFO_MAX]; + + struct device_node *of_node; + + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + + ISP_DBG("count = %d\n", count); + if (count <= 0) { + pr_err("no clocks found in device tree, count=%d", count); + return 0; + } + + if (count > VFE_CLK_INFO_MAX) { + pr_err("invalid count=%d, max is %d\n", count, + VFE_CLK_INFO_MAX); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(vfe_clk_info[i].clk_name)); + ISP_DBG("clock-names[%d] = %s\n", i, vfe_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + vfe_clk_info[i].clk_rate = + (rates[i] == 0) ? (long)-1 : rates[i]; + ISP_DBG("clk_rate[%d] = %ld\n", i, vfe_clk_info[i].clk_rate); + } + vfe_dev->num_clk = count; + return 0; +} + +void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp, + struct vfe_device *vfe_dev) +{ + struct timespec ts; + + do_gettimeofday(&(time_stamp->event_time)); + if (vfe_dev->vt_enable) { + msm_isp_get_avtimer_ts(time_stamp); + time_stamp->buf_time.tv_sec = time_stamp->vt_time.tv_sec; + time_stamp->buf_time.tv_usec = time_stamp->vt_time.tv_usec; + } else { + get_monotonic_boottime(&ts); + time_stamp->buf_time.tv_sec = ts.tv_sec; + time_stamp->buf_time.tv_usec = ts.tv_nsec/1000; + } +} + +int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + int rc = 0; + + rc = v4l2_event_subscribe(fh, sub, MAX_ISP_V4l2_EVENTS, NULL); + if (rc == 0) { + if (sub->type == V4L2_EVENT_ALL) { + int i; + + vfe_dev->axi_data.event_mask = 0; + for (i = 0; i < ISP_EVENT_MAX; i++) + vfe_dev->axi_data.event_mask |= (1 << i); + } else { + int event_idx = sub->type - ISP_EVENT_BASE; + + vfe_dev->axi_data.event_mask |= (1 << event_idx); + } + } + return rc; +} + +int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + int rc = 0; + + rc = v4l2_event_unsubscribe(fh, sub); + if (sub->type == V4L2_EVENT_ALL) { + vfe_dev->axi_data.event_mask = 0; + } else { + int event_idx = sub->type - ISP_EVENT_BASE; + + vfe_dev->axi_data.event_mask &= ~(1 << event_idx); + } + return rc; +} + +static int msm_isp_get_max_clk_rate(struct vfe_device *vfe_dev, long *rate) +{ + int clk_idx = 0; + unsigned long max_value = ~0; + long round_rate = 0; + + if (!vfe_dev || !rate) { + pr_err("%s:%d failed: vfe_dev %pK rate %pK\n", + __func__, __LINE__, vfe_dev, rate); + return -EINVAL; + } + + *rate = 0; + if (!vfe_dev->hw_info) { + pr_err("%s:%d failed: vfe_dev->hw_info %pK\n", __func__, + __LINE__, vfe_dev->hw_info); + return -EINVAL; + } + + clk_idx = vfe_dev->hw_info->vfe_clk_idx; + if (clk_idx >= vfe_dev->num_clk) { + pr_err("%s:%d failed: clk_idx %d max array size %d\n", + __func__, __LINE__, clk_idx, + vfe_dev->num_clk); + return -EINVAL; + } + + round_rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], max_value); + if (round_rate < 0) { + pr_err("%s: Invalid vfe clock rate\n", __func__); + return -EINVAL; + } + + *rate = round_rate; + return 0; +} + +static int msm_isp_set_clk_rate(struct vfe_device *vfe_dev, long *rate) +{ + int rc = 0; + int clk_idx = vfe_dev->hw_info->vfe_clk_idx; + long round_rate = + clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate); + if (round_rate < 0) { + pr_err("%s: Invalid vfe clock rate\n", __func__); + return round_rate; + } + + rc = clk_set_rate(vfe_dev->vfe_clk[clk_idx], round_rate); + if (rc < 0) { + pr_err("%s: Vfe set rate error\n", __func__); + return rc; + } + *rate = round_rate; + vfe_dev->msm_isp_vfe_clk_rate = round_rate; + return 0; +} + +void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev, + struct msm_vfe_fetch_engine_info *fetch_engine_info) +{ + struct msm_isp32_event_data fe_rd_done_event; + + if (!fetch_engine_info->is_busy) + return; + memset(&fe_rd_done_event, 0, sizeof(struct msm_isp32_event_data)); + fe_rd_done_event.frame_id = + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; + fe_rd_done_event.u.buf_done.session_id = fetch_engine_info->session_id; + fe_rd_done_event.u.buf_done.stream_id = fetch_engine_info->stream_id; + fe_rd_done_event.u.buf_done.handle = fetch_engine_info->bufq_handle; + fe_rd_done_event.u.buf_done.buf_idx = fetch_engine_info->buf_idx; + ISP_DBG("%s:VFE%d ISP_EVENT_FE_READ_DONE buf_idx %d\n", + __func__, vfe_dev->pdev->id, fetch_engine_info->buf_idx); + fetch_engine_info->is_busy = 0; + msm_isp_send_event(vfe_dev, ISP_EVENT_FE_READ_DONE, &fe_rd_done_event); +} + +static int msm_isp_cfg_pix(struct vfe_device *vfe_dev, + struct msm_vfe_input_cfg *input_cfg) +{ + int rc = 0; + + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { + pr_err("%s: src %d path is active\n", __func__, VFE_PIX_0); + return -EINVAL; + } + + vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock = + input_cfg->input_pix_clk; + vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux = + input_cfg->d.pix_cfg.input_mux; + vfe_dev->axi_data.src_info[VFE_PIX_0].input_format = + input_cfg->d.pix_cfg.input_format; + + rc = msm_isp_set_clk_rate(vfe_dev, + &vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock); + if (rc < 0) { + pr_err("%s: clock set rate failed\n", __func__); + return rc; + } + + ISP_DBG("%s: input mux is %d CAMIF %d io_format 0x%x\n", __func__, + input_cfg->d.pix_cfg.input_mux, CAMIF, + input_cfg->d.pix_cfg.input_format); + + if (input_cfg->d.pix_cfg.input_mux == CAMIF) { + vfe_dev->axi_data.src_info[VFE_PIX_0].width = + input_cfg->d.pix_cfg.camif_cfg.pixels_per_line; + } else if (input_cfg->d.pix_cfg.input_mux == EXTERNAL_READ) { + vfe_dev->axi_data.src_info[VFE_PIX_0].width = + input_cfg->d.pix_cfg.fetch_engine_cfg.buf_stride; + } + vfe_dev->hw_info->vfe_ops.core_ops.cfg_input_mux( + vfe_dev, &input_cfg->d.pix_cfg); + return rc; +} + +static int msm_isp_cfg_rdi(struct vfe_device *vfe_dev, + struct msm_vfe_input_cfg *input_cfg) +{ + int rc = 0; + + if (vfe_dev->axi_data.src_info[input_cfg->input_src].active) { + pr_err("%s: RAW%d path is active\n", __func__, + input_cfg->input_src - VFE_RAW_0); + return -EINVAL; + } + + vfe_dev->axi_data.src_info[input_cfg->input_src].pixel_clock = + input_cfg->input_pix_clk; + vfe_dev->hw_info->vfe_ops.core_ops.cfg_rdi_reg( + vfe_dev, &input_cfg->d.rdi_cfg, input_cfg->input_src); + return rc; +} + +int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + struct msm_vfe_input_cfg *input_cfg = arg; + + switch (input_cfg->input_src) { + case VFE_PIX_0: + rc = msm_isp_cfg_pix(vfe_dev, input_cfg); + break; + case VFE_RAW_0: + case VFE_RAW_1: + case VFE_RAW_2: + rc = msm_isp_cfg_rdi(vfe_dev, input_cfg); + break; + default: + pr_err("%s: Invalid input source\n", __func__); + rc = -EINVAL; + } + return rc; +} + +static int msm_isp_proc_cmd_list_unlocked(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + uint32_t count = 0; + struct msm_vfe_cfg_cmd_list *proc_cmd = + (struct msm_vfe_cfg_cmd_list *)arg; + struct msm_vfe_cfg_cmd_list cmd, cmd_next; + struct msm_vfe_cfg_cmd2 cfg_cmd; + + if (!vfe_dev || !arg) { + pr_err("%s:%d failed: vfe_dev %pK arg %pK", __func__, __LINE__, + vfe_dev, arg); + return -EINVAL; + } + + rc = msm_isp_proc_cmd(vfe_dev, &proc_cmd->cfg_cmd); + if (rc < 0) + pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc); + + cmd = *proc_cmd; + + while (cmd.next) { + if (cmd.next_size != sizeof(struct msm_vfe_cfg_cmd_list)) { + pr_err("%s:%d failed: next size %u != expected %zu\n", + __func__, __LINE__, cmd.next_size, + sizeof(struct msm_vfe_cfg_cmd_list)); + break; + } + if (++count >= MAX_ISP_REG_LIST) { + pr_err("%s:%d Error exceeding the max register count:%u\n", + __func__, __LINE__, count); + rc = -EFAULT; + break; + } + if (copy_from_user(&cmd_next, (void __user *)cmd.next, + sizeof(struct msm_vfe_cfg_cmd_list))) { + rc = -EFAULT; + continue; + } + + cfg_cmd = cmd_next.cfg_cmd; + + rc = msm_isp_proc_cmd(vfe_dev, &cfg_cmd); + if (rc < 0) + pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc); + + cmd = cmd_next; + } + return rc; +} + +#ifdef CONFIG_COMPAT +struct msm_vfe_cfg_cmd2_32 { + uint16_t num_cfg; + uint16_t cmd_len; + compat_caddr_t cfg_data; + compat_caddr_t cfg_cmd; +}; + +struct msm_vfe_cfg_cmd_list_32 { + struct msm_vfe_cfg_cmd2_32 cfg_cmd; + compat_caddr_t next; + uint32_t next_size; +}; + +#define VIDIOC_MSM_VFE_REG_CFG_COMPAT \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2_32) +#define VIDIOC_MSM_VFE_REG_LIST_CFG_COMPAT \ + _IOWR('V', BASE_VIDIOC_PRIVATE+14, struct msm_vfe_cfg_cmd_list_32) + +static void msm_isp_compat_to_proc_cmd(struct msm_vfe_cfg_cmd2 *proc_cmd, + struct msm_vfe_cfg_cmd2_32 *proc_cmd_ptr32) +{ + proc_cmd->num_cfg = proc_cmd_ptr32->num_cfg; + proc_cmd->cmd_len = proc_cmd_ptr32->cmd_len; + proc_cmd->cfg_data = compat_ptr(proc_cmd_ptr32->cfg_data); + proc_cmd->cfg_cmd = compat_ptr(proc_cmd_ptr32->cfg_cmd); +} + +static int msm_isp_proc_cmd_list_compat(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + uint32_t count = 0; + struct msm_vfe_cfg_cmd_list_32 *proc_cmd = + (struct msm_vfe_cfg_cmd_list_32 *)arg; + struct msm_vfe_cfg_cmd_list_32 cmd, cmd_next; + struct msm_vfe_cfg_cmd2 current_cmd; + + if (!vfe_dev || !arg) { + pr_err("%s:%d failed: vfe_dev %pK arg %pK", __func__, __LINE__, + vfe_dev, arg); + return -EINVAL; + } + msm_isp_compat_to_proc_cmd(¤t_cmd, &proc_cmd->cfg_cmd); + rc = msm_isp_proc_cmd(vfe_dev, ¤t_cmd); + if (rc < 0) + pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc); + + cmd = *proc_cmd; + + while (compat_ptr(cmd.next) != NULL) { + if (cmd.next_size != sizeof(struct msm_vfe_cfg_cmd_list_32)) { + pr_err("%s:%d failed: next size %u != expected %zu\n", + __func__, __LINE__, cmd.next_size, + sizeof(struct msm_vfe_cfg_cmd_list)); + break; + } + if (++count >= MAX_ISP_REG_LIST) { + pr_err("%s:%d Error exceeding the max register count:%u\n", + __func__, __LINE__, count); + rc = -EFAULT; + break; + } + if (copy_from_user(&cmd_next, compat_ptr(cmd.next), + sizeof(struct msm_vfe_cfg_cmd_list_32))) { + rc = -EFAULT; + continue; + } + + msm_isp_compat_to_proc_cmd(¤t_cmd, &cmd_next.cfg_cmd); + rc = msm_isp_proc_cmd(vfe_dev, ¤t_cmd); + if (rc < 0) + pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc); + + cmd = cmd_next; + } + return rc; +} + +static int msm_isp_proc_cmd_list(struct vfe_device *vfe_dev, void *arg) +{ + if (is_compat_task()) + return msm_isp_proc_cmd_list_compat(vfe_dev, arg); + else + return msm_isp_proc_cmd_list_unlocked(vfe_dev, arg); +} +#else /* CONFIG_COMPAT */ +static int msm_isp_proc_cmd_list(struct vfe_device *vfe_dev, void *arg) +{ + return msm_isp_proc_cmd_list_unlocked(vfe_dev, arg); +} +#endif /* CONFIG_COMPAT */ + + +static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + long rc = 0; + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + + if (!vfe_dev || !vfe_dev->vfe_base) { + pr_err("%s:%d failed: invalid params %pK\n", + __func__, __LINE__, vfe_dev); + if (vfe_dev) + pr_err("%s:%d failed %pK\n", __func__, + __LINE__, vfe_dev->vfe_base); + return -EINVAL; + } + + /* use real time mutex for hard real-time ioctls such as + * buffer operations and register updates. + * Use core mutex for other ioctls that could take + * longer time to complete such as start/stop ISP streams + * which blocks until the hardware start/stop streaming + */ + ISP_DBG("%s cmd: %d\n", __func__, _IOC_TYPE(cmd)); + switch (cmd) { + case VIDIOC_MSM_VFE_REG_CFG: { + mutex_lock(&vfe_dev->realtime_mutex); + rc = msm_isp_proc_cmd(vfe_dev, arg); + mutex_unlock(&vfe_dev->realtime_mutex); + break; + } + case VIDIOC_MSM_VFE_REG_LIST_CFG: { + mutex_lock(&vfe_dev->realtime_mutex); + rc = msm_isp_proc_cmd_list(vfe_dev, arg); + mutex_unlock(&vfe_dev->realtime_mutex); + break; + } + case VIDIOC_MSM_ISP_REQUEST_BUF: + case VIDIOC_MSM_ISP_ENQUEUE_BUF: + case VIDIOC_MSM_ISP_RELEASE_BUF: { + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_proc_buf_cmd(vfe_dev->buf_mgr, cmd, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + } + case VIDIOC_MSM_ISP32_REQUEST_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_request_axi_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_RELEASE_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_release_axi_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_CFG_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_cfg_axi_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_AXI_HALT: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_axi_halt(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_AXI_RESET: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_axi_reset(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_AXI_RESTART: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_axi_restart(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_INPUT_CFG: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_cfg_input(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_FETCH_ENG_START: + mutex_lock(&vfe_dev->core_mutex); + rc = vfe_dev->hw_info->vfe_ops.core_ops. + start_fetch_eng(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_REG_UPDATE_CMD: + if (arg) { + enum msm_vfe_input_src frame_src = + *((enum msm_vfe_input_src *)arg); + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev, (1 << frame_src)); + vfe_dev->axi_data.src_info[frame_src].last_updt_frm_id = + vfe_dev->axi_data.src_info[frame_src].frame_id; + } + break; + case VIDIOC_MSM_ISP_SET_SRC_STATE: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_set_src_state(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_REQUEST_STATS_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_request_stats_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_RELEASE_STATS_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_release_stats_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_CFG_STATS_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_cfg_stats_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_UPDATE_STATS_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_update_stats_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_UPDATE_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_update_axi_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_SMMU_ATTACH: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_smmu_attach(vfe_dev->buf_mgr, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case MSM_SD_NOTIFY_FREEZE: + vfe_dev->isp_sof_debug = 0; + break; + case VIDIOC_MSM_ISP_BUF_DONE: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_user_buf_done(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case MSM_SD_SHUTDOWN: + while (vfe_dev->vfe_open_cnt != 0) + msm_isp_close_node(sd, NULL); + break; + + default: + pr_err_ratelimited("%s: Invalid ISP command\n", __func__); + rc = -EINVAL; + } + return rc; +} + + +#ifdef CONFIG_COMPAT +static long msm_isp_ioctl_compat(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + long rc = 0; + + if (!vfe_dev || !vfe_dev->vfe_base) { + pr_err("%s:%d failed: invalid params %pK\n", + __func__, __LINE__, vfe_dev); + if (vfe_dev) + pr_err("%s:%d failed %pK\n", __func__, + __LINE__, vfe_dev->vfe_base); + return -EINVAL; + } + + switch (cmd) { + case VIDIOC_MSM_VFE_REG_CFG_COMPAT: { + struct msm_vfe_cfg_cmd2 proc_cmd; + + mutex_lock(&vfe_dev->realtime_mutex); + msm_isp_compat_to_proc_cmd(&proc_cmd, + (struct msm_vfe_cfg_cmd2_32 *) arg); + rc = msm_isp_proc_cmd(vfe_dev, &proc_cmd); + mutex_unlock(&vfe_dev->realtime_mutex); + break; + } + case VIDIOC_MSM_VFE_REG_LIST_CFG_COMPAT: { + mutex_lock(&vfe_dev->realtime_mutex); + rc = msm_isp_proc_cmd_list(vfe_dev, arg); + mutex_unlock(&vfe_dev->realtime_mutex); + break; + } + default: + return msm_isp_ioctl_unlocked(sd, cmd, arg); + } + + return rc; +} + +long msm_isp_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + return msm_isp_ioctl_compat(sd, cmd, arg); +} +#else /* CONFIG_COMPAT */ +long msm_isp_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + return msm_isp_ioctl_unlocked(sd, cmd, arg); +} +#endif /* CONFIG_COMPAT */ + +static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, + struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd, + uint32_t *cfg_data, uint32_t cmd_len) +{ + if (!vfe_dev || !reg_cfg_cmd) { + pr_err("%s:%d failed: vfe_dev %pK reg_cfg_cmd %pK\n", __func__, + __LINE__, vfe_dev, reg_cfg_cmd); + return -EINVAL; + } + if ((reg_cfg_cmd->cmd_type != VFE_CFG_MASK) && + (!cfg_data || !cmd_len)) { + pr_err("%s:%d failed: cmd type %d cfg_data %pK cmd_len %d\n", + __func__, __LINE__, reg_cfg_cmd->cmd_type, cfg_data, + cmd_len); + return -EINVAL; + } + + /* Validate input parameters */ + switch (reg_cfg_cmd->cmd_type) { + case VFE_WRITE: + case VFE_READ: + case VFE_WRITE_MB: { + if ((reg_cfg_cmd->u.rw_info.reg_offset > + (UINT_MAX - reg_cfg_cmd->u.rw_info.len)) || + ((reg_cfg_cmd->u.rw_info.reg_offset + + reg_cfg_cmd->u.rw_info.len) > + resource_size(vfe_dev->vfe_mem)) || + (reg_cfg_cmd->u.rw_info.reg_offset & 0x3)) { + pr_err("%s:%d reg_offset %d len %d res %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.rw_info.reg_offset, + reg_cfg_cmd->u.rw_info.len, + (uint32_t)resource_size(vfe_dev->vfe_mem)); + return -EINVAL; + } + + if ((reg_cfg_cmd->u.rw_info.cmd_data_offset > + (UINT_MAX - reg_cfg_cmd->u.rw_info.len)) || + ((reg_cfg_cmd->u.rw_info.cmd_data_offset + + reg_cfg_cmd->u.rw_info.len) > cmd_len)) { + pr_err("%s:%d cmd_data_offset %d len %d cmd_len %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.rw_info.cmd_data_offset, + reg_cfg_cmd->u.rw_info.len, cmd_len); + return -EINVAL; + } + break; + } + + case VFE_WRITE_DMI_16BIT: + case VFE_WRITE_DMI_32BIT: + case VFE_WRITE_DMI_64BIT: + case VFE_READ_DMI_16BIT: + case VFE_READ_DMI_32BIT: + case VFE_READ_DMI_64BIT: { + if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT || + reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { + if ((reg_cfg_cmd->u.dmi_info.hi_tbl_offset <= + reg_cfg_cmd->u.dmi_info.lo_tbl_offset) || + (reg_cfg_cmd->u.dmi_info.hi_tbl_offset - + reg_cfg_cmd->u.dmi_info.lo_tbl_offset != + (sizeof(uint32_t)))) { + pr_err("%s:%d hi %d lo %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.hi_tbl_offset, + reg_cfg_cmd->u.dmi_info.hi_tbl_offset); + return -EINVAL; + } + if (reg_cfg_cmd->u.dmi_info.len <= sizeof(uint32_t)) { + pr_err("%s:%d len %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.len); + return -EINVAL; + } + if (((UINT_MAX - + reg_cfg_cmd->u.dmi_info.hi_tbl_offset) < + (reg_cfg_cmd->u.dmi_info.len - + sizeof(uint32_t))) || + ((reg_cfg_cmd->u.dmi_info.hi_tbl_offset + + reg_cfg_cmd->u.dmi_info.len - + sizeof(uint32_t)) > cmd_len)) { + pr_err("%s:%d hi_tbl_offset %d len %d cmd %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.hi_tbl_offset, + reg_cfg_cmd->u.dmi_info.len, cmd_len); + return -EINVAL; + } + } + if ((reg_cfg_cmd->u.dmi_info.lo_tbl_offset > + (UINT_MAX - reg_cfg_cmd->u.dmi_info.len)) || + ((reg_cfg_cmd->u.dmi_info.lo_tbl_offset + + reg_cfg_cmd->u.dmi_info.len) > cmd_len)) { + pr_err("%s:%d lo_tbl_offset %d len %d cmd_len %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.lo_tbl_offset, + reg_cfg_cmd->u.dmi_info.len, cmd_len); + return -EINVAL; + } + break; + } + + default: + break; + } + + switch (reg_cfg_cmd->cmd_type) { + case VFE_WRITE: { + msm_camera_io_memcpy(vfe_dev->vfe_base + + reg_cfg_cmd->u.rw_info.reg_offset, + cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4, + reg_cfg_cmd->u.rw_info.len); + break; + } + case VFE_WRITE_MB: { + msm_camera_io_memcpy_mb(vfe_dev->vfe_base + + reg_cfg_cmd->u.rw_info.reg_offset, + cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4, + reg_cfg_cmd->u.rw_info.len); + break; + } + case VFE_CFG_MASK: { + uint32_t temp; + + if ((UINT_MAX - sizeof(temp) < + reg_cfg_cmd->u.mask_info.reg_offset) || + (resource_size(vfe_dev->vfe_mem) < + reg_cfg_cmd->u.mask_info.reg_offset + + sizeof(temp)) || + (reg_cfg_cmd->u.mask_info.reg_offset & 0x3)) { + pr_err("%s: VFE_CFG_MASK: Invalid length\n", __func__); + return -EINVAL; + } + temp = msm_camera_io_r(vfe_dev->vfe_base + + reg_cfg_cmd->u.mask_info.reg_offset); + + temp &= ~reg_cfg_cmd->u.mask_info.mask; + temp |= reg_cfg_cmd->u.mask_info.val; + msm_camera_io_w(temp, vfe_dev->vfe_base + + reg_cfg_cmd->u.mask_info.reg_offset); + break; + } + case VFE_WRITE_DMI_16BIT: + case VFE_WRITE_DMI_32BIT: + case VFE_WRITE_DMI_64BIT: { + int i; + uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL; + uint32_t hi_val, lo_val, lo_val1; + + if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) { + hi_tbl_ptr = cfg_data + + reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4; + } + lo_tbl_ptr = cfg_data + + reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4; + if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) + reg_cfg_cmd->u.dmi_info.len = + reg_cfg_cmd->u.dmi_info.len / 2; + for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) { + lo_val = *lo_tbl_ptr++; + if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_16BIT) { + lo_val1 = lo_val & 0x0000FFFF; + lo_val = (lo_val & 0xFFFF0000)>>16; + msm_camera_io_w(lo_val1, vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset + 0x4); + } else if (reg_cfg_cmd->cmd_type == + VFE_WRITE_DMI_64BIT) { + lo_tbl_ptr++; + hi_val = *hi_tbl_ptr; + hi_tbl_ptr = hi_tbl_ptr + 2; + msm_camera_io_w(hi_val, vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset); + } + msm_camera_io_w(lo_val, vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset + 0x4); + } + break; + } + case VFE_READ_DMI_16BIT: + case VFE_READ_DMI_32BIT: + case VFE_READ_DMI_64BIT: { + int i; + uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL; + uint32_t hi_val, lo_val, lo_val1; + + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { + hi_tbl_ptr = cfg_data + + reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4; + } + + lo_tbl_ptr = cfg_data + + reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4; + + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) + reg_cfg_cmd->u.dmi_info.len = + reg_cfg_cmd->u.dmi_info.len / 2; + + for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) { + lo_val = msm_camera_io_r(vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset + 0x4); + + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_16BIT) { + lo_val1 = msm_camera_io_r(vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset + 0x4); + lo_val |= lo_val1 << 16; + } + *lo_tbl_ptr++ = lo_val; + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { + hi_val = msm_camera_io_r(vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset); + *hi_tbl_ptr = hi_val; + hi_tbl_ptr += 2; + lo_tbl_ptr++; + } + } + break; + } + case VFE_HW_UPDATE_LOCK: { + uint32_t update_id = + vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id; + if (update_id) { + ISP_DBG("%s hw_update_lock fail cur_id %u,last_id %u\n", + __func__, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id, + update_id); + return -EINVAL; + } + break; + } + case VFE_HW_UPDATE_UNLOCK: { + if (vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id + != *cfg_data) { + ISP_DBG("hw_updt over frm bound,strt_id %u end_id %d\n", + *cfg_data, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id); + } + vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id = + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; + break; + } + case VFE_READ: { + int i; + uint32_t *data_ptr = cfg_data + + reg_cfg_cmd->u.rw_info.cmd_data_offset/4; + for (i = 0; i < reg_cfg_cmd->u.rw_info.len/4; i++) { + if ((data_ptr < cfg_data) || + (UINT_MAX / sizeof(*data_ptr) < + (data_ptr - cfg_data)) || + (sizeof(*data_ptr) * (data_ptr - cfg_data) >= + cmd_len)) + return -EINVAL; + *data_ptr++ = msm_camera_io_r(vfe_dev->vfe_base + + reg_cfg_cmd->u.rw_info.reg_offset); + reg_cfg_cmd->u.rw_info.reg_offset += 4; + } + break; + } + case GET_MAX_CLK_RATE: { + int rc = 0; + unsigned long rate; + + if (cmd_len != sizeof(__u32)) { + pr_err("%s:%d failed: invalid cmd len %u exp %zu\n", + __func__, __LINE__, cmd_len, + sizeof(__u32)); + return -EINVAL; + } + rc = msm_isp_get_max_clk_rate(vfe_dev, &rate); + if (rc < 0) { + pr_err("%s:%d failed: rc %d\n", __func__, __LINE__, rc); + return -EINVAL; + } + + *(__u32 *)cfg_data = (__u32)rate; + + break; + } + case GET_ISP_ID: { + uint32_t *isp_id = NULL; + + if (cmd_len < sizeof(uint32_t)) { + pr_err("%s:%d failed: invalid cmd len %u exp %zu\n", + __func__, __LINE__, cmd_len, + sizeof(uint32_t)); + return -EINVAL; + } + + isp_id = (uint32_t *)cfg_data; + *isp_id = vfe_dev->pdev->id; + break; + } + case SET_WM_UB_SIZE: + break; + case SET_UB_POLICY: { + + if (cmd_len < sizeof(vfe_dev->vfe_ub_policy)) { + pr_err("%s:%d failed: invalid cmd len %u exp %zu\n", + __func__, __LINE__, cmd_len, + sizeof(vfe_dev->vfe_ub_policy)); + return -EINVAL; + } + vfe_dev->vfe_ub_policy = *cfg_data; + break; + } + default: + break; + } + return 0; +} + +int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0, i; + struct msm_vfe_cfg_cmd2 *proc_cmd = arg; + struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd; + uint32_t *cfg_data = NULL; + + if (!proc_cmd->num_cfg) { + pr_err("%s: Passed num_cfg as 0\n", __func__); + return -EINVAL; + } + + reg_cfg_cmd = kzalloc(sizeof(struct msm_vfe_reg_cfg_cmd)* + proc_cmd->num_cfg, GFP_KERNEL); + if (!reg_cfg_cmd) { + rc = -ENOMEM; + goto reg_cfg_failed; + } + + if (copy_from_user(reg_cfg_cmd, + (void __user *)(proc_cmd->cfg_cmd), + sizeof(struct msm_vfe_reg_cfg_cmd) * proc_cmd->num_cfg)) { + rc = -EFAULT; + goto copy_cmd_failed; + } + + if (proc_cmd->cmd_len > 0 && + proc_cmd->cmd_len < UINT16_MAX) { + cfg_data = kzalloc(proc_cmd->cmd_len, GFP_KERNEL); + if (!cfg_data) { + pr_err("%s: cfg_data alloc failed\n", __func__); + rc = -ENOMEM; + goto cfg_data_failed; + } + + if (copy_from_user(cfg_data, + (void __user *)(proc_cmd->cfg_data), + proc_cmd->cmd_len)) { + rc = -EFAULT; + goto copy_cmd_failed; + } + } + + for (i = 0; i < proc_cmd->num_cfg; i++) + rc = msm_isp_send_hw_cmd(vfe_dev, ®_cfg_cmd[i], + cfg_data, proc_cmd->cmd_len); + + if (copy_to_user(proc_cmd->cfg_data, + cfg_data, proc_cmd->cmd_len)) { + rc = -EFAULT; + goto copy_cmd_failed; + } + +copy_cmd_failed: + kfree(cfg_data); +cfg_data_failed: + kfree(reg_cfg_cmd); +reg_cfg_failed: + return rc; +} + +int msm_isp_send_event(struct vfe_device *vfe_dev, + uint32_t event_type, + struct msm_isp32_event_data *event_data) +{ + struct v4l2_event isp_event; + + memset(&isp_event, 0, sizeof(struct v4l2_event)); + isp_event.id = 0; + isp_event.type = event_type; + + memcpy(&isp_event.u.data[0], event_data, + sizeof(struct msm_isp32_event_data)); + v4l2_event_queue(vfe_dev->subdev.sd.devnode, &isp_event); + return 0; +} + +#define CAL_WORD(width, M, N) ((width * M + N - 1) / N) + +int msm_isp_cal_word_per_line(uint32_t output_format, + uint32_t pixel_per_line) +{ + int val = -1; + + switch (output_format) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_META: + val = CAL_WORD(pixel_per_line, 1, 8); + break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + val = CAL_WORD(pixel_per_line, 5, 32); + break; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + val = CAL_WORD(pixel_per_line, 3, 16); + break; + case V4L2_PIX_FMT_SBGGR14: + case V4L2_PIX_FMT_SGBRG14: + case V4L2_PIX_FMT_SGRBG14: + case V4L2_PIX_FMT_SRGGB14: + val = CAL_WORD(pixel_per_line, 7, 32); + break; + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + val = CAL_WORD(pixel_per_line, 1, 6); + break; + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + val = CAL_WORD(pixel_per_line, 1, 5); + break; + case V4L2_PIX_FMT_QBGGR14: + case V4L2_PIX_FMT_QGBRG14: + case V4L2_PIX_FMT_QGRBG14: + case V4L2_PIX_FMT_QRGGB14: + val = CAL_WORD(pixel_per_line, 1, 4); + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV41: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + val = CAL_WORD(pixel_per_line, 1, 8); + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + val = CAL_WORD(pixel_per_line, 2, 8); + break; + case V4L2_PIX_FMT_P16BGGR10: + case V4L2_PIX_FMT_P16GBRG10: + case V4L2_PIX_FMT_P16GRBG10: + case V4L2_PIX_FMT_P16RGGB10: + val = CAL_WORD(pixel_per_line, 1, 4); + break; + /*TD: Add more image format*/ + default: + msm_isp_print_fourcc_error(__func__, output_format); + break; + } + return val; +} + +enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format) +{ + switch (output_format) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_SBGGR14: + case V4L2_PIX_FMT_SGBRG14: + case V4L2_PIX_FMT_SGRBG14: + case V4L2_PIX_FMT_SRGGB14: + return MIPI; + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + case V4L2_PIX_FMT_QBGGR14: + case V4L2_PIX_FMT_QGBRG14: + case V4L2_PIX_FMT_QGRBG14: + case V4L2_PIX_FMT_QRGGB14: + return QCOM; + case V4L2_PIX_FMT_P16BGGR10: + case V4L2_PIX_FMT_P16GBRG10: + case V4L2_PIX_FMT_P16GRBG10: + case V4L2_PIX_FMT_P16RGGB10: + return PLAIN16; + default: + msm_isp_print_fourcc_error(__func__, output_format); + break; + } + return -EINVAL; +} + +int msm_isp_get_bit_per_pixel(uint32_t output_format) +{ + switch (output_format) { + case V4L2_PIX_FMT_Y4: + return 4; + case V4L2_PIX_FMT_Y6: + return 6; + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_META: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV41: + case V4L2_PIX_FMT_YVU410: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YYUV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUV411P: + case V4L2_PIX_FMT_Y41P: + case V4L2_PIX_FMT_YUV444: + case V4L2_PIX_FMT_YUV555: + case V4L2_PIX_FMT_YUV565: + case V4L2_PIX_FMT_YUV32: + case V4L2_PIX_FMT_YUV410: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_GREY: + case V4L2_PIX_FMT_PAL8: + case V4L2_PIX_FMT_UV8: + case MSM_V4L2_PIX_FMT_META: + return 8; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + case V4L2_PIX_FMT_Y10: + case V4L2_PIX_FMT_Y10BPACK: + case V4L2_PIX_FMT_P16BGGR10: + case V4L2_PIX_FMT_P16GBRG10: + case V4L2_PIX_FMT_P16GRBG10: + case V4L2_PIX_FMT_P16RGGB10: + return 10; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + case V4L2_PIX_FMT_Y12: + return 12; + case V4L2_PIX_FMT_SBGGR14: + case V4L2_PIX_FMT_SGBRG14: + case V4L2_PIX_FMT_SGRBG14: + case V4L2_PIX_FMT_SRGGB14: + case V4L2_PIX_FMT_QBGGR14: + case V4L2_PIX_FMT_QGBRG14: + case V4L2_PIX_FMT_QGRBG14: + case V4L2_PIX_FMT_QRGGB14: + return 14; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_Y16: + return 16; + /*TD: Add more image format*/ + default: + msm_isp_print_fourcc_error(__func__, output_format); + pr_err("%s: Invalid output format %x\n", + __func__, output_format); + return -EINVAL; + } +} + +void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev) +{ + struct msm_vfe_error_info *error_info = &vfe_dev->error_info; + + error_info->info_dump_frame_count++; +} + +void msm_isp_process_error_info(struct vfe_device *vfe_dev) +{ + int i; + uint8_t num_stats_type = + vfe_dev->hw_info->stats_hw_info->num_stats_type; + struct msm_vfe_error_info *error_info = &vfe_dev->error_info; + static DEFINE_RATELIMIT_STATE(rs, + DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); + static DEFINE_RATELIMIT_STATE(rs_stats, + DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); + + if (error_info->error_count == 1 || + !(error_info->info_dump_frame_count % 100)) { + vfe_dev->hw_info->vfe_ops.core_ops. + process_error_status(vfe_dev); + error_info->error_mask0 = 0; + error_info->error_mask1 = 0; + error_info->camif_status = 0; + error_info->violation_status = 0; + for (i = 0; i < MAX_NUM_STREAM; i++) { + if (error_info->stream_framedrop_count[i] != 0 && + __ratelimit(&rs)) { + pr_err("%s: Stream[%d]: dropped %d frames\n", + __func__, i, + error_info->stream_framedrop_count[i]); + error_info->stream_framedrop_count[i] = 0; + } + } + for (i = 0; i < num_stats_type; i++) { + if (error_info->stats_framedrop_count[i] != 0 && + __ratelimit(&rs_stats)) { + pr_err("%s: Stats stream[%d]: dropped %d frames\n", + __func__, i, + error_info->stats_framedrop_count[i]); + error_info->stats_framedrop_count[i] = 0; + } + } + } +} + +static inline void msm_isp_update_error_info(struct vfe_device *vfe_dev, + uint32_t error_mask0, uint32_t error_mask1) +{ + vfe_dev->error_info.error_mask0 |= error_mask0; + vfe_dev->error_info.error_mask1 |= error_mask1; + vfe_dev->error_info.error_count++; +} + +static void msm_isp_process_overflow_irq( + struct vfe_device *vfe_dev, + uint32_t *irq_status0, uint32_t *irq_status1) +{ + uint32_t overflow_mask; + + /* if there are no active streams - do not start recovery */ + if (!vfe_dev->axi_data.num_active_stream) + return; + + /*Mask out all other irqs if recovery is started*/ + if (atomic_read(&vfe_dev->error_info.overflow_state) != NO_OVERFLOW) { + uint32_t halt_restart_mask0, halt_restart_mask1; + + vfe_dev->hw_info->vfe_ops.core_ops. + get_halt_restart_mask(&halt_restart_mask0, + &halt_restart_mask1); + *irq_status0 &= halt_restart_mask0; + *irq_status1 &= halt_restart_mask1; + + return; + } + + /*Check if any overflow bit is set*/ + vfe_dev->hw_info->vfe_ops.core_ops. + get_overflow_mask(&overflow_mask); + overflow_mask &= *irq_status1; + + if (overflow_mask) { + struct msm_isp32_event_data error_event; + + if (vfe_dev->reset_pending == 1) { + pr_err("%s:%d failed: overflow %x during reset\n", + __func__, __LINE__, overflow_mask); + /* Clear overflow bits since reset is pending */ + *irq_status1 &= ~overflow_mask; + return; + } + + ISP_DBG("%s: Bus overflow detected: 0x%x, start recovery!\n", + __func__, overflow_mask); + atomic_set(&vfe_dev->error_info.overflow_state, + OVERFLOW_DETECTED); + /*Store current IRQ mask*/ + vfe_dev->hw_info->vfe_ops.core_ops.get_irq_mask(vfe_dev, + &vfe_dev->error_info.overflow_recover_irq_mask0, + &vfe_dev->error_info.overflow_recover_irq_mask1); + + /*Halt the hardware & Clear all other IRQ mask*/ + vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 0); + + /*Stop CAMIF Immediately*/ + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY); + + /*Update overflow state*/ + *irq_status0 = 0; + *irq_status1 = 0; + + memset(&error_event, 0, sizeof(error_event)); + error_event.frame_id = + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; + error_event.u.error_info.error_mask = 1 << ISP_WM_BUS_OVERFLOW; + msm_isp_send_event(vfe_dev, + ISP_EVENT_WM_BUS_OVERFLOW, &error_event); + } +} + +void msm_isp_reset_burst_count_and_frame_drop( + struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) +{ + uint32_t framedrop_period = 0; + + if (stream_info->state != ACTIVE || + stream_info->stream_type != BURST_STREAM) { + return; + } + if (stream_info->num_burst_capture != 0) { + framedrop_period = msm_isp_get_framedrop_period( + stream_info->frame_skip_pattern); + stream_info->burst_frame_count = + stream_info->init_frame_drop + + (stream_info->num_burst_capture - 1) * + framedrop_period + 1; + msm_isp_reset_framedrop(vfe_dev, stream_info); + } +} + +irqreturn_t msm_isp_process_irq(int irq_num, void *data) +{ + unsigned long flags; + struct msm_vfe_tasklet_queue_cmd *queue_cmd; + struct vfe_device *vfe_dev = (struct vfe_device *) data; + uint32_t irq_status0, irq_status1; + uint32_t error_mask0, error_mask1; + + vfe_dev->hw_info->vfe_ops.irq_ops. + read_irq_status(vfe_dev, &irq_status0, &irq_status1); + + if ((irq_status0 == 0) && (irq_status1 == 0)) { + pr_err_ratelimited("%s:VFE%d irq_status0 & 1 are both 0\n", + __func__, vfe_dev->pdev->id); + return IRQ_HANDLED; + } + + msm_isp_process_overflow_irq(vfe_dev, + &irq_status0, &irq_status1); + + vfe_dev->hw_info->vfe_ops.core_ops. + get_error_mask(&error_mask0, &error_mask1); + error_mask0 &= irq_status0; + error_mask1 &= irq_status1; + irq_status0 &= ~error_mask0; + irq_status1 &= ~error_mask1; + if (!vfe_dev->ignore_error && + ((error_mask0 != 0) || (error_mask1 != 0))) + msm_isp_update_error_info(vfe_dev, error_mask0, error_mask1); + + if ((irq_status0 == 0) && (irq_status1 == 0) && + (!(((error_mask0 != 0) || (error_mask1 != 0)) && + vfe_dev->error_info.error_count == 1))) { + ISP_DBG("%s: error_mask0/1 & error_count are set!\n", __func__); + return IRQ_HANDLED; + } + + spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); + queue_cmd = &vfe_dev->tasklet_queue_cmd[vfe_dev->taskletq_idx]; + if (queue_cmd->cmd_used) { + pr_err_ratelimited("%s: Tasklet queue overflow: %d\n", + __func__, vfe_dev->pdev->id); + list_del(&queue_cmd->list); + } else { + atomic_add(1, &vfe_dev->irq_cnt); + } + queue_cmd->vfeInterruptStatus0 = irq_status0; + queue_cmd->vfeInterruptStatus1 = irq_status1; + msm_isp_get_timestamp(&queue_cmd->ts, vfe_dev); + queue_cmd->cmd_used = 1; + vfe_dev->taskletq_idx = + (vfe_dev->taskletq_idx + 1) % MSM_VFE_TASKLETQ_SIZE; + list_add_tail(&queue_cmd->list, &vfe_dev->tasklet_q); + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + tasklet_schedule(&vfe_dev->vfe_tasklet); + return IRQ_HANDLED; +} + +void msm_isp_do_tasklet(unsigned long data) +{ + unsigned long flags; + struct vfe_device *vfe_dev = (struct vfe_device *) data; + struct msm_vfe_irq_ops *irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops; + struct msm_vfe_tasklet_queue_cmd *queue_cmd; + struct msm_isp_timestamp ts; + uint32_t irq_status0, irq_status1; + + while (atomic_read(&vfe_dev->irq_cnt)) { + spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); + queue_cmd = list_first_entry(&vfe_dev->tasklet_q, + struct msm_vfe_tasklet_queue_cmd, list); + + if (!queue_cmd) { + atomic_set(&vfe_dev->irq_cnt, 0); + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + return; + } + atomic_sub(1, &vfe_dev->irq_cnt); + list_del(&queue_cmd->list); + queue_cmd->cmd_used = 0; + irq_status0 = queue_cmd->vfeInterruptStatus0; + irq_status1 = queue_cmd->vfeInterruptStatus1; + ts = queue_cmd->ts; + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + ISP_DBG("%s: status0: 0x%x status1: 0x%x\n", + __func__, irq_status0, irq_status1); + irq_ops->process_reset_irq(vfe_dev, + irq_status0, irq_status1); + irq_ops->process_halt_irq(vfe_dev, + irq_status0, irq_status1); + if (atomic_read(&vfe_dev->error_info.overflow_state) + != NO_OVERFLOW) { + pr_err("%s: Recovery in processing, Ignore IRQs!!!\n", + __func__); + continue; + } + msm_isp_process_error_info(vfe_dev); + irq_ops->process_camif_irq(vfe_dev, + irq_status0, irq_status1, &ts); + irq_ops->process_axi_irq(vfe_dev, + irq_status0, irq_status1, &ts); + irq_ops->process_stats_irq(vfe_dev, + irq_status0, irq_status1, &ts); + irq_ops->process_reg_update(vfe_dev, + irq_status0, irq_status1, &ts); + irq_ops->process_epoch_irq(vfe_dev, + irq_status0, irq_status1, &ts); + } +} + +int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg) +{ + struct msm_vfe_axi_src_state *src_state = arg; + + if (src_state->input_src >= VFE_SRC_MAX) + return -EINVAL; + vfe_dev->axi_data.src_info[src_state->input_src].active = + src_state->src_active; + vfe_dev->axi_data.src_info[src_state->input_src].frame_id = + src_state->src_frame_id; + return 0; +} + +static void msm_vfe_iommu_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long iova, int flags, void *token) +{ + struct vfe_device *vfe_dev = NULL; + + if (token) { + vfe_dev = (struct vfe_device *)token; + if (!vfe_dev->buf_mgr || !vfe_dev->buf_mgr->ops) { + pr_err("%s:%d] buf_mgr %pK\n", __func__, + __LINE__, vfe_dev->buf_mgr); + goto end; + } + if (!vfe_dev->buf_mgr->pagefault_debug_disable) { + pr_err("%s:%d] vfe_dev %pK id %d\n", __func__, + __LINE__, vfe_dev, vfe_dev->pdev->id); + vfe_dev->buf_mgr->ops->buf_mgr_debug(vfe_dev->buf_mgr, + iova); + } + } else { + ISP_DBG("%s:%d] no token received: %pK\n", + __func__, __LINE__, token); + goto end; + } +end: + return; +} + +int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + long rc = 0; + + ISP_DBG("%s\n", __func__); + + mutex_lock(&vfe_dev->realtime_mutex); + mutex_lock(&vfe_dev->core_mutex); + + if (vfe_dev->vfe_open_cnt++ && vfe_dev->vfe_base) { + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return 0; + } + + if (vfe_dev->vfe_base) { + pr_err("%s:%d invalid params cnt %d base %pK\n", __func__, + __LINE__, vfe_dev->vfe_open_cnt, vfe_dev->vfe_base); + vfe_dev->vfe_base = NULL; + } + + vfe_dev->reset_pending = 0; + vfe_dev->isp_sof_debug = 0; + + if (vfe_dev->hw_info->vfe_ops.core_ops.init_hw(vfe_dev) < 0) { + pr_err("%s: init hardware failed\n", __func__); + vfe_dev->vfe_open_cnt--; + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return -EBUSY; + } + + memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); + atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW); + + vfe_dev->hw_info->vfe_ops.core_ops.clear_status_reg(vfe_dev); + + rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 1, 1); + if (rc <= 0) { + pr_err("%s: reset timeout\n", __func__); + vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev); + vfe_dev->vfe_open_cnt--; + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return -EINVAL; + } + vfe_dev->vfe_hw_version = msm_camera_io_r(vfe_dev->vfe_base); + ISP_DBG("%s: HW Version: 0x%x\n", __func__, vfe_dev->vfe_hw_version); + + vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); + + vfe_dev->buf_mgr->ops->buf_mgr_init(vfe_dev->buf_mgr, "msm_isp"); + + memset(&vfe_dev->axi_data, 0, sizeof(struct msm_vfe_axi_shared_data)); + memset(&vfe_dev->stats_data, 0, + sizeof(struct msm_vfe_stats_shared_data)); + memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); + memset(&vfe_dev->fetch_engine_info, 0, + sizeof(vfe_dev->fetch_engine_info)); + vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info; + vfe_dev->taskletq_idx = 0; + vfe_dev->vt_enable = 0; + vfe_dev->bus_util_factor = 0; + rc = of_property_read_u32(vfe_dev->pdev->dev.of_node, + "bus-util-factor", &vfe_dev->bus_util_factor); + if (rc < 0) + ISP_DBG("%s: Use default bus utilization factor\n", __func__); + + cam_smmu_reg_client_page_fault_handler( + vfe_dev->buf_mgr->iommu_hdl, + msm_vfe_iommu_fault_handler, + NULL, + vfe_dev); + + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return 0; +} + +#ifdef CONFIG_MSM_AVTIMER +static void msm_isp_end_avtimer(void) +{ + avcs_core_disable_power_collapse(0); +} +#else +static void msm_isp_end_avtimer(void) +{ + pr_err("AV Timer is not supported\n"); +} +#endif + +int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + long rc = 0; + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + + ISP_DBG("%s E\n", __func__); + mutex_lock(&vfe_dev->realtime_mutex); + mutex_lock(&vfe_dev->core_mutex); + + if (!vfe_dev->vfe_open_cnt) { + pr_err("%s invalid state open cnt %d\n", __func__, + vfe_dev->vfe_open_cnt); + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return -EINVAL; + } + + if (--vfe_dev->vfe_open_cnt) { + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return 0; + } + + /* Unregister page fault handler */ + cam_smmu_reg_client_page_fault_handler( + vfe_dev->buf_mgr->iommu_hdl, + NULL, NULL, vfe_dev); + + rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); + if (rc < 0) + pr_err("%s: halt timeout rc=%ld\n", __func__, rc); + + vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr); + vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev); + if (vfe_dev->vt_enable) { + msm_isp_end_avtimer(); + vfe_dev->vt_enable = 0; + } + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return 0; +} diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util_32.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util_32.h new file mode 100644 index 000000000000..f2268c3b46a1 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util_32.h @@ -0,0 +1,84 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __MSM_ISP_UTIL_H__ +#define __MSM_ISP_UTIL_H__ + +#include "msm_isp_32.h" +#include + +/* #define CONFIG_MSM_ISP_DBG 1 */ + +#ifdef CONFIG_MSM_ISP_DBG +#define ISP_DBG(fmt, args...) printk(fmt, ##args) +#else +#define ISP_DBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +#define ALT_VECTOR_IDX(x) {x = 3 - x; } + +struct msm_isp_bandwidth_mgr { + uint32_t bus_client; + uint32_t bus_vector_active_idx; + uint32_t use_count; + struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT]; +}; + +uint32_t msm_isp_get_framedrop_period( + enum msm_vfe_frame_skip_pattern frame_skip_pattern); +void msm_isp_reset_burst_count_and_frame_drop( + struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info); + +int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client); +int msm_isp_update_bandwidth(enum msm_isp_hw_client client, + uint64_t ab, uint64_t ib); +void msm_isp_util_get_bandwidth_stats(struct vfe_device *vfe_dev, + struct msm_isp_statistics *stats); +void msm_isp_util_update_last_overflow_ab_ib(struct vfe_device *vfe_dev); +void msm_isp_util_update_clk_rate(long clock_rate); +void msm_isp_update_req_history(uint32_t client, uint64_t ab, + uint64_t ib, + struct msm_isp_bandwidth_info *client_info, + unsigned long long ts); +void msm_isp_deinit_bandwidth_mgr(enum msm_isp_hw_client client); + +int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub); + +int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub); + +int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg); +int msm_isp_send_event(struct vfe_device *vfe_dev, + uint32_t type, struct msm_isp32_event_data *event_data); +int msm_isp_cal_word_per_line(uint32_t output_format, + uint32_t pixel_per_line); +int msm_isp_get_bit_per_pixel(uint32_t output_format); +enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format); +irqreturn_t msm_isp_process_irq(int irq_num, void *data); +int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg); +void msm_isp_do_tasklet(unsigned long data); +void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev); +void msm_isp_process_error_info(struct vfe_device *vfe_dev); +int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); +int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); +long msm_isp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg); +int msm_isp_get_clk_info(struct vfe_device *vfe_dev, + struct platform_device *pdev, struct msm_cam_clk_info *vfe_clk_info); +void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev, + struct msm_vfe_fetch_engine_info *fetch_engine_info); +void msm_camera_io_dump_2(void __iomem *addr, int size); +void msm_isp_print_fourcc_error(const char *origin, uint32_t fourcc_format); +void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp, + struct vfe_device *vfe_dev); +void msm_isp_get_avtimer_ts(struct msm_isp_timestamp *time_stamp); +int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg); +#endif /* __MSM_ISP_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/ispif/Makefile b/drivers/media/platform/msm/camera_v2/ispif/Makefile index 236ec7340c56..d56332d27abb 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/Makefile +++ b/drivers/media/platform/msm/camera_v2/ispif/Makefile @@ -1,4 +1,8 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v2 ccflags-y += -Idrivers/media/platform/msm/camera_v2/common ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ifeq ($(CONFIG_MSM_ISP_V1),y) +obj-$(CONFIG_MSM_CSID) += msm_ispif_32.o +else obj-$(CONFIG_MSM_CSID) += msm_ispif.o +endif diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_32.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_32.c new file mode 100644 index 000000000000..e9b2a1d80280 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_32.c @@ -0,0 +1,1581 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_ispif_32.h" +#include "msm.h" +#include "msm_sd.h" +#include "msm_camera_io_util.h" + +#ifdef CONFIG_MSM_ISPIF_V1 +#include "msm_ispif_hwreg_v1.h" +#else +#include "msm_ispif_hwreg_v2.h" +#endif + +#define V4L2_IDENT_ISPIF 50001 +#define MSM_ISPIF_DRV_NAME "msm_ispif" + +#define ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY 0x00 +#define ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY 0x01 +#define ISPIF_INTF_CMD_DISABLE_IMMEDIATELY 0x02 + +#define ISPIF_TIMEOUT_SLEEP_US 1000 +#define ISPIF_TIMEOUT_ALL_US 1000000 + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +static void msm_ispif_io_dump_reg(struct ispif_device *ispif) +{ + if (!ispif->enb_dump_reg) + return; + + if (!ispif->base) { + pr_err("%s: null pointer for the ispif base\n", __func__); + return; + } + + msm_camera_io_dump(ispif->base, 0x250, 1); +} + + +static inline int msm_ispif_is_intf_valid(uint32_t csid_version, + uint8_t intf_type) +{ + return (((csid_version <= CSID_VERSION_V22 + && intf_type != VFE0) || + (intf_type >= VFE_MAX)) + ? false : true); +} + +static struct msm_cam_clk_info ispif_8626_reset_clk_info[] = { + {"ispif_ahb_clk", NO_SET_RATE}, + {"csi0_src_clk", NO_SET_RATE}, + {"csi0_clk", NO_SET_RATE}, + {"csi0_pix_clk", NO_SET_RATE}, + {"csi0_rdi_clk", NO_SET_RATE}, + {"csi1_src_clk", NO_SET_RATE}, + {"csi1_clk", NO_SET_RATE}, + {"csi1_pix_clk", NO_SET_RATE}, + {"csi1_rdi_clk", NO_SET_RATE}, + {"camss_vfe_vfe0_clk", NO_SET_RATE}, + {"camss_csi_vfe0_clk", NO_SET_RATE}, +}; + +static struct msm_cam_clk_info ispif_8974_ahb_clk_info[ISPIF_CLK_INFO_MAX]; + +static struct msm_cam_clk_info ispif_8974_reset_clk_info[] = { + {"csi0_src_clk", INIT_RATE}, + {"csi0_clk", NO_SET_RATE}, + {"csi0_pix_clk", NO_SET_RATE}, + {"csi0_rdi_clk", NO_SET_RATE}, + {"csi1_src_clk", INIT_RATE}, + {"csi1_clk", NO_SET_RATE}, + {"csi1_pix_clk", NO_SET_RATE}, + {"csi1_rdi_clk", NO_SET_RATE}, + {"csi2_src_clk", INIT_RATE}, + {"csi2_clk", NO_SET_RATE}, + {"csi2_pix_clk", NO_SET_RATE}, + {"csi2_rdi_clk", NO_SET_RATE}, + {"csi3_src_clk", INIT_RATE}, + {"csi3_clk", NO_SET_RATE}, + {"csi3_pix_clk", NO_SET_RATE}, + {"csi3_rdi_clk", NO_SET_RATE}, + {"vfe0_clk_src", INIT_RATE}, + {"camss_vfe_vfe0_clk", NO_SET_RATE}, + {"camss_csi_vfe0_clk", NO_SET_RATE}, + {"vfe1_clk_src", INIT_RATE}, + {"camss_vfe_vfe1_clk", NO_SET_RATE}, + {"camss_csi_vfe1_clk", NO_SET_RATE}, +}; + +static int msm_ispif_reset_hw(struct ispif_device *ispif) +{ + int rc = 0; + long timeout = 0; + struct clk *reset_clk[ARRAY_SIZE(ispif_8974_reset_clk_info)]; + struct clk *reset_clk1[ARRAY_SIZE(ispif_8626_reset_clk_info)]; + + ispif->clk_idx = 0; + + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 1); + if (rc < 0) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8626_reset_clk_info, reset_clk1, + ARRAY_SIZE(ispif_8626_reset_clk_info), 1); + if (rc < 0) { + pr_err("%s: cannot enable clock, error = %d", + __func__, rc); + } else { + /* This is set when device is 8x26 */ + ispif->clk_idx = 2; + } + } else { + /* This is set when device is 8974 */ + ispif->clk_idx = 1; + } + + init_completion(&ispif->reset_complete[VFE0]); + if (ispif->hw_num_isps > 1) + init_completion(&ispif->reset_complete[VFE1]); + + /* initiate reset of ISPIF */ + msm_camera_io_w(ISPIF_RST_CMD_MASK, + ispif->base + ISPIF_RST_CMD_ADDR); + if (ispif->hw_num_isps > 1) + msm_camera_io_w(ISPIF_RST_CMD_1_MASK, + ispif->base + ISPIF_RST_CMD_1_ADDR); + + timeout = wait_for_completion_timeout( + &ispif->reset_complete[VFE0], msecs_to_jiffies(500)); + CDBG("%s: VFE0 done\n", __func__); + + if (timeout <= 0) { + pr_err("%s: VFE0 reset wait timeout\n", __func__); + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 0); + if (rc < 0) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8626_reset_clk_info, reset_clk1, + ARRAY_SIZE(ispif_8626_reset_clk_info), 0); + if (rc < 0) + pr_err("%s: VFE0 reset wait timeout\n", + __func__); + } + return -ETIMEDOUT; + } + + if (ispif->hw_num_isps > 1) { + timeout = wait_for_completion_timeout( + &ispif->reset_complete[VFE1], + msecs_to_jiffies(500)); + CDBG("%s: VFE1 done\n", __func__); + if (timeout <= 0) { + pr_err("%s: VFE1 reset wait timeout\n", __func__); + msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 0); + return -ETIMEDOUT; + } + } + + if (ispif->clk_idx == 1) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 0); + if (rc < 0) { + pr_err("%s: cannot disable clock, error = %d", + __func__, rc); + } + } + + if (ispif->clk_idx == 2) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8626_reset_clk_info, reset_clk1, + ARRAY_SIZE(ispif_8626_reset_clk_info), 0); + if (rc < 0) { + pr_err("%s: cannot disable clock, error = %d", + __func__, rc); + } + } + + return rc; +} + +static int msm_ispif_get_ahb_clk_info(struct ispif_device *ispif_dev, + struct platform_device *pdev, + struct msm_cam_clk_info *ahb_clk_info) +{ + uint32_t num_ahb_clk = 0; + int i, count, rc; + uint32_t rates[ISPIF_CLK_INFO_MAX]; + + struct device_node *of_node; + + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + + CDBG("count = %d\n", count); + if (count <= 0) { + pr_err("no clocks found in device tree, count=%d", count); + return 0; + } + + if (count > ISPIF_CLK_INFO_MAX) { + pr_err("invalid count=%d, max is %d\n", count, + ISPIF_CLK_INFO_MAX); + return -EINVAL; + } + + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(ahb_clk_info[num_ahb_clk].clk_name)); + CDBG("clock-names[%d] = %s\n", + i, ahb_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + if (strnstr(ahb_clk_info[num_ahb_clk].clk_name, "ahb", + sizeof(ahb_clk_info[num_ahb_clk].clk_name))) { + ahb_clk_info[num_ahb_clk].clk_rate = + (rates[i] == 0) ? (long)-1 : rates[i]; + CDBG("clk_rate[%d] = %ld\n", i, + ahb_clk_info[i].clk_rate); + num_ahb_clk++; + } + } + ispif_dev->num_ahb_clk = num_ahb_clk; + return 0; +} + +static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable) +{ + int rc = 0; + + if (ispif->csid_version < CSID_VERSION_V30) { + /* Older ISPIF versiond don't need ahb clokc */ + return 0; + } + + rc = msm_ispif_get_ahb_clk_info(ispif, ispif->pdev, + ispif_8974_ahb_clk_info); + if (rc < 0) { + pr_err("%s: msm_isp_get_clk_info() failed", __func__); + return -EFAULT; + } + + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_ahb_clk_info, ispif->ahb_clk, + ispif->num_ahb_clk, enable); + if (rc < 0) { + pr_err("%s: cannot enable clock, error = %d", + __func__, rc); + } + + return rc; +} + +static int msm_ispif_reset(struct ispif_device *ispif) +{ + int rc = 0; + int i; + + if (WARN_ON(!ispif)) + return -EINVAL; + + memset(ispif->sof_count, 0, sizeof(ispif->sof_count)); + for (i = 0; i < ispif->vfe_info.num_vfe; i++) { + + msm_camera_io_w(1 << PIX0_LINE_BUF_EN_BIT, + ispif->base + ISPIF_VFE_m_CTRL_0(i)); + msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(i)); + msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(i)); + msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(i)); + msm_camera_io_w(0xFFFFFFFF, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_0(i)); + msm_camera_io_w(0xFFFFFFFF, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_1(i)); + msm_camera_io_w(0xFFFFFFFF, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_2(i)); + + msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INPUT_SEL(i)); + + msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, + ispif->base + ISPIF_VFE_m_INTF_CMD_0(i)); + msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, + ispif->base + ISPIF_VFE_m_INTF_CMD_1(i)); + pr_debug("%s: base %pK", __func__, ispif->base); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 0)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 1)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 2)); + + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_PIX_INTF_n_CROP(i, 0)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_PIX_INTF_n_CROP(i, 1)); + } + + msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + return rc; +} + +static void msm_ispif_sel_csid_core(struct ispif_device *ispif, + uint8_t intftype, uint8_t csid, uint8_t vfe_intf) +{ + uint32_t data; + + if (WARN_ON(!ispif)) + return; + + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return; + } + + data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_INPUT_SEL(vfe_intf)); + switch (intftype) { + case PIX0: + data &= ~(BIT(1) | BIT(0)); + data |= (uint32_t)csid; + break; + case RDI0: + data &= ~(BIT(5) | BIT(4)); + data |= (uint32_t)(csid << 4); + break; + case PIX1: + data &= ~(BIT(9) | BIT(8)); + data |= (uint32_t)(csid << 8); + break; + case RDI1: + data &= ~(BIT(13) | BIT(12)); + data |= (uint32_t)(csid << 12); + break; + case RDI2: + data &= ~(BIT(21) | BIT(20)); + data |= (uint32_t)(csid << 20); + break; + } + + msm_camera_io_w_mb(data, ispif->base + + ISPIF_VFE_m_INPUT_SEL(vfe_intf)); +} + +static void msm_ispif_enable_crop(struct ispif_device *ispif, + uint8_t intftype, uint8_t vfe_intf, uint16_t start_pixel, + uint16_t end_pixel) +{ + uint32_t data; + + if (WARN_ON(!ispif)) + return; + + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return; + } + + data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf)); + data |= (1 << (intftype + 7)); + if (intftype == PIX0) + data |= 1 << PIX0_LINE_BUF_EN_BIT; + msm_camera_io_w(data, + ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf)); + + if (intftype == PIX0) + msm_camera_io_w_mb(start_pixel | (end_pixel << 16), + ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 0)); + else if (intftype == PIX1) + msm_camera_io_w_mb(start_pixel | (end_pixel << 16), + ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 1)); + else { + pr_err("%s: invalid intftype=%d\n", __func__, intftype); + WARN_ON(1); + return; + } +} + +static void msm_ispif_enable_intf_cids(struct ispif_device *ispif, + uint8_t intftype, uint16_t cid_mask, uint8_t vfe_intf, uint8_t enable) +{ + uint32_t intf_addr, data; + + if (WARN_ON((!ispif))) + return; + + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return; + } + + switch (intftype) { + case PIX0: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 0); + break; + case RDI0: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 0); + break; + case PIX1: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 1); + break; + case RDI1: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 1); + break; + case RDI2: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 2); + break; + default: + pr_err("%s: invalid intftype=%d\n", __func__, intftype); + WARN_ON(1); + return; + } + + data = msm_camera_io_r(ispif->base + intf_addr); + if (enable) + data |= (uint32_t)cid_mask; + else + data &= ~((uint32_t)cid_mask); + msm_camera_io_w_mb(data, ispif->base + intf_addr); +} + +static int msm_ispif_validate_intf_status(struct ispif_device *ispif, + uint8_t intftype, uint8_t vfe_intf) +{ + int rc = 0; + uint32_t data = 0; + + if (WARN_ON((!ispif))) + return -ENODEV; + + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return -EINVAL; + } + + switch (intftype) { + case PIX0: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0)); + break; + case RDI0: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0)); + break; + case PIX1: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1)); + break; + case RDI1: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1)); + break; + case RDI2: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2)); + break; + } + if ((data & 0xf) != 0xf) + rc = -EBUSY; + return rc; +} + +static void msm_ispif_select_clk_mux(struct ispif_device *ispif, + uint8_t intftype, uint8_t csid, uint8_t vfe_intf) +{ + uint32_t data = 0; + + switch (intftype) { + case PIX0: + data = msm_camera_io_r(ispif->clk_mux_base); + data &= ~(0xf << (vfe_intf * 8)); + data |= (csid << (vfe_intf * 8)); + msm_camera_io_w(data, ispif->clk_mux_base); + break; + + case RDI0: + data = msm_camera_io_r(ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + data &= ~(0xf << (vfe_intf * 12)); + data |= (csid << (vfe_intf * 12)); + msm_camera_io_w(data, ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + break; + + case PIX1: + data = msm_camera_io_r(ispif->clk_mux_base); + data &= ~(0xf0 << (vfe_intf * 8)); + data |= (csid << (4 + (vfe_intf * 8))); + msm_camera_io_w(data, ispif->clk_mux_base); + break; + + case RDI1: + data = msm_camera_io_r(ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + data &= ~(0xf << (4 + (vfe_intf * 12))); + data |= (csid << (4 + (vfe_intf * 12))); + msm_camera_io_w(data, ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + break; + + case RDI2: + data = msm_camera_io_r(ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + data &= ~(0xf << (8 + (vfe_intf * 12))); + data |= (csid << (8 + (vfe_intf * 12))); + msm_camera_io_w(data, ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + break; + } + CDBG("%s intftype %d data %x\n", __func__, intftype, data); + /* ensure clk mux is enabled */ + mb(); +} + +static uint16_t msm_ispif_get_cids_mask_from_cfg( + struct msm_ispif_params_entry *entry) +{ + int i; + uint16_t cids_mask = 0; + + if (WARN_ON(!entry)) { + pr_err("%s: invalid entry", __func__); + return cids_mask; + } + + for (i = 0; i < entry->num_cids && i < MAX_CID_CH_PARAM_ENTRY; i++) + cids_mask |= (1 << entry->cids[i]); + + return cids_mask; +} + +static int msm_ispif_config(struct ispif_device *ispif, + struct msm_ispif_param_data *params) +{ + int rc = 0, i = 0; + uint16_t cid_mask; + enum msm_ispif_intftype intftype; + enum msm_ispif_vfe_intf vfe_intf; + + if (WARN_ON(!ispif) || WARN_ON(!params)) + return -EINVAL; + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + + for (i = 0; i < params->num; i++) { + vfe_intf = params->entries[i].vfe_intf; + if (vfe_intf >= VFE_MAX) { + pr_err("%s: %d invalid i %d vfe_intf %d\n", __func__, + __LINE__, i, vfe_intf); + return -EINVAL; + } + if (!msm_ispif_is_intf_valid(ispif->csid_version, + vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return -EINVAL; + } + msm_camera_io_w(0x0, ispif->base + + ISPIF_VFE_m_IRQ_MASK_0(vfe_intf)); + msm_camera_io_w(0x0, ispif->base + + ISPIF_VFE_m_IRQ_MASK_1(vfe_intf)); + msm_camera_io_w_mb(0x0, ispif->base + + ISPIF_VFE_m_IRQ_MASK_2(vfe_intf)); + } + + for (i = 0; i < params->num; i++) { + intftype = params->entries[i].intftype; + + vfe_intf = params->entries[i].vfe_intf; + + CDBG("%s intftype %x, vfe_intf %d, csid %d\n", __func__, + intftype, vfe_intf, params->entries[i].csid); + + if ((intftype >= INTF_MAX) || + (vfe_intf >= ispif->vfe_info.num_vfe) || + (ispif->csid_version <= CSID_VERSION_V22 && + (vfe_intf > VFE0))) { + pr_err("%s: VFEID %d and CSID version %d mismatch\n", + __func__, vfe_intf, ispif->csid_version); + return -EINVAL; + } + + if (ispif->csid_version >= CSID_VERSION_V30) + msm_ispif_select_clk_mux(ispif, intftype, + params->entries[i].csid, vfe_intf); + + rc = msm_ispif_validate_intf_status(ispif, intftype, vfe_intf); + if (rc) { + pr_err("%s:validate_intf_status failed, rc = %d\n", + __func__, rc); + return rc; + } + + msm_ispif_sel_csid_core(ispif, intftype, + params->entries[i].csid, vfe_intf); + cid_mask = msm_ispif_get_cids_mask_from_cfg( + ¶ms->entries[i]); + msm_ispif_enable_intf_cids(ispif, intftype, + cid_mask, vfe_intf, 1); + if (params->entries[i].crop_enable) + msm_ispif_enable_crop(ispif, intftype, vfe_intf, + params->entries[i].crop_start_pixel, + params->entries[i].crop_end_pixel); + } + + for (vfe_intf = 0; vfe_intf < 2; vfe_intf++) { + msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + + ISPIF_VFE_m_IRQ_MASK_0(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_0(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base + + ISPIF_VFE_m_IRQ_MASK_1(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_1(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base + + ISPIF_VFE_m_IRQ_MASK_2(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_2(vfe_intf)); + } + + msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + return rc; +} + +static int msm_ispif_intf_cmd(struct ispif_device *ispif, uint32_t cmd_bits, + struct msm_ispif_param_data *params) +{ + uint8_t vc; + int i, k; + enum msm_ispif_intftype intf_type; + enum msm_ispif_cid cid; + enum msm_ispif_vfe_intf vfe_intf; + + if (WARN_ON(!ispif) || WARN_ON(!params)) + return -EINVAL; + + for (i = 0; i < params->num; i++) { + vfe_intf = params->entries[i].vfe_intf; + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return -EINVAL; + } + if (params->entries[i].num_cids > MAX_CID_CH_PARAM_ENTRY) { + pr_err("%s: out of range of cid_num %d\n", + __func__, params->entries[i].num_cids); + return -EINVAL; + } + } + + for (i = 0; i < params->num; i++) { + intf_type = params->entries[i].intftype; + vfe_intf = params->entries[i].vfe_intf; + for (k = 0; k < params->entries[i].num_cids; k++) { + cid = params->entries[i].cids[k]; + vc = cid / 4; + if (intf_type == RDI2) { + /* zero out two bits */ + ispif->applied_intf_cmd[vfe_intf].intf_cmd1 &= + ~(0x3 << (vc * 2 + 8)); + /* set cmd bits */ + ispif->applied_intf_cmd[vfe_intf].intf_cmd1 |= + (cmd_bits << (vc * 2 + 8)); + } else { + /* zero 2 bits */ + ispif->applied_intf_cmd[vfe_intf].intf_cmd &= + ~(0x3 << (vc * 2 + intf_type * 8)); + /* set cmd bits */ + ispif->applied_intf_cmd[vfe_intf].intf_cmd |= + (cmd_bits << (vc * 2 + intf_type * 8)); + } + } + /* cmd for PIX0, PIX1, RDI0, RDI1 */ + if (ispif->applied_intf_cmd[vfe_intf].intf_cmd != 0xFFFFFFFF) + msm_camera_io_w_mb( + ispif->applied_intf_cmd[vfe_intf].intf_cmd, + ispif->base + ISPIF_VFE_m_INTF_CMD_0(vfe_intf)); + + /* cmd for RDI2 */ + if (ispif->applied_intf_cmd[vfe_intf].intf_cmd1 != 0xFFFFFFFF) + msm_camera_io_w_mb( + ispif->applied_intf_cmd[vfe_intf].intf_cmd1, + ispif->base + ISPIF_VFE_m_INTF_CMD_1(vfe_intf)); + } + return 0; +} + +static int msm_ispif_stop_immediately(struct ispif_device *ispif, + struct msm_ispif_param_data *params) +{ + int i, rc = 0; + uint16_t cid_mask = 0; + + if (WARN_ON(!ispif) || WARN_ON(!params)) + return -EINVAL; + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_DISABLE_IMMEDIATELY, params); + + /* after stop the interface we need to unmask the CID enable bits */ + for (i = 0; i < params->num; i++) { + cid_mask = msm_ispif_get_cids_mask_from_cfg( + ¶ms->entries[i]); + msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype, + cid_mask, params->entries[i].vfe_intf, 0); + } + + return rc; +} + +static int msm_ispif_start_frame_boundary(struct ispif_device *ispif, + struct msm_ispif_param_data *params) +{ + int rc = 0; + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + + msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params); + + return rc; +} + +static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif, + struct msm_ispif_param_data *params) +{ + int rc = 0, i; + long timeout = 0; + uint16_t cid_mask; + enum msm_ispif_intftype intftype; + enum msm_ispif_vfe_intf vfe_intf; + uint32_t vfe_mask = 0; + uint32_t intf_addr; + struct clk *reset_clk[ARRAY_SIZE(ispif_8974_reset_clk_info)]; + struct clk *reset_clk1[ARRAY_SIZE(ispif_8626_reset_clk_info)]; + + ispif->clk_idx = 0; + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + + for (i = 0; i < params->num; i++) { + vfe_intf = params->entries[i].vfe_intf; + if (vfe_intf >= VFE_MAX) { + pr_err("%s: %d invalid i %d vfe_intf %d\n", __func__, + __LINE__, i, vfe_intf); + return -EINVAL; + } + vfe_mask |= (1 << vfe_intf); + } + + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 1); + if (rc < 0) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8626_reset_clk_info, reset_clk1, + ARRAY_SIZE(ispif_8626_reset_clk_info), 1); + if (rc < 0) { + pr_err("%s: cannot enable clock, error = %d", + __func__, rc); + } else { + /* This is set when device is 8x26 */ + ispif->clk_idx = 2; + } + } else { + /* This is set when device is 8974 */ + ispif->clk_idx = 1; + } + + if (vfe_mask & (1 << VFE0)) { + init_completion(&ispif->reset_complete[VFE0]); + pr_err("%s Init completion VFE0\n", __func__); + /* initiate reset of ISPIF */ + msm_camera_io_w(0x00001FF9, + ispif->base + ISPIF_RST_CMD_ADDR); + } + if (ispif->hw_num_isps > 1 && (vfe_mask & (1 << VFE1))) { + init_completion(&ispif->reset_complete[VFE1]); + pr_err("%s Init completion VFE1\n", __func__); + msm_camera_io_w(0x00001FF9, + ispif->base + ISPIF_RST_CMD_1_ADDR); + } + + if (vfe_mask & (1 << VFE0)) { + timeout = wait_for_completion_timeout( + &ispif->reset_complete[VFE0], msecs_to_jiffies(500)); + if (timeout <= 0) { + pr_err("%s: VFE0 reset wait timeout\n", __func__); + rc = -ETIMEDOUT; + goto disable_clk; + } + } + + if (ispif->hw_num_isps > 1 && (vfe_mask & (1 << VFE1))) { + timeout = wait_for_completion_timeout( + &ispif->reset_complete[VFE1], + msecs_to_jiffies(500)); + if (timeout <= 0) { + pr_err("%s: VFE1 reset wait timeout\n", __func__); + rc = -ETIMEDOUT; + goto disable_clk; + } + } + + pr_info("%s: ISPIF reset hw done", __func__); + + if (ispif->clk_idx == 1) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 0); + if (rc < 0) { + pr_err("%s: cannot disable clock, error = %d", + __func__, rc); + goto end; + } + } + + if (ispif->clk_idx == 2) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8626_reset_clk_info, reset_clk1, + ARRAY_SIZE(ispif_8626_reset_clk_info), 0); + if (rc < 0) { + pr_err("%s: cannot disable clock, error = %d", + __func__, rc); + goto end; + } + } + + for (i = 0; i < params->num; i++) { + intftype = params->entries[i].intftype; + vfe_intf = params->entries[i].vfe_intf; + + switch (params->entries[0].intftype) { + case PIX0: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0); + break; + case RDI0: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0); + break; + case PIX1: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1); + break; + case RDI1: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1); + break; + case RDI2: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2); + break; + default: + pr_err("%s: invalid intftype=%d\n", __func__, + params->entries[i].intftype); + rc = -EPERM; + goto end; + } + + msm_ispif_intf_cmd(ispif, + ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params); + } + + for (i = 0; i < params->num; i++) { + intftype = params->entries[i].intftype; + + vfe_intf = params->entries[i].vfe_intf; + + + cid_mask = msm_ispif_get_cids_mask_from_cfg( + ¶ms->entries[i]); + + msm_ispif_enable_intf_cids(ispif, intftype, + cid_mask, vfe_intf, 1); + } + +end: + return rc; +disable_clk: + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 0); + if (rc < 0) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8626_reset_clk_info, reset_clk1, + ARRAY_SIZE(ispif_8626_reset_clk_info), 0); + if (rc < 0) + pr_err("%s: cannot enable clock, error = %d", + __func__, rc); + } + + return -ETIMEDOUT; +} + +static int msm_ispif_stop_frame_boundary(struct ispif_device *ispif, + struct msm_ispif_param_data *params) +{ + int i, rc = 0; + uint16_t cid_mask = 0; + uint32_t intf_addr; + enum msm_ispif_vfe_intf vfe_intf; + uint32_t stop_flag = 0; + + if (WARN_ON(!ispif) || WARN_ON(!params)) + return -EINVAL; + + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + + for (i = 0; i < params->num; i++) { + if (!msm_ispif_is_intf_valid(ispif->csid_version, + params->entries[i].vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + rc = -EINVAL; + goto end; + } + } + + msm_ispif_intf_cmd(ispif, + ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY, params); + + for (i = 0; i < params->num; i++) { + cid_mask = + msm_ispif_get_cids_mask_from_cfg(¶ms->entries[i]); + vfe_intf = params->entries[i].vfe_intf; + + switch (params->entries[i].intftype) { + case PIX0: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0); + break; + case RDI0: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0); + break; + case PIX1: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1); + break; + case RDI1: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1); + break; + case RDI2: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2); + break; + default: + pr_err("%s: invalid intftype=%d\n", __func__, + params->entries[i].intftype); + rc = -EPERM; + goto end; + } + + rc = readl_poll_timeout(ispif->base + intf_addr, stop_flag, + (stop_flag & 0xF) == 0xF, + ISPIF_TIMEOUT_SLEEP_US, + ISPIF_TIMEOUT_ALL_US); + if (rc < 0) + goto end; + + /* disable CIDs in CID_MASK register */ + msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype, + cid_mask, vfe_intf, 0); + } + +end: + return rc; +} + +static void ispif_process_irq(struct ispif_device *ispif, + struct ispif_irq_status *out, enum msm_ispif_vfe_intf vfe_id) +{ + if (WARN_ON(!ispif) || WARN_ON(!out)) + return; + + if (out[vfe_id].ispifIrqStatus0 & + ISPIF_IRQ_STATUS_PIX_SOF_MASK) { + if (ispif->ispif_sof_debug < 5) + pr_err("%s: PIX0 frame id: %u\n", __func__, + ispif->sof_count[vfe_id].sof_cnt[PIX0]); + ispif->sof_count[vfe_id].sof_cnt[PIX0]++; + ispif->ispif_sof_debug++; + } + if (out[vfe_id].ispifIrqStatus0 & + ISPIF_IRQ_STATUS_RDI0_SOF_MASK) { + ispif->sof_count[vfe_id].sof_cnt[RDI0]++; + } + if (out[vfe_id].ispifIrqStatus1 & + ISPIF_IRQ_STATUS_RDI1_SOF_MASK) { + ispif->sof_count[vfe_id].sof_cnt[RDI1]++; + } + if (out[vfe_id].ispifIrqStatus2 & + ISPIF_IRQ_STATUS_RDI2_SOF_MASK) { + ispif->sof_count[vfe_id].sof_cnt[RDI2]++; + } +} + +static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out, + void *data) +{ + struct ispif_device *ispif = (struct ispif_device *)data; + + if (WARN_ON(!ispif) || WARN_ON(!out)) + return; + + out[VFE0].ispifIrqStatus0 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_0(VFE0)); + msm_camera_io_w(out[VFE0].ispifIrqStatus0, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE0)); + + out[VFE0].ispifIrqStatus1 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_1(VFE0)); + msm_camera_io_w(out[VFE0].ispifIrqStatus1, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE0)); + + out[VFE0].ispifIrqStatus2 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_2(VFE0)); + msm_camera_io_w_mb(out[VFE0].ispifIrqStatus2, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE0)); + + if (ispif->vfe_info.num_vfe > 1) { + out[VFE1].ispifIrqStatus0 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_0(VFE1)); + msm_camera_io_w(out[VFE1].ispifIrqStatus0, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE1)); + + out[VFE1].ispifIrqStatus1 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_1(VFE1)); + msm_camera_io_w(out[VFE1].ispifIrqStatus1, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE1)); + + out[VFE1].ispifIrqStatus2 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_2(VFE1)); + msm_camera_io_w_mb(out[VFE1].ispifIrqStatus2, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE1)); + } + msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) { + if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ) + complete(&ispif->reset_complete[VFE0]); + + if (out[VFE0].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) + pr_err("%s: VFE0 pix0 overflow.\n", __func__); + + if (out[VFE0].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) + pr_err("%s: VFE0 rdi0 overflow.\n", __func__); + + if (out[VFE0].ispifIrqStatus1 & RAW_INTF_1_OVERFLOW_IRQ) + pr_err("%s: VFE0 rdi1 overflow.\n", __func__); + + if (out[VFE0].ispifIrqStatus2 & RAW_INTF_2_OVERFLOW_IRQ) + pr_err("%s: VFE0 rdi2 overflow.\n", __func__); + + ispif_process_irq(ispif, out, VFE0); + } + if (ispif->hw_num_isps > 1) { + if (out[VFE1].ispifIrqStatus0 & RESET_DONE_IRQ) + complete(&ispif->reset_complete[VFE1]); + + if (out[VFE1].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) + pr_err("%s: VFE1 pix0 overflow.\n", __func__); + + if (out[VFE1].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) + pr_err("%s: VFE1 rdi0 overflow.\n", __func__); + + if (out[VFE1].ispifIrqStatus1 & RAW_INTF_1_OVERFLOW_IRQ) + pr_err("%s: VFE1 rdi1 overflow.\n", __func__); + + if (out[VFE1].ispifIrqStatus2 & RAW_INTF_2_OVERFLOW_IRQ) + pr_err("%s: VFE1 rdi2 overflow.\n", __func__); + + ispif_process_irq(ispif, out, VFE1); + } +} + +static irqreturn_t msm_io_ispif_irq(int irq_num, void *data) +{ + struct ispif_irq_status irq[VFE_MAX]; + + msm_ispif_read_irq_status(irq, data); + return IRQ_HANDLED; +} + +static int msm_ispif_set_vfe_info(struct ispif_device *ispif, + struct msm_ispif_vfe_info *vfe_info) +{ + if (!vfe_info || (vfe_info->num_vfe <= 0) || + ((uint32_t)(vfe_info->num_vfe) > ispif->hw_num_isps)) { + pr_err("Invalid VFE info: %pK %d\n", vfe_info, + (vfe_info ? vfe_info->num_vfe:0)); + return -EINVAL; + } + + memcpy(&ispif->vfe_info, vfe_info, sizeof(struct msm_ispif_vfe_info)); + + return 0; +} + +static int msm_ispif_init(struct ispif_device *ispif, + uint32_t csid_version) +{ + int rc = 0; + + if (WARN_ON(!ispif)) { + pr_err("%s: invalid ispif params", __func__); + return -EINVAL; + } + + if (ispif->ispif_state == ISPIF_POWER_UP) { + pr_err("%s: ispif already initted state = %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + + /* can we set to zero? */ + ispif->applied_intf_cmd[VFE0].intf_cmd = 0xFFFFFFFF; + ispif->applied_intf_cmd[VFE0].intf_cmd1 = 0xFFFFFFFF; + ispif->applied_intf_cmd[VFE1].intf_cmd = 0xFFFFFFFF; + ispif->applied_intf_cmd[VFE1].intf_cmd1 = 0xFFFFFFFF; + memset(ispif->sof_count, 0, sizeof(ispif->sof_count)); + + ispif->csid_version = csid_version; + + if (ispif->csid_version >= CSID_VERSION_V30) { + if (!ispif->clk_mux_mem || !ispif->clk_mux_io) { + pr_err("%s csi clk mux mem %pK io %pK\n", __func__, + ispif->clk_mux_mem, ispif->clk_mux_io); + rc = -ENOMEM; + return rc; + } + ispif->clk_mux_base = ioremap(ispif->clk_mux_mem->start, + resource_size(ispif->clk_mux_mem)); + if (!ispif->clk_mux_base) { + pr_err("%s: clk_mux_mem ioremap failed\n", __func__); + rc = -ENOMEM; + return rc; + } + } + + ispif->base = ioremap(ispif->mem->start, + resource_size(ispif->mem)); + if (!ispif->base) { + rc = -ENOMEM; + pr_err("%s: nomem\n", __func__); + goto end; + } + rc = request_irq(ispif->irq->start, msm_io_ispif_irq, + IRQF_TRIGGER_RISING, "ispif", ispif); + if (rc) { + pr_err("%s: request_irq error = %d\n", __func__, rc); + goto error_irq; + } + + rc = msm_ispif_clk_ahb_enable(ispif, 1); + if (rc) { + pr_err("%s: ahb_clk enable failed", __func__); + goto error_ahb; + } + + msm_ispif_reset_hw(ispif); + + rc = msm_ispif_reset(ispif); + if (rc == 0) { + ispif->ispif_state = ISPIF_POWER_UP; + CDBG("%s: power up done\n", __func__); + goto end; + } + +error_ahb: + free_irq(ispif->irq->start, ispif); +error_irq: + iounmap(ispif->base); + +end: + return rc; +} + +static void msm_ispif_release(struct ispif_device *ispif) +{ + if (WARN_ON(!ispif)) { + pr_err("%s: invalid ispif params", __func__); + return; + } + + if (!ispif->base) { + pr_err("%s: ispif base is NULL\n", __func__); + return; + } + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + return; + } + + /* make sure no streaming going on */ + msm_ispif_reset(ispif); + + msm_ispif_clk_ahb_enable(ispif, 0); + + free_irq(ispif->irq->start, ispif); + + iounmap(ispif->base); + + iounmap(ispif->clk_mux_base); + + ispif->ispif_state = ISPIF_POWER_DOWN; +} + +static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg) +{ + long rc = 0; + struct ispif_cfg_data *pcdata = (struct ispif_cfg_data *)arg; + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + + if (WARN_ON(!sd) || WARN_ON(!pcdata)) + return -EINVAL; + + mutex_lock(&ispif->mutex); + switch (pcdata->cfg_type) { + case ISPIF_ENABLE_REG_DUMP: + ispif->enb_dump_reg = pcdata->reg_dump; /* save dump config */ + break; + case ISPIF_INIT: + rc = msm_ispif_init(ispif, pcdata->csid_version); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_CFG: + rc = msm_ispif_config(ispif, &pcdata->params); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_START_FRAME_BOUNDARY: + rc = msm_ispif_start_frame_boundary(ispif, &pcdata->params); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_RESTART_FRAME_BOUNDARY: + rc = msm_ispif_restart_frame_boundary(ispif, &pcdata->params); + msm_ispif_io_dump_reg(ispif); + break; + + case ISPIF_STOP_FRAME_BOUNDARY: + rc = msm_ispif_stop_frame_boundary(ispif, &pcdata->params); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_STOP_IMMEDIATELY: + rc = msm_ispif_stop_immediately(ispif, &pcdata->params); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_RELEASE: + msm_ispif_release(ispif); + break; + case ISPIF_SET_VFE_INFO: + rc = msm_ispif_set_vfe_info(ispif, &pcdata->vfe_info); + break; + default: + pr_err("%s: invalid cfg_type\n", __func__); + rc = -EINVAL; + break; + } + mutex_unlock(&ispif->mutex); + return rc; +} +static struct v4l2_file_operations msm_ispif_v4l2_subdev_fops; + +static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_MSM_ISPIF_CFG: + return msm_ispif_cmd(sd, arg); + case MSM_SD_NOTIFY_FREEZE: { + ispif->ispif_sof_debug = 0; + return 0; + } + case MSM_SD_SHUTDOWN: { + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + if (ispif && ispif->base) { + mutex_lock(&ispif->mutex); + msm_ispif_release(ispif); + mutex_unlock(&ispif->mutex); + } + return 0; + } + default: + pr_err_ratelimited("%s: invalid cmd 0x%x received\n", + __func__, cmd); + return -ENOIOCTLCMD; + } +} + +static long msm_ispif_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + + return msm_ispif_subdev_ioctl(sd, cmd, arg); +} + +static long msm_ispif_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, msm_ispif_subdev_do_ioctl); +} + +static int ispif_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ispif_device *ispif = v4l2_get_subdevdata(sd); + + mutex_lock(&ispif->mutex); + /* mem remap is done in init when the clock is on */ + ispif->open_cnt++; + mutex_unlock(&ispif->mutex); + return 0; +} + +static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct ispif_device *ispif = v4l2_get_subdevdata(sd); + + if (!ispif) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + mutex_lock(&ispif->mutex); + if (ispif->open_cnt == 0) { + pr_err("%s: Invalid close\n", __func__); + rc = -ENODEV; + goto end; + } + ispif->open_cnt--; + if (ispif->open_cnt == 0) + msm_ispif_release(ispif); +end: + mutex_unlock(&ispif->mutex); + return rc; +} + +static struct v4l2_subdev_core_ops msm_ispif_subdev_core_ops = { + /* .g_chip_ident = &msm_ispif_subdev_g_chip_ident, */ + .ioctl = &msm_ispif_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_ispif_subdev_ops = { + .core = &msm_ispif_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops msm_ispif_internal_ops = { + .open = ispif_open_node, + .close = ispif_close_node, +}; + +static int ispif_probe(struct platform_device *pdev) +{ + int rc; + struct ispif_device *ispif; + + ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL); + if (!ispif) + return -ENOMEM; + + if (pdev->dev.of_node) { + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + rc = of_property_read_u32((&pdev->dev)->of_node, + "qcom,num-isps", &ispif->hw_num_isps); + if (rc) + /* backward compatibility */ + ispif->hw_num_isps = 1; + /* not an error condition */ + rc = 0; + } + + mutex_init(&ispif->mutex); + ispif->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "ispif"); + if (!ispif->mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto error; + } + ispif->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "ispif"); + if (!ispif->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto error; + } + ispif->io = request_mem_region(ispif->mem->start, + resource_size(ispif->mem), pdev->name); + if (!ispif->io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto error; + } + ispif->clk_mux_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "csi_clk_mux"); + if (ispif->clk_mux_mem) { + ispif->clk_mux_io = request_mem_region( + ispif->clk_mux_mem->start, + resource_size(ispif->clk_mux_mem), + ispif->clk_mux_mem->name); + if (!ispif->clk_mux_io) + pr_err("%s: no valid csi_mux region\n", __func__); + } + + v4l2_subdev_init(&ispif->msm_sd.sd, &msm_ispif_subdev_ops); + ispif->msm_sd.sd.internal_ops = &msm_ispif_internal_ops; + ispif->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + snprintf(ispif->msm_sd.sd.name, + ARRAY_SIZE(ispif->msm_sd.sd.name), MSM_ISPIF_DRV_NAME); + v4l2_set_subdevdata(&ispif->msm_sd.sd, ispif); + + platform_set_drvdata(pdev, &ispif->msm_sd.sd); + + media_entity_pads_init(&ispif->msm_sd.sd.entity, 0, NULL); + ispif->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_ISPIF; + ispif->msm_sd.sd.entity.name = pdev->name; + ispif->msm_sd.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x1; + rc = msm_sd_register(&ispif->msm_sd); + if (rc) { + pr_err("%s: msm_sd_register error = %d\n", __func__, rc); + goto error; + } + msm_ispif_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; + msm_ispif_v4l2_subdev_fops.open = v4l2_subdev_fops.open; + msm_ispif_v4l2_subdev_fops.unlocked_ioctl = msm_ispif_subdev_fops_ioctl; + msm_ispif_v4l2_subdev_fops.release = v4l2_subdev_fops.release; + msm_ispif_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; +#ifdef CONFIG_COMPAT + msm_ispif_v4l2_subdev_fops.compat_ioctl32 = msm_ispif_subdev_fops_ioctl; +#endif + ispif->msm_sd.sd.devnode->fops = &msm_ispif_v4l2_subdev_fops; + ispif->pdev = pdev; + ispif->ispif_state = ISPIF_POWER_DOWN; + ispif->open_cnt = 0; + return 0; + +error: + mutex_destroy(&ispif->mutex); + kfree(ispif); + return rc; +} + +static const struct of_device_id msm_ispif_dt_match[] = { + {.compatible = "qcom,ispif"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_ispif_dt_match); + +static struct platform_driver ispif_driver = { + .probe = ispif_probe, + .driver = { + .name = MSM_ISPIF_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_ispif_dt_match, + }, +}; + +static int __init msm_ispif_init_module(void) +{ + return platform_driver_register(&ispif_driver); +} + +static void __exit msm_ispif_exit_module(void) +{ + platform_driver_unregister(&ispif_driver); +} + +module_init(msm_ispif_init_module); +module_exit(msm_ispif_exit_module); +MODULE_DESCRIPTION("MSM ISP Interface driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_32.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_32.h new file mode 100644 index 000000000000..6217fbaa18f6 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_32.h @@ -0,0 +1,69 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MSM_ISPIF_H +#define MSM_ISPIF_H + +#include +#include +#include +#include +#include "msm_sd.h" + +#define ISPIF_CLK_INFO_MAX 24 + +struct ispif_irq_status { + uint32_t ispifIrqStatus0; + uint32_t ispifIrqStatus1; + uint32_t ispifIrqStatus2; +}; + +enum msm_ispif_state_t { + ISPIF_POWER_UP, + ISPIF_POWER_DOWN, +}; +struct ispif_sof_count { + uint32_t sof_cnt[INTF_MAX]; +}; + +struct ispif_intf_cmd { + uint32_t intf_cmd; + uint32_t intf_cmd1; +}; + +struct ispif_device { + struct platform_device *pdev; + struct msm_sd_subdev msm_sd; + struct resource *mem; + struct resource *clk_mux_mem; + struct resource *irq; + struct resource *io; + struct resource *clk_mux_io; + void __iomem *base; + void __iomem *clk_mux_base; + struct mutex mutex; + uint8_t start_ack_pending; + uint32_t csid_version; + int enb_dump_reg; + uint32_t open_cnt; + struct ispif_sof_count sof_count[VFE_MAX]; + struct ispif_intf_cmd applied_intf_cmd[VFE_MAX]; + enum msm_ispif_state_t ispif_state; + struct msm_ispif_vfe_info vfe_info; + struct clk *ahb_clk[ISPIF_CLK_INFO_MAX]; + struct completion reset_complete[VFE_MAX]; + uint32_t hw_num_isps; + uint32_t num_ahb_clk; + uint32_t clk_idx; + uint32_t ispif_sof_debug; +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c index 625a0dbeb80f..c045eda41385 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -2077,14 +2077,8 @@ static struct platform_driver msm_actuator_platform_driver = { static int __init msm_actuator_init_module(void) { - int32_t rc = 0; - CDBG("Enter\n"); - rc = platform_driver_register(&msm_actuator_platform_driver); - if (!rc) - return rc; - - CDBG("%s:%d rc %d\n", __func__, __LINE__, rc); + platform_driver_register(&msm_actuator_platform_driver); return i2c_add_driver(&msm_actuator_i2c_driver); } diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c index dfcb73aa5300..d5e79897f73c 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c @@ -323,8 +323,7 @@ static int msm_csid_config(struct csid_device *csid_dev, if (!msm_csid_find_max_clk_rate(csid_dev)) pr_err("msm_csid_find_max_clk_rate failed\n"); - clk_rate = (csid_params->csi_clk > 0) ? - (csid_params->csi_clk) : csid_dev->csid_max_clk; + clk_rate = csid_dev->csid_max_clk; clk_rate = msm_camera_clk_set_rate(&csid_dev->pdev->dev, csid_dev->csid_clk[csid_dev->csid_clk_index], clk_rate); diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c index fa3aceefd32b..5f5667675337 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c @@ -29,7 +29,6 @@ #include "include/msm_csiphy_5_0_hwreg.h" #include "include/msm_csiphy_5_0_1_hwreg.h" #include "include/msm_csiphy_10_0_0_hwreg.h" - #include "cam_hw_ops.h" #define DBG_CSIPHY 0 @@ -1248,9 +1247,7 @@ static int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev, return rc; } - clk_rate = (csiphy_params->csiphy_clk > 0) - ? csiphy_params->csiphy_clk : - csiphy_dev->csiphy_max_clk; + clk_rate = csiphy_dev->csiphy_max_clk; clk_rate = msm_camera_clk_set_rate(&csiphy_dev->pdev->dev, csiphy_dev->csiphy_clk[csiphy_dev->csiphy_clk_index], clk_rate); diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c index df22d843e651..3590e15e5d52 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c @@ -20,7 +20,6 @@ #include "msm_sensor.h" #undef CDBG -#define MSM_CAMERA_TZ_I2C_VERBOSE #ifdef CONFIG_MSM_SEC_CCI_DEBUG #define TZ_I2C_FN_RETURN(ret, i2c_fn, ...) \ diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c index 0b0f98a84786..f80de3a0e569 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. */ -#define SENSOR_DRIVER_I2C "i2c_camera" +#define SENSOR_DRIVER_I2C "camera" /* Header file declaration */ #include "msm_sensor.h" #include "msm_sd.h" diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 3679c596c276..ee643b1ae3a0 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -738,7 +738,7 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { (1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI) | (1 << V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS)| (1 << V4L2_MPEG_VIDC_EXTRADATA_ROI_QP)| - (1UL << V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP) + (1 << V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO) ), .qmenu = mpeg_video_vidc_extradata, }, diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h index 95679cb5ccb6..176dd2e44f07 100644 --- a/include/media/msmb_isp.h +++ b/include/media/msmb_isp.h @@ -28,6 +28,19 @@ struct msm_isp_event_data32 { struct msm_isp_sof_info sof_info; } u; }; + +struct msm_isp32_event_data32 { + struct compat_timeval timestamp; + struct compat_timeval mono_timestamp; + enum msm_vfe_input_src input_intf; + uint32_t frame_id; + union { + struct msm_isp_stats_event stats; + struct msm_isp_buf_event buf_done; + struct msm_isp32_error_info error_info; + } u; +}; + #endif #ifdef CONFIG_MSM_AVTIMER struct avtimer_fptr_t { diff --git a/include/uapi/media/msmb_isp.h b/include/uapi/media/msmb_isp.h index 053fa768cfaf..74a8d9359d34 100644 --- a/include/uapi/media/msmb_isp.h +++ b/include/uapi/media/msmb_isp.h @@ -18,6 +18,7 @@ #define ISP1_BIT (0x10000 << 2) #define ISP_META_CHANNEL_BIT (0x10000 << 3) #define ISP_SCRATCH_BUF_BIT (0x10000 << 4) +#define ISP_PDAF_CHANNEL_BIT (0x10000 << 5) #define ISP_OFFLINE_STATS_BIT (0x10000 << 5) #define ISP_SVHDR_IN_BIT (0x10000 << 6) /* RDI hw stream for SVHDR */ #define ISP_SVHDR_OUT_BIT (0x10000 << 7) /* SVHDR output bufq stream*/ @@ -295,6 +296,11 @@ struct msm_vfe_axi_plane_cfg { uint8_t rdi_cid;/*CID 1-16*/ }; +enum msm_stream_memory_input_t { + MEMORY_INPUT_DISABLED, + MEMORY_INPUT_ENABLED +}; + enum msm_stream_rdi_input_type { MSM_CAMERA_RDI_MIN, MSM_CAMERA_RDI_PDAF, @@ -324,6 +330,29 @@ struct msm_vfe_axi_stream_request_cmd { enum msm_stream_rdi_input_type rdi_input_type; }; +struct msm_vfe32_axi_stream_request_cmd { + uint32_t session_id; + uint32_t stream_id; + uint32_t vt_enable; + uint32_t output_format;/*Planar/RAW/Misc*/ + enum msm_vfe_axi_stream_src stream_src; /*CAMIF/IDEAL/RDIs*/ + struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM]; + + uint32_t burst_count; + uint32_t hfr_mode; + uint8_t frame_base; + + uint32_t init_frame_drop; /*MAX 31 Frames*/ + enum msm_vfe_frame_skip_pattern frame_skip_pattern; + uint8_t buf_divert; /* if TRUE no vb2 buf done. */ + /*Return values*/ + uint32_t axi_stream_handle; + uint32_t controllable_output; + uint32_t burst_len; + /* Flag indicating memory input stream */ + enum msm_stream_memory_input_t memory_input; +}; + struct msm_vfe_axi_stream_release_cmd { uint32_t stream_handle; }; @@ -680,7 +709,9 @@ enum msm_isp_event_idx { ISP_PING_PONG_MISMATCH = 12, ISP_REG_UPDATE_MISSING = 13, ISP_BUF_FATAL_ERROR = 14, - ISP_EVENT_MAX = 15 + ISP_EVENT_MAX = 15, + ISP_WM_BUS_OVERFLOW = 16, + ISP_CAMIF_ERROR = 17, }; #define ISP_EVENT_OFFSET 8 @@ -710,6 +741,7 @@ enum msm_isp_event_idx { #define ISP_EVENT_REG_UPDATE_MISSING (ISP_EVENT_BASE + ISP_REG_UPDATE_MISSING) #define ISP_EVENT_BUF_FATAL_ERROR (ISP_EVENT_BASE + ISP_BUF_FATAL_ERROR) #define ISP_EVENT_STREAM_UPDATE_DONE (ISP_STREAM_EVENT_BASE) +#define ISP_EVENT_WM_BUS_OVERFLOW (ISP_EVENT_BASE + ISP_WM_BUS_OVERFLOW) /* The msm_v4l2_event_data structure should match the * v4l2_event.u.data field. @@ -759,6 +791,11 @@ struct msm_isp_error_info { uint32_t stream_id_mask; }; +struct msm_isp32_error_info { + /* 1 << msm_isp_event_idx */ + uint32_t error_mask; +}; + /* This structure reports delta between master and slave */ struct msm_isp_ms_delta_info { uint8_t num_delta_info; @@ -827,6 +864,25 @@ struct msm_isp_event_data { } u; /* union can have max 52 bytes */ }; +struct msm_isp32_event_data { + /*Wall clock except for buffer divert events + *which use monotonic clock + */ + struct timeval timestamp; + /* Monotonic timestamp since bootup */ + struct timeval mono_timestamp; + enum msm_vfe_input_src input_intf; + uint32_t frame_id; + union { + /* Sent for Stats_Done event */ + struct msm_isp_stats_event stats; + /* Sent for Buf_Divert event */ + struct msm_isp_buf_event buf_done; + struct msm_isp32_error_info error_info; + } u; /* union can have max 52 bytes */ + uint32_t is_skip_pproc; +}; + enum msm_vfe_ahb_clk_vote { MSM_ISP_CAMERA_AHB_SVS_VOTE = 1, MSM_ISP_CAMERA_AHB_TURBO_VOTE = 2, @@ -919,6 +975,7 @@ enum msm_isp_ioctl_cmd_code { MSM_ISP_MAP_BUF_START_MULTI_PASS_FE, MSM_ISP_REQUEST_BUF_VER2, MSM_ISP_DUAL_HW_LPM_MODE, + MSM_ISP32_REQUEST_STREAM, }; #define VIDIOC_MSM_VFE_REG_CFG \ @@ -941,6 +998,10 @@ enum msm_isp_ioctl_cmd_code { _IOWR('V', MSM_ISP_REQUEST_STREAM, \ struct msm_vfe_axi_stream_request_cmd) +#define VIDIOC_MSM_ISP32_REQUEST_STREAM \ + _IOWR('V', MSM_ISP32_REQUEST_STREAM, \ + struct msm_vfe32_axi_stream_request_cmd) + #define VIDIOC_MSM_ISP_CFG_STREAM \ _IOWR('V', MSM_ISP_CFG_STREAM, \ struct msm_vfe_axi_stream_cfg_cmd) @@ -1038,6 +1099,8 @@ enum msm_isp_ioctl_cmd_code { #define VIDIOC_MSM_ISP_REQUEST_BUF_VER2 \ _IOWR('V', MSM_ISP_REQUEST_BUF_VER2, struct msm_isp_buf_request_ver2) +#define VIDIOC_MSM_ISP_BUF_DONE \ + _IOWR('V', BASE_VIDIOC_PRIVATE+21, struct msm_isp32_event_data) #define VIDIOC_MSM_ISP_DUAL_HW_LPM_MODE \ _IOWR('V', MSM_ISP_DUAL_HW_LPM_MODE, \ -- GitLab From d4689a8e6b14a68777326eba675f659f40beb270 Mon Sep 17 00:00:00 2001 From: Sundara Vinayagam Date: Wed, 2 May 2018 21:01:57 +0530 Subject: [PATCH 739/855] ARM: dts: msm: Add camera DT for apq8009 platforms Initial snapshot of camera device tree is taken from msm-3.18 kernel version @ commit cb28f8462e971a ("Merge PM / devfreq: memlat: Remove kfree() on probe fails"). Change-Id: I0c95cc0790d87abdea8cd57378b043e1bfa8882d Signed-off-by: Kaushal Billore Signed-off-by: Sundara Vinayagam --- .../dts/qcom/apq8009-mtp-wcd9326-refboard.dts | 2 + .../msm8909-pm8916-camera-sensor-robot.dtsi | 91 ++++++++ .../boot/dts/qcom/msm8909-pm8916-camera.dtsi | 200 ++++++++++++++++++ 3 files changed, 293 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/msm8909-pm8916-camera-sensor-robot.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm8909-pm8916-camera.dtsi diff --git a/arch/arm64/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts b/arch/arm64/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts index a0a9c5457a00..1866e2f4537a 100644 --- a/arch/arm64/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts +++ b/arch/arm64/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts @@ -18,6 +18,8 @@ #include "apq8009-audio-external_codec.dtsi" #include "apq8009-memory.dtsi" #include +#include "msm8909-pm8916-camera.dtsi" +#include "msm8909-pm8916-camera-sensor-robot.dtsi" / { model = "Qualcomm Technologies, Inc. APQ8009 WCD9326 Reference Board"; diff --git a/arch/arm64/boot/dts/qcom/msm8909-pm8916-camera-sensor-robot.dtsi b/arch/arm64/boot/dts/qcom/msm8909-pm8916-camera-sensor-robot.dtsi new file mode 100644 index 000000000000..6f6655a5e2bf --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8909-pm8916-camera-sensor-robot.dtsi @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&i2c_3 { + status = "ok"; +}; + +&i2c_3 { + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x2>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <90>; + cam_vdig-supply = <&pm8916_l2>; + cam_vana-supply = <&pm8916_l17>; + cam_vio-supply = <&pm8916_l6>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; + qcom,cam-vreg-min-voltage = <1200000 1800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 1800000 2850000>; + qcom,cam-vreg-op-mode = <200000 0 80000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default + &cam_sensor_rear_default>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; + gpios = <&msm_gpio 26 0>, + <&msm_gpio 35 0>, + <&msm_gpio 34 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET", + "CAM_STANDBY"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + status = "ok"; + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@1 { + cell-index = <1>; + compatible = "qcom,camera"; + reg = <0x1>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <90>; + cam_vana-supply = <&pm8916_l17>; + cam_vio-supply = <&pm8916_l6>; + qcom,cam-vreg-name = "cam_vio","cam_vana"; + qcom,cam-vreg-min-voltage = <1800000 2850000>; + qcom,cam-vreg-max-voltage = <1800000 2850000>; + qcom,cam-vreg-op-mode = <0 80000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default + &cam_sensor_rear_default>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; + gpios = <&msm_gpio 26 0>, + <&msm_gpio 35 0>, + <&msm_gpio 34 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET", + "CAM_STANDBY"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + status = "ok"; + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8909-pm8916-camera.dtsi b/arch/arm64/boot/dts/qcom/msm8909-pm8916-camera.dtsi new file mode 100644 index 000000000000..0b648ec3192d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8909-pm8916-camera.dtsi @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,msm-cam@1800000{ + compatible = "qcom,msm-cam"; + reg = <0x1b00000 0x40000>; + reg-names = "msm-cam"; + status = "ok"; + bus-vectors = "suspend", "svs", "nominal", "turbo"; + qcom,bus-votes = <0 320000000 640000000 640000000>; + }; + + qcom,csiphy@1b0ac00 { + cell-index = <0>; + compatible = "qcom,csiphy-v3.1", "qcom,csiphy"; + reg = <0x1b0ac00 0x200>, + <0x1b00030 0x4>; + reg-names = "csiphy", "csiphy_clk_mux"; + interrupts = <0 78 0>; + interrupt-names = "csiphy"; + clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_csi0phytimer_clk_src>, + <&clock_gcc clk_gcc_camss_csi0phytimer_clk>, + <&clock_gcc clk_camss_top_ahb_clk_src>, + <&clock_gcc clk_gcc_camss_csi0phy_clk>, + <&clock_gcc clk_gcc_camss_csi1phy_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>; + clock-names = "camss_top_ahb_clk", "ispif_ahb_clk", + "csiphy_timer_src_clk", "csiphy_timer_clk", + "camss_ahb_src", "csi0_phy_clk", "csi1_phy_clk", + "camss_ahb_clk"; + qcom,clock-rates = <0 0 200000000 0 0 0 0 0>; + }; + + qcom,csid@1b08000 { + cell-index = <0>; + compatible = "qcom,csid-v3.1", "qcom,csid"; + reg = <0x1b08000 0x100>; + reg-names = "csid"; + interrupts = <0 49 0>; + interrupt-names = "csid"; + qcom,csi-vdd-voltage = <1200000>; + qcom,mipi-csi-vdd-supply = <&pm8916_l2>; + clocks = <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_csi0_ahb_clk>, + <&clock_gcc clk_csi0_clk_src>, + <&clock_gcc clk_gcc_camss_csi0_clk>, + <&clock_gcc clk_gcc_camss_csi0pix_clk>, + <&clock_gcc clk_gcc_camss_csi0rdi_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>; + clock-names = "ispif_ahb_clk", "camss_top_ahb_clk", + "csi_ahb_clk", "csi_src_clk", + "csi_clk", "csi_pix_clk", + "csi_rdi_clk", "camss_ahb_clk"; + qcom,clock-rates = <40000000 0 0 200000000 0 0 0 0>; + }; + + qcom,csid@1b08400 { + cell-index = <1>; + compatible = "qcom,csid-v3.1", "qcom,csid"; + reg = <0x1b08400 0x100>; + reg-names = "csid"; + interrupts = <0 50 0>; + interrupt-names = "csid"; + qcom,csi-vdd-voltage = <1200000>; + qcom,mipi-csi-vdd-supply = <&pm8916_l2>; + clocks = <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_csi1_ahb_clk>, + <&clock_gcc clk_csi1_clk_src>, + <&clock_gcc clk_gcc_camss_csi1_clk>, + <&clock_gcc clk_gcc_camss_csi1pix_clk>, + <&clock_gcc clk_gcc_camss_csi1rdi_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>, + <&clock_gcc clk_gcc_camss_csi1phy_clk>; + clock-names = "ispif_ahb_clk", "camss_top_ahb_clk", + "csi_ahb_clk", "csi_src_clk", + "csi_clk", "csi_pix_clk", + "csi_rdi_clk", "camss_ahb_clk", "camss_csi1_phy"; + qcom,clock-rates = <40000000 0 0 200000000 0 0 0 0 0>; + }; + + qcom,ispif@1b0a000 { + cell-index = <0>; + compatible = "qcom,ispif"; + reg = <0x1b0a000 0x500>, + <0x1b00020 0x10>; + reg-names = "ispif", "csi_clk_mux"; + interrupts = <0 51 0>; + interrupt-names = "ispif"; + qcom,num-isps = <0x1>; + vfe0_vdd_supply = <&gdsc_vfe>; + clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + + <&clock_gcc clk_csi0_clk_src>, + <&clock_gcc clk_gcc_camss_csi0_clk>, + <&clock_gcc clk_gcc_camss_csi0rdi_clk>, + <&clock_gcc clk_gcc_camss_csi0pix_clk>, + <&clock_gcc clk_csi1_clk_src>, + <&clock_gcc clk_gcc_camss_csi1_clk>, + <&clock_gcc clk_gcc_camss_csi1rdi_clk>, + <&clock_gcc clk_gcc_camss_csi1pix_clk>, + <&clock_gcc clk_vfe0_clk_src>, + <&clock_gcc clk_gcc_camss_vfe0_clk>, + <&clock_gcc clk_gcc_camss_csi_vfe0_clk>; + + clock-names = "camss_top_ahb_clk", "ispif_ahb_clk", + "csi0_src_clk", "csi0_clk", + "csi0_rdi_clk", "csi0_pix_clk", + "csi1_src_clk", "csi1_clk", + "csi1_rdi_clk", "csi1_pix_clk", + "vfe0_clk_src", "camss_vfe_vfe0_clk", + "camss_csi_vfe0_clk"; + qcom,clock-rates = <0 40000000 + 200000000 0 0 0 + 200000000 0 0 0 + 0 0 0>; + qcom,clock-control = "NO_SET_RATE", "SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", "NO_SET_RATE", "NO_SET_RATE"; + }; + + qcom,vfe@1b10000 { + cell-index = <0>; + compatible = "qcom,vfe32"; + reg = <0x1b10000 0x830>, + <0x1b40000 0x200>; + reg-names = "vfe", "vfe_vbif"; + interrupts = <0 52 0>; + interrupt-names = "vfe"; + vdd-supply = <&gdsc_vfe>; + clocks = <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_vfe0_clk_src>, + <&clock_gcc clk_gcc_camss_vfe0_clk>, + <&clock_gcc clk_gcc_camss_csi_vfe0_clk>, + <&clock_gcc clk_gcc_camss_vfe_ahb_clk>, + <&clock_gcc clk_gcc_camss_vfe_axi_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>, + <&clock_gcc clk_gcc_camss_top_ahb_clk>; + clock-names = "camss_top_ahb_clk", "vfe_clk_src", + "camss_vfe_vfe_clk", "camss_csi_vfe_clk", "iface_clk", + "bus_clk", "camss_ahb_clk", "ispif_ahb_clk"; + qcom,clock-rates = <40000000 266670000 0 0 0 0 0 0>; + + qos-entries = <8>; + qos-regs = <0x7BC 0x7C0 0x7C4 0x7C8 0x7CC 0x7D0 + 0x7D4 0x798>; + qos-settings = <0xAAA5AAA5 0xAAA5AAA5 0xAAA5AAA5 + 0xAAA5AAA5 0xAAA5AAA5 0xAAA5AAA5 + 0xAAA5AAA5 0x00010000>; + vbif-entries = <1>; + vbif-regs = <0x04>; + vbif-settings = <0x1>; + ds-entries = <15>; + ds-regs = <0x7D8 0x7DC 0x7E0 0x7E4 0x7E8 + 0x7EC 0x7F0 0x7F4 0x7F8 0x7FC 0x800 + 0x804 0x808 0x80C 0x810>; + ds-settings = <0xCCCC1111 0xCCCC1111 0xCCCC1111 + 0xCCCC1111 0xCCCC1111 0xCCCC1111 + 0xCCCC1111 0xCCCC1111 0xCCCC1111 + 0xCCCC1111 0xCCCC1111 0xCCCC1111 + 0xCCCC1111 0xCCCC1111 0x00000103>; + + bus-util-factor = <1024>; + }; + + qcom,cam_smmu { + status = "ok"; + compatible = "qcom,msm-cam-smmu"; + msm_cam_smmu_cb1: msm_cam_smmu_cb1 { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_iommu 0x400 0x00>; + label = "vfe"; + qcom,scratch-buf-support; + }; + }; + + qcom,irqrouter@1b00000 { + status = "ok"; + cell-index = <0>; + compatible = "qcom,irqrouter"; + reg = <0x1b00000 0x100>; + reg-names = "irqrouter"; + }; +}; -- GitLab From 60b2f6764eeb12367662e1dc8ccda7a04e3d3076 Mon Sep 17 00:00:00 2001 From: Sundara Vinayagam Date: Fri, 25 May 2018 22:08:13 +0530 Subject: [PATCH 740/855] defconfig: msm: camera: enable configurations to support apq8009 Enable kernel configurations to support camera on apq8009 platform. Change-Id: I21a5330660d72a8673c0ff35be356d7203f47967 Signed-off-by: Sundara Vinayagam Signed-off-by: Kaushal Billore --- arch/arm/configs/msm8909-perf_defconfig | 14 ++++++++++++-- arch/arm/configs/msm8909_defconfig | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 1eaf4ffc03ce..cb3c33350b2c 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -321,6 +321,16 @@ CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_CSID=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_ISP_V1=y +CONFIG_MSM_ISPIF=y +CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_VIRTUAL=y CONFIG_BACKLIGHT_LCD_SUPPORT=y @@ -374,8 +384,7 @@ CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y +CONFIG_LEDS_CLASS_FLASH=y CONFIG_LEDS_QPNP=y CONFIG_LEDS_QPNP_VIBRATOR=y CONFIG_LEDS_TRIGGERS=y @@ -398,6 +407,7 @@ CONFIG_USB_BAM=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_MAILBOX=y CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y CONFIG_MSM_BOOT_STATS=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index 5e6a68b97b7b..bab3132e0c54 100644 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -316,6 +316,16 @@ CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_CSID=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_ISP_V1=y +CONFIG_MSM_ISPIF=y +CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_VIRTUAL=y CONFIG_BACKLIGHT_LCD_SUPPORT=y @@ -369,8 +379,7 @@ CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y +CONFIG_LEDS_CLASS_FLASH=y CONFIG_LEDS_QPNP=y CONFIG_LEDS_QPNP_VIBRATOR=y CONFIG_LEDS_TRIGGERS=y @@ -393,6 +402,7 @@ CONFIG_USB_BAM=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_MAILBOX=y CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y CONFIG_MSM_BOOT_STATS=y -- GitLab From f4e179e6af295abb0a5c5785a87edaeac9f25692 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 6 Jun 2018 14:26:26 -0700 Subject: [PATCH 741/855] msm: camera: sensor: Remove NULL check This change removes the NULL check in update power settings since this function is expected to be invoked only once at the time of probe. Change-Id: I976c976bea2df35adf5de1988930bfa3fe454561 Signed-off-by: Karthik Anantha Ram --- .../cam_sensor_utils/cam_sensor_util.c | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 6fccf1b9c74b..73a0cf71071e 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -698,25 +698,21 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, } power_info->power_setting_size = 0; - if (power_info->power_setting == NULL) { - power_info->power_setting = - (struct cam_sensor_power_setting *) - kzalloc(sizeof(struct cam_sensor_power_setting) * - MAX_POWER_CONFIG, GFP_KERNEL); - if (!power_info->power_setting) - return -ENOMEM; - } + power_info->power_setting = + (struct cam_sensor_power_setting *) + kzalloc(sizeof(struct cam_sensor_power_setting) * + MAX_POWER_CONFIG, GFP_KERNEL); + if (!power_info->power_setting) + return -ENOMEM; power_info->power_down_setting_size = 0; - if (power_info->power_down_setting == NULL) { - power_info->power_down_setting = - (struct cam_sensor_power_setting *) - kzalloc(sizeof(struct cam_sensor_power_setting) * - MAX_POWER_CONFIG, GFP_KERNEL); - if (!power_info->power_down_setting) { - rc = -ENOMEM; - goto free_power_settings; - } + power_info->power_down_setting = + (struct cam_sensor_power_setting *) + kzalloc(sizeof(struct cam_sensor_power_setting) * + MAX_POWER_CONFIG, GFP_KERNEL); + if (!power_info->power_down_setting) { + rc = -ENOMEM; + goto free_power_settings; } while (tot_size < cmd_length) { -- GitLab From fbc51864397f4f5dfa00bccb1c0853c5627cbc93 Mon Sep 17 00:00:00 2001 From: Shihuan Liu Date: Tue, 27 Feb 2018 23:21:14 -0800 Subject: [PATCH 742/855] msm: ipa: ipa gsb driver IPA Generic Software Bridging (GSB) driver implementation. Change-Id: Id329e1f09250d9d171d4d4dde1eaf9907c457f2c Acked-by: Shihuan Liu Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_clients/Makefile | 2 +- .../platform/msm/ipa/ipa_clients/ipa_gsb.c | 1071 +++++++++++++++++ .../platform/msm/ipa/ipa_clients/odu_bridge.c | 382 +----- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 17 +- 4 files changed, 1087 insertions(+), 385 deletions(-) create mode 100644 drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c diff --git a/drivers/platform/msm/ipa/ipa_clients/Makefile b/drivers/platform/msm/ipa/ipa_clients/Makefile index 738d88f23ddd..a21313085c56 100644 --- a/drivers/platform/msm/ipa/ipa_clients/Makefile +++ b/drivers/platform/msm/ipa/ipa_clients/Makefile @@ -1,4 +1,4 @@ -obj-$(CONFIG_IPA3) += ipa_usb.o odu_bridge.o ipa_mhi_client.o ipa_uc_offload.o ipa_wdi3.o +obj-$(CONFIG_IPA3) += ipa_usb.o odu_bridge.o ipa_mhi_client.o ipa_uc_offload.o ipa_wdi3.o ipa_gsb.o obj-$(CONFIG_IPA) += odu_bridge.o ipa_mhi_client.o ipa_uc_offload.o ipa_wdi3.o obj-$(CONFIG_ECM_IPA) += ecm_ipa.o obj-$(CONFIG_RNDIS_IPA) += rndis_ipa.o diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c new file mode 100644 index 000000000000..df19384a145a --- /dev/null +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c @@ -0,0 +1,1071 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../ipa_common_i.h" +#ifdef CONFIG_IPA3 +#include "../ipa_v3/ipa_pm.h" +#endif + +#define IPA_GSB_DRV_NAME "ipa_gsb" + +#define MAX_SUPPORTED_IFACE 5 + +#define IPA_GSB_DBG(fmt, args...) \ + do { \ + pr_debug(IPA_GSB_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + IPA_GSB_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPA_GSB_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +#define IPA_GSB_DBG_LOW(fmt, args...) \ + do { \ + pr_debug(IPA_GSB_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPA_GSB_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +#define IPA_GSB_ERR(fmt, args...) \ + do { \ + pr_err(IPA_GSB_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + IPA_GSB_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPA_GSB_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +#define IPA_GSB_MAX_MSG_LEN 512 +static char dbg_buff[IPA_GSB_MAX_MSG_LEN]; + +#define IPA_GSB_SKB_HEADROOM 256 +#define IPA_GSB_AGGR_BYTE_LIMIT 6 +#define IPA_GSB_AGGR_TIME_LIMIT 1 + +static struct dentry *dent; +static struct dentry *dfile_stats; + +/** + * struct stats - driver statistics, + * @num_ul_packets: number of uplink packets + * @num_dl_packets: number of downlink packets + * @num_insufficient_headroom_packets: number of + packets with insufficient headroom + */ +struct stats { + u64 num_ul_packets; + u64 num_dl_packets; + u64 num_insufficient_headroom_packets; +}; + +/** + * struct ipa_gsb_mux_hdr - ipa gsb mux header, + * @iface_hdl: interface handle + * @qmap_id: qmap id + * @pkt_size: packet size + */ +struct ipa_gsb_mux_hdr { + u8 iface_hdl; + u8 qmap_id; + u16 pkt_size; +}; + +/** + * struct ipa_gsb_iface_info - GSB interface information + * @netdev_name: network interface name + * @device_ethaddr: network interface ethernet address + * @priv: client's private data. to be used in client's callbacks + * @tx_dp_notify: client callback for handling IPA ODU_PROD callback + * @send_dl_skb: client callback for sending skb in downlink direction + * @iface_stats: statistics, how many packets were transmitted + * using the SW bridge. + * @partial_hdr_hdl: handle for partial header + * @wakeup_request: client callback to wakeup + * @is_conencted: is interface connected ? + * @is_resumed: is interface resumed ? + * @iface_hdl: interface handle + */ +struct ipa_gsb_iface_info { + char netdev_name[IPA_RESOURCE_NAME_MAX]; + u8 device_ethaddr[ETH_ALEN]; + void *priv; + ipa_notify_cb tx_dp_notify; + int (*send_dl_skb)(void *priv, struct sk_buff *skb); + struct stats iface_stats; + uint32_t partial_hdr_hdl[IPA_IP_MAX]; + void (*wakeup_request)(void *); + bool is_connected; + bool is_resumed; + u8 iface_hdl; +}; + +/** + * struct ipa_gsb_context - GSB driver context information + * @logbuf: buffer of ipc logging + * @logbuf_low: buffer of ipc logging (low priority) + * @lock: mutex lock + * @prod_hdl: handle for prod pipe + * @cons_hdl: handle for cons pipe + * @ipa_sys_desc_size: sys pipe desc size + * @num_iface: number of interface + * @iface_hdl: interface handles + * @num_connected_iface: number of connected interface + * @num_resumed_iface: number of resumed interface + * @iface: interface information + * @pm_hdl: IPA PM handle + */ +struct ipa_gsb_context { + void *logbuf; + void *logbuf_low; + struct mutex lock; + u32 prod_hdl; + u32 cons_hdl; + u32 ipa_sys_desc_size; + int num_iface; + bool iface_hdl[MAX_SUPPORTED_IFACE]; + int num_connected_iface; + int num_resumed_iface; + struct ipa_gsb_iface_info *iface[MAX_SUPPORTED_IFACE]; + u32 pm_hdl; +}; + +static struct ipa_gsb_context *ipa_gsb_ctx; + +#ifdef CONFIG_DEBUG_FS +static ssize_t ipa_gsb_debugfs_stats(struct file *file, + char __user *ubuf, + size_t count, + loff_t *ppos) +{ + int i, nbytes = 0; + + for (i = 0; i < MAX_SUPPORTED_IFACE; i++) + if (ipa_gsb_ctx->iface[i] != NULL) { + nbytes += scnprintf(&dbg_buff[nbytes], + IPA_GSB_MAX_MSG_LEN - nbytes, + "netdev: %s\n", + ipa_gsb_ctx->iface[i]->netdev_name); + + nbytes += scnprintf(&dbg_buff[nbytes], + IPA_GSB_MAX_MSG_LEN - nbytes, + "UL packets: %lld\n", + ipa_gsb_ctx->iface[i]-> + iface_stats.num_ul_packets); + + nbytes += scnprintf(&dbg_buff[nbytes], + IPA_GSB_MAX_MSG_LEN - nbytes, + "DL packets: %lld\n", + ipa_gsb_ctx->iface[i]-> + iface_stats.num_dl_packets); + + nbytes += scnprintf(&dbg_buff[nbytes], + IPA_GSB_MAX_MSG_LEN - nbytes, + "packets with insufficient headroom: %lld\n", + ipa_gsb_ctx->iface[i]-> + iface_stats.num_insufficient_headroom_packets); + } + return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes); +} + +static const struct file_operations ipa_gsb_stats_ops = { + .read = ipa_gsb_debugfs_stats, +}; + +static void ipa_gsb_debugfs_init(void) +{ + const mode_t read_only_mode = 00444; + + dent = debugfs_create_dir("ipa_gsb", NULL); + if (IS_ERR(dent)) { + IPA_GSB_ERR("fail to create folder ipa_gsb\n"); + return; + } + + dfile_stats = + debugfs_create_file("stats", read_only_mode, dent, + NULL, &ipa_gsb_stats_ops); + if (!dfile_stats || IS_ERR(dfile_stats)) { + IPA_GSB_ERR("fail to create file stats\n"); + goto fail; + } + + return; + +fail: + debugfs_remove_recursive(dent); +} + +static void ipa_gsb_debugfs_destroy(void) +{ + debugfs_remove_recursive(dent); +} +#else +static void ipa_gsb_debugfs_init(void) +{ +} + +static void ipa_gsb_debugfs_destroy(void) +{ +} +#endif + +static int ipa_gsb_driver_init(struct odu_bridge_params *params) +{ + if (!ipa_is_ready()) { + IPA_GSB_ERR("IPA is not ready\n"); + return -EFAULT; + } + + ipa_gsb_ctx = kzalloc(sizeof(*ipa_gsb_ctx), + GFP_KERNEL); + + if (!ipa_gsb_ctx) + return -ENOMEM; + + mutex_init(&ipa_gsb_ctx->lock); + ipa_gsb_debugfs_init(); + + return 0; +} + +static int ipa_gsb_commit_partial_hdr(struct ipa_gsb_iface_info *iface_info) +{ + int i; + struct ipa_ioc_add_hdr *hdr; + + if (!iface_info) { + IPA_GSB_ERR("invalid input\n"); + return -EINVAL; + } + + hdr = kzalloc(sizeof(struct ipa_ioc_add_hdr) + + 2 * sizeof(struct ipa_hdr_add), GFP_KERNEL); + if (!hdr) + return -ENOMEM; + + hdr->commit = 1; + hdr->num_hdrs = 2; + + snprintf(hdr->hdr[0].name, sizeof(hdr->hdr[0].name), + "%s_ipv4", iface_info->netdev_name); + snprintf(hdr->hdr[1].name, sizeof(hdr->hdr[1].name), + "%s_ipv6", iface_info->netdev_name); + /* partial header: [hdl][QMAP ID][pkt size][ETH header] */ + for (i = IPA_IP_v4; i < IPA_IP_MAX; i++) { + hdr->hdr[i].hdr_len = ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr); + hdr->hdr[i].type = IPA_HDR_L2_ETHERNET_II; + hdr->hdr[i].is_partial = 1; + hdr->hdr[i].is_eth2_ofst_valid = 1; + hdr->hdr[i].eth2_ofst = sizeof(struct ipa_gsb_mux_hdr); + /* populate iface handle */ + hdr->hdr[i].hdr[0] = iface_info->iface_hdl; + /* populate src ETH address */ + memcpy(&hdr->hdr[i].hdr[10], iface_info->device_ethaddr, 6); + /* populate Ethertype */ + if (i == IPA_IP_v4) + *(u16 *)(hdr->hdr[i].hdr + 16) = htons(ETH_P_IP); + else + *(u16 *)(hdr->hdr[i].hdr + 16) = htons(ETH_P_IPV6); + } + + if (ipa_add_hdr(hdr)) { + IPA_GSB_ERR("fail to add partial headers\n"); + kfree(hdr); + return -EFAULT; + } + + for (i = IPA_IP_v4; i < IPA_IP_MAX; i++) + iface_info->partial_hdr_hdl[i] = + hdr->hdr[i].hdr_hdl; + + IPA_GSB_DBG("added partial hdr hdl for ipv4: %d\n", + iface_info->partial_hdr_hdl[IPA_IP_v4]); + IPA_GSB_DBG("added partial hdr hdl for ipv6: %d\n", + iface_info->partial_hdr_hdl[IPA_IP_v6]); + + kfree(hdr); + return 0; +} + +static void ipa_gsb_delete_partial_hdr(struct ipa_gsb_iface_info *iface_info) +{ + struct ipa_ioc_del_hdr *del_hdr; + + del_hdr = kzalloc(sizeof(struct ipa_ioc_del_hdr) + + 2 * sizeof(struct ipa_hdr_del), GFP_KERNEL); + if (!del_hdr) + return; + + del_hdr->commit = 1; + del_hdr->num_hdls = 2; + del_hdr->hdl[IPA_IP_v4].hdl = iface_info->partial_hdr_hdl[IPA_IP_v4]; + del_hdr->hdl[IPA_IP_v6].hdl = iface_info->partial_hdr_hdl[IPA_IP_v6]; + + if (ipa_del_hdr(del_hdr) != 0) + IPA_GSB_ERR("failed to delete partial hdr\n"); + + IPA_GSB_DBG("deleted partial hdr hdl for ipv4: %d\n", + iface_info->partial_hdr_hdl[IPA_IP_v4]); + IPA_GSB_DBG("deleted partial hdr hdl for ipv6: %d\n", + iface_info->partial_hdr_hdl[IPA_IP_v6]); + + kfree(del_hdr); +} + +static int ipa_gsb_reg_intf_props(struct ipa_gsb_iface_info *iface_info) +{ + struct ipa_tx_intf tx; + struct ipa_rx_intf rx; + struct ipa_ioc_tx_intf_prop tx_prop[2]; + struct ipa_ioc_rx_intf_prop rx_prop[2]; + + /* populate tx prop */ + tx.num_props = 2; + tx.prop = tx_prop; + + memset(tx_prop, 0, sizeof(tx_prop)); + tx_prop[0].ip = IPA_IP_v4; + tx_prop[0].dst_pipe = IPA_CLIENT_ODU_EMB_CONS; + tx_prop[0].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + snprintf(tx_prop[0].hdr_name, sizeof(tx_prop[0].hdr_name), + "%s_ipv4", iface_info->netdev_name); + + tx_prop[1].ip = IPA_IP_v6; + tx_prop[1].dst_pipe = IPA_CLIENT_ODU_EMB_CONS; + tx_prop[1].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + snprintf(tx_prop[1].hdr_name, sizeof(tx_prop[1].hdr_name), + "%s_ipv6", iface_info->netdev_name); + + /* populate rx prop */ + rx.num_props = 2; + rx.prop = rx_prop; + + memset(rx_prop, 0, sizeof(rx_prop)); + rx_prop[0].ip = IPA_IP_v4; + rx_prop[0].src_pipe = IPA_CLIENT_ODU_PROD; + rx_prop[0].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + rx_prop[0].attrib.attrib_mask |= IPA_FLT_META_DATA; + rx_prop[0].attrib.meta_data = iface_info->iface_hdl; + rx_prop[0].attrib.meta_data_mask = 0xFF; + + rx_prop[1].ip = IPA_IP_v6; + rx_prop[1].src_pipe = IPA_CLIENT_ODU_PROD; + rx_prop[1].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + rx_prop[1].attrib.attrib_mask |= IPA_FLT_META_DATA; + rx_prop[1].attrib.meta_data = iface_info->iface_hdl; + rx_prop[1].attrib.meta_data_mask = 0xFF; + + if (ipa_register_intf(iface_info->netdev_name, &tx, &rx)) { + IPA_GSB_ERR("fail to add interface prop\n"); + return -EFAULT; + } + + return 0; +} + +static void ipa_gsb_dereg_intf_props(struct ipa_gsb_iface_info *iface_info) +{ + if (ipa_deregister_intf(iface_info->netdev_name) != 0) + IPA_GSB_ERR("fail to dereg intf props\n"); + + IPA_GSB_DBG("deregistered iface props for %s\n", + iface_info->netdev_name); +} + +static void ipa_gsb_pm_cb(void *user_data, enum ipa_pm_cb_event event) +{ + int i; + + if (event != IPA_PM_REQUEST_WAKEUP) { + IPA_GSB_ERR("Unexpected event %d\n", event); + WARN_ON(1); + return; + } + + IPA_GSB_DBG("wake up clients\n"); + for (i = 0; i < MAX_SUPPORTED_IFACE; i++) + if (ipa_gsb_ctx->iface[i] != NULL) + ipa_gsb_ctx->iface[i]->wakeup_request( + ipa_gsb_ctx->iface[i]->priv); +} + +static int ipa_gsb_register_pm(void) +{ + struct ipa_pm_register_params reg_params; + int ret; + + memset(®_params, 0, sizeof(reg_params)); + reg_params.name = "ipa_gsb"; + reg_params.callback = ipa_gsb_pm_cb; + reg_params.user_data = NULL; + reg_params.group = IPA_PM_GROUP_DEFAULT; + + ret = ipa_pm_register(®_params, + &ipa_gsb_ctx->pm_hdl); + if (ret) { + IPA_GSB_ERR("fail to register with PM %d\n", ret); + goto fail_pm_reg; + } + IPA_GSB_DBG("ipa pm hdl: %d\n", ipa_gsb_ctx->pm_hdl); + + ret = ipa_pm_associate_ipa_cons_to_client(ipa_gsb_ctx->pm_hdl, + IPA_CLIENT_ODU_EMB_CONS); + if (ret) { + IPA_GSB_ERR("fail to associate cons with PM %d\n", ret); + goto fail_pm_cons; + } + + return 0; + +fail_pm_cons: + ipa_pm_deregister(ipa_gsb_ctx->pm_hdl); + ipa_gsb_ctx->pm_hdl = ~0; +fail_pm_reg: + return ret; +} + +int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl) +{ + int i, ret; + struct ipa_gsb_iface_info *new_intf; + + if (!params || !params->wakeup_request || !hdl || + !params->info.netdev_name || !params->info.tx_dp_notify || + !params->info.send_dl_skb) { + IPA_GSB_ERR("NULL parameters\n"); + return -EINVAL; + } + + IPA_GSB_DBG("netdev_name: %s\n", params->info.netdev_name); + + if (ipa_gsb_ctx == NULL) { + ret = ipa_gsb_driver_init(¶ms->info); + if (ret) { + IPA_GSB_ERR("fail to init ipa gsb driver\n"); + return -EFAULT; + } + ipa_gsb_ctx->ipa_sys_desc_size = + params->info.ipa_desc_size; + IPA_GSB_DBG("desc size: %d\n", ipa_gsb_ctx->ipa_sys_desc_size); + } + + mutex_lock(&ipa_gsb_ctx->lock); + + if (params->info.ipa_desc_size != ipa_gsb_ctx->ipa_sys_desc_size) { + IPA_GSB_ERR("unmatch: orig desc size %d, new desc size %d\n", + ipa_gsb_ctx->ipa_sys_desc_size, + params->info.ipa_desc_size); + mutex_unlock(&ipa_gsb_ctx->lock); + return -EFAULT; + } + + for (i = 0; i < MAX_SUPPORTED_IFACE; i++) + if (ipa_gsb_ctx->iface[i] != NULL && + strnlen(ipa_gsb_ctx->iface[i]->netdev_name, + IPA_RESOURCE_NAME_MAX) == + strnlen(params->info.netdev_name, + IPA_RESOURCE_NAME_MAX) && + strcmp(ipa_gsb_ctx->iface[i]->netdev_name, + params->info.netdev_name) == 0) { + IPA_GSB_ERR("intf was added before.\n"); + mutex_unlock(&ipa_gsb_ctx->lock); + return -EFAULT; + } + + if (ipa_gsb_ctx->num_iface == MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("reached maximum supported interfaces"); + mutex_unlock(&ipa_gsb_ctx->lock); + return -EFAULT; + } + + for (i = 0; i < MAX_SUPPORTED_IFACE; i++) + if (ipa_gsb_ctx->iface_hdl[i] == false) { + ipa_gsb_ctx->iface_hdl[i] = true; + *hdl = i; + IPA_GSB_DBG("iface hdl: %d\n", *hdl); + break; + } + + IPA_GSB_DBG("intf was not added before, proceed.\n"); + new_intf = kzalloc(sizeof(*new_intf), GFP_KERNEL); + if (new_intf == NULL) { + ret = -ENOMEM; + goto fail_alloc_mem; + } + + strlcpy(new_intf->netdev_name, params->info.netdev_name, + sizeof(new_intf->netdev_name)); + new_intf->wakeup_request = params->wakeup_request; + new_intf->priv = params->info.priv; + new_intf->tx_dp_notify = params->info.tx_dp_notify; + new_intf->send_dl_skb = params->info.send_dl_skb; + new_intf->iface_hdl = *hdl; + memcpy(new_intf->device_ethaddr, params->info.device_ethaddr, + sizeof(new_intf->device_ethaddr)); + + if (ipa_gsb_commit_partial_hdr(new_intf) != 0) { + IPA_GSB_ERR("fail to commit partial hdrs\n"); + ret = -EFAULT; + goto fail_partial_hdr; + } + + if (ipa_gsb_reg_intf_props(new_intf) != 0) { + IPA_GSB_ERR("fail to register interface props\n"); + ret = -EFAULT; + goto fail_reg_intf_props; + } + + if (ipa_gsb_ctx->num_iface == 0) { + ret = ipa_gsb_register_pm(); + if (ret) { + IPA_GSB_ERR("fail to register with IPA PM %d\n", ret); + ret = -EFAULT; + goto fail_register_pm; + } + } + + ipa_gsb_ctx->iface[*hdl] = new_intf; + ipa_gsb_ctx->num_iface++; + IPA_GSB_DBG("num_iface %d\n", ipa_gsb_ctx->num_iface); + mutex_unlock(&ipa_gsb_ctx->lock); + return 0; + +fail_register_pm: + ipa_gsb_dereg_intf_props(new_intf); +fail_reg_intf_props: + ipa_gsb_delete_partial_hdr(new_intf); +fail_partial_hdr: + kfree(new_intf); +fail_alloc_mem: + ipa_gsb_ctx->iface_hdl[*hdl] = false; + mutex_unlock(&ipa_gsb_ctx->lock); + return ret; +} +EXPORT_SYMBOL(ipa_bridge_init); + +static void ipa_gsb_deregister_pm(void) +{ + IPA_GSB_DBG("deregister ipa pm hdl: %d\n", ipa_gsb_ctx->pm_hdl); + ipa_pm_deactivate_sync(ipa_gsb_ctx->pm_hdl); + ipa_pm_deregister(ipa_gsb_ctx->pm_hdl); + ipa_gsb_ctx->pm_hdl = ~0; +} + +int ipa_bridge_cleanup(u32 hdl) +{ + if (!ipa_gsb_ctx) { + IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n"); + return -EFAULT; + } + + if (hdl >= MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("invalid hdl: %d\n", hdl); + return -EINVAL; + } + + if (ipa_gsb_ctx->iface[hdl] == NULL) { + IPA_GSB_ERR("fail to find interface\n"); + return -EFAULT; + } + + IPA_GSB_DBG("client hdl: %d\n", hdl); + mutex_lock(&ipa_gsb_ctx->lock); + + if (ipa_gsb_ctx->iface[hdl]->is_connected) { + IPA_GSB_ERR("cannot cleanup when iface is connected\n"); + mutex_unlock(&ipa_gsb_ctx->lock); + return -EFAULT; + } + + ipa_gsb_dereg_intf_props(ipa_gsb_ctx->iface[hdl]); + ipa_gsb_delete_partial_hdr(ipa_gsb_ctx->iface[hdl]); + kfree(ipa_gsb_ctx->iface[hdl]); + ipa_gsb_ctx->iface[hdl] = NULL; + ipa_gsb_ctx->iface_hdl[hdl] = false; + ipa_gsb_ctx->num_iface--; + IPA_GSB_DBG("num_iface %d\n", ipa_gsb_ctx->num_iface); + + if (ipa_gsb_ctx->num_iface == 0) { + ipa_gsb_deregister_pm(); + ipa_gsb_debugfs_destroy(); + ipc_log_context_destroy(ipa_gsb_ctx->logbuf); + ipc_log_context_destroy(ipa_gsb_ctx->logbuf_low); + mutex_unlock(&ipa_gsb_ctx->lock); + kfree(ipa_gsb_ctx); + ipa_gsb_ctx = NULL; + return 0; + } + + mutex_unlock(&ipa_gsb_ctx->lock); + return 0; +} +EXPORT_SYMBOL(ipa_bridge_cleanup); + +static struct sk_buff *ipa_gsb_skb_copy(struct sk_buff *skb, int len) +{ + struct sk_buff *skb2 = NULL; + + skb2 = __dev_alloc_skb(len + IPA_GSB_SKB_HEADROOM, GFP_KERNEL); + if (likely(skb2)) { + skb_reserve(skb2, IPA_GSB_SKB_HEADROOM); + memcpy(skb2->data, skb->data, len); + skb2->len = len; + skb_set_tail_pointer(skb2, len); + } + + return skb2; +} + +static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt, + unsigned long data) +{ + struct sk_buff *skb; + struct sk_buff *skb2; + struct ipa_gsb_mux_hdr *mux_hdr; + u16 pkt_size, pad_byte; + u8 hdl; + + if (evt != IPA_RECEIVE) { + IPA_GSB_ERR("unexpected event\n"); + WARN_ON(1); + return; + } + + skb = (struct sk_buff *)data; + + while (skb->len) { + mux_hdr = (struct ipa_gsb_mux_hdr *)skb->data; + pkt_size = mux_hdr->pkt_size; + /* 4-byte padding */ + pad_byte = ((pkt_size + sizeof(*mux_hdr) + ETH_HLEN + 3) & ~3) + - (pkt_size + sizeof(*mux_hdr) + ETH_HLEN); + hdl = mux_hdr->iface_hdl; + IPA_GSB_DBG("pkt_size: %d, pad_byte: %d, hdl: %d\n", + pkt_size, pad_byte, hdl); + + /* remove 4 byte mux header */ + skb_pull(skb, sizeof(*mux_hdr)); + skb2 = ipa_gsb_skb_copy(skb, pkt_size + ETH_HLEN); + ipa_gsb_ctx->iface[hdl]->send_dl_skb( + ipa_gsb_ctx->iface[hdl]->priv, skb2); + ipa_gsb_ctx->iface[hdl]->iface_stats.num_dl_packets++; + + skb_pull(skb, pkt_size + ETH_HLEN + pad_byte); + } +} + +static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt, + unsigned long data) +{ + struct sk_buff *skb; + struct ipa_gsb_mux_hdr *mux_hdr; + u8 hdl; + + skb = (struct sk_buff *)data; + + if (evt != IPA_WRITE_DONE && evt != IPA_RECEIVE) { + IPA_GSB_ERR("unexpected event: %d\n", evt); + dev_kfree_skb_any(skb); + return; + } + + /* fetch iface handle from header */ + mux_hdr = (struct ipa_gsb_mux_hdr *)skb->data; + /* change to host order */ + *(u32 *)mux_hdr = ntohl(*(u32 *)mux_hdr); + hdl = mux_hdr->iface_hdl; + IPA_GSB_DBG("evt: %d, hdl in tx_dp_notify: %d\n", evt, hdl); + + /* remove 4 byte mux header */ + skb_pull(skb, sizeof(struct ipa_gsb_mux_hdr)); + ipa_gsb_ctx->iface[hdl]->tx_dp_notify( + ipa_gsb_ctx->iface[hdl]->priv, evt, + (unsigned long)skb); +} + +static int ipa_gsb_connect_sys_pipe(void) +{ + struct ipa_sys_connect_params prod_params; + struct ipa_sys_connect_params cons_params; + int res; + + memset(&prod_params, 0, sizeof(prod_params)); + memset(&cons_params, 0, sizeof(cons_params)); + + /* configure RX EP */ + prod_params.client = IPA_CLIENT_ODU_PROD; + prod_params.ipa_ep_cfg.hdr.hdr_len = + ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr); + prod_params.ipa_ep_cfg.nat.nat_en = IPA_SRC_NAT; + prod_params.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1; + prod_params.ipa_ep_cfg.hdr.hdr_ofst_metadata = 0; + prod_params.desc_fifo_sz = ipa_gsb_ctx->ipa_sys_desc_size; + prod_params.priv = NULL; + prod_params.notify = ipa_gsb_tx_dp_notify; + res = ipa_setup_sys_pipe(&prod_params, + &ipa_gsb_ctx->prod_hdl); + if (res) { + IPA_GSB_ERR("fail to setup prod sys pipe %d\n", res); + goto fail_prod; + } + + /* configure TX EP */ + cons_params.client = IPA_CLIENT_ODU_EMB_CONS; + cons_params.ipa_ep_cfg.hdr.hdr_len = + ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr); + cons_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; + cons_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 2; + cons_params.ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment = 2; + cons_params.ipa_ep_cfg.hdr_ext.hdr_little_endian = true; + cons_params.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + /* setup aggregation */ + cons_params.ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR; + cons_params.ipa_ep_cfg.aggr.aggr = IPA_GENERIC; + cons_params.ipa_ep_cfg.aggr.aggr_time_limit = + IPA_GSB_AGGR_TIME_LIMIT; + cons_params.ipa_ep_cfg.aggr.aggr_byte_limit = + IPA_GSB_AGGR_BYTE_LIMIT; + cons_params.desc_fifo_sz = ipa_gsb_ctx->ipa_sys_desc_size; + cons_params.priv = NULL; + cons_params.notify = ipa_gsb_cons_cb; + res = ipa_setup_sys_pipe(&cons_params, + &ipa_gsb_ctx->cons_hdl); + if (res) { + IPA_GSB_ERR("fail to setup cons sys pipe %d\n", res); + goto fail_cons; + } + + IPA_GSB_DBG("prod_hdl = %d, cons_hdl = %d\n", + ipa_gsb_ctx->prod_hdl, ipa_gsb_ctx->cons_hdl); + + return 0; + +fail_cons: + ipa_teardown_sys_pipe(ipa_gsb_ctx->prod_hdl); + ipa_gsb_ctx->prod_hdl = 0; +fail_prod: + return res; +} + +int ipa_bridge_connect(u32 hdl) +{ + int ret; + + if (!ipa_gsb_ctx) { + IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n"); + return -EFAULT; + } + + IPA_GSB_DBG("client hdl: %d\n", hdl); + + mutex_lock(&ipa_gsb_ctx->lock); + + if (ipa_gsb_ctx->iface[hdl]->is_connected) { + IPA_GSB_DBG("iface was already connected\n"); + mutex_unlock(&ipa_gsb_ctx->lock); + return 0; + } + + if (ipa_gsb_ctx->num_connected_iface == 0) { + ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl); + if (ret) { + IPA_GSB_ERR("failed to activate ipa pm\n"); + mutex_unlock(&ipa_gsb_ctx->lock); + return ret; + } + ret = ipa_gsb_connect_sys_pipe(); + if (ret) { + IPA_GSB_ERR("fail to connect pipe\n"); + mutex_unlock(&ipa_gsb_ctx->lock); + return ret; + } + } + + /* connect = connect + resume */ + ipa_gsb_ctx->iface[hdl]->is_connected = true; + ipa_gsb_ctx->iface[hdl]->is_resumed = true; + + ipa_gsb_ctx->num_connected_iface++; + IPA_GSB_DBG("connected iface: %d\n", + ipa_gsb_ctx->num_connected_iface); + ipa_gsb_ctx->num_resumed_iface++; + IPA_GSB_DBG("num resumed iface: %d\n", + ipa_gsb_ctx->num_resumed_iface); + + mutex_unlock(&ipa_gsb_ctx->lock); + return 0; +} +EXPORT_SYMBOL(ipa_bridge_connect); + +static int ipa_gsb_disconnect_sys_pipe(void) +{ + int ret; + + IPA_GSB_DBG("prod_hdl = %d, cons_hdl = %d\n", + ipa_gsb_ctx->prod_hdl, ipa_gsb_ctx->cons_hdl); + + ret = ipa_teardown_sys_pipe(ipa_gsb_ctx->prod_hdl); + if (ret) { + IPA_GSB_ERR("failed to tear down prod pipe\n"); + return -EFAULT; + } + ipa_gsb_ctx->prod_hdl = 0; + + ret = ipa_teardown_sys_pipe(ipa_gsb_ctx->cons_hdl); + if (ret) { + IPA_GSB_ERR("failed to tear down cons pipe\n"); + return -EFAULT; + } + ipa_gsb_ctx->cons_hdl = 0; + + return 0; +} + +int ipa_bridge_disconnect(u32 hdl) +{ + int ret; + + if (!ipa_gsb_ctx) { + IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n"); + return -EFAULT; + } + + IPA_GSB_DBG("client hdl: %d\n", hdl); + + mutex_lock(&ipa_gsb_ctx->lock); + + if (!ipa_gsb_ctx->iface[hdl]->is_connected) { + IPA_GSB_DBG("iface was not connected\n"); + mutex_unlock(&ipa_gsb_ctx->lock); + return 0; + } + + if (ipa_gsb_ctx->num_connected_iface == 1) { + ret = ipa_gsb_disconnect_sys_pipe(); + if (ret) { + IPA_GSB_ERR("fail to discon pipes\n"); + mutex_unlock(&ipa_gsb_ctx->lock); + return -EFAULT; + } + + ret = ipa_pm_deactivate_sync(ipa_gsb_ctx->pm_hdl); + if (ret) { + IPA_GSB_ERR("failed to deactivate ipa pm\n"); + mutex_unlock(&ipa_gsb_ctx->lock); + return -EFAULT; + } + } + + /* disconnect = suspend + disconnect */ + ipa_gsb_ctx->iface[hdl]->is_connected = false; + ipa_gsb_ctx->num_connected_iface--; + IPA_GSB_DBG("connected iface: %d\n", + ipa_gsb_ctx->num_connected_iface); + + if (ipa_gsb_ctx->iface[hdl]->is_resumed) { + ipa_gsb_ctx->iface[hdl]->is_resumed = false; + ipa_gsb_ctx->num_resumed_iface--; + IPA_GSB_DBG("num resumed iface: %d\n", + ipa_gsb_ctx->num_resumed_iface); + } + + mutex_unlock(&ipa_gsb_ctx->lock); + return 0; +} +EXPORT_SYMBOL(ipa_bridge_disconnect); + +int ipa_bridge_resume(u32 hdl) +{ + int ret; + + if (!ipa_gsb_ctx) { + IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n"); + return -EFAULT; + } + + IPA_GSB_DBG("client hdl: %d\n", hdl); + + if (!ipa_gsb_ctx->iface[hdl]->is_connected) { + IPA_GSB_ERR("iface is not connected\n"); + return -EFAULT; + } + + if (ipa_gsb_ctx->iface[hdl]->is_resumed) { + IPA_GSB_DBG("iface was already resumed\n"); + return 0; + } + + mutex_lock(&ipa_gsb_ctx->lock); + + if (ipa_gsb_ctx->num_resumed_iface == 0) { + ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl); + if (ret) { + IPA_GSB_ERR("fail to activate ipa pm\n"); + mutex_unlock(&ipa_gsb_ctx->lock); + return ret; + } + + ret = ipa_start_gsi_channel( + ipa_gsb_ctx->cons_hdl); + if (ret) { + IPA_GSB_ERR( + "fail to start con ep %d\n", + ret); + mutex_unlock(&ipa_gsb_ctx->lock); + return ret; + } + } + + ipa_gsb_ctx->iface[hdl]->is_resumed = true; + ipa_gsb_ctx->num_resumed_iface++; + IPA_GSB_DBG("num resumed iface: %d\n", + ipa_gsb_ctx->num_resumed_iface); + + mutex_unlock(&ipa_gsb_ctx->lock); + return 0; +} +EXPORT_SYMBOL(ipa_bridge_resume); + +int ipa_bridge_suspend(u32 hdl) +{ + int ret; + + if (!ipa_gsb_ctx) { + IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n"); + return -EFAULT; + } + + IPA_GSB_DBG("client hdl: %d\n", hdl); + + if (!ipa_gsb_ctx->iface[hdl]->is_connected) { + IPA_GSB_ERR("iface is not connected\n"); + return -EFAULT; + } + + if (!ipa_gsb_ctx->iface[hdl]->is_resumed) { + IPA_GSB_DBG("iface was already suspended\n"); + return 0; + } + + mutex_lock(&ipa_gsb_ctx->lock); + + if (ipa_gsb_ctx->num_resumed_iface == 1) { + ret = ipa_stop_gsi_channel( + ipa_gsb_ctx->cons_hdl); + if (ret) { + IPA_GSB_ERR( + "fail to stop cons ep %d\n", + ret); + mutex_unlock(&ipa_gsb_ctx->lock); + return ret; + } + + ret = ipa_pm_deactivate_sync(ipa_gsb_ctx->pm_hdl); + if (ret) { + IPA_GSB_ERR("fail to deactivate ipa pm\n"); + ipa_start_gsi_channel(ipa_gsb_ctx->cons_hdl); + mutex_unlock(&ipa_gsb_ctx->lock); + return ret; + } + } + + ipa_gsb_ctx->iface[hdl]->is_resumed = false; + ipa_gsb_ctx->num_resumed_iface--; + IPA_GSB_DBG("num resumed iface: %d\n", + ipa_gsb_ctx->num_resumed_iface); + + mutex_unlock(&ipa_gsb_ctx->lock); + return 0; +} +EXPORT_SYMBOL(ipa_bridge_suspend); + +int ipa_bridge_set_perf_profile(u32 hdl, u32 bandwidth) +{ + int ret; + + IPA_GSB_DBG("client hdl: %d, BW: %d\n", hdl, bandwidth); + + mutex_lock(&ipa_gsb_ctx->lock); + + ret = ipa_pm_set_perf_profile(ipa_gsb_ctx->pm_hdl, + bandwidth); + if (ret) + IPA_GSB_ERR("fail to set perf profile\n"); + + mutex_unlock(&ipa_gsb_ctx->lock); + return ret; +} +EXPORT_SYMBOL(ipa_bridge_set_perf_profile); + +int ipa_bridge_tx_dp(u32 hdl, struct sk_buff *skb, + struct ipa_tx_meta *metadata) +{ + struct ipa_gsb_mux_hdr *mux_hdr; + struct sk_buff *skb2; + int ret; + + IPA_GSB_DBG("client hdl: %d\n", hdl); + + /* make sure skb has enough headroom */ + if (unlikely(skb_headroom(skb) < sizeof(struct ipa_gsb_mux_hdr))) { + IPA_GSB_DBG("skb doesn't have enough headroom\n"); + skb2 = skb_copy_expand(skb, sizeof(struct ipa_gsb_mux_hdr), + 0, GFP_ATOMIC); + if (!skb2) { + dev_kfree_skb_any(skb); + return -ENOMEM; + } + dev_kfree_skb_any(skb); + skb = skb2; + ipa_gsb_ctx->iface[hdl]->iface_stats. + num_insufficient_headroom_packets++; + } + + /* add 4 byte header for mux */ + mux_hdr = (struct ipa_gsb_mux_hdr *)skb_push(skb, + sizeof(struct ipa_gsb_mux_hdr)); + mux_hdr->iface_hdl = (u8)hdl; + /* change to network order */ + *(u32 *)mux_hdr = htonl(*(u32 *)mux_hdr); + + ret = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata); + if (ret) { + IPA_GSB_ERR("tx dp failed %d\n", ret); + return -EFAULT; + } + ipa_gsb_ctx->iface[hdl]->iface_stats.num_ul_packets++; + + return 0; +} +EXPORT_SYMBOL(ipa_bridge_tx_dp); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ipa gsb driver"); diff --git a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c index df546cd7fad3..32284103ec4d 100644 --- a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c +++ b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1262,385 +1262,5 @@ int odu_bridge_cleanup(void) } EXPORT_SYMBOL(odu_bridge_cleanup); -/* IPA Bridge implementation */ -#ifdef CONFIG_IPA3 - -static void ipa_br_rm_notify(void *user_data, enum ipa_rm_event event, - unsigned long data) -{ - if (event == IPA_RM_RESOURCE_GRANTED) - complete(&odu_bridge_ctx->rm_comp); -} - -static int ipa_br_request_prod(void) -{ - int res; - - ODU_BRIDGE_FUNC_ENTRY(); - - reinit_completion(&odu_bridge_ctx->rm_comp); - ODU_BRIDGE_DBG("requesting odu prod\n"); - res = ipa_rm_request_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD); - if (res) { - if (res != -EINPROGRESS) { - ODU_BRIDGE_ERR("failed to request prod %d\n", res); - return res; - } - wait_for_completion(&odu_bridge_ctx->rm_comp); - } - - ODU_BRIDGE_FUNC_EXIT(); - return 0; - -} - -static int ipa_br_release_prod(void) -{ - int res; - - ODU_BRIDGE_FUNC_ENTRY(); - - reinit_completion(&odu_bridge_ctx->rm_comp); - ODU_BRIDGE_DBG("requesting odu prod\n"); - res = ipa_rm_release_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD); - if (res) { - ODU_BRIDGE_ERR("failed to release prod %d\n", res); - return res; - } - - ODU_BRIDGE_FUNC_EXIT(); - return 0; - -} - -static int ipa_br_cons_request(void) -{ - ODU_BRIDGE_FUNC_ENTRY(); - if (odu_bridge_ctx->is_suspended) - odu_bridge_ctx->wakeup_request(odu_bridge_ctx->priv); - ODU_BRIDGE_FUNC_EXIT(); - return 0; -} - -static int ipa_br_cons_release(void) -{ - ODU_BRIDGE_FUNC_ENTRY(); - ODU_BRIDGE_FUNC_EXIT(); - return 0; -} - -static void ipa_br_pm_cb(void *p, enum ipa_pm_cb_event event) -{ - ODU_BRIDGE_FUNC_ENTRY(); - if (event != IPA_PM_REQUEST_WAKEUP) { - ODU_BRIDGE_ERR("Unexpected event %d\n", event); - WARN_ON(1); - return; - } - - if (odu_bridge_ctx->is_suspended) - odu_bridge_ctx->wakeup_request(odu_bridge_ctx->priv); - ODU_BRIDGE_FUNC_EXIT(); -} - -static int ipa_br_register_pm(void) -{ - struct ipa_pm_register_params reg_params; - int ret; - - memset(®_params, 0, sizeof(reg_params)); - reg_params.name = "ODU Bridge"; - reg_params.callback = ipa_br_pm_cb; - reg_params.group = IPA_PM_GROUP_DEFAULT; - - ret = ipa_pm_register(®_params, - &odu_bridge_ctx->pm_hdl); - if (ret) { - ODU_BRIDGE_ERR("fail to register with PM %d\n", ret); - goto fail_pm_reg; - } - - ret = ipa_pm_associate_ipa_cons_to_client(odu_bridge_ctx->pm_hdl, - IPA_CLIENT_ODU_EMB_CONS); - if (ret) { - ODU_BRIDGE_ERR("fail to associate cons with PM %d\n", ret); - goto fail_pm_cons; - } - - return 0; - -fail_pm_cons: - ipa_pm_deregister(odu_bridge_ctx->pm_hdl); - odu_bridge_ctx->pm_hdl = ~0; -fail_pm_reg: - return ret; -} - -static int ipa_br_create_rm_resources(void) -{ - int ret; - struct ipa_rm_create_params create_params; - - /* create IPA RM resources for power management */ - init_completion(&odu_bridge_ctx->rm_comp); - memset(&create_params, 0, sizeof(create_params)); - create_params.name = IPA_RM_RESOURCE_ODU_ADAPT_PROD; - create_params.reg_params.user_data = odu_bridge_ctx; - create_params.reg_params.notify_cb = ipa_br_rm_notify; - create_params.floor_voltage = IPA_VOLTAGE_SVS; - ret = ipa_rm_create_resource(&create_params); - if (ret) { - ODU_BRIDGE_ERR("failed to create RM prod %d\n", ret); - goto fail_rm_prod; - } - - ret = ipa_rm_add_dependency_sync(IPA_RM_RESOURCE_ODU_ADAPT_PROD, - IPA_RM_RESOURCE_APPS_CONS); - if (ret) { - ODU_BRIDGE_ERR("failed to add ODU->APPS dependency %d\n", ret); - goto fail_add_dep; - } - - memset(&create_params, 0, sizeof(create_params)); - create_params.name = IPA_RM_RESOURCE_ODU_ADAPT_CONS; - create_params.request_resource = ipa_br_cons_request; - create_params.release_resource = ipa_br_cons_release; - create_params.floor_voltage = IPA_VOLTAGE_SVS; - ret = ipa_rm_create_resource(&create_params); - if (ret) { - ODU_BRIDGE_ERR("failed to create RM cons %d\n", ret); - goto fail_rm_cons; - } - - return 0; - -fail_rm_cons: - ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD, - IPA_RM_RESOURCE_APPS_CONS); -fail_add_dep: - ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD); -fail_rm_prod: - return ret; -} - -/* IPA Bridge API is the new API which will replaces old odu_bridge API */ -int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl) -{ - int ret; - - if (!params || !params->wakeup_request || !hdl) { - ODU_BRIDGE_ERR("NULL arg\n"); - return -EINVAL; - } - - - ret = odu_bridge_init(¶ms->info); - if (ret) - return ret; - - odu_bridge_ctx->wakeup_request = params->wakeup_request; - - if (ipa_pm_is_used()) - ret = ipa_br_register_pm(); - else - ret = ipa_br_create_rm_resources(); - if (ret) { - ODU_BRIDGE_ERR("fail to register woth RM/PM %d\n", ret); - goto fail_pm; - } - - /* handle is ignored for now */ - *hdl = 0; - - return 0; - -fail_pm: - odu_bridge_cleanup(); - return ret; -} -EXPORT_SYMBOL(ipa_bridge_init); - -int ipa_bridge_connect(u32 hdl) -{ - int ret; - - if (!odu_bridge_ctx) { - ODU_BRIDGE_ERR("Not initialized\n"); - return -EFAULT; - } - - if (odu_bridge_ctx->is_connected) { - ODU_BRIDGE_ERR("already connected\n"); - return -EFAULT; - } - - if (ipa_pm_is_used()) - ret = ipa_pm_activate_sync(odu_bridge_ctx->pm_hdl); - else - ret = ipa_br_request_prod(); - if (ret) - return ret; - - return odu_bridge_connect(); -} -EXPORT_SYMBOL(ipa_bridge_connect); - -int ipa_bridge_set_perf_profile(u32 hdl, u32 bandwidth) -{ - struct ipa_rm_perf_profile profile = {0}; - int ret; - - if (ipa_pm_is_used()) - return ipa_pm_set_perf_profile(odu_bridge_ctx->pm_hdl, - bandwidth); - - profile.max_supported_bandwidth_mbps = bandwidth; - ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_ODU_ADAPT_PROD, &profile); - if (ret) { - ODU_BRIDGE_ERR("failed to set perf profile to prod %d\n", ret); - return ret; - } - - ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_ODU_ADAPT_CONS, &profile); - if (ret) { - ODU_BRIDGE_ERR("failed to set perf profile to cons %d\n", ret); - return ret; - } - - return 0; -} -EXPORT_SYMBOL(ipa_bridge_set_perf_profile); - -int ipa_bridge_disconnect(u32 hdl) -{ - int ret; - - ret = odu_bridge_disconnect(); - if (ret) - return ret; - - if (ipa_pm_is_used()) - ret = ipa_pm_deactivate_sync(odu_bridge_ctx->pm_hdl); - else - ret = ipa_br_release_prod(); - if (ret) - return ret; - - return 0; -} -EXPORT_SYMBOL(ipa_bridge_disconnect); - -int ipa_bridge_suspend(u32 hdl) -{ - int ret; - - if (!odu_bridge_ctx) { - ODU_BRIDGE_ERR("Not initialized\n"); - return -EFAULT; - } - - if (!odu_bridge_ctx->is_connected) { - ODU_BRIDGE_ERR("bridge is disconnected\n"); - return -EFAULT; - } - - if (odu_bridge_ctx->is_suspended) { - ODU_BRIDGE_ERR("bridge is already suspended\n"); - return -EFAULT; - } - - /* stop cons channel to prevent downlink data during suspend */ - ret = ipa_stop_gsi_channel(odu_bridge_ctx->odu_emb_cons_hdl); - if (ret) { - ODU_BRIDGE_ERR("failed to stop CONS channel %d\n", ret); - return ret; - } - - if (ipa_pm_is_used()) - ret = ipa_pm_deactivate_sync(odu_bridge_ctx->pm_hdl); - else - ret = ipa_br_release_prod(); - if (ret) { - ODU_BRIDGE_ERR("failed to release prod %d\n", ret); - ipa_start_gsi_channel(odu_bridge_ctx->odu_emb_cons_hdl); - return ret; - } - odu_bridge_ctx->is_suspended = true; - - return 0; -} -EXPORT_SYMBOL(ipa_bridge_suspend); - -int ipa_bridge_resume(u32 hdl) -{ - int ret; - - if (!odu_bridge_ctx) { - ODU_BRIDGE_ERR("Not initialized\n"); - return -EFAULT; - } - - if (!odu_bridge_ctx->is_connected) { - ODU_BRIDGE_ERR("bridge is disconnected\n"); - return -EFAULT; - } - - if (!odu_bridge_ctx->is_suspended) { - ODU_BRIDGE_ERR("bridge is not suspended\n"); - return -EFAULT; - } - - if (ipa_pm_is_used()) - ret = ipa_pm_activate_sync(odu_bridge_ctx->pm_hdl); - else - ret = ipa_br_request_prod(); - if (ret) - return ret; - - ret = ipa_start_gsi_channel(odu_bridge_ctx->odu_emb_cons_hdl); - if (ret) { - ODU_BRIDGE_ERR("failed to start CONS channel %d\n", ret); - return ret; - } - odu_bridge_ctx->is_suspended = false; - - return 0; -} -EXPORT_SYMBOL(ipa_bridge_resume); - -int ipa_bridge_tx_dp(u32 hdl, struct sk_buff *skb, - struct ipa_tx_meta *metadata) -{ - return odu_bridge_tx_dp(skb, metadata); -} -EXPORT_SYMBOL(ipa_bridge_tx_dp); - -static void ipa_br_delete_rm_resources(void) -{ - ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD, - IPA_RM_RESOURCE_APPS_CONS); - ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD); - ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_CONS); -} - -static void ipa_br_deregister_pm(void) -{ - ipa_pm_deactivate_sync(odu_bridge_ctx->pm_hdl); - ipa_pm_deregister(odu_bridge_ctx->pm_hdl); - odu_bridge_ctx->pm_hdl = ~0; -} - -int ipa_bridge_cleanup(u32 hdl) -{ - if (ipa_pm_is_used()) - ipa_br_deregister_pm(); - else - ipa_br_delete_rm_resources(); - return odu_bridge_cleanup(); -} -EXPORT_SYMBOL(ipa_bridge_cleanup); - -#endif /* CONFIG_IPA3 */ - MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("ODU bridge driver"); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 84124ab9bb6f..34f3265947ab 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -2936,7 +2936,6 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in, INIT_DELAYED_WORK(&sys->replenish_rx_work, ipa3_replenish_rx_work_func); atomic_set(&sys->curr_polling_state, 0); - sys->rx_buff_sz = IPA_ODU_RX_BUFF_SZ; sys->rx_pool_sz = in->desc_fifo_sz / IPA_FIFO_ELEMENT_SIZE - 1; if (sys->rx_pool_sz > IPA_ODU_RX_POOL_SZ) @@ -2944,8 +2943,20 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in, sys->pyld_hdlr = ipa3_odu_rx_pyld_hdlr; sys->get_skb = ipa3_get_skb_ipa_rx; sys->free_skb = ipa3_free_skb_rx; - sys->free_rx_wrapper = ipa3_free_rx_wrapper; - sys->repl_hdlr = ipa3_replenish_rx_cache; + /* recycle skb for GSB use case */ + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) { + sys->free_rx_wrapper = + ipa3_recycle_rx_wrapper; + sys->repl_hdlr = + ipa3_replenish_rx_cache_recycle; + sys->rx_buff_sz = IPA_GENERIC_RX_BUFF_SZ( + IPA_GENERIC_RX_BUFF_BASE_SZ); + } else { + sys->free_rx_wrapper = + ipa3_free_rx_wrapper; + sys->repl_hdlr = ipa3_replenish_rx_cache; + sys->rx_buff_sz = IPA_ODU_RX_BUFF_SZ; + } } else if (in->client == IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS) { IPADBG("assigning policy to client:%d", -- GitLab From b17f245bbb4b918f1f4ecd4c91595d4dca5bf5e6 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Wed, 6 Jun 2018 13:57:47 +0800 Subject: [PATCH 743/855] ARM: dts: msm: Add SDAM ramp configuration for PWM channels on PMI632 Set SDAM based ramp configurations for the PWM channels that are used for controlling RGB LEDs. The RGB LEDs can be configured to blink with various ramping patterns. Change-Id: I16c2709cedb6187901a87f6ff12342147cb5dc3f Signed-off-by: Fenglin Wu --- arch/arm64/boot/dts/qcom/pmi632.dtsi | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi index d77d55dc7de3..814d66997364 100644 --- a/arch/arm64/boot/dts/qcom/pmi632.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi @@ -527,6 +527,16 @@ compatible = "qcom,msm-bcl-soc"; #thermal-sensor-cells = <0>; }; + + pmi632_pbs_client3: qcom,pbs@7400 { + compatible = "qcom,qpnp-pbs"; + reg = <0x7400 0x100>; + }; + + pmi632_sdam7: qcom,sdam@b600 { + compatible = "qcom,spmi-sdam"; + reg = <0xb600 0x100>; + }; }; pmi632_3: qcom,pmi632@3 { @@ -547,6 +557,36 @@ reg = <0xb300 0x500>; reg-names = "lpg-base"; #pwm-cells = <2>; + nvmem-names = "ppg_sdam"; + nvmem = <&pmi632_sdam7>; + qcom,pbs-client = <&pmi632_pbs_client3>; + qcom,lut-sdam-base = <0x80>; + qcom,lut-patterns = <0 0 0 14 28 42 56 70 84 100 + 100 84 70 56 42 28 14 0 0 0>; + lpg@1 { + qcom,lpg-chan-id = <1>; + qcom,ramp-step-ms = <200>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <19>; + qcom,ramp-pattern-repeat; + qcom,lpg-sdam-base = <0x48>; + }; + lpg@2 { + qcom,lpg-chan-id = <2>; + qcom,ramp-step-ms = <200>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <19>; + qcom,ramp-pattern-repeat; + qcom,lpg-sdam-base = <0x56>; + }; + lpg@3 { + qcom,lpg-chan-id = <3>; + qcom,ramp-step-ms = <200>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <19>; + qcom,ramp-pattern-repeat; + qcom,lpg-sdam-base = <0x64>; + }; }; pmi632_rgb: qcom,leds@d000 { -- GitLab From 0161cd79c8830544f8b839b670b05cf7a9b37037 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Mon, 14 May 2018 15:02:02 +0530 Subject: [PATCH 744/855] ARM: dts: msm: Vote for bus_aggr_clk clock by eMMC and UFS on sdm710 Updated gcc_aggre_ufs_phy_axi_clk clock node in eMMC & UFS device node with corresponding voter clock node, so that both these drivers can vote for this clock. On SDM710, both eMMC & UFS drivers need gcc_aggre_ufs_phy_axi_clk for their respective functionality. So both the drivers should vote this clock to ensure this clock is enabled while driver is being accessed. Change-Id: I19df15e24f91951ae2103c18246c98a7d26e36db Signed-off-by: Veerabhadrarao Badiganti --- arch/arm64/boot/dts/qcom/sdm670.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index fbfae4d922b2..01953687f363 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -1880,7 +1880,7 @@ "rx_lane0_sync_clk"; clocks = <&clock_gcc GCC_UFS_PHY_AXI_HW_CTL_CLK>, - <&clock_gcc GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK>, + <&clock_gcc UFS_PHY_AXI_UFS_VOTE_CLK>, <&clock_gcc GCC_UFS_PHY_AHB_CLK>, <&clock_gcc GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK>, <&clock_gcc GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK>, @@ -2384,7 +2384,7 @@ clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, <&clock_gcc GCC_SDCC1_APPS_CLK>, <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>, - <&clock_gcc GCC_AGGRE_UFS_PHY_AXI_CLK>; + <&clock_gcc UFS_PHY_AXI_EMMC_VOTE_CLK>; clock-names = "iface_clk", "core_clk", "ice_core_clk", "bus_aggr_clk"; -- GitLab From 7f175ff38e56f0cc39ac9d4c80e7aeb775727a3d Mon Sep 17 00:00:00 2001 From: Vamshi Krishna B V Date: Tue, 29 May 2018 01:45:33 +0530 Subject: [PATCH 745/855] power: qpnp-qg: add support for TTF and TTE features Time to full(TTF) and Time to empty(TTE) algorithms are supported through fg-alg.c. Add the necessary initialization and callback functions to qg driver to support those algorithms. CRs-Fixed: 2254530 Change-Id: I4c400b749aa2b6fb270ab38e8a294ce69b0e20d7 Signed-off-by: Vamshi Krishna B V --- drivers/power/supply/qcom/qg-core.h | 4 + drivers/power/supply/qcom/qg-defs.h | 1 + drivers/power/supply/qcom/qpnp-qg.c | 135 ++++++++++++++++++++++++++++ include/uapi/linux/qg.h | 3 +- 4 files changed, 142 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index b2c8b892c938..e834b8e65404 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -118,6 +118,7 @@ struct qpnp_qg { bool charge_full; int charge_status; int charge_type; + int chg_iterm_ma; int next_wakeup_ms; u32 fifo_done_count; u32 wa_flags; @@ -135,6 +136,7 @@ struct qpnp_qg { int pon_soc; int batt_soc; int cc_soc; + int full_soc; struct alarm alarm_timer; u32 sdam_data[SDAM_MAX]; @@ -145,6 +147,8 @@ struct qpnp_qg { struct cap_learning *cl; /* charge counter */ struct cycle_counter *counter; + /* ttf */ + struct ttf *ttf; }; enum ocv_type { diff --git a/drivers/power/supply/qcom/qg-defs.h b/drivers/power/supply/qcom/qg-defs.h index 02a193fc3461..997ff701c77d 100644 --- a/drivers/power/supply/qcom/qg-defs.h +++ b/drivers/power/supply/qcom/qg-defs.h @@ -34,6 +34,7 @@ #define GOOD_OCV_VOTER "GOOD_OCV_VOTER" #define PROFILE_IRQ_DISABLE "NO_PROFILE_IRQ_DISABLE" #define QG_INIT_STATE_IRQ_DISABLE "QG_INIT_STATE_IRQ_DISABLE" +#define TTF_AWAKE_VOTER "TTF_AWAKE_VOTER" #define V_RAW_TO_UV(V_RAW) div_u64(194637ULL * (u64)V_RAW, 1000) #define I_RAW_TO_UA(I_RAW) div_s64(152588LL * (s64)I_RAW, 1000) diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 0ee5c302b462..a8a7826ad8ae 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -221,6 +221,14 @@ static void qg_notify_charger(struct qpnp_qg *chip) } pr_debug("Notified charger on float voltage and FCC\n"); + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, &prop); + if (rc < 0) { + pr_err("Failed to get charge term current, rc=%d\n", rc); + return; + } + chip->chg_iterm_ma = prop.intval; } static bool is_batt_available(struct qpnp_qg *chip) @@ -1014,6 +1022,9 @@ static void process_udata_work(struct work_struct *work) if (chip->udata.param[QG_BATT_SOC].valid) chip->batt_soc = chip->udata.param[QG_BATT_SOC].data; + if (chip->udata.param[QG_FULL_SOC].valid) + chip->full_soc = chip->udata.param[QG_FULL_SOC].data; + if (chip->udata.param[QG_SOC].valid) { qg_dbg(chip, QG_DEBUG_SOC, "udata SOC=%d last SOC=%d\n", chip->udata.param[QG_SOC].data, chip->catch_up_soc); @@ -1044,6 +1055,8 @@ static void process_udata_work(struct work_struct *work) if (!chip->dt.esr_disable) qg_store_esr_params(chip); + qg_dbg(chip, QG_DEBUG_STATUS, "udata update: batt_soc=%d cc_soc=%d full_soc=%d qg_esr=%d\n", + chip->batt_soc, chip->cc_soc, chip->full_soc, chip->esr_last); vote(chip->awake_votable, UDATA_READY_VOTER, false, 0); } @@ -1570,6 +1583,87 @@ static int qg_get_battery_capacity(struct qpnp_qg *chip, int *soc) return 0; } +static int qg_get_ttf_param(void *data, enum ttf_param param, int *val) +{ + union power_supply_propval prop = {0, }; + struct qpnp_qg *chip = data; + int rc = 0; + int64_t temp = 0; + + if (!chip) + return -ENODEV; + + if (chip->battery_missing || !chip->profile_loaded) + return -EPERM; + + switch (param) { + case TTF_MSOC: + rc = qg_get_battery_capacity(chip, val); + break; + case TTF_VBAT: + rc = qg_get_battery_voltage(chip, val); + break; + case TTF_IBAT: + rc = qg_get_battery_current(chip, val); + break; + case TTF_FCC: + if (chip->qg_psy) { + rc = power_supply_get_property(chip->qg_psy, + POWER_SUPPLY_PROP_CHARGE_FULL, &prop); + if (rc >= 0) { + temp = div64_u64(prop.intval, 1000); + *val = div64_u64(chip->full_soc * temp, + QG_SOC_FULL); + } + } + break; + case TTF_MODE: + *val = TTF_MODE_NORMAL; + break; + case TTF_ITERM: + if (chip->chg_iterm_ma == INT_MIN) + *val = 0; + else + *val = chip->chg_iterm_ma; + break; + case TTF_RBATT: + rc = qg_sdam_read(SDAM_RBAT_MOHM, val); + if (!rc) + *val *= 1000; + break; + case TTF_VFLOAT: + *val = chip->bp.float_volt_uv; + break; + case TTF_CHG_TYPE: + *val = chip->charge_type; + break; + case TTF_CHG_STATUS: + *val = chip->charge_status; + break; + default: + pr_err("Unsupported property %d\n", param); + rc = -EINVAL; + break; + } + + return rc; +} + +static int qg_ttf_awake_voter(void *data, bool val) +{ + struct qpnp_qg *chip = data; + + if (!chip) + return -ENODEV; + + if (chip->battery_missing || !chip->profile_loaded) + return -EPERM; + + vote(chip->awake_votable, TTF_AWAKE_VOTER, val, 0); + + return 0; +} + static int qg_psy_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *pval) @@ -1685,6 +1779,12 @@ static int qg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CYCLE_COUNT: rc = get_cycle_count(chip->counter, &pval->intval); break; + case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: + rc = ttf_get_time_to_full(chip->ttf, &pval->intval); + break; + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: + rc = ttf_get_time_to_empty(chip->ttf, &pval->intval); + break; default: pr_debug("Unsupported property %d\n", psp); break; @@ -1726,6 +1826,8 @@ static enum power_supply_property qg_psy_props[] = { POWER_SUPPLY_PROP_CYCLE_COUNTS, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, }; static const struct power_supply_desc qg_psy_desc = { @@ -1912,6 +2014,8 @@ static void qg_status_change_work(struct work_struct *work) rc = qg_charge_full_update(chip); if (rc < 0) pr_err("Failed in charge_full_update, rc=%d\n", rc); + + ttf_update(chip->ttf, chip->usb_present); out: pm_relax(chip->dev); } @@ -2688,10 +2792,12 @@ static int qg_request_irqs(struct qpnp_qg *chip) return 0; } +#define QG_TTF_ITERM_DELTA_MA 1 static int qg_alg_init(struct qpnp_qg *chip) { struct cycle_counter *counter; struct cap_learning *cl; + struct ttf *ttf; struct device_node *node = chip->dev->of_node; int rc; @@ -2714,6 +2820,28 @@ static int qg_alg_init(struct qpnp_qg *chip) chip->counter = counter; + ttf = devm_kzalloc(chip->dev, sizeof(*ttf), GFP_KERNEL); + if (!ttf) + return -ENOMEM; + + ttf->get_ttf_param = qg_get_ttf_param; + ttf->awake_voter = qg_ttf_awake_voter; + ttf->iterm_delta = QG_TTF_ITERM_DELTA_MA; + ttf->data = chip; + + rc = ttf_tte_init(ttf); + if (rc < 0) { + dev_err(chip->dev, "Error in initializing ttf, rc:%d\n", + rc); + ttf->data = NULL; + counter->data = NULL; + devm_kfree(chip->dev, ttf); + devm_kfree(chip->dev, counter); + return rc; + } + + chip->ttf = ttf; + chip->dt.cl_disable = of_property_read_bool(node, "qcom,cl-disable"); @@ -2738,6 +2866,7 @@ static int qg_alg_init(struct qpnp_qg *chip) counter->data = NULL; cl->data = NULL; devm_kfree(chip->dev, counter); + devm_kfree(chip->dev, ttf); devm_kfree(chip->dev, cl); return rc; } @@ -3064,6 +3193,7 @@ static int process_suspend(struct qpnp_qg *chip) if (!chip->profile_loaded) return 0; + cancel_delayed_work_sync(&chip->ttf->ttf_work); /* disable GOOD_OCV IRQ in sleep */ vote(chip->good_ocv_irq_disable_votable, QG_INIT_STATE_IRQ_DISABLE, true, 0); @@ -3196,6 +3326,8 @@ static int process_resume(struct qpnp_qg *chip) chip->suspend_data = false; } + schedule_delayed_work(&chip->ttf->ttf_work, 0); + return rc; } @@ -3273,6 +3405,8 @@ static int qpnp_qg_probe(struct platform_device *pdev) chip->maint_soc = -EINVAL; chip->batt_soc = INT_MIN; chip->cc_soc = INT_MIN; + chip->full_soc = QG_SOC_FULL; + chip->chg_iterm_ma = INT_MIN; rc = qg_alg_init(chip); if (rc < 0) { @@ -3338,6 +3472,7 @@ static int qpnp_qg_probe(struct platform_device *pdev) pr_err("Error in restoring cycle_count, rc=%d\n", rc); return rc; } + schedule_delayed_work(&chip->ttf->ttf_work, 10000); } rc = qg_determine_pon_soc(chip); diff --git a/include/uapi/linux/qg.h b/include/uapi/linux/qg.h index d338db9d8786..2194e1f1ac27 100644 --- a/include/uapi/linux/qg.h +++ b/include/uapi/linux/qg.h @@ -18,7 +18,7 @@ enum qg { QG_ESR_DISCHARGE_DELTA, QG_ESR_CHARGE_SF, QG_ESR_DISCHARGE_SF, - QG_RESERVED_7, + QG_FULL_SOC, QG_RESERVED_8, QG_RESERVED_9, QG_RESERVED_10, @@ -31,6 +31,7 @@ enum qg { #define QG_ESR_DISCHARGE_DELTA QG_ESR_DISCHARGE_DELTA #define QG_ESR_CHARGE_SF QG_ESR_CHARGE_SF #define QG_ESR_DISCHARGE_SF QG_ESR_DISCHARGE_SF +#define QG_FULL_SOC QG_FULL_SOC struct fifo_data { unsigned int v; -- GitLab From 108561ee7acf1942ebef0049e8f62593e1c47de9 Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Mon, 4 Jun 2018 16:28:12 +0530 Subject: [PATCH 746/855] soc: qcom: socinfo: add support for sxr1130 Add support for getting soc-id and dummy handle on sxr1130. Change-Id: I92ae715e6a3030123cca4cc7e5ea6d0f4e19e72b Signed-off-by: Kaushal Kumar --- drivers/soc/qcom/socinfo.c | 7 +++++++ include/soc/qcom/socinfo.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index e02bf8409088..1ac30ebc3cee 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -593,6 +593,9 @@ static struct msm_soc_info cpu_of_id[] = { /* QCS605 ID */ [347] = {MSM_CPU_QCS605, "QCS605"}, + /* SXR1130 ID */ + [371] = {MSM_CPU_SXR1130, "SXR1130"}, + /* SDA670 ID */ [337] = {MSM_CPU_SDA670, "SDA670"}, @@ -1532,6 +1535,10 @@ static void * __init setup_dummy_socinfo(void) dummy_socinfo.id = 336; strlcpy(dummy_socinfo.build_id, "sdm670 - ", sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_sxr1130()) { + dummy_socinfo.id = 371; + strlcpy(dummy_socinfo.build_id, "sxr1130 - ", + sizeof(dummy_socinfo.build_id)); } else if (early_machine_is_sdm710()) { dummy_socinfo.id = 360; strlcpy(dummy_socinfo.build_id, "sdm710 - ", diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h index 5f496a8a39a8..e7d42ce689e9 100644 --- a/include/soc/qcom/socinfo.h +++ b/include/soc/qcom/socinfo.h @@ -102,6 +102,8 @@ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm845") #define early_machine_is_sdm670() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm670") +#define early_machine_is_sxr1130() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sxr1130") #define early_machine_is_qcs605() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,qcs605") #define early_machine_is_sda670() \ @@ -169,6 +171,7 @@ #define early_machine_is_sdxpoorwills() 0 #define early_machine_is_sdm845() 0 #define early_machine_is_sdm670() 0 +#define early_machine_is_sxr1130() 0 #define early_machine_is_qcs605() 0 #define early_machine_is_sda670() 0 #define early_machine_is_sdm710() 0 @@ -243,6 +246,7 @@ enum msm_cpu { SDX_CPU_SDXPOORWILLS, MSM_CPU_SDM845, MSM_CPU_SDM670, + MSM_CPU_SXR1130, MSM_CPU_QCS605, MSM_CPU_SDA670, MSM_CPU_SDM710, -- GitLab From 6d5f0ae149dece6c593e6b98af28a39d3a53383c Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Tue, 29 May 2018 20:46:30 +0530 Subject: [PATCH 747/855] ARM: dts: msm: Update SDC1 lines sleep configuration for 8909w BG Configure SDC1 pins to no-pull & active low during sleep. Otherwise these gpios are causing leakage on 8909w BG platforms. Change-Id: I7db80667d41de006cfe3c0e56e517ba4889da995 Signed-off-by: Sundara Vinayagam --- .../boot/dts/qcom/msm8909w-bg-wtp-v2.dts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts index 6f61dd4832ba..3a420170d99e 100644 --- a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts @@ -243,6 +243,33 @@ status = "disabled"; }; +&sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +&sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +&sdc1_data_off { + config { + pins = "sdc1_data"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + &sdhc_2 { status = "disabled"; }; -- GitLab From b67336e16b766311562ff0fcaacae668092034c4 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Tue, 8 Aug 2017 18:56:03 +0530 Subject: [PATCH 748/855] msm: ADSPRPC: Use msm_ion_do_cache_op to flush userspace buffers Remove the use of dmac_flush_range for userspace buffers and add msm_ion_do_cache_op for flushing user space buffers. Change-Id: Ice73eafac840bd1cabee0a2bfc8a641832a7d0c8 Acked-by: Bharath Kumar Signed-off-by: Tharun Kumar Merugu --- drivers/char/adsprpc.c | 54 +++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 7d8605bfeb84..d52c80c5449a 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1567,9 +1567,18 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) if (map && (map->attr & FASTRPC_ATTR_COHERENT)) continue; - if (rpra && rpra[i].buf.len && ctx->overps[oix]->mstart) - dmac_flush_range(uint64_to_ptr(rpra[i].buf.pv), - uint64_to_ptr(rpra[i].buf.pv + rpra[i].buf.len)); + if (rpra && rpra[i].buf.len && ctx->overps[oix]->mstart) { + if (map && map->handle) + msm_ion_do_cache_op(ctx->fl->apps->client, + map->handle, + uint64_to_ptr(rpra[i].buf.pv), + rpra[i].buf.len, + ION_IOC_CLEAN_INV_CACHES); + else + dmac_flush_range(uint64_to_ptr(rpra[i].buf.pv), + uint64_to_ptr(rpra[i].buf.pv + + rpra[i].buf.len)); + } } PERF_END); for (i = bufs; rpra && i < bufs + handles; i++) { @@ -1578,11 +1587,6 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) rpra[i].dma.offset = (uint32_t)(uintptr_t)lpra[i].buf.pv; } - if (!ctx->fl->sctx->smmu.coherent) { - PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_FLUSH), - dmac_flush_range((char *)rpra, (char *)rpra + ctx->used); - PERF_END); - } bail: return err; } @@ -1671,14 +1675,33 @@ static void inv_args_pre(struct smq_invoke_ctx *ctx) if (buf_page_start(ptr_to_uint64((void *)rpra)) == buf_page_start(rpra[i].buf.pv)) continue; - if (!IS_CACHE_ALIGNED((uintptr_t)uint64_to_ptr(rpra[i].buf.pv))) - dmac_flush_range(uint64_to_ptr(rpra[i].buf.pv), - (char *)(uint64_to_ptr(rpra[i].buf.pv + 1))); + if (!IS_CACHE_ALIGNED((uintptr_t) + uint64_to_ptr(rpra[i].buf.pv))) { + if (map && map->handle) + msm_ion_do_cache_op(ctx->fl->apps->client, + map->handle, + uint64_to_ptr(rpra[i].buf.pv), + sizeof(uintptr_t), + ION_IOC_CLEAN_INV_CACHES); + else + dmac_flush_range( + uint64_to_ptr(rpra[i].buf.pv), (char *) + uint64_to_ptr(rpra[i].buf.pv + 1)); + } + end = (uintptr_t)uint64_to_ptr(rpra[i].buf.pv + rpra[i].buf.len); - if (!IS_CACHE_ALIGNED(end)) - dmac_flush_range((char *)end, - (char *)end + 1); + if (!IS_CACHE_ALIGNED(end)) { + if (map && map->handle) + msm_ion_do_cache_op(ctx->fl->apps->client, + map->handle, + uint64_to_ptr(end), + sizeof(uintptr_t), + ION_IOC_CLEAN_INV_CACHES); + else + dmac_flush_range((char *)end, + (char *)end + 1); + } } } @@ -1687,7 +1710,6 @@ static void inv_args(struct smq_invoke_ctx *ctx) int i, inbufs, outbufs; uint32_t sc = ctx->sc; remote_arg64_t *rpra = ctx->rpra; - int used = ctx->used; inbufs = REMOTE_SCALARS_INBUFS(sc); outbufs = REMOTE_SCALARS_OUTBUFS(sc); @@ -1718,8 +1740,6 @@ static void inv_args(struct smq_invoke_ctx *ctx) + rpra[i].buf.len)); } - if (rpra) - dmac_inv_range(rpra, (char *)rpra + used); } static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx, -- GitLab From b2057fdf97800c7abe046c3f22d5763370863aba Mon Sep 17 00:00:00 2001 From: Dhoat Harpal Date: Wed, 23 May 2018 20:14:10 +0530 Subject: [PATCH 749/855] soc: qcom: glink: Move tx_info to pending list after tx Glink add tx_info to pending remote done even before actual tx. Therefore tx_info will exist in two lists simultaneously, that leads to use after free when purge intent list put reference from both the lists. Move tx_info to pending remote done list only after actual tx. CRs-Fixed: 2244774 Change-Id: Iabf0e0635a7d0b25928d12d37cbfb37d70ba2806 Signed-off-by: Dhoat Harpal --- drivers/soc/qcom/glink.c | 41 +++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c index b8deec19ff8b..c976f1711a37 100644 --- a/drivers/soc/qcom/glink.c +++ b/drivers/soc/qcom/glink.c @@ -1775,6 +1775,18 @@ struct glink_core_tx_pkt *ch_get_tx_pending_remote_done( return tx_pkt; } } + list_for_each_entry(tx_pkt, &ctx->tx_active, list_node) { + if (tx_pkt->riid == riid) { + if (tx_pkt->size_remaining) { + GLINK_ERR_CH(ctx, "%s: R[%u] TX not complete", + __func__, riid); + tx_pkt = NULL; + } + spin_unlock_irqrestore( + &ctx->tx_pending_rmt_done_lock_lhc4, flags); + return tx_pkt; + } + } spin_unlock_irqrestore(&ctx->tx_pending_rmt_done_lock_lhc4, flags); GLINK_ERR_CH(ctx, "%s: R[%u] Tx packet for intent not found.\n", @@ -1817,6 +1829,20 @@ void ch_remove_tx_pending_remote_done(struct channel_ctx *ctx, return; } } + list_for_each_entry_safe(local_tx_pkt, tmp_tx_pkt, + &ctx->tx_active, list_node) { + if (tx_pkt == local_tx_pkt) { + list_del_init(&tx_pkt->list_done); + GLINK_DBG_CH(ctx, + "%s: R[%u] Removed Tx packet for intent\n", + __func__, + tx_pkt->riid); + rwref_put(&tx_pkt->pkt_ref); + spin_unlock_irqrestore( + &ctx->tx_pending_rmt_done_lock_lhc4, flags); + return; + } + } spin_unlock_irqrestore(&ctx->tx_pending_rmt_done_lock_lhc4, flags); GLINK_ERR_CH(ctx, "%s: R[%u] Tx packet for intent not found", __func__, @@ -5578,12 +5604,6 @@ static int glink_scheduler_tx(struct channel_ctx *ctx, tx_info = list_first_entry(&ctx->tx_active, struct glink_core_tx_pkt, list_node); rwref_get(&tx_info->pkt_ref); - - spin_lock(&ctx->tx_pending_rmt_done_lock_lhc4); - if (list_empty(&tx_info->list_done)) - list_add(&tx_info->list_done, - &ctx->tx_pending_remote_done); - spin_unlock(&ctx->tx_pending_rmt_done_lock_lhc4); spin_unlock_irqrestore(&ctx->tx_lists_lock_lhc3, flags); if (unlikely(tx_info->tracer_pkt)) { @@ -5648,9 +5668,16 @@ static int glink_scheduler_tx(struct channel_ctx *ctx, txd_len += tx_len; if (!tx_info->size_remaining) { num_pkts++; + spin_lock(&ctx->tx_pending_rmt_done_lock_lhc4); list_del_init(&tx_info->list_node); + if (list_empty(&tx_info->list_done)) + list_add(&tx_info->list_done, + &ctx->tx_pending_remote_done); + rwref_put(&tx_info->pkt_ref); + spin_unlock(&ctx->tx_pending_rmt_done_lock_lhc4); + } else { + rwref_put(&tx_info->pkt_ref); } - rwref_put(&tx_info->pkt_ref); } ctx->txd_len += txd_len; -- GitLab From b22ef4ef1e8c7bbdfde6a7581d0834cc3e62c8c8 Mon Sep 17 00:00:00 2001 From: Dhoat Harpal Date: Thu, 24 May 2018 14:09:06 +0530 Subject: [PATCH 750/855] soc: qcom: glink_smem_native_xprt: Reset in_ssr in subsys_up Glink smem xprt is resetting in_ssr only if rx_fifo is initialized. This can lead to in_ssr is never set to false if rx_fifo is not initialized by remote side in time. Reset in_ssr in subsys_up before checking rx_fifo. CRs-Fixed: 2248066 Change-Id: I23c7fb101c1737a1fc2319750103c37a5fdd6e90 Signed-off-by: Dhoat Harpal --- drivers/soc/qcom/glink_smem_native_xprt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index ca9953a9467e..5640666b3cea 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.c @@ -949,6 +949,12 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx) return; } + if (!einfo->rx_fifo) { + if (!get_rx_fifo(einfo)) + return; + einfo->xprt_if.glink_core_if_ptr->link_up(&einfo->xprt_if); + } + if ((atomic_ctx) && ((einfo->tx_resume_needed) || (waitqueue_active(&einfo->tx_blocked_queue)))) /* tx waiting ?*/ tx_wakeup_worker(einfo); @@ -1554,10 +1560,10 @@ static void subsys_up(struct glink_transport_if *if_ptr) struct edge_info *einfo; einfo = container_of(if_ptr, struct edge_info, xprt_if); + einfo->in_ssr = false; if (!einfo->rx_fifo) { if (!get_rx_fifo(einfo)) return; - einfo->in_ssr = false; einfo->xprt_if.glink_core_if_ptr->link_up(&einfo->xprt_if); } } -- GitLab From cfd0ce48b29904489edfc1084a3ea0d01efc247d Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Thu, 7 Jun 2018 18:25:18 +0530 Subject: [PATCH 751/855] qcom: smb-lib: fix adapter allowance for PMI632 PMI632 only supports VBUS voltage upto 9V, add support to limit adapter allowance to maximum 9V for PMI632. Change-Id: I6604fd50957287aef5e8570e66e370cb95bcbca3 Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/smb5-lib.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 9f395619092e..5c345ae8e7a4 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -472,6 +472,23 @@ static int smblib_set_adapter_allowance(struct smb_charger *chg, { int rc = 0; + /* PMI632 only support max. 9V */ + if (chg->smb_version == PMI632_SUBTYPE) { + switch (allowed_voltage) { + case USBIN_ADAPTER_ALLOW_12V: + case USBIN_ADAPTER_ALLOW_9V_TO_12V: + allowed_voltage = USBIN_ADAPTER_ALLOW_9V; + break; + case USBIN_ADAPTER_ALLOW_5V_OR_12V: + case USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V: + allowed_voltage = USBIN_ADAPTER_ALLOW_5V_OR_9V; + break; + case USBIN_ADAPTER_ALLOW_5V_TO_12V: + allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V; + break; + } + } + rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, allowed_voltage); if (rc < 0) { smblib_err(chg, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n", -- GitLab From ca49e6471cab7812f6adbefc7fe551333b95ff3c Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Mon, 4 Jun 2018 15:24:59 +0530 Subject: [PATCH 752/855] defconfig: Enable EHSET Test Fixture device driver for sdxpoorwills Enable required EHSET Test fixture driver to perform the high speed electrical testing procedure for USB-IF compliance for sdx24. Change-Id: Ib5b0936c524ee5ea46da9e9d451bbc02f8522783 Signed-off-by: Chandana Kishori Chiluveru --- arch/arm/configs/sdxpoorwills_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig index d86bc52e00aa..065ec6db4401 100644 --- a/arch/arm/configs/sdxpoorwills_defconfig +++ b/arch/arm/configs/sdxpoorwills_defconfig @@ -297,6 +297,7 @@ CONFIG_USB_STORAGE_KARMA=y CONFIG_USB_STORAGE_CYPRESS_ATACB=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y +CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_MSM_SSPHY_QMP=y CONFIG_MSM_HSUSB_PHY=y -- GitLab From 4ca21c12a538fc85c7d2a704e3732cc330a8618e Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Fri, 30 Jun 2017 23:22:18 +0530 Subject: [PATCH 753/855] usb: dwc3-msm: Add sysfs node to enable SS host compliance xHCI specs revision 1.1 mentions that if Compliance Transition Capability (CTC) flag is set, then xHC supports software control of the transition to Compliance mode. For this, we need to write a value of 10 to Port Link State(PLS) field of PORTSC register during dwc3_otg_start_host time after the xhci platform device has been added. Then the link transitions to compliance state on detection of first LFPS timeout. Steps to enable compliance transition: 1. Do not connect host cable 2. echo y > /sys/devices/platform/a600000.ssusb/xhci_link_compliance 3. Connect host cable with breakout fixture and start testing Steps to disable compliance transition: 1. Disconnect the host cable 2. echo n > /sys/devices/platform/a600000.ssusb/xhci_link_compliance 3. Connect host cable Change-Id: I73225ccad105414d3ebd60f95138b9ecf65005d4 Signed-off-by: Ajay Agarwal Signed-off-by: Chandana Kishori Chiluveru --- drivers/usb/dwc3/dwc3-msm.c | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index bb1aec7a09bb..bf1baf6f344f 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -73,6 +73,8 @@ MODULE_PARM_DESC(cpu_to_affin, "affin usb irq to this cpu"); /* XHCI registers */ #define USB3_HCSPARAMS1 (0x4) +#define USB3_HCCPARAMS2 (0x1c) +#define HCC_CTC(p) ((p) & (1 << 3)) #define USB3_PORTSC (0x420) /** @@ -255,6 +257,7 @@ struct dwc3_msm { struct notifier_block host_restart_nb; struct notifier_block host_nb; + bool xhci_ss_compliance_enable; atomic_t in_p3; unsigned int lpm_to_suspend_delay; @@ -3286,6 +3289,35 @@ static ssize_t usb_compliance_mode_store(struct device *dev, static DEVICE_ATTR_RW(usb_compliance_mode); +static ssize_t xhci_link_compliance_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + + if (mdwc->xhci_ss_compliance_enable) + return snprintf(buf, PAGE_SIZE, "y\n"); + else + return snprintf(buf, PAGE_SIZE, "n\n"); +} + +static ssize_t xhci_link_compliance_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + bool value; + int ret; + + ret = strtobool(buf, &value); + if (!ret) { + mdwc->xhci_ss_compliance_enable = value; + return count; + } + + return ret; +} + +static DEVICE_ATTR_RW(xhci_link_compliance); + static int dwc3_msm_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node, *dwc3_node; @@ -3643,6 +3675,7 @@ static int dwc3_msm_probe(struct platform_device *pdev) device_create_file(&pdev->dev, &dev_attr_mode); device_create_file(&pdev->dev, &dev_attr_speed); device_create_file(&pdev->dev, &dev_attr_usb_compliance_mode); + device_create_file(&pdev->dev, &dev_attr_xhci_link_compliance); host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST; if (!dwc->is_drd && host_mode) { @@ -3681,6 +3714,7 @@ static int dwc3_msm_remove(struct platform_device *pdev) int ret_pm; device_remove_file(&pdev->dev, &dev_attr_mode); + device_remove_file(&pdev->dev, &dev_attr_xhci_link_compliance); if (mdwc->usb_psy) power_supply_put(mdwc->usb_psy); @@ -3946,6 +3980,25 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) return ret; } + /* + * If the Compliance Transition Capability(CTC) flag of + * HCCPARAMS2 register is set and xhci_link_compliance sysfs + * param has been enabled by the user for the SuperSpeed host + * controller, then write 10 (Link in Compliance Mode State) + * onto the Port Link State(PLS) field of the PORTSC register + * for 3.0 host controller which is at an offset of USB3_PORTSC + * + 0x10 from the DWC3 base address. Also, disable the runtime + * PM of 3.0 root hub (root hub of shared_hcd of xhci device) + */ + if (HCC_CTC(dwc3_msm_read_reg(mdwc->base, USB3_HCCPARAMS2)) + && mdwc->xhci_ss_compliance_enable + && dwc->maximum_speed == USB_SPEED_SUPER) { + dwc3_msm_write_reg(mdwc->base, USB3_PORTSC + 0x10, + 0x10340); + pm_runtime_disable(&hcd_to_xhci(platform_get_drvdata( + dwc->xhci))->shared_hcd->self.root_hub->dev); + } + /* * In some cases it is observed that USB PHY is not going into * suspend with host mode suspend functionality. Hence disable -- GitLab From b2b06feb17f96562f745dd96b4d6e0901a675f91 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Thu, 7 Jun 2018 18:35:21 +0530 Subject: [PATCH 754/855] power: smb5: initialize OTG current configuration Update OTG current limit configuration during hardware initialization. Change-Id: I18084e96e9557e0291dd0fc681c755e44a4ad5c7 Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/qpnp-smb5.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 65a74c7c143a..e095eb0e7ea7 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -267,6 +267,7 @@ static int smb5_chg_config_init(struct smb5 *chip) } #define MICRO_1P5A 1500000 +#define MICRO_1PA 1000000 #define MICRO_P1A 100000 #define OTG_DEFAULT_DEGLITCH_TIME_MS 50 #define MIN_WD_BARK_TIME 16 @@ -317,7 +318,8 @@ static int smb5_parse_dt(struct smb5 *chip) rc = of_property_read_u32(node, "qcom,otg-cl-ua", &chg->otg_cl_ua); if (rc < 0) - chg->otg_cl_ua = MICRO_1P5A; + chg->otg_cl_ua = (chip->chg.smb_version == PMI632_SUBTYPE) ? + MICRO_1PA : MICRO_1P5A; if (of_find_property(node, "qcom,thermal-mitigation", &byte_len)) { chg->thermal_mitigation = devm_kzalloc(chg->dev, byte_len, @@ -1623,6 +1625,13 @@ static int smb5_init_hw(struct smb5 *chip) return rc; } + /* set OTG current limit */ + rc = smblib_set_charge_param(chg, &chg->param.otg_cl, chg->otg_cl_ua); + if (rc < 0) { + pr_err("Couldn't set otg current limit rc=%d\n", rc); + return rc; + } + /* vote 0mA on usb_icl for non battery platforms */ vote(chg->usb_icl_votable, DEFAULT_VOTER, chip->dt.no_battery, 0); @@ -2386,16 +2395,16 @@ static int smb5_probe(struct platform_device *pdev) return -EINVAL; } - rc = smb5_parse_dt(chip); + rc = smb5_chg_config_init(chip); if (rc < 0) { - pr_err("Couldn't parse device tree rc=%d\n", rc); + if (rc != -EPROBE_DEFER) + pr_err("Couldn't setup chg_config rc=%d\n", rc); return rc; } - rc = smb5_chg_config_init(chip); + rc = smb5_parse_dt(chip); if (rc < 0) { - if (rc != -EPROBE_DEFER) - pr_err("Couldn't setup chg_config rc=%d\n", rc); + pr_err("Couldn't parse device tree rc=%d\n", rc); return rc; } -- GitLab From 367bdf3d2be424092be889d320ca523939bfad9e Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Mon, 4 Jun 2018 20:46:07 -0700 Subject: [PATCH 755/855] drm/msm/sde: fix feature enable check for CWB support Fix the Concurrent Writeback feature enabled validation to check if CWB feature bit set in the Writeback feature flag. Change-Id: Iffd3167b500edaa3c3338094eadcdc08606ff5c1 Signed-off-by: Prabhanjan Kandula --- drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c index bad608de9772..82dd64abe66c 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c @@ -462,7 +462,7 @@ static void _sde_enc_phys_wb_detect_cwb(struct sde_encoder_phys *phys_enc, phys_enc->in_clone_mode = false; /* Check if WB has CWB support */ - if (!(wb_cfg->features & SDE_WB_HAS_CWB)) + if (!(wb_cfg->features & BIT(SDE_WB_HAS_CWB))) return; /* Count the number of connectors on the given crtc */ -- GitLab From 87a86127ed6ad875d141832d3d1569b4847f95ca Mon Sep 17 00:00:00 2001 From: Mohan Pallaka Date: Mon, 23 Feb 2015 16:41:47 -0800 Subject: [PATCH 756/855] leds: led-class: add support for max_brightness store Add store interface for max_brightness to allow users to change the maximum brightness to be supported by the hardware. Change-Id: I8b65debdc52ded24227483c4db21aaec63e27927 Signed-off-by: Mohan Pallaka Signed-off-by: Manaf Meethalavalappu Pallikunhi --- drivers/leds/led-class.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 8cb32654f2b6..4dd225ce9b7d 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -71,7 +71,24 @@ static ssize_t max_brightness_show(struct device *dev, return sprintf(buf, "%u\n", led_cdev->max_brightness); } -static DEVICE_ATTR_RO(max_brightness); + +static ssize_t max_brightness_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + unsigned long state; + ssize_t ret = -EINVAL; + + ret = kstrtoul(buf, 10, &state); + if (ret) + return ret; + + led_cdev->max_brightness = state; + led_set_brightness(led_cdev, led_cdev->brightness); + + return size; +} +static DEVICE_ATTR_RW(max_brightness); #ifdef CONFIG_LEDS_TRIGGERS static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store); -- GitLab From a1dbc9e820488a24d0f0bc050f80d723675aadfc Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Fri, 25 May 2018 15:50:14 +0530 Subject: [PATCH 757/855] usb: f_gsi: Report Function Remote Wake capabilities Add support for sending Function Wake capabilities in response to GET_STATUS from the host. GET_STATUS addressed to an Interface allows the device to report if it is capable of doing a Function Remote Wake. Windows8/10 MBIM hosts request this information before enabling Suspend in SS mode. Change-Id: Ic0a6db57b2b46804a82847de511feb433a3dfca6 Signed-off-by: Devdutt Patnaik Signed-off-by: Chandana Kishori Chiluveru --- drivers/usb/dwc3/ep0.c | 10 +++++++++- drivers/usb/gadget/function/f_gsi.c | 9 +++++++++ include/linux/usb/composite.h | 3 +++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 902d36e665bb..d9baac65bd0a 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -43,6 +43,8 @@ MODULE_PARM_DESC(enable_dwc3_u1u2, "Enable support for U1U2 low power modes"); static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req); +static int dwc3_ep0_delegate_req(struct dwc3 *dwc, + struct usb_ctrlrequest *ctrl); static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) { @@ -358,12 +360,14 @@ static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req) { } + /* * ch 9.4.5 */ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { + int ret; struct dwc3_ep *dep; u32 recip; u32 reg; @@ -397,7 +401,8 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, * Function Remote Wake Capable D0 * Function Remote Wakeup D1 */ - break; + ret = dwc3_ep0_delegate_req(dwc, ctrl); + return ret; case USB_RECIP_ENDPOINT: dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); @@ -524,6 +529,9 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, if (wIndex & USB_INTRF_FUNC_SUSPEND_RW) /* XXX enable remote wakeup */ ; + ret = dwc3_ep0_delegate_req(dwc, ctrl); + if (ret) + return ret; break; default: return -EINVAL; diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index d3799e599ad5..454723d29fad 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -2537,6 +2537,14 @@ static void gsi_resume(struct usb_function *f) log_event_dbg("%s: completed", __func__); } +static int gsi_get_status(struct usb_function *f) +{ + unsigned int remote_wakeup_en_status = f->func_wakeup_allowed ? 1 : 0; + + return (remote_wakeup_en_status << FUNC_WAKEUP_ENABLE_SHIFT) | + (1 << FUNC_WAKEUP_CAPABLE_SHIFT); +} + static int gsi_func_suspend(struct usb_function *f, u8 options) { bool func_wakeup_allowed; @@ -3304,6 +3312,7 @@ static int gsi_bind_config(struct f_gsi *gsi) gsi->function.disable = gsi_disable; gsi->function.free_func = gsi_free_func; gsi->function.suspend = gsi_suspend; + gsi->function.get_status = gsi_get_status; gsi->function.func_suspend = gsi_func_suspend; gsi->function.resume = gsi_resume; diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 7f4367bacf34..dbf6240e8c63 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -45,6 +45,9 @@ #define FUNC_SUSPEND_OPT_SUSP_MASK BIT(0) #define FUNC_SUSPEND_OPT_RW_EN_MASK BIT(1) +#define FUNC_WAKEUP_CAPABLE_SHIFT 0 +#define FUNC_WAKEUP_ENABLE_SHIFT 1 + /* * USB function drivers should return USB_GADGET_DELAYED_STATUS if they * wish to delay the data/status stages of the control transfer till they -- GitLab From 3d39e54aee57a82d00e3ce2456e2b1ce44dff61e Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Fri, 11 May 2018 18:36:41 +0530 Subject: [PATCH 758/855] ARM: dts: msm: Add camera support for MSM8917 QRD device Add camera dtsi changes for MSM8917 QRD device, and camera pinctrl dtsi. It is needed to support for camera driver which is accessed by various clients. Port msm-3.18 camera kernel on msm-4.9 kernel This snapshot is taken from msm-3.18 branch as of: 'commit 3e917a308af6 ("ARM: dts: msm: Add camera device tree files for MSMgold")' Change-Id: Ic466afb1a1ec20422eb488a91894b1e7fe077164 Signed-off-by: Abhishek Jain --- .../boot/dts/qcom/msm8917-camera-pinctrl.dtsi | 277 +++++++++ .../dts/qcom/msm8917-camera-sensor-qrd.dtsi | 181 ++++++ arch/arm64/boot/dts/qcom/msm8917-camera.dtsi | 533 ++++++++++++++++++ arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi | 2 +- .../dts/qcom/msm8917-pmi8937-qrd-sku5.dts | 9 + arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi | 1 + arch/arm64/boot/dts/qcom/msm8917.dtsi | 1 + 7 files changed, 1003 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/qcom/msm8917-camera-pinctrl.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm8917-camera-sensor-qrd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm8917-camera.dtsi diff --git a/arch/arm64/boot/dts/qcom/msm8917-camera-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8917-camera-pinctrl.dtsi new file mode 100644 index 000000000000..33cc8aecc360 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-camera-pinctrl.dtsi @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +cci { + cci0_active: cci0_active { + /* cci0 active state */ + mux { + /* CLK, DATA */ + pins = "gpio29", "gpio30"; + function = "cci_i2c"; + }; + + config { + pins = "gpio29", "gpio30"; + drive-strength = <2>; /* 2 MA */ + bias-disable; /* No PULL */ + }; + }; + + cci0_suspend: cci0_suspend { + /* cci0 suspended state */ + mux { + /* CLK, DATA */ + pins = "gpio29", "gpio30"; + function = "cci_i2c"; + }; + + config { + pins = "gpio29", "gpio30"; + drive-strength = <2>; /* 2 MA */ + bias-disable; /* No PULL */ + }; + }; + + cci1_active: cci1_active { + /* cci1 active state */ + mux { + /* CLK, DATA */ + pins = "gpio31", "gpio32"; + function = "cci_i2c"; + }; + + config { + pins = "gpio31", "gpio32"; + drive-strength = <2>; /* 2 MA */ + bias-disable; /* No PULL */ + }; + }; + + cci1_suspend: cci1_suspend { + /* cci1 suspended state */ + mux { + /* CLK, DATA */ + pins = "gpio31", "gpio32"; + function = "cci_i2c"; + }; + + config { + pins = "gpio31", "gpio32"; + drive-strength = <2>; /* 2 MA */ + bias-disable; /* No PULL */ + }; + }; +}; + +/*sensors */ +cam_sensor_mclk0_default: cam_sensor_mclk0_default { + /* MCLK0 */ + mux { + /* CLK, DATA */ + pins = "gpio26"; + function = "cam_mclk"; + }; + + config { + pins = "gpio26"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +cam_sensor_mclk0_sleep: cam_sensor_mclk0_sleep { + /* MCLK0 */ + mux { + /* CLK, DATA */ + pins = "gpio26"; + function = "cam_mclk"; + }; + + config { + pins = "gpio26"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +cam_sensor_rear_default: cam_sensor_rear_default { + /* RESET, STANDBY */ + mux { + pins = "gpio36", "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio36","gpio35"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +cam_sensor_rear_sleep: cam_sensor_rear_sleep { + /* RESET, STANDBY */ + mux { + pins = "gpio36","gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio36","gpio35"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +cam_sensor_rear_vdig: cam_sensor_rear_vdig { + /* VDIG */ + mux { + pins = "gpio62"; + function = "gpio"; + }; + + config { + pins = "gpio62"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +cam_sensor_rear_vdig_sleep: cam_sensor_rear_vdig_sleep { + /* VDIG */ + mux { + pins = "gpio62"; + function = "gpio"; + }; + + config { + pins = "gpio62"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +cam_sensor_mclk1_default: cam_sensor_mclk1_default { + /* MCLK1 */ + mux { + /* CLK, DATA */ + pins = "gpio27"; + function = "cam_mclk"; + }; + + config { + pins = "gpio27"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +cam_sensor_mclk1_sleep: cam_sensor_mclk1_sleep { + /* MCLK1 */ + mux { + /* CLK, DATA */ + pins = "gpio27"; + function = "cam_mclk"; + }; + + config { + pins = "gpio27"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +cam_sensor_front_default: cam_sensor_front_default { + /* RESET, STANDBY */ + mux { + pins = "gpio38","gpio50"; + function = "gpio"; + }; + + config { + pins = "gpio38","gpio50"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +cam_sensor_front_sleep: cam_sensor_front_sleep { + /* RESET, STANDBY */ + mux { + pins = "gpio38","gpio50"; + function = "gpio"; + }; + + config { + pins = "gpio38","gpio50"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +cam_sensor_mclk2_default: cam_sensor_mclk2_default { + /* MCLK2 */ + mux { + /* CLK, DATA */ + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +cam_sensor_mclk2_sleep: cam_sensor_mclk2_sleep { + /* MCLK2 */ + mux { + /* CLK, DATA */ + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +cam_sensor_front1_default: cam_sensor_front1_default { + /* RESET, STANDBY */ + mux { + pins = "gpio40", "gpio39"; + function = "gpio"; + }; + + config { + pins = "gpio40", "gpio39"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +cam_sensor_front1_sleep: cam_sensor_front1_sleep { + /* RESET, STANDBY */ + mux { + pins = "gpio40", "gpio39"; + function = "gpio"; + }; + + config { + pins = "gpio40", "gpio39"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-qrd.dtsi new file mode 100644 index 000000000000..dbaccfafb4c2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-qrd.dtsi @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&cci { + actuator0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2850000>; + qcom,cam-vreg-max-voltage = <2850000>; + qcom,cam-vreg-op-mode = <80000>; + }; + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + qcom,cci-master = <0>; + reg = <0x0>; + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <200000 0 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default + &cam_sensor_rear_default>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; + gpios = <&tlmm 26 0>, + <&tlmm 36 0>, + <&tlmm 35 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_STANDBY0"; + status = "ok"; + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <19200000 0>; + }; + + eeprom2: qcom,eeprom@2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + reg = <0x02>; + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <105000 0 80000 100000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_default + &cam_sensor_front1_default>; + pinctrl-1 = <&cam_sensor_mclk2_sleep + &cam_sensor_front1_sleep>; + gpios = <&tlmm 28 0>, + <&tlmm 40 0>, + <&tlmm 39 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_STANDBY2"; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_gcc clk_mclk2_clk_src>, + <&clock_gcc clk_gcc_camss_mclk2_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <19200000 0>; + }; + + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x0>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <90>; + qcom,actuator-src = <&actuator0>; + qcom,led-flash-src = <&led_flash0>; + qcom,eeprom-src = <&eeprom0>; + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <200000 0 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default + &cam_sensor_rear_default>; + pinctrl-1 = <&cam_sensor_mclk0_sleep + &cam_sensor_rear_sleep>; + gpios = <&tlmm 26 0>, + <&tlmm 36 0>, + <&tlmm 35 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_STANDBY0"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@2 { + cell-index = <2>; + compatible = "qcom,camera"; + reg = <0x02>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,eeprom-src = <&eeprom2>; + qcom,mount-angle = <270>; + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000>; + qcom,cam-vreg-op-mode = <105000 0 80000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_default + &cam_sensor_front1_default>; + pinctrl-1 = <&cam_sensor_mclk2_sleep + &cam_sensor_front1_sleep>; + gpios = <&tlmm 28 0>, + <&tlmm 40 0>, + <&tlmm 39 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_STANDBY2"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + clocks = <&clock_gcc clk_mclk2_clk_src>, + <&clock_gcc clk_gcc_camss_mclk2_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-camera.dtsi b/arch/arm64/boot/dts/qcom/msm8917-camera.dtsi new file mode 100644 index 000000000000..4991ff721c7c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-camera.dtsi @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,msm-cam@1b00000 { + compatible = "qcom,msm-cam"; + reg = <0x1b00000 0x40000>; + reg-names = "msm-cam"; + status = "ok"; + bus-vectors = "suspend", "svs", "nominal", "turbo"; + qcom,bus-votes = <0 160000000 320000000 320000000>; + }; + + qcom,csiphy@1b34000 { + status = "ok"; + cell-index = <0>; + compatible = "qcom,csiphy-v3.4.2", "qcom,csiphy"; + reg = <0x1b34000 0x1000>, + <0x1b00030 0x4>; + reg-names = "csiphy", "csiphy_clk_mux"; + interrupts = <0 78 0>; + interrupt-names = "csiphy"; + clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_csi0phytimer_clk_src>, + <&clock_gcc clk_gcc_camss_csi0phytimer_clk>, + <&clock_gcc clk_camss_top_ahb_clk_src>, + <&clock_gcc clk_gcc_camss_csi0phy_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>; + clock-names = "camss_top_ahb_clk", "ispif_ahb_clk", + "csiphy_timer_src_clk", "csiphy_timer_clk", + "camss_ahb_src", "csi_phy_clk", + "camss_ahb_clk"; + qcom,clock-rates = <0 61540000 200000000 0 0 0 0>; + }; + + qcom,csiphy@1b35000 { + status = "ok"; + cell-index = <1>; + compatible = "qcom,csiphy-v3.4.2", "qcom,csiphy"; + reg = <0x1b35000 0x1000>, + <0x1b00038 0x4>; + reg-names = "csiphy", "csiphy_clk_mux"; + interrupts = <0 79 0>; + interrupt-names = "csiphy"; + clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_csi1phytimer_clk_src>, + <&clock_gcc clk_gcc_camss_csi1phytimer_clk>, + <&clock_gcc clk_camss_top_ahb_clk_src>, + <&clock_gcc clk_gcc_camss_csi1phy_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>; + clock-names = "camss_top_ahb_clk", "ispif_ahb_clk", + "csiphy_timer_src_clk", "csiphy_timer_clk", + "camss_ahb_src", "csi_phy_clk", + "camss_ahb_clk"; + qcom,clock-rates = <0 61540000 200000000 0 0 0 0>; + }; + + qcom,csid@1b30000 { + status = "ok"; + cell-index = <0>; + compatible = "qcom,csid-v3.4.3", "qcom,csid"; + reg = <0x1b30000 0x400>; + reg-names = "csid"; + interrupts = <0 51 0>; + interrupt-names = "csid"; + qcom,csi-vdd-voltage = <1200000>; + qcom,mipi-csi-vdd-supply = <&pm8937_l2>; + clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_gcc_camss_csi0_ahb_clk>, + <&clock_gcc clk_csi0_clk_src>, + <&clock_gcc clk_gcc_camss_csi0_clk>, + <&clock_gcc clk_gcc_camss_csi0pix_clk>, + <&clock_gcc clk_gcc_camss_csi0rdi_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>; + clock-names = "camss_top_ahb_clk", + "ispif_ahb_clk", "csi_ahb_clk", "csi_src_clk", + "csi_clk", "csi_pix_clk", + "csi_rdi_clk", "camss_ahb_clk"; + qcom,clock-rates = <0 61540000 0 200000000 0 0 0 0>; + }; + + qcom,csid@1b30400 { + status = "ok"; + cell-index = <1>; + compatible = "qcom,csid-v3.4.3", "qcom,csid"; + reg = <0x1b30400 0x400>; + reg-names = "csid"; + interrupts = <0 52 0>; + interrupt-names = "csid"; + qcom,csi-vdd-voltage = <1200000>; + qcom,mipi-csi-vdd-supply = <&pm8937_l2>; + clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_gcc_camss_csi1_ahb_clk>, + <&clock_gcc clk_csi1_clk_src>, + <&clock_gcc clk_gcc_camss_csi1_clk>, + <&clock_gcc clk_gcc_camss_csi1pix_clk>, + <&clock_gcc clk_gcc_camss_csi1rdi_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>; + clock-names = "camss_top_ahb_clk", + "ispif_ahb_clk", "csi_ahb_clk", "csi_src_clk", + "csi_clk", "csi_pix_clk", + "csi_rdi_clk", "camss_ahb_clk"; + qcom,clock-rates = <0 61540000 0 200000000 0 0 0 0>; + }; + + qcom,csid@1b30800 { + status = "ok"; + cell-index = <2>; + compatible = "qcom,csid-v3.4.3", "qcom,csid"; + reg = <0x1b30800 0x400>; + reg-names = "csid"; + interrupts = <0 153 0>; + interrupt-names = "csid"; + qcom,csi-vdd-voltage = <1200000>; + qcom,mipi-csi-vdd-supply = <&pm8937_l2>; + clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_gcc_camss_csi2_ahb_clk>, + <&clock_gcc clk_csi2_clk_src>, + <&clock_gcc clk_gcc_camss_csi2_clk>, + <&clock_gcc clk_gcc_camss_csi2pix_clk>, + <&clock_gcc clk_gcc_camss_csi2rdi_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>; + clock-names = "camss_top_ahb_clk", + "ispif_ahb_clk", "csi_ahb_clk", "csi_src_clk", + "csi_clk", "csi_pix_clk", + "csi_rdi_clk", "camss_ahb_clk"; + qcom,clock-rates = <0 61540000 0 200000000 0 0 0 0>; + }; + + qcom,ispif@1b31000 { + cell-index = <0>; + compatible = "qcom,ispif-v3.0", "qcom,ispif"; + reg = <0x1b31000 0x500>, + <0x1b00020 0x10>; + reg-names = "ispif", "csi_clk_mux"; + interrupts = <0 55 0>; + interrupt-names = "ispif"; + qcom,num-isps = <0x2>; + vfe0-vdd-supply = <&gdsc_vfe>; + vfe1-vdd-supply = <&gdsc_vfe1>; + qcom,vdd-names = "vfe0-vdd", "vfe1-vdd"; + clocks = <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>, + <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_camss_top_ahb_clk_src>, + <&clock_gcc clk_csi0_clk_src>, + <&clock_gcc clk_gcc_camss_csi0_clk>, + <&clock_gcc clk_gcc_camss_csi0rdi_clk>, + <&clock_gcc clk_gcc_camss_csi0pix_clk>, + <&clock_gcc clk_csi1_clk_src>, + <&clock_gcc clk_gcc_camss_csi1_clk>, + <&clock_gcc clk_gcc_camss_csi1rdi_clk>, + <&clock_gcc clk_gcc_camss_csi1pix_clk>, + <&clock_gcc clk_csi2_clk_src>, + <&clock_gcc clk_gcc_camss_csi2_clk>, + <&clock_gcc clk_gcc_camss_csi2rdi_clk>, + <&clock_gcc clk_gcc_camss_csi2pix_clk>, + <&clock_gcc clk_vfe0_clk_src>, + <&clock_gcc clk_gcc_camss_vfe0_clk>, + <&clock_gcc clk_gcc_camss_csi_vfe0_clk>, + <&clock_gcc clk_vfe1_clk_src>, + <&clock_gcc clk_gcc_camss_vfe1_clk>, + <&clock_gcc clk_gcc_camss_csi_vfe1_clk>; + clock-names = "ispif_ahb_clk", + "camss_ahb_clk", "camss_top_ahb_clk", + "camss_ahb_src", + "csi0_src_clk", "csi0_clk", + "csi0_rdi_clk", "csi0_pix_clk", + "csi1_src_clk", "csi1_clk", + "csi1_rdi_clk", "csi1_pix_clk", + "csi2_src_clk", "csi2_clk", + "csi2_rdi_clk", "csi2_pix_clk", + "vfe0_clk_src", "camss_vfe_vfe0_clk", + "camss_csi_vfe0_clk", "vfe1_clk_src", + "camss_vfe_vfe1_clk", "camss_csi_vfe1_clk"; + qcom,clock-rates = <61540000 0 0 0 + 200000000 0 0 0 + 200000000 0 0 0 + 200000000 0 0 0 + 0 0 0 + 0 0 0>; + qcom,clock-cntl-support; + qcom,clock-control = "SET_RATE","NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", "SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "INIT_RATE", "NO_SET_RATE", + "NO_SET_RATE", "INIT_RATE", "NO_SET_RATE", + "NO_SET_RATE"; + }; + + vfe0: qcom,vfe0@1b10000 { + cell-index = <0>; + compatible = "qcom,vfe40"; + reg = <0x1b10000 0x1000>, + <0x1b40000 0x200>; + reg-names = "vfe", "vfe_vbif"; + interrupts = <0 57 0>; + interrupt-names = "vfe"; + vdd-supply = <&gdsc_vfe>; + clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>, + <&clock_gcc clk_vfe0_clk_src>, + <&clock_gcc clk_gcc_camss_vfe0_clk>, + <&clock_gcc clk_gcc_camss_csi_vfe0_clk>, + <&clock_gcc clk_gcc_camss_vfe_ahb_clk>, + <&clock_gcc clk_gcc_camss_vfe_axi_clk>, + <&clock_gcc clk_gcc_camss_ispif_ahb_clk>; + clock-names = "camss_top_ahb_clk", "camss_ahb_clk", + "vfe_clk_src", "camss_vfe_vfe_clk", + "camss_csi_vfe_clk", "iface_clk", + "bus_clk", "iface_ahb_clk"; + qcom,clock-rates = <0 0 266670000 0 0 0 0 0>; + qos-entries = <8>; + qos-regs = <0x2c4 0x2c8 0x2cc 0x2d0 0x2d4 0x2d8 + 0x2dc 0x2e0>; + qos-settings = <0xaa55aa55 + 0xaa55aa55 0xaa55aa55 + 0xaa55aa55 0xaa55aa55 + 0xaa55aa55 0xaa55aa55 + 0xaa55aa55>; + vbif-entries = <1>; + vbif-regs = <0x124>; + vbif-settings = <0x3>; + ds-entries = <17>; + ds-regs = <0x988 0x98c 0x990 0x994 0x998 + 0x99c 0x9a0 0x9a4 0x9a8 0x9ac 0x9b0 + 0x9b4 0x9b8 0x9bc 0x9c0 0x9c4 0x9c8>; + ds-settings = <0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0x00000110>; + max-clk-nominal = <400000000>; + max-clk-turbo = <432000000>; + }; + + vfe1: qcom,vfe1@1b14000 { + cell-index = <1>; + compatible = "qcom,vfe40"; + reg = <0x1b14000 0x1000>, + <0x1ba0000 0x200>; + reg-names = "vfe", "vfe_vbif"; + interrupts = <0 29 0>; + interrupt-names = "vfe"; + vdd-supply = <&gdsc_vfe1>; + clocks = <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>, + <&clock_gcc clk_vfe1_clk_src>, + <&clock_gcc clk_gcc_camss_vfe1_clk>, + <&clock_gcc clk_gcc_camss_csi_vfe1_clk>, + <&clock_gcc clk_gcc_camss_vfe1_ahb_clk>, + <&clock_gcc clk_gcc_camss_vfe1_axi_clk>, + <&clock_gcc clk_gcc_camss_ispif_ahb_clk>; + clock-names = "camss_top_ahb_clk" , "camss_ahb_clk", + "vfe_clk_src", "camss_vfe_vfe_clk", + "camss_csi_vfe_clk", "iface_clk", + "bus_clk", "iface_ahb_clk"; + qcom,clock-rates = <0 0 266670000 0 0 0 0 0>; + qos-entries = <8>; + qos-regs = <0x2c4 0x2c8 0x2cc 0x2d0 0x2d4 0x2d8 + 0x2dc 0x2e0>; + qos-settings = <0xaa55aa55 + 0xaa55aa55 0xaa55aa55 + 0xaa55aa55 0xaa55aa55 + 0xaa55aa55 0xaa55aa55 + 0xaa55aa55>; + vbif-entries = <1>; + vbif-regs = <0x124>; + vbif-settings = <0x3>; + ds-entries = <17>; + ds-regs = <0x988 0x98c 0x990 0x994 0x998 + 0x99c 0x9a0 0x9a4 0x9a8 0x9ac 0x9b0 + 0x9b4 0x9b8 0x9bc 0x9c0 0x9c4 0x9c8>; + ds-settings = <0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0xcccc1111 + 0xcccc1111 0x00000110>; + max-clk-nominal = <400000000>; + max-clk-turbo = <432000000>; + }; + + qcom,vfe { + compatible = "qcom,vfe"; + num_child = <2>; + }; + + qcom,cam_smmu { + status = "ok"; + compatible = "qcom,msm-cam-smmu"; + msm_cam_smmu_cb1: msm_cam_smmu_cb1 { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_iommu 0x400 0x00>, + <&apps_iommu 0x2400 0x00>; + label = "vfe"; + qcom,scratch-buf-support; + }; + + msm_cam_smmu_cb2: msm_cam_smmu_cb2 { + compatible = "qcom,msm-cam-smmu-cb"; + label = "vfe_secure"; + qcom,secure-context; + }; + + msm_cam_smmu_cb3: msm_cam_smmu_cb3 { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_iommu 0x1c00 0x00>; + label = "cpp"; + }; + + msm_cam_smmu_cb4: msm_cam_smmu_cb4 { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_iommu 0x1800 0x00>; + label = "jpeg_enc0"; + }; + }; + + qcom,jpeg@1b1c000 { + status = "ok"; + cell-index = <0>; + compatible = "qcom,jpeg"; + reg = <0x1b1c000 0x400>, + <0x1b60000 0xc30>; + reg-names = "jpeg_hw", "jpeg_vbif"; + interrupts = <0 59 0>; + interrupt-names = "jpeg"; + vdd-supply = <&gdsc_jpeg>; + qcom,vdd-names = "vdd"; + clock-names = "core_clk", "iface_clk", "bus_clk0", + "camss_top_ahb_clk", "camss_ahb_clk"; + clocks = <&clock_gcc clk_gcc_camss_jpeg0_clk>, + <&clock_gcc clk_gcc_camss_jpeg_ahb_clk>, + <&clock_gcc clk_gcc_camss_jpeg_axi_clk>, + <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>; + qcom,clock-rates = <266670000 0 0 0 0>; + qcom,qos-reg-settings = <0x28 0x0000555e>, + <0xc8 0x00005555>; + qcom,msm-bus,name = "msm_camera_jpeg0"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <62 512 0 0>, + <62 512 800000 800000>; + qcom,vbif-reg-settings = <0xc0 0x10101000>, + <0xb0 0x10100010>; + }; + + qcom,irqrouter@1b00000 { + status = "ok"; + cell-index = <0>; + compatible = "qcom,irqrouter"; + reg = <0x1b00000 0x100>; + reg-names = "irqrouter"; + }; + + qcom,cpp@1b04000 { + status = "ok"; + cell-index = <0>; + compatible = "qcom,cpp"; + reg = <0x1b04000 0x100>, + <0x1b80000 0x200>, + <0x1b18000 0x018>, + <0x1858078 0x4>; + reg-names = "cpp", "cpp_vbif", "cpp_hw", "camss_cpp"; + interrupts = <0 49 0>; + interrupt-names = "cpp"; + vdd-supply = <&gdsc_cpp>; + qcom,vdd-names = "vdd"; + clocks = <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_cpp_clk_src>, + <&clock_gcc clk_gcc_camss_top_ahb_clk>, + <&clock_gcc clk_gcc_camss_cpp_ahb_clk>, + <&clock_gcc clk_gcc_camss_cpp_axi_clk>, + <&clock_gcc clk_gcc_camss_cpp_clk>, + <&clock_gcc clk_gcc_camss_micro_ahb_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>; + clock-names = "ispif_ahb_clk", "cpp_core_clk", + "camss_top_ahb_clk", "camss_vfe_cpp_ahb_clk", + "camss_vfe_cpp_axi_clk", "camss_vfe_cpp_clk", + "micro_iface_clk", "camss_ahb_clk"; + qcom,clock-rates = <61540000 180000000 0 0 0 180000000 0 0>; + qcom,min-clock-rate = <133000000>; + resets = <&clock_gcc GCC_CAMSS_MICRO_BCR>; + reset-names = "micro_iface_reset"; + qcom,bus-master = <1>; + qcom,msm-bus,name = "msm_camera_cpp"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <106 512 0 0>, + <106 512 0 0>; + qcom,msm-bus-vector-dyn-vote; + qcom,micro-reset; + qcom,cpp-fw-payload-info { + qcom,stripe-base = <156>; + qcom,plane-base = <141>; + qcom,stripe-size = <27>; + qcom,plane-size = <5>; + qcom,fe-ptr-off = <5>; + qcom,we-ptr-off = <11>; + }; + }; + + cci: qcom,cci@1b0c000 { + status = "ok"; + cell-index = <0>; + compatible = "qcom,cci"; + reg = <0x1b0c000 0x4000>; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "cci"; + interrupts = <0 50 0>; + interrupt-names = "cci"; + clocks = <&clock_gcc clk_gcc_camss_ispif_ahb_clk>, + <&clock_gcc clk_cci_clk_src>, + <&clock_gcc clk_gcc_camss_cci_ahb_clk>, + <&clock_gcc clk_gcc_camss_cci_clk>, + <&clock_gcc clk_gcc_camss_ahb_clk>, + <&clock_gcc clk_gcc_camss_top_ahb_clk>; + clock-names = "ispif_ahb_clk", "cci_src_clk", + "cci_ahb_clk", "camss_cci_clk", + "camss_ahb_clk", "camss_top_ahb_clk"; + qcom,clock-rates = <61540000 19200000 0 0 0 0>, + <61540000 37500000 0 0 0 0>; + pinctrl-names = "cci_default", "cci_suspend"; + pinctrl-0 = <&cci0_active &cci1_active>; + pinctrl-1 = <&cci0_suspend &cci1_suspend>; + gpios = <&tlmm 29 0>, + <&tlmm 30 0>, + <&tlmm 31 0>, + <&tlmm 32 0>; + qcom,gpio-tbl-num = <0 1 2 3>; + qcom,gpio-tbl-flags = <1 1 1 1>; + qcom,gpio-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + i2c_freq_100Khz: qcom,i2c_standard_mode { + status = "disabled"; + }; + i2c_freq_400Khz: qcom,i2c_fast_mode { + status = "disabled"; + }; + i2c_freq_custom: qcom,i2c_custom_mode { + status = "disabled"; + }; + + i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { + status = "disabled"; + }; + }; +}; + +&i2c_freq_100Khz { + qcom,hw-thigh = <78>; + qcom,hw-tlow = <114>; + qcom,hw-tsu-sto = <28>; + qcom,hw-tsu-sta = <28>; + qcom,hw-thd-dat = <10>; + qcom,hw-thd-sta = <77>; + qcom,hw-tbuf = <118>; + qcom,hw-scl-stretch-en = <0>; + qcom,hw-trdhld = <6>; + qcom,hw-tsp = <1>; +}; + +&i2c_freq_400Khz { + qcom,hw-thigh = <20>; + qcom,hw-tlow = <28>; + qcom,hw-tsu-sto = <21>; + qcom,hw-tsu-sta = <21>; + qcom,hw-thd-dat = <13>; + qcom,hw-thd-sta = <18>; + qcom,hw-tbuf = <32>; + qcom,hw-scl-stretch-en = <0>; + qcom,hw-trdhld = <6>; + qcom,hw-tsp = <3>; + status = "ok"; +}; + +&i2c_freq_custom { + qcom,hw-thigh = <15>; + qcom,hw-tlow = <28>; + qcom,hw-tsu-sto = <21>; + qcom,hw-tsu-sta = <21>; + qcom,hw-thd-dat = <13>; + qcom,hw-thd-sta = <18>; + qcom,hw-tbuf = <25>; + qcom,hw-scl-stretch-en = <1>; + qcom,hw-trdhld = <6>; + qcom,hw-tsp = <3>; + status = "ok"; +}; + +&i2c_freq_1Mhz { + qcom,hw-thigh = <16>; + qcom,hw-tlow = <22>; + qcom,hw-tsu-sto = <17>; + qcom,hw-tsu-sta = <18>; + qcom,hw-thd-dat = <16>; + qcom,hw-thd-sta = <15>; + qcom,hw-tbuf = <19>; + qcom,hw-scl-stretch-en = <1>; + qcom,hw-trdhld = <3>; + qcom,hw-tsp = <3>; + qcom,cci-clk-src = <37500000>; + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi index 26fb25ccb66d..858936d86e85 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi @@ -22,7 +22,7 @@ interrupt-parent = <&wakegpio>; #interrupt-cells = <2>; - +#include "msm8917-camera-pinctrl.dtsi" /* add pingrp for touchscreen */ pmx_ts_int_active { ts_int_active: ts_int_active { diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8937-qrd-sku5.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-qrd-sku5.dts index 29ef47c5e3c6..832a0abbefc2 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-pmi8937-qrd-sku5.dts +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-qrd-sku5.dts @@ -114,4 +114,13 @@ qcom,key-codes = <139 172 158>; qcom,y-offset = <0>; }; + + led_flash0: qcom,camera-flash { + cell-index = <0>; + compatible = "qcom,camera-flash"; + qcom,flash-type = <1>; + qcom,flash-source = <&pmi8937_flash0>; + qcom,torch-source = <&pmi8937_torch0>; + qcom,switch-source = <&pmi8937_switch>; + }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi index fae258d07bf9..431a5e54fe35 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi @@ -12,6 +12,7 @@ */ #include "msm8917-pinctrl.dtsi" +#include "msm8917-camera-sensor-qrd.dtsi" &blsp1_uart2 { status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/msm8917.dtsi b/arch/arm64/boot/dts/qcom/msm8917.dtsi index d0805395705f..242fd9c00327 100644 --- a/arch/arm64/boot/dts/qcom/msm8917.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917.dtsi @@ -157,6 +157,7 @@ }; #include "msm8917-pinctrl.dtsi" +#include "msm8917-camera.dtsi" #include "msm8917-cpu.dtsi" #include "msm8917-pm.dtsi" #include "msm8917-ion.dtsi" -- GitLab From 5ce35af7341b4c202dbe2a06521348bebe1b60e1 Mon Sep 17 00:00:00 2001 From: Monika Singh Date: Sat, 24 Feb 2018 17:25:08 +0530 Subject: [PATCH 759/855] ARM: dts: msm: Mount system and vendor for SDM450 Add avb flag when mounting system and vendor images for non-multislot. When multislot is disabled system is not the root folder hence early mounting to be done using dtsi. Change-Id: Id4754402e15e0f2e63ca4f6b9340a738158bee71 Signed-off-by: Monika Singh --- arch/arm64/boot/dts/qcom/msm8953.dtsi | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index 67fd75ff7bc3..0e71058571a8 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -33,6 +33,11 @@ firmware: firmware { android { compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo,recovery"; + }; + fstab { compatible = "android,fstab"; vendor { @@ -40,7 +45,7 @@ dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; + fsmgr_flags = "wait,avb"; status = "ok"; }; system { @@ -48,7 +53,7 @@ dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; + fsmgr_flags = "wait,avb"; status = "ok"; }; -- GitLab From 85f8d252700315cdc0ed480647f5928d313a199d Mon Sep 17 00:00:00 2001 From: Maria Yu Date: Thu, 7 Jun 2018 19:20:54 +0800 Subject: [PATCH 760/855] tty: serial: msm: Add timeout for waiting TX ready At worst case, msm serial driver is stuck in waiting TX ready, so have a 500ms timeout to avoid stuck and only lost some log to uart. Change-Id: I2984ed8ad094a040c8ae49ee6ffba5f0238ca336 Signed-off-by: Maria Yu Signed-off-by: Teng Fei Fan --- drivers/tty/serial/msm_serial.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 60acbf7b466e..69fa4dc2cef8 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -395,10 +395,22 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base) static inline void msm_wait_for_xmitr(struct uart_port *port) { + u32 count = 500000; + while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) { if (msm_read(port, UART_ISR) & UART_ISR_TX_READY) break; udelay(1); + + /* At worst case, it is stuck in this loop for waiting + * TX ready, have a 500ms timeout to avoid stuck here + * and only miss some log to uart. + */ + if (count-- == 0) { + msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); + printk_deferred("uart may lost data, resetting TX!\n"); + break; + } } msm_write(port, UART_CR_CMD_RESET_TX_READY, UART_CR); } -- GitLab From ffbbfaf54360b2b424c459c4405b1fe8520e3e8e Mon Sep 17 00:00:00 2001 From: Ramesh Yadav Javadi Date: Fri, 8 Jun 2018 11:56:22 +0530 Subject: [PATCH 761/855] defconfig: msm: Enable SYSMON communication interface for msm8909w To provide communication among multiple subsystems enable SYSMON communication interface. Change-Id: I0e664eb24e10e9d9b0943388879240f814d0cea9 Signed-off-by: Ramesh Yadav Javadi --- arch/arm/configs/msm8909w-perf_defconfig | 1 + arch/arm/configs/msm8909w_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 69dc93fe716f..887ab5cea1f4 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -437,6 +437,7 @@ CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_GLINK_PKT=y CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_MSS_QDSP6V5=y diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index 3c600374239e..8c5f143d57a7 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -407,6 +407,7 @@ CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_GLINK_PKT=y CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_SYSMON_COMM=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_MSS_QDSP6V5=y -- GitLab From 741896f7078a5f739e11139c401667ff57caaf9c Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Tue, 5 Jun 2018 12:04:14 +0800 Subject: [PATCH 762/855] defconfig: sdxpoorwills: Enable bluetooth relevant config options Enable BT relevant configuration options for sdxpoorwills. CRs-Fixed: 2254063 Change-Id: Iddbe961ff40e5568ec0597ea3a8eebc0a84f12bc Signed-off-by: Zijun Hu --- arch/arm/configs/sdxpoorwills_defconfig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig index d86bc52e00aa..ac9fbf839e25 100644 --- a/arch/arm/configs/sdxpoorwills_defconfig +++ b/arch/arm/configs/sdxpoorwills_defconfig @@ -157,6 +157,8 @@ CONFIG_NET_SCH_PRIO=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_DEBUGFS=y CONFIG_CFG80211_INTERNAL_REGDB=y @@ -228,7 +230,6 @@ CONFIG_I2C_MSM_V2=y CONFIG_SPI=y CONFIG_SPI_QUP=y CONFIG_SPI_SPIDEV=m -CONFIG_SLIMBUS=y CONFIG_SPMI=y CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y CONFIG_PTP_1588_CLOCK=y @@ -453,8 +454,6 @@ CONFIG_SECURITY_NETWORK=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y # CONFIG_SECURITY_SELINUX_AVC_STATS is not set -CONFIG_CRYPTO_CMAC=y -CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -- GitLab From 18c5b4e31d4b9499443f3d7c93370a29bdcc79e2 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Tue, 5 Jun 2018 21:11:12 +0800 Subject: [PATCH 763/855] ARM: dts: msm: Correct the dump_mem size for MSM8953 and MSM8937 Correct the size of dump_mem as it is too large for mem_dump. Change-Id: I64fb6c7500d9101c6662ddf45b8054744967ae36 Signed-off-by: Mao Jinlong --- arch/arm64/boot/dts/qcom/msm8937.dtsi | 2 +- arch/arm64/boot/dts/qcom/msm8953.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi index 66c7e7cd987f..67ec032b793c 100644 --- a/arch/arm64/boot/dts/qcom/msm8937.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi @@ -132,7 +132,7 @@ dump_mem: mem_dump_region { compatible = "shared-dma-pool"; reusable; - size = <0 0x2400000>; + size = <0x400000>; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index 67fd75ff7bc3..d25d5b36deab 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -143,7 +143,7 @@ dump_mem: mem_dump_region { compatible = "shared-dma-pool"; reusable; - size = <0 0x2400000>; + size = <0x400000>; }; }; -- GitLab From 69486b6e6322fafad4471504e642654f86e302d5 Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Fri, 8 Jun 2018 14:44:25 +0530 Subject: [PATCH 764/855] ARM: dts: msm: update APC CPR voltage margins for sdm439 Add CPR closed-loop voltage margins as per sdm439 voltage plan. Also add floor-to-ceiling voltage range values. Change-Id: Ifa6373e8e97db756e1e4d95a81006b6b63d5eeb0 Signed-off-by: Tirupathi Reddy --- arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi index b97e66e60abe..7c208a461f46 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi @@ -472,11 +472,18 @@ qcom,cpr-fuse-version-map = /* */ <(-1) (-1) ( 0) (-1) (-1) (-1)>, + <(-1) (-1) ( 1) (-1) (-1) (-1)>, <(-1) (-1) (-1) (-1) (-1) (-1)>; qcom,cpr-quotient-adjustment = - <66 77 66>, /* SVSP_30mV, NOM_35mV, TUR_30mV */ - <0 0 0>; + <66 77 66>, /* SVSP/NOM/TUR:30/35/30 mV */ + <(-74) (-57) (-30)>, /* SVSP/NOM/TUR:-34/-26/-14 mV */ + <0 0 0>; + + qcom,cpr-floor-to-ceiling-max-range = + <50000 50000 50000 65000 65000>, + <50000 50000 50000 65000 65000>, + <50000 50000 50000 65000 65000>; qcom,cpr-voltage-ceiling-override = <(-1) (-1) 810000 845000 885000 960000 960000>; -- GitLab From 78747c55fb4bc758d6295ee00edfc2be5a545dcc Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Fri, 1 Jun 2018 12:59:53 +0530 Subject: [PATCH 765/855] usb: gsi: Fix runtime PM usage count for MBIM interface GSI Driver get the usage count in work handler when set_alt 1 happens and this counter will decrement in disconnect work due to cable disconnect or in gsi_suspend for suspended state. In this case set alt to 0 came for MBIM interface and clear the data_interface_up flag. After that suspend happens and does not decrement the counter in gsi_suspend. This causes a mismatch of usage count and usb not entering to low power mode. Fix this by checking for USB_PROT_GPS_CTRL instead of data_interface_up. Change-Id: Iaabf3de46ed72e33980d1e3e386e8ca0ae651c74 Signed-off-by: Chandana Kishori Chiluveru --- drivers/usb/gadget/function/f_gsi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index d3799e599ad5..55c8648e6a21 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -2481,7 +2481,11 @@ static void gsi_suspend(struct usb_function *f) return; } - if (!gsi->data_interface_up) { + /* + * GPS doesn't use any data interface, hence bail out as there is no + * GSI specific handling needed. + */ + if (gsi->prot_id == USB_PROT_GPS_CTRL) { log_event_dbg("%s: suspend done\n", __func__); return; } @@ -2515,7 +2519,7 @@ static void gsi_resume(struct usb_function *f) /* Check any pending cpkt, and queue immediately on resume */ gsi_ctrl_send_notification(gsi); - if (!gsi->data_interface_up) { + if (gsi->prot_id == USB_PROT_GPS_CTRL) { log_event_dbg("%s: resume done\n", __func__); return; } -- GitLab From fcf6042ac8efe1083db8eaadc0d60e8b3dd526f5 Mon Sep 17 00:00:00 2001 From: Yue Ma Date: Tue, 1 May 2018 16:59:56 -0700 Subject: [PATCH 766/855] cnss2: Add bus layer Bus layer is a shim layer for potential buses (PCIe, USB and SDIO) of WLAN devices. It abstracts all the bus related APIs for common files of the driver so that it can help make them bus independent. Change-Id: I06e19a26d34168fe0fcc65229a4519b868cd97c1 Signed-off-by: Yue Ma --- drivers/net/wireless/cnss2/Makefile | 1 + drivers/net/wireless/cnss2/bus.c | 165 ++++++++++++++++++++++++++++ drivers/net/wireless/cnss2/bus.h | 40 +++++++ drivers/net/wireless/cnss2/main.c | 113 +++---------------- drivers/net/wireless/cnss2/main.h | 2 +- drivers/net/wireless/cnss2/pci.c | 115 +++++++++++++------ drivers/net/wireless/cnss2/pci.h | 15 +-- drivers/net/wireless/cnss2/qmi.c | 5 +- 8 files changed, 309 insertions(+), 147 deletions(-) create mode 100644 drivers/net/wireless/cnss2/bus.c create mode 100644 drivers/net/wireless/cnss2/bus.h diff --git a/drivers/net/wireless/cnss2/Makefile b/drivers/net/wireless/cnss2/Makefile index b49d0898178b..318076f23213 100644 --- a/drivers/net/wireless/cnss2/Makefile +++ b/drivers/net/wireless/cnss2/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_CNSS2) += cnss2.o cnss2-y := main.o +cnss2-y += bus.o cnss2-y += debug.o cnss2-y += pci.o cnss2-y += power.o diff --git a/drivers/net/wireless/cnss2/bus.c b/drivers/net/wireless/cnss2/bus.c new file mode 100644 index 000000000000..834ae8add0bd --- /dev/null +++ b/drivers/net/wireless/cnss2/bus.c @@ -0,0 +1,165 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "bus.h" +#include "debug.h" +#include "pci.h" + +enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev) +{ + if (!dev) + return CNSS_BUS_NONE; + + if (!dev->bus) + return CNSS_BUS_NONE; + + if (memcmp(dev->bus->name, "pci", 3) == 0) + return CNSS_BUS_PCI; + else + return CNSS_BUS_NONE; +} + +enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id) +{ + switch (device_id) { + case QCA6174_DEVICE_ID: + case QCA6290_EMULATION_DEVICE_ID: + case QCA6290_DEVICE_ID: + return CNSS_BUS_PCI; + default: + cnss_pr_err("Unknown device_id: 0x%lx\n", device_id); + return CNSS_BUS_NONE; + } +} + +int cnss_bus_init(struct cnss_plat_data *plat_priv) +{ + if (!plat_priv) + return -ENODEV; + + switch (plat_priv->bus_type) { + case CNSS_BUS_PCI: + return cnss_pci_init(plat_priv); + default: + cnss_pr_err("Unsupported bus type: %d\n", + plat_priv->bus_type); + return -EINVAL; + } +} + +void cnss_bus_deinit(struct cnss_plat_data *plat_priv) +{ + if (!plat_priv) + return; + + switch (plat_priv->bus_type) { + case CNSS_BUS_PCI: + cnss_pci_deinit(plat_priv); + default: + cnss_pr_err("Unsupported bus type: %d\n", + plat_priv->bus_type); + return; + } +} + +int cnss_bus_load_m3(struct cnss_plat_data *plat_priv) +{ + if (!plat_priv) + return -ENODEV; + + switch (plat_priv->bus_type) { + case CNSS_BUS_PCI: + return cnss_pci_load_m3(plat_priv->bus_priv); + default: + cnss_pr_err("Unsupported bus type: %d\n", + plat_priv->bus_type); + return -EINVAL; + } +} + +int cnss_bus_alloc_fw_mem(struct cnss_plat_data *plat_priv) +{ + if (!plat_priv) + return -ENODEV; + + switch (plat_priv->bus_type) { + case CNSS_BUS_PCI: + return cnss_pci_alloc_fw_mem(plat_priv->bus_priv); + default: + cnss_pr_err("Unsupported bus type: %d\n", + plat_priv->bus_type); + return -EINVAL; + } +} + +u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv) +{ + if (!plat_priv) + return -ENODEV; + + switch (plat_priv->bus_type) { + case CNSS_BUS_PCI: + return cnss_pci_get_wake_msi(plat_priv->bus_priv); + default: + cnss_pr_err("Unsupported bus type: %d\n", + plat_priv->bus_type); + return -EINVAL; + } +} + +int cnss_bus_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv) +{ + if (!plat_priv) + return -ENODEV; + + switch (plat_priv->bus_type) { + case CNSS_BUS_PCI: + return cnss_pci_force_fw_assert_hdlr(plat_priv->bus_priv); + default: + cnss_pr_err("Unsupported bus type: %d\n", + plat_priv->bus_type); + return -EINVAL; + } +} + +void cnss_bus_fw_boot_timeout_hdlr(unsigned long data) +{ + struct cnss_plat_data *plat_priv = (struct cnss_plat_data *)data; + + if (!plat_priv) + return; + + switch (plat_priv->bus_type) { + case CNSS_BUS_PCI: + return cnss_pci_fw_boot_timeout_hdlr(plat_priv->bus_priv); + default: + cnss_pr_err("Unsupported bus type: %d\n", + plat_priv->bus_type); + return; + } +} + +void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv, bool in_panic) +{ + if (!plat_priv) + return; + + switch (plat_priv->bus_type) { + case CNSS_BUS_PCI: + return cnss_pci_collect_dump_info(plat_priv->bus_priv, + in_panic); + default: + cnss_pr_err("Unsupported bus type: %d\n", + plat_priv->bus_type); + return; + } +} diff --git a/drivers/net/wireless/cnss2/bus.h b/drivers/net/wireless/cnss2/bus.h new file mode 100644 index 000000000000..b7aeafa4c76b --- /dev/null +++ b/drivers/net/wireless/cnss2/bus.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CNSS_BUS_H +#define _CNSS_BUS_H + +#include "main.h" + +#define QCA6174_VENDOR_ID 0x168C +#define QCA6174_DEVICE_ID 0x003E +#define QCA6174_REV_ID_OFFSET 0x08 +#define QCA6174_REV3_VERSION 0x5020000 +#define QCA6174_REV3_2_VERSION 0x5030000 +#define QCA6290_VENDOR_ID 0x17CB +#define QCA6290_DEVICE_ID 0x1100 +#define QCA6290_EMULATION_VENDOR_ID 0x168C +#define QCA6290_EMULATION_DEVICE_ID 0xABCD + +enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev); +enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id); +int cnss_bus_init(struct cnss_plat_data *plat_priv); +void cnss_bus_deinit(struct cnss_plat_data *plat_priv); +int cnss_bus_load_m3(struct cnss_plat_data *plat_priv); +int cnss_bus_alloc_fw_mem(struct cnss_plat_data *plat_priv); +u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv); +int cnss_bus_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv); +void cnss_bus_fw_boot_timeout_hdlr(unsigned long data); +void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv, + bool in_panic); + +#endif /* _CNSS_BUS_H */ diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index e4efb98aec57..8b4b985b967f 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -23,6 +23,7 @@ #include #include "main.h" +#include "bus.h" #include "debug.h" #include "pci.h" @@ -37,7 +38,6 @@ #define FW_READY_TIMEOUT 20000 #define FW_ASSERT_TIMEOUT 5000 #define CNSS_EVENT_PENDING 2989 -#define WAKE_MSI_NAME "WAKE" static struct cnss_plat_data *plat_env; @@ -87,20 +87,6 @@ struct cnss_driver_event { void *data; }; -static enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev) -{ - if (!dev) - return CNSS_BUS_NONE; - - if (!dev->bus) - return CNSS_BUS_NONE; - - if (memcmp(dev->bus->name, "pci", 3) == 0) - return CNSS_BUS_PCI; - else - return CNSS_BUS_NONE; -} - static void cnss_set_plat_priv(struct platform_device *plat_dev, struct cnss_plat_data *plat_priv) { @@ -274,23 +260,6 @@ int cnss_get_platform_cap(struct device *dev, struct cnss_platform_cap *cap) } EXPORT_SYMBOL(cnss_get_platform_cap); -int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info) -{ - int ret = 0; - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); - void *bus_priv = cnss_bus_dev_to_bus_priv(dev); - - if (!plat_priv) - return -ENODEV; - - ret = cnss_pci_get_bar_info(bus_priv, &info->va, &info->pa); - if (ret) - return ret; - - return 0; -} -EXPORT_SYMBOL(cnss_get_soc_info); - void cnss_request_pm_qos(struct device *dev, u32 qos_val) { struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); @@ -506,24 +475,6 @@ int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode) } EXPORT_SYMBOL(cnss_set_fw_log_mode); -u32 cnss_get_wake_msi(struct cnss_plat_data *plat_priv) -{ - struct cnss_pci_data *pci_priv = plat_priv->bus_priv; - int ret, num_vectors; - u32 user_base_data, base_vector; - - ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev, - WAKE_MSI_NAME, &num_vectors, - &user_base_data, &base_vector); - - if (ret) { - cnss_pr_err("WAKE MSI is not valid\n"); - return 0; - } - - return user_base_data; -} - static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv) { int ret = 0; @@ -541,7 +492,7 @@ static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv) if (ret) goto out; - ret = cnss_pci_load_m3(plat_priv->bus_priv); + ret = cnss_bus_load_m3(plat_priv); if (ret) goto out; @@ -1442,7 +1393,6 @@ static const char *cnss_recovery_reason_to_str(enum cnss_recovery_reason reason) static int cnss_do_recovery(struct cnss_plat_data *plat_priv, enum cnss_recovery_reason reason) { - struct cnss_pci_data *pci_priv = plat_priv->bus_priv; struct cnss_subsys_info *subsys_info = &plat_priv->subsys_info; @@ -1451,11 +1401,6 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv, if (plat_priv->device_id == QCA6174_DEVICE_ID) goto self_recovery; - if (plat_priv->driver_ops && - test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) - plat_priv->driver_ops->update_status(pci_priv->pci_dev, - CNSS_RECOVERY); - if (test_bit(SKIP_RECOVERY, &quirks)) { cnss_pr_dbg("Skip device recovery\n"); return 0; @@ -1468,7 +1413,7 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv, break; case CNSS_REASON_RDDM: clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state); - cnss_pci_collect_dump_info(pci_priv, false); + cnss_bus_collect_dump_info(plat_priv, false); break; case CNSS_REASON_DEFAULT: case CNSS_REASON_TIMEOUT: @@ -1575,28 +1520,6 @@ void cnss_schedule_recovery(struct device *dev, } EXPORT_SYMBOL(cnss_schedule_recovery); -static int cnss_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv) -{ - struct cnss_pci_data *pci_priv = plat_priv->bus_priv; - int ret; - - ret = cnss_pci_set_mhi_state(plat_priv->bus_priv, - CNSS_MHI_TRIGGER_RDDM); - if (ret) { - cnss_pr_err("Failed to trigger RDDM, err = %d\n", ret); - cnss_schedule_recovery(&pci_priv->pci_dev->dev, - CNSS_REASON_DEFAULT); - return 0; - } - - if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) { - mod_timer(&plat_priv->fw_boot_timer, - jiffies + msecs_to_jiffies(FW_ASSERT_TIMEOUT)); - } - - return 0; -} - int cnss_force_fw_assert(struct device *dev) { struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); @@ -1624,17 +1547,6 @@ int cnss_force_fw_assert(struct device *dev) } EXPORT_SYMBOL(cnss_force_fw_assert); -void fw_boot_timeout(unsigned long data) -{ - struct cnss_plat_data *plat_priv = (struct cnss_plat_data *)data; - struct cnss_pci_data *pci_priv = plat_priv->bus_priv; - - cnss_pr_err("Timeout waiting for FW ready indication!\n"); - - cnss_schedule_recovery(&pci_priv->pci_dev->dev, - CNSS_REASON_TIMEOUT); -} - static int cnss_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data) { @@ -1731,7 +1643,7 @@ static void cnss_driver_event_work(struct work_struct *work) ret = cnss_wlfw_server_exit(plat_priv); break; case CNSS_DRIVER_EVENT_REQUEST_MEM: - ret = cnss_pci_alloc_fw_mem(plat_priv->bus_priv); + ret = cnss_bus_alloc_fw_mem(plat_priv); if (ret) break; ret = cnss_wlfw_respond_mem_send_sync(plat_priv); @@ -1760,7 +1672,7 @@ static void cnss_driver_event_work(struct work_struct *work) event->data); break; case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT: - ret = cnss_force_fw_assert_hdlr(plat_priv); + ret = cnss_bus_force_fw_assert_hdlr(plat_priv); break; case CNSS_DRIVER_EVENT_POWER_UP: ret = cnss_power_up_hdlr(plat_priv); @@ -2204,6 +2116,7 @@ static int cnss_probe(struct platform_device *plat_dev) plat_priv->plat_dev = plat_dev; plat_priv->device_id = device_id->driver_data; + plat_priv->bus_type = cnss_get_bus_type(plat_priv->device_id); cnss_set_plat_priv(plat_dev, plat_priv); platform_set_drvdata(plat_dev, plat_priv); @@ -2216,14 +2129,14 @@ static int cnss_probe(struct platform_device *plat_dev) if (ret) goto free_res; - ret = cnss_pci_init(plat_priv); + ret = cnss_bus_init(plat_priv); if (ret) goto power_off; } ret = cnss_register_esoc(plat_priv); if (ret) - goto deinit_pci; + goto deinit_bus; ret = cnss_register_bus_scale(plat_priv); if (ret) @@ -2245,8 +2158,8 @@ static int cnss_probe(struct platform_device *plat_dev) if (ret) goto deinit_qmi; - setup_timer(&plat_priv->fw_boot_timer, - fw_boot_timeout, (unsigned long)plat_priv); + setup_timer(&plat_priv->fw_boot_timer, cnss_bus_fw_boot_timeout_hdlr, + (unsigned long)plat_priv); register_pm_notifier(&cnss_pm_notifier); @@ -2272,9 +2185,9 @@ static int cnss_probe(struct platform_device *plat_dev) cnss_unregister_bus_scale(plat_priv); unreg_esoc: cnss_unregister_esoc(plat_priv); -deinit_pci: +deinit_bus: if (!test_bit(SKIP_DEVICE_BOOT, &quirks)) - cnss_pci_deinit(plat_priv); + cnss_bus_deinit(plat_priv); power_off: if (!test_bit(SKIP_DEVICE_BOOT, &quirks)) cnss_power_off_device(plat_priv); @@ -2301,7 +2214,7 @@ static int cnss_remove(struct platform_device *plat_dev) cnss_remove_sysfs(plat_priv); cnss_unregister_bus_scale(plat_priv); cnss_unregister_esoc(plat_priv); - cnss_pci_deinit(plat_priv); + cnss_bus_deinit(plat_priv); cnss_put_resources(plat_priv); platform_set_drvdata(plat_dev, NULL); plat_env = NULL; diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index b62c01446945..f27f3ea70511 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -173,6 +173,7 @@ struct cnss_pin_connect_result { struct cnss_plat_data { struct platform_device *plat_dev; void *bus_priv; + enum cnss_dev_bus_type bus_type; struct cnss_vreg_info *vreg_info; struct cnss_pinctrl_info pinctrl_info; struct cnss_subsys_info subsys_info; @@ -229,6 +230,5 @@ void cnss_unregister_subsys(struct cnss_plat_data *plat_priv); int cnss_register_ramdump(struct cnss_plat_data *plat_priv); void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv); void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv); -u32 cnss_get_wake_msi(struct cnss_plat_data *plat_priv); #endif /* _CNSS_MAIN_H */ diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 4726750a371d..b9efe4d8c838 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -19,6 +19,7 @@ #include #include "main.h" +#include "bus.h" #include "debug.h" #include "pci.h" @@ -43,6 +44,10 @@ #define MAX_M3_FILE_NAME_LENGTH 13 #define DEFAULT_M3_FILE_NAME "m3.bin" +#define WAKE_MSI_NAME "WAKE" + +#define FW_ASSERT_TIMEOUT 5000 + static DEFINE_SPINLOCK(pci_link_down_lock); static unsigned int pci_link_down_panic; @@ -592,18 +597,7 @@ static int cnss_pci_runtime_idle(struct device *dev) int cnss_wlan_pm_control(struct device *dev, bool vote) { - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); - struct cnss_pci_data *pci_priv; - struct pci_dev *pci_dev; - - if (!plat_priv) - return -ENODEV; - - pci_priv = plat_priv->bus_priv; - if (!pci_priv) - return -ENODEV; - - pci_dev = pci_priv->pci_dev; + struct pci_dev *pci_dev = to_pci_dev(dev); return msm_pcie_pm_control(vote ? MSM_PCIE_DISABLE_PC : MSM_PCIE_ENABLE_PC, @@ -615,19 +609,17 @@ EXPORT_SYMBOL(cnss_wlan_pm_control); int cnss_auto_suspend(struct device *dev) { int ret = 0; - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); - struct pci_dev *pci_dev; - struct cnss_pci_data *pci_priv; + struct pci_dev *pci_dev = to_pci_dev(dev); + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev); + struct cnss_plat_data *plat_priv; struct cnss_bus_bw_info *bus_bw_info; - if (!plat_priv) - return -ENODEV; - - pci_priv = plat_priv->bus_priv; if (!pci_priv) return -ENODEV; - pci_dev = pci_priv->pci_dev; + plat_priv = pci_priv->plat_priv; + if (!plat_priv) + return -ENODEV; if (pci_priv->pci_link_state) { if (cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_SUSPEND)) { @@ -673,19 +665,18 @@ EXPORT_SYMBOL(cnss_auto_suspend); int cnss_auto_resume(struct device *dev) { int ret = 0; - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); - struct pci_dev *pci_dev; - struct cnss_pci_data *pci_priv; + struct pci_dev *pci_dev = to_pci_dev(dev); + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev); + struct cnss_plat_data *plat_priv; struct cnss_bus_bw_info *bus_bw_info; - if (!plat_priv) + if (!pci_priv) return -ENODEV; - pci_priv = plat_priv->bus_priv; - if (!pci_priv) + plat_priv = pci_priv->plat_priv; + if (!plat_priv) return -ENODEV; - pci_dev = pci_priv->pci_dev; if (!pci_priv->pci_link_state) { cnss_pr_dbg("Resuming PCI link\n"); if (cnss_set_pci_link(pci_priv, PCI_LINK_UP)) { @@ -830,17 +821,58 @@ static void cnss_pci_free_m3_mem(struct cnss_pci_data *pci_priv) m3_mem->size = 0; } -int cnss_pci_get_bar_info(struct cnss_pci_data *pci_priv, void __iomem **va, - phys_addr_t *pa) +int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv) +{ + int ret; + struct cnss_plat_data *plat_priv; + + if (!pci_priv) + return -ENODEV; + + plat_priv = pci_priv->plat_priv; + if (!plat_priv) + return -ENODEV; + + ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_TRIGGER_RDDM); + if (ret) { + cnss_pr_err("Failed to trigger RDDM, err = %d\n", ret); + cnss_schedule_recovery(&pci_priv->pci_dev->dev, + CNSS_REASON_DEFAULT); + return 0; + } + + if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) { + mod_timer(&plat_priv->fw_boot_timer, + jiffies + msecs_to_jiffies(FW_ASSERT_TIMEOUT)); + } + + return 0; +} + +void cnss_pci_fw_boot_timeout_hdlr(struct cnss_pci_data *pci_priv) { + if (!pci_priv) + return; + + cnss_pr_err("Timeout waiting for FW ready indication\n"); + + cnss_schedule_recovery(&pci_priv->pci_dev->dev, + CNSS_REASON_TIMEOUT); +} + +int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info) +{ + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev)); + if (!pci_priv) return -ENODEV; - *va = pci_priv->bar; - *pa = pci_resource_start(pci_priv->pci_dev, PCI_BAR_NUM); + info->va = pci_priv->bar; + info->pa = pci_resource_start(pci_priv->pci_dev, PCI_BAR_NUM); return 0; } +EXPORT_SYMBOL(cnss_get_soc_info); static struct cnss_msi_config msi_config = { .total_vectors = 32, @@ -927,7 +959,7 @@ int cnss_get_user_msi_assignment(struct device *dev, char *user_name, int *num_vectors, u32 *user_base_data, u32 *base_vector) { - struct cnss_pci_data *pci_priv = dev_get_drvdata(dev); + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev)); struct cnss_msi_config *msi_config; int idx; @@ -986,6 +1018,25 @@ void cnss_get_msi_address(struct device *dev, u32 *msi_addr_low, } EXPORT_SYMBOL(cnss_get_msi_address); +u32 cnss_pci_get_wake_msi(struct cnss_pci_data *pci_priv) +{ + int ret, num_vectors; + u32 user_base_data, base_vector; + + if (!pci_priv) + return -ENODEV; + + ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev, + WAKE_MSI_NAME, &num_vectors, + &user_base_data, &base_vector); + if (ret) { + cnss_pr_err("WAKE MSI is not valid\n"); + return 0; + } + + return user_base_data; +} + static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv) { int ret = 0; diff --git a/drivers/net/wireless/cnss2/pci.h b/drivers/net/wireless/cnss2/pci.h index 4b2f6bcf0e3a..70cf445bdb32 100644 --- a/drivers/net/wireless/cnss2/pci.h +++ b/drivers/net/wireless/cnss2/pci.h @@ -21,16 +21,6 @@ #include "main.h" -#define QCA6174_VENDOR_ID 0x168C -#define QCA6174_DEVICE_ID 0x003E -#define QCA6174_REV_ID_OFFSET 0x08 -#define QCA6174_REV3_VERSION 0x5020000 -#define QCA6174_REV3_2_VERSION 0x5030000 -#define QCA6290_VENDOR_ID 0x17CB -#define QCA6290_DEVICE_ID 0x1100 -#define QCA6290_EMULATION_VENDOR_ID 0x168C -#define QCA6290_EMULATION_DEVICE_ID 0xABCD - enum cnss_mhi_state { CNSS_MHI_INIT, CNSS_MHI_DEINIT, @@ -130,8 +120,6 @@ int cnss_pci_init(struct cnss_plat_data *plat_priv); void cnss_pci_deinit(struct cnss_plat_data *plat_priv); int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv); int cnss_pci_load_m3(struct cnss_pci_data *pci_priv); -int cnss_pci_get_bar_info(struct cnss_pci_data *pci_priv, void __iomem **va, - phys_addr_t *pa); int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv, enum cnss_mhi_state state); int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv); @@ -139,5 +127,8 @@ void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv); void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic); void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv); int cnss_pm_request_resume(struct cnss_pci_data *pci_priv); +u32 cnss_pci_get_wake_msi(struct cnss_pci_data *pci_priv); +int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv); +void cnss_pci_fw_boot_timeout_hdlr(struct cnss_pci_data *pci_priv); #endif /* _CNSS_PCI_H */ diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index b8777c18d252..222a131796b8 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -15,8 +15,9 @@ #include #include -#include "main.h" +#include "bus.h" #include "debug.h" +#include "main.h" #include "qmi.h" #define WLFW_SERVICE_INS_ID_V01 1 @@ -163,7 +164,7 @@ static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv) req.num_clients = daemon_support ? 2 : 1; cnss_pr_dbg("Number of clients is %d\n", req.num_clients); - req.wake_msi = cnss_get_wake_msi(plat_priv); + req.wake_msi = cnss_bus_get_wake_irq(plat_priv); if (req.wake_msi) { cnss_pr_dbg("WAKE MSI base data is %d\n", req.wake_msi); req.wake_msi_valid = 1; -- GitLab From f72cd450ab0a1f3e07da34ee4c373dfa9951003f Mon Sep 17 00:00:00 2001 From: Ram Chandrasekar Date: Thu, 2 Apr 2015 10:44:57 -0600 Subject: [PATCH 767/855] leds: led-class: Retain the latest user brightness request Retain the latest user brightness request. This ensures that when a max brightness limit is altered, the last brightness request is taken into account, when restoring the current brightness. Change-Id: I6461e06f64abe336cabc27a3992d734f1fb745c6 Signed-off-by: Ram Chandrasekar --- drivers/leds/led-class.c | 3 ++- include/linux/leds.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 4dd225ce9b7d..2522a3dc7035 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -56,6 +56,7 @@ static ssize_t brightness_store(struct device *dev, if (state == LED_OFF && !(led_cdev->flags & LED_KEEP_TRIGGER)) led_trigger_remove(led_cdev); led_set_brightness(led_cdev, state); + led_cdev->usr_brightness_req = state; ret = size; unlock: @@ -84,7 +85,7 @@ static ssize_t max_brightness_store(struct device *dev, return ret; led_cdev->max_brightness = state; - led_set_brightness(led_cdev, led_cdev->brightness); + led_set_brightness(led_cdev, led_cdev->usr_brightness_req); return size; } diff --git a/include/linux/leds.h b/include/linux/leds.h index 66a1f4e865e7..b27315c80d8e 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -35,6 +35,7 @@ struct led_classdev { const char *name; enum led_brightness brightness; enum led_brightness max_brightness; + enum led_brightness usr_brightness_req; int flags; /* Lower 16 bits reflect status */ -- GitLab From 7e3b688bbeb00ea2f76e174dd56431d72f093087 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Sun, 10 Jun 2018 18:34:58 +0530 Subject: [PATCH 768/855] ARM: dts: msm: Move QRD-specific device property for SDM439 Move general QRD-specific DT entry from SDM439 dts files to common dtsi file. Change-Id: I1c832d3005a4eab12f56494a250bfeddc872a7b2 Signed-off-by: Jishnu Prakash --- arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-qrd.dts | 7 ------- arch/arm64/boot/dts/qcom/sdm439-qrd.dts | 7 ------- arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi | 6 ++++++ 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-qrd.dts b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-qrd.dts index 71157e2f4282..2bad28b3a966 100644 --- a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-qrd.dts +++ b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm439-qrd.dts @@ -22,10 +22,3 @@ qcom,board-id = <0xb 2>; qcom,pmic-id = <0x010016 0x25 0x0 0x0>; }; - -&pmi632_vadc { - chan@4a { - qcom,scale-function = <22>; - }; -}; - diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dts b/arch/arm64/boot/dts/qcom/sdm439-qrd.dts index b8a9f2b3661b..4a2fbffe2588 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dts @@ -22,10 +22,3 @@ qcom,board-id = <0xb 2>; qcom,pmic-id = <0x010016 0x25 0x0 0x0>; }; - -&pmi632_vadc { - chan@4a { - qcom,scale-function = <22>; - }; -}; - diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi index 5097b7f5ea58..c58f1f535adb 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi @@ -330,6 +330,12 @@ #include "smb1355.dtsi" }; +&pmi632_vadc { + chan@4a { + qcom,scale-function = <22>; + }; +}; + &pmi632_gpios { smb_en { smb_en_default: smb_en_default { -- GitLab From 41817677c505d5d2201e07fe22fa9a713e9498cd Mon Sep 17 00:00:00 2001 From: Meera Gande Date: Fri, 2 Mar 2018 15:02:36 +0530 Subject: [PATCH 769/855] msm:camera:isp: Remove unwanted register update At some cases, if register update is not issued from user space, due to the register update at frame drop config, partial settings may be applied. Remove the unwanted register update at frame drop configuration. Change-Id: I717a6c29ae997a3702510f41ef833ec72053b3df Signed-off-by: Meera Gande --- drivers/media/platform/msm/camera_v2/isp/msm_isp40.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index 19b1aaca3d4f..72ab3bad7c3c 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -889,8 +889,6 @@ static void msm_vfe40_cfg_framedrop(struct vfe_device *vfe_dev, msm_camera_io_w(temp | (framedrop_period - 1) << 2, vfe_base + VFE40_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC); } - - msm_camera_io_w_mb(0x1, vfe_base + 0x378); } static void msm_vfe40_clear_framedrop(struct vfe_device *vfe_dev, -- GitLab From 20ca0134e4c7aecfe6ac6253c49912ce4bbd5f7a Mon Sep 17 00:00:00 2001 From: Venkata Prahlad Valluru Date: Fri, 25 May 2018 11:34:27 +0530 Subject: [PATCH 770/855] ARM: dts: msm: Add synaptics lpm setting for MSM8909w BG Set the low power current setting for i2c bus. Change-Id: Iaba69bc0484fe8c6a1e95daeb20930ea4b5d8398 Signed-off-by: Venkata Prahlad Valluru --- arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts index 3a420170d99e..255c146e7fbb 100644 --- a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts @@ -54,6 +54,8 @@ synaptics,power-delay-ms = <200>; synaptics,reset-delay-ms = <200>; synaptics,max-y-for-2d = <389>; + synaptics,bus-lpm-cur-uA = <450>; + synaptics,do-not-disable-regulators; synaptics,wakeup-gestures-en; synaptics,resume-in-workqueue; synaptics,x-flip; -- GitLab From c4805881564dc112499e35c4a29fe90568c944a1 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Fri, 18 May 2018 14:31:02 +0530 Subject: [PATCH 771/855] msm: camera: Version changes for new csid on MSM8917 MSM8917 uses a new version of csid. Adding new configuration file and making necessary driver changes for that. Change-Id: I8dff24219b61da9c2ea837d248cbd47eea4abf6b Signed-off-by: Abhishek Jain --- .../csid/include/msm_csid_3_4_3_hwreg.h | 63 +++++++++++++++++++ .../msm/camera_v2/sensor/csid/msm_csid.c | 8 +++ 2 files changed, 71 insertions(+) create mode 100644 drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_3_hwreg.h diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_3_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_3_hwreg.h new file mode 100644 index 000000000000..ac0a989a2b05 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_3_hwreg.h @@ -0,0 +1,63 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MSM_CSID_3_4_3_HWREG_H +#define MSM_CSID_3_4_3_HWREG_H + +#include + +static uint8_t csid_lane_assign_v3_4_3[PHY_LANE_MAX] = {0, 4, 1, 2, 3}; +static struct csid_reg_parms_t csid_v3_4_3 = { + /* MIPI CSID registers */ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x14, + 0x18, + 0x1C, + 0x20, + 0x60, + 0x64, + 0x68, + 0x6C, + 0x70, + 0x74, + 0x78, + 0x7C, + 0x80, + 0x84, + 0x88, + 0x8C, + 0x90, + 0x94, + 0x98, + 0xA0, + 0xA4, + 0xAC, + 0xB0, + 0xB4, + 11, + 0x7FFF, + 0x4, + 17, + 0x30040003, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x7f010800, + 20, + 0xFFFFFFFF, + 0xFFFFFFFF, +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c index d5e79897f73c..9d3184ee38e0 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c @@ -26,6 +26,7 @@ #include "include/msm_csid_3_5_hwreg.h" #include "include/msm_csid_3_4_1_hwreg.h" #include "include/msm_csid_3_4_2_hwreg.h" +#include "include/msm_csid_3_4_3_hwreg.h" #include "include/msm_csid_3_6_0_hwreg.h" #include "include/msm_csid_3_5_1_hwreg.h" #include "cam_hw_ops.h" @@ -42,6 +43,7 @@ #define CSID_VERSION_V34 0x30040000 #define CSID_VERSION_V34_1 0x30040001 #define CSID_VERSION_V34_2 0x30040002 +#define CSID_VERSION_V34_3 0x30040003 #define CSID_VERSION_V36 0x30060000 #define CSID_VERSION_V37 0x30070000 #define CSID_VERSION_V35 0x30050000 @@ -1178,6 +1180,12 @@ static int csid_probe(struct platform_device *pdev) new_csid_dev->hw_dts_version = CSID_VERSION_V34_2; new_csid_dev->ctrl_reg->csid_lane_assign = csid_lane_assign_v3_4_2; + } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v3.4.3")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v3_4_3; + new_csid_dev->hw_dts_version = CSID_VERSION_V34_3; + new_csid_dev->ctrl_reg->csid_lane_assign = + csid_lane_assign_v3_4_3; } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, "qcom,csid-v3.6.0")) { new_csid_dev->ctrl_reg->csid_reg = csid_v3_6_0; -- GitLab From a50fb861e42f5b1b2632c6f5a903c13da1aa0b19 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Mon, 11 Jun 2018 17:56:53 +0530 Subject: [PATCH 772/855] ARM: dts: msm: update SMB1355 stat gpio for SDM439 SMB1355 stat pin is connected to MSM GPIO61 on SDM439 platform. Change-Id: I52ca39cab0b93f4093bf676f4f1914796a44d86c Signed-off-by: Ashay Jaiswal --- arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi | 8 ++++---- arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi index 7a61a7aedf56..a9405157be3a 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi @@ -570,11 +570,11 @@ &tlmm { smb_int_default: smb_int_default { mux { - pins = "gpio59"; + pins = "gpio61"; function = "gpio"; }; config { - pins = "gpio59"; + pins = "gpio61"; drive-strength = <2>; bias-pull-up; input-enable; @@ -587,7 +587,7 @@ pinctrl-0 = <&smb_int_default &smb_en_default &pmi632_sense_default>; interrupt-parent = <&tlmm>; - interrupts = <59 IRQ_TYPE_LEVEL_LOW>; + interrupts = <61 IRQ_TYPE_LEVEL_LOW>; smb1355_charger_0: qcom,smb1355-charger@1000 { status ="ok"; /delete-property/ io-channels; @@ -601,7 +601,7 @@ pinctrl-0 = <&smb_int_default &smb_en_default &pmi632_sense_default>; interrupt-parent = <&tlmm>; - interrupts = <59 IRQ_TYPE_LEVEL_LOW>; + interrupts = <61 IRQ_TYPE_LEVEL_LOW>; smb1355_charger_1: qcom,smb1355-charger@1000 { status ="ok"; /delete-property/ io-channels; diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi index 5097b7f5ea58..b637e3fe903e 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi @@ -352,11 +352,11 @@ &tlmm { smb_int_default: smb_int_default { mux { - pins = "gpio59"; + pins = "gpio61"; function = "gpio"; }; config { - pins = "gpio59"; + pins = "gpio61"; drive-strength = <2>; bias-pull-up; input-enable; @@ -369,7 +369,7 @@ pinctrl-0 = <&smb_int_default &smb_en_default &pmi632_sense_default>; interrupt-parent = <&tlmm>; - interrupts = <59 IRQ_TYPE_LEVEL_LOW>; + interrupts = <61 IRQ_TYPE_LEVEL_LOW>; smb1355_charger_0: qcom,smb1355-charger@1000 { status ="ok"; /delete-property/ io-channels; @@ -383,7 +383,7 @@ pinctrl-0 = <&smb_int_default &smb_en_default &pmi632_sense_default>; interrupt-parent = <&tlmm>; - interrupts = <59 IRQ_TYPE_LEVEL_LOW>; + interrupts = <61 IRQ_TYPE_LEVEL_LOW>; smb1355_charger_1: qcom,smb1355-charger@1000 { status ="ok"; /delete-property/ io-channels; -- GitLab From ad3dec4ad6150ed37ee98cd94e3a7268cc04866d Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Wed, 6 Jun 2018 17:21:49 -0700 Subject: [PATCH 773/855] usb_bam: Get source bam size to map into USB CB For USB QDSS BAM2BAM usecase when USB is using SMMU S1 functionality, it is required to map QDSS BAM device register address space into USB context bank. Currently USB BAM device register address space is used instead of QDSS BAM device which results into garbage data with this usecase although QDSS is not generating any data. Fix this issue by mapping QDSS BAM device register address space. Change-Id: I66c46513865a0acf21c28bba242845e52fbd7d67 Signed-off-by: Mayank Rana --- drivers/platform/msm/usb_bam.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c index 9374bc8475ad..aafb5c8ede8a 100644 --- a/drivers/platform/msm/usb_bam.c +++ b/drivers/platform/msm/usb_bam.c @@ -1119,7 +1119,7 @@ int get_qdss_bam_info(enum usb_ctrl cur_bam, u8 idx, &ctx->usb_bam_connections[idx]; unsigned long peer_bam_handle; - ret = sps_phy2h(pipe_connect->dst_phy_addr, &peer_bam_handle); + ret = sps_phy2h(pipe_connect->src_phy_addr, &peer_bam_handle); if (ret) { log_event_err("%s: sps_phy2h failed (src BAM) %d\n", __func__, ret); -- GitLab From 6a719aeb64486f4a78fa8511b8183f8937474861 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Mon, 11 Jun 2018 22:44:14 +0530 Subject: [PATCH 774/855] msm: mhi_dev: Make MHI channel state callback trigger per-channel Trigger the MHI channel state callback only for the channel whose state has changed. Change-Id: Ieb7be2d4429884cd30f5367122dfba9385878c85 Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/mhi_dev/mhi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index f06d6f34b926..ab43d326bc07 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -824,13 +824,13 @@ int mhi_dev_send_ee_event(struct mhi_dev *mhi, enum mhi_dev_execenv exec_env) } EXPORT_SYMBOL(mhi_dev_send_ee_event); -static void mhi_dev_trigger_cb(void) +static void mhi_dev_trigger_cb(enum mhi_client_channel ch_id) { struct mhi_dev_ready_cb_info *info; enum mhi_ctrl_info state_data; list_for_each_entry(info, &mhi_ctx->client_cb_list, list) - if (info->cb) { + if (info->cb && info->cb_data.channel == ch_id) { mhi_ctrl_state_info(info->cb_data.channel, &state_data); info->cb_data.ctrl_info = state_data; info->cb(&info->cb_data); @@ -1023,7 +1023,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, mhi_update_state_info(ch_id, MHI_STATE_CONNECTED); /* Trigger callback to clients */ - mhi_dev_trigger_cb(); + mhi_dev_trigger_cb(ch_id); if (ch_id == MHI_CLIENT_MBIM_OUT) kobject_uevent_env(&mhi_ctx->dev->kobj, KOBJ_CHANGE, connected); -- GitLab From e5d5d317141f545fb8451a1b7031dfd2feabad93 Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Wed, 6 Jun 2018 12:26:48 -0700 Subject: [PATCH 775/855] msm: ipa: Validate pdn_idx on modify_flt_rule Replace the incomplete validate code on ipa_mdfy_flt_rule with the already present ipa_validate function which is checks for pdn_idx and is more complete. Change-Id: Icfbd0c24ee832ce7c7a7af079219cbdf0c455b60 Crs-fixed: 2250028 Signed-off-by: Michael Adisumarta --- drivers/platform/msm/ipa/ipa_v3/ipa_flt.c | 35 ++--------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c index 6703bf5b957e..b0901515b47e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c @@ -1014,41 +1014,12 @@ static int __ipa_mdfy_flt_rule(struct ipa_flt_rule_mdfy *frule, goto error; } + if (__ipa_validate_flt_rule(&frule->rule, &rt_tbl, ip)) + goto error; + if (entry->rt_tbl) entry->rt_tbl->ref_cnt--; - if (frule->rule.action != IPA_PASS_TO_EXCEPTION) { - if (!frule->rule.eq_attrib_type) { - if (!frule->rule.rt_tbl_hdl) { - IPAERR_RL("invalid RT tbl\n"); - goto error; - } - - rt_tbl = ipa3_id_find(frule->rule.rt_tbl_hdl); - if (rt_tbl == NULL) { - IPAERR_RL("RT tbl not found\n"); - goto error; - } - - if (rt_tbl->cookie != IPA_RT_TBL_COOKIE) { - IPAERR_RL("RT table cookie is invalid\n"); - goto error; - } - } else { - if (frule->rule.rt_tbl_idx > ((ip == IPA_IP_v4) ? - IPA_MEM_PART(v4_modem_rt_index_hi) : - IPA_MEM_PART(v6_modem_rt_index_hi))) { - IPAERR_RL("invalid RT tbl\n"); - goto error; - } - } - } else { - if (frule->rule.rt_tbl_idx > 0) { - IPAERR_RL("invalid RT tbl\n"); - goto error; - } - } - entry->rule = frule->rule; entry->rt_tbl = rt_tbl; if (entry->rt_tbl) -- GitLab From cfb6064e8d7c87f76e05aeb63ced6f3d5fb58e50 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Mon, 30 Apr 2018 12:40:25 -0700 Subject: [PATCH 776/855] drm/msm/sde: remove frame done wait from sde_crtc SDE crtc module waits for previous frame done before it triggers a new frame. This is unnecessary because sde encoder has similar wait already within prepare_kickoff API call. This patch avoids extra frame done wait and only flush the event thread to trigger pending fences. Change-Id: I45b6dcd5ec39491303fe29eaaf41988a68f48465 Signed-off-by: Dhaval Patel --- drivers/gpu/drm/msm/sde/sde_crtc.c | 51 ++++++------------------------ drivers/gpu/drm/msm/sde/sde_crtc.h | 2 -- 2 files changed, 9 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index f5c24e2e9a0c..29593dd3d175 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -2380,7 +2380,6 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) struct sde_crtc *sde_crtc; struct sde_kms *sde_kms; unsigned long flags; - bool frame_done = false; bool in_clone_mode = false; if (!work) { @@ -2435,10 +2434,6 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) SDE_EVT32_VERBOSE(DRMID(crtc), fevent->event, SDE_EVTLOG_FUNC_CASE3); } - - if (fevent->event & (SDE_ENCODER_FRAME_EVENT_DONE - | SDE_ENCODER_FRAME_EVENT_ERROR)) - frame_done = true; } if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE) { @@ -2459,9 +2454,6 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) SDE_ERROR("crtc%d ts:%lld received panel dead event\n", crtc->base.id, ktime_to_ns(fevent->ts)); - if (frame_done) - complete_all(&sde_crtc->frame_done_comp); - spin_lock_irqsave(&sde_crtc->spin_lock, flags); list_add_tail(&fevent->list, &sde_crtc->frame_event_list); spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); @@ -3341,10 +3333,10 @@ static void sde_crtc_destroy_state(struct drm_crtc *crtc, &cstate->property_state); } -static int _sde_crtc_wait_for_frame_done(struct drm_crtc *crtc) +static int _sde_crtc_flush_event_thread(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc; - int ret, rc = 0, i; + int i; if (!crtc) { SDE_ERROR("invalid argument\n"); @@ -3368,17 +3360,9 @@ static int _sde_crtc_wait_for_frame_done(struct drm_crtc *crtc) kthread_flush_work(&sde_crtc->frame_events[i].work); } - ret = wait_for_completion_timeout(&sde_crtc->frame_done_comp, - msecs_to_jiffies(SDE_FRAME_DONE_TIMEOUT)); - if (!ret) { - SDE_ERROR("frame done completion wait timed out, ret:%d\n", - ret); - SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FATAL); - rc = -ETIMEDOUT; - } SDE_EVT32_VERBOSE(DRMID(crtc), SDE_EVTLOG_FUNC_EXIT); - return rc; + return 0; } static int _sde_crtc_commit_kickoff_rot(struct drm_crtc *crtc, @@ -3705,7 +3689,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, struct sde_kms *sde_kms; struct sde_crtc_state *cstate; bool is_error, reset_req; - int ret; if (!crtc) { SDE_ERROR("invalid argument\n"); @@ -3764,23 +3747,11 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, } sde_crtc->reset_request = reset_req; - /* wait for frame_event_done completion */ - SDE_ATRACE_BEGIN("wait_for_frame_done_event"); - ret = _sde_crtc_wait_for_frame_done(crtc); - SDE_ATRACE_END("wait_for_frame_done_event"); + SDE_ATRACE_BEGIN("flush_event_thread"); + _sde_crtc_flush_event_thread(crtc); + SDE_ATRACE_END("flush_event_thread"); sde_crtc_calc_fps(sde_crtc); - if (ret) { - SDE_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", - crtc->base.id, - atomic_read(&sde_crtc->frame_pending)); - - is_error = true; - - /* force offline rotation mode since the commit has no pipes */ - cstate->sbuf_cfg.rot_op_mode = SDE_CTL_ROT_OP_MODE_OFFLINE; - } - if (atomic_inc_return(&sde_crtc->frame_pending) == 1) { /* acquire bandwidth and other resources */ SDE_DEBUG("crtc%d first commit\n", crtc->base.id); @@ -3818,7 +3789,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, sde_encoder_kickoff(encoder, false); } - reinit_completion(&sde_crtc->frame_done_comp); SDE_ATRACE_END("crtc_commit"); return; } @@ -4219,11 +4189,7 @@ static void sde_crtc_disable(struct drm_crtc *crtc) if (cstate->num_ds_enabled) sde_crtc->ds_reconfig = true; - /* wait for frame_event_done completion */ - if (_sde_crtc_wait_for_frame_done(crtc)) - SDE_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", - crtc->base.id, - atomic_read(&sde_crtc->frame_pending)); + _sde_crtc_flush_event_thread(crtc); SDE_EVT32(DRMID(crtc), sde_crtc->enabled, sde_crtc->suspend, sde_crtc->vblank_requested, @@ -4238,6 +4204,8 @@ static void sde_crtc_disable(struct drm_crtc *crtc) sde_crtc->enabled = false; if (atomic_read(&sde_crtc->frame_pending)) { + SDE_ERROR("crtc%d frame_pending%d\n", crtc->base.id, + atomic_read(&sde_crtc->frame_pending)); SDE_EVT32(DRMID(crtc), atomic_read(&sde_crtc->frame_pending), SDE_EVTLOG_FUNC_CASE2); sde_core_perf_crtc_release_bw(crtc); @@ -6097,7 +6065,6 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) mutex_init(&sde_crtc->rp_lock); INIT_LIST_HEAD(&sde_crtc->rp_head); - init_completion(&sde_crtc->frame_done_comp); sde_crtc->enabled = false; INIT_LIST_HEAD(&sde_crtc->frame_event_list); diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index c02a81ea1b1e..99177b111745 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -190,7 +190,6 @@ struct sde_crtc_fps_info { * @frame_events : static allocation of in-flight frame events * @frame_event_list : available frame event list * @spin_lock : spin lock for frame event, transaction status, etc... - * @frame_done_comp : for frame_event_done synchronization * @event_thread : Pointer to event handler thread * @event_worker : Event worker queue * @event_cache : Local cache of event worker structures @@ -262,7 +261,6 @@ struct sde_crtc { struct sde_crtc_frame_event frame_events[SDE_CRTC_FRAME_EVENT_SIZE]; struct list_head frame_event_list; spinlock_t spin_lock; - struct completion frame_done_comp; /* for handling internal event thread */ struct sde_crtc_event event_cache[SDE_CRTC_MAX_EVENT_COUNT]; -- GitLab From 891486d3dd5dcc70ccb95e4e76aab11523eca605 Mon Sep 17 00:00:00 2001 From: Pengfei Liu Date: Tue, 22 May 2018 17:33:17 +0800 Subject: [PATCH 777/855] ARM: dts: msm: Add camera node in sda670 hdk platform Add sensor eeprom actuator node for camera in sda670 hdk platform. Change-Id: Ic83923a3c5a5dad4ce0e7548b1996b7855e850ae Signed-off-by: Pengfei Liu --- .../dts/qcom/sda670-camera-sensor-hdk.dtsi | 412 ++++++++++++++++++ arch/arm64/boot/dts/qcom/sda670-hdk.dtsi | 1 + 2 files changed, 413 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sda670-camera-sensor-hdk.dtsi diff --git a/arch/arm64/boot/dts/qcom/sda670-camera-sensor-hdk.dtsi b/arch/arm64/boot/dts/qcom/sda670-camera-sensor-hdk.dtsi new file mode 100644 index 000000000000..484ed64da63d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670-camera-sensor-hdk.dtsi @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + com,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm660l_flash0 &pm660l_flash1>; + torch-source = <&pm660l_torch0 &pm660l_torch1>; + switch-source = <&pm660l_switch0>; + status = "ok"; + }; + + qcom,camera-flash@1 { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm660l_flash0 &pm660l_flash1>; + torch-source = <&pm660l_torch0 &pm660l_torch1>; + switch-source = <&pm660l_switch0>; + status = "ok"; + }; + + led_flash_front: qcom,camera-flash@2 { + cell-index = <2>; + reg = <0x02 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm660l_flash2>; + torch-source = <&pm660l_torch2>; + switch-source = <&pm660l_switch1>; + status = "ok"; + }; + + gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "actuator_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <100>; + enable-active-high; + gpio = <&tlmm 27 0>; + }; + + camera_ldo: gpio-regulator@2 { + compatible = "regulator-fixed"; + reg = <0x02 0x00>; + regulator-name = "camera_ldo"; + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm660l_gpios 3 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_dvdd_en_default>; + vin-supply = <&pm660_s6>; + }; + + camera_rear_ldo: gpio-regulator@1 { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "camera_rear_ldo"; + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&pm660l_gpios 4 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_rear_dvdd_en_default>; + vin-supply = <&pm660_s6>; + }; + + camera_vio_ldo: gpio-regulator@3 { + compatible = "regulator-fixed"; + reg = <0x03 0x00>; + regulator-name = "camera_vio_ldo"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&tlmm 29 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_rear_vio>; + vin-supply = <&pm660_s4>; + }; + + camera_vana_ldo: gpio-regulator@4 { + compatible = "regulator-fixed"; + reg = <0x04 0x00>; + regulator-name = "camera_vana_ldo"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&tlmm 8 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_rear_vana>; + vin-supply = <&pm660l_bob>; + }; +}; + +&cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + + qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + qcom,actuator@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + ois_rear: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + status = "disabled"; + }; + + qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0 2800000>; + rgltr-max-voltage = <1352000 1800000 2850000 0 2800000>; + rgltr-load-current = <105000 0 80000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0 2800000>; + rgltr-max-voltage = <1352000 1800000 2850000 0 2800000>; + rgltr-load-current = <105000 0 80000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + ois-src = <&ois_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0>; + rgltr-max-voltage = <1800000 2850000 1352000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear_aux>; + actuator-src = <&actuator_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + led-flash-src = <&led_flash_front>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi b/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi index 4daf8b4edd9a..8471d11ffca9 100644 --- a/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi +++ b/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi @@ -11,6 +11,7 @@ */ #include "sdm670-qrd.dtsi" #include "sdm670-external-codec.dtsi" +#include "sda670-camera-sensor-hdk.dtsi" &dsi_dual_nt36850_truly_cmd_display { /delete-property/ qcom,dsi-display-active; -- GitLab From 4c6d848d010f331f1568cdc79c81a1ccf35ffa62 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Tue, 5 Jun 2018 20:58:13 +0800 Subject: [PATCH 778/855] coresight: etm: Add check of trace unit power property Add check of trace unit power property to enable/disable that keep the trace unit powered. Change-Id: I66dbfee16df63480c9309092e61ee39b8b0cd6e8 Signed-off-by: Mao Jinlong --- .../devicetree/bindings/arm/coresight.txt | 3 ++ drivers/hwtracing/coresight/coresight-etm4x.c | 28 ++++++++++++------- drivers/hwtracing/coresight/coresight-etm4x.h | 4 ++- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index 3a966104a258..ee9b46517fdf 100644 --- a/Documentation/devicetree/bindings/arm/coresight.txt +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -110,6 +110,9 @@ its hardware characteristcs. * cpu: the cpu phandle this ETM/PTM is affined to. When omitted the source is considered to belong to CPU0. + * qcom,tupwr-disable: For ETM, don't keep trace unit powered across power + collapse. + * Optional property for TMC: * arm,buffer-size: size of contiguous buffer space for TMC ETR diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index 5db74f0e9ec3..95d13a9d3989 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -167,12 +168,14 @@ static void etm4_enable_hw(void *info) writel_relaxed(config->vmid_mask0, drvdata->base + TRCVMIDCCTLR0); writel_relaxed(config->vmid_mask1, drvdata->base + TRCVMIDCCTLR1); - /* - * Request to keep the trace unit powered and also - * emulation of powerdown - */ - writel_relaxed(readl_relaxed(drvdata->base + TRCPDCR) | TRCPDCR_PU, - drvdata->base + TRCPDCR); + if (!drvdata->tupwr_disable) { + /* + * Request to keep the trace unit powered and also + * emulation of powerdown + */ + writel_relaxed(readl_relaxed(drvdata->base + TRCPDCR) + | TRCPDCR_PU, drvdata->base + TRCPDCR); + } /* Enable the trace unit */ writel_relaxed(1, drvdata->base + TRCPRGCTLR); @@ -313,10 +316,12 @@ static void etm4_disable_hw(void *info) CS_UNLOCK(drvdata->base); - /* power can be removed from the trace unit now */ - control = readl_relaxed(drvdata->base + TRCPDCR); - control &= ~TRCPDCR_PU; - writel_relaxed(control, drvdata->base + TRCPDCR); + if (!drvdata->tupwr_disable) { + /* power can be removed from the trace unit now */ + control = readl_relaxed(drvdata->base + TRCPDCR); + control &= ~TRCPDCR_PU; + writel_relaxed(control, drvdata->base + TRCPDCR); + } control = readl_relaxed(drvdata->base + TRCPRGCTLR); @@ -1041,6 +1046,9 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id) etmdrvdata[drvdata->cpu] = drvdata; + drvdata->tupwr_disable = of_property_read_bool(drvdata->dev->of_node, + "qcom,tupwr-disable"); + dev_info(dev, "CPU%d: %s initialized\n", drvdata->cpu, (char *)id->data); diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index 4e51ecdca219..5f34bdc4599e 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -345,6 +345,7 @@ struct etmv4_config { * @nooverflow: Indicate if overflow prevention is supported. * @atbtrig: If the implementation can support ATB triggers * @lpoverride: If the implementation can support low-power state over. + * @tupwr_disable: If disable the support of keeping trace unit powered. * @config: structure holding configuration parameters. */ struct etmv4_drvdata { @@ -391,6 +392,7 @@ struct etmv4_drvdata { bool nooverflow; bool atbtrig; bool lpoverride; + bool tupwr_disable; struct etmv4_config config; }; -- GitLab From ad0f296e4aacc84cc2db654f5a7a58780773fab0 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Mon, 4 Jun 2018 13:49:56 +0800 Subject: [PATCH 779/855] Fingerprint: fix potential null pointer dereference issue The pointer of two-dimensional array which may cause some null pointer dereference. eg..fpc1020->pinctrl_state[1] is not initialized by default, although fpc1020->pinctrl_state is initialized by default. Use one dimensional array pointer to fix the issue. Change-Id: Ib36abe2ec60c1e5d5636471bec6c11f482313814 Signed-off-by: Can Guo --- drivers/misc/fpr_FingerprintCard/fpc1020_platform_tee.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/fpr_FingerprintCard/fpc1020_platform_tee.c b/drivers/misc/fpr_FingerprintCard/fpc1020_platform_tee.c index 887c8eb2f9ee..a6ed374e5b8e 100644 --- a/drivers/misc/fpr_FingerprintCard/fpc1020_platform_tee.c +++ b/drivers/misc/fpr_FingerprintCard/fpc1020_platform_tee.c @@ -75,8 +75,8 @@ static const struct vreg_config vreg_conf[] = { struct fpc1020_data { struct device *dev; struct pinctrl *fingerprint_pinctrl; - struct pinctrl_state **pinctrl_state; - struct regulator **vreg; + struct pinctrl_state *pinctrl_state[ARRAY_SIZE(pctl_names)]; + struct regulator *vreg[ARRAY_SIZE(vreg_conf)]; struct wakeup_source ttw_wl; struct mutex lock; /* To set/get exported values in sysfs */ int irq_gpio; -- GitLab From 7f6212ff582c1e7121db3acb59a9a04127b9e4fa Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Tue, 12 Jun 2018 09:00:58 +0530 Subject: [PATCH 780/855] power: qpnp-qg: Fix SDAM base offset for OCV The SDAM OCV offset was incorrect, fix it. While at it, fix minor print errors in qg-sdam. Change-Id: Iaabf3de46ed72e33980d1e3e386e8ca0ae651c75 Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qg-reg.h | 4 +++- drivers/power/supply/qcom/qg-sdam.c | 13 +++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h index d586a721d8b7..88572ca5d3bd 100644 --- a/drivers/power/supply/qcom/qg-reg.h +++ b/drivers/power/supply/qcom/qg-reg.h @@ -105,6 +105,8 @@ #define QG_SDAM_ESR_DISCHARGE_DELTA_OFFSET 0x6E /* 4-byte 0x6E-0x71 */ #define QG_SDAM_ESR_CHARGE_SF_OFFSET 0x72 /* 2-byte 0x72-0x73 */ #define QG_SDAM_ESR_DISCHARGE_SF_OFFSET 0x74 /* 2-byte 0x74-0x75 */ -#define QG_SDAM_PON_OCV_OFFSET 0x7C /* 2-byte 0x7C-0x7D */ + +/* Below offset is used by PBS */ +#define QG_SDAM_PON_OCV_OFFSET 0xBC /* 2-byte 0xBC-0xBD */ #endif diff --git a/drivers/power/supply/qcom/qg-sdam.c b/drivers/power/supply/qcom/qg-sdam.c index e7ffcb592dfb..a7cb97e0e53d 100644 --- a/drivers/power/supply/qcom/qg-sdam.c +++ b/drivers/power/supply/qcom/qg-sdam.c @@ -111,7 +111,7 @@ int qg_sdam_write(u8 param, u32 data) length = sdam_info[param].length; rc = regmap_bulk_write(chip->regmap, offset, (u8 *)&data, length); if (rc < 0) - pr_err("Failed to write offset=%0x4x param=%d value=%d\n", + pr_err("Failed to write offset=%0x4 param=%d value=%d\n", offset, param, data); else pr_debug("QG SDAM write param=%s value=%d\n", @@ -137,11 +137,12 @@ int qg_sdam_read(u8 param, u32 *data) return -EINVAL; } + *data = 0; offset = chip->sdam_base + sdam_info[param].offset; length = sdam_info[param].length; rc = regmap_raw_read(chip->regmap, offset, (u8 *)data, length); if (rc < 0) - pr_err("Failed to read offset=%0x4x param=%d\n", + pr_err("Failed to read offset=%0x4 param=%d\n", offset, param); else pr_debug("QG SDAM read param=%s value=%d\n", @@ -163,11 +164,11 @@ int qg_sdam_multibyte_write(u32 offset, u8 *data, u32 length) offset = chip->sdam_base + offset; rc = regmap_bulk_write(chip->regmap, offset, data, (size_t)length); if (rc < 0) { - pr_err("Failed to write offset=%0x4x value=%d\n", + pr_err("Failed to write offset=%0x4 value=%d\n", offset, *data); } else { for (i = 0; i < length; i++) - pr_debug("QG SDAM write offset=%0x4x value=%d\n", + pr_debug("QG SDAM write offset=%0x4 value=%d\n", offset++, data[i]); } @@ -187,10 +188,10 @@ int qg_sdam_multibyte_read(u32 offset, u8 *data, u32 length) offset = chip->sdam_base + offset; rc = regmap_raw_read(chip->regmap, offset, (u8 *)data, (size_t)length); if (rc < 0) { - pr_err("Failed to read offset=%0x4x\n", offset); + pr_err("Failed to read offset=%0x4\n", offset); } else { for (i = 0; i < length; i++) - pr_debug("QG SDAM read offset=%0x4x value=%d\n", + pr_debug("QG SDAM read offset=%0x4 value=%d\n", offset++, data[i]); } -- GitLab From 19c284109981287937ec5d89d168b01c9cbc882c Mon Sep 17 00:00:00 2001 From: Qiwei Liu Date: Tue, 15 May 2018 19:42:01 +0800 Subject: [PATCH 781/855] msm: vidc: refine instance info stats Add operating-rate and priority info when printing running instances info stats. CRs-Fixed: 2255248 Change-Id: I670caaf36f856568646600dc30db3c818ba7e1f5 Signed-off-by: Qiwei Liu --- .../media/platform/msm/vidc/msm_vidc_common.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 40c986211218..dca098fb6788 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -3154,10 +3154,11 @@ static int msm_comm_session_init(int flipped_state, static void msm_vidc_print_running_insts(struct msm_vidc_core *core) { struct msm_vidc_inst *temp; + int op_rate = 0; dprintk(VIDC_ERR, "Running instances:\n"); - dprintk(VIDC_ERR, "%4s|%4s|%4s|%4s|%4s\n", - "type", "w", "h", "fps", "prop"); + dprintk(VIDC_ERR, "%4s|%4s|%4s|%4s|%6s|%4s\n", + "type", "w", "h", "fps", "opr", "prop"); mutex_lock(&core->lock); list_for_each_entry(temp, &core->instances, list) { @@ -3171,13 +3172,21 @@ static void msm_vidc_print_running_insts(struct msm_vidc_core *core) if (msm_comm_turbo_session(temp)) strlcat(properties, "T", sizeof(properties)); - dprintk(VIDC_ERR, "%4d|%4d|%4d|%4d|%4s\n", + if (is_realtime_session(temp)) + strlcat(properties, "R", sizeof(properties)); + + if (temp->clk_data.operating_rate) + op_rate = temp->clk_data.operating_rate >> 16; + else + op_rate = temp->prop.fps; + + dprintk(VIDC_ERR, "%4d|%4d|%4d|%4d|%6d|%4s\n", temp->session_type, max(temp->prop.width[CAPTURE_PORT], temp->prop.width[OUTPUT_PORT]), max(temp->prop.height[CAPTURE_PORT], temp->prop.height[OUTPUT_PORT]), - temp->prop.fps, properties); + temp->prop.fps, op_rate, properties); } } mutex_unlock(&core->lock); -- GitLab From 630e245c05afb08b7ba7b340e2eea0d4d639e8c3 Mon Sep 17 00:00:00 2001 From: Swetha Chikkaboraiah Date: Fri, 1 Jun 2018 11:15:53 +0530 Subject: [PATCH 782/855] soc: qcom: socinfo: Add support for msm8917 soc-id Add support for getting soc-id and dummy handle on msm8917. Change-Id: Id5a5984b57d05ef7ecea9af4e6d604d0837a35bb Signed-off-by: Swetha Chikkaboraiah --- arch/arm/mach-qcom/board-msm8917.c | 1 + drivers/soc/qcom/socinfo.c | 10 ++++++++++ include/soc/qcom/socinfo.h | 4 ++++ 3 files changed, 15 insertions(+) diff --git a/arch/arm/mach-qcom/board-msm8917.c b/arch/arm/mach-qcom/board-msm8917.c index 63bc43bc64c6..0bd698459333 100644 --- a/arch/arm/mach-qcom/board-msm8917.c +++ b/arch/arm/mach-qcom/board-msm8917.c @@ -17,6 +17,7 @@ static const char *msm8917_dt_match[] __initconst = { "qcom,msm8917", + "qcom,apq8017", NULL }; diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 1ac30ebc3cee..0da784387462 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -618,6 +618,12 @@ static struct msm_soc_info cpu_of_id[] = { [294] = {MSM_CPU_8937, "MSM8937"}, [295] = {MSM_CPU_8937, "APQ8937"}, + /* MSM8917 IDs */ + [303] = {MSM_CPU_8917, "MSM8917"}, + [307] = {MSM_CPU_8917, "APQ8017"}, + [308] = {MSM_CPU_8917, "MSM8217"}, + [309] = {MSM_CPU_8917, "MSM8617"}, + /* SDM429 and SDM439 ID*/ [353] = {MSM_CPU_SDM439, "SDM439"}, [354] = {MSM_CPU_SDM429, "SDM429"}, @@ -1567,6 +1573,10 @@ static void * __init setup_dummy_socinfo(void) dummy_socinfo.id = 294; strlcpy(dummy_socinfo.build_id, "msm8937 - ", sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_msm8917()) { + dummy_socinfo.id = 303; + strlcpy(dummy_socinfo.build_id, "msm8917 - ", + sizeof(dummy_socinfo.build_id)); } else if (early_machine_is_sdm450()) { dummy_socinfo.id = 338; strlcpy(dummy_socinfo.build_id, "sdm450 - ", diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h index e7d42ce689e9..e2644e74b7fe 100644 --- a/include/soc/qcom/socinfo.h +++ b/include/soc/qcom/socinfo.h @@ -114,6 +114,8 @@ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8953") #define early_machine_is_msm8937() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8937") +#define early_machine_is_msm8917() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8917") #define early_machine_is_mdm9607() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,mdm9607") #define early_machine_is_sdm450() \ @@ -177,6 +179,7 @@ #define early_machine_is_sdm710() 0 #define early_machine_is_msm8953() 0 #define early_machine_is_msm8937() 0 +#define early_machine_is_msm8917() 0 #define early_machine_is_sdm450() 0 #define early_machine_is_sdm632() 0 #define early_machine_is_sdm439() 0 @@ -255,6 +258,7 @@ enum msm_cpu { MSM_CPU_SDM632, MSM_CPU_SDA632, MSM_CPU_8937, + MSM_CPU_8917, MSM_CPU_9607, MSM_CPU_SDM439, MSM_CPU_SDM429, -- GitLab From 75eeaa1b4af35c2c7ce5a5e7806a93906a54638f Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Fri, 18 May 2018 14:31:02 +0530 Subject: [PATCH 783/855] msm: camera: Version changes for new csid on MSM8917 MSM8917 uses a new version of csid. Adding new configuration file and making necessary driver changes for that. Change-Id: I8dff24219b61da9c2ea837d248cbd47eea4abf6b Signed-off-by: Abhishek Jain --- .../csid/include/msm_csid_3_4_3_hwreg.h | 63 +++++++++++++++++++ .../msm/camera_v2/sensor/csid/msm_csid.c | 8 +++ 2 files changed, 71 insertions(+) create mode 100644 drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_3_hwreg.h diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_3_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_3_hwreg.h new file mode 100644 index 000000000000..ac0a989a2b05 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_4_3_hwreg.h @@ -0,0 +1,63 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MSM_CSID_3_4_3_HWREG_H +#define MSM_CSID_3_4_3_HWREG_H + +#include + +static uint8_t csid_lane_assign_v3_4_3[PHY_LANE_MAX] = {0, 4, 1, 2, 3}; +static struct csid_reg_parms_t csid_v3_4_3 = { + /* MIPI CSID registers */ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x14, + 0x18, + 0x1C, + 0x20, + 0x60, + 0x64, + 0x68, + 0x6C, + 0x70, + 0x74, + 0x78, + 0x7C, + 0x80, + 0x84, + 0x88, + 0x8C, + 0x90, + 0x94, + 0x98, + 0xA0, + 0xA4, + 0xAC, + 0xB0, + 0xB4, + 11, + 0x7FFF, + 0x4, + 17, + 0x30040003, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x7f010800, + 20, + 0xFFFFFFFF, + 0xFFFFFFFF, +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c index d5e79897f73c..9d3184ee38e0 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c @@ -26,6 +26,7 @@ #include "include/msm_csid_3_5_hwreg.h" #include "include/msm_csid_3_4_1_hwreg.h" #include "include/msm_csid_3_4_2_hwreg.h" +#include "include/msm_csid_3_4_3_hwreg.h" #include "include/msm_csid_3_6_0_hwreg.h" #include "include/msm_csid_3_5_1_hwreg.h" #include "cam_hw_ops.h" @@ -42,6 +43,7 @@ #define CSID_VERSION_V34 0x30040000 #define CSID_VERSION_V34_1 0x30040001 #define CSID_VERSION_V34_2 0x30040002 +#define CSID_VERSION_V34_3 0x30040003 #define CSID_VERSION_V36 0x30060000 #define CSID_VERSION_V37 0x30070000 #define CSID_VERSION_V35 0x30050000 @@ -1178,6 +1180,12 @@ static int csid_probe(struct platform_device *pdev) new_csid_dev->hw_dts_version = CSID_VERSION_V34_2; new_csid_dev->ctrl_reg->csid_lane_assign = csid_lane_assign_v3_4_2; + } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v3.4.3")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v3_4_3; + new_csid_dev->hw_dts_version = CSID_VERSION_V34_3; + new_csid_dev->ctrl_reg->csid_lane_assign = + csid_lane_assign_v3_4_3; } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, "qcom,csid-v3.6.0")) { new_csid_dev->ctrl_reg->csid_reg = csid_v3_6_0; -- GitLab From 32a7daf0e5e81f2532f521ed670a0967108044df Mon Sep 17 00:00:00 2001 From: Raviteja Tamatam Date: Tue, 12 Jun 2018 14:31:10 +0530 Subject: [PATCH 784/855] drm/msm/sde: prevent clearing multirect flags during validate failure In corner case where crtc->planemask and atomic state->planes[] do not match, driver clears the multirect_index/multirect_mode in the plane->state during validate failure case. This can lead to multirect_index/multirect_mode mismatch for next commits during failure condition. Change-Id: Idccaa79431469e185ca46c1e40b040427d02a96d Signed-off-by: Raviteja Tamatam --- drivers/gpu/drm/msm/sde/sde_crtc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index f5c24e2e9a0c..ee831820942d 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -4731,8 +4731,6 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, for (i = 1; i < SSPP_MAX; i++) { if (pipe_staged[i]) { - sde_plane_clear_multirect(pipe_staged[i]); - if (is_sde_plane_virtual(pipe_staged[i]->plane)) { SDE_ERROR( "r1 only virt plane:%d not supported\n", @@ -4740,6 +4738,7 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, rc = -EINVAL; goto end; } + sde_plane_clear_multirect(pipe_staged[i]); } } -- GitLab From 4fcd68930e3d52fb4ce0bb925f791e8965d7918e Mon Sep 17 00:00:00 2001 From: Narender Ankam Date: Mon, 11 Jun 2018 13:09:00 +0530 Subject: [PATCH 785/855] msm: mdss: dsi: parse and control vdd_ext gpio Parse and control vdd_ext gpio during power_on/off sequence required for 10" novatek panel on apq8053 FEPv2. Change-Id: Iab7f99b6f83f6ef69d84e584e8438b23de01a641 Signed-off-by: Narender Ankam --- .../devicetree/bindings/fb/mdss-dsi.txt | 1 + drivers/video/fbdev/msm/mdss_dsi.c | 22 +++++++++++++++++++ drivers/video/fbdev/msm/mdss_dsi.h | 1 + drivers/video/fbdev/msm/mdss_dsi_panel.c | 12 ++++++++++ 4 files changed, 36 insertions(+) diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi.txt b/Documentation/devicetree/bindings/fb/mdss-dsi.txt index 1934bc5c9f34..2d689d23a3c6 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi.txt @@ -113,6 +113,7 @@ Optional properties: - qcom,platform-bklight-en-gpio-invert: Invert the gpio used to enable display back-light - qcom,panel-mode-gpio: Specifies the GPIO to select video/command/single-port/dual-port mode of panel through gpio when it supports these modes. +- qcom,ext-vdd-gpio: Specifies the GPIO to enable external VDD supply. - pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node Refer to pinctrl-bindings.txt - pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 816eed022994..a553172111cb 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -383,6 +383,14 @@ static int mdss_dsi_panel_power_off(struct mdss_panel_data *pdata) ret = 0; } + if (gpio_is_valid(ctrl_pdata->vdd_ext_gpio)) { + ret = gpio_direction_output( + ctrl_pdata->vdd_ext_gpio, 0); + if (ret) + pr_err("%s: unable to set dir for vdd gpio\n", + __func__); + } + if (mdss_dsi_pinctrl_set_state(ctrl_pdata, false)) pr_debug("reset disable: pinctrl not enabled\n"); @@ -410,6 +418,15 @@ static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata) ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); + if (gpio_is_valid(ctrl_pdata->vdd_ext_gpio)) { + ret = gpio_direction_output( + ctrl_pdata->vdd_ext_gpio, 1); + usleep_range(3000, 4000); /* h/w recommended delay */ + if (ret) + pr_err("%s: unable to set dir for vdd gpio\n", + __func__); + } + ret = msm_mdss_enable_vreg( ctrl_pdata->panel_power_data.vreg_config, ctrl_pdata->panel_power_data.num_vreg, 1); @@ -4183,6 +4200,11 @@ static int mdss_dsi_parse_gpio_params(struct platform_device *ctrl_pdev, of_property_read_bool(ctrl_pdev->dev.of_node, "qcom,platform-bklight-en-gpio-invert"); + ctrl_pdata->vdd_ext_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, + "qcom,ext-vdd-gpio", 0); + if (!gpio_is_valid(ctrl_pdata->vdd_ext_gpio)) + pr_info("%s: ext vdd gpio not specified\n", __func__); + ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-reset-gpio", 0); if (!gpio_is_valid(ctrl_pdata->rst_gpio)) diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 2ff2951d1d1c..5d2d677c6597 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -435,6 +435,7 @@ struct mdss_dsi_ctrl_pdata { int rst_gpio; int disp_en_gpio; int bklt_en_gpio; + int vdd_ext_gpio; int mode_gpio; int intf_mux_gpio; bool bklt_en_gpio_invert; diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 85ed42e1a492..b94280ddcd15 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -326,6 +326,15 @@ static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata) goto bklt_en_gpio_err; } } + if (gpio_is_valid(ctrl_pdata->vdd_ext_gpio)) { + rc = gpio_request(ctrl_pdata->vdd_ext_gpio, + "vdd_enable"); + if (rc) { + pr_err("request vdd enable gpio failed, rc=%d\n", + rc); + goto vdd_en_gpio_err; + } + } if (gpio_is_valid(ctrl_pdata->mode_gpio)) { rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode"); if (rc) { @@ -337,6 +346,9 @@ static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata) return rc; mode_gpio_err: + if (gpio_is_valid(ctrl_pdata->vdd_ext_gpio)) + gpio_free(ctrl_pdata->vdd_ext_gpio); +vdd_en_gpio_err: if (gpio_is_valid(ctrl_pdata->bklt_en_gpio)) gpio_free(ctrl_pdata->bklt_en_gpio); bklt_en_gpio_err: -- GitLab From 7548e392226e9a6b0c17d7bed22cf20b713d2c37 Mon Sep 17 00:00:00 2001 From: Narender Ankam Date: Fri, 1 Jun 2018 14:22:47 +0530 Subject: [PATCH 786/855] ARM: dts: msm: add support for 10 inch boent51021 1200p panel on apq8053 Add support for boent51021-1200p video mode panel to enable display on apq8053 FEPv2. Change-Id: Ie70b5de9213b5c4f5f9cc038e4a1c4ed8e8f5af9 Signed-off-by: Narender Ankam --- .../dts/qcom/apq8053-lite-dragon-v2.1.dtsi | 2 +- .../dts/qcom/apq8053-lite-dragon-v2.2.dtsi | 35 +++++++ .../dsi-panel-boent51021-1200p-video.dtsi | 92 +++++++++++++++++++ .../boot/dts/qcom/msm8953-mdss-panels.dtsi | 9 ++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-boent51021-1200p-video.dtsi diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dtsi index 4d9c40c2d070..993799b83d7d 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dtsi @@ -14,7 +14,7 @@ #include "apq8053-lite-dragon.dtsi" &mdss_dsi0 { - qcom,ext_vdd-gpio = <&tlmm 100 0>; + qcom,ext-vdd-gpio = <&tlmm 100 0>; qcom,platform-bklight-en-gpio = <&tlmm 95 0>; qcom,platform-lane-config = [00 00 ff 0f diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dtsi index 396fd55b7c3a..1744c90659c5 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dtsi @@ -18,6 +18,41 @@ /delete-node/ himax_ts@48; }; +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_boent51021_1200p_video>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + vdd-supply = <&pm8953_l10>; + vddio-supply = <&pm8953_l6>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + + qcom,platform-te-gpio = <&tlmm 24 0>; + qcom,platform-reset-gpio = <&tlmm 61 0>; + qcom,ext-vdd-gpio = <&tlmm 100 0>; + qcom,platform-bklight-en-gpio = <&tlmm 95 0>; + + qcom,platform-lane-config = [00 00 ff 0f + 00 00 ff 0f + 00 00 ff 0f + 00 00 ff 0f + 00 00 ff 8f]; +}; + +&mdss_dsi1 { + status = "disabled"; +}; + &eeprom0 { gpios = <&tlmm 26 0>, <&tlmm 40 0>, diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-boent51021-1200p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-boent51021-1200p-video.dtsi new file mode 100644 index 000000000000..04accd89b569 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-boent51021-1200p-video.dtsi @@ -0,0 +1,92 @@ +/* Novatek Android Driver Sample Code for Novatek chipset + * + * Copyright (C) 2015-2018 Novatek Microelectronics Corp. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +&mdss_mdp { + dsi_boent51021_1200p_video: qcom,mdss_dsi_boent51021_1200p_video { + qcom,mdss-dsi-panel-name = + "boent51021 1200p video mode dsi panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <1200>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <1>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <25>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [ + 23 01 00 00 01 00 02 8f a5 + 23 01 00 00 00 00 02 83 00 + 23 01 00 00 00 00 02 84 00 + 23 01 00 00 00 00 02 8c 80 + 23 01 00 00 00 00 02 cd 6c + 23 01 00 00 00 00 02 c8 fc + 23 01 00 00 00 00 02 97 00 + 23 01 00 00 00 00 02 8b 10 + 23 01 00 00 00 00 02 a9 20 + 23 01 00 00 00 00 02 83 aa + 23 01 00 00 00 00 02 84 11 + 23 01 00 00 00 00 02 a9 4b + 23 01 00 00 00 00 02 85 04 + 23 01 00 00 00 00 02 86 08 + 23 01 00 00 00 00 02 9c 10 + 05 01 00 00 00 00 02 11 00 + 23 01 00 00 00 00 02 8f 00 + ]; + qcom,mdss-dsi-off-command = [ + 23 01 00 00 00 00 02 83 00 + 23 01 00 00 78 00 02 84 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [ + f2 3a 28 00 6c 70 2c 3e 2e 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x33>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-force-clock-lane-hs; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-pan-physical-width-dimension = <135>; + qcom,mdss-pan-physical-height-dimension = <216>; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-post-init-delay = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi index 7ee30f6c5b4f..a80b4fed098f 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi @@ -25,6 +25,7 @@ #include "dsi-panel-lt8912-1080p-video.dtsi" #include "dsi-panel-hx8399c-fhd-plus-video.dtsi" #include "dsi-panel-hx83100a-800p-video.dtsi" +#include "dsi-panel-boent51021-1200p-video.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { @@ -169,3 +170,11 @@ 1f 1c 05 06 03 03 04 a0 1f 10 05 06 03 03 04 a0]; }; + +&dsi_boent51021_1200p_video { + qcom,mdss-dsi-panel-timings-phy-v2 = [25 20 08 0a 06 03 04 a0 + 25 20 08 0a 06 03 04 a0 + 25 20 08 0a 06 03 04 a0 + 25 20 08 0a 06 03 04 a0 + 25 1d 08 0a 06 03 04 a0]; +}; -- GitLab From 009901635f3c99de9f83a52a0fe78fb0ea01b84e Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Wed, 6 Jun 2018 15:36:03 +0530 Subject: [PATCH 787/855] ARM: dts: msm: Add device tree support for qcs605 LC CDP Add base device tree and overlay support for qcs605 LC CDP board variant. Change-Id: I845dcd165d8d79105fb530d65fc66525808e9ade Signed-off-by: Kaushal Kumar --- arch/arm64/boot/dts/qcom/Makefile | 3 + .../boot/dts/qcom/qcs605-lc-cdp-base.dts | 22 +++++ .../boot/dts/qcom/qcs605-lc-cdp-overlay.dts | 26 ++++++ arch/arm64/boot/dts/qcom/qcs605-lc-cdp.dts | 25 ++++++ arch/arm64/boot/dts/qcom/qcs605-lc-cdp.dtsi | 87 +++++++++++++++++++ 5 files changed, 163 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/qcs605-lc-cdp-base.dts create mode 100644 arch/arm64/boot/dts/qcom/qcs605-lc-cdp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/qcs605-lc-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/qcs605-lc-cdp.dtsi diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 1d845e862787..3acf355327c7 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -147,6 +147,7 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) qcs605-360camera-overlay.dtbo \ qcs605-external-codec-mtp-overlay.dtbo \ qcs605-lc-mtp-overlay.dtbo \ + qcs605-lc-cdp-overlay.dtbo \ sdm710-cdp-overlay.dtbo \ sdm710-mtp-overlay.dtbo \ sdm710-qrd-overlay.dtbo \ @@ -203,6 +204,7 @@ qcs605-mtp-overlay.dtbo-base := qcs605.dtb qcs605-external-codec-mtp-overlay.dtbo-base := qcs605.dtb qcs605-lc-mtp-overlay.dtbo-base := qcs605-lc.dtb qcs605-360camera-overlay.dtbo-base := qcs605.dtb +qcs605-lc-cdp-overlay.dtbo-base := qcs605-lc-cdp-base.dtb sdm710-cdp-overlay.dtbo-base := sdm710.dtb sdm710-mtp-overlay.dtbo-base := sdm710.dtb sdm710-qrd-overlay.dtbo-base := sdm710.dtb @@ -258,6 +260,7 @@ dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \ qcs605-cdp.dtb \ qcs605-external-codec-mtp.dtb \ qcs605-lc-mtp.dtb \ + qcs605-lc-cdp.dtb \ sdm710-mtp.dtb \ sdm710-cdp.dtb \ sdm710-qrd.dtb \ diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-cdp-base.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-cdp-base.dts new file mode 100644 index 000000000000..e08acea508f3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-cdp-base.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "qcs605-lc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS605 LC CDP Base SoC"; + compatible = "qcom,qcs605"; + qcom,board-id = <1 4>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-cdp-overlay.dts new file mode 100644 index 000000000000..5987fb30523c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-cdp-overlay.dts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include "qcs605-lc-cdp.dtsi" +#include "qcs605-lc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 CDP"; + compatible = "qcom,qcs605-cdp", "qcom,qcs605", "qcom,cdp"; + qcom,msm-id = <347 0x0>; + qcom,board-id = <1 4>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-cdp.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-cdp.dts new file mode 100644 index 000000000000..753b4965607d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-cdp.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "qcs605-lc.dtsi" +#include "qcs605-lc-cdp.dtsi" +#include "qcs605-lc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 CDP"; + compatible = "qcom,qcs605-cdp", "qcom,qcs605", "qcom,cdp"; + qcom,board-id = <1 4>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-cdp.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-cdp.dtsi new file mode 100644 index 000000000000..e32128cfb938 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-cdp.dtsi @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qcs605-lc-pmic-overlay.dtsi" + +&qupv3_se9_2uart { + status = "disabled"; +}; + +&qupv3_se12_2uart { + status = "ok"; +}; + +&qupv3_se8_spi { + status = "disabled"; +}; + +&sdhc_1 { + vdd-supply = <&pm660_l19>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&tlmm { + sdc2_cd_on: cd_on { + mux { + pins = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_cd_off: cd_off { + mux { + pins = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + drive-strength = <2>; + bias-disable; + }; + }; +}; + +&sdhc_2 { + /* VDD external regulator is enabled/disabled by pm660_l18 regulator */ + vdd-io-supply = <&pm660_l18>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 116 0x1>; + + status = "ok"; +}; -- GitLab From 206918434ebd36727a99372a2bdbbaa71024c981 Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Mon, 4 Jun 2018 15:54:45 +0530 Subject: [PATCH 788/855] ARM: dts: msm: Add device tree support for sxr1120 Add base device tree and overlay support for sxr1120 CDP and MTP board variants. Support both internal and external audio codec variants. Change-Id: I8a38bc1ad89ad6a70e782dc21ee15060d1a4d8e5 Signed-off-by: Kaushal Kumar --- .../devicetree/bindings/arm/msm/msm.txt | 5 +++ arch/arm64/boot/dts/qcom/Makefile | 12 +++++++ .../boot/dts/qcom/sxr1120-lc-cdp-overlay.dts | 31 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sxr1120-lc-cdp.dts | 25 +++++++++++++++ arch/arm64/boot/dts/qcom/sxr1120-lc-cdp.dtsi | 14 +++++++++ .../sxr1120-lc-external-codec-cdp-overlay.dts | 30 ++++++++++++++++++ .../qcom/sxr1120-lc-external-codec-cdp.dts | 24 ++++++++++++++ .../sxr1120-lc-external-codec-mtp-overlay.dts | 30 ++++++++++++++++++ .../qcom/sxr1120-lc-external-codec-mtp.dts | 24 ++++++++++++++ .../boot/dts/qcom/sxr1120-lc-mtp-overlay.dts | 31 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sxr1120-lc-mtp.dts | 25 +++++++++++++++ arch/arm64/boot/dts/qcom/sxr1120-lc-mtp.dtsi | 14 +++++++++ arch/arm64/boot/dts/qcom/sxr1120-lc.dts | 22 +++++++++++++ arch/arm64/boot/dts/qcom/sxr1120-lc.dtsi | 20 ++++++++++++ 14 files changed, 307 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sxr1120-lc-cdp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1120-lc-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1120-lc-cdp.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-cdp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1120-lc-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1120-lc-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1120-lc-mtp.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sxr1120-lc.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1120-lc.dtsi diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 9df16fb49443..1a9c8bdae684 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -95,6 +95,9 @@ SoCs: - QCS605 compatible = "qcom,qcs605" +- SXR1120 + compatible = "qcom,sxr1120" + - SDA670 compatible = "qcom,sda670" @@ -324,6 +327,8 @@ compatible = "qcom,sdm670-mtp" compatible = "qcom,sdm670-qrd" compatible = "qcom,qcs605-cdp" compatible = "qcom,qcs605-mtp" +compatible = "qcom,sxr1120-mtp" +compatible = "qcom,sxr1120-cdp" compatible = "qcom,sda670-cdp" compatible = "qcom,sda670-mtp" compatible = "qcom,sda670-hdk" diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 3acf355327c7..ae21ef58e1ac 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -142,6 +142,10 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sdm670-pm660a-tasha-codec-cdp-overlay.dtbo \ sdm670-aqt1000-cdp-overlay.dtbo \ sdm670-pm660a-aqt1000-cdp-overlay.dtbo \ + sxr1120-lc-mtp-overlay.dtbo \ + sxr1120-lc-external-codec-mtp-overlay.dtbo \ + sxr1120-lc-cdp-overlay.dtbo \ + sxr1120-lc-external-codec-cdp-overlay.dtbo \ qcs605-cdp-overlay.dtbo \ qcs605-mtp-overlay.dtbo \ qcs605-360camera-overlay.dtbo \ @@ -199,6 +203,10 @@ sda670-mtp-overlay.dtbo-base := sda670.dtb sda670-hdk-overlay.dtbo-base := sda670.dtb sda670-pm660a-cdp-overlay.dtbo-base := sda670.dtb sda670-pm660a-mtp-overlay.dtbo-base := sda670.dtb +sxr1120-lc-mtp-overlay.dtbo-base := sxr1120-lc.dtb +sxr1120-lc-external-codec-mtp-overlay.dtbo-base := sxr1120-lc.dtb +sxr1120-lc-cdp-overlay.dtbo-base := sxr1120-lc.dtb +sxr1120-lc-external-codec-cdp-overlay.dtbo-base := sxr1120-lc.dtb qcs605-cdp-overlay.dtbo-base := qcs605.dtb qcs605-mtp-overlay.dtbo-base := qcs605.dtb qcs605-external-codec-mtp-overlay.dtbo-base := qcs605.dtb @@ -255,6 +263,10 @@ dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \ sdm670-pm660a-tasha-codec-cdp.dtb \ sda670-pm660a-mtp.dtb \ sda670-pm660a-cdp.dtb \ + sxr1120-lc-mtp.dtb \ + sxr1120-lc-external-codec-mtp.dtb \ + sxr1120-lc-cdp.dtb \ + sxr1120-lc-external-codec-cdp.dtb \ qcs605-360camera.dtb \ qcs605-mtp.dtb \ qcs605-cdp.dtb \ diff --git a/arch/arm64/boot/dts/qcom/sxr1120-lc-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1120-lc-cdp-overlay.dts new file mode 100644 index 000000000000..c3aa763a5d31 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1120-lc-cdp-overlay.dts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sxr1120-lc-cdp.dtsi" +#include "qcs605-lc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1120 LC Groot+PM8005 CDP"; + compatible = "qcom,sxr1120-cdp", "qcom,sxr1120", "qcom,cdp"; + qcom,msm-id = <370 0x0>; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1120-lc-cdp.dts b/arch/arm64/boot/dts/qcom/sxr1120-lc-cdp.dts new file mode 100644 index 000000000000..62378734b674 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1120-lc-cdp.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1120-lc.dtsi" +#include "sxr1120-lc-cdp.dtsi" +#include "qcs605-lc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1120 LC Groot+PM8005 CDP"; + compatible = "qcom,sxr1120-cdp", "qcom,sxr1120", "qcom,cdp"; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1120-lc-cdp.dtsi b/arch/arm64/boot/dts/qcom/sxr1120-lc-cdp.dtsi new file mode 100644 index 000000000000..d4d42c5904ef --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1120-lc-cdp.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qcs605-lc-cdp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-cdp-overlay.dts new file mode 100644 index 000000000000..e90f3b495230 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-cdp-overlay.dts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sxr1120-lc-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1120 LC Groot+PM8005 Ext. Audio Codec CDP"; + compatible = "qcom,sxr1120-cdp", "qcom,sxr1120", "qcom,cdp"; + qcom,msm-id = <370 0x0>; + qcom,board-id = <1 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-cdp.dts new file mode 100644 index 000000000000..76c424d04d0a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-cdp.dts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1120-lc.dtsi" +#include "sxr1120-lc-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1120 LC Groot+PM8005 Ext. Audio Codec CDP"; + compatible = "qcom,sxr1120-cdp", "qcom,sxr1120", "qcom,cdp"; + qcom,board-id = <1 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-mtp-overlay.dts new file mode 100644 index 000000000000..946298ffd0fd --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-mtp-overlay.dts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sxr1120-lc-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1120 LC Groot+PM8005 Ext. Audio Codec MTP"; + compatible = "qcom,sxr1120-mtp", "qcom,sxr1120", "qcom,mtp"; + qcom,msm-id = <370 0x0>; + qcom,board-id = <8 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-mtp.dts new file mode 100644 index 000000000000..e53bbe36bbba --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1120-lc-external-codec-mtp.dts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1120-lc.dtsi" +#include "sxr1120-lc-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1120 LC Groot+PM8005 Ext. Audio Codec MTP"; + compatible = "qcom,sxr1120-mtp", "qcom,sxr1120", "qcom,mtp"; + qcom,board-id = <8 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1120-lc-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1120-lc-mtp-overlay.dts new file mode 100644 index 000000000000..8af46ef45b1a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1120-lc-mtp-overlay.dts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sxr1120-lc-mtp.dtsi" +#include "qcs605-lc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1120 LC Groot+PM8005 MTP"; + compatible = "qcom,sxr1120-mtp", "qcom,sxr1120", "qcom,mtp"; + qcom,msm-id = <370 0x0>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1120-lc-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1120-lc-mtp.dts new file mode 100644 index 000000000000..ffcdeda34588 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1120-lc-mtp.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1120-lc.dtsi" +#include "sxr1120-lc-mtp.dtsi" +#include "qcs605-lc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1120 LC Groot+PM8005 MTP"; + compatible = "qcom,sxr1120-mtp", "qcom,sxr1120", "qcom,mtp"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1120-lc-mtp.dtsi b/arch/arm64/boot/dts/qcom/sxr1120-lc-mtp.dtsi new file mode 100644 index 000000000000..270aa0e132fb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1120-lc-mtp.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qcs605-lc-mtp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sxr1120-lc.dts b/arch/arm64/boot/dts/qcom/sxr1120-lc.dts new file mode 100644 index 000000000000..59673880dcd1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1120-lc.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sxr1120-lc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1120 LC SoC"; + compatible = "qcom,sxr1120"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1120-lc.dtsi b/arch/arm64/boot/dts/qcom/sxr1120-lc.dtsi new file mode 100644 index 000000000000..1413e2cadff1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1120-lc.dtsi @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qcs605-lc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1120 SoC"; + compatible = "qcom,sxr1120"; + qcom,msm-id = <370 0x0>; +}; -- GitLab From 14cdd329475022410fe80ab8b1a5b532618d3a52 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Tue, 5 Jun 2018 20:51:34 +0800 Subject: [PATCH 789/855] ARM: dts: msm: Add tupwr-disable property for MSM8953 and MSM8937 On MSM8953 and MSM8937, device will reset if cpu enters into power collapse while etm trace unit is kept powered on. Add property to control power of the trace unit for MSM8953 and MSM8937's ETM. Don't keep trace unit powered across power collapse. Change-Id: If1df95b2819b40a14749bada7b9a145ee77f788a Signed-off-by: Mao Jinlong --- arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi | 16 ++++++++++++++++ arch/arm64/boot/dts/qcom/msm8953-coresight.dtsi | 2 ++ 2 files changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi index b9529088b5c8..d085d2de0629 100644 --- a/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi @@ -462,6 +462,8 @@ reg = <0x619c000 0x1000>; cpu = <&CPU4>; + + qcom,tupwr-disable; coresight-name = "coresight-etm4"; clocks = <&clock_gcc clk_qdss_clk>, @@ -481,6 +483,8 @@ reg = <0x619d000 0x1000>; cpu = <&CPU5>; + + qcom,tupwr-disable; coresight-name = "coresight-etm5"; clocks = <&clock_gcc clk_qdss_clk>, @@ -500,6 +504,8 @@ reg = <0x619e000 0x1000>; cpu = <&CPU6>; + + qcom,tupwr-disable; coresight-name = "coresight-etm6"; clocks = <&clock_gcc clk_qdss_clk>, @@ -519,6 +525,8 @@ reg = <0x619f000 0x1000>; cpu = <&CPU7>; + + qcom,tupwr-disable; coresight-name = "coresight-etm7"; clocks = <&clock_gcc clk_qdss_clk>, @@ -538,6 +546,8 @@ reg = <0x61bc000 0x1000>; cpu = <&CPU0>; + + qcom,tupwr-disable; coresight-name = "coresight-etm0"; clocks = <&clock_gcc clk_qdss_clk>, @@ -557,6 +567,8 @@ reg = <0x61bd000 0x1000>; cpu = <&CPU1>; + + qcom,tupwr-disable; coresight-name = "coresight-etm1"; clocks = <&clock_gcc clk_qdss_clk>, @@ -576,6 +588,8 @@ reg = <0x61be000 0x1000>; cpu = <&CPU2>; + + qcom,tupwr-disable; coresight-name = "coresight-etm2"; clocks = <&clock_gcc clk_qdss_clk>, @@ -594,6 +608,8 @@ arm,primecell-periphid = <0x000bb95d>; reg = <0x61bf000 0x1000>; + + qcom,tupwr-disable; coresight-name = "coresight-etm3"; cpu = <&CPU3>; diff --git a/arch/arm64/boot/dts/qcom/msm8953-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8953-coresight.dtsi index 196a52694375..d3c2e265fb3e 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-coresight.dtsi @@ -505,6 +505,8 @@ reg = <0x619c000 0x1000>; cpu = <&CPU0>; + + qcom,tupwr-disable; coresight-name = "coresight-etm0"; clocks = <&clock_gcc clk_qdss_clk>, -- GitLab From b97e274df4afc9befd521264ffcea50731771c75 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 24 May 2018 19:30:17 +0800 Subject: [PATCH 790/855] defconfig: arm: Enable qdss components for MSM8953 Enable dcc and coresight components for arm MSM8953 qdss. CRs-Fixed: 2248199 Change-Id: Ic94deeb0fb6194a1f3f742c91715e9125c9d1332 Signed-off-by: Mao Jinlong --- arch/arm/configs/msm8953-perf_defconfig | 4 ++++ arch/arm/configs/msm8953_defconfig | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index 06e5360bfd87..8caee2f09f96 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -572,6 +572,7 @@ CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_AVTIMER=y CONFIG_MSM_PM=y +CONFIG_QCOM_DCC=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MEM_SHARE_QMI_SERVICE=y @@ -620,8 +621,11 @@ CONFIG_SCHED_STACK_END_CHECK=y CONFIG_IPC_LOGGING=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_QCOM_REPLICATOR=y +CONFIG_CORESIGHT_DBGUI=y CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index 70adcf185f30..e76f0458eeb8 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -590,6 +590,7 @@ CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_AVTIMER=y CONFIG_MSM_PM=y +CONFIG_QCOM_DCC=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MEM_SHARE_QMI_SERVICE=y @@ -684,8 +685,12 @@ CONFIG_FORCE_PAGES=y CONFIG_PID_IN_CONTEXTIDR=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SOURCE_ETM4X=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_QCOM_REPLICATOR=y +CONFIG_CORESIGHT_DBGUI=y CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y -- GitLab From e49c9d82dfaa3f5c5684ef145ea1b3280c822488 Mon Sep 17 00:00:00 2001 From: Sayali Lokhande Date: Tue, 12 Jun 2018 16:15:02 +0530 Subject: [PATCH 791/855] scsi: ufs: Fix race condition in rls_work and ufshcd_resume In some rare scenario, race condition is observed between rls_work handler and ufshcd_resume operation. Sequence of events: 1.rls_work is scheduled due to UIC error. 2.ufshcd_rls_handler sets host_self_blocked to 1 and then invokes pm_runtime_get_sync 3. pm_runtime_get_sync is not yet completed because runtime_status was RPM_RESUMING. 4.pm_runtime_work schedules at almost same time of rls_work. Here ufshcd_resume schedules out as host_self_blocked was set to 1 by rls_work. Call stacks: -006|wait_for_completion_io(?) -007|blk_execute_rq() -008|scsi_execute() -009|scsi_execute_req_flags() -010|ufshcd_set_dev_pwr_mode() -011|ufshcd_resume() -012|ufshcd_runtime_resume(hba) -013|ufshcd_pltfrm_runtime_resume(?) -014|pm_generic_runtime_resume(?) -015|__rpm_callback(inline) -003|schedule() -004|spin_lock_irq(inline) -004|rpm_resume() -005|__pm_runtime_resume() -006|ufshcd_rls_handler() Fix this by calling pm_runtime_get_sync before setting host_self_blocked to 1 during rls_work. Change-Id: I69f23c169ac8a9eb59062b461302f5521cd57ebc Signed-off-by: Sayali Lokhande --- drivers/scsi/ufs/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index aeb09f36c2ee..1a31ce844f9b 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -6559,8 +6559,8 @@ static void ufshcd_rls_handler(struct work_struct *work) u32 mode; hba = container_of(work, struct ufs_hba, rls_work); - ufshcd_scsi_block_requests(hba); pm_runtime_get_sync(hba->dev); + ufshcd_scsi_block_requests(hba); down_write(&hba->lock); ret = ufshcd_wait_for_doorbell_clr(hba, U64_MAX); if (ret) { -- GitLab From d674645fba4589a3f59916f0dc0c368a1bf62526 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Tue, 12 Jun 2018 16:45:51 +0800 Subject: [PATCH 792/855] coresight: etm3x: Check fuse status after clearing power down bit Move check of the fuse behind clearing power down bit action as ETMCR bit 0 must be cleared before checking any ETM status. Change-Id: I581b827eb43404413a2dca5299ea42d4233d99b5 Signed-off-by: Mao Jinlong --- drivers/hwtracing/coresight/coresight-etm3x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c index 3bbcc957740c..04870ce057db 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x.c +++ b/drivers/hwtracing/coresight/coresight-etm3x.c @@ -712,10 +712,6 @@ static void etm_init_arch_data(void *info) CS_UNLOCK(drvdata->base); - /* check the state of the fuse */ - if (!coresight_authstatus_enabled(drvdata->base)) - goto out; - /* First dummy read */ (void)etm_readl(drvdata, ETMPDSR); /* Provide power to ETM: ETMPDCR[3] == 1 */ @@ -725,6 +721,11 @@ static void etm_init_arch_data(void *info) * certain registers might be ignored. */ etm_clr_pwrdwn(drvdata); + + /* check the state of the fuse */ + if (!coresight_authstatus_enabled(drvdata->base)) + goto out; + /* * Set prog bit. It will be set from reset but this is included to * ensure it is set -- GitLab From c492dd3e0368de1a0993cd9a5ec0d4101d21a656 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:47 +0100 Subject: [PATCH 793/855] debugfs: add support for more elaborate ->d_fsdata Currently, the user provided fops, "real_fops", are stored directly into ->d_fsdata. In order to be able to store more per-file state and thus prepare for more granular file removal protection, wrap the real_fops into a dynamically allocated container struct, debugfs_fsdata. A struct debugfs_fsdata gets allocated at file creation and freed from the newly intoduced ->d_release(). Finally, move the implementation of debugfs_real_fops() out of the public debugfs header such that struct debugfs_fsdata's declaration can be kept private. Change-Id: I830f6018c3bc2af6511a07ca8248d216077a924e Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: 7c8d469877b16d2c1cecf101a0abb7b218db85bc Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Tingwei Zhang --- fs/debugfs/file.c | 12 ++++++++++++ fs/debugfs/inode.c | 22 +++++++++++++++++++--- fs/debugfs/internal.h | 4 ++++ include/linux/debugfs.h | 20 +++----------------- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 354e2ab62031..15655a1a0704 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -97,6 +97,18 @@ EXPORT_SYMBOL_GPL(debugfs_use_file_finish); #define F_DENTRY(filp) ((filp)->f_path.dentry) +const struct file_operations *debugfs_real_fops(const struct file *filp) + __must_hold(&debugfs_srcu) +{ + struct debugfs_fsdata *fsd = F_DENTRY(filp)->d_fsdata; + /* + * Neither the pointer to the struct file_operations, nor its + * contents ever change -- srcu_dereference() is not needed here. + */ + return fsd->real_fops; +} +EXPORT_SYMBOL_GPL(debugfs_real_fops); + static int open_proxy_open(struct inode *inode, struct file *filp) { const struct dentry *dentry = F_DENTRY(filp); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 3d7de9f4f545..82b84d87d181 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -185,6 +185,11 @@ static const struct super_operations debugfs_super_operations = { .evict_inode = debugfs_evict_inode, }; +static void debugfs_release_dentry(struct dentry *dentry) +{ + kfree(dentry->d_fsdata); +} + static struct vfsmount *debugfs_automount(struct path *path) { debugfs_automount_t f; @@ -194,6 +199,7 @@ static struct vfsmount *debugfs_automount(struct path *path) static const struct dentry_operations debugfs_dops = { .d_delete = always_delete_dentry, + .d_release = debugfs_release_dentry, .d_automount = debugfs_automount, }; @@ -307,24 +313,34 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode, { struct dentry *dentry; struct inode *inode; + struct debugfs_fsdata *fsd; + + fsd = kmalloc(sizeof(*fsd), GFP_KERNEL); + if (!fsd) + return NULL; if (!(mode & S_IFMT)) mode |= S_IFREG; BUG_ON(!S_ISREG(mode)); dentry = start_creating(name, parent); - if (IS_ERR(dentry)) + if (IS_ERR(dentry)) { + kfree(fsd); return NULL; + } inode = debugfs_get_inode(dentry->d_sb); - if (unlikely(!inode)) + if (unlikely(!inode)) { + kfree(fsd); return failed_creating(dentry); + } inode->i_mode = mode; inode->i_private = data; inode->i_fop = proxy_fops; - dentry->d_fsdata = (void *)real_fops; + fsd->real_fops = real_fops; + dentry->d_fsdata = fsd; d_instantiate(dentry, inode); fsnotify_create(d_inode(dentry->d_parent), dentry); diff --git a/fs/debugfs/internal.h b/fs/debugfs/internal.h index b3e8443a1f47..512601eed3ce 100644 --- a/fs/debugfs/internal.h +++ b/fs/debugfs/internal.h @@ -19,4 +19,8 @@ extern const struct file_operations debugfs_noop_file_operations; extern const struct file_operations debugfs_open_proxy_file_operations; extern const struct file_operations debugfs_full_proxy_file_operations; +struct debugfs_fsdata { + const struct file_operations *real_fops; +}; + #endif /* _DEBUGFS_INTERNAL_H_ */ diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index b20a0945b550..557be0d80204 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -45,23 +45,6 @@ extern struct dentry *arch_debugfs_dir; extern struct srcu_struct debugfs_srcu; -/** - * debugfs_real_fops - getter for the real file operation - * @filp: a pointer to a struct file - * - * Must only be called under the protection established by - * debugfs_use_file_start(). - */ -static inline const struct file_operations *debugfs_real_fops(struct file *filp) - __must_hold(&debugfs_srcu) -{ - /* - * Neither the pointer to the struct file_operations, nor its - * contents ever change -- srcu_dereference() is not needed here. - */ - return filp->f_path.dentry->d_fsdata; -} - #define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \ static int __fops ## _open(struct inode *inode, struct file *file) \ { \ @@ -110,6 +93,9 @@ int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx) void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu); +const struct file_operations *debugfs_real_fops(const struct file *filp) + __must_hold(&debugfs_srcu); + ssize_t debugfs_attr_read(struct file *file, char __user *buf, size_t len, loff_t *ppos); ssize_t debugfs_attr_write(struct file *file, const char __user *buf, -- GitLab From e62d012db5ecb0c8105a381faf64580dc0ccde38 Mon Sep 17 00:00:00 2001 From: Amit Shekhar Date: Thu, 24 May 2018 13:03:50 -0700 Subject: [PATCH 794/855] msm: vidc: Fix downscaling check for HEIC Don't check for downscaling when format is HEIC. Downscaling is not required for HEIC even if it may have non-matching input/output resolution. CRs-Fixed: 2251048 Change-Id: I7c243ebc3d5d1fd39e9ec4138309cd7acc5e989d Signed-off-by: Amit Shekhar --- .../media/platform/msm/vidc/msm_vidc_common.c | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 40c986211218..936b6dffee7a 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -2361,6 +2361,17 @@ int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst, return 0; } +static bool is_heic_encode_session(struct msm_vidc_inst *inst) +{ + if (inst->session_type == MSM_VIDC_ENCODER && + (get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) == + HAL_VIDEO_CODEC_HEVC) && + (inst->img_grid_dimension > 0)) + return true; + else + return false; +} + static bool is_eos_buffer(struct msm_vidc_inst *inst, u32 device_addr) { struct eos_buf *temp, *next; @@ -2406,10 +2417,7 @@ static void handle_ebd(enum hal_command_response cmd, void *data) } empty_buf_done = (struct vidc_hal_ebd *)&response->input_done; - if (inst->session_type == MSM_VIDC_ENCODER && - (get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) == - HAL_VIDEO_CODEC_HEVC) && - (inst->img_grid_dimension > 0) && + if (is_heic_encode_session(inst) && (empty_buf_done->input_tag < inst->tinfo.count - 1)) { dprintk(VIDC_DBG, "Wait for last tile. Current tile no: %d\n", empty_buf_done->input_tag); @@ -4425,10 +4433,7 @@ int msm_comm_qbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf) for (c = 0; c < etbs.count; ++c) { struct vidc_frame_data *frame_data = &etbs.data[c]; - if (inst->session_type == MSM_VIDC_ENCODER && - get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) - == HAL_VIDEO_CODEC_HEVC && - (inst->img_grid_dimension > 0)) { + if (is_heic_encode_session(inst)) { rc = msm_comm_qbuf_heic_tiles(inst, frame_data); if (rc) { dprintk(VIDC_ERR, @@ -5506,6 +5511,11 @@ int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst) u32 input_height, input_width, output_height, output_width; u32 rotation; + if (is_heic_encode_session(inst)) { + dprintk(VIDC_DBG, "Skip downscale check for HEIC\n"); + return 0; + } + input_height = inst->prop.height[OUTPUT_PORT]; input_width = inst->prop.width[OUTPUT_PORT]; output_height = inst->prop.height[CAPTURE_PORT]; -- GitLab From 2d1a762171672a77726d2a123ac8cbb14a12c020 Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Wed, 30 May 2018 17:01:58 -0700 Subject: [PATCH 795/855] msm: ipa: use IOMMU_MMIO only for device type Remove IOMMU_MMIO flag from all the DDR mappings done by IPA. Change-Id: I8147d3ded0dbd71b87f2e8a8bc05531e19164a83 CRs-Fixed: 2254877 Acked-by: Ady Abraham Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 82c8709faf27..9190e9ee464c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -6270,7 +6270,7 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) iova_p, &pa_p, size_p); ipa3_iommu_map(cb->mapping->domain, iova_p, pa_p, size_p, - IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO); + IOMMU_READ | IOMMU_WRITE); } -- GitLab From ffaf7209448c0134a521e51c49ca059e405a82fd Mon Sep 17 00:00:00 2001 From: Bojun Pan Date: Thu, 31 May 2018 16:16:25 -0700 Subject: [PATCH 796/855] msm: ipa: ipa gsb optimization Optimization to change the skb_copy to skb_clone to get rid of memcpy which will save some cpu cycles. Change-Id: I616eba7734dd54646d2ca45c297caee4b2026334 Signed-off-by: Bojun Pan --- .../platform/msm/ipa/ipa_clients/ipa_gsb.c | 93 +++++++++++-------- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 12 ++- 2 files changed, 62 insertions(+), 43 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c index df19384a145a..5812d8df9c9a 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c @@ -67,7 +67,8 @@ static char dbg_buff[IPA_GSB_MAX_MSG_LEN]; #define IPA_GSB_SKB_HEADROOM 256 -#define IPA_GSB_AGGR_BYTE_LIMIT 6 +#define IPA_GSB_SKB_DUMMY_HEADER 42 +#define IPA_GSB_AGGR_BYTE_LIMIT 14 #define IPA_GSB_AGGR_TIME_LIMIT 1 static struct dentry *dent; @@ -278,22 +279,36 @@ static int ipa_gsb_commit_partial_hdr(struct ipa_gsb_iface_info *iface_info) "%s_ipv4", iface_info->netdev_name); snprintf(hdr->hdr[1].name, sizeof(hdr->hdr[1].name), "%s_ipv6", iface_info->netdev_name); - /* partial header: [hdl][QMAP ID][pkt size][ETH header] */ + /* + * partial header: + * [hdl][QMAP ID][pkt size][Dummy Header][ETH header] + */ for (i = IPA_IP_v4; i < IPA_IP_MAX; i++) { - hdr->hdr[i].hdr_len = ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr); + /* + * Optimization: add dummy header to reserve space + * for rndis header, so we can do the skb_clone + * instead of deep copy. + */ + hdr->hdr[i].hdr_len = ETH_HLEN + + sizeof(struct ipa_gsb_mux_hdr) + + IPA_GSB_SKB_DUMMY_HEADER; hdr->hdr[i].type = IPA_HDR_L2_ETHERNET_II; hdr->hdr[i].is_partial = 1; hdr->hdr[i].is_eth2_ofst_valid = 1; - hdr->hdr[i].eth2_ofst = sizeof(struct ipa_gsb_mux_hdr); + hdr->hdr[i].eth2_ofst = sizeof(struct ipa_gsb_mux_hdr) + + IPA_GSB_SKB_DUMMY_HEADER; /* populate iface handle */ hdr->hdr[i].hdr[0] = iface_info->iface_hdl; /* populate src ETH address */ - memcpy(&hdr->hdr[i].hdr[10], iface_info->device_ethaddr, 6); + memcpy(&hdr->hdr[i].hdr[10 + IPA_GSB_SKB_DUMMY_HEADER], + iface_info->device_ethaddr, 6); /* populate Ethertype */ if (i == IPA_IP_v4) - *(u16 *)(hdr->hdr[i].hdr + 16) = htons(ETH_P_IP); + *(u16 *)(hdr->hdr[i].hdr + 16 + + IPA_GSB_SKB_DUMMY_HEADER) = htons(ETH_P_IP); else - *(u16 *)(hdr->hdr[i].hdr + 16) = htons(ETH_P_IPV6); + *(u16 *)(hdr->hdr[i].hdr + 16 + + IPA_GSB_SKB_DUMMY_HEADER) = htons(ETH_P_IPV6); } if (ipa_add_hdr(hdr)) { @@ -410,7 +425,7 @@ static void ipa_gsb_pm_cb(void *user_data, enum ipa_pm_cb_event event) return; } - IPA_GSB_DBG("wake up clients\n"); + IPA_GSB_DBG_LOW("wake up clients\n"); for (i = 0; i < MAX_SUPPORTED_IFACE; i++) if (ipa_gsb_ctx->iface[i] != NULL) ipa_gsb_ctx->iface[i]->wakeup_request( @@ -629,21 +644,6 @@ int ipa_bridge_cleanup(u32 hdl) } EXPORT_SYMBOL(ipa_bridge_cleanup); -static struct sk_buff *ipa_gsb_skb_copy(struct sk_buff *skb, int len) -{ - struct sk_buff *skb2 = NULL; - - skb2 = __dev_alloc_skb(len + IPA_GSB_SKB_HEADROOM, GFP_KERNEL); - if (likely(skb2)) { - skb_reserve(skb2, IPA_GSB_SKB_HEADROOM); - memcpy(skb2->data, skb->data, len); - skb2->len = len; - skb_set_tail_pointer(skb2, len); - } - - return skb2; -} - static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data) { @@ -665,21 +665,33 @@ static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt, mux_hdr = (struct ipa_gsb_mux_hdr *)skb->data; pkt_size = mux_hdr->pkt_size; /* 4-byte padding */ - pad_byte = ((pkt_size + sizeof(*mux_hdr) + ETH_HLEN + 3) & ~3) - - (pkt_size + sizeof(*mux_hdr) + ETH_HLEN); + pad_byte = ((pkt_size + sizeof(*mux_hdr) + ETH_HLEN + + 3 + IPA_GSB_SKB_DUMMY_HEADER) & ~3) - + (pkt_size + sizeof(*mux_hdr) + + ETH_HLEN + IPA_GSB_SKB_DUMMY_HEADER); hdl = mux_hdr->iface_hdl; - IPA_GSB_DBG("pkt_size: %d, pad_byte: %d, hdl: %d\n", + IPA_GSB_DBG_LOW("pkt_size: %d, pad_byte: %d, hdl: %d\n", pkt_size, pad_byte, hdl); - /* remove 4 byte mux header */ - skb_pull(skb, sizeof(*mux_hdr)); - skb2 = ipa_gsb_skb_copy(skb, pkt_size + ETH_HLEN); + /* remove 4 byte mux header AND dummy header*/ + skb_pull(skb, sizeof(*mux_hdr) + IPA_GSB_SKB_DUMMY_HEADER); + + skb2 = skb_clone(skb, GFP_KERNEL); + if (!skb2) { + IPA_GSB_ERR("skb_clone failed\n"); + WARN_ON(1); + break; + } + skb_trim(skb2, pkt_size + ETH_HLEN); ipa_gsb_ctx->iface[hdl]->send_dl_skb( ipa_gsb_ctx->iface[hdl]->priv, skb2); ipa_gsb_ctx->iface[hdl]->iface_stats.num_dl_packets++; - skb_pull(skb, pkt_size + ETH_HLEN + pad_byte); } + if (skb) { + dev_kfree_skb_any(skb); + skb = NULL; + } } static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt, @@ -702,7 +714,7 @@ static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt, /* change to host order */ *(u32 *)mux_hdr = ntohl(*(u32 *)mux_hdr); hdl = mux_hdr->iface_hdl; - IPA_GSB_DBG("evt: %d, hdl in tx_dp_notify: %d\n", evt, hdl); + IPA_GSB_DBG_LOW("evt: %d, hdl in tx_dp_notify: %d\n", evt, hdl); /* remove 4 byte mux header */ skb_pull(skb, sizeof(struct ipa_gsb_mux_hdr)); @@ -740,7 +752,8 @@ static int ipa_gsb_connect_sys_pipe(void) /* configure TX EP */ cons_params.client = IPA_CLIENT_ODU_EMB_CONS; cons_params.ipa_ep_cfg.hdr.hdr_len = - ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr); + ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr) + + IPA_GSB_SKB_DUMMY_HEADER; cons_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; cons_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 2; cons_params.ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment = 2; @@ -911,7 +924,7 @@ int ipa_bridge_resume(u32 hdl) return -EFAULT; } - IPA_GSB_DBG("client hdl: %d\n", hdl); + IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("iface is not connected\n"); @@ -919,7 +932,7 @@ int ipa_bridge_resume(u32 hdl) } if (ipa_gsb_ctx->iface[hdl]->is_resumed) { - IPA_GSB_DBG("iface was already resumed\n"); + IPA_GSB_DBG_LOW("iface was already resumed\n"); return 0; } @@ -946,7 +959,7 @@ int ipa_bridge_resume(u32 hdl) ipa_gsb_ctx->iface[hdl]->is_resumed = true; ipa_gsb_ctx->num_resumed_iface++; - IPA_GSB_DBG("num resumed iface: %d\n", + IPA_GSB_DBG_LOW("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); mutex_unlock(&ipa_gsb_ctx->lock); @@ -963,7 +976,7 @@ int ipa_bridge_suspend(u32 hdl) return -EFAULT; } - IPA_GSB_DBG("client hdl: %d\n", hdl); + IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("iface is not connected\n"); @@ -971,7 +984,7 @@ int ipa_bridge_suspend(u32 hdl) } if (!ipa_gsb_ctx->iface[hdl]->is_resumed) { - IPA_GSB_DBG("iface was already suspended\n"); + IPA_GSB_DBG_LOW("iface was already suspended\n"); return 0; } @@ -999,7 +1012,7 @@ int ipa_bridge_suspend(u32 hdl) ipa_gsb_ctx->iface[hdl]->is_resumed = false; ipa_gsb_ctx->num_resumed_iface--; - IPA_GSB_DBG("num resumed iface: %d\n", + IPA_GSB_DBG_LOW("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); mutex_unlock(&ipa_gsb_ctx->lock); @@ -1032,11 +1045,11 @@ int ipa_bridge_tx_dp(u32 hdl, struct sk_buff *skb, struct sk_buff *skb2; int ret; - IPA_GSB_DBG("client hdl: %d\n", hdl); + IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); /* make sure skb has enough headroom */ if (unlikely(skb_headroom(skb) < sizeof(struct ipa_gsb_mux_hdr))) { - IPA_GSB_DBG("skb doesn't have enough headroom\n"); + IPA_GSB_DBG_LOW("skb doesn't have enough headroom\n"); skb2 = skb_copy_expand(skb, sizeof(struct ipa_gsb_mux_hdr), 0, GFP_ATOMIC); if (!skb2) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 34f3265947ab..7969476cbf71 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -35,6 +35,9 @@ #define IPA_GENERIC_AGGR_TIME_LIMIT 1 #define IPA_GENERIC_AGGR_PKT_LIMIT 0 +#define IPA_GSB_AGGR_BYTE_LIMIT 14 +#define IPA_GSB_RX_BUFF_BASE_SZ 16384 + #define IPA_GENERIC_RX_BUFF_BASE_SZ 8192 #define IPA_REAL_GENERIC_RX_BUFF_SZ(X) (SKB_DATA_ALIGN(\ (X) + NET_SKB_PAD) +\ @@ -2946,11 +2949,14 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in, /* recycle skb for GSB use case */ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) { sys->free_rx_wrapper = - ipa3_recycle_rx_wrapper; + ipa3_free_rx_wrapper; sys->repl_hdlr = - ipa3_replenish_rx_cache_recycle; + ipa3_replenish_rx_cache; + /* Overwrite buffer size & aggr limit for GSB */ sys->rx_buff_sz = IPA_GENERIC_RX_BUFF_SZ( - IPA_GENERIC_RX_BUFF_BASE_SZ); + IPA_GSB_RX_BUFF_BASE_SZ); + in->ipa_ep_cfg.aggr.aggr_byte_limit = + IPA_GSB_AGGR_BYTE_LIMIT; } else { sys->free_rx_wrapper = ipa3_free_rx_wrapper; -- GitLab From 4aaa9c35f92c84eb0d816bdb0ba09cdcdb17ab6a Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Mon, 30 Sep 2013 16:51:14 +0530 Subject: [PATCH 797/855] USB: gadget: rndis: Optimize tx path for better performance Current rndis header addition and aggregation steps: 1. Increase skb headroom by size of rndis header. 2. Copy skb data with newly created skb having more headroom. 3. Create and add rndis header with it. 4. Again copy skb data with usb request buffer for aggregation purpose. New optimized steps : 1. Create and copy rndis header directly with usb request buffer 2. Copy skb data with usb request buffer Above new steps avoids cpu intensive skb operations which reduces CPU usage and provide better throughput. This change also assigns completion handle with usb request at the time of usb request creation instead of assigning everytime before queueing usb request. Also create debugfs for ether stats. Change-Id: Ifc64d6a8573f6a24e28c73ef9a19b62649e171cd Signed-off-by: Mayank Rana Signed-off-by: Ajay Agarwal --- drivers/usb/gadget/function/f_rndis.c | 21 +++++++++++ drivers/usb/gadget/function/u_ether.c | 53 +++++++++++++++++++++++---- drivers/usb/gadget/function/u_ether.h | 1 + 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index a75e5d346cfb..24bc2d4d96b2 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -386,10 +386,31 @@ static struct sk_buff *rndis_add_header(struct gether *port, struct sk_buff *skb) { struct sk_buff *skb2; + struct rndis_packet_msg_type *header = NULL; + struct f_rndis *rndis = func_to_rndis(&port->func); if (!skb) return NULL; + if (rndis->port.multi_pkt_xfer) { + if (port->header) { + header = port->header; + header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET); + header->MessageLength = cpu_to_le32(skb->len + + sizeof(*header)); + header->DataOffset = cpu_to_le32(36); + header->DataLength = cpu_to_le32(skb->len); + pr_debug("MessageLength:%d DataLength:%d\n", + header->MessageLength, + header->DataLength); + return skb; + } + + dev_kfree_skb(skb); + pr_err("RNDIS header is NULL.\n"); + return NULL; + } + skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type)); rndis_add_hdr(skb2); diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 9e388099f8b1..fbf90c42c40f 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -246,6 +246,7 @@ static void defer_kevent(struct eth_dev *dev, int flag) } static void rx_complete(struct usb_ep *ep, struct usb_request *req); +static void tx_complete(struct usb_ep *ep, struct usb_request *req); static int rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) @@ -307,7 +308,6 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) req->buf = skb->data; req->length = size; - req->complete = rx_complete; req->context = skb; retval = usb_ep_queue(out, req, gfp_flags); @@ -410,6 +410,7 @@ static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n) { unsigned i; struct usb_request *req; + bool usb_in; if (!n) return -ENOMEM; @@ -420,10 +421,22 @@ static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n) if (i-- == 0) goto extra; } + + if (ep->desc->bEndpointAddress & USB_DIR_IN) + usb_in = true; + else + usb_in = false; + while (i--) { req = usb_ep_alloc_request(ep, GFP_ATOMIC); if (!req) return list_empty(list) ? -ENOMEM : 0; + /* update completion handler */ + if (usb_in) + req->complete = tx_complete; + else + req->complete = rx_complete; + list_add(&req->list, list); } return 0; @@ -575,7 +588,7 @@ static void eth_work(struct work_struct *work) static void tx_complete(struct usb_ep *ep, struct usb_request *req) { - struct sk_buff *skb = req->context; + struct sk_buff *skb; struct eth_dev *dev = ep->driver_data; struct net_device *net = dev->net; struct usb_request *new_req; @@ -683,6 +696,7 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req) spin_unlock(&dev->req_lock); } } else { + skb = req->context; /* Is aggregation already enabled and buffers allocated ? */ if (dev->port_usb->multi_pkt_xfer && dev->tx_req_bufsize) { req->buf = kzalloc(dev->tx_req_bufsize @@ -725,7 +739,7 @@ static int alloc_tx_buffer(struct eth_dev *dev) list_for_each(act, &dev->tx_reqs) { req = container_of(act, struct usb_request, list); if (!req->buf) - req->buf = kmalloc(dev->tx_req_bufsize + req->buf = kzalloc(dev->tx_req_bufsize + dev->gadget->extra_buf_alloc, GFP_ATOMIC); if (!req->buf) @@ -866,8 +880,19 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, spin_unlock_irqrestore(&dev->req_lock, flags); if (multi_pkt_xfer) { + pr_debug("req->length:%d header_len:%u\n" + "skb->len:%d skb->data_len:%d\n", + req->length, dev->header_len, + skb->len, skb->data_len); + /* Add RNDIS Header */ + memcpy(req->buf + req->length, dev->port_usb->header, + dev->header_len); + /* Increment req length by header size */ + req->length += dev->header_len; + /* Copy received IP data from SKB */ memcpy(req->buf + req->length, skb->data, skb->len); - req->length = req->length + skb->len; + /* Increment req length by skb data length */ + req->length += skb->len; length = req->length; dev_kfree_skb_any(skb); @@ -927,8 +952,6 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, req->context = skb; } - req->complete = tx_complete; - /* NCM requires no zlp if transfer is dwNtbInMaxSize */ if (is_fixed && length == fixed_in_len && (length % in->maxpacket) == 0) @@ -981,7 +1004,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, spin_lock_irqsave(&dev->req_lock, flags); if (list_empty(&dev->tx_reqs)) netif_start_queue(net); - list_add(&req->list, &dev->tx_reqs); + list_add_tail(&req->list, &dev->tx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); } success: @@ -1443,6 +1466,8 @@ int gether_register_netdev(struct net_device *net) else INFO(dev, "MAC %pM\n", dev->dev_mac); + uether_debugfs_init(dev); + return status; } EXPORT_SYMBOL_GPL(gether_register_netdev); @@ -1594,6 +1619,11 @@ struct net_device *gether_connect(struct gether *link) if (!dev) return ERR_PTR(-EINVAL); + /* size of rndis_packet_msg_type is 44 */ + link->header = kzalloc(44, GFP_ATOMIC); + if (!link->header) + return ERR_PTR(-ENOMEM); + if (link->in_ep) { link->in_ep->driver_data = dev; result = usb_ep_enable(link->in_ep); @@ -1657,8 +1687,12 @@ struct net_device *gether_connect(struct gether *link) } fail0: /* caller is responsible for cleanup on error */ - if (result < 0) + if (result < 0) { + kfree(link->header); + return ERR_PTR(result); + } + return dev->net; } EXPORT_SYMBOL_GPL(gether_connect); @@ -1711,6 +1745,9 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->req_lock); } spin_unlock(&dev->req_lock); + /* Free rndis header buffer memory */ + kfree(link->header); + link->header = NULL; link->in_ep->desc = NULL; } diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 3ff09d1ae530..a10503a3a6b7 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -87,6 +87,7 @@ struct gether { /* called on network open/close */ void (*open)(struct gether *); void (*close)(struct gether *); + struct rndis_packet_msg_type *header; }; #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ -- GitLab From df7fa6686ded10080b0ba0c4d0a75184925fae24 Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Mon, 11 Jun 2018 12:41:51 +0530 Subject: [PATCH 798/855] regulator: qpnp-lcdb: Introduce regulator off-on delay Add turn on delay for LDO and NCP regulators to make sure that these regulators are not turned on before it is fully discharged. Change-Id: Idfb6034c31f3509d002157f85ad0da051abcc7c1 Signed-off-by: Kiran Gunda --- drivers/regulator/qpnp-lcdb-regulator.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c index 07a6198acc1a..cc01399b1740 100644 --- a/drivers/regulator/qpnp-lcdb-regulator.c +++ b/drivers/regulator/qpnp-lcdb-regulator.c @@ -167,6 +167,8 @@ #define PM660_BST_HEADROOM_DEFAULT_MV 200 #define BST_HEADROOM_DEFAULT_MV 150 +#define PMIC5_LCDB_OFF_ON_DELAY_US 20000 + struct ldo_regulator { struct regulator_desc rdesc; struct regulator_dev *rdev; @@ -1340,22 +1342,27 @@ static struct regulator_ops qpnp_lcdb_ncp_ops = { static int qpnp_lcdb_regulator_register(struct qpnp_lcdb *lcdb, u8 type) { - int rc = 0; + int rc = 0, off_on_delay = 0; struct regulator_init_data *init_data; struct regulator_config cfg = {}; struct regulator_desc *rdesc; struct regulator_dev *rdev; struct device_node *node; + if (lcdb->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE) + off_on_delay = PMIC5_LCDB_OFF_ON_DELAY_US; + if (type == LDO) { node = lcdb->ldo.node; rdesc = &lcdb->ldo.rdesc; rdesc->ops = &qpnp_lcdb_ldo_ops; + rdesc->off_on_delay = off_on_delay; rdev = lcdb->ldo.rdev; } else if (type == NCP) { node = lcdb->ncp.node; rdesc = &lcdb->ncp.rdesc; rdesc->ops = &qpnp_lcdb_ncp_ops; + rdesc->off_on_delay = off_on_delay; rdev = lcdb->ncp.rdev; } else { pr_err("Invalid regulator type %d\n", type); -- GitLab From bc95367124820b8844fae452885e69f01c2d8db1 Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Tue, 12 Jun 2018 20:01:28 +0530 Subject: [PATCH 799/855] usb: dwc3: update LC timer as per new usb V3.20 This is the workaround for STAR 9001285599 which affects dwc3 core version 3.20a only. The timer value for PM_LC_TIMER in V3.20a for the Link ECN changes is not correct. If the PM TIMER ECN is enabled thru GUCTL2[19], then link compliance test (TD7.21) may fail. If the ECN is not enabled (GUCTL2[19] = 0), the controller will use the old timer value (5us), which is still fine for Link Compliance test. Hence Clear GUCTL2[19] to pass usb link compliance test: TD 7.21. Change-Id: I5fc535ef2bdd54764086a50cf9a3cb538f92a465 Signed-off-by: Chandana Kishori Chiluveru --- drivers/usb/dwc3/core.c | 15 +++++++++++++++ drivers/usb/dwc3/core.h | 1 + 2 files changed, 16 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 248dd9a96c5a..93d8e14945fc 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -909,6 +909,21 @@ int dwc3_core_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); } + /* + * Workaround for STAR 9001285599 which affects dwc3 core version 3.20a + * only. If the PM TIMER ECN is enabled thru GUCTL2[19], then link + * compliance test (TD7.21) may fail. If the ECN is not enabled + * GUCTL2[19] = 0), the controller will use the old timer value (5us), + * which is still fine for Link Compliance test. Hence Do not enable + * PM TIMER ECN in V3.20a by setting GUCTL2[19] by default, + * instead use GUCTL2[19] = 0. + */ + if (dwc->revision == DWC3_REVISION_320A) { + reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); + reg &= ~DWC3_GUCTL2_LC_TIMER; + dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); + } + /* * Enable hardware control of sending remote wakeup in HS when * the device is in the L1 state. diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index e5fe7a472aab..61dd864f8d7b 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -333,6 +333,7 @@ #define DWC3_GUCTL2_RST_ACTBITLATER (1 << 14) #define DWC3_GUCTL2_HP_TIMER(n) ((n) << 21) #define DWC3_GUCTL2_HP_TIMER_MASK DWC3_GUCTL2_HP_TIMER(0x1f) +#define DWC3_GUCTL2_LC_TIMER (1 << 19) /* Device Configuration Register */ #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) -- GitLab From 3d9006f43fd2a938bb2fcff83d41f6ce184531ec Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Wed, 13 Jun 2018 12:23:52 +0530 Subject: [PATCH 800/855] defconfig: Enable SDCARDFS for msm8909 This enables SDCARDFS for msm8909 variants. Change-Id: I55dd1e4744006faa5807adcd88c919130c1d02d9 Signed-off-by: Ritesh Harjani --- arch/arm/configs/msm8909-perf_defconfig | 1 + arch/arm/configs/msm8909_defconfig | 1 + arch/arm/configs/msm8909w-perf_defconfig | 1 + arch/arm/configs/msm8909w_defconfig | 1 + 4 files changed, 4 insertions(+) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 1eaf4ffc03ce..d0400d86abb2 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -446,6 +446,7 @@ CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index 5e6a68b97b7b..4750788edda0 100644 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -441,6 +441,7 @@ CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 69dc93fe716f..1250e01e3c29 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -474,6 +474,7 @@ CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index 2eb602bab1a5..7c60312f9e02 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -490,6 +490,7 @@ CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y -- GitLab From 47a09898b06ee68deac896965571584576154109 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Mon, 28 May 2018 14:46:44 +0530 Subject: [PATCH 801/855] msm: ipa4: Update the missing config on sdx24 Couple of missing config changes on sdx24 with respect to EE_n_GSI_CH_k_QOS register, - USE_DB_ENG starting from sdx24, since there is no smart prefetch in MCS, this field should be 0 (for direct mode) for all channels, except for MHI with burst mode enabled. - MAX_PREFETCH This should be 0 (i.e, one prefetch buffer) - WRR_WEIGHT Software configurable, already taken care. - ESCAPE_BUFFER_ONLY update as per ep config excel. Change-Id: Ib464f5b475f843ed0f913f737a1fe6f046969fc1 Signed-off-by: Mohammed Javid --- .../platform/msm/ipa/ipa_clients/ipa_usb.c | 7 +- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 14 +- drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 2 + drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c | 22 ++- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 138 ++++++++++-------- include/linux/ipa.h | 2 + 6 files changed, 120 insertions(+), 65 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c index c7df5cf39808..8b998fee2f77 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c @@ -1336,7 +1336,12 @@ static int ipa3_usb_request_xdci_channel( chan_params.chan_params.ring_base_addr = params->xfer_ring_base_addr_iova; chan_params.chan_params.ring_base_vaddr = NULL; - chan_params.chan_params.use_db_eng = GSI_CHAN_DB_MODE; + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) + chan_params.chan_params.use_db_eng = GSI_CHAN_DIRECT_MODE; + else + chan_params.chan_params.use_db_eng = GSI_CHAN_DB_MODE; + chan_params.chan_params.prefetch_mode = + ipa_get_ep_prefetch_mode(chan_params.client); chan_params.chan_params.max_prefetch = GSI_ONE_PREFETCH_SEG; if (params->dir == GSI_CHAN_DIR_FROM_GSI) chan_params.chan_params.low_weight = diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 34f3265947ab..01b9a7ebd228 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -3695,8 +3695,13 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, ep->gsi_mem_info.chan_ring_base_vaddr = gsi_channel_props.ring_base_vaddr; - gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) + gsi_channel_props.use_db_eng = GSI_CHAN_DIRECT_MODE; + else + gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; gsi_channel_props.max_prefetch = GSI_ONE_PREFETCH_SEG; + gsi_channel_props.prefetch_mode = + ipa_get_ep_prefetch_mode(ep->client); if (ep->client == IPA_CLIENT_APPS_CMD_PROD) gsi_channel_props.low_weight = IPA_GSI_MAX_CH_LOW_WEIGHT; else @@ -3935,7 +3940,12 @@ int ipa_gsi_ch20_wa(void) dma_alloc_coherent(ipa3_ctx->pdev, gsi_channel_props.ring_len, &dma_addr, 0); gsi_channel_props.ring_base_addr = dma_addr; - gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; + + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) + gsi_channel_props.use_db_eng = GSI_CHAN_DIRECT_MODE; + else + gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; + gsi_channel_props.max_prefetch = GSI_ONE_PREFETCH_SEG; gsi_channel_props.low_weight = 1; gsi_channel_props.err_cb = ipa_gsi_chan_err_cb; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 268f5fadddf9..c860bd071772 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -2258,6 +2258,8 @@ int ipa3_remove_interrupt_handler(enum ipa_irq_type interrupt); */ int ipa3_get_ep_mapping(enum ipa_client_type client); +enum gsi_prefetch_mode ipa_get_ep_prefetch_mode(enum ipa_client_type client); + bool ipa3_is_ready(void); void ipa3_proxy_clk_vote(void); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c index 82cd81878903..902e8941fa76 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c @@ -198,6 +198,7 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, union __packed gsi_channel_scratch ch_scratch; struct ipa3_ep_context *ep; const struct ipa_gsi_ep_config *ep_cfg; + bool burst_mode_enabled = false; IPA_MHI_FUNC_ENTRY(); @@ -280,8 +281,21 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, ch_props.ring_len = params->ch_ctx_host->rlen; ch_props.ring_base_addr = IPA_MHI_HOST_ADDR_COND( params->ch_ctx_host->rbase); - ch_props.use_db_eng = GSI_CHAN_DB_MODE; + + if (params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_DEFAULT || + params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_ENABLE) { + burst_mode_enabled = true; + } + + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0 && + !burst_mode_enabled) + ch_props.use_db_eng = GSI_CHAN_DIRECT_MODE; + else + ch_props.use_db_eng = GSI_CHAN_DB_MODE; + ch_props.max_prefetch = GSI_ONE_PREFETCH_SEG; + ch_props.prefetch_mode = + ipa_get_ep_prefetch_mode(client); ch_props.low_weight = 1; ch_props.err_cb = params->ch_err_cb; ch_props.chan_user_data = params->channel; @@ -307,9 +321,9 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, ch_scratch.mhi.outstanding_threshold = 0; } ch_scratch.mhi.oob_mod_threshold = 4; - if (params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_DEFAULT || - params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_ENABLE) { - ch_scratch.mhi.burst_mode_enabled = true; + + if (burst_mode_enabled) { + ch_scratch.mhi.burst_mode_enabled = burst_mode_enabled; ch_scratch.mhi.polling_configuration = ipa3_mhi_get_ch_poll_cfg(client, params->ch_ctx_host, (ch_props.ring_len / ch_props.re_size)); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 554023ebfc60..73fb4993713c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1126,86 +1126,86 @@ static const struct ipa_ep_configuration ipa3_ep_mapping true, IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, - { 6, 2, 8, 16, IPA_EE_UC } }, + { 6, 2, 8, 16, IPA_EE_UC, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0][IPA_CLIENT_USB_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, - { 0, 8, 8, 16, IPA_EE_AP } }, + { 0, 8, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_APPS_LAN_PROD] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - { 8, 10, 8, 16, IPA_EE_AP } }, + { 8, 10, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_APPS_WAN_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, - { 2, 3, 16, 32, IPA_EE_AP } }, + { 2, 3, 16, 32, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_APPS_CMD_PROD] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY, QMB_MASTER_SELECT_DDR, - { 5, 4, 20, 24, IPA_EE_AP } }, + { 5, 4, 20, 24, IPA_EE_AP, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0][IPA_CLIENT_ODU_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, - { 1, 0, 8, 16, IPA_EE_AP } }, + { 1, 0, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_ETHERNET_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, - { 9, 0, 8, 16, IPA_EE_UC } }, + { 9, 0, 8, 16, IPA_EE_UC, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0][IPA_CLIENT_Q6_WAN_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - { 3, 0, 16, 32, IPA_EE_Q6 } }, + { 3, 0, 16, 32, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0][IPA_CLIENT_Q6_CMD_PROD] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - { 4, 1, 20, 24, IPA_EE_Q6 } }, + { 4, 1, 20, 24, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } }, /* Only for test purpose */ [IPA_4_0][IPA_CLIENT_TEST_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - {0, 8, 8, 16, IPA_EE_AP } }, + {0, 8, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_TEST1_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - {0, 8, 8, 16, IPA_EE_AP } }, + {0, 8, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_TEST2_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - { 1, 0, 8, 16, IPA_EE_AP } }, + { 1, 0, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_TEST3_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - { 7, 9, 8, 16, IPA_EE_AP } }, + { 7, 9, 8, 16, IPA_EE_AP, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0][IPA_CLIENT_TEST4_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - {8, 10, 8, 16, IPA_EE_AP } }, + {8, 10, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_WLAN1_CONS] = { @@ -1213,73 +1213,73 @@ static const struct ipa_ep_configuration ipa3_ep_mapping false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 18, 3, 6, 9, IPA_EE_UC } }, + { 18, 3, 6, 9, IPA_EE_UC, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0][IPA_CLIENT_WLAN2_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 20, 13, 9, 9, IPA_EE_AP } }, + { 20, 13, 9, 9, IPA_EE_AP, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0][IPA_CLIENT_WLAN3_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 21, 14, 9, 9, IPA_EE_AP } }, + { 21, 14, 9, 9, IPA_EE_AP, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0][IPA_CLIENT_USB_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 19, 12, 9, 9, IPA_EE_AP } }, + { 19, 12, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_USB_DPL_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 15, 7, 5, 5, IPA_EE_AP } }, + { 15, 7, 5, 5, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_APPS_LAN_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 10, 5, 9, 9, IPA_EE_AP } }, + { 10, 5, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_APPS_WAN_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 11, 6, 9, 9, IPA_EE_AP } }, + { 11, 6, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_ODU_EMB_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 17, 1, 17, 17, IPA_EE_AP } }, + { 17, 1, 17, 17, IPA_EE_AP, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0][IPA_CLIENT_ETHERNET_CONS] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 22, 1, 17, 17, IPA_EE_UC } }, + { 22, 1, 17, 17, IPA_EE_UC, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0][IPA_CLIENT_Q6_LAN_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 14, 4, 9, 9, IPA_EE_Q6 } }, + { 14, 4, 9, 9, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0][IPA_CLIENT_Q6_WAN_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 13, 3, 9, 9, IPA_EE_Q6 } }, + { 13, 3, 9, 9, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 16, 5, 9, 9, IPA_EE_Q6 } }, + { 16, 5, 9, 9, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } }, /* Only for test purpose */ /* MBIM aggregation test pipes should have the same QMB as USB_CONS */ [IPA_4_0][IPA_CLIENT_TEST_CONS] = { @@ -1287,38 +1287,38 @@ static const struct ipa_ep_configuration ipa3_ep_mapping false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 11, 6, 9, 9, IPA_EE_AP } }, + { 11, 6, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_TEST1_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 11, 6, 9, 9, IPA_EE_AP } }, + { 11, 6, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_TEST2_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 12, 2, 5, 5, IPA_EE_AP } }, + { 12, 2, 5, 5, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_TEST3_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 19, 12, 9, 9, IPA_EE_AP } }, + { 19, 12, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0][IPA_CLIENT_TEST4_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 21, 14, 9, 9, IPA_EE_AP } }, + { 21, 14, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, /* Dummy consumer (pipe 31) is used in L2TP rt rule */ [IPA_4_0][IPA_CLIENT_DUMMY_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 31, 31, 8, 8, IPA_EE_AP } }, + { 31, 31, 8, 8, IPA_EE_AP, GSI_USE_PREFETCH_BUFS } }, /* IPA_4_0_MHI */ [IPA_4_0_MHI][IPA_CLIENT_APPS_WAN_PROD] = { @@ -1326,74 +1326,74 @@ static const struct ipa_ep_configuration ipa3_ep_mapping true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - { 2, 3, 16, 32, IPA_EE_AP } }, + { 2, 3, 16, 32, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_APPS_CMD_PROD] = { true, IPA_v4_0_MHI_GROUP_DDR, false, IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY, QMB_MASTER_SELECT_DDR, - { 5, 4, 20, 24, IPA_EE_AP } }, + { 5, 4, 20, 24, IPA_EE_AP, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0_MHI][IPA_CLIENT_MHI_PROD] = { true, IPA_v4_0_MHI_GROUP_PCIE, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_PCIE, - { 1, 0, 8, 16, IPA_EE_AP } }, + { 1, 0, 8, 16, IPA_EE_AP, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0_MHI][IPA_CLIENT_Q6_WAN_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - { 3, 0, 16, 32, IPA_EE_Q6 } }, + { 3, 0, 16, 32, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0_MHI][IPA_CLIENT_Q6_CMD_PROD] = { true, IPA_v4_0_MHI_GROUP_PCIE, false, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - { 4, 1, 20, 24, IPA_EE_Q6 } }, + { 4, 1, 20, 24, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0_MHI][IPA_CLIENT_MEMCPY_DMA_SYNC_PROD] = { true, IPA_v4_0_MHI_GROUP_DMA, false, IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY, QMB_MASTER_SELECT_DDR, - { 7, 9, 8, 16, IPA_EE_AP } }, + { 7, 9, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_MEMCPY_DMA_ASYNC_PROD] = { true, IPA_v4_0_MHI_GROUP_DMA, false, IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY, QMB_MASTER_SELECT_DDR, - { 8, 10, 8, 16, IPA_EE_AP } }, + { 8, 10, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, /* Only for test purpose */ [IPA_4_0_MHI][IPA_CLIENT_TEST_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - {0, 8, 8, 16, IPA_EE_AP } }, + {0, 8, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_TEST1_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - {0, 8, 8, 16, IPA_EE_AP } }, + {0, 8, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_TEST2_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - { 1, 0, 8, 16, IPA_EE_AP } }, + { 1, 0, 8, 16, IPA_EE_AP, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0_MHI][IPA_CLIENT_TEST3_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - {7, 9, 8, 16, IPA_EE_AP } }, + {7, 9, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_TEST4_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, - { 8, 10, 8, 16, IPA_EE_AP } }, + { 8, 10, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_APPS_LAN_CONS] = { @@ -1401,87 +1401,87 @@ static const struct ipa_ep_configuration ipa3_ep_mapping false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 10, 5, 9, 9, IPA_EE_AP } }, + { 10, 5, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_APPS_WAN_CONS] = { true, IPA_v4_0_MHI_GROUP_DDR, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 11, 6, 9, 9, IPA_EE_AP } }, + { 11, 6, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_MHI_CONS] = { true, IPA_v4_0_MHI_GROUP_PCIE, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_PCIE, - { 17, 1, 17, 17, IPA_EE_AP } }, + { 17, 1, 17, 17, IPA_EE_AP, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0_MHI][IPA_CLIENT_Q6_LAN_CONS] = { true, IPA_v4_0_MHI_GROUP_DDR, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 14, 4, 9, 9, IPA_EE_Q6 } }, + { 14, 4, 9, 9, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0_MHI][IPA_CLIENT_Q6_WAN_CONS] = { true, IPA_v4_0_MHI_GROUP_DDR, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 13, 3, 9, 9, IPA_EE_Q6 } }, + { 13, 3, 9, 9, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } }, [IPA_4_0_MHI][IPA_CLIENT_MEMCPY_DMA_SYNC_CONS] = { true, IPA_v4_0_MHI_GROUP_DMA, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_PCIE, - { 20, 13, 9, 9, IPA_EE_AP } }, + { 20, 13, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS] = { true, IPA_v4_0_MHI_GROUP_DMA, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_PCIE, - { 21, 14, 9, 9, IPA_EE_AP } }, + { 21, 14, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 16, 5, 9, 9, IPA_EE_Q6 } }, + { 16, 5, 9, 9, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS } }, /* Only for test purpose */ [IPA_4_0_MHI][IPA_CLIENT_TEST_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_PCIE, - { 11, 6, 9, 9, IPA_EE_AP } }, + { 11, 6, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_TEST1_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_PCIE, - { 11, 6, 9, 9, IPA_EE_AP } }, + { 11, 6, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_TEST2_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 12, 2, 5, 5, IPA_EE_AP } }, + { 12, 2, 5, 5, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_TEST3_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_PCIE, - { 19, 12, 9, 9, IPA_EE_AP } }, + { 19, 12, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, [IPA_4_0_MHI][IPA_CLIENT_TEST4_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_PCIE, - { 21, 14, 9, 9, IPA_EE_AP } }, + { 21, 14, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY } }, /* Dummy consumer (pipe 31) is used in L2TP rt rule */ [IPA_4_0_MHI][IPA_CLIENT_DUMMY_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 31, 31, 8, 8, IPA_EE_AP } }, + { 31, 31, 8, 8, IPA_EE_AP, GSI_USE_PREFETCH_BUFS } }, }; /** @@ -2133,6 +2133,28 @@ int ipa3_get_ep_mapping(enum ipa_client_type client) return ipa_ep_idx; } + +/** + * ipa_get_ep_prefetch_mode() - provide prefetch_mode endpoint + * @client: client type + * + * Return value: prefetch_mode + */ +enum gsi_prefetch_mode ipa_get_ep_prefetch_mode(enum ipa_client_type client) +{ + enum gsi_prefetch_mode prefetch_mode; + + if (client >= IPA_CLIENT_MAX || client < 0) { + IPAERR_RL("Bad client number: client =%d\n", client); + return -IPA_EP_NOT_ALLOCATED; + } + + prefetch_mode = ipa3_ep_mapping[ipa3_get_hw_type_index()][client]. + ipa_gsi_ep_info.prefetch_mode; + + return prefetch_mode; +} + /** * ipa3_get_gsi_ep_info() - provide gsi ep information * @client: IPA client value diff --git a/include/linux/ipa.h b/include/linux/ipa.h index 1a1c68e3a44e..2c316662670e 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -1156,6 +1156,7 @@ struct ipa_wdi_buffer_info { * @ipa_if_tlv: number of IPA_IF TLV * @ipa_if_aos: number of IPA_IF AOS * @ee: Execution environment + * @prefetch_mode: Prefetch mode to be used */ struct ipa_gsi_ep_config { int ipa_ep_num; @@ -1163,6 +1164,7 @@ struct ipa_gsi_ep_config { int ipa_if_tlv; int ipa_if_aos; int ee; + enum gsi_prefetch_mode prefetch_mode; }; /** -- GitLab From 7e4bcb40d393f22f93c2562c08627b293ec90ca8 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Thu, 31 May 2018 19:07:58 +0530 Subject: [PATCH 802/855] msm: ipa: gsi: mhi: Couple of code changes Couple of code changes, - Enable IPC logging for MHI driver. IPC logging was missed to enable on mhi driver, enable it. - Configure appropriate polling mode bit for MHI ep. A. For MHI --> IPA pipe: When resuming due to transition to M0, set the polling mode bit to 0. In other cases, restore it's value form when you stopped the channel. B. For IPA-->MHI pipe: Always restore the polling mode bit. Change-Id: Ibc203e8c9dc8d05107a5eba396c76e29c1646479 Signed-off-by: Mohammed Javid --- drivers/platform/msm/gsi/gsi.c | 60 +++++++++++++++++++ drivers/platform/msm/gsi/gsi.h | 1 + .../msm/ipa/ipa_clients/ipa_mhi_client.c | 34 +++++++++-- drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c | 32 ++++++++-- include/linux/msm_gsi.h | 19 ++++++ 5 files changed, 138 insertions(+), 8 deletions(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 1af34476651c..b2474dc80287 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -1876,6 +1876,32 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl, } EXPORT_SYMBOL(gsi_alloc_channel); +static void __gsi_read_channel_scratch(unsigned long chan_hdl, + union __packed gsi_channel_scratch * val) +{ + uint32_t reg; + + reg = gsi_readl(gsi_ctx->base + + GSI_EE_n_GSI_CH_k_SCRATCH_0_OFFS(chan_hdl, + gsi_ctx->per.ee)); + val->data.word1 = reg; + + reg = gsi_readl(gsi_ctx->base + + GSI_EE_n_GSI_CH_k_SCRATCH_1_OFFS(chan_hdl, + gsi_ctx->per.ee)); + val->data.word2 = reg; + + reg = gsi_readl(gsi_ctx->base + + GSI_EE_n_GSI_CH_k_SCRATCH_2_OFFS(chan_hdl, + gsi_ctx->per.ee)); + val->data.word3 = reg; + + reg = gsi_readl(gsi_ctx->base + + GSI_EE_n_GSI_CH_k_SCRATCH_3_OFFS(chan_hdl, + gsi_ctx->per.ee)); + val->data.word4 = reg; +} + static void __gsi_write_channel_scratch(unsigned long chan_hdl, union __packed gsi_channel_scratch val) { @@ -1936,6 +1962,40 @@ int gsi_write_channel_scratch(unsigned long chan_hdl, } EXPORT_SYMBOL(gsi_write_channel_scratch); +int gsi_read_channel_scratch(unsigned long chan_hdl, + union __packed gsi_channel_scratch * ch_scratch) +{ + struct gsi_chan_ctx *ctx; + + if (!gsi_ctx) { + pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__); + return -GSI_STATUS_NODEV; + } + + if (chan_hdl >= gsi_ctx->max_ch) { + GSIERR("bad params chan_hdl=%lu\n", chan_hdl); + return -GSI_STATUS_INVALID_PARAMS; + } + + if (gsi_ctx->chan[chan_hdl].state != GSI_CHAN_STATE_ALLOCATED && + gsi_ctx->chan[chan_hdl].state != GSI_CHAN_STATE_STARTED && + gsi_ctx->chan[chan_hdl].state != GSI_CHAN_STATE_STOPPED) { + GSIERR("bad state %d\n", + gsi_ctx->chan[chan_hdl].state); + return -GSI_STATUS_UNSUPPORTED_OP; + } + + ctx = &gsi_ctx->chan[chan_hdl]; + + mutex_lock(&ctx->mlock); + __gsi_read_channel_scratch(chan_hdl, ch_scratch); + ctx->restore_scratch = *ch_scratch; + mutex_unlock(&ctx->mlock); + + return GSI_STATUS_SUCCESS; +} +EXPORT_SYMBOL(gsi_read_channel_scratch); + int gsi_query_channel_db_addr(unsigned long chan_hdl, uint32_t *db_addr_wp_lsb, uint32_t *db_addr_wp_msb) { diff --git a/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h index 92849d9d10b6..4a3f4ec82032 100644 --- a/drivers/platform/msm/gsi/gsi.h +++ b/drivers/platform/msm/gsi/gsi.h @@ -137,6 +137,7 @@ struct gsi_chan_ctx { bool allocated; atomic_t poll_mode; union __packed gsi_channel_scratch scratch; + union __packed gsi_channel_scratch restore_scratch; struct gsi_chan_stats stats; bool enable_dp_stats; bool print_dp_stats; diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c index 906e911091af..b4af0a0948bc 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -24,13 +24,39 @@ #endif #define IPA_MHI_DRV_NAME "ipa_mhi_client" + #define IPA_MHI_DBG(fmt, args...) \ - pr_debug(IPA_MHI_DRV_NAME " %s:%d " fmt, \ - __func__, __LINE__, ## args) + do { \ + pr_debug(IPA_MHI_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + IPA_MHI_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPA_MHI_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +#define IPA_MHI_DBG_LOW(fmt, args...) \ + do { \ + pr_debug(IPA_MHI_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPA_MHI_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + + #define IPA_MHI_ERR(fmt, args...) \ - pr_err(IPA_MHI_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) + do { \ + pr_err(IPA_MHI_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + IPA_MHI_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPA_MHI_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + #define IPA_MHI_FUNC_ENTRY() \ IPA_MHI_DBG("ENTRY\n") + #define IPA_MHI_FUNC_EXIT() \ IPA_MHI_DBG("EXIT\n") diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c index 82cd81878903..a07a9d102118 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c @@ -56,9 +56,9 @@ #define IPA_MHI_FUNC_ENTRY() \ - IPA_MHI_DBG_LOW("ENTRY\n") + IPA_MHI_DBG("ENTRY\n") #define IPA_MHI_FUNC_EXIT() \ - IPA_MHI_DBG_LOW("EXIT\n") + IPA_MHI_DBG("EXIT\n") #define IPA_MHI_MAX_UL_CHANNELS 1 #define IPA_MHI_MAX_DL_CHANNELS 1 @@ -549,6 +549,7 @@ int ipa3_mhi_resume_channels_internal(enum ipa_client_type client, int res; int ipa_ep_idx; struct ipa3_ep_context *ep; + union __packed gsi_channel_scratch gsi_ch_scratch; IPA_MHI_FUNC_ENTRY(); @@ -563,11 +564,34 @@ int ipa3_mhi_resume_channels_internal(enum ipa_client_type client, /* * set polling mode bit to DB mode before * resuming the channel + * + * For MHI-->IPA pipes: + * when resuming due to transition to M0, + * set the polling mode bit to 0. + * In other cases, restore it's value form + * when you stopped the channel. + * Here, after successful resume client move to M0 state. + * So, by default setting polling mode bit to 0. + * + * For IPA-->MHI pipe: + * always restore the polling mode bit. */ + + res = gsi_read_channel_scratch( + ep->gsi_chan_hdl, &gsi_ch_scratch); + if (res) { + IPA_MHI_ERR("Read ch scratch fail %d\n" + , res); + return res; + } + + if (IPA_CLIENT_IS_PROD(client)) + gsi_ch_scratch.mhi.polling_mode = false; + res = gsi_write_channel_scratch( - ep->gsi_chan_hdl, ch_scratch); + ep->gsi_chan_hdl, gsi_ch_scratch); if (res) { - IPA_MHI_ERR("write ch scratch fail %d\n" + IPA_MHI_ERR("Write ch scratch fail %d\n" , res); return res; } diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h index 3b1e0e7be518..79e7daa1ebf5 100644 --- a/include/linux/msm_gsi.h +++ b/include/linux/msm_gsi.h @@ -853,6 +853,18 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl, int gsi_write_channel_scratch(unsigned long chan_hdl, union __packed gsi_channel_scratch val); +/** + * gsi_read_channel_scratch - Peripheral should call this function to + * read the scratch area of the channel context + * + * @chan_hdl: Client handle previously obtained from + * gsi_alloc_channel + * + * @Return gsi_status + */ +int gsi_read_channel_scratch(unsigned long chan_hdl, + union __packed gsi_channel_scratch *ch_scratch); + /** * gsi_start_channel - Peripheral should call this function to * start a channel i.e put into running state @@ -1111,6 +1123,7 @@ int gsi_halt_channel_ee(unsigned int chan_idx, unsigned int ee, int *code); * gsi_alloc_channel (for as many channels as needed; channels can have * no event ring, an exclusive event ring or a shared event ring) * gsi_write_channel_scratch + * gsi_read_channel_scratch * gsi_start_channel * gsi_queue_xfer/gsi_start_xfer * gsi_config_channel_mode/gsi_poll_channel (if clients wants to poll on @@ -1195,6 +1208,12 @@ static inline int gsi_write_channel_scratch(unsigned long chan_hdl, return -GSI_STATUS_UNSUPPORTED_OP; } +static inline int gsi_read_channel_scratch(unsigned long chan_hdl, + union __packed gsi_channel_scratch *ch_scratch) +{ + return -GSI_STATUS_UNSUPPORTED_OP; +} + static inline int gsi_start_channel(unsigned long chan_hdl) { return -GSI_STATUS_UNSUPPORTED_OP; -- GitLab From 913d69890401c27312dce2550ee2e36a5a50ff96 Mon Sep 17 00:00:00 2001 From: Vikash Garodia Date: Wed, 13 Jun 2018 12:46:43 +0530 Subject: [PATCH 803/855] msm: vidc: Unset mem core for unused clocks For a SDM670 SKU, one video core is disabled. The memory associated with the disable core remains ON as the associated clock keeps it ON. Set the clock flags to disable the mem_core for disable video core. Change-Id: Ife973b25d247d8b562372c87d7b59f8a583f8365 Signed-off-by: Vikash Garodia --- drivers/media/platform/msm/vidc/msm_vidc_res_parse.c | 6 ++++++ drivers/media/platform/msm/vidc/msm_vidc_resources.h | 3 ++- drivers/media/platform/msm/vidc/venus_hfi.c | 11 +++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index 530fe3a5703a..1dc6723ea358 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -25,6 +25,7 @@ enum clock_properties { CLOCK_PROP_HAS_SCALING = 1 << 0, CLOCK_PROP_HAS_MEM_RETENTION = 1 << 1, + CLOCK_PROP_DISABLE_MEMCORE_ONLY = 1 << 2, }; #define PERF_GOV "performance" @@ -666,6 +667,11 @@ static int msm_vidc_load_clock_table( else vc->has_mem_retention = false; + if (clock_props[c] & CLOCK_PROP_DISABLE_MEMCORE_ONLY) + vc->disable_memcore_only = true; + else + vc->disable_memcore_only = false; + dprintk(VIDC_DBG, "Found clock %s: scale-able = %s\n", vc->name, vc->count ? "yes" : "no"); } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h index 23e33fe104f2..06d8fa5c8b53 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -90,6 +90,7 @@ struct clock_info { u32 count; bool has_scaling; bool has_mem_retention; + bool disable_memcore_only; }; struct clock_set { diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index ade04e32c320..d2e56f348002 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -1097,6 +1097,8 @@ static int __set_clocks(struct venus_hfi_device *device, u32 freq) int rc = 0; venus_hfi_for_each_clock(device, cl) { + if (cl->disable_memcore_only) + continue; if (cl->has_scaling) {/* has_scaling */ device->clk_freq = freq; rc = clk_set_rate(cl->clk, freq); @@ -3362,6 +3364,8 @@ static inline void __disable_unprepare_clks(struct venus_hfi_device *device) } venus_hfi_for_each_clock_reverse(device, cl) { + if (cl->disable_memcore_only) + continue; dprintk(VIDC_DBG, "Clock: %s disable and unprepare\n", cl->name); rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_PERIPH); @@ -3391,6 +3395,11 @@ static inline int __prepare_enable_clks(struct venus_hfi_device *device) } venus_hfi_for_each_clock(device, cl) { + /* MEM CORE is ON by default. Unset it for unused clocks*/ + if (cl->disable_memcore_only) { + clk_set_flags(cl->clk, CLKFLAG_NORETAIN_MEM); + continue; + } /* * For the clocks we control, set the rate prior to preparing * them. Since we don't really have a load at this point, scale @@ -3428,6 +3437,8 @@ static inline int __prepare_enable_clks(struct venus_hfi_device *device) fail_clk_enable: venus_hfi_for_each_clock_reverse_continue(device, cl, c) { + if (cl->disable_memcore_only) + continue; dprintk(VIDC_ERR, "Clock: %s disable and unprepare\n", cl->name); clk_disable_unprepare(cl->clk); -- GitLab From d1b20639615ab424a9f214502a4fcb79c69196a0 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:48 +0100 Subject: [PATCH 804/855] debugfs: implement per-file removal protection Since commit 49d200deaa68 ("debugfs: prevent access to removed files' private data"), accesses to a file's private data are protected from concurrent removal by covering all file_operations with a SRCU read section and sychronizing with those before returning from debugfs_remove() by means of synchronize_srcu(). As pointed out by Johannes Berg, there are debugfs files with forever blocking file_operations. Their corresponding SRCU read side sections would block any debugfs_remove() forever as well, even unrelated ones. This results in a livelock. Because a remover can't cancel any indefinite blocking within foreign files, this is a problem. Resolve this by introducing support for more granular protection on a per-file basis. This is implemented by introducing an 'active_users' refcount_t to the per-file struct debugfs_fsdata state. At file creation time, it is set to one and a debugfs_remove() will drop that initial reference. The new debugfs_file_get() and debugfs_file_put(), intended to be used in place of former debugfs_use_file_start() and debugfs_use_file_finish(), increment and decrement it respectively. Once the count drops to zero, debugfs_file_put() will signal a completion which is possibly being waited for from debugfs_remove(). Thus, as long as there is a debugfs_file_get() not yet matched by a corresponding debugfs_file_put() around, debugfs_remove() will block. Actual users of debugfs_use_file_start() and -finish() will get converted to the new debugfs_file_get() and debugfs_file_put() by followup patches. Change-Id: I8240a7e8f45bc2003c78a49369282f4d49f82171 Fixes: 49d200deaa68 ("debugfs: prevent access to removed files' private data") Reported-by: Johannes Berg Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: e9117a5a4bf65d8e99f060d356a04d27a60b436d Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git [tingwei@codeaurora.org: Add refcount.h to resolve compile error] Signed-off-by: Tingwei Zhang --- fs/debugfs/file.c | 48 +++++++++++++++++++++++++++++++++++++++++ fs/debugfs/inode.c | 29 +++++++++++++++++++------ fs/debugfs/internal.h | 4 ++++ include/linux/debugfs.h | 11 ++++++++++ 4 files changed, 86 insertions(+), 6 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 15655a1a0704..081d74d390a6 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -109,6 +109,54 @@ const struct file_operations *debugfs_real_fops(const struct file *filp) } EXPORT_SYMBOL_GPL(debugfs_real_fops); +/** + * debugfs_file_get - mark the beginning of file data access + * @dentry: the dentry object whose data is being accessed. + * + * Up to a matching call to debugfs_file_put(), any successive call + * into the file removing functions debugfs_remove() and + * debugfs_remove_recursive() will block. Since associated private + * file data may only get freed after a successful return of any of + * the removal functions, you may safely access it after a successful + * call to debugfs_file_get() without worrying about lifetime issues. + * + * If -%EIO is returned, the file has already been removed and thus, + * it is not safe to access any of its data. If, on the other hand, + * it is allowed to access the file data, zero is returned. + */ +int debugfs_file_get(struct dentry *dentry) +{ + struct debugfs_fsdata *fsd = dentry->d_fsdata; + + /* Avoid starvation of removers. */ + if (d_unlinked(dentry)) + return -EIO; + + if (!refcount_inc_not_zero(&fsd->active_users)) + return -EIO; + + return 0; +} +EXPORT_SYMBOL_GPL(debugfs_file_get); + +/** + * debugfs_file_put - mark the end of file data access + * @dentry: the dentry object formerly passed to + * debugfs_file_get(). + * + * Allow any ongoing concurrent call into debugfs_remove() or + * debugfs_remove_recursive() blocked by a former call to + * debugfs_file_get() to proceed and return to its caller. + */ +void debugfs_file_put(struct dentry *dentry) +{ + struct debugfs_fsdata *fsd = dentry->d_fsdata; + + if (refcount_dec_and_test(&fsd->active_users)) + complete(&fsd->active_users_drained); +} +EXPORT_SYMBOL_GPL(debugfs_file_put); + static int open_proxy_open(struct inode *inode, struct file *filp) { const struct dentry *dentry = F_DENTRY(filp); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 82b84d87d181..dd1bb69437c0 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -340,6 +340,7 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode, inode->i_fop = proxy_fops; fsd->real_fops = real_fops; + refcount_set(&fsd->active_users, 1); dentry->d_fsdata = fsd; d_instantiate(dentry, inode); @@ -597,18 +598,34 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, } EXPORT_SYMBOL_GPL(debugfs_create_symlink); +static void __debugfs_remove_file(struct dentry *dentry, struct dentry *parent) +{ + struct debugfs_fsdata *fsd; + + simple_unlink(d_inode(parent), dentry); + d_delete(dentry); + fsd = dentry->d_fsdata; + init_completion(&fsd->active_users_drained); + if (!refcount_dec_and_test(&fsd->active_users)) + wait_for_completion(&fsd->active_users_drained); +} + static int __debugfs_remove(struct dentry *dentry, struct dentry *parent) { int ret = 0; if (simple_positive(dentry)) { dget(dentry); - if (d_is_dir(dentry)) - ret = simple_rmdir(d_inode(parent), dentry); - else - simple_unlink(d_inode(parent), dentry); - if (!ret) - d_delete(dentry); + if (!d_is_reg(dentry)) { + if (d_is_dir(dentry)) + ret = simple_rmdir(d_inode(parent), dentry); + else + simple_unlink(d_inode(parent), dentry); + if (!ret) + d_delete(dentry); + } else { + __debugfs_remove_file(dentry, parent); + } dput(dentry); } return ret; diff --git a/fs/debugfs/internal.h b/fs/debugfs/internal.h index 512601eed3ce..40669884d68f 100644 --- a/fs/debugfs/internal.h +++ b/fs/debugfs/internal.h @@ -12,6 +12,8 @@ #ifndef _DEBUGFS_INTERNAL_H_ #define _DEBUGFS_INTERNAL_H_ +#include + struct file_operations; /* declared over in file.c */ @@ -21,6 +23,8 @@ extern const struct file_operations debugfs_full_proxy_file_operations; struct debugfs_fsdata { const struct file_operations *real_fops; + refcount_t active_users; + struct completion active_users_drained; }; #endif /* _DEBUGFS_INTERNAL_H_ */ diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 557be0d80204..3c3e6ca0c7a1 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -96,6 +96,9 @@ void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu); const struct file_operations *debugfs_real_fops(const struct file *filp) __must_hold(&debugfs_srcu); +int debugfs_file_get(struct dentry *dentry); +void debugfs_file_put(struct dentry *dentry); + ssize_t debugfs_attr_read(struct file *file, char __user *buf, size_t len, loff_t *ppos); ssize_t debugfs_attr_write(struct file *file, const char __user *buf, @@ -220,6 +223,14 @@ static inline void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu) { } +static inline int debugfs_file_get(struct dentry *dentry) +{ + return 0; +} + +static inline void debugfs_file_put(struct dentry *dentry) +{ } + static inline ssize_t debugfs_attr_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) { -- GitLab From 2ab6fd48b97e1c010f8d486d19f3140cd1b80529 Mon Sep 17 00:00:00 2001 From: Vikash Garodia Date: Wed, 13 Jun 2018 12:59:22 +0530 Subject: [PATCH 805/855] ARM: dts: msm: Add video clocks on SDM670 For a SDM670 SKU, one video core is disabled. The memory associated with the disable core remains ON as the associated clock keeps it ON. Add the clocks and related configs in order to set the clock flags. Setting the desired flag for the associated clocks would disable the mem_core. Change-Id: Iae3c6850a8867bf58c5ab2501a598329aa6a758e Signed-off-by: Vikash Garodia --- arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi index a0b4a2211a6a..f5e9489887d5 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi @@ -129,15 +129,19 @@ /* Clocks */ clock-names = "core_clk", "iface_clk", "bus_clk", - "core0_clk", "core0_bus_clk"; + "core0_clk", "core0_bus_clk", "core1_clk", + "core1_bus_clk"; clocks = <&clock_videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>, <&clock_videocc VIDEO_CC_VENUS_CTL_AXI_CLK>, <&clock_videocc VIDEO_CC_VCODEC0_CORE_CLK>, - <&clock_videocc VIDEO_CC_VCODEC0_AXI_CLK>; + <&clock_videocc VIDEO_CC_VCODEC0_AXI_CLK>, + <&clock_videocc VIDEO_CC_VCODEC1_CORE_CLK>, + <&clock_videocc VIDEO_CC_VCODEC1_AXI_CLK>; qcom,proxy-clock-names = "core_clk", "iface_clk", - "bus_clk", "core0_clk", "core0_bus_clk"; - qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0>; + "bus_clk", "core0_clk", "core0_bus_clk", + "core1_clk", "core1_bus_clk"; + qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0 0x4 0x4>; qcom,allowed-clock-rates = <100000000 200000000 330000000 364700000>; -- GitLab From f6ba3d45b45dd396ce98fe50bf9d1ae333cc85e8 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:49 +0100 Subject: [PATCH 806/855] debugfs: debugfs_real_fops(): drop __must_hold sparse annotation Currently, debugfs_real_fops() is annotated with a __must_hold(&debugfs_srcu) sparse annotation. With the conversion of the SRCU based protection of users against concurrent file removals to a per-file refcount based scheme, this becomes wrong. Drop this annotation. Change-Id: I959c9b4519965132794e48ddb2e160ea130ff2fd Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: 055ab8e3e3d52e005d2047b14ce63551b3a8b8b5 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Tingwei Zhang --- fs/debugfs/file.c | 6 +----- include/linux/debugfs.h | 3 +-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 081d74d390a6..3bc3e2e69f80 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -98,13 +98,9 @@ EXPORT_SYMBOL_GPL(debugfs_use_file_finish); #define F_DENTRY(filp) ((filp)->f_path.dentry) const struct file_operations *debugfs_real_fops(const struct file *filp) - __must_hold(&debugfs_srcu) { struct debugfs_fsdata *fsd = F_DENTRY(filp)->d_fsdata; - /* - * Neither the pointer to the struct file_operations, nor its - * contents ever change -- srcu_dereference() is not needed here. - */ + return fsd->real_fops; } EXPORT_SYMBOL_GPL(debugfs_real_fops); diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 3c3e6ca0c7a1..04b70e3eefe9 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -93,8 +93,7 @@ int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx) void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu); -const struct file_operations *debugfs_real_fops(const struct file *filp) - __must_hold(&debugfs_srcu); +const struct file_operations *debugfs_real_fops(const struct file *filp); int debugfs_file_get(struct dentry *dentry); void debugfs_file_put(struct dentry *dentry); -- GitLab From 5602508bc78dbeab4504d9cd4e9ae7a96e929e24 Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Fri, 8 Jun 2018 20:08:04 +0800 Subject: [PATCH 807/855] trace: ipc_logging: Convert to debugfs_file_get() and -put() Convert all calls to the now obsolete debugfs_use_file_start() and debugfs_use_file_finish() from ipc_logging to the new debugfs_file_get() and debugfs_file_put() API. Change-Id: I83781f97cd5ee5d441a915afb1d235427c206003 Signed-off-by: Tingwei Zhang --- kernel/trace/ipc_logging_debug.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/kernel/trace/ipc_logging_debug.c b/kernel/trace/ipc_logging_debug.c index 7a4c6306eb05..3a13ef3b357e 100644 --- a/kernel/trace/ipc_logging_debug.c +++ b/kernel/trace/ipc_logging_debug.c @@ -78,17 +78,16 @@ static ssize_t debug_read_helper(struct file *file, char __user *buff, struct dentry *d = file->f_path.dentry; char *buffer; int bsize; - int srcu_idx; int r; - r = debugfs_use_file_start(d, &srcu_idx); + r = debugfs_file_get(d); if (!r) { ilctxt = file->private_data; r = kref_get_unless_zero(&ilctxt->refcount) ? 0 : -EIO; - } - debugfs_use_file_finish(srcu_idx); - if (r) + } else { return r; + } + debugfs_file_put(d); buffer = kmalloc(count, GFP_KERNEL); if (!buffer) { @@ -119,18 +118,17 @@ static ssize_t debug_write_ctrl(struct file *file, const char __user *buff, struct ipc_log_context *ilctxt; struct dentry *d = file->f_path.dentry; int bsize = 1; - int srcu_idx; int r; char local_buf[3]; - r = debugfs_use_file_start(d, &srcu_idx); + r = debugfs_file_get(d); if (!r) { ilctxt = file->private_data; r = kref_get_unless_zero(&ilctxt->refcount) ? 0 : -EIO; - } - debugfs_use_file_finish(srcu_idx); - if (r) + } else { return r; + } + debugfs_file_put(d); if (copy_from_user(local_buf, buff, bsize)) { count = -EFAULT; @@ -172,17 +170,16 @@ static ssize_t debug_read_ctrl(struct file *file, char __user *buff, struct ipc_log_context *ilctxt; struct dentry *d = file->f_path.dentry; int bsize = 2; - int srcu_idx; int r; - r = debugfs_use_file_start(d, &srcu_idx); + r = debugfs_file_get(d); if (!r) { ilctxt = file->private_data; r = kref_get_unless_zero(&ilctxt->refcount) ? 0 : -EIO; - } - debugfs_use_file_finish(srcu_idx); - if (r) + } else { return r; + } + debugfs_file_put(d); bsize = simple_read_from_buffer(buff, count, ppos, ilctxt->disabled?"1\n":"0\n", bsize); -- GitLab From 5300fd8e1ce6909cf93afb441517053d202ba7b3 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:50 +0100 Subject: [PATCH 808/855] debugfs: convert to debugfs_file_get() and -put() Convert all calls to the now obsolete debugfs_use_file_start() and debugfs_use_file_finish() from the debugfs core itself to the new debugfs_file_get() and debugfs_file_put() API. Change-Id: I335bdb5050297b561281c51f840a81097e8ea88a Fixes: 49d200deaa68 ("debugfs: prevent access to removed files' private data") Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: 69d29f9e6a53559895e6f785f6cf72daa738f132 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Tingwei Zhang --- fs/debugfs/file.c | 106 ++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 56 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 3bc3e2e69f80..ebf5b2faf91c 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -155,15 +155,12 @@ EXPORT_SYMBOL_GPL(debugfs_file_put); static int open_proxy_open(struct inode *inode, struct file *filp) { - const struct dentry *dentry = F_DENTRY(filp); + struct dentry *dentry = F_DENTRY(filp); const struct file_operations *real_fops = NULL; - int srcu_idx, r; + int r = 0; - r = debugfs_use_file_start(dentry, &srcu_idx); - if (r) { - r = -ENOENT; - goto out; - } + if (debugfs_file_get(dentry)) + return -ENOENT; real_fops = debugfs_real_fops(filp); real_fops = fops_get(real_fops); @@ -180,7 +177,7 @@ static int open_proxy_open(struct inode *inode, struct file *filp) r = real_fops->open(inode, filp); out: - debugfs_use_file_finish(srcu_idx); + debugfs_file_put(dentry); return r; } @@ -194,16 +191,16 @@ const struct file_operations debugfs_open_proxy_file_operations = { #define FULL_PROXY_FUNC(name, ret_type, filp, proto, args) \ static ret_type full_proxy_ ## name(proto) \ { \ - const struct dentry *dentry = F_DENTRY(filp); \ + struct dentry *dentry = F_DENTRY(filp); \ const struct file_operations *real_fops = \ debugfs_real_fops(filp); \ - int srcu_idx; \ ret_type r; \ \ - r = debugfs_use_file_start(dentry, &srcu_idx); \ - if (likely(!r)) \ - r = real_fops->name(args); \ - debugfs_use_file_finish(srcu_idx); \ + r = debugfs_file_get(dentry); \ + if (unlikely(r)) \ + return r; \ + r = real_fops->name(args); \ + debugfs_file_put(dentry); \ return r; \ } @@ -228,18 +225,15 @@ FULL_PROXY_FUNC(unlocked_ioctl, long, filp, static unsigned int full_proxy_poll(struct file *filp, struct poll_table_struct *wait) { - const struct dentry *dentry = F_DENTRY(filp); const struct file_operations *real_fops = debugfs_real_fops(filp); - int srcu_idx; + struct dentry *dentry = F_DENTRY(filp); unsigned int r = 0; - if (debugfs_use_file_start(dentry, &srcu_idx)) { - debugfs_use_file_finish(srcu_idx); + if (debugfs_file_get(dentry)) return POLLHUP; - } r = real_fops->poll(filp, wait); - debugfs_use_file_finish(srcu_idx); + debugfs_file_put(dentry); return r; } @@ -283,16 +277,13 @@ static void __full_proxy_fops_init(struct file_operations *proxy_fops, static int full_proxy_open(struct inode *inode, struct file *filp) { - const struct dentry *dentry = F_DENTRY(filp); + struct dentry *dentry = F_DENTRY(filp); const struct file_operations *real_fops = NULL; struct file_operations *proxy_fops = NULL; - int srcu_idx, r; + int r = 0; - r = debugfs_use_file_start(dentry, &srcu_idx); - if (r) { - r = -ENOENT; - goto out; - } + if (debugfs_file_get(dentry)) + return -ENOENT; real_fops = debugfs_real_fops(filp); real_fops = fops_get(real_fops); @@ -330,7 +321,7 @@ static int full_proxy_open(struct inode *inode, struct file *filp) kfree(proxy_fops); fops_put(real_fops); out: - debugfs_use_file_finish(srcu_idx); + debugfs_file_put(dentry); return r; } @@ -341,13 +332,14 @@ const struct file_operations debugfs_full_proxy_file_operations = { ssize_t debugfs_attr_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) { + struct dentry *dentry = F_DENTRY(file); ssize_t ret; - int srcu_idx; - ret = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!ret)) - ret = simple_attr_read(file, buf, len, ppos); - debugfs_use_file_finish(srcu_idx); + ret = debugfs_file_get(dentry); + if (unlikely(ret)) + return ret; + ret = simple_attr_read(file, buf, len, ppos); + debugfs_file_put(dentry); return ret; } EXPORT_SYMBOL_GPL(debugfs_attr_read); @@ -355,13 +347,14 @@ EXPORT_SYMBOL_GPL(debugfs_attr_read); ssize_t debugfs_attr_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { + struct dentry *dentry = F_DENTRY(file); ssize_t ret; - int srcu_idx; - ret = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!ret)) - ret = simple_attr_write(file, buf, len, ppos); - debugfs_use_file_finish(srcu_idx); + ret = debugfs_file_get(dentry); + if (unlikely(ret)) + return ret; + ret = simple_attr_write(file, buf, len, ppos); + debugfs_file_put(dentry); return ret; } EXPORT_SYMBOL_GPL(debugfs_attr_write); @@ -795,14 +788,14 @@ ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf, { char buf[3]; bool val; - int r, srcu_idx; + int r; + struct dentry *dentry = F_DENTRY(file); - r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!r)) - val = *(bool *)file->private_data; - debugfs_use_file_finish(srcu_idx); - if (r) + r = debugfs_file_get(dentry); + if (unlikely(r)) return r; + val = *(bool *)file->private_data; + debugfs_file_put(dentry); if (val) buf[0] = 'Y'; @@ -820,8 +813,9 @@ ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, char buf[32]; size_t buf_size; bool bv; - int r, srcu_idx; + int r; bool *val = file->private_data; + struct dentry *dentry = F_DENTRY(file); buf_size = min(count, (sizeof(buf)-1)); if (copy_from_user(buf, user_buf, buf_size)) @@ -829,12 +823,11 @@ ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, buf[buf_size] = '\0'; if (strtobool(buf, &bv) == 0) { - r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!r)) - *val = bv; - debugfs_use_file_finish(srcu_idx); - if (r) + r = debugfs_file_get(dentry); + if (unlikely(r)) return r; + *val = bv; + debugfs_file_put(dentry); } return count; @@ -896,14 +889,15 @@ static ssize_t read_file_blob(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct debugfs_blob_wrapper *blob = file->private_data; + struct dentry *dentry = F_DENTRY(file); ssize_t r; - int srcu_idx; - r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!r)) - r = simple_read_from_buffer(user_buf, count, ppos, blob->data, - blob->size); - debugfs_use_file_finish(srcu_idx); + r = debugfs_file_get(dentry); + if (unlikely(r)) + return r; + r = simple_read_from_buffer(user_buf, count, ppos, blob->data, + blob->size); + debugfs_file_put(dentry); return r; } -- GitLab From b6a1f9f505715dde7ed2a18a92732e14eb827e97 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:51 +0100 Subject: [PATCH 809/855] IB/hfi1: convert to debugfs_file_get() and -put() Convert all calls to the now obsolete debugfs_use_file_start() and debugfs_use_file_finish() to the new debugfs_file_get() and debugfs_file_put() API. Change-Id: I2079a2db214773eb6b5cc57c63743903f01942e3 Fixes: 49d200deaa68 ("debugfs: prevent access to removed files' private data") Signed-off-by: Nicolai Stange Reviewed-by: Dennis Dalessandro Signed-off-by: Greg Kroah-Hartman Git-commit: 7cda7b8f97da9382bb945d541a85cde58d5dac27 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Tingwei Zhang --- drivers/infiniband/hw/hfi1/debugfs.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/debugfs.c b/drivers/infiniband/hw/hfi1/debugfs.c index 632ba21759ab..0022660400d4 100644 --- a/drivers/infiniband/hw/hfi1/debugfs.c +++ b/drivers/infiniband/hw/hfi1/debugfs.c @@ -67,13 +67,13 @@ static ssize_t hfi1_seq_read( loff_t *ppos) { struct dentry *d = file->f_path.dentry; - int srcu_idx; ssize_t r; - r = debugfs_use_file_start(d, &srcu_idx); - if (likely(!r)) - r = seq_read(file, buf, size, ppos); - debugfs_use_file_finish(srcu_idx); + r = debugfs_file_get(d); + if (unlikely(r)) + return r; + r = seq_read(file, buf, size, ppos); + debugfs_file_put(d); return r; } @@ -83,13 +83,13 @@ static loff_t hfi1_seq_lseek( int whence) { struct dentry *d = file->f_path.dentry; - int srcu_idx; loff_t r; - r = debugfs_use_file_start(d, &srcu_idx); - if (likely(!r)) - r = seq_lseek(file, offset, whence); - debugfs_use_file_finish(srcu_idx); + r = debugfs_file_get(d); + if (unlikely(r)) + return r; + r = seq_lseek(file, offset, whence); + debugfs_file_put(d); return r; } -- GitLab From d3a70bf69744615c8ba6d0078b269f784453f492 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:52 +0100 Subject: [PATCH 810/855] debugfs: purge obsolete SRCU based removal protection Purge the SRCU based file removal race protection in favour of the new, refcount based debugfs_file_get()/debugfs_file_put() API. Change-Id: I59adb0c01d9701438a32a97fb41d5decae8bf71e Fixes: 49d200deaa68 ("debugfs: prevent access to removed files' private data") Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: c9afbec27089cd6b4e621b639f41c7fc726c3bf1 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Tingwei Zhang --- fs/debugfs/file.c | 48 ----------------------------------------- fs/debugfs/inode.c | 7 ------ include/linux/debugfs.h | 19 ---------------- lib/Kconfig.debug | 1 - 4 files changed, 75 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index ebf5b2faf91c..7de733ccdf6c 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include "internal.h" @@ -48,53 +47,6 @@ const struct file_operations debugfs_noop_file_operations = { .llseek = noop_llseek, }; -/** - * debugfs_use_file_start - mark the beginning of file data access - * @dentry: the dentry object whose data is being accessed. - * @srcu_idx: a pointer to some memory to store a SRCU index in. - * - * Up to a matching call to debugfs_use_file_finish(), any - * successive call into the file removing functions debugfs_remove() - * and debugfs_remove_recursive() will block. Since associated private - * file data may only get freed after a successful return of any of - * the removal functions, you may safely access it after a successful - * call to debugfs_use_file_start() without worrying about - * lifetime issues. - * - * If -%EIO is returned, the file has already been removed and thus, - * it is not safe to access any of its data. If, on the other hand, - * it is allowed to access the file data, zero is returned. - * - * Regardless of the return code, any call to - * debugfs_use_file_start() must be followed by a matching call - * to debugfs_use_file_finish(). - */ -int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx) - __acquires(&debugfs_srcu) -{ - *srcu_idx = srcu_read_lock(&debugfs_srcu); - barrier(); - if (d_unlinked(dentry)) - return -EIO; - return 0; -} -EXPORT_SYMBOL_GPL(debugfs_use_file_start); - -/** - * debugfs_use_file_finish - mark the end of file data access - * @srcu_idx: the SRCU index "created" by a former call to - * debugfs_use_file_start(). - * - * Allow any ongoing concurrent call into debugfs_remove() or - * debugfs_remove_recursive() blocked by a former call to - * debugfs_use_file_start() to proceed and return to its caller. - */ -void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu) -{ - srcu_read_unlock(&debugfs_srcu, srcu_idx); -} -EXPORT_SYMBOL_GPL(debugfs_use_file_finish); - #define F_DENTRY(filp) ((filp)->f_path.dentry) const struct file_operations *debugfs_real_fops(const struct file *filp) diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index dd1bb69437c0..9c4699038964 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -27,14 +27,11 @@ #include #include #include -#include #include "internal.h" #define DEBUGFS_DEFAULT_MODE 0700 -DEFINE_SRCU(debugfs_srcu); - static struct vfsmount *debugfs_mount; static int debugfs_mount_count; static bool debugfs_registered; @@ -659,8 +656,6 @@ void debugfs_remove(struct dentry *dentry) inode_unlock(d_inode(parent)); if (!ret) simple_release_fs(&debugfs_mount, &debugfs_mount_count); - - synchronize_srcu(&debugfs_srcu); } EXPORT_SYMBOL_GPL(debugfs_remove); @@ -734,8 +729,6 @@ void debugfs_remove_recursive(struct dentry *dentry) if (!__debugfs_remove(child, parent)) simple_release_fs(&debugfs_mount, &debugfs_mount_count); inode_unlock(d_inode(parent)); - - synchronize_srcu(&debugfs_srcu); } EXPORT_SYMBOL_GPL(debugfs_remove_recursive); diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 04b70e3eefe9..2e75ae2d850b 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -23,7 +23,6 @@ struct device; struct file_operations; -struct srcu_struct; struct debugfs_blob_wrapper { void *data; @@ -43,8 +42,6 @@ struct debugfs_regset32 { extern struct dentry *arch_debugfs_dir; -extern struct srcu_struct debugfs_srcu; - #define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \ static int __fops ## _open(struct inode *inode, struct file *file) \ { \ @@ -88,11 +85,6 @@ struct dentry *debugfs_create_automount(const char *name, void debugfs_remove(struct dentry *dentry); void debugfs_remove_recursive(struct dentry *dentry); -int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx) - __acquires(&debugfs_srcu); - -void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu); - const struct file_operations *debugfs_real_fops(const struct file *filp); int debugfs_file_get(struct dentry *dentry); @@ -211,17 +203,6 @@ static inline void debugfs_remove(struct dentry *dentry) static inline void debugfs_remove_recursive(struct dentry *dentry) { } -static inline int debugfs_use_file_start(const struct dentry *dentry, - int *srcu_idx) - __acquires(&debugfs_srcu) -{ - return 0; -} - -static inline void debugfs_use_file_finish(int srcu_idx) - __releases(&debugfs_srcu) -{ } - static inline int debugfs_file_get(struct dentry *dentry) { return 0; diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 37641d1c1f86..640818c67aa3 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -269,7 +269,6 @@ config PAGE_OWNER_ENABLE_DEFAULT config DEBUG_FS bool "Debug Filesystem" - select SRCU help debugfs is a virtual file system that kernel developers use to put debugging files into. Enable this option to be able to read and -- GitLab From f0a58a8b9e879ff217b35a9328929c9990d4c0f1 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:53 +0100 Subject: [PATCH 811/855] debugfs: call debugfs_real_fops() only after debugfs_file_get() The current implementation of debugfs_real_fops() relies on a debugfs_fsdata instance to be installed at ->d_fsdata. With future patches introducing lazy allocation of these, this requirement will be guaranteed to be fullfilled only inbetween a debugfs_file_get()/debugfs_file_put() pair. The full proxies' fops implemented by debugfs happen to be the only offenders. Fix them up by moving their debugfs_real_fops() calls past those to debugfs_file_get(). full_proxy_release() is special as it doesn't invoke debugfs_file_get() at all. Leave it alone for now. Change-Id: I77c899614d317a581dea72c96583cd9f55f97930 Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: 154b9d7512ae012aca7b4e90af67a72419ad1941 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Tingwei Zhang --- fs/debugfs/file.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 7de733ccdf6c..d92038c5f131 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -144,13 +144,13 @@ const struct file_operations debugfs_open_proxy_file_operations = { static ret_type full_proxy_ ## name(proto) \ { \ struct dentry *dentry = F_DENTRY(filp); \ - const struct file_operations *real_fops = \ - debugfs_real_fops(filp); \ + const struct file_operations *real_fops; \ ret_type r; \ \ r = debugfs_file_get(dentry); \ if (unlikely(r)) \ return r; \ + real_fops = debugfs_real_fops(filp); \ r = real_fops->name(args); \ debugfs_file_put(dentry); \ return r; \ @@ -177,13 +177,14 @@ FULL_PROXY_FUNC(unlocked_ioctl, long, filp, static unsigned int full_proxy_poll(struct file *filp, struct poll_table_struct *wait) { - const struct file_operations *real_fops = debugfs_real_fops(filp); struct dentry *dentry = F_DENTRY(filp); unsigned int r = 0; + const struct file_operations *real_fops; if (debugfs_file_get(dentry)) return POLLHUP; + real_fops = debugfs_real_fops(filp); r = real_fops->poll(filp, wait); debugfs_file_put(dentry); return r; -- GitLab From 5455f7b4255d5c050d63017ada46553aebbecde2 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:54 +0100 Subject: [PATCH 812/855] debugfs: defer debugfs_fsdata allocation to first usage Currently, __debugfs_create_file allocates one struct debugfs_fsdata instance for every file created. However, there are potentially many debugfs file around, most of which are never touched by userspace. Thus, defer the allocations to the first usage, i.e. to the first debugfs_file_get(). A dentry's ->d_fsdata starts out to point to the "real", user provided fops. After a debugfs_fsdata instance has been allocated (and the real fops pointer has been moved over into its ->real_fops member), ->d_fsdata is changed to point to it from then on. The two cases are distinguished by setting BIT(0) for the real fops case. struct debugfs_fsdata's foremost purpose is to track active users and to make debugfs_remove() block until they are done. Since no debugfs_fsdata instance means no active users, make debugfs_remove() return immediately in this case. Take care of possible races between debugfs_file_get() and debugfs_remove(): either debugfs_remove() must see a debugfs_fsdata instance and thus wait for possible active users or debugfs_file_get() must see a dead dentry and return immediately. Make a dentry's ->d_release(), i.e. debugfs_release_dentry(), check whether ->d_fsdata is actually a debugfs_fsdata instance before kfree()ing it. Similarly, make debugfs_real_fops() check whether ->d_fsdata is actually a debugfs_fsdata instance before returning it, otherwise emit a warning. The set of possible error codes returned from debugfs_file_get() has grown from -EIO to -EIO and -ENOMEM. Make open_proxy_open() and full_proxy_open() pass the -ENOMEM onwards to their callers. Change-Id: I978318e95910338b8a6d4da66c273f72bde864cc Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: 7d39bc50c47b3f8ed0e1a9d671ecb9ec02f10a2d Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Tingwei Zhang --- fs/debugfs/file.c | 55 ++++++++++++++++++++++++++++++++++++------- fs/debugfs/inode.c | 36 +++++++++++++++------------- fs/debugfs/internal.h | 8 +++++++ 3 files changed, 73 insertions(+), 26 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index d92038c5f131..0536072b60d7 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -53,6 +53,15 @@ const struct file_operations *debugfs_real_fops(const struct file *filp) { struct debugfs_fsdata *fsd = F_DENTRY(filp)->d_fsdata; + if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) { + /* + * Urgh, we've been called w/o a protecting + * debugfs_file_get(). + */ + WARN_ON(1); + return NULL; + } + return fsd->real_fops; } EXPORT_SYMBOL_GPL(debugfs_real_fops); @@ -74,9 +83,35 @@ EXPORT_SYMBOL_GPL(debugfs_real_fops); */ int debugfs_file_get(struct dentry *dentry) { - struct debugfs_fsdata *fsd = dentry->d_fsdata; + struct debugfs_fsdata *fsd; + void *d_fsd; + + d_fsd = READ_ONCE(dentry->d_fsdata); + if (!((unsigned long)d_fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) { + fsd = d_fsd; + } else { + fsd = kmalloc(sizeof(*fsd), GFP_KERNEL); + if (!fsd) + return -ENOMEM; + + fsd->real_fops = (void *)((unsigned long)d_fsd & + ~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); + refcount_set(&fsd->active_users, 1); + init_completion(&fsd->active_users_drained); + if (cmpxchg(&dentry->d_fsdata, d_fsd, fsd) != d_fsd) { + kfree(fsd); + fsd = READ_ONCE(dentry->d_fsdata); + } + } - /* Avoid starvation of removers. */ + /* + * In case of a successful cmpxchg() above, this check is + * strictly necessary and must follow it, see the comment in + * __debugfs_remove_file(). + * OTOH, if the cmpxchg() hasn't been executed or wasn't + * successful, this serves the purpose of not starving + * removers. + */ if (d_unlinked(dentry)) return -EIO; @@ -98,7 +133,7 @@ EXPORT_SYMBOL_GPL(debugfs_file_get); */ void debugfs_file_put(struct dentry *dentry) { - struct debugfs_fsdata *fsd = dentry->d_fsdata; + struct debugfs_fsdata *fsd = READ_ONCE(dentry->d_fsdata); if (refcount_dec_and_test(&fsd->active_users)) complete(&fsd->active_users_drained); @@ -109,10 +144,11 @@ static int open_proxy_open(struct inode *inode, struct file *filp) { struct dentry *dentry = F_DENTRY(filp); const struct file_operations *real_fops = NULL; - int r = 0; + int r; - if (debugfs_file_get(dentry)) - return -ENOENT; + r = debugfs_file_get(dentry); + if (r) + return r == -EIO ? -ENOENT : r; real_fops = debugfs_real_fops(filp); real_fops = fops_get(real_fops); @@ -233,10 +269,11 @@ static int full_proxy_open(struct inode *inode, struct file *filp) struct dentry *dentry = F_DENTRY(filp); const struct file_operations *real_fops = NULL; struct file_operations *proxy_fops = NULL; - int r = 0; + int r; - if (debugfs_file_get(dentry)) - return -ENOENT; + r = debugfs_file_get(dentry); + if (r) + return r == -EIO ? -ENOENT : r; real_fops = debugfs_real_fops(filp); real_fops = fops_get(real_fops); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 9c4699038964..f7f672db1cdb 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -184,7 +184,10 @@ static const struct super_operations debugfs_super_operations = { static void debugfs_release_dentry(struct dentry *dentry) { - kfree(dentry->d_fsdata); + void *fsd = dentry->d_fsdata; + + if (!((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) + kfree(dentry->d_fsdata); } static struct vfsmount *debugfs_automount(struct path *path) @@ -310,35 +313,25 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode, { struct dentry *dentry; struct inode *inode; - struct debugfs_fsdata *fsd; - - fsd = kmalloc(sizeof(*fsd), GFP_KERNEL); - if (!fsd) - return NULL; if (!(mode & S_IFMT)) mode |= S_IFREG; BUG_ON(!S_ISREG(mode)); dentry = start_creating(name, parent); - if (IS_ERR(dentry)) { - kfree(fsd); + if (IS_ERR(dentry)) return NULL; - } inode = debugfs_get_inode(dentry->d_sb); - if (unlikely(!inode)) { - kfree(fsd); + if (unlikely(!inode)) return failed_creating(dentry); - } inode->i_mode = mode; inode->i_private = data; inode->i_fop = proxy_fops; - fsd->real_fops = real_fops; - refcount_set(&fsd->active_users, 1); - dentry->d_fsdata = fsd; + dentry->d_fsdata = (void *)((unsigned long)real_fops | + DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); d_instantiate(dentry, inode); fsnotify_create(d_inode(dentry->d_parent), dentry); @@ -601,8 +594,17 @@ static void __debugfs_remove_file(struct dentry *dentry, struct dentry *parent) simple_unlink(d_inode(parent), dentry); d_delete(dentry); - fsd = dentry->d_fsdata; - init_completion(&fsd->active_users_drained); + + /* + * Paired with the closing smp_mb() implied by a successful + * cmpxchg() in debugfs_file_get(): either + * debugfs_file_get() must see a dead dentry or we must see a + * debugfs_fsdata instance at ->d_fsdata here (or both). + */ + smp_mb(); + fsd = READ_ONCE(dentry->d_fsdata); + if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) + return; if (!refcount_dec_and_test(&fsd->active_users)) wait_for_completion(&fsd->active_users_drained); } diff --git a/fs/debugfs/internal.h b/fs/debugfs/internal.h index 40669884d68f..49ba8dde85ef 100644 --- a/fs/debugfs/internal.h +++ b/fs/debugfs/internal.h @@ -27,4 +27,12 @@ struct debugfs_fsdata { struct completion active_users_drained; }; +/* + * A dentry's ->d_fsdata either points to the real fops or to a + * dynamically allocated debugfs_fsdata instance. + * In order to distinguish between these two cases, a real fops + * pointer gets its lowest bit set. + */ +#define DEBUGFS_FSDATA_IS_REAL_FOPS_BIT BIT(0) + #endif /* _DEBUGFS_INTERNAL_H_ */ -- GitLab From 1e96e31d5a2265b325a7045cfdaca653031387ba Mon Sep 17 00:00:00 2001 From: zhaochen Date: Wed, 13 Jun 2018 17:44:50 +0800 Subject: [PATCH 813/855] icm20602: fix attribute show and add ldo control In driver icm20602 there is no attribute show on the sysfs and we need use ldo to supply the vdd. Change-Id: Iae1d75da08c4a9b0d905ee06c54d81629851ddfb Signed-off-by: zhaochen --- .../iio/imu/inv_icm20602/inv_icm20602_bsp.c | 30 ++-- .../iio/imu/inv_icm20602/inv_icm20602_core.c | 140 +++++++++++++----- .../iio/imu/inv_icm20602/inv_icm20602_iio.h | 6 + .../iio/imu/inv_icm20602/inv_icm20602_ring.c | 12 +- 4 files changed, 123 insertions(+), 65 deletions(-) diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c index 9968e44d91d9..0ebc9ab6dd46 100644 --- a/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c @@ -99,7 +99,6 @@ int icm20602_bulk_read(struct inv_icm20602_state *st, { int result = MPU_SUCCESS; char tx_buf[2] = {0x0, 0x0}; - int tmp_size = size; u8 *tmp_buf = buf; struct i2c_msg msg[2]; @@ -225,7 +224,7 @@ int icm20602_read_raw(struct inv_icm20602_state *st, { struct struct_icm20602_raw_data raw_data; - if (type & ACCEL != 0) { + if ((type) & (ACCEL) != 0) { icm20602_read_reg(st, reg_set_20602.ACCEL_XOUT_H.address, &raw_data.ACCEL_XOUT_H); @@ -257,7 +256,7 @@ int icm20602_read_raw(struct inv_icm20602_state *st, raw_data.ACCEL_ZOUT_L); } - if (type & GYRO != 0) { + if ((type) & (GYRO) != 0) { icm20602_read_reg(st, reg_set_20602.GYRO_XOUT_H.address, &raw_data.GYRO_XOUT_H); @@ -327,7 +326,7 @@ int icm20602_start_fifo(struct inv_icm20602_state *st) return MPU_SUCCESS; } -static int icm20602_stop_fifo(struct inv_icm20602_state *st) +int icm20602_stop_fifo(struct inv_icm20602_state *st) { struct icm20602_user_config *config = NULL; @@ -434,10 +433,7 @@ static int icm20602_read_ST_code(struct inv_icm20602_state *st) static int icm20602_set_self_test(struct inv_icm20602_state *st) { uint8_t raw_data[6] = {0, 0, 0, 0, 0, 0}; - uint8_t selfTest[6]; - float factory_trim[6]; int result = 0; - int ii; reg_set_20602.SMPLRT_DIV.reg_u.REG.SMPLRT_DIV = 0; result |= icm20602_write_reg_simple(st, reg_set_20602.SMPLRT_DIV); @@ -456,7 +452,7 @@ static int icm20602_set_self_test(struct inv_icm20602_state *st) reg_set_20602.ACCEL_CONFIG.reg_u.REG.ACCEL_FS_SEL = ICM20602_ACC_FSR_2G; result |= icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG); - //icm20602_read_ST_code(st); + icm20602_read_ST_code(st); return 0; } @@ -466,8 +462,7 @@ static int icm20602_do_test_acc(struct inv_icm20602_state *st, { struct struct_icm20602_real_data *real_data = kmalloc(sizeof(struct inv_icm20602_state), GFP_ATOMIC); - struct icm20602_user_config *config = st->config; - int i, j; + int i; for (i = 0; i < SELFTEST_COUNT; i++) { icm20602_read_raw(st, real_data, ACCEL); @@ -514,7 +509,7 @@ static int icm20602_do_test_gyro(struct inv_icm20602_state *st, { struct struct_icm20602_real_data *real_data = kmalloc(sizeof(struct inv_icm20602_state), GFP_ATOMIC); - int i, j; + int i; for (i = 0; i < SELFTEST_COUNT; i++) { icm20602_read_raw(st, real_data, GYRO); @@ -570,7 +565,7 @@ static bool icm20602_check_acc_selftest(struct inv_icm20602_state *st, st_otp.Y = (st_otp.Y != 0) ? mpu_st_tb[acc_ST_code.Y - 1] : 0; st_otp.Z = (st_otp.Z != 0) ? mpu_st_tb[acc_ST_code.Z - 1] : 0; - if (st_otp.X & st_otp.Y & st_otp.Z == 0) + if ((st_otp.X) & (st_otp.Y) & (st_otp.Z) == 0) otp_value_zero = true; st_shift_cust.X = acc_st->X - acc->X; @@ -627,11 +622,11 @@ static int icm20602_check_gyro_selftest(struct inv_icm20602_state *st, gyro_ST_code.Y = st->config->gyro_self_test.Y; gyro_ST_code.Z = st->config->gyro_self_test.Z; - st_otp.X = (st_otp.X != 0) ? mpu_st_tb[gyro_ST_code.X - 1] : 0; - st_otp.Y = (st_otp.Y != 0) ? mpu_st_tb[gyro_ST_code.Y - 1] : 0; - st_otp.Z = (st_otp.Z != 0) ? mpu_st_tb[gyro_ST_code.Z - 1] : 0; + st_otp.X = (gyro_ST_code.X != 0) ? mpu_st_tb[gyro_ST_code.X - 1] : 0; + st_otp.Y = (gyro_ST_code.Y != 0) ? mpu_st_tb[gyro_ST_code.Y - 1] : 0; + st_otp.Z = (gyro_ST_code.Z != 0) ? mpu_st_tb[gyro_ST_code.Z - 1] : 0; - if (st_otp.X & st_otp.Y & st_otp.Z == 0) + if ((st_otp.X) & (st_otp.Y) & (st_otp.Z) == 0) otp_value_zero = true; st_shift_cust.X = gyro_st->X - gyro->X; @@ -741,8 +736,6 @@ static int icm20602_initialize_gyro(struct inv_icm20602_state *st) { struct icm20602_user_config *config = NULL; int result = MPU_SUCCESS; - int sample_rate; - uint8_t fchoice_b; if (st == NULL) return -MPU_FAIL; @@ -928,7 +921,6 @@ int icm20602_detect(struct inv_icm20602_state *st) { int result = MPU_SUCCESS; uint8_t retry = 0, val = 0; - uint8_t usr_ctrl = 0; pr_debug("icm20602_detect\n"); /* reset to make sure previous state are not there */ diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c index 15df4479a5e1..7dda14e33428 100644 --- a/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c @@ -29,6 +29,7 @@ #include #include #include "inv_icm20602_iio.h" +#include /* Attribute of icm20602 device init show */ static ssize_t inv_icm20602_init_show(struct device *dev, @@ -89,7 +90,10 @@ static IIO_DEVICE_ATTR( static ssize_t inv_gyro_lpf_show(struct device *dev, struct device_attribute *attr, char *buf) { - return 0; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + return snprintf(buf, 4, "%d\n", st->config->gyro_lpf); } static ssize_t inv_gyro_lpf_store(struct device *dev, @@ -105,6 +109,7 @@ static ssize_t inv_gyro_lpf_store(struct device *dev, if (gyro_lpf > INV_ICM20602_GYRO_LFP_NUM) return -EINVAL; config->gyro_lpf = gyro_lpf; + return count; } static IIO_DEVICE_ATTR( @@ -118,7 +123,10 @@ static IIO_DEVICE_ATTR( static ssize_t inv_gyro_fsr_show(struct device *dev, struct device_attribute *attr, char *buf) { - return 0; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + return snprintf(buf, 4, "%d\n", st->config->gyro_fsr); } static ssize_t inv_gyro_fsr_store(struct device *dev, @@ -145,30 +153,37 @@ static IIO_DEVICE_ATTR( inv_gyro_fsr_store, 0); -/* Attribute of gyro_self_test */ -static ssize_t inv_gyro_self_test_show(struct device *dev, +/* Attribute of self_test */ +static ssize_t inv_self_test_show(struct device *dev, struct device_attribute *attr, char *buf) { return 0; } -static ssize_t inv_gyro_self_test_store(struct device *dev, +static ssize_t inv_self_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - return 0; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + icm20602_self_test(st); + return count; } static IIO_DEVICE_ATTR( - inv_icm20602_gyro_self_test, + inv_icm20602_self_test, 0644, - inv_gyro_self_test_show, - inv_gyro_self_test_store, + inv_self_test_show, + inv_self_test_store, 0); /* Attribute of gyro fsr base on enum inv_icm20602_acc_fsr_e */ static ssize_t inv_gyro_acc_fsr_show(struct device *dev, struct device_attribute *attr, char *buf) { - return 0; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + return snprintf(buf, 4, "%d\n", st->config->acc_fsr); } static ssize_t inv_gyro_acc_fsr_store(struct device *dev, @@ -198,7 +213,10 @@ static IIO_DEVICE_ATTR( static ssize_t inv_gyro_acc_lpf_show(struct device *dev, struct device_attribute *attr, char *buf) { - return 0; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + return snprintf(buf, 4, "%d\n", st->config->acc_lpf); } static ssize_t inv_gyro_acc_lpf_store(struct device *dev, @@ -224,30 +242,14 @@ static IIO_DEVICE_ATTR( inv_gyro_acc_lpf_store, 0); -/* Attribute of acc_self_test */ -static ssize_t inv_acc_self_test_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return 0; -} - -static ssize_t inv_acc_self_test_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - return 0; -} -static IIO_DEVICE_ATTR( - inv_icm20602_acc_self_test, - 0644, - inv_acc_self_test_show, - inv_acc_self_test_store, - 0); - /* Attribute of user_fps_in_ms */ static ssize_t inv_user_fps_in_ms_show(struct device *dev, struct device_attribute *attr, char *buf) { - return 0; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + return snprintf(buf, 4, "%d\n", st->config->user_fps_in_ms); } static ssize_t inv_user_fps_in_ms_store(struct device *dev, @@ -277,13 +279,27 @@ static IIO_DEVICE_ATTR( static ssize_t inv_sampling_frequency_show(struct device *dev, struct device_attribute *attr, char *buf) { - return 0; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + return snprintf(buf, 4, "%d\n", st->config->gyro_accel_sample_rate); } static ssize_t inv_sampling_frequency_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - return 0; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + int gyro_accel_sample_rate; + + if (kstrtoint(buf, 10, &gyro_accel_sample_rate)) + return -EINVAL; + if (gyro_accel_sample_rate < 10) + return -EINVAL; + + config->gyro_accel_sample_rate = gyro_accel_sample_rate; + return count; } static IIO_DEV_ATTR_SAMP_FREQ( 0644, @@ -293,11 +309,11 @@ static IIO_DEV_ATTR_SAMP_FREQ( static struct attribute *inv_icm20602_attributes[] = { &iio_dev_attr_inv_icm20602_init.dev_attr.attr, - &iio_dev_attr_inv_icm20602_gyro_self_test.dev_attr.attr, &iio_dev_attr_inv_icm20602_gyro_fsr.dev_attr.attr, &iio_dev_attr_inv_icm20602_gyro_lpf.dev_attr.attr, - &iio_dev_attr_inv_icm20602_acc_self_test.dev_attr.attr, + &iio_dev_attr_inv_icm20602_self_test.dev_attr.attr, + &iio_dev_attr_inv_icm20602_acc_fsr.dev_attr.attr, &iio_dev_attr_inv_icm20602_acc_lpf.dev_attr.attr, @@ -363,6 +379,44 @@ static const struct iio_info icm20602_info = { .validate_trigger = inv_icm20602_validate_trigger, }; +static int icm20602_ldo_work(struct inv_icm20602_state *st, bool enable) +{ + int ret = 0; + + if (enable) { + ret = regulator_set_voltage(st->reg_ldo, + ICM20602_LDO_VTG_MIN_UV, ICM20602_LDO_VTG_MAX_UV); + if (ret) + pr_err("Failed to request LDO voltage.\n"); + + ret = regulator_enable(st->reg_ldo); + if (ret) + pr_err("Failed to enable LDO %d\n", ret); + } else { + ret = regulator_disable(st->reg_ldo); + if (ret) + pr_err("Failed to disable LDO %d\n", ret); + regulator_set_load(st->reg_ldo, 0); + } + + return MPU_SUCCESS; +} + +static int icm20602_init_regulators(struct inv_icm20602_state *st) +{ + struct regulator *reg; + + reg = regulator_get(&st->client->dev, "vdd-ldo"); + if (IS_ERR_OR_NULL(reg)) { + pr_err("Unable to get regulator for LDO\n"); + return -MPU_FAIL; + } + + st->reg_ldo = reg; + + return MPU_SUCCESS; +} + static int of_populate_icm20602_dt(struct inv_icm20602_state *st) { int result = MPU_SUCCESS; @@ -450,6 +504,8 @@ static int inv_icm20602_probe(struct i2c_client *client, result); goto out_remove_trigger; } + icm20602_init_regulators(st); + icm20602_ldo_work(st, true); result = inv_icm20602_probe_trigger(indio_dev); if (result) { @@ -471,7 +527,6 @@ static int inv_icm20602_probe(struct i2c_client *client, inv_icm20602_remove_trigger(st); out_unreg_ring: iio_triggered_buffer_cleanup(indio_dev); -out_free: iio_device_free(indio_dev); gpio_free(st->gpio); @@ -494,11 +549,24 @@ static int inv_icm20602_remove(struct i2c_client *client) static int inv_icm20602_suspend(struct device *dev) { + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + icm20602_stop_fifo(st); + icm20602_ldo_work(st, false); return 0; } static int inv_icm20602_resume(struct device *dev) { + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + icm20602_ldo_work(st, true); + icm20602_detect(st); + icm20602_init_device(st); + icm20602_start_fifo(st); + return 0; } diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h index 9ea5ae5ce96c..b369ae4dc0ab 100644 --- a/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h @@ -41,6 +41,9 @@ #define INV20602_SMD_IRQ_TRIGGER 1 #endif +#define ICM20602_LDO_VTG_MIN_UV 3300000 +#define ICM20602_LDO_VTG_MAX_UV 3300000 + #define INV_ICM20602_TIME_STAMP_TOR 5 #define ICM20602_PACKAGE_SIZE 14 @@ -217,6 +220,7 @@ struct inv_icm20602_state { struct struct_icm20602_data *data_push; enum inv_devices chip_type; int gpio; + struct regulator *reg_ldo; DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); }; @@ -281,4 +285,6 @@ int icm20602_detect(struct inv_icm20602_state *st); int icm20602_read_fifo(struct inv_icm20602_state *st, void *buf, const int size); int icm20602_start_fifo(struct inv_icm20602_state *st); +int icm20602_stop_fifo(struct inv_icm20602_state *st); +bool icm20602_self_test(struct inv_icm20602_state *st); #endif diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c index de02656478ff..081bec9a38d3 100644 --- a/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c @@ -67,9 +67,8 @@ static int inv_icm20602_read_data(struct iio_dev *indio_dev) struct icm20602_user_config *config = st->config; int package_count; char *buf = st->buf; - struct struct_icm20602_data *data_push = st->data_push; s64 timestamp; - u8 int_status, int_wm_status; + u8 int_status; u16 fifo_count; int i; @@ -81,6 +80,7 @@ static int inv_icm20602_read_data(struct iio_dev *indio_dev) if (int_status & BIT_FIFO_OFLOW_INT) { icm20602_fifo_count(st, &fifo_count); pr_debug("fifo_count = %d\n", fifo_count); + inv_clear_kfifo(st); icm20602_reset_fifo(st); goto end_session; } @@ -105,14 +105,6 @@ static int inv_icm20602_read_data(struct iio_dev *indio_dev) mutex_unlock(&indio_dev->mlock); iio_trigger_notify_done(indio_dev->trig); return MPU_SUCCESS; - -flush_fifo: - /* Flush HW and SW FIFOs. */ - inv_clear_kfifo(st); - icm20602_reset_fifo(st); - mutex_unlock(&indio_dev->mlock); - iio_trigger_notify_done(indio_dev->trig); - return MPU_SUCCESS; } /* -- GitLab From 8567156af41daa031243cdf0ab061346deed024c Mon Sep 17 00:00:00 2001 From: zhaochen Date: Wed, 13 Jun 2018 17:48:56 +0800 Subject: [PATCH 814/855] =?UTF-8?q?vl53l0x=EF=BC=9Afix=20some=20variable?= =?UTF-8?q?=20in=20sysfs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In vl53l0x driver some attributes need to delete some variable. Change-Id: Idcf96ca6d7fe412fccc03f666876b3023659395c Signed-off-by: zhaochen --- .../vl53l0x/src/vl53l0x_api_calibration.c | 2 +- .../input/misc/vl53l0x/src/vl53l0x_api_core.c | 2 +- .../input/misc/vl53l0x/stmvl53l0x_module.c | 58 ++++++++++--------- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c index 08b5ce23fe79..3905bd25bfd2 100644 --- a/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c @@ -506,7 +506,7 @@ int8_t count_enabled_spads(uint8_t spadArray[], *pIsAperture = 1; if ((byteIndex < 2) && (bitIndex < 4)) *pIsAperture = 0; - spadTypeIdentified = 1; + spadTypeIdentified = 1; } } tempByte >>= 1; diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c index ceb3585b20e7..6824c02c5262 100644 --- a/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c @@ -182,7 +182,7 @@ int8_t VL_device_read_strobe(struct vl_data *Dev) Status = VL_RdByte(Dev, 0x83, &strobe); if ((strobe != 0x00) || Status != VL_ERROR_NONE) break; - LoopNb = LoopNb + 1; + LoopNb = LoopNb + 1; } while (LoopNb < VL_DEFAULT_MAX_LOOP); if (LoopNb >= VL_DEFAULT_MAX_LOOP) diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c index 78ca6373554a..99cbc11db4e5 100644 --- a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c +++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c @@ -777,18 +777,18 @@ static ssize_t stmvl53l0x_store_enable_ps_sensor(struct device *dev, size_t count) { struct vl_data *data = dev_get_drvdata(dev); - + int ret; unsigned int val; - kstrtoint(buf, 10, &val); + ret = kstrtoint(buf, 10, &val); if ((val != 0) && (val != 1)) { - err("store unvalid value=%ld\n", val); + err("store unvalid value=%d\n", val); return count; } mutex_lock(&data->work_mutex); dbg("Enter, enable_ps_sensor flag:%d\n", data->enable_ps_sensor); - dbg("enable ps senosr ( %ld)\n", val); + dbg("enable ps senosr ( %d)\n", val); if (val == 1) { /* turn on tof sensor */ @@ -831,10 +831,11 @@ static ssize_t stmvl53l0x_store_enable_debug(struct device *dev, { struct vl_data *data = dev_get_drvdata(dev); int on; + int ret; - kstrtoint(buf, 10, &on); + ret = kstrtoint(buf, 10, &on); if ((on != 0) && (on != 1)) { - err("set debug=%ld\n", on); + err("set debug=%d\n", on); return count; } data->enableDebug = on; @@ -862,10 +863,11 @@ static ssize_t stmvl53l0x_store_set_delay_ms(struct device *dev, { struct vl_data *data = dev_get_drvdata(dev); int delay_ms; + int ret; - kstrtoint(buf, 10, &delay_ms); + ret = kstrtoint(buf, 10, &delay_ms); if (delay_ms == 0) { - err("set delay_ms=%ld\n", delay_ms); + err("set delay_ms=%d\n", delay_ms); return count; } mutex_lock(&data->work_mutex); @@ -895,10 +897,11 @@ static ssize_t stmvl53l0x_store_set_timing_budget(struct device *dev, { struct vl_data *data = dev_get_drvdata(dev); int timingBudget; + int ret; - kstrtoint(buf, 10, &timingBudget); + ret = kstrtoint(buf, 10, &timingBudget); if (timingBudget == 0) { - err("set timingBudget=%ld\n", timingBudget); + err("set timingBudget=%d\n", timingBudget); return count; } mutex_lock(&data->work_mutex); @@ -929,10 +932,11 @@ static ssize_t stmvl53l0x_store_set_long_range(struct device *dev, { struct vl_data *data = dev_get_drvdata(dev); int useLongRange; + int ret; - kstrtoint(buf, 10, &useLongRange); + ret = kstrtoint(buf, 10, &useLongRange); if ((useLongRange != 0) && (useLongRange != 1)) { - err("set useLongRange=%ld\n", useLongRange); + err("set useLongRange=%d\n", useLongRange); return count; } @@ -960,7 +964,6 @@ static ssize_t stmvl53l0x_show_meter(struct device *dev, struct VL_RangingMeasurementData_t Measure; papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure); - dbg("Measure = %d\n", Measure.RangeMilliMeter); return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter); } @@ -972,11 +975,7 @@ static DEVICE_ATTR(show_meter, 0660/*S_IWUGO | S_IRUGO*/, static ssize_t stmvl53l0x_show_xtalk(struct device *dev, struct device_attribute *attr, char *buf) { - struct vl_data *data = dev_get_drvdata(dev); - struct VL_RangingMeasurementData_t Measure; - - dbg("Measure = %d\n", Measure.RangeMilliMeter); - return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter); + return 0; } static ssize_t stmvl53l0x_set_xtalk(struct device *dev, @@ -985,8 +984,9 @@ static ssize_t stmvl53l0x_set_xtalk(struct device *dev, { struct vl_data *data = dev_get_drvdata(dev); unsigned int targetDistance; + int ret; - kstrtoint(buf, 10, &targetDistance); + ret = kstrtoint(buf, 10, &targetDistance); data->xtalkCalDistance = targetDistance; stmvl53l0x_start(data, 3, XTALKCALIB_MODE); return count; @@ -1004,7 +1004,6 @@ static ssize_t stmvl53l0x_show_offset(struct device *dev, struct VL_RangingMeasurementData_t Measure; papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure); - dbg("Measure = %d\n", Measure.RangeMilliMeter); return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter); } @@ -1014,8 +1013,9 @@ static ssize_t stmvl53l0x_set_offset(struct device *dev, { struct vl_data *data = dev_get_drvdata(dev); unsigned int targetDistance; + int ret; - kstrtoint(buf, 10, &targetDistance); + ret = kstrtoint(buf, 10, &targetDistance); data->offsetCalDistance = targetDistance; stmvl53l0x_start(data, 3, OFFSETCALIB_MODE); return count; @@ -1067,9 +1067,9 @@ static ssize_t stmvl53l0x_show_OffsetCalibrationData(struct device *dev, papi_func_tbl->GetOffsetCalibrationDataMicroMeter(data, &offset_calibration_data); - dbg("GetOffsetCalibrationDataMicroMeter = %ld\n", + dbg("GetOffsetCalibrationDataMicroMeter = %d\n", offset_calibration_data); - return snprintf(buf, 2, "%ld\n", + return snprintf(buf, 2, "%d\n", offset_calibration_data); } @@ -1079,8 +1079,9 @@ static ssize_t stmvl53l0x_set_OffsetCalibrationData(struct device *dev, { struct vl_data *data = dev_get_drvdata(dev); int32_t offset_calibration_data; + int ret; - kstrtoint(buf, 10, &offset_calibration_data); + ret = kstrtoint(buf, 10, &offset_calibration_data); papi_func_tbl->SetOffsetCalibrationDataMicroMeter(data, offset_calibration_data); return count; @@ -1100,9 +1101,9 @@ static ssize_t stmvl53l0x_show_XTalkCompensationRateMegaCps(struct device *dev, papi_func_tbl->GetXTalkCompensationRateMegaCps(data, &xtalk_compensation_rate); - dbg("xtalk_compensation_rate = %ld\n", + dbg("xtalk_compensation_rate = %d\n", xtalk_compensation_rate); - return snprintf(buf, 2, "%ld\n", xtalk_compensation_rate); + return snprintf(buf, 2, "%d\n", xtalk_compensation_rate); } @@ -1112,8 +1113,9 @@ static ssize_t stmvl53l0x_set_XTalkCompensationRateMegaCps(struct device *dev, { struct vl_data *data = dev_get_drvdata(dev); unsigned int xtalk_compensation_rate; + int ret; - kstrtoint(buf, 10, &xtalk_compensation_rate); + ret = kstrtoint(buf, 10, &xtalk_compensation_rate); papi_func_tbl->SetXTalkCompensationRateMegaCps(data, xtalk_compensation_rate); return count; @@ -1689,7 +1691,7 @@ static int stmvl53l0x_start(struct vl_data *data, uint8_t scaling, vl53l0x_dev, &ref_spad_count, &is_aperture_spads); - dbg("SPAD calibration:%lu,%u\n", ref_spad_count, + dbg("SPAD calibration:%d,%d\n", ref_spad_count, (unsigned int)is_aperture_spads); return rc; } else if (mode == REFCALIB_MODE) { -- GitLab From fcd0515db2256b808125b62f6a5b51a1749b6ff8 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Tue, 12 Jun 2018 15:03:56 +0530 Subject: [PATCH 815/855] usb: gadget: u_ether: Check tx_reqs before allocating new SKB Commit fdafb970a9fc ("usb: gadget: u_ether: reorganize code for better readability") refactored the eth_start_xmit function to free old skb first, add RNDIS header to new SKB and then check if disconnect interrupt has freed up the tx_reqs. If this happens, then on next eth_start_xmit we will end up using the previous skb which leads to page fault. Fix this by first checking tx_reqs availability and then adding RNDIS header. Change-Id: I0bf59361c71c989a436685917301cabd62b91e95 Signed-off-by: Ajay Agarwal --- drivers/usb/gadget/function/u_ether.c | 48 +++++++++++++-------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index fbf90c42c40f..c75e790d289a 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -818,29 +818,6 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, } dev->tx_pkts_rcvd++; - /* - * no buffer copies needed, unless the network stack did it - * or the hardware can't use skb buffers. - * or there's not enough space for extra headers we need - */ - spin_lock_irqsave(&dev->lock, flags); - if (dev->wrap && dev->port_usb) - skb = dev->wrap(dev->port_usb, skb); - spin_unlock_irqrestore(&dev->lock, flags); - - if (!skb) { - if (dev->port_usb && dev->port_usb->supports_multi_frame) { - /* - * Multi frame CDC protocols may store the frame for - * later which is not a dropped frame. - */ - } else { - dev->net->stats.tx_dropped++; - } - - /* no error code for dropped packets */ - return NETDEV_TX_OK; - } /* Allocate memory for tx_reqs to support multi packet transfer */ spin_lock_irqsave(&dev->req_lock, flags); @@ -875,9 +852,30 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, dev->tx_throttle++; netif_stop_queue(net); } + spin_unlock_irqrestore(&dev->req_lock, flags); + + /* no buffer copies needed, unless the network stack did it + * or the hardware can't use skb buffers. + * or there's not enough space for extra headers we need + */ + spin_lock_irqsave(&dev->lock, flags); + if (dev->wrap) { + if (dev->port_usb) + skb = dev->wrap(dev->port_usb, skb); + if (!skb) { + spin_unlock_irqrestore(&dev->lock, flags); + /* Multi frame CDC protocols may store the frame for + * later which is not a dropped frame. + */ + if (dev->port_usb && + dev->port_usb->supports_multi_frame) + goto multiframe; + goto drop; + } + } dev->tx_skb_hold_count++; - spin_unlock_irqrestore(&dev->req_lock, flags); + spin_unlock_irqrestore(&dev->lock, flags); if (multi_pkt_xfer) { pr_debug("req->length:%d header_len:%u\n" @@ -1000,7 +998,9 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, dev_kfree_skb_any(skb); else req->length = 0; +drop: dev->net->stats.tx_dropped++; +multiframe: spin_lock_irqsave(&dev->req_lock, flags); if (list_empty(&dev->tx_reqs)) netif_start_queue(net); -- GitLab From 5301ccc02de04115b09219243aab02b9423faa05 Mon Sep 17 00:00:00 2001 From: Raja Mallik Date: Thu, 24 May 2018 11:26:50 +0530 Subject: [PATCH 816/855] ARM: dts: msm: Add device tree support for apq8009 IoT refboard Enable audio support For apq8009 IoT refboard with external codec WCD9326. Change-Id: I849b0d7341b23de8357f2745d3ac4cc017f6c4de Signed-off-by: Raja Mallik --- .../qcom/apq8009-audio-external_codec.dtsi | 36 ++++++++--- .../dts/qcom/apq8009-mtp-wcd9326-refboard.dts | 64 +++++++++++++++++-- arch/arm64/boot/dts/qcom/msm8909-pinctrl.dtsi | 28 ++++++++ 3 files changed, 112 insertions(+), 16 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/apq8009-audio-external_codec.dtsi b/arch/arm64/boot/dts/qcom/apq8009-audio-external_codec.dtsi index d28e13937bff..9261dfe378c2 100644 --- a/arch/arm64/boot/dts/qcom/apq8009-audio-external_codec.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8009-audio-external_codec.dtsi @@ -19,6 +19,12 @@ }; &soc { + qcom,msm-audio-apr { + compatible = "qcom,msm-audio-apr"; + msm_audio_apr_dummy { + compatible = "qcom,msm-audio-apr-dummy"; + }; + }; sound-9335 { compatible = "qcom,apq8009-audio-i2s-codec"; qcom,model = "apq8009-tashalite-snd-card"; @@ -234,16 +240,17 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36864>; qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-sec-port-enable; qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36864>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -254,17 +261,26 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36865>; qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-sec-port-enable; qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36865>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; }; + +&wcd9xxx_intc { + status = "okay"; +}; + +&clock_audio { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts b/arch/arm64/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts index 1866e2f4537a..2afd5acb3223 100644 --- a/arch/arm64/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts +++ b/arch/arm64/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts @@ -95,7 +95,7 @@ }; &soc { - sound-9335 { + ext_codec: sound-9335 { qcom,audio-routing = "AIF4 VI", "MCLK", "RX_BIAS", "MCLK", @@ -112,12 +112,22 @@ "MIC BIAS3", "Digital Mic3", "SpkrLeft IN", "SPK1 OUT", "SpkrRight IN", "SPK2 OUT"; - }; - i2c@78b8000 { - wcd9xxx_codec@d { - qcom,cdc-reset-gpio = <&msm_gpio 27 0>; - }; + qcom,msm-gpios = + "us_eu_gpio"; + qcom,pinctrl-names = + "all_off", + "us_eu_gpio_act"; + pinctrl-names = + "all_off", + "us_eu_gpio_act"; + pinctrl-0 = <&cross_conn_det_sus>; + pinctrl-1 = <&cross_conn_det_act>; + qcom,pri-mi2s-gpios = <&cdc_pri_mi2s_gpios>; + qcom,quat-mi2s-gpios = <&cdc_quat_mi2s_gpios>; + + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; }; i2c@78b9000 { @@ -205,6 +215,36 @@ qcom,id-det-gpio = <&msm_gpio 110 0>; qcom,dpdm_switch_gpio = <&pm8916_gpios 3 0>; }; + + i2c@78b8000 { + wcd9xxx_codec@d { + status = "okay"; + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + }; + }; + + cdc_pri_mi2s_gpios: msm_cdc_pinctrl_pri { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_mi2s_active &pri_mi2s_ws_active + &pri_mi2s_dout_active &pri_mi2s_din_active>; + pinctrl-1 = <&pri_mi2s_sleep &pri_mi2s_ws_sleep + &pri_mi2s_dout_sleep &pri_mi2s_din_sleep>; + }; + + cdc_quat_mi2s_gpios: msm_cdc_pinctrl_quat { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>; + pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>; + }; + + wcd_rst_gpio: wcd_gpio_ctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + }; }; &wcnss { @@ -327,4 +367,16 @@ status = "disabled"; }; +&wcd_rst_gpio { + status = "okay"; +}; + +&ext_codec { + status = "okay"; +}; + +&blsp1_uart2_hs { + status = "disabled"; +}; + /delete-node/ &cont_splash_mem; diff --git a/arch/arm64/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8909-pinctrl.dtsi index c86da64cfe2e..eda92c5ef0c2 100644 --- a/arch/arm64/boot/dts/qcom/msm8909-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909-pinctrl.dtsi @@ -1890,6 +1890,34 @@ }; }; + cdc_reset_ctrl { + cdc_reset_sleep: cdc_reset_sleep { + mux { + pins = "gpio27"; + function = "gpio"; + }; + config { + pins = "gpio27"; + drive-strength = <16>; + bias-disable; + output-low; + }; + }; + cdc_reset_active:cdc_reset_active { + mux { + pins = "gpio27"; + function = "gpio"; + }; + config { + pins = "gpio27"; /* gpio67 old */ + drive-strength = <16>; + bias-pull-down; + output-high; + }; + }; + }; + + cdc-dmic-lines { cdc_dmic0_clk_act: dmic0_clk_on { mux { -- GitLab From 4279b564429b97e2f04d1423ac3c315bfc02c662 Mon Sep 17 00:00:00 2001 From: Vamshi Krishna B V Date: Wed, 13 Jun 2018 16:17:56 +0530 Subject: [PATCH 817/855] ARM: dts: msm: Add Vendor node for supporting PMI8950 FG Add Vendor node for supporting PMI8950 FG and move the battery_data under Vendor node for MSM8953 MTP. CRs-Fixed: 2246295 Change-Id: I7d95be138d4d9c4bd4e6c85cd45d2cc09765ade7 Signed-off-by: Vamshi Krishna B V --- .../dts/qcom/msm8953-ext-codec-mtp-overlay.dts | 18 ++++++++++++++++++ .../boot/dts/qcom/msm8953-mtp-overlay.dts | 2 +- arch/arm64/boot/dts/qcom/msm8953.dtsi | 7 +++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp-overlay.dts index b182a25698d3..67ed1974e1d9 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp-overlay.dts @@ -23,6 +23,24 @@ qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; }; +&vendor { + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "batterydata-itech-3000mah.dtsi" + #include "batterydata-ascent-3450mAh.dtsi" + }; +}; + +&qpnp_fg { + qcom,battery-data = <&mtp_batterydata>; +}; + +&qpnp_smbcharger { + qcom,battery-data = <&mtp_batterydata>; + qcom,chg-led-sw-controls; + qcom,chg-led-support; +}; + &int_codec { status = "disabled"; }; diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts index c6ae512fa41c..e4897bc1cd7b 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts @@ -21,7 +21,7 @@ qcom,board-id = <8 0>; }; -/{ +&vendor { mtp_batterydata: qcom,battery-data { qcom,batt-id-range-pct = <15>; #include "batterydata-itech-3000mah.dtsi" diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index 0c1bbc2afd32..684a44247035 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -30,6 +30,13 @@ bootargs = "core_ctl_disable_cpumask=0-7 kpti=0"; }; + vendor: vendor { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + }; + firmware: firmware { android { compatible = "android,firmware"; -- GitLab From 4c47ad5f6ed71d3e0c42b9de7b407cdb56ca3364 Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Fri, 8 Jun 2018 15:30:24 +0530 Subject: [PATCH 818/855] usb: gsi: Allow suspend upon previous suspend failure in gsi_suspend Driver marks func_is_suspended flag to true and queue suspend work in gsi_suspend. suspend_work may fail the suspend if the LINK is not in U3. During host hibernation testing gsi_suspend failing as LINK is not in U3 and next time when bus suspend initiated driver checking for func_is_suspended flag and bailout the suspend with out queuing suspend work. This causes a mismatch of usage count and usb not entering to low power mode. To fix this issue, Check for the state in gsi_suspend. If the state is != suspended or != suspend_in_progress then don't bail out the suspend. Change-Id: Iade9ba330b232261e205cd821ef42053297befbb Signed-off-by: Chandana Kishori Chiluveru --- drivers/usb/gadget/function/f_gsi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index f3ad6699d8a7..89f1ba296eb5 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -2480,8 +2480,12 @@ static void gsi_suspend(struct usb_function *f) bool block_db; struct f_gsi *gsi = func_to_gsi(f); - /* Check if function is already suspended in gsi_func_suspend() */ - if (f->func_is_suspended) { + /* Check if function is already suspended in gsi_func_suspend() + * Or func_suspend would have bailed out earlier if func_remote_wakeup + * wasn't enabled. + */ + if (f->func_is_suspended && (gsi->d_port.sm_state == STATE_SUSPENDED || + gsi->d_port.sm_state == STATE_SUSPEND_IN_PROGRESS)) { log_event_dbg("%s: func already suspended, return\n", __func__); return; } -- GitLab From adb8ebf66b3a8c204ace279480e8588e7666dccc Mon Sep 17 00:00:00 2001 From: Can Guo Date: Tue, 22 May 2018 00:57:05 -0700 Subject: [PATCH 819/855] ARM: dts: msm: Add UFS support for sdm670 HDK platform This change enables ufs support on sdm670 HDK platform. Change-Id: Ie5727340d6553aa6e453cfbab80226bca84ff1d3 Signed-off-by: Can Guo Signed-off-by: Ziqi Chen --- arch/arm64/boot/dts/qcom/sda670-hdk.dtsi | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi b/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi index 8471d11ffca9..5b1ed9c11763 100644 --- a/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi +++ b/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi @@ -31,3 +31,29 @@ &dsi_hx8399_truly_cmd_display { qcom,dsi-display-active; }; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v3"; + + vdda-phy-supply = <&pm660l_l1>; /* 0.88v */ + vdda-pll-supply = <&pm660_l1>; /* 1.2v */ + vdda-phy-max-microamp = <62900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm660l_l4>; + vcc-voltage-level = <2960000 2960000>; + vccq2-supply = <&pm660_l8>; + vcc-max-microamp = <600000>; + vccq2-max-microamp = <600000>; + + qcom,vddp-ref-clk-supply = <&pm660_l1>; + qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; +}; -- GitLab From 638d5f047861222cfcaae63d433f9763e725739a Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Tue, 12 Jun 2018 09:11:27 +0530 Subject: [PATCH 820/855] leds: vibrator-ldo: Disable LDO if VREG_READY is not set If the LDO does not settle within the expected time, disable it. CRs-Fixed: 2257990 Change-Id: Ic8d5777fa356d166a722d3961a5a31cf06942e30 Signed-off-by: Tirupathi Reddy --- drivers/leds/leds-qpnp-vibrator-ldo.c | 39 +++++++++++++++++---------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/leds/leds-qpnp-vibrator-ldo.c b/drivers/leds/leds-qpnp-vibrator-ldo.c index 6a143247cd9b..488bb9979d86 100644 --- a/drivers/leds/leds-qpnp-vibrator-ldo.c +++ b/drivers/leds/leds-qpnp-vibrator-ldo.c @@ -65,9 +65,29 @@ struct vib_ldo_chip { bool disable_overdrive; }; -static int qpnp_vib_ldo_set_voltage(struct vib_ldo_chip *chip, int new_uV) +static inline int qpnp_vib_ldo_poll_status(struct vib_ldo_chip *chip) { unsigned int val; + int ret; + + ret = regmap_read_poll_timeout(chip->regmap, + chip->base + QPNP_VIB_LDO_REG_STATUS1, val, + val & QPNP_VIB_LDO_VREG_READY, 100, 1000); + if (ret < 0) { + pr_err("Vibrator LDO vreg_ready timeout, status=0x%02x, ret=%d\n", + val, ret); + + /* Keep VIB_LDO disabled */ + regmap_update_bits(chip->regmap, + chip->base + QPNP_VIB_LDO_REG_EN_CTL, + QPNP_VIB_LDO_EN, 0); + } + + return ret; +} + +static int qpnp_vib_ldo_set_voltage(struct vib_ldo_chip *chip, int new_uV) +{ u32 vlevel; u8 reg[2]; int ret; @@ -86,13 +106,9 @@ static int qpnp_vib_ldo_set_voltage(struct vib_ldo_chip *chip, int new_uV) } if (chip->vib_enabled) { - ret = regmap_read_poll_timeout(chip->regmap, - chip->base + QPNP_VIB_LDO_REG_STATUS1, - val, val & QPNP_VIB_LDO_VREG_READY, - 100, 1000); + ret = qpnp_vib_ldo_poll_status(chip); if (ret < 0) { - pr_err("Vibrator LDO vreg_ready timeout, status=0x%02x, ret=%d\n", - val, ret); + pr_err("Vibrator LDO status polling timedout\n"); return ret; } } @@ -103,7 +119,6 @@ static int qpnp_vib_ldo_set_voltage(struct vib_ldo_chip *chip, int new_uV) static inline int qpnp_vib_ldo_enable(struct vib_ldo_chip *chip, bool enable) { - unsigned int val; int ret; if (chip->vib_enabled == enable) @@ -120,13 +135,9 @@ static inline int qpnp_vib_ldo_enable(struct vib_ldo_chip *chip, bool enable) } if (enable) { - ret = regmap_read_poll_timeout(chip->regmap, - chip->base + QPNP_VIB_LDO_REG_STATUS1, - val, val & QPNP_VIB_LDO_VREG_READY, - 100, 1000); + ret = qpnp_vib_ldo_poll_status(chip); if (ret < 0) { - pr_err("Vibrator LDO vreg_ready timeout, status=0x%02x, ret=%d\n", - val, ret); + pr_err("Vibrator LDO status polling timedout\n"); return ret; } } -- GitLab From 1a3b2748b0e7a22ae9d46bb38ba4c30f7542877f Mon Sep 17 00:00:00 2001 From: Jingbiao Lu Date: Wed, 13 Jun 2018 16:19:31 +0800 Subject: [PATCH 821/855] ARM: dts: msm: correct clock header file and move to right place Correct clock header file from msm-clocks-8953.h to msm-clocks-8952.h for msm8937, move it to right place. And delete unnecessary header files. Change-Id: I6fe2b3bd87e0911695f6391796320f4b0b96d40a Signed-off-by: Jingbiao Lu --- arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts | 3 --- arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts | 3 --- arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts | 3 --- arch/arm64/boot/dts/qcom/sdm439-camera-sensor-cdp.dtsi | 2 ++ arch/arm64/boot/dts/qcom/sdm439-camera-sensor-mtp.dtsi | 2 ++ arch/arm64/boot/dts/qcom/sdm439-camera-sensor-qrd.dtsi | 2 ++ arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts | 3 --- .../arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts | 4 ---- arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts | 3 --- arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts | 3 --- 10 files changed, 6 insertions(+), 22 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts index c55c2a508bae..5f0db81c5351 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts @@ -14,9 +14,6 @@ /dts-v1/; /plugin/; -#include -#include -#include #include "sdm429-cdp.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts index 7735b35ced88..571f0fcc976c 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts @@ -14,9 +14,6 @@ /dts-v1/; /plugin/; -#include -#include -#include #include "sdm429-mtp.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts index fae68c994356..8e12295f3493 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts @@ -14,9 +14,6 @@ /dts-v1/; /plugin/; -#include -#include -#include #include "sdm429-qrd.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-cdp.dtsi index 5e2c7406ff0d..eae8c56f3bd2 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-cdp.dtsi @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#include + &cci { actuator0: qcom,actuator@0 { cell-index = <0>; diff --git a/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-mtp.dtsi index 5e2c7406ff0d..eae8c56f3bd2 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-mtp.dtsi @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#include + &cci { actuator0: qcom,actuator@0 { cell-index = <0>; diff --git a/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-qrd.dtsi index c2c9c79fd5a6..ef0e9779877b 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-qrd.dtsi @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#include + &cci { actuator0: qcom,actuator@0 { cell-index = <0>; diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts index 5e866721dffd..87239b93d28c 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts @@ -14,9 +14,6 @@ /dts-v1/; /plugin/; -#include -#include -#include #include "sdm439-cdp.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts index 468f514f6cfb..37741b2f78a3 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts @@ -14,10 +14,6 @@ /dts-v1/; /plugin/; -#include -#include -#include - #include "sdm439-mtp.dtsi" #include "sdm439-external-codec.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts index 8b6c6fb7f152..a7c5f4e53bbc 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts @@ -14,9 +14,6 @@ /dts-v1/; /plugin/; -#include -#include -#include #include "sdm439-mtp.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts index ed6b2ade25ea..46a7856f804a 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts @@ -14,9 +14,6 @@ /dts-v1/; /plugin/; - #include - #include - #include #include "sdm439-qrd.dtsi" / { -- GitLab From 8386daaf8e5b9544fde1cdd2440fc2b480fbe5c9 Mon Sep 17 00:00:00 2001 From: Jingbiao Lu Date: Wed, 13 Jun 2018 16:31:01 +0800 Subject: [PATCH 822/855] ARM: dts: msm: add device tree support for sdm439 rcm Add device tree support for sdm439 rcm. Also add device tree overlay support. Change-Id: Ie3435cfd341ab2d1d6177964fd0731ca0612a765 Signed-off-by: Jingbiao Lu --- arch/arm64/boot/dts/qcom/Makefile | 7 ++++-- .../boot/dts/qcom/sdm439-rcm-overlay.dts | 22 +++++++++++++++++ arch/arm64/boot/dts/qcom/sdm439-rcm.dts | 24 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm439-rcm.dtsi | 14 +++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/sdm439-rcm-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm439-rcm.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm439-rcm.dtsi diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 1d845e862787..f7ac61624dea 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -312,7 +312,8 @@ dtbo-$(CONFIG_ARCH_SDM632) += sdm632-rumi-overlay.dtbo \ dtbo-$(CONFIG_ARCH_SDM439) += sdm439-mtp-overlay.dtbo \ sdm439-cdp-overlay.dtbo \ sdm439-qrd-overlay.dtbo \ - sdm439-external-codec-mtp-overlay.dtbo + sdm439-external-codec-mtp-overlay.dtbo \ + sdm439-rcm-overlay.dtbo dtbo-$(CONFIG_ARCH_SDM429) += sdm429-mtp-overlay.dtbo \ sdm429-cdp-overlay.dtbo \ @@ -380,6 +381,7 @@ sdm439-cdp-overlay.dtbo-base := sdm439.dtb \ sdm439-qrd-overlay.dtbo-base := sdm439.dtb \ msm8937-interposer-sdm439.dtb sdm439-external-codec-mtp-overlay.dtbo-base := sdm439.dtb +sdm439-rcm-overlay.dtbo-base := sdm439.dtb sdm429-mtp-overlay.dtbo-base := sdm429.dtb \ sda429.dtb \ msm8937-interposer-sdm429.dtb @@ -489,7 +491,8 @@ dtb-$(CONFIG_ARCH_SDM439) += sdm439-mtp.dtb \ sdm439-qrd.dtb \ sda439-mtp.dtb \ sda439-cdp.dtb \ - sdm439-external-codec-mtp.dtb + sdm439-external-codec-mtp.dtb \ + sdm439-rcm.dtb dtb-$(CONFIG_ARCH_SDM429) += sdm429-mtp.dtb \ sdm429-cdp.dtb \ diff --git a/arch/arm64/boot/dts/qcom/sdm439-rcm-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-rcm-overlay.dts new file mode 100644 index 000000000000..be0de060bcfb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm439-rcm-overlay.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include "sdm439-rcm.dtsi" + +/ { + model = "RCM"; + qcom,board-id = <21 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm439-rcm.dts b/arch/arm64/boot/dts/qcom/sdm439-rcm.dts new file mode 100644 index 000000000000..71d02a0726a0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm439-rcm.dts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sdm439.dtsi" +#include "sdm439-rcm.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM439 RCM"; + compatible = "qcom,sdm439-cdp", "qcom,sdm439", "qcom,cdp"; + qcom,board-id = <21 1>; + qcom,pmic-id = <0x010016 0x25 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm439-rcm.dtsi b/arch/arm64/boot/dts/qcom/sdm439-rcm.dtsi new file mode 100644 index 000000000000..4ba4c00e1a2f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm439-rcm.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sdm439-cdp.dtsi" -- GitLab From 3e408fe3e33606d212398471c22cafd2f8b97f3e Mon Sep 17 00:00:00 2001 From: Bryan Huntsman Date: Mon, 4 Jun 2018 15:11:10 -0700 Subject: [PATCH 823/855] scripts/build-all: relax check_kernel() Enforce just that PWD is the top working directory by dropping the hard-coded defconfig lookup. Change-Id: I14404de5e28605c14329768747bb18a49487694f Signed-off-by: Bryan Huntsman --- scripts/build-all.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/build-all.py b/scripts/build-all.py index bd468cd4bb4e..4a60ebc71d09 100755 --- a/scripts/build-all.py +++ b/scripts/build-all.py @@ -59,12 +59,8 @@ if not os.environ.get('CROSS_COMPILE'): def check_kernel(): """Ensure that PWD is a kernel directory""" - have_defconfig = any([ - os.path.isfile('arch/arm64/configs/msm_defconfig'), - os.path.isfile('arch/arm64/configs/sdm845_defconfig')]) - - if not all([os.path.isfile('MAINTAINERS'), have_defconfig]): - fail("This doesn't seem to be an MSM kernel dir") + if not os.path.isfile('MAINTAINERS'): + fail("This doesn't seem to be a kernel dir") def check_build(): """Ensure that the build directory is present.""" -- GitLab From e7b5d9c3597c561268662f1ba083b489c1ad3b7f Mon Sep 17 00:00:00 2001 From: Vijay kumar Tumati Date: Thu, 14 Jun 2018 12:25:28 +0530 Subject: [PATCH 824/855] msm: camera: Disable camera csiphy IRQs during stream-on csiphy IRQs if left enabled after stream-on, causes a storm. Change-Id: I295070040aa84a80ca34580b6dd38797a013496d Signed-off-by: Vijay kumar Tumati --- .../media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c index 58a43904006e..a0411b0f68aa 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c @@ -2057,7 +2057,10 @@ static int32_t msm_csiphy_cmd(struct csiphy_device *csiphy_dev, void *arg) rc = -EFAULT; break; } - csiphy_dev->csiphy_sof_debug = SOF_DEBUG_DISABLE; + if (csiphy_dev->csiphy_sof_debug == SOF_DEBUG_ENABLE) { + csiphy_dev->csiphy_sof_debug = SOF_DEBUG_DISABLE; + rc = msm_camera_enable_irq(csiphy_dev->irq, false); + } rc = msm_csiphy_lane_config(csiphy_dev, &csiphy_params); break; case CSIPHY_RELEASE: -- GitLab From 99f5f42c4d6eaff4d9c56db8143804e1c4e2fc7f Mon Sep 17 00:00:00 2001 From: Srinivasarao P Date: Tue, 8 May 2018 17:45:02 +0530 Subject: [PATCH 825/855] arm: Kconfig: enable CONFIG_ARM_MODULE_PLTS Module loading is failing since kernel jumps/calls are out of range. Use PLTs to jump to far away addresses. Change-Id: I4cda60dc12cec1f281574a4e30585fb96b0d57e8 Signed-off-by: Srinivasarao P --- arch/arm/configs/msm8937-perf_defconfig | 1 + arch/arm/configs/msm8937_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index dae45e115206..ced854d108db 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -67,6 +67,7 @@ CONFIG_ARM_PSCI=y CONFIG_PREEMPT=y CONFIG_AEABI=y CONFIG_HIGHMEM=y +CONFIG_ARM_MODULE_PLTS=y CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 3c43fa39a474..40d5cb156e26 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -70,6 +70,7 @@ CONFIG_ARM_PSCI=y CONFIG_PREEMPT=y CONFIG_AEABI=y CONFIG_HIGHMEM=y +CONFIG_ARM_MODULE_PLTS=y CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y -- GitLab From c8b897bef2764d97eba688c9d6bd4143fba0f292 Mon Sep 17 00:00:00 2001 From: Mulu He Date: Fri, 8 Jun 2018 11:21:10 +0800 Subject: [PATCH 826/855] coresight: stm: Out of bound access from STM The memory size allocated for stm_master is less than it's defined. Change-Id: Ia913ac899c069383cff498b03815d985dacacdf4 Signed-off-by: Mulu He --- drivers/hwtracing/stm/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index 2dd60ee7413e..b8e29925190c 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -174,8 +174,9 @@ static int stp_master_alloc(struct stm_device *stm, unsigned int idx) { struct stp_master *master; size_t size; + unsigned long align = sizeof(unsigned long); - size = ALIGN(stm->data->sw_nchannels, 8) / 8; + size = ALIGN(stm->data->sw_nchannels, align) / align; size += sizeof(struct stp_master); master = kzalloc(size, GFP_ATOMIC); if (!master) -- GitLab From a1e30afa21e2722bc633dbd003177a13a8ff1a9a Mon Sep 17 00:00:00 2001 From: Gan Guo Date: Thu, 17 May 2018 10:59:29 +0800 Subject: [PATCH 827/855] defconfig: msm: Enable FPC driver for SDM439 with fpc1028 SDM439 QRD device use fpc1028 fingerprint sensor so Enable FPR_FPC build option to support it. Change-Id: I346104331be20276509318366fb9d5bb27b60c01 Signed-off-by: Gan Guo --- arch/arm64/configs/msm8937-perf_defconfig | 1 + arch/arm64/configs/msm8937_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index a33d09a2ffa8..4d0cde93294e 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -246,6 +246,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y +CONFIG_FPR_FPC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig index ded6e42f895b..99b4a5a2ef3c 100644 --- a/arch/arm64/configs/msm8937_defconfig +++ b/arch/arm64/configs/msm8937_defconfig @@ -252,6 +252,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y +CONFIG_FPR_FPC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y -- GitLab From db962818be157d7a621265810dd22d4fb1914f53 Mon Sep 17 00:00:00 2001 From: Arun kumar Date: Wed, 30 May 2018 16:31:52 +0530 Subject: [PATCH 828/855] msm: mdss: Add SPI display driver Add Mdp3 and display SPI interface driver to support SPI panel, since limited by SPI rate, the current max fps only reach to 27fps and only support RGB565. Change-Id: Id452b70ed51c1f29aef7b89c1d2f54214c3a7b37 Signed-off-by: Arun kumar --- .../bindings/fb/mdss-spi-client.txt | 27 + .../devicetree/bindings/fb/mdss-spi-panel.txt | 203 ++ drivers/video/fbdev/msm/Kconfig | 10 + drivers/video/fbdev/msm/Makefile | 5 + drivers/video/fbdev/msm/dsi_status_v2.c | 77 + drivers/video/fbdev/msm/mdp3.c | 55 +- drivers/video/fbdev/msm/mdp3.h | 6 + drivers/video/fbdev/msm/mdp3_ctrl.c | 168 +- drivers/video/fbdev/msm/mdp3_ctrl.h | 3 +- drivers/video/fbdev/msm/mdp3_dma.c | 27 +- drivers/video/fbdev/msm/mdp3_dma.h | 1 + drivers/video/fbdev/msm/mdp3_layer.c | 13 +- drivers/video/fbdev/msm/mdp3_ppp.c | 8 +- drivers/video/fbdev/msm/mdp3_ppp_data.c | 4 +- drivers/video/fbdev/msm/mdss_dsi.c | 9 + drivers/video/fbdev/msm/mdss_dsi_status.c | 17 +- drivers/video/fbdev/msm/mdss_fb.c | 20 + drivers/video/fbdev/msm/mdss_panel.h | 17 + drivers/video/fbdev/msm/mdss_spi_client.c | 198 ++ drivers/video/fbdev/msm/mdss_spi_client.h | 20 + drivers/video/fbdev/msm/mdss_spi_panel.c | 1713 +++++++++++++++++ drivers/video/fbdev/msm/mdss_spi_panel.h | 148 ++ 22 files changed, 2688 insertions(+), 61 deletions(-) create mode 100644 Documentation/devicetree/bindings/fb/mdss-spi-client.txt create mode 100644 Documentation/devicetree/bindings/fb/mdss-spi-panel.txt create mode 100644 drivers/video/fbdev/msm/mdss_spi_client.c create mode 100644 drivers/video/fbdev/msm/mdss_spi_client.h create mode 100644 drivers/video/fbdev/msm/mdss_spi_panel.c create mode 100644 drivers/video/fbdev/msm/mdss_spi_panel.h diff --git a/Documentation/devicetree/bindings/fb/mdss-spi-client.txt b/Documentation/devicetree/bindings/fb/mdss-spi-client.txt new file mode 100644 index 000000000000..0d5fde838df7 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-spi-client.txt @@ -0,0 +1,27 @@ +Qualcomm Technologies, Inc. mdss-spi-client + +mdss-spi-client is for SPI display to send the FB data to SPI master. + +Required properties: +- compatible : should be "qcom,mdss-spi-client" +- spi-max-frequency : Maximum SPI clocking speed of device in Hz + +Optional properties: +- label: A string used to describe the controller used. +- spi-cpol : Boolean property indicating device requires inverse + clock polarity (CPOL) mode +- spi-cpha : Empty property indicating device requires shifted + clock phase (CPHA) mode +- spi-cs-high : Empty property indicating device requires + chip select active high + +Example: +spi@78b9000 { /* BLSP1 QUP5 */ + qcom,mdss_spi_client { + reg = <0>; + compatible = "qcom,mdss-spi-client"; + label = "MDSS SPI QUP5 CLIENT"; + spi-max-frequency = <50000000>; + }; +}; + diff --git a/Documentation/devicetree/bindings/fb/mdss-spi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-spi-panel.txt new file mode 100644 index 000000000000..d46068f01695 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-spi-panel.txt @@ -0,0 +1,203 @@ +Qualcomm Technologies, Inc. mdss-spi-panel + +mdss-spi-panel is a SPI panel device which supports panels that +are compatible with display serial interface specification. + +Required properties: +- qcom,mdss-spi-panel-controller: Specifies the phandle for the SPI controller that + this panel will be mapped to. +- qcom,mdss-spi-panel-width: Specifies panel width in pixels. +- qcom,mdss-spi-panel-height: Specifies panel height in pixels. +- qcom,mdss-spi-bpp: Specifies the panel bits per pixels. + 3 = for rgb111 + 8 = for rgb332 + 12 = for rgb444 + 16 = for rgb565 + 18 = for rgb666 + 24 = for rgb888 +- qcom,mdss-spi-panel-destination: A string that specifies the destination display for the panel. + "display_1" = DISPLAY_1 + "display_2" = DISPLAY_2 +- qcom,mdss-spi-on-command: A byte stream formed by multiple packets + byte 0: wait number of specified ms after command + transmitted + byte 1: 8 bits length in network byte order + byte 3 and beyond: number byte of payload +- qcom,mdss-spi-off-command: A byte stream formed by multiple packets + byte 0: wait number of specified ms after command + transmitted + byte 1: 8 bits length in network byte order + byte 3 and beyond: number byte of payload +Optional properties: +- qcom,mdss-spi-panel-name: A string used as a descriptive name of the panel +- qcom,cont-splash-enabled: Boolean used to enable continuous splash mode. + If this property is specified, it is required to + to specify the memory reserved for the splash + screen using the qcom,memblock-reserve binding + for the framebuffer device attached to the panel. +- qcom,mdss-spi-h-back-porch: Horizontal back porch value in pixels. + 6 = default value. +- qcom,mdss-spi-h-front-porch: Horizontal front porch value in pixels. + 6 = default value. +- qcom,mdss-spi-h-pulse-width: Horizontal pulse width. + 2 = default value. +- qcom,mdss-spi-h-sync-skew: Horizontal sync skew value. + 0 = default value. +- qcom,mdss-spi-v-back-porch: Vertical back porch value in pixels. + 6 = default value. +- qcom,mdss-spi-v-front-porch: Vertical front porch value in pixels. + 6 = default value. +- qcom,mdss-spi-v-pulse-width: Vertical pulse width. + 2 = default value. +- qcom,mdss-spi-bl-pmic-control-type: A string that specifies the implementation of backlight + control for this panel. + "bl_ctrl_pwm" = Backlight controlled by PWM gpio. + "bl_ctrl_wled" = Backlight controlled by WLED. + other: Unknown backlight control. (default) +- qcom,mdss-spi-bl-min-level: Specifies the min backlight level supported by the panel. + 0 = default value. +- qcom,mdss-spi-bl-max-level: Specifies the max backlight level supported by the panel. + 255 = default value. +- qcom,mdss-spi-panel-framerate: Specifies the frame rate for the panel. +- qcom,esd-check-enabled: Boolean used to enable ESD recovery feature. +- qcom,mdss-spi-panel-status-check-mode:Specifies the panel status check method for ESD recovery. + "send_init_command" = send init code to recover panel status. + "reg_read" = Read register value to check the panel status. +- qcom,mdss-spi-panel-status-reg:Unsigned 8bits integer value to specifies the value + of panel status register address. +- qcom,mdss-spi-panel-status-read-length:Unsigned 8bits integer value that specifies + the expected read-back length of the panel register. +- qcom,mdss-spi-panel-status-value:An unsigned 8bits integer araray that specifies the + values of the panel status register which is used to + check the panel status. + The size of this array is specified by + qcom,mdss-dsi-panel-status-read-length. + +Example: +&mdss_mdp { + spi_gc9305_qvga_cmd: qcom,mdss_spi_gc9305_qvga_cmd { + qcom,mdss-spi-panel-name = "gc9305 qvga command mode spi panel"; + qcom,mdss-spi-panel-destination = "display_1"; + qcom,mdss-spi-panel-controller = <&mdss_spi>; + qcom,mdss-spi-panel-framerate = <30>; + qcom,mdss-spi-panel-width = <240>; + qcom,mdss-spi-panel-height = <320>; + qcom,mdss-spi-h-front-porch = <79>; + qcom,mdss-spi-h-back-porch = <59>; + qcom,mdss-spi-h-pulse-width = <60>; + qcom,mdss-spi-v-back-porch = <10>; + qcom,mdss-spi-v-front-porch = <7>; + qcom,mdss-spi-v-pulse-width = <2>; + qcom,mdss-spi-h-left-border = <0>; + qcom,mdss-spi-h-right-border = <0>; + qcom,mdss-spi-v-top-border = <0>; + qcom,mdss-spi-v-bottom-border = <0>; + qcom,mdss-spi-bpp = <16>; + qcom,mdss-spi-on-command = [00 01 FE + 00 01 EF + 00 02 36 48 + 00 02 3A 05 + 00 02 35 00 + 00 03 A4 44 44 + 00 03 A5 42 42 + 00 03 AA 88 88 + 00 03 E8 12 40 + 00 03 E3 01 10 + 00 02 FF 61 + 00 02 AC 00 + 00 03 A6 2A 2A + 00 03 A7 2B 2B + 00 03 A8 18 18 + 00 03 A9 2A 2A + 00 02 AD 33 + 00 02 AF 55 + 00 02 AE 2B + 00 05 2A 00 00 00 EF + 00 05 2B 00 00 01 3F + 00 01 2C + 00 07 F0 02 02 00 08 0C 10 + 00 07 F1 01 00 00 14 1D 0E + 00 07 F2 10 09 37 04 04 48 + 00 07 F3 10 0B 3F 05 05 4E + 00 07 F4 0D 19 17 1D 1E 0F + 00 07 F5 06 12 13 1A 1B 0F + 78 01 11 + 00 01 29 + 00 01 2C]; + qcom,mdss-spi-off-command = [20 01 28 + 20 01 10]; + qcom,mdss-spi-bl-min-level = <1>; + qcom,mdss-spi-bl-max-level = <4095>; + qcom,esd-check-enabled; + qcom,mdss-spi-panel-status-check-mode = "reg_read"; + qcom,mdss-spi-panel-status-reg = /bits/ 8 <0x09>; + qcom,mdss-spi-panel-status-read-length = <4>; + qcom,mdss-spi-panel-status-value = /bits/ 8 <0x52 0x29 0x83 0x00>; + }; +}; + +mdss-spi-display is a spi interface display which support send frame +data and command to panel, compatible with SPI interface specification. + +Required properties: +- compatible: This property applies to SPI panels only. + compatible = "qcom,mdss-spi-display". +- vdd-supply: Phandle for vdd regulator device node. +- vddio-supply: Phandle for vdd-io regulator device node. +- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the interface is mapped. +- qcom,mdss-mdp: pHandle that specifies the mdss-mdp device. +- qcom,panel-supply-entries: A node that lists the elements of the supply used to + power the DSI panel. There can be more than one instance + of this binding, in which case the entry would be appended + with the supply entry index. For a detailed description + fields in the supply entry, refer to the qcom,ctrl-supply-entries + binding above. +- qcom,platform-spi-dc-gpio: Pull down this gpio indicate current package is command, + Pull up this gpio indicate current package is parameter or pixels. + +Optional properties: +- label:A string used to describe the controller used. + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off + +Example: + mdss_spi: qcom,mdss_spi { + compatible = "qcom,mdss-spi-display"; + label = "mdss spi panel"; + + qcom,mdss-fb-map = <&mdss_fb0>; + qcom,mdss-mdp = <&mdss_mdp>; + vdd-supply = <&pm8909_l17>; + vddio-supply = <&pm8909_l6>; + qcom,platform-spi-dc-gpio = <&msm_gpio 110 0>; + + qcom,panel-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <2850000>; + qcom,supply-max-voltage = <2850000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; + }; diff --git a/drivers/video/fbdev/msm/Kconfig b/drivers/video/fbdev/msm/Kconfig index e8f902bc0e19..a5e066268fd2 100644 --- a/drivers/video/fbdev/msm/Kconfig +++ b/drivers/video/fbdev/msm/Kconfig @@ -82,6 +82,16 @@ config FB_MSM_MDSS_HDMI_MHL_SII8334 MHL (Mobile High-Definition Link) technology uses USB connector to output HDMI content +config FB_MSM_MDSS_SPI_PANEL + depends on FB_MSM_MDSS + bool "Support SPI panel feature" + default n + ---help--- + The MDSS SPI Panel provides support for transmittimg SPI signals of + MDSS frame buffer data to connected panel. Limited by SPI rate, the + current max fps only reach to 27 fps, and limited by MDP hardware + architecture only supply on MDP3 + config FB_MSM_MDSS_MHL3 depends on FB_MSM_MDSS_HDMI_PANEL bool "MHL3 SII8620 Support" diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile index 81d4953828f0..26a940c4628a 100644 --- a/drivers/video/fbdev/msm/Makefile +++ b/drivers/video/fbdev/msm/Makefile @@ -46,6 +46,11 @@ mdss-dsi-objs += mdss_dsi_clk.o obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o obj-$(CONFIG_FB_MSM_MDSS) += mdss_panel.o +ifeq ($(CONFIG_SPI_QUP), y) +obj-$(CONFIG_FB_MSM_MDSS_SPI_PANEL) += mdss_spi_client.o +obj-$(CONFIG_FB_MSM_MDSS_SPI_PANEL) += mdss_spi_panel.o +endif + ifneq ($(CONFIG_FB_MSM_MDSS_MDP3), y) obj-$(CONFIG_FB_MSM_MDSS) += mdss_hdmi_util.o obj-$(CONFIG_FB_MSM_MDSS) += mdss_hdmi_edid.o diff --git a/drivers/video/fbdev/msm/dsi_status_v2.c b/drivers/video/fbdev/msm/dsi_status_v2.c index 35b09849f3c8..87720cf87d99 100644 --- a/drivers/video/fbdev/msm/dsi_status_v2.c +++ b/drivers/video/fbdev/msm/dsi_status_v2.c @@ -18,6 +18,7 @@ #include "mdss_dsi.h" #include "mdp3_ctrl.h" +#include "mdss_spi_panel.h" /* * mdp3_check_te_status() - Check the status of panel for TE based ESD. @@ -165,3 +166,79 @@ void mdp3_check_dsi_ctrl_status(struct work_struct *work, mdss_fb_report_panel_dead(pdsi_status->mfd); } +#if defined(CONFIG_FB_MSM_MDSS_SPI_PANEL) +void mdp3_check_spi_panel_status(struct work_struct *work, uint32_t interval) +{ + struct dsi_status_data *pdsi_status = NULL; + struct mdss_panel_data *pdata = NULL; + struct spi_panel_data *ctrl_pdata = NULL; + struct mdp3_session_data *mdp3_session = NULL; + int ret = 0; + + pdsi_status = container_of(to_delayed_work(work), + struct dsi_status_data, check_status); + + if (!pdsi_status || !(pdsi_status->mfd)) { + pr_err("%s: mfd not available\n", __func__); + return; + } + + pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev); + if (!pdata) { + pr_err("%s: panel data not available\n", __func__); + return; + } + + ctrl_pdata = container_of(pdata, struct spi_panel_data, panel_data); + if (!ctrl_pdata || !ctrl_pdata->check_status) { + pr_err("%s: Dsi ctrl or status_check callback not available\n", + __func__); + return; + } + + mdp3_session = pdsi_status->mfd->mdp.private1; + if (!mdp3_session) { + pr_err("%s: Display is off\n", __func__); + return; + } + + if (mdp3_session->in_splash_screen) { + schedule_delayed_work(&pdsi_status->check_status, + msecs_to_jiffies(interval)); + pr_debug("%s: cont splash is on\n", __func__); + return; + } + + mutex_lock(&mdp3_session->lock); + if (!mdp3_session->status) { + pr_debug("%s: display off already\n", __func__); + mutex_unlock(&mdp3_session->lock); + return; + } + + if (!ret) + ret = ctrl_pdata->check_status(ctrl_pdata); + else + pr_err("%s:wait_for_dma_done error\n", __func__); + mutex_unlock(&mdp3_session->lock); + + if (mdss_fb_is_power_on_interactive(pdsi_status->mfd)) { + if (ret > 0) { + schedule_delayed_work(&pdsi_status->check_status, + msecs_to_jiffies(interval)); + } else { + char *envp[2] = {"PANEL_ALIVE=0", NULL}; + + pdata->panel_info.panel_dead = true; + ret = kobject_uevent_env( + &pdsi_status->mfd->fbi->dev->kobj, KOBJ_CHANGE, envp); + pr_err("%s:panel has gone bad, sending uevent - %s\n", + __func__, envp[0]); + } + } +} +#else +void mdp3_check_spi_panel_status(struct work_struct *work, uint32_t interval) +{ +} +#endif diff --git a/drivers/video/fbdev/msm/mdp3.c b/drivers/video/fbdev/msm/mdp3.c index c9db88e07706..54e99199ff9b 100644 --- a/drivers/video/fbdev/msm/mdp3.c +++ b/drivers/video/fbdev/msm/mdp3.c @@ -56,6 +56,7 @@ #include "mdss_debug.h" #include "mdss_smmu.h" #include "mdss.h" +#include "mdss_spi_panel.h" #ifndef EXPORT_COMPAT #define EXPORT_COMPAT(x) @@ -109,6 +110,7 @@ struct mdp3_bus_handle_map mdp3_bus_handle[MDP3_BUS_HANDLE_MAX] = { static struct mdss_panel_intf pan_types[] = { {"dsi", MDSS_PANEL_INTF_DSI}, + {"spi", MDSS_PANEL_INTF_SPI}, }; static char mdss_mdp3_panel[MDSS_MAX_PANEL_LEN]; @@ -127,6 +129,13 @@ struct mdp3_iommu_domain_map mdp3_iommu_domains[MDP3_IOMMU_DOMAIN_MAX] = { }, }; +#ifndef CONFIG_FB_MSM_MDSS_SPI_PANEL +void mdss_spi_panel_bl_ctrl_update(struct mdss_panel_data *pdata, u32 bl_level) +{ + +} +#endif + static irqreturn_t mdp3_irq_handler(int irq, void *ptr) { int i = 0; @@ -1350,7 +1359,11 @@ int mdp3_put_img(struct mdp3_img_data *data, int client) client == MDP3_CLIENT_DMA_P) mdss_smmu_unmap_dma_buf(data->tab_clone, dom, dir, data->srcp_dma_buf); - else + else if (client == MDP3_CLIENT_SPI) { + ion_unmap_kernel(iclient, data->srcp_ihdl); + ion_free(iclient, data->srcp_ihdl); + data->srcp_ihdl = NULL; + } else mdss_smmu_unmap_dma_buf(data->srcp_table, dom, dir, data->srcp_dma_buf); data->mapped = false; @@ -1416,7 +1429,13 @@ int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data, int client) data->srcp_dma_buf = NULL; return ret; } - + data->srcp_ihdl = ion_import_dma_buf(iclient, + data->srcp_dma_buf); + if (IS_ERR_OR_NULL(data->srcp_ihdl)) { + pr_err("error on ion_import_fd\n"); + data->srcp_ihdl = NULL; + return -EIO; + } data->srcp_attachment = mdss_smmu_dma_buf_attach(data->srcp_dma_buf, &mdp3_res->pdev->dev, dom); @@ -1449,6 +1468,25 @@ int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data, int client) data->tab_clone, dom, &data->addr, &data->len, DMA_BIDIRECTIONAL); + } else if (client == MDP3_CLIENT_SPI) { + void *vaddr; + + if (ion_handle_get_size(iclient, + data->srcp_ihdl, + (size_t *)&data->len) < 0) { + pr_err("get size failed\n"); + return -EINVAL; + } + vaddr = ion_map_kernel(iclient, + data->srcp_ihdl); + if (IS_ERR_OR_NULL(vaddr)) { + pr_err("Mapping failed\n"); + mdp3_put_img(data, client); + return -EINVAL; + } + data->addr = (dma_addr_t) vaddr; + data->len -= img->offset; + return 0; } else { ret = mdss_smmu_map_dma_buf(data->srcp_dma_buf, data->srcp_table, dom, &data->addr, @@ -1741,6 +1779,8 @@ static int mdp3_is_display_on(struct mdss_panel_data *pdata) if (pdata->panel_info.type == MIPI_VIDEO_PANEL) { status = MDP3_REG_READ(MDP3_REG_DSI_VIDEO_EN); rc = status & 0x1; + } else if (pdata->panel_info.type == SPI_PANEL) { + rc = is_spi_panel_continuous_splash_on(pdata); } else { status = MDP3_REG_READ(MDP3_REG_DMA_P_CONFIG); status &= 0x180000; @@ -1777,7 +1817,11 @@ static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata) mdp3_clk_set_rate(MDP3_CLK_MDP_SRC, mdp_clk_rate, MDP3_CLIENT_DMA_P); - rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, ab, ib); + /*DMA not used on SPI interface, remove DMA bus voting*/ + if (panel_info->type == SPI_PANEL) + rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, 0, 0); + else + rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, ab, ib); bus_handle->restore_ab[MDP3_CLIENT_DMA_P] = ab; bus_handle->restore_ib[MDP3_CLIENT_DMA_P] = ib; @@ -1795,6 +1839,8 @@ static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata) if (panel_info->type == MIPI_VIDEO_PANEL) mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_VIDEO].active = 1; + else if (panel_info->type == SPI_PANEL) + mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_SPI_CMD].active = 1; else mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_CMD].active = 1; @@ -2485,6 +2531,9 @@ static int mdp3_probe(struct platform_device *pdev) mdp3_res->mdss_util->mdp_probe_done = true; pr_debug("%s: END\n", __func__); + if (mdp3_res->pan_cfg.pan_intf == MDSS_PANEL_INTF_SPI) + mdp3_interface.check_dsi_status = mdp3_check_spi_panel_status; + probe_done: if (IS_ERR_VALUE(rc)) kfree(mdp3_res->mdp3_hw.irq_info); diff --git a/drivers/video/fbdev/msm/mdp3.h b/drivers/video/fbdev/msm/mdp3.h index 7132dee09e15..6b560521ec53 100644 --- a/drivers/video/fbdev/msm/mdp3.h +++ b/drivers/video/fbdev/msm/mdp3.h @@ -84,6 +84,7 @@ enum { MDP3_CLIENT_DSI = 1, MDP3_CLIENT_PPP, MDP3_CLIENT_IOMMU, + MDP3_CLIENT_SPI, MDP3_CLIENT_MAX, }; @@ -208,6 +209,8 @@ struct mdp3_hw_resource { bool solid_fill_vote_en; struct list_head reg_bus_clist; struct mutex reg_bus_lock; + int bklt_level; + int bklt_update; bool twm_en; u32 max_bw; @@ -267,6 +270,7 @@ int mdp3_misr_get(struct mdp_misr *misr_resp); void mdp3_enable_regulator(int enable); void mdp3_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval); +void mdp3_check_spi_panel_status(struct work_struct *work, uint32_t interval); int mdp3_dynamic_clock_gating_ctrl(int enable); int mdp3_footswitch_ctrl(int enable); int mdp3_qos_remapper_setup(struct mdss_panel_data *panel); @@ -279,6 +283,8 @@ void mdp3_calc_dma_res(struct mdss_panel_info *panel_info, u64 *clk_rate, void mdp3_clear_irq(u32 interrupt_mask); int mdp3_enable_panic_ctrl(void); +void mdss_spi_panel_bl_ctrl_update(struct mdss_panel_data *pdata, u32 bl_level); + int mdp3_layer_pre_commit(struct msm_fb_data_type *mfd, struct file *file, struct mdp_layer_commit_v1 *commit); int mdp3_layer_atomic_validate(struct msm_fb_data_type *mfd, diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c index 50b232afca81..c976c0e11914 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.c +++ b/drivers/video/fbdev/msm/mdp3_ctrl.c @@ -23,11 +23,13 @@ #include #include #include +#include #include "mdp3_ctrl.h" #include "mdp3.h" #include "mdp3_ppp.h" #include "mdss_smmu.h" +#include "mdss_spi_panel.h" #include "mdss_sync.h" #define VSYNC_EXPIRE_TICK 4 @@ -72,7 +74,7 @@ static void mdp3_bufq_init(struct mdp3_buffer_queue *bufq) bufq->pop_idx = 0; } -void mdp3_bufq_deinit(struct mdp3_buffer_queue *bufq) +void mdp3_bufq_deinit(struct mdp3_buffer_queue *bufq, int client) { int count = bufq->count; @@ -83,7 +85,7 @@ void mdp3_bufq_deinit(struct mdp3_buffer_queue *bufq) struct mdp3_img_data *data = &bufq->img_data[bufq->pop_idx]; bufq->pop_idx = (bufq->pop_idx + 1) % MDP3_MAX_BUF_QUEUE; - mdp3_put_img(data, MDP3_CLIENT_DMA_P); + mdp3_put_img(data, client); } bufq->count = 0; bufq->push_idx = 0; @@ -122,6 +124,18 @@ static int mdp3_bufq_count(struct mdp3_buffer_queue *bufq) return bufq->count; } +int mdp3_get_ion_client(struct msm_fb_data_type *mfd) +{ + int intf_type; + + intf_type = mdp3_ctrl_get_intf_type(mfd); + + if (intf_type == MDP3_DMA_OUTPUT_SEL_SPI_CMD) + return MDP3_CLIENT_SPI; + else + return MDP3_CLIENT_DMA_P; +} + void mdp3_ctrl_notifier_register(struct mdp3_session_data *ses, struct notifier_block *notifier) { @@ -308,8 +322,11 @@ static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable) struct mdp3_notification vsync_client; struct mdp3_notification *arg = NULL; bool mod_vsync_timer = false; + int intf_type; pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable); + + intf_type = mdp3_ctrl_get_intf_type(mfd); mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma || !mdp3_session->intf) @@ -347,18 +364,25 @@ static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable) } } - mdp3_clk_enable(1, 0); - mdp3_session->dma->vsync_enable(mdp3_session->dma, arg); - mdp3_clk_enable(0, 0); + if (intf_type == MDP3_DMA_OUTPUT_SEL_SPI_CMD) { + mdp3_spi_vsync_enable(mdp3_session->panel, arg); + } else { + mdp3_clk_enable(1, 0); + mdp3_session->dma->vsync_enable(mdp3_session->dma, arg); + mdp3_clk_enable(0, 0); + } /* * Need to fake vsync whenever dsi interface is not * active or when dsi clocks are currently off */ - if (mod_vsync_timer) { + if (mod_vsync_timer && (intf_type != MDP3_DMA_OUTPUT_SEL_SPI_CMD)) { mod_timer(&mdp3_session->vsync_timer, jiffies + msecs_to_jiffies(mdp3_session->vsync_period)); - } else if (!enable) { + } else if (enable && !mdp3_session->clk_on) { + mdp3_ctrl_reset_countdown(mdp3_session, mfd); + mdp3_ctrl_clk_enable(mfd, 1); + } else if (!enable && (intf_type != MDP3_DMA_OUTPUT_SEL_SPI_CMD)) { del_timer(&mdp3_session->vsync_timer); } @@ -597,14 +621,32 @@ static int mdp3_ctrl_clk_enable(struct msm_fb_data_type *mfd, int enable) static int mdp3_ctrl_res_req_bus(struct msm_fb_data_type *mfd, int status) { int rc = 0; + u32 vtotal = 0; + int frame_rate = DEFAULT_FRAME_RATE; if (status) { + struct mdss_panel_info *panel_info = mfd->panel_info; u64 ab = 0; u64 ib = 0; + frame_rate = mdss_panel_get_framerate(mfd->panel_info, + FPS_RESOLUTION_HZ); mdp3_calc_dma_res(mfd->panel_info, NULL, &ab, &ib, ppp_bpp(mfd->fb_imgType)); - rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, ab, ib); + vtotal = panel_info->yres + panel_info->lcdc.v_back_porch + + panel_info->lcdc.v_front_porch + + panel_info->lcdc.v_pulse_width; + ab = panel_info->xres * vtotal * ppp_bpp(mfd->fb_imgType); + ab *= frame_rate; + ib = ab; + + /*DMA not used on SPI interface, remove DMA bus voting*/ + if (mdp3_ctrl_get_intf_type(mfd) == + MDP3_DMA_OUTPUT_SEL_SPI_CMD) + rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, 0, 0); + else + rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, + ab, ib); } else { rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, 0, 0); } @@ -653,6 +695,9 @@ static int mdp3_ctrl_get_intf_type(struct msm_fb_data_type *mfd) case LCDC_PANEL: type = MDP3_DMA_OUTPUT_SEL_LCDC; break; + case SPI_PANEL: + type = MDP3_DMA_OUTPUT_SEL_SPI_CMD; + break; default: type = MDP3_DMA_OUTPUT_SEL_MAX; } @@ -717,7 +762,8 @@ static int mdp3_ctrl_intf_init(struct msm_fb_data_type *mfd, cfg.type = mdp3_ctrl_get_intf_type(mfd); if (cfg.type == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO || - cfg.type == MDP3_DMA_OUTPUT_SEL_LCDC) { + cfg.type == MDP3_DMA_OUTPUT_SEL_LCDC || + cfg.type == MDP3_DMA_OUTPUT_SEL_SPI_CMD) { video->hsync_period = hsync_period; video->hsync_pulse_width = h_pulse_width; video->vsync_period = vsync_period; @@ -765,7 +811,7 @@ static int mdp3_ctrl_dma_init(struct msm_fb_data_type *mfd, struct fb_var_screeninfo *var; struct mdp3_dma_output_config outputConfig; struct mdp3_dma_source sourceConfig; - int frame_rate = mfd->panel_info->mipi.frame_rate; + int frame_rate = DEFAULT_FRAME_RATE; int vbp, vfp, vspw; int vtotal, vporch; struct mdp3_notification dma_done_callback; @@ -774,6 +820,7 @@ static int mdp3_ctrl_dma_init(struct msm_fb_data_type *mfd, mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + frame_rate = mdss_panel_get_framerate(panel_info, FPS_RESOLUTION_HZ); vbp = panel_info->lcdc.v_back_porch; vfp = panel_info->lcdc.v_front_porch; vspw = panel_info->lcdc.v_pulse_width; @@ -814,7 +861,7 @@ static int mdp3_ctrl_dma_init(struct msm_fb_data_type *mfd, sourceConfig.stride = fix->line_length; } - te.frame_rate = panel_info->mipi.frame_rate; + te.frame_rate = frame_rate; te.hw_vsync_mode = panel_info->mipi.hw_vsync_mode; te.tear_check_en = panel_info->te.tear_check_en; te.sync_cfg_height = panel_info->te.sync_cfg_height; @@ -1003,6 +1050,7 @@ static bool mdp3_is_twm_en(void) static int mdp3_ctrl_off(struct msm_fb_data_type *mfd) { int rc = 0; + int client = 0; bool intf_stopped = true; struct mdp3_session_data *mdp3_session; struct mdss_panel_data *panel; @@ -1156,10 +1204,11 @@ static int mdp3_ctrl_off(struct msm_fb_data_type *mfd) pr_err("%s: pm_runtime_put failed (rc %d)\n", __func__, rc); } - mdp3_bufq_deinit(&mdp3_session->bufq_out); + client = mdp3_get_ion_client(mfd); + mdp3_bufq_deinit(&mdp3_session->bufq_out, client); if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) { mdp3_session->overlay.id = MSMFB_NEW_REQUEST; - mdp3_bufq_deinit(&mdp3_session->bufq_in); + mdp3_bufq_deinit(&mdp3_session->bufq_in, client); } } @@ -1189,6 +1238,10 @@ static int mdp3_ctrl_off(struct msm_fb_data_type *mfd) mdp3_ctrl_clk_enable(mdp3_session->mfd, 0); } off_error: + if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) { + mdp3_session->overlay.id = MSMFB_NEW_REQUEST; + mdp3_bufq_deinit(&mdp3_session->bufq_in, client); + } MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__); mutex_unlock(&mdp3_session->lock); /* Release the last reference to the runtime device */ @@ -1336,14 +1389,16 @@ static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx) struct fb_info *fbi = mfd->fbi; struct fb_fix_screeninfo *fix; int format; + int client; fix = &fbi->fix; format = mdp3_ctrl_get_source_format(mfd->fb_imgType); mutex_lock(&mdp3_session->lock); + client = mdp3_get_ion_client(mfd); if (mdp3_session->overlay.id == ndx && ndx == 1) { mdp3_session->overlay.id = MSMFB_NEW_REQUEST; - mdp3_bufq_deinit(&mdp3_session->bufq_in); + mdp3_bufq_deinit(&mdp3_session->bufq_in, client); } else { rc = -EINVAL; } @@ -1362,18 +1417,20 @@ static int mdp3_overlay_queue_buffer(struct msm_fb_data_type *mfd, struct msmfb_data *img = &req->data; struct mdp3_img_data data; struct mdp3_dma *dma = mdp3_session->dma; + int client; + client = mdp3_get_ion_client(mfd); memset(&data, 0, sizeof(struct mdp3_img_data)); - if (mfd->panel.type == MIPI_CMD_PANEL) + if (mfd->panel.type == MIPI_CMD_PANEL || client == MDP3_CLIENT_SPI) is_panel_type_cmd = true; if (is_panel_type_cmd) { - rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P); + rc = mdp3_iommu_enable(client); if (rc) { pr_err("fail to enable iommu\n"); return rc; } } - rc = mdp3_get_img(img, &data, MDP3_CLIENT_DMA_P); + rc = mdp3_get_img(img, &data, client); if (rc) { pr_err("fail to get overlay buffer\n"); goto err; @@ -1383,14 +1440,14 @@ static int mdp3_overlay_queue_buffer(struct msm_fb_data_type *mfd, pr_err("buf size(0x%lx) is smaller than dma config(0x%x)\n", data.len, (dma->source_config.stride * dma->source_config.height)); - mdp3_put_img(&data, MDP3_CLIENT_DMA_P); + mdp3_put_img(&data, client); rc = -EINVAL; goto err; } rc = mdp3_bufq_push(&mdp3_session->bufq_in, &data); if (rc) { pr_err("fail to queue the overlay buffer, buffer drop\n"); - mdp3_put_img(&data, MDP3_CLIENT_DMA_P); + mdp3_put_img(&data, client); goto err; } rc = 0; @@ -1449,8 +1506,11 @@ static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd, struct mdp3_img_data *data; struct mdss_panel_info *panel_info; int rc = 0; + int client; static bool splash_done; struct mdss_panel_data *panel; + int frame_rate = DEFAULT_FRAME_RATE; + int stride; if (!mfd || !mfd->mdp.private1) return -EINVAL; @@ -1460,6 +1520,9 @@ static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd, if (!mdp3_session || !mdp3_session->dma) return -EINVAL; + frame_rate = mdss_panel_get_framerate(panel_info, FPS_RESOLUTION_HZ); + client = mdp3_get_ion_client(mfd); + if (mdp3_bufq_count(&mdp3_session->bufq_in) == 0) { pr_debug("no buffer in queue yet\n"); return -EPERM; @@ -1510,7 +1573,17 @@ static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd, if (data) { mdp3_ctrl_reset_countdown(mdp3_session, mfd); mdp3_ctrl_clk_enable(mfd, 1); - if (mdp3_session->dma->update_src_cfg && + stride = mdp3_session->dma->source_config.stride; + if (mdp3_ctrl_get_intf_type(mfd) == + MDP3_DMA_OUTPUT_SEL_SPI_CMD){ + mdp3_session->intf->active = false; + msm_ion_do_cache_op(mdp3_res->ion_client, + data->srcp_ihdl, (void *)(int)data->addr, + data->len, ION_IOC_INV_CACHES); + rc = mdss_spi_panel_kickoff(mdp3_session->panel, + (void *)(int)data->addr, (int)data->len, + stride); + } else if (mdp3_session->dma->update_src_cfg && panel_info->partial_update_enabled) { panel->panel_info.roi.x = mdp3_session->dma->roi.x; panel->panel_info.roi.y = mdp3_session->dma->roi.y; @@ -1530,7 +1603,9 @@ static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd, MDP_NOTIFY_FRAME_TIMEOUT); } else { if (mdp3_ctrl_get_intf_type(mfd) == - MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) { + MDP3_DMA_OUTPUT_SEL_DSI_VIDEO || + mdp3_ctrl_get_intf_type(mfd) == + MDP3_DMA_OUTPUT_SEL_SPI_CMD) { mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_DONE); } @@ -1545,16 +1620,16 @@ static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd, mdp3_release_splash_memory(mfd); data = mdp3_bufq_pop(&mdp3_session->bufq_out); if (data) - mdp3_put_img(data, MDP3_CLIENT_DMA_P); + mdp3_put_img(data, client); } if (mdp3_session->first_commit) { /*wait to ensure frame is sent to panel*/ if (panel_info->mipi.post_init_delay) - msleep(((1000 / panel_info->mipi.frame_rate) + 1) * + msleep(((1000 / frame_rate) + 1) * panel_info->mipi.post_init_delay); else - msleep(1000 / panel_info->mipi.frame_rate); + msleep((1000 / frame_rate) + 1); mdp3_session->first_commit = false; if (panel) rc |= panel->event_handler(panel, @@ -1569,6 +1644,12 @@ static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd, mdp3_session->esd_recovery = false; } + /*Update backlight only if its changed*/ + if (mdp3_res->bklt_level && mdp3_res->bklt_update) { + mdss_spi_panel_bl_ctrl_update(panel, mdp3_res->bklt_level); + mdp3_res->bklt_update = false; + } + /* start vsync tick countdown for cmd mode if vsync isn't enabled */ if (mfd->panel.type == MIPI_CMD_PANEL && !mdp3_session->vsync_enabled) mdp3_ctrl_vsync_enable(mdp3_session->mfd, 0); @@ -1695,17 +1776,18 @@ static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd) } panel = mdp3_session->panel; - if (mdp3_session->first_commit) { - /*wait to ensure frame is sent to panel*/ - if (panel_info->mipi.post_init_delay) - msleep(((1000 / panel_info->mipi.frame_rate) + 1) * - panel_info->mipi.post_init_delay); - else - msleep(1000 / panel_info->mipi.frame_rate); - mdp3_session->first_commit = false; - if (panel) - panel->event_handler(panel, MDSS_EVENT_POST_PANEL_ON, - NULL); + if (mdp3_ctrl_get_intf_type(mfd) != MDP3_DMA_OUTPUT_SEL_SPI_CMD) { + if (mdp3_session->first_commit) { + if (panel_info->mipi.init_delay) + msleep(((1000 / panel_info->mipi.frame_rate) + + 1) * panel_info->mipi.post_init_delay); + else + msleep(1000 / panel_info->mipi.frame_rate); + mdp3_session->first_commit = false; + if (panel) + panel->event_handler(panel, + MDSS_EVENT_POST_PANEL_ON, NULL); + } } mdp3_session->vsync_before_commit = 0; @@ -1716,6 +1798,11 @@ static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd) mdp3_session->esd_recovery = false; } + /*Update backlight only if its changed*/ + if (mdp3_res->bklt_level && mdp3_res->bklt_update) { + mdss_spi_panel_bl_ctrl_update(panel, mdp3_res->bklt_level); + mdp3_res->bklt_update = false; + } pan_error: mutex_unlock(&mdp3_session->lock); @@ -1756,7 +1843,8 @@ static int mdp3_get_metadata(struct msm_fb_data_type *mfd, switch (metadata->op) { case metadata_op_frame_rate: metadata->data.panel_frame_rate = - mfd->panel_info->mipi.frame_rate; + mdss_panel_get_framerate(mfd->panel_info, + FPS_RESOLUTION_HZ); break; case metadata_op_get_caps: metadata->data.caps.mdp_rev = 305; @@ -2893,6 +2981,7 @@ int mdp3_ctrl_init(struct msm_fb_data_type *mfd) struct msm_mdp_interface *mdp3_interface = &mfd->mdp; struct mdp3_session_data *mdp3_session = NULL; u32 intf_type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO; + int frame_rate = DEFAULT_FRAME_RATE; int rc; int splash_mismatch = 0; struct sched_param sched = { .sched_priority = 16 }; @@ -2902,6 +2991,8 @@ int mdp3_ctrl_init(struct msm_fb_data_type *mfd) if (rc) splash_mismatch = 1; + frame_rate = mdss_panel_get_framerate(mfd->panel_info, + FPS_RESOLUTION_HZ); mdp3_interface->on_fnc = mdp3_ctrl_on; mdp3_interface->off_fnc = mdp3_ctrl_off; mdp3_interface->do_histogram = NULL; @@ -2980,10 +3071,11 @@ int mdp3_ctrl_init(struct msm_fb_data_type *mfd) init_timer(&mdp3_session->vsync_timer); mdp3_session->vsync_timer.function = mdp3_vsync_timer_func; mdp3_session->vsync_timer.data = (u32)mdp3_session; - mdp3_session->vsync_period = 1000 / mfd->panel_info->mipi.frame_rate; + mdp3_session->vsync_period = 1000 / frame_rate; mfd->mdp.private1 = mdp3_session; init_completion(&mdp3_session->dma_completion); - if (intf_type != MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) + if (intf_type != MDP3_DMA_OUTPUT_SEL_DSI_VIDEO || + intf_type != MDP3_DMA_OUTPUT_SEL_SPI_CMD) mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done; rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group); diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.h b/drivers/video/fbdev/msm/mdp3_ctrl.h index b7b667b69a9a..5193af1822e4 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.h +++ b/drivers/video/fbdev/msm/mdp3_ctrl.h @@ -84,12 +84,13 @@ struct mdp3_session_data { struct work_struct retire_work; }; -void mdp3_bufq_deinit(struct mdp3_buffer_queue *bufq); +void mdp3_bufq_deinit(struct mdp3_buffer_queue *bufq, int client); int mdp3_ctrl_init(struct msm_fb_data_type *mfd); int mdp3_bufq_push(struct mdp3_buffer_queue *bufq, struct mdp3_img_data *data); int mdp3_ctrl_get_source_format(u32 imgType); int mdp3_ctrl_get_pack_pattern(u32 imgType); int mdp3_ctrl_reset(struct msm_fb_data_type *mfd); +int mdp3_get_ion_client(struct msm_fb_data_type *mfd); #endif /* MDP3_CTRL_H */ diff --git a/drivers/video/fbdev/msm/mdp3_dma.c b/drivers/video/fbdev/msm/mdp3_dma.c index 71fcbf9ba490..b223c87599b7 100644 --- a/drivers/video/fbdev/msm/mdp3_dma.c +++ b/drivers/video/fbdev/msm/mdp3_dma.c @@ -114,7 +114,8 @@ void mdp3_dma_callback_enable(struct mdp3_dma *dma, int type) } if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO || - dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC) { + dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC || + dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_SPI_CMD) { if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC) mdp3_irq_enable(MDP3_INTR_LCDC_START_OF_FRAME); } else if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) { @@ -150,7 +151,8 @@ void mdp3_dma_callback_disable(struct mdp3_dma *dma, int type) } if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO || - dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC) { + dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC || + dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_SPI_CMD) { if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC) mdp3_irq_disable(MDP3_INTR_LCDC_START_OF_FRAME); } else if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) { @@ -1268,6 +1270,22 @@ int dsi_cmd_stop(struct mdp3_intf *intf) return 0; } +static int spi_cmd_config(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg) +{ + return 0; +} + +static int spi_cmd_start(struct mdp3_intf *intf) +{ + intf->active = true; + return 0; +} + +static int spi_cmd_stop(struct mdp3_intf *intf) +{ + intf->active = false; + return 0; +} int mdp3_intf_init(struct mdp3_intf *intf) { switch (intf->cfg.type) { @@ -1286,6 +1304,11 @@ int mdp3_intf_init(struct mdp3_intf *intf) intf->start = dsi_cmd_start; intf->stop = dsi_cmd_stop; break; + case MDP3_DMA_OUTPUT_SEL_SPI_CMD: + intf->config = spi_cmd_config; + intf->start = spi_cmd_start; + intf->stop = spi_cmd_stop; + break; default: return -EINVAL; diff --git a/drivers/video/fbdev/msm/mdp3_dma.h b/drivers/video/fbdev/msm/mdp3_dma.h index 24caedb931f7..ec327b6ed75e 100644 --- a/drivers/video/fbdev/msm/mdp3_dma.h +++ b/drivers/video/fbdev/msm/mdp3_dma.h @@ -47,6 +47,7 @@ enum { MDP3_DMA_OUTPUT_SEL_DSI_CMD, MDP3_DMA_OUTPUT_SEL_LCDC, MDP3_DMA_OUTPUT_SEL_DSI_VIDEO, + MDP3_DMA_OUTPUT_SEL_SPI_CMD, MDP3_DMA_OUTPUT_SEL_MAX }; diff --git a/drivers/video/fbdev/msm/mdp3_layer.c b/drivers/video/fbdev/msm/mdp3_layer.c index 0078466dc2a4..98b5c19aa324 100644 --- a/drivers/video/fbdev/msm/mdp3_layer.c +++ b/drivers/video/fbdev/msm/mdp3_layer.c @@ -197,6 +197,7 @@ static int __mdp3_map_layer_buffer(struct msm_fb_data_type *mfd, struct msmfb_data img; bool is_panel_type_cmd = false; struct mdp3_img_data data; + int intf_type; int rc = 0; layer = &input_layer[0]; @@ -208,23 +209,24 @@ static int __mdp3_map_layer_buffer(struct msm_fb_data_type *mfd, goto err; } + intf_type = mdp3_get_ion_client(mfd); memset(&img, 0, sizeof(img)); img.memory_id = buffer->planes[0].fd; img.offset = buffer->planes[0].offset; memset(&data, 0, sizeof(struct mdp3_img_data)); - if (mfd->panel.type == MIPI_CMD_PANEL) + if (mfd->panel.type == MIPI_CMD_PANEL || intf_type == MDP3_CLIENT_SPI) is_panel_type_cmd = true; if (is_panel_type_cmd) { - rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P); + rc = mdp3_iommu_enable(intf_type); if (rc) { pr_err("fail to enable iommu\n"); return rc; } } - rc = mdp3_get_img(&img, &data, MDP3_CLIENT_DMA_P); + rc = mdp3_get_img(&img, &data, intf_type); if (rc) { pr_err("fail to get overlay buffer\n"); goto err; @@ -260,7 +262,7 @@ int mdp3_layer_pre_commit(struct msm_fb_data_type *mfd, struct mdp3_session_data *mdp3_session; struct mdp3_dma *dma; int layer_count = commit->input_layer_cnt; - int stride, format; + int stride, format, client; /* Handle NULL commit */ if (!layer_count) { @@ -273,7 +275,8 @@ int mdp3_layer_pre_commit(struct msm_fb_data_type *mfd, mutex_lock(&mdp3_session->lock); - mdp3_bufq_deinit(&mdp3_session->bufq_in); + client = mdp3_get_ion_client(mfd); + mdp3_bufq_deinit(&mdp3_session->bufq_in, client); layer_list = commit->input_layers; layer = &layer_list[0]; diff --git a/drivers/video/fbdev/msm/mdp3_ppp.c b/drivers/video/fbdev/msm/mdp3_ppp.c index 33910596d46e..545951094f73 100644 --- a/drivers/video/fbdev/msm/mdp3_ppp.c +++ b/drivers/video/fbdev/msm/mdp3_ppp.c @@ -542,6 +542,7 @@ int mdp3_calc_ppp_res(struct msm_fb_data_type *mfd, { struct mdss_panel_info *panel_info = mfd->panel_info; int i, lcount = 0; + int frame_rate = DEFAULT_FRAME_RATE; struct mdp_blit_req *req; struct bpp_info bpp; u64 old_solid_fill_pixel = 0; @@ -556,6 +557,7 @@ int mdp3_calc_ppp_res(struct msm_fb_data_type *mfd, ATRACE_BEGIN(__func__); lcount = lreq->count; + frame_rate = mdss_panel_get_framerate(panel_info, FPS_RESOLUTION_HZ); if (lcount == 0) { pr_err("Blit with request count 0, continue to recover!!!\n"); ATRACE_END(__func__); @@ -583,11 +585,11 @@ int mdp3_calc_ppp_res(struct msm_fb_data_type *mfd, is_blit_optimization_possible(lreq, i); req = &(lreq->req_list[i]); - if (req->fps > 0 && req->fps <= panel_info->mipi.frame_rate) { + if (req->fps > 0 && req->fps <= frame_rate) { if (fps == 0) fps = req->fps; else - fps = panel_info->mipi.frame_rate; + fps = frame_rate; } mdp3_get_bpp_info(req->src.format, &bpp); @@ -645,7 +647,7 @@ int mdp3_calc_ppp_res(struct msm_fb_data_type *mfd, } if (fps == 0) - fps = panel_info->mipi.frame_rate; + fps = frame_rate; if (lreq->req_list[0].flags & MDP_SOLID_FILL) { honest_ppp_ab = ppp_res.solid_fill_byte * 4; diff --git a/drivers/video/fbdev/msm/mdp3_ppp_data.c b/drivers/video/fbdev/msm/mdp3_ppp_data.c index ac88d9b29d38..dd2cce007b8d 100644 --- a/drivers/video/fbdev/msm/mdp3_ppp_data.c +++ b/drivers/video/fbdev/msm/mdp3_ppp_data.c @@ -89,8 +89,8 @@ const uint32_t pack_patt_lut[MDP_IMGTYPE_LIMIT] = { }; const uint32_t swapped_pack_patt_lut[MDP_IMGTYPE_LIMIT] = { - [MDP_RGB_565] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8), - [MDP_BGR_565] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8), + [MDP_RGB_565] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8), + [MDP_BGR_565] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8), [MDP_RGB_888] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8), [MDP_BGR_888] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8), [MDP_BGRA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 816eed022994..fdc7f5cf3a2f 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -3263,6 +3263,7 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) struct mdss_util_intf *util; static int te_irq_registered; struct mdss_panel_data *pdata; + struct mdss_panel_cfg *pan_cfg = NULL; if (!pdev || !pdev->dev.of_node) { pr_err("%s: pdev not found for DSI controller\n", __func__); @@ -3295,6 +3296,14 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) return -ENODEV; } + pan_cfg = util->panel_intf_type(MDSS_PANEL_INTF_SPI); + if (IS_ERR(pan_cfg)) { + return PTR_ERR(pan_cfg); + } else if (pan_cfg) { + pr_debug("%s: SPI is primary\n", __func__); + return -ENODEV; + } + ctrl_pdata->mdss_util = util; atomic_set(&ctrl_pdata->te_irq_ready, 0); diff --git a/drivers/video/fbdev/msm/mdss_dsi_status.c b/drivers/video/fbdev/msm/mdss_dsi_status.c index c5af96214114..326768d35ba9 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_status.c +++ b/drivers/video/fbdev/msm/mdss_dsi_status.c @@ -146,15 +146,18 @@ static int fb_event_callback(struct notifier_block *self, return NOTIFY_DONE; mfd = evdata->info->par; - ctrl_pdata = container_of(dev_get_platdata(&mfd->pdev->dev), + if (mfd->panel_info->type == SPI_PANEL) { + pinfo = mfd->panel_info; + } else { + ctrl_pdata = container_of(dev_get_platdata(&mfd->pdev->dev), struct mdss_dsi_ctrl_pdata, panel_data); - if (!ctrl_pdata) { - pr_err("%s: DSI ctrl not available\n", __func__); - return NOTIFY_BAD; - } - - pinfo = &ctrl_pdata->panel_data.panel_info; + if (!ctrl_pdata) { + pr_err("%s: DSI ctrl not available\n", __func__); + return NOTIFY_BAD; + } + pinfo = &ctrl_pdata->panel_data.panel_info; + } if ((!(pinfo->esd_check_enabled) && dsi_status_disable) || (dsi_status_disable == DSI_STATUS_CHECK_DISABLE)) { diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 72f651e83e4b..edeecb4eba5b 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -345,6 +345,9 @@ static ssize_t mdss_fb_get_type(struct device *dev, case EDP_PANEL: ret = snprintf(buf, PAGE_SIZE, "edp panel\n"); break; + case SPI_PANEL: + ret = snprintf(buf, PAGE_SIZE, "spi panel\n"); + break; default: ret = snprintf(buf, PAGE_SIZE, "unknown panel\n"); break; @@ -1214,6 +1217,7 @@ static int mdss_fb_probe(struct platform_device *pdev) struct mdss_panel_data *pdata; struct fb_info *fbi; int rc; + const char *data; if (fbi_list_index >= MAX_FBI_LIST) return -ENOMEM; @@ -1262,6 +1266,21 @@ static int mdss_fb_probe(struct platform_device *pdev) mfd->pdev = pdev; + if (mfd->panel.type == SPI_PANEL) + mfd->fb_imgType = MDP_RGB_565; + if (mfd->panel.type == MIPI_VIDEO_PANEL || mfd->panel.type == + MIPI_CMD_PANEL || mfd->panel.type == SPI_PANEL){ + rc = of_property_read_string(pdev->dev.of_node, + "qcom,mdss-fb-format", &data); + if (!rc) { + if (!strcmp(data, "rgb888")) + mfd->fb_imgType = MDP_RGB_888; + else if (!strcmp(data, "rgb565")) + mfd->fb_imgType = MDP_RGB_565; + else + mfd->fb_imgType = MDP_RGBA_8888; + } + } mfd->split_fb_left = mfd->split_fb_right = 0; mdss_fb_set_split_mode(mfd, pdata); @@ -1374,6 +1393,7 @@ static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd, mfd->mdp_sync_pt_data.threshold = 1; mfd->mdp_sync_pt_data.retire_threshold = 0; break; + case SPI_PANEL: case MIPI_CMD_PANEL: mfd->mdp_sync_pt_data.threshold = 1; mfd->mdp_sync_pt_data.retire_threshold = 1; diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index aa90d5fb2cd5..314dc0e50774 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -60,6 +60,7 @@ enum fps_resolution { #define WRITEBACK_PANEL 10 /* Wifi display */ #define LVDS_PANEL 11 /* LVDS */ #define EDP_PANEL 12 /* LVDS */ +#define SPI_PANEL 13 #define DSC_PPS_LEN 128 @@ -108,6 +109,7 @@ enum { MDSS_PANEL_INTF_DSI, MDSS_PANEL_INTF_EDP, MDSS_PANEL_INTF_HDMI, + MDSS_PANEL_INTF_SPI, }; enum { @@ -117,6 +119,12 @@ enum { MDSS_PANEL_POWER_LP2, }; +enum { + MDSS_PANEL_BLANK_BLANK = 0, + MDSS_PANEL_BLANK_UNBLANK, + MDSS_PANEL_BLANK_LOW_POWER, +}; + enum { MDSS_PANEL_LOW_PERSIST_MODE_OFF = 0, MDSS_PANEL_LOW_PERSIST_MODE_ON, @@ -430,6 +438,10 @@ struct edp_panel_info { char frame_rate; /* fps */ }; +struct spi_panel_info { + char frame_rate; +}; + /** * struct dynamic_fps_data - defines dynamic fps related data * @hfp: horizontal front porch @@ -677,6 +689,7 @@ struct mdss_panel_info { u32 partial_update_roi_merge; struct ion_handle *splash_ihdl; int panel_power_state; + int blank_state; int compression_mode; uint32_t panel_dead; @@ -736,6 +749,7 @@ struct mdss_panel_info { struct lcd_panel_info lcdc; struct fbc_panel_info fbc; struct mipi_panel_info mipi; + struct spi_panel_info spi; struct lvds_panel_info lvds; struct edp_panel_info edp; @@ -875,6 +889,9 @@ static inline u32 mdss_panel_get_framerate(struct mdss_panel_info *panel_info, frame_rate = panel_info->lcdc.frame_rate; break; } + case SPI_PANEL: + frame_rate = panel_info->spi.frame_rate; + break; default: pixel_total = (panel_info->lcdc.h_back_porch + panel_info->lcdc.h_front_porch + diff --git a/drivers/video/fbdev/msm/mdss_spi_client.c b/drivers/video/fbdev/msm/mdss_spi_client.c new file mode 100644 index 000000000000..541e382bd1d5 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_spi_client.c @@ -0,0 +1,198 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mdss_spi_client.h" + +#define MAX_READ_SPEED_HZ 9600000 +#define SPI_PANEL_COMMAND_LEN 1 +static struct spi_device *mdss_spi_client; + +int mdss_spi_read_data(u8 reg_addr, u8 *data, u8 len) +{ + int rc = 0; + u32 max_speed_hz; + u8 memory_write_reg = 0x2c; + u8 empty_pack[] = {0x29, 0x29, 0x29}; + struct spi_transfer t[4] = { + [0] = { + .tx_buf = ®_addr, + .len = 1, + }, + [1] = { + .rx_buf = data, + .len = len, + }, + [2] = { + .tx_buf = &empty_pack, + .len = 3, + }, + [3] = { + .tx_buf = &memory_write_reg, + .len = 1, + } + }; + struct spi_message m; + + if (!mdss_spi_client) { + pr_err("%s: spi client not available\n", __func__); + return -EINVAL; + } + + mdss_spi_client->bits_per_word = 8; + max_speed_hz = mdss_spi_client->max_speed_hz; + mdss_spi_client->max_speed_hz = MAX_READ_SPEED_HZ; + + spi_message_init(&m); + spi_message_add_tail(&t[0], &m); + spi_message_add_tail(&t[1], &m); + rc = spi_sync(mdss_spi_client, &m); + + spi_message_init(&m); + spi_message_add_tail(&t[2], &m); + rc = spi_sync(mdss_spi_client, &m); + spi_message_init(&m); + spi_message_add_tail(&t[3], &m); + rc = spi_sync(mdss_spi_client, &m); + mdss_spi_client->max_speed_hz = max_speed_hz; + + return rc; +} + +int mdss_spi_tx_command(const void *buf) +{ + int rc = 0; + struct spi_transfer t = { + .tx_buf = buf, + .len = SPI_PANEL_COMMAND_LEN, + }; + struct spi_message m; + + if (!mdss_spi_client) { + pr_err("%s: spi client not available\n", __func__); + return -EINVAL; + } + + mdss_spi_client->bits_per_word = 8; + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + rc = spi_sync(mdss_spi_client, &m); + + return rc; +} + +int mdss_spi_tx_parameter(const void *buf, size_t len) +{ + int rc = 0; + struct spi_transfer t = { + .tx_buf = buf, + .len = len, + }; + struct spi_message m; + + if (!mdss_spi_client) { + pr_err("%s: spi client not available\n", __func__); + return -EINVAL; + } + + mdss_spi_client->bits_per_word = 8; + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + rc = spi_sync(mdss_spi_client, &m); + + return rc; +} + +int mdss_spi_tx_pixel(const void *buf, size_t len) +{ + int rc = 0; + struct spi_transfer t = { + .tx_buf = buf, + .len = len, + }; + struct spi_message m; + + if (!mdss_spi_client) { + pr_err("%s: spi client not available\n", __func__); + return -EINVAL; + } + + mdss_spi_client->bits_per_word = 16; + spi_message_init(&m); + spi_message_add_tail(&t, &m); + rc = spi_sync(mdss_spi_client, &m); + + return rc; +} + +static int mdss_spi_client_probe(struct spi_device *spidev) +{ + int irq; + int cs; + int cpha, cpol, cs_high; + u32 max_speed; + struct device_node *np; + + irq = spidev->irq; + cs = spidev->chip_select; + cpha = (spidev->mode & SPI_CPHA) ? 1:0; + cpol = (spidev->mode & SPI_CPOL) ? 1:0; + cs_high = (spidev->mode & SPI_CS_HIGH) ? 1:0; + max_speed = spidev->max_speed_hz; + np = spidev->dev.of_node; + pr_debug("cs[%x] CPHA[%x] CPOL[%x] CS_HIGH[%x] Max_speed[%d]\n", + cs, cpha, cpol, cs_high, max_speed); + mdss_spi_client = spidev; + + return 0; +} + + +static const struct of_device_id mdss_spi_dt_match[] = { + { .compatible = "qcom,mdss-spi-client" }, + {}, +}; + +static struct spi_driver mdss_spi_client_driver = { + .probe = mdss_spi_client_probe, + .driver = { + .name = "mdss-spi-client", + .owner = THIS_MODULE, + .of_match_table = mdss_spi_dt_match, + }, +}; + +static int __init mdss_spi_init(void) +{ + int ret; + + ret = spi_register_driver(&mdss_spi_client_driver); + + return 0; +} +module_init(mdss_spi_init); + +static void __exit mdss_spi_exit(void) +{ + spi_unregister_driver(&mdss_spi_client_driver); +} +module_exit(mdss_spi_exit); + diff --git a/drivers/video/fbdev/msm/mdss_spi_client.h b/drivers/video/fbdev/msm/mdss_spi_client.h new file mode 100644 index 000000000000..2d15625e2c23 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_spi_client.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MDSS_SPI_CLINET_H__ +#define __MDSS_SPI_CLINET_H__ + +int mdss_spi_tx_command(const void *buf); +int mdss_spi_tx_parameter(const void *buf, size_t len); +int mdss_spi_tx_pixel(const void *buf, size_t len); +int mdss_spi_read_data(u8 reg_addr, u8 *data, u8 len); +#endif /* End of __MDSS_SPI_CLINET_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_spi_panel.c b/drivers/video/fbdev/msm/mdss_spi_panel.c new file mode 100644 index 000000000000..86a1c1c32b4a --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_spi_panel.c @@ -0,0 +1,1713 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mdss.h" +#include "mdss_panel.h" +#include "mdss_spi_panel.h" +#include "mdss_spi_client.h" +#include "mdp3.h" + +DEFINE_LED_TRIGGER(bl_led_trigger); +static int mdss_spi_panel_reset(struct mdss_panel_data *pdata, int enable) +{ + struct spi_panel_data *ctrl_pdata = NULL; + struct mdss_panel_info *pinfo = NULL; + int i, rc = 0; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct spi_panel_data, + panel_data); + + if (!gpio_is_valid(ctrl_pdata->rst_gpio)) { + pr_debug("%s:%d, reset line not configured\n", + __func__, __LINE__); + return rc; + } + + if (!gpio_is_valid(ctrl_pdata->disp_dc_gpio)) { + pr_debug("%s:%d, dc line not configured\n", + __func__, __LINE__); + return rc; + } + + pr_debug("%s: enable = %d\n", __func__, enable); + pinfo = &(ctrl_pdata->panel_data.panel_info); + + if (enable) { + rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n"); + if (rc) { + pr_err("display reset gpio request failed\n"); + return rc; + } + + rc = gpio_request(ctrl_pdata->disp_dc_gpio, "disp_dc"); + if (rc) { + pr_err("display dc gpio request failed\n"); + return rc; + } + + if (!pinfo->cont_splash_enabled) { + for (i = 0; i < pdata->panel_info.rst_seq_len; ++i) { + gpio_direction_output((ctrl_pdata->rst_gpio), + pdata->panel_info.rst_seq[i]); + if (pdata->panel_info.rst_seq[++i]) + usleep_range(pinfo->rst_seq[i] * 1000, + pinfo->rst_seq[i] * 1000); + } + } + + if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) { + pr_debug("%s: Panel Not properly turned OFF\n", + __func__); + ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT; + pr_err("%s: Reset panel done\n", __func__); + } + } else { + gpio_direction_output((ctrl_pdata->rst_gpio), 0); + gpio_free(ctrl_pdata->rst_gpio); + + gpio_direction_output(ctrl_pdata->disp_dc_gpio, 0); + gpio_free(ctrl_pdata->disp_dc_gpio); + } + return rc; +} + + +static int mdss_spi_panel_pinctrl_set_state( + struct spi_panel_data *ctrl_pdata, + bool active) +{ + struct pinctrl_state *pin_state; + int rc = -EFAULT; + + if (IS_ERR_OR_NULL(ctrl_pdata->pin_res.pinctrl)) + return PTR_ERR(ctrl_pdata->pin_res.pinctrl); + + pin_state = active ? ctrl_pdata->pin_res.gpio_state_active + : ctrl_pdata->pin_res.gpio_state_suspend; + if (!IS_ERR_OR_NULL(pin_state)) { + rc = pinctrl_select_state(ctrl_pdata->pin_res.pinctrl, + pin_state); + if (rc) + pr_err("%s: can not set %s pins\n", __func__, + active ? MDSS_PINCTRL_STATE_DEFAULT + : MDSS_PINCTRL_STATE_SLEEP); + } else { + pr_err("%s: invalid '%s' pinstate\n", __func__, + active ? MDSS_PINCTRL_STATE_DEFAULT + : MDSS_PINCTRL_STATE_SLEEP); + } + return rc; +} + + +static int mdss_spi_panel_pinctrl_init(struct platform_device *pdev) +{ + struct spi_panel_data *ctrl_pdata; + + ctrl_pdata = platform_get_drvdata(pdev); + ctrl_pdata->pin_res.pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(ctrl_pdata->pin_res.pinctrl)) { + pr_err("%s: failed to get pinctrl\n", __func__); + return PTR_ERR(ctrl_pdata->pin_res.pinctrl); + } + + ctrl_pdata->pin_res.gpio_state_active + = pinctrl_lookup_state(ctrl_pdata->pin_res.pinctrl, + MDSS_PINCTRL_STATE_DEFAULT); + if (IS_ERR_OR_NULL(ctrl_pdata->pin_res.gpio_state_active)) + pr_warn("%s: can not get default pinstate\n", __func__); + + ctrl_pdata->pin_res.gpio_state_suspend + = pinctrl_lookup_state(ctrl_pdata->pin_res.pinctrl, + MDSS_PINCTRL_STATE_SLEEP); + if (IS_ERR_OR_NULL(ctrl_pdata->pin_res.gpio_state_suspend)) + pr_warn("%s: can not get sleep pinstate\n", __func__); + + return 0; +} + + +static int mdss_spi_panel_power_on(struct mdss_panel_data *pdata) +{ + int ret = 0; + struct spi_panel_data *ctrl_pdata = NULL; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct spi_panel_data, + panel_data); + ret = msm_mdss_enable_vreg( + ctrl_pdata->panel_power_data.vreg_config, + ctrl_pdata->panel_power_data.num_vreg, 1); + if (ret) { + pr_err("%s: failed to enable vregs for %s\n", + __func__, "PANEL_PM"); + } + + /* + * If continuous splash screen feature is enabled, then we need to + * request all the GPIOs that have already been configured in the + * bootloader. This needs to be done irresepective of whether + * the lp11_init flag is set or not. + */ + if (pdata->panel_info.cont_splash_enabled) { + if (mdss_spi_panel_pinctrl_set_state(ctrl_pdata, true)) + pr_debug("reset enable: pinctrl not enabled\n"); + + ret = mdss_spi_panel_reset(pdata, 1); + if (ret) + pr_err("%s: Panel reset failed. rc=%d\n", + __func__, ret); + } + + return ret; +} + + +static int mdss_spi_panel_power_off(struct mdss_panel_data *pdata) +{ + int ret = 0; + struct spi_panel_data *ctrl_pdata = NULL; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + ret = -EINVAL; + goto end; + } + ctrl_pdata = container_of(pdata, struct spi_panel_data, + panel_data); + + ret = mdss_spi_panel_reset(pdata, 0); + if (ret) { + pr_warn("%s: Panel reset failed. rc=%d\n", __func__, ret); + ret = 0; + } + + if (mdss_spi_panel_pinctrl_set_state(ctrl_pdata, false)) + pr_warn("reset disable: pinctrl not enabled\n"); + + ret = msm_mdss_enable_vreg( + ctrl_pdata->panel_power_data.vreg_config, + ctrl_pdata->panel_power_data.num_vreg, 0); + if (ret) + pr_err("%s: failed to disable vregs for %s\n", + __func__, "PANEL_PM"); + +end: + return ret; +} + + +static int mdss_spi_panel_power_ctrl(struct mdss_panel_data *pdata, + int power_state) +{ + int ret; + struct mdss_panel_info *pinfo; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + pinfo = &pdata->panel_info; + pr_debug("%s: cur_power_state=%d req_power_state=%d\n", __func__, + pinfo->panel_power_state, power_state); + + if (pinfo->panel_power_state == power_state) { + pr_debug("%s: no change needed\n", __func__); + return 0; + } + + switch (power_state) { + case MDSS_PANEL_POWER_OFF: + ret = mdss_spi_panel_power_off(pdata); + break; + case MDSS_PANEL_POWER_ON: + ret = mdss_spi_panel_power_on(pdata); + break; + default: + pr_err("%s: unknown panel power state requested (%d)\n", + __func__, power_state); + ret = -EINVAL; + } + + if (!ret) + pinfo->panel_power_state = power_state; + + return ret; +} + +static int mdss_spi_panel_unblank(struct mdss_panel_data *pdata) +{ + int ret = 0; + struct spi_panel_data *ctrl_pdata = NULL; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct spi_panel_data, + panel_data); + + if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) { + ret = ctrl_pdata->on(pdata); + if (ret) { + pr_err("%s: unable to initialize the panel\n", + __func__); + return ret; + } + ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT; + } + + return ret; +} + +static int mdss_spi_panel_blank(struct mdss_panel_data *pdata, int power_state) +{ + int ret = 0; + struct spi_panel_data *ctrl_pdata = NULL; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct spi_panel_data, + panel_data); + + if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) { + ret = ctrl_pdata->off(pdata); + if (ret) { + pr_err("%s: Panel OFF failed\n", __func__); + return ret; + } + ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT; + } + + return ret; +} + + +static int mdss_spi_panel_event_handler(struct mdss_panel_data *pdata, + int event, void *arg) +{ + int rc = 0; + struct spi_panel_data *ctrl_pdata = NULL; + int power_state; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + ctrl_pdata = container_of(pdata, struct spi_panel_data, + panel_data); + + switch (event) { + case MDSS_EVENT_LINK_READY: + rc = mdss_spi_panel_power_ctrl(pdata, MDSS_PANEL_POWER_ON); + if (rc) { + pr_err("%s:Panel power on failed. rc=%d\n", + __func__, rc); + return rc; + } + mdss_spi_panel_pinctrl_set_state(ctrl_pdata, true); + mdss_spi_panel_reset(pdata, 1); + break; + case MDSS_EVENT_UNBLANK: + rc = mdss_spi_panel_unblank(pdata); + break; + case MDSS_EVENT_PANEL_ON: + ctrl_pdata->ctrl_state |= CTRL_STATE_MDP_ACTIVE; + break; + case MDSS_EVENT_BLANK: + power_state = (int) (unsigned long) arg; + break; + case MDSS_EVENT_PANEL_OFF: + power_state = (int) (unsigned long) arg; + ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE; + rc = mdss_spi_panel_blank(pdata, power_state); + rc = mdss_spi_panel_power_ctrl(pdata, power_state); + break; + default: + pr_debug("%s: unhandled event=%d\n", __func__, event); + break; + } + pr_debug("%s-:event=%d, rc=%d\n", __func__, event, rc); + return rc; +} + +int is_spi_panel_continuous_splash_on(struct mdss_panel_data *pdata) +{ + int i = 0, voltage = 0; + struct mdss_vreg *vreg; + int num_vreg; + struct spi_panel_data *ctrl_pdata = NULL; + + ctrl_pdata = container_of(pdata, struct spi_panel_data, + panel_data); + vreg = ctrl_pdata->panel_power_data.vreg_config; + num_vreg = ctrl_pdata->panel_power_data.num_vreg; + + for (i = 0; i < num_vreg; i++) { + if (regulator_is_enabled(vreg[i].vreg) <= 0) + return false; + voltage = regulator_get_voltage(vreg[i].vreg); + if (!(voltage >= vreg[i].min_voltage && + voltage <= vreg[i].max_voltage)) + return false; + } + + return true; +} + +static void enable_spi_panel_te_irq(struct spi_panel_data *ctrl_pdata, + bool enable) +{ + static bool is_enabled = true; + + if (is_enabled == enable) + return; + + if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) { + pr_err("%s:%d,SPI panel TE GPIO not configured\n", + __func__, __LINE__); + return; + } + + if (enable) + enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); + else + disable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); + + is_enabled = enable; +} + +int mdss_spi_panel_kickoff(struct mdss_panel_data *pdata, + char *buf, int len, int dma_stride) +{ + struct spi_panel_data *ctrl_pdata = NULL; + char *tx_buf; + int rc = 0; + int panel_yres; + int panel_xres; + int padding_length = 0; + int actual_stride = 0; + int byte_per_pixel = 0; + int scan_count = 0; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct spi_panel_data, + panel_data); + + tx_buf = ctrl_pdata->tx_buf; + panel_xres = ctrl_pdata->panel_data.panel_info.xres; + panel_yres = ctrl_pdata->panel_data.panel_info.yres; + + byte_per_pixel = ctrl_pdata->panel_data.panel_info.bpp / 8; + actual_stride = panel_xres * byte_per_pixel; + padding_length = dma_stride - actual_stride; + + /* remove the padding and copy to continuous buffer */ + while (scan_count < panel_yres) { + memcpy((tx_buf + scan_count * actual_stride), + (buf + scan_count * (actual_stride + padding_length)), + actual_stride); + scan_count++; + } + + enable_spi_panel_te_irq(ctrl_pdata, true); + + mutex_lock(&ctrl_pdata->spi_tx_mutex); + reinit_completion(&ctrl_pdata->spi_panel_te); + + rc = wait_for_completion_timeout(&ctrl_pdata->spi_panel_te, + msecs_to_jiffies(SPI_PANEL_TE_TIMEOUT)); + + if (rc == 0) + pr_err("wait panel TE time out\n"); + + rc = mdss_spi_tx_pixel(tx_buf, ctrl_pdata->byte_pre_frame); + mutex_unlock(&ctrl_pdata->spi_tx_mutex); + + return rc; +} + +static int mdss_spi_read_panel_data(struct mdss_panel_data *pdata, + u8 reg_addr, u8 *data, u8 len) +{ + int rc = 0; + struct spi_panel_data *ctrl_pdata = NULL; + + ctrl_pdata = container_of(pdata, struct spi_panel_data, + panel_data); + + mutex_lock(&ctrl_pdata->spi_tx_mutex); + gpio_direction_output(ctrl_pdata->disp_dc_gpio, 0); + rc = mdss_spi_read_data(reg_addr, data, len); + gpio_direction_output(ctrl_pdata->disp_dc_gpio, 1); + mutex_unlock(&ctrl_pdata->spi_tx_mutex); + + return rc; +} + +static int mdss_spi_panel_on(struct mdss_panel_data *pdata) +{ + struct spi_panel_data *ctrl = NULL; + struct mdss_panel_info *pinfo; + int i; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + pinfo = &pdata->panel_info; + ctrl = container_of(pdata, struct spi_panel_data, + panel_data); + + for (i = 0; i < ctrl->on_cmds.cmd_cnt; i++) { + /* pull down dc gpio indicate this is command */ + gpio_direction_output(ctrl->disp_dc_gpio, 0); + mdss_spi_tx_command(ctrl->on_cmds.cmds[i].command); + gpio_direction_output((ctrl->disp_dc_gpio), 1); + + if (ctrl->on_cmds.cmds[i].dchdr.dlen > 1) { + mdss_spi_tx_parameter(ctrl->on_cmds.cmds[i].parameter, + ctrl->on_cmds.cmds[i].dchdr.dlen-1); + } + if (ctrl->on_cmds.cmds[i].dchdr.wait != 0) + msleep(ctrl->on_cmds.cmds[i].dchdr.wait); + } + + pinfo->blank_state = MDSS_PANEL_BLANK_UNBLANK; + + pr_debug("%s:-\n", __func__); + + return 0; +} + + +static int mdss_spi_panel_off(struct mdss_panel_data *pdata) +{ + struct spi_panel_data *ctrl = NULL; + struct mdss_panel_info *pinfo; + int i; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + pinfo = &pdata->panel_info; + ctrl = container_of(pdata, struct spi_panel_data, + panel_data); + + for (i = 0; i < ctrl->off_cmds.cmd_cnt; i++) { + /* pull down dc gpio indicate this is command */ + gpio_direction_output(ctrl->disp_dc_gpio, 0); + mdss_spi_tx_command(ctrl->off_cmds.cmds[i].command); + gpio_direction_output((ctrl->disp_dc_gpio), 1); + + if (ctrl->off_cmds.cmds[i].dchdr.dlen > 1) { + mdss_spi_tx_parameter(ctrl->off_cmds.cmds[i].parameter, + ctrl->off_cmds.cmds[i].dchdr.dlen-1); + } + + if (ctrl->off_cmds.cmds[i].dchdr.wait != 0) + msleep(ctrl->off_cmds.cmds[i].dchdr.wait); + } + + pinfo->blank_state = MDSS_PANEL_BLANK_BLANK; + + pr_debug("%s:-\n", __func__); + return 0; +} + +static void mdss_spi_put_dt_vreg_data(struct device *dev, + struct mdss_module_power *module_power) +{ + if (!module_power) { + pr_err("%s: invalid input\n", __func__); + return; + } + + if (module_power->vreg_config) { + devm_kfree(dev, module_power->vreg_config); + module_power->vreg_config = NULL; + } + module_power->num_vreg = 0; +} + + +static int mdss_spi_get_panel_vreg_data(struct device *dev, + struct mdss_module_power *mp) +{ + int i = 0, rc = 0; + u32 tmp = 0; + struct device_node *of_node = NULL, *supply_node = NULL; + struct device_node *supply_root_node = NULL; + + if (!dev || !mp) { + pr_err("%s: invalid input\n", __func__); + rc = -EINVAL; + return rc; + } + + of_node = dev->of_node; + + mp->num_vreg = 0; + + supply_root_node = of_get_child_by_name(of_node, + "qcom,panel-supply-entries"); + + for_each_available_child_of_node(supply_root_node, supply_node) { + mp->num_vreg++; + } + if (mp->num_vreg == 0) { + pr_debug("%s: no vreg\n", __func__); + goto novreg; + } else { + pr_debug("%s: vreg found. count=%d\n", __func__, mp->num_vreg); + } + + mp->vreg_config = kcalloc(mp->num_vreg, sizeof(struct mdss_vreg), + GFP_KERNEL); + + if (mp->vreg_config != NULL) { + for_each_available_child_of_node(supply_root_node, + supply_node) { + const char *st = NULL; + /* vreg-name */ + rc = of_property_read_string(supply_node, + "qcom,supply-name", &st); + if (rc) { + pr_err("%s: error reading name. rc=%d\n", + __func__, rc); + goto error; + } + snprintf(mp->vreg_config[i].vreg_name, + ARRAY_SIZE((mp->vreg_config[i].vreg_name)), + "%s", st); + /* vreg-min-voltage */ + rc = of_property_read_u32(supply_node, + "qcom,supply-min-voltage", &tmp); + if (rc) { + pr_err("%s: error reading min volt. rc=%d\n", + __func__, rc); + goto error; + } + mp->vreg_config[i].min_voltage = tmp; + + /* vreg-max-voltage */ + rc = of_property_read_u32(supply_node, + "qcom,supply-max-voltage", &tmp); + if (rc) { + pr_err("%s: error reading max volt. rc=%d\n", + __func__, rc); + goto error; + } + mp->vreg_config[i].max_voltage = tmp; + + /* enable-load */ + rc = of_property_read_u32(supply_node, + "qcom,supply-enable-load", &tmp); + if (rc) { + pr_err("%s: error read enable load. rc=%d\n", + __func__, rc); + goto error; + } + mp->vreg_config[i].load[DSS_REG_MODE_ENABLE] = tmp; + + /* disable-load */ + rc = of_property_read_u32(supply_node, + "qcom,supply-disable-load", &tmp); + if (rc) { + pr_err("%s: error read disable load. rc=%d\n", + __func__, rc); + goto error; + } + mp->vreg_config[i].load[DSS_REG_MODE_DISABLE] = tmp; + + /* pre-sleep */ + rc = of_property_read_u32(supply_node, + "qcom,supply-pre-on-sleep", &tmp); + if (rc) { + pr_debug("%s: error read pre on value\n", + __func__); + rc = 0; + } else { + mp->vreg_config[i].pre_on_sleep = tmp; + } + + rc = of_property_read_u32(supply_node, + "qcom,supply-pre-off-sleep", &tmp); + if (rc) { + pr_debug("%s: error read pre off value\n", + __func__); + rc = 0; + } else { + mp->vreg_config[i].pre_off_sleep = tmp; + } + + /* post-sleep */ + rc = of_property_read_u32(supply_node, + "qcom,supply-post-on-sleep", &tmp); + if (rc) { + pr_debug("%s: error read post on value\n", + __func__); + rc = 0; + } else { + mp->vreg_config[i].post_on_sleep = tmp; + } + + rc = of_property_read_u32(supply_node, + "qcom,supply-post-off-sleep", &tmp); + if (rc) { + pr_debug("%s: error read post off value\n", + __func__); + rc = 0; + } else { + mp->vreg_config[i].post_off_sleep = tmp; + } + + ++i; + } + } + return rc; +error: + kfree(mp->vreg_config); + mp->vreg_config = NULL; + +novreg: + mp->num_vreg = 0; + + return rc; + +} + +static int mdss_spi_panel_parse_cmds(struct device_node *np, + struct spi_panel_cmds *pcmds, char *cmd_key) +{ + const char *data; + int blen = 0, len; + char *buf, *bp; + struct spi_ctrl_hdr *dchdr; + int i, cnt; + + data = of_get_property(np, cmd_key, &blen); + if (!data) { + pr_err("%s: failed, key=%s\n", __func__, cmd_key); + return -ENOMEM; + } + + buf = kcalloc(blen, sizeof(char), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy(buf, data, blen); + + /* scan dcs commands */ + bp = buf; + len = blen; + cnt = 0; + while (len >= sizeof(*dchdr)) { + dchdr = (struct spi_ctrl_hdr *)bp; + if (dchdr->dlen > len) { + pr_err("%s: dtsi parse error, len=%d", + __func__, dchdr->dlen); + goto exit_free; + } + bp += sizeof(*dchdr); + len -= sizeof(*dchdr); + bp += dchdr->dlen; + len -= dchdr->dlen; + cnt++; + } + + if (len != 0) { + pr_err("%s: dcs_cmd=%x len=%d error", + __func__, buf[0], len); + goto exit_free; + } + + pcmds->cmds = kcalloc(cnt, sizeof(struct spi_cmd_desc), + GFP_KERNEL); + if (!pcmds->cmds) + goto exit_free; + + pcmds->cmd_cnt = cnt; + pcmds->buf = buf; + pcmds->blen = blen; + + bp = buf; + len = blen; + for (i = 0; i < cnt; i++) { + dchdr = (struct spi_ctrl_hdr *)bp; + len -= sizeof(*dchdr); + bp += sizeof(*dchdr); + pcmds->cmds[i].dchdr = *dchdr; + pcmds->cmds[i].command = bp; + pcmds->cmds[i].parameter = bp + sizeof(char); + bp += dchdr->dlen; + len -= dchdr->dlen; + } + + pr_debug("%s: dcs_cmd=%x, len=%d, cmd_cnt=%d\n", __func__, + pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt); + + return 0; + +exit_free: + kfree(buf); + return -ENOMEM; +} +static int mdss_spi_panel_parse_reset_seq(struct device_node *np, + u32 rst_seq[MDSS_SPI_RST_SEQ_LEN], u32 *rst_len, + const char *name) +{ + int num = 0, i; + int rc; + struct property *data; + u32 tmp[MDSS_SPI_RST_SEQ_LEN]; + + *rst_len = 0; + data = of_find_property(np, name, &num); + num /= sizeof(u32); + if (!data || !num || num > MDSS_SPI_RST_SEQ_LEN || num % 2) { + pr_err("%s:%d, error reading %s, length found = %d\n", + __func__, __LINE__, name, num); + } else { + rc = of_property_read_u32_array(np, name, tmp, num); + if (rc) + pr_err("%s:%d, error reading %s, rc = %d\n", + __func__, __LINE__, name, rc); + else { + for (i = 0; i < num; ++i) + rst_seq[i] = tmp[i]; + *rst_len = num; + } + } + return 0; +} + +static bool mdss_send_panel_cmd_for_esd(struct spi_panel_data *ctrl_pdata) +{ + + if (ctrl_pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return false; + } + + mutex_lock(&ctrl_pdata->spi_tx_mutex); + mdss_spi_panel_on(&ctrl_pdata->panel_data); + mutex_unlock(&ctrl_pdata->spi_tx_mutex); + + return true; +} + +static bool mdss_spi_reg_status_check(struct spi_panel_data *ctrl_pdata) +{ + int ret = 0; + int i = 0; + + if (ctrl_pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return false; + } + + pr_debug("%s: Checking Register status\n", __func__); + + ret = mdss_spi_read_panel_data(&ctrl_pdata->panel_data, + ctrl_pdata->panel_status_reg, + ctrl_pdata->act_status_value, + ctrl_pdata->status_cmds_rlen); + if (ret < 0) { + pr_err("%s: Read status register returned error\n", __func__); + } else { + for (i = 0; i < ctrl_pdata->status_cmds_rlen; i++) { + pr_debug("act_value[%d] = %x, exp_value[%d] = %x\n", + i, ctrl_pdata->act_status_value[i], + i, ctrl_pdata->exp_status_value[i]); + if (ctrl_pdata->act_status_value[i] != + ctrl_pdata->exp_status_value[i]) + return false; + } + } + + return true; +} + +static void mdss_spi_parse_esd_params(struct device_node *np, + struct spi_panel_data *ctrl) +{ + u32 tmp; + int rc; + struct property *data; + const char *string; + struct mdss_panel_info *pinfo = &ctrl->panel_data.panel_info; + + pinfo->esd_check_enabled = of_property_read_bool(np, + "qcom,esd-check-enabled"); + + if (!pinfo->esd_check_enabled) + return; + + ctrl->status_mode = SPI_ESD_MAX; + + rc = of_property_read_string(np, + "qcom,mdss-spi-panel-status-check-mode", &string); + if (!rc) { + if (!strcmp(string, "reg_read")) { + ctrl->status_mode = SPI_ESD_REG; + ctrl->check_status = + mdss_spi_reg_status_check; + } else if (!strcmp(string, "send_init_command")) { + ctrl->status_mode = SPI_SEND_PANEL_COMMAND; + ctrl->check_status = + mdss_send_panel_cmd_for_esd; + return; + } else { + pr_err("No valid panel-status-check-mode string\n"); + pinfo->esd_check_enabled = false; + return; + } + } + + rc = of_property_read_u8(np, "qcom,mdss-spi-panel-status-reg", + &ctrl->panel_status_reg); + if (rc) { + pr_warn("%s:%d, Read status reg failed, disable ESD check\n", + __func__, __LINE__); + pinfo->esd_check_enabled = false; + return; + } + + rc = of_property_read_u32(np, "qcom,mdss-spi-panel-status-read-length", + &tmp); + if (rc) { + pr_warn("%s:%d, Read reg length failed, disable ESD check\n", + __func__, __LINE__); + pinfo->esd_check_enabled = false; + return; + } + + ctrl->status_cmds_rlen = (!rc ? tmp : 1); + + ctrl->exp_status_value = kzalloc(sizeof(u8) * + (ctrl->status_cmds_rlen + 1), GFP_KERNEL); + ctrl->act_status_value = kzalloc(sizeof(u8) * + (ctrl->status_cmds_rlen + 1), GFP_KERNEL); + + if (!ctrl->exp_status_value || !ctrl->act_status_value) { + pr_err("%s: Error allocating memory for status buffer\n", + __func__); + pinfo->esd_check_enabled = false; + return; + } + + data = of_find_property(np, "qcom,mdss-spi-panel-status-value", &tmp); + tmp /= sizeof(u8); + if (!data || (tmp != ctrl->status_cmds_rlen)) { + pr_err("%s: Panel status values not found\n", __func__); + pinfo->esd_check_enabled = false; + memset(ctrl->exp_status_value, 0, ctrl->status_cmds_rlen); + } else { + rc = of_property_read_u8_array(np, + "qcom,mdss-spi-panel-status-value", + ctrl->exp_status_value, tmp); + if (rc) { + pr_err("%s: Error reading panel status values\n", + __func__); + pinfo->esd_check_enabled = false; + memset(ctrl->exp_status_value, 0, + ctrl->status_cmds_rlen); + } + } +} + +static int mdss_spi_panel_parse_dt(struct device_node *np, + struct spi_panel_data *ctrl_pdata) +{ + u32 tmp; + int rc; + const char *data; + struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); + + pinfo->cont_splash_enabled = of_property_read_bool(np, + "qcom,cont-splash-enabled"); + + rc = of_property_read_u32(np, "qcom,mdss-spi-panel-width", &tmp); + if (rc) { + pr_err("%s: panel width not specified\n", __func__); + return -EINVAL; + } + pinfo->xres = (!rc ? tmp : 240); + + rc = of_property_read_u32(np, "qcom,mdss-spi-panel-height", &tmp); + if (rc) { + pr_err("%s:panel height not specified\n", __func__); + return -EINVAL; + } + pinfo->yres = (!rc ? tmp : 320); + + rc = of_property_read_u32(np, + "qcom,mdss-pan-physical-width-dimension", &tmp); + pinfo->physical_width = (!rc ? tmp : 0); + rc = of_property_read_u32(np, + "qcom,mdss-pan-physical-height-dimension", &tmp); + pinfo->physical_height = (!rc ? tmp : 0); + rc = of_property_read_u32(np, "qcom,mdss-spi-panel-framerate", &tmp); + pinfo->spi.frame_rate = (!rc ? tmp : 30); + rc = of_property_read_u32(np, "qcom,mdss-spi-h-front-porch", &tmp); + pinfo->lcdc.h_front_porch = (!rc ? tmp : 6); + rc = of_property_read_u32(np, "qcom,mdss-spi-h-back-porch", &tmp); + pinfo->lcdc.h_back_porch = (!rc ? tmp : 6); + rc = of_property_read_u32(np, "qcom,mdss-spi-h-pulse-width", &tmp); + pinfo->lcdc.h_pulse_width = (!rc ? tmp : 2); + rc = of_property_read_u32(np, "qcom,mdss-spi-h-sync-skew", &tmp); + pinfo->lcdc.hsync_skew = (!rc ? tmp : 0); + rc = of_property_read_u32(np, "qcom,mdss-spi-v-back-porch", &tmp); + pinfo->lcdc.v_back_porch = (!rc ? tmp : 6); + rc = of_property_read_u32(np, "qcom,mdss-spi-v-front-porch", &tmp); + pinfo->lcdc.v_front_porch = (!rc ? tmp : 6); + rc = of_property_read_u32(np, "qcom,mdss-spi-v-pulse-width", &tmp); + pinfo->lcdc.v_pulse_width = (!rc ? tmp : 2); + + + rc = of_property_read_u32(np, "qcom,mdss-spi-bpp", &tmp); + if (rc) { + pr_err("%s: bpp not specified\n", __func__); + return -EINVAL; + } + pinfo->bpp = (!rc ? tmp : 16); + + pinfo->pdest = DISPLAY_1; + + ctrl_pdata->bklt_ctrl = SPI_UNKNOWN_CTRL; + data = of_get_property(np, "qcom,mdss-spi-bl-pmic-control-type", NULL); + if (data) { + if (!strcmp(data, "bl_ctrl_wled")) { + led_trigger_register_simple("bkl-trigger", + &bl_led_trigger); + pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", + __func__); + ctrl_pdata->bklt_ctrl = SPI_BL_WLED; + } else if (!strcmp(data, "bl_gpio_pulse")) { + led_trigger_register_simple("gpio-bklt-trigger", + &bl_led_trigger); + pr_debug("%s: SUCCESS-> GPIO PULSE TRIGGER register\n", + __func__); + ctrl_pdata->bklt_ctrl = SPI_BL_WLED; + } else if (!strcmp(data, "bl_ctrl_pwm")) { + ctrl_pdata->bklt_ctrl = SPI_BL_PWM; + ctrl_pdata->pwm_pmi = of_property_read_bool(np, + "qcom,mdss-spi-bl-pwm-pmi"); + rc = of_property_read_u32(np, + "qcom,mdss-spi-bl-pmic-pwm-frequency", &tmp); + if (rc) { + pr_err("%s: Error, panel pwm_period\n", + __func__); + return -EINVAL; + } + ctrl_pdata->pwm_period = tmp; + if (ctrl_pdata->pwm_pmi) { + ctrl_pdata->pwm_bl = of_pwm_get(np, NULL); + if (IS_ERR(ctrl_pdata->pwm_bl)) { + pr_err("%s: Error, pwm device\n", + __func__); + ctrl_pdata->pwm_bl = NULL; + return -EINVAL; + } + } else { + rc = of_property_read_u32(np, + "qcom,mdss-spi-bl-pmic-bank-select", + &tmp); + if (rc) { + pr_err("%s: Error, lpg channel\n", + __func__); + return -EINVAL; + } + ctrl_pdata->pwm_lpg_chan = tmp; + tmp = of_get_named_gpio(np, + "qcom,mdss-spi-pwm-gpio", 0); + ctrl_pdata->pwm_pmic_gpio = tmp; + pr_debug("%s: Configured PWM bklt ctrl\n", + __func__); + } + } + } + rc = of_property_read_u32(np, "qcom,mdss-brightness-max-level", &tmp); + pinfo->brightness_max = (!rc ? tmp : MDSS_MAX_BL_BRIGHTNESS); + rc = of_property_read_u32(np, "qcom,mdss-spi-bl-min-level", &tmp); + pinfo->bl_min = (!rc ? tmp : 0); + rc = of_property_read_u32(np, "qcom,mdss-spi-bl-max-level", &tmp); + pinfo->bl_max = (!rc ? tmp : 255); + ctrl_pdata->bklt_max = pinfo->bl_max; + + + mdss_spi_panel_parse_reset_seq(np, pinfo->rst_seq, + &(pinfo->rst_seq_len), + "qcom,mdss-spi-reset-sequence"); + + mdss_spi_panel_parse_cmds(np, &ctrl_pdata->on_cmds, + "qcom,mdss-spi-on-command"); + + mdss_spi_panel_parse_cmds(np, &ctrl_pdata->off_cmds, + "qcom,mdss-spi-off-command"); + + mdss_spi_parse_esd_params(np, ctrl_pdata); + + + return 0; +} + +static void mdss_spi_panel_pwm_cfg(struct spi_panel_data *ctrl) +{ + if (ctrl->pwm_pmi) + return; + + ctrl->pwm_bl = pwm_request(ctrl->pwm_lpg_chan, "lcd-bklt"); + if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) { + pr_err("%s: Error: lpg_chan=%d pwm request failed", + __func__, ctrl->pwm_lpg_chan); + } + ctrl->pwm_enabled = 0; +} + +static void mdss_spi_panel_bklt_pwm(struct spi_panel_data *ctrl, int level) +{ + int ret; + u32 duty; + u32 period_ns; + + if (ctrl->pwm_bl == NULL) { + pr_err("%s: no PWM\n", __func__); + return; + } + + if (level == 0) { + if (ctrl->pwm_enabled) { + ret = pwm_config_us(ctrl->pwm_bl, level, + ctrl->pwm_period); + if (ret) + pr_err("%s: pwm_config_us() failed err=%d.\n", + __func__, ret); + pwm_disable(ctrl->pwm_bl); + } + ctrl->pwm_enabled = 0; + return; + } + + duty = level * ctrl->pwm_period; + duty /= ctrl->bklt_max; + + pr_debug("%s: bklt_ctrl=%d pwm_period=%d pwm_gpio=%d pwm_lpg_chan=%d\n", + __func__, ctrl->bklt_ctrl, ctrl->pwm_period, + ctrl->pwm_pmic_gpio, ctrl->pwm_lpg_chan); + + if (ctrl->pwm_period >= USEC_PER_SEC) { + ret = pwm_config_us(ctrl->pwm_bl, duty, ctrl->pwm_period); + if (ret) { + pr_err("%s: pwm_config_us() failed err=%d\n", + __func__, ret); + return; + } + } else { + period_ns = ctrl->pwm_period * NSEC_PER_USEC; + ret = pwm_config(ctrl->pwm_bl, + level * period_ns / ctrl->bklt_max, + period_ns); + if (ret) { + pr_err("%s: pwm_config() failed err=%d\n", + __func__, ret); + return; + } + } + + if (!ctrl->pwm_enabled) { + ret = pwm_enable(ctrl->pwm_bl); + if (ret) + pr_err("%s: pwm_enable() failed err=%d\n", __func__, + ret); + ctrl->pwm_enabled = 1; + } +} + +static void mdss_spi_panel_bl_ctrl(struct mdss_panel_data *pdata, + u32 bl_level) +{ + if (bl_level) { + mdp3_res->bklt_level = bl_level; + mdp3_res->bklt_update = true; + } else { + mdss_spi_panel_bl_ctrl_update(pdata, bl_level); + } +} + +#if defined(CONFIG_FB_MSM_MDSS_SPI_PANEL) && defined(CONFIG_SPI_QUP) +void mdss_spi_panel_bl_ctrl_update(struct mdss_panel_data *pdata, + u32 bl_level) +{ + struct spi_panel_data *ctrl_pdata = NULL; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return; + } + + ctrl_pdata = container_of(pdata, struct spi_panel_data, + panel_data); + + if ((bl_level < pdata->panel_info.bl_min) && (bl_level != 0)) + bl_level = pdata->panel_info.bl_min; + + switch (ctrl_pdata->bklt_ctrl) { + case SPI_BL_WLED: + led_trigger_event(bl_led_trigger, bl_level); + break; + case SPI_BL_PWM: + mdss_spi_panel_bklt_pwm(ctrl_pdata, bl_level); + break; + default: + pr_err("%s: Unknown bl_ctrl configuration %d\n", + __func__, ctrl_pdata->bklt_ctrl); + break; + } +} +#endif + +static int mdss_spi_panel_init(struct device_node *node, + struct spi_panel_data *ctrl_pdata, + bool cmd_cfg_cont_splash) +{ + int rc = 0; + static const char *panel_name; + struct mdss_panel_info *pinfo; + + if (!node || !ctrl_pdata) { + pr_err("%s: Invalid arguments\n", __func__); + return -ENODEV; + } + + pinfo = &ctrl_pdata->panel_data.panel_info; + + pr_debug("%s:%d\n", __func__, __LINE__); + pinfo->panel_name[0] = '\0'; + panel_name = of_get_property(node, "qcom,mdss-spi-panel-name", NULL); + if (!panel_name) { + pr_info("%s:%d, Panel name not specified\n", + __func__, __LINE__); + } else { + pr_debug("%s: Panel Name = %s\n", __func__, panel_name); + strlcpy(&pinfo->panel_name[0], panel_name, MDSS_MAX_PANEL_LEN); + } + rc = mdss_spi_panel_parse_dt(node, ctrl_pdata); + if (rc) { + pr_err("%s:%d panel dt parse failed\n", __func__, __LINE__); + return rc; + } + + ctrl_pdata->byte_pre_frame = pinfo->xres * pinfo->yres * pinfo->bpp/8; + + ctrl_pdata->tx_buf = kmalloc(ctrl_pdata->byte_pre_frame, GFP_KERNEL); + + if (!cmd_cfg_cont_splash) + pinfo->cont_splash_enabled = false; + + pr_info("%s: Continuous splash %s\n", __func__, + pinfo->cont_splash_enabled ? "enabled" : "disabled"); + + pinfo->dynamic_switch_pending = false; + pinfo->is_lpm_mode = false; + pinfo->esd_rdy = false; + + ctrl_pdata->on = mdss_spi_panel_on; + ctrl_pdata->off = mdss_spi_panel_off; + ctrl_pdata->panel_data.set_backlight = mdss_spi_panel_bl_ctrl; + + return 0; +} + +static int mdss_spi_get_panel_cfg(char *panel_cfg, + struct spi_panel_data *ctrl_pdata) +{ + int rc; + struct mdss_panel_cfg *pan_cfg = NULL; + + if (!ctrl_pdata) + return MDSS_PANEL_INTF_INVALID; + + pan_cfg = ctrl_pdata->mdss_util->panel_intf_type(MDSS_PANEL_INTF_SPI); + if (IS_ERR(pan_cfg)) { + return PTR_ERR(pan_cfg); + } else if (!pan_cfg) { + panel_cfg[0] = 0; + return 0; + } + + pr_debug("%s:%d: cfg:[%s]\n", __func__, __LINE__, + pan_cfg->arg_cfg); + ctrl_pdata->panel_data.panel_info.is_prim_panel = true; + rc = strlcpy(panel_cfg, pan_cfg->arg_cfg, + sizeof(pan_cfg->arg_cfg)); + return rc; +} + +static int mdss_spi_panel_regulator_init(struct platform_device *pdev) +{ + int rc = 0; + + struct spi_panel_data *ctrl_pdata = NULL; + + if (!pdev) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + ctrl_pdata = platform_get_drvdata(pdev); + if (!ctrl_pdata) { + pr_err("%s: invalid driver data\n", __func__); + return -EINVAL; + } + + rc = msm_mdss_config_vreg(&pdev->dev, + ctrl_pdata->panel_power_data.vreg_config, + ctrl_pdata->panel_power_data.num_vreg, 1); + if (rc) + pr_err("%s: failed to init vregs for %s\n", + __func__, "PANEL_PM"); + + return rc; + +} + +static irqreturn_t spi_panel_te_handler(int irq, void *data) +{ + struct spi_panel_data *ctrl_pdata = (struct spi_panel_data *)data; + static int count = 2; + + if (!ctrl_pdata) { + pr_err("%s: SPI display not available\n", __func__); + return IRQ_HANDLED; + } + complete(&ctrl_pdata->spi_panel_te); + + if (ctrl_pdata->vsync_client.handler && !(--count)) { + ctrl_pdata->vsync_client.handler(ctrl_pdata->vsync_client.arg); + count = 2; + } + + return IRQ_HANDLED; +} + +void mdp3_spi_vsync_enable(struct mdss_panel_data *pdata, + struct mdp3_notification *vsync_client) +{ + int updated = 0; + struct spi_panel_data *ctrl_pdata = NULL; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return; + } + + ctrl_pdata = container_of(pdata, struct spi_panel_data, + panel_data); + + if (vsync_client) { + if (ctrl_pdata->vsync_client.handler != vsync_client->handler) { + ctrl_pdata->vsync_client = *vsync_client; + updated = 1; + } + } else { + if (ctrl_pdata->vsync_client.handler) { + ctrl_pdata->vsync_client.handler = NULL; + ctrl_pdata->vsync_client.arg = NULL; + updated = 1; + } + } + + if (updated) { + if (vsync_client && vsync_client->handler) + enable_spi_panel_te_irq(ctrl_pdata, true); + else + enable_spi_panel_te_irq(ctrl_pdata, false); + } +} + +static struct device_node *mdss_spi_pref_prim_panel( + struct platform_device *pdev) +{ + struct device_node *spi_pan_node = NULL; + + pr_debug("%s:%d: Select primary panel from dt\n", + __func__, __LINE__); + spi_pan_node = of_parse_phandle(pdev->dev.of_node, + "qcom,spi-pref-prim-pan", 0); + if (!spi_pan_node) + pr_err("%s:can't find panel phandle\n", __func__); + + return spi_pan_node; +} + +static int spi_panel_device_register(struct device_node *pan_node, + struct spi_panel_data *ctrl_pdata) +{ + int rc; + struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); + struct device_node *spi_ctrl_np = NULL; + struct platform_device *ctrl_pdev = NULL; + + pinfo->type = SPI_PANEL; + + spi_ctrl_np = of_parse_phandle(pan_node, + "qcom,mdss-spi-panel-controller", 0); + if (!spi_ctrl_np) { + pr_err("%s: SPI controller node not initialized\n", __func__); + return -EPROBE_DEFER; + } + + ctrl_pdev = of_find_device_by_node(spi_ctrl_np); + if (!ctrl_pdev) { + of_node_put(spi_ctrl_np); + pr_err("%s: SPI controller node not find\n", __func__); + return -EPROBE_DEFER; + } + + rc = mdss_spi_panel_regulator_init(ctrl_pdev); + if (rc) { + pr_err("%s: failed to init regulator, rc=%d\n", + __func__, rc); + return rc; + } + + pinfo->panel_max_fps = mdss_panel_get_framerate(pinfo, + FPS_RESOLUTION_HZ); + pinfo->panel_max_vtotal = mdss_panel_get_vtotal(pinfo); + + ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, + "qcom,platform-te-gpio", 0); + if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) + pr_err("%s:%d, TE gpio not specified\n", + __func__, __LINE__); + + ctrl_pdata->disp_dc_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, + "qcom,platform-spi-dc-gpio", 0); + if (!gpio_is_valid(ctrl_pdata->disp_dc_gpio)) + pr_err("%s:%d, SPI DC gpio not specified\n", + __func__, __LINE__); + + ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, + "qcom,platform-reset-gpio", 0); + if (!gpio_is_valid(ctrl_pdata->rst_gpio)) + pr_err("%s:%d, reset gpio not specified\n", + __func__, __LINE__); + + ctrl_pdata->panel_data.event_handler = mdss_spi_panel_event_handler; + + if (ctrl_pdata->bklt_ctrl == SPI_BL_PWM) + mdss_spi_panel_pwm_cfg(ctrl_pdata); + + ctrl_pdata->ctrl_state = CTRL_STATE_UNKNOWN; + + if (pinfo->cont_splash_enabled) { + rc = mdss_spi_panel_power_ctrl(&(ctrl_pdata->panel_data), + MDSS_PANEL_POWER_ON); + if (rc) { + pr_err("%s: Panel power on failed\n", __func__); + return rc; + } + if (ctrl_pdata->bklt_ctrl == SPI_BL_PWM) + ctrl_pdata->pwm_enabled = 1; + pinfo->blank_state = MDSS_PANEL_BLANK_UNBLANK; + ctrl_pdata->ctrl_state |= + (CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE); + } else { + pinfo->panel_power_state = MDSS_PANEL_POWER_OFF; + } + + rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data)); + if (rc) { + pr_err("%s: unable to register SPI panel\n", __func__); + return rc; + } + + pr_debug("%s: Panel data initialized\n", __func__); + return 0; +} + + +/** + * mdss_spi_find_panel_of_node(): find device node of spi panel + * @pdev: platform_device of the spi ctrl node + * @panel_cfg: string containing intf specific config data + * + * Function finds the panel device node using the interface + * specific configuration data. This configuration data is + * could be derived from the result of bootloader's GCDB + * panel detection mechanism. If such config data doesn't + * exist then this panel returns the default panel configured + * in the device tree. + * + * returns pointer to panel node on success, NULL on error. + */ +static struct device_node *mdss_spi_find_panel_of_node( + struct platform_device *pdev, char *panel_cfg) +{ + int len, i; + int ctrl_id = pdev->id - 1; + char panel_name[MDSS_MAX_PANEL_LEN] = ""; + char ctrl_id_stream[3] = "0:"; + char *stream = NULL, *pan = NULL; + struct device_node *spi_pan_node = NULL, *mdss_node = NULL; + + len = strlen(panel_cfg); + if (!len) { + /* no panel cfg chg, parse dt */ + pr_err("%s:%d: no cmd line cfg present\n", + __func__, __LINE__); + goto end; + } else { + if (ctrl_id == 1) + strlcpy(ctrl_id_stream, "1:", 3); + + stream = strnstr(panel_cfg, ctrl_id_stream, len); + if (!stream) { + pr_err("controller config is not present\n"); + goto end; + } + stream += 2; + + pan = strnchr(stream, strlen(stream), ':'); + if (!pan) { + strlcpy(panel_name, stream, MDSS_MAX_PANEL_LEN); + } else { + for (i = 0; (stream + i) < pan; i++) + panel_name[i] = *(stream + i); + panel_name[i] = 0; + } + + pr_debug("%s:%d:%s:%s\n", __func__, __LINE__, + panel_cfg, panel_name); + + mdss_node = of_parse_phandle(pdev->dev.of_node, + "qcom,mdss-mdp", 0); + if (!mdss_node) { + pr_err("%s: %d: mdss_node null\n", + __func__, __LINE__); + return NULL; + } + + spi_pan_node = of_find_node_by_name(mdss_node, + panel_name); + if (!spi_pan_node) { + pr_err("%s: invalid pan node, selecting prim panel\n", + __func__); + goto end; + } + return spi_pan_node; + } +end: + if (strcmp(panel_name, NONE_PANEL)) + spi_pan_node = mdss_spi_pref_prim_panel(pdev); + of_node_put(mdss_node); + return spi_pan_node; +} + + +static int mdss_spi_panel_probe(struct platform_device *pdev) +{ + int rc = 0; + struct spi_panel_data *ctrl_pdata; + struct mdss_panel_cfg *pan_cfg = NULL; + struct device_node *spi_pan_node = NULL; + bool cmd_cfg_cont_splash = true; + char panel_cfg[MDSS_MAX_PANEL_LEN]; + struct mdss_util_intf *util; + const char *ctrl_name; + + util = mdss_get_util_intf(); + if (util == NULL) { + pr_err("Failed to get mdss utility functions\n"); + return -ENODEV; + } + + if (!util->mdp_probe_done) { + pr_err("%s: MDP not probed yet\n", __func__); + return -EPROBE_DEFER; + } + + if (!pdev->dev.of_node) { + pr_err("SPI driver only supports device tree probe\n"); + return -ENOTSUPP; + } + + pan_cfg = util->panel_intf_type(MDSS_PANEL_INTF_DSI); + if (IS_ERR(pan_cfg)) { + pr_err("%s: return MDSS_PANEL_INTF_DSI\n", __func__); + return PTR_ERR(pan_cfg); + } else if (pan_cfg) { + pr_err("%s: DSI is primary\n", __func__); + return -ENODEV; + } + + ctrl_pdata = platform_get_drvdata(pdev); + if (!ctrl_pdata) { + ctrl_pdata = devm_kzalloc(&pdev->dev, + sizeof(struct spi_panel_data), + GFP_KERNEL); + if (!ctrl_pdata) { + pr_err("%s: FAILED: cannot alloc spi panel\n", + __func__); + rc = -ENOMEM; + goto error_no_mem; + } + platform_set_drvdata(pdev, ctrl_pdata); + } + + ctrl_pdata->mdss_util = util; + + ctrl_name = of_get_property(pdev->dev.of_node, "label", NULL); + if (!ctrl_name) + pr_info("%s:%d, Ctrl name not specified\n", + __func__, __LINE__); + else + pr_debug("%s: Ctrl name = %s\n", + __func__, ctrl_name); + + + rc = of_platform_populate(pdev->dev.of_node, + NULL, NULL, &pdev->dev); + if (rc) { + dev_err(&pdev->dev, + "%s: failed to add child nodes, rc=%d\n", + __func__, rc); + goto error_no_mem; + } + + rc = mdss_spi_panel_pinctrl_init(pdev); + if (rc) + pr_warn("%s: failed to get pin resources\n", __func__); + + rc = mdss_spi_get_panel_vreg_data(&pdev->dev, + &ctrl_pdata->panel_power_data); + if (rc) { + dev_err(&pdev->dev, + "%s: failed to get panel vreg data, rc=%d\n", + __func__, rc); + goto error_vreg; + } + + /* SPI panels can be different between controllers */ + rc = mdss_spi_get_panel_cfg(panel_cfg, ctrl_pdata); + if (!rc) + /* spi panel cfg not present */ + pr_warn("%s:%d:spi specific cfg not present\n", + __func__, __LINE__); + + /* find panel device node */ + spi_pan_node = mdss_spi_find_panel_of_node(pdev, panel_cfg); + if (!spi_pan_node) { + pr_err("%s: can't find panel node %s\n", __func__, panel_cfg); + goto error_pan_node; + } + + cmd_cfg_cont_splash = true; + + rc = mdss_spi_panel_init(spi_pan_node, ctrl_pdata, cmd_cfg_cont_splash); + if (rc) { + pr_err("%s: spi panel init failed\n", __func__); + goto error_pan_node; + } + + rc = spi_panel_device_register(spi_pan_node, ctrl_pdata); + if (rc) { + pr_err("%s: spi panel dev reg failed\n", __func__); + goto error_pan_node; + } + + ctrl_pdata->panel_data.event_handler = mdss_spi_panel_event_handler; + + + init_completion(&ctrl_pdata->spi_panel_te); + mutex_init(&ctrl_pdata->spi_tx_mutex); + + rc = devm_request_irq(&pdev->dev, + gpio_to_irq(ctrl_pdata->disp_te_gpio), + spi_panel_te_handler, IRQF_TRIGGER_RISING, + "TE_GPIO", ctrl_pdata); + if (rc) { + pr_err("TE request_irq failed.\n"); + return rc; + } + + pr_debug("%s: spi panel initialized\n", __func__); + return 0; + +error_pan_node: + of_node_put(spi_pan_node); +error_vreg: + mdss_spi_put_dt_vreg_data(&pdev->dev, + &ctrl_pdata->panel_power_data); +error_no_mem: + devm_kfree(&pdev->dev, ctrl_pdata); + return rc; +} + + +static const struct of_device_id mdss_spi_panel_match[] = { + { .compatible = "qcom,mdss-spi-display" }, + {}, +}; + +static struct platform_driver this_driver = { + .probe = mdss_spi_panel_probe, + .driver = { + .name = "spi_panel", + .owner = THIS_MODULE, + .of_match_table = mdss_spi_panel_match, + }, +}; + +static int __init mdss_spi_display_init(void) +{ + int ret; + + ret = platform_driver_register(&this_driver); + return 0; +} +module_init(mdss_spi_display_init); + +MODULE_DEVICE_TABLE(of, mdss_spi_panel_match); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/fbdev/msm/mdss_spi_panel.h b/drivers/video/fbdev/msm/mdss_spi_panel.h new file mode 100644 index 000000000000..80b7ea894ce3 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_spi_panel.h @@ -0,0 +1,148 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __MDSS_SPI_PANEL_H__ +#define __MDSS_SPI_PANEL_H__ + +#if defined(CONFIG_FB_MSM_MDSS_SPI_PANEL) && defined(CONFIG_SPI_QUP) +#include +#include +#include +#include +#include + +#include "mdss_panel.h" +#include "mdp3_dma.h" + +#define MDSS_MAX_BL_BRIGHTNESS 255 + +#define MDSS_SPI_RST_SEQ_LEN 10 + +#define NONE_PANEL "none" + +#define CTRL_STATE_UNKNOWN 0x00 +#define CTRL_STATE_PANEL_INIT BIT(0) +#define CTRL_STATE_MDP_ACTIVE BIT(1) + +#define MDSS_PINCTRL_STATE_DEFAULT "mdss_default" +#define MDSS_PINCTRL_STATE_SLEEP "mdss_sleep" +#define SPI_PANEL_TE_TIMEOUT 400 + +enum spi_panel_data_type { + panel_cmd, + panel_parameter, + panel_pixel, + UNKNOWN_FORMAT, +}; + +enum spi_panel_bl_ctrl { + SPI_BL_PWM, + SPI_BL_WLED, + SPI_BL_DCS_CMD, + SPI_UNKNOWN_CTRL, +}; + +struct spi_pinctrl_res { + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; +}; +#define SPI_PANEL_DST_FORMAT_RGB565 0 + +struct spi_ctrl_hdr { + char wait; /* ms */ + char dlen; /* 8 bits */ +}; + +struct spi_cmd_desc { + struct spi_ctrl_hdr dchdr; + char *command; + char *parameter; +}; + +struct spi_panel_cmds { + char *buf; + int blen; + struct spi_cmd_desc *cmds; + int cmd_cnt; +}; + +enum spi_panel_status_mode { + SPI_ESD_REG, + SPI_SEND_PANEL_COMMAND, + SPI_ESD_MAX, +}; + + +struct spi_panel_data { + struct mdss_panel_data panel_data; + struct mdss_util_intf *mdss_util; + struct spi_pinctrl_res pin_res; + struct mdss_module_power panel_power_data; + struct completion spi_panel_te; + struct mdp3_notification vsync_client; + unsigned int vsync_status; + int byte_pre_frame; + char *tx_buf; + u8 ctrl_state; + int disp_te_gpio; + int rst_gpio; + int disp_dc_gpio; /* command or data */ + struct spi_panel_cmds on_cmds; + struct spi_panel_cmds off_cmds; + bool (*check_status)(struct spi_panel_data *pdata); + int (*on)(struct mdss_panel_data *pdata); + int (*off)(struct mdss_panel_data *pdata); + struct mutex spi_tx_mutex; + struct pwm_device *pwm_bl; + int bklt_ctrl; /* backlight ctrl */ + bool pwm_pmi; + int pwm_period; + int pwm_pmic_gpio; + int pwm_lpg_chan; + int pwm_enabled; + int bklt_max; + int status_mode; + u32 status_cmds_rlen; + u8 panel_status_reg; + u8 *exp_status_value; + u8 *act_status_value; + unsigned char *return_buf; +}; + +int mdss_spi_panel_kickoff(struct mdss_panel_data *pdata, + char *buf, int len, int stride); +int is_spi_panel_continuous_splash_on(struct mdss_panel_data *pdata); +void mdp3_spi_vsync_enable(struct mdss_panel_data *pdata, + struct mdp3_notification *vsync_client); +void mdp3_check_spi_panel_status(struct work_struct *work, + uint32_t interval); + +#else +static inline int mdss_spi_panel_kickoff(struct mdss_panel_data *pdata, + char *buf, int len, int stride){ + return 0; +} +static inline int is_spi_panel_continuous_splash_on( + struct mdss_panel_data *pdata) +{ + return 0; +} +static inline int mdp3_spi_vsync_enable(struct mdss_panel_data *pdata, + struct mdp3_notification *vsync_client){ + return 0; +} + +#endif/* End of CONFIG_FB_MSM_MDSS_SPI_PANEL && ONFIG_SPI_QUP */ + +#endif /* End of __MDSS_SPI_PANEL_H__ */ -- GitLab From 2d09915ba636213c9a937a84650ebc5704e29f6f Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 14 Jun 2018 21:31:28 +0800 Subject: [PATCH 829/855] coresight: tmc: Avoid reading tmc node before it being enabled It is possible that the mem_size of tmc_etr will be allocated failed while enabling. And if we read tmc-etr after this, system reset will happen. So don't read tmc before it being enabled. CRs-Fixed: 2243995 Change-Id: I6a0be80834f7d4c1c7464f9684228e5b35f31a77 Signed-off-by: Mao Jinlong --- .../hwtracing/coresight/coresight-tmc-etr.c | 1 - drivers/hwtracing/coresight/coresight-tmc.c | 3 +- drivers/hwtracing/coresight/coresight.c | 92 ++++++++++++------- 3 files changed, 60 insertions(+), 36 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 9d2ab016de70..e369ea1680ce 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -845,7 +845,6 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) } drvdata->enable = true; - drvdata->sticky_enable = true; out: spin_unlock_irqrestore(&drvdata->spinlock, flags); if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 287f9012b390..8aed31a49a5f 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -139,7 +139,6 @@ static void __tmc_reg_dump(struct tmc_drvdata *drvdata) void tmc_enable_hw(struct tmc_drvdata *drvdata) { drvdata->enable = true; - drvdata->sticky_enable = true; writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL); if (drvdata->force_reg_dump) __tmc_reg_dump(drvdata); @@ -155,7 +154,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) { int ret = 0; - if (!drvdata->sticky_enable) + if (!drvdata->enable) return -EPERM; switch (drvdata->config_type) { diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 85a16b13c4e1..21c74ec5abb0 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012, 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -181,8 +181,10 @@ static int coresight_enable_link(struct coresight_device *csdev, if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { if (link_ops(csdev)->enable) { ret = link_ops(csdev)->enable(csdev, inport, outport); - if (ret) + if (ret) { + atomic_dec(&csdev->refcnt[refport]); return ret; + } } } @@ -263,42 +265,66 @@ static void coresight_disable_source(struct coresight_device *csdev) } } -void coresight_disable_path(struct list_head *path) +static void coresigh_disable_list_node(struct list_head *path, + struct coresight_node *nd) { u32 type; - struct coresight_node *nd; struct coresight_device *csdev, *parent, *child; - list_for_each_entry(nd, path, link) { - csdev = nd->csdev; - type = csdev->type; + csdev = nd->csdev; + type = csdev->type; - /* - * ETF devices are tricky... They can be a link or a sink, - * depending on how they are configured. If an ETF has been - * "activated" it will be configured as a sink, otherwise - * go ahead with the link configuration. - */ - if (type == CORESIGHT_DEV_TYPE_LINKSINK) - type = (csdev == coresight_get_sink(path)) ? - CORESIGHT_DEV_TYPE_SINK : - CORESIGHT_DEV_TYPE_LINK; + /* + * ETF devices are tricky... They can be a link or a sink, + * depending on how they are configured. If an ETF has been + * "activated" it will be configured as a sink, otherwise + * go ahead with the link configuration. + */ + if (type == CORESIGHT_DEV_TYPE_LINKSINK) + type = (csdev == coresight_get_sink(path)) ? + CORESIGHT_DEV_TYPE_SINK : + CORESIGHT_DEV_TYPE_LINK; + + switch (type) { + case CORESIGHT_DEV_TYPE_SINK: + coresight_disable_sink(csdev); + break; + case CORESIGHT_DEV_TYPE_SOURCE: + /* sources are disabled from either sysFS or Perf */ + break; + case CORESIGHT_DEV_TYPE_LINK: + parent = list_prev_entry(nd, link)->csdev; + child = list_next_entry(nd, link)->csdev; + coresight_disable_link(csdev, parent, child); + break; + default: + break; + } +} - switch (type) { - case CORESIGHT_DEV_TYPE_SINK: - coresight_disable_sink(csdev); - break; - case CORESIGHT_DEV_TYPE_SOURCE: - /* sources are disabled from either sysFS or Perf */ - break; - case CORESIGHT_DEV_TYPE_LINK: - parent = list_prev_entry(nd, link)->csdev; - child = list_next_entry(nd, link)->csdev; - coresight_disable_link(csdev, parent, child); - break; - default: - break; - } +/** + * During enabling path, if it is failed, then only those enabled + * devices need to be disabled. This function is to disable devices + * which is enabled before the failed device. + * + * @path the head of the list + * @nd the failed device node + */ +static void coresight_disable_previous_devs(struct list_head *path, + struct coresight_node *nd) +{ + + list_for_each_entry_continue(nd, path, link) { + coresigh_disable_list_node(path, nd); + } +} + +void coresight_disable_path(struct list_head *path) +{ + struct coresight_node *nd; + + list_for_each_entry(nd, path, link) { + coresigh_disable_list_node(path, nd); } } @@ -349,7 +375,7 @@ int coresight_enable_path(struct list_head *path, u32 mode) out: return ret; err: - coresight_disable_path(path); + coresight_disable_previous_devs(path, nd); goto out; } -- GitLab From 288519925e57938cbad0f8a6bdbc4d25772a9ce8 Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Wed, 13 Jun 2018 23:43:55 +0530 Subject: [PATCH 830/855] defconfig: Enable defconfig to support USB Enable defconfigs that are needed to support USB. In device mode only ADB and DIAG are enabled. Host mode supports HID, Audio, Storage and basic USB to ethernet devices. Change-Id: I2dd84e99ee87f207e58343c8056d7c7361c4fc8b Signed-off-by: Sriharsha Allenki --- .../arm/configs/msm8953-batcam-perf_defconfig | 39 +++++++++++++++++++ arch/arm/configs/msm8953-batcam_defconfig | 39 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/arch/arm/configs/msm8953-batcam-perf_defconfig b/arch/arm/configs/msm8953-batcam-perf_defconfig index 5b886a825e5a..a6fe9b088fe0 100644 --- a/arch/arm/configs/msm8953-batcam-perf_defconfig +++ b/arch/arm/configs/msm8953-batcam-perf_defconfig @@ -79,9 +79,11 @@ CONFIG_INET=y CONFIG_DMA_CMA=y # CONFIG_OF_KOBJ is not set CONFIG_QSEECOM=y +CONFIG_SCSI=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_NETDEVICES=y +CONFIG_USB_USBNET=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y @@ -147,8 +149,43 @@ CONFIG_FB=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y CONFIG_SND_SOC=y CONFIG_UHID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_SERIAL=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_MMC=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y @@ -189,6 +226,7 @@ CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_COINCELL=y CONFIG_QPNP_REVID=y +CONFIG_USB_BAM=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_MAILBOX=y CONFIG_ARM_SMMU=y @@ -225,6 +263,7 @@ CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_SPDM_SCM=y CONFIG_DEVFREQ_SPDM=y +CONFIG_EXTCON_USB_GPIO=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_PWM_QTI_LPG=y diff --git a/arch/arm/configs/msm8953-batcam_defconfig b/arch/arm/configs/msm8953-batcam_defconfig index dc6688c79b6b..cd86b016ce7a 100644 --- a/arch/arm/configs/msm8953-batcam_defconfig +++ b/arch/arm/configs/msm8953-batcam_defconfig @@ -78,9 +78,11 @@ CONFIG_INET=y CONFIG_DMA_CMA=y # CONFIG_OF_KOBJ is not set CONFIG_QSEECOM=y +CONFIG_SCSI=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_NETDEVICES=y +CONFIG_USB_USBNET=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y @@ -148,8 +150,43 @@ CONFIG_FB=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y CONFIG_SND_SOC=y CONFIG_UHID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_SERIAL=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_MMC=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y @@ -190,6 +227,7 @@ CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_COINCELL=y CONFIG_QPNP_REVID=y +CONFIG_USB_BAM=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_MAILBOX=y CONFIG_ARM_SMMU=y @@ -226,6 +264,7 @@ CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_SPDM_SCM=y CONFIG_DEVFREQ_SPDM=y +CONFIG_EXTCON_USB_GPIO=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_PWM_QTI_LPG=y -- GitLab From 57439e13fb01ebe2690034eea068e60dc530ac99 Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Fri, 1 Jun 2018 15:31:32 -0700 Subject: [PATCH 831/855] msm: ep_pcie: Initialize MHI MMIO once Initialize MHI MMIO during device initialization the first time. For cases where the link shuts down without device bootup the MMIO is not required to be reinitialized. If the MMIO is reinitialized without device bootup it causes the host and device to go out of sync. Change-Id: I7188d3c6e9e79ff93c4b0ce0207cee5161ae519b Signed-off-by: Siddartha Mohanadoss --- drivers/platform/msm/ep_pcie/ep_pcie_com.h | 2 +- drivers/platform/msm/ep_pcie/ep_pcie_core.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h index 33e0314f8833..36d49e4eb4d3 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h @@ -359,7 +359,7 @@ struct ep_pcie_dev_t { ulong global_irq_counter; bool dump_conf; - + bool config_mmio_init; bool enumerated; enum ep_pcie_link_status link_status; bool perst_deast; diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index 4558530251d2..0ada0bffa50f 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -503,6 +503,13 @@ static void ep_pcie_config_mmio(struct ep_pcie_dev_t *dev) "Initial version of MMIO is:0x%x\n", readl_relaxed(dev->mmio + PCIE20_MHIVER)); + if (dev->config_mmio_init) { + EP_PCIE_DBG(dev, + "PCIe V%d: MMIO already initialized, return\n", + dev->rev); + return; + } + ep_pcie_write_reg(dev->mmio, PCIE20_MHICFG, 0x02800880); ep_pcie_write_reg(dev->mmio, PCIE20_BHI_EXECENV, 0x2); ep_pcie_write_reg(dev->mmio, PCIE20_MHICTRL, 0x0); @@ -511,6 +518,8 @@ static void ep_pcie_config_mmio(struct ep_pcie_dev_t *dev) ep_pcie_write_reg(dev->mmio, PCIE20_BHI_VERSION_LOWER, 0x2); ep_pcie_write_reg(dev->mmio, PCIE20_BHI_VERSION_UPPER, 0x1); ep_pcie_write_reg(dev->mmio, PCIE20_BHI_INTVEC, 0xffffffff); + + dev->config_mmio_init = true; } static void ep_pcie_core_init(struct ep_pcie_dev_t *dev, bool configured) -- GitLab From 01efda810c9818b0aebde84ded404fdb70d4a3e9 Mon Sep 17 00:00:00 2001 From: Sachin Grover Date: Thu, 14 Jun 2018 11:19:34 +0530 Subject: [PATCH 832/855] Revert "defconfig: Enable PAN emulation" This reverts commit 8d327f8f95831238326233e4d2da9fbf9d5ac9b1. Change-Id: I0dbe6f06b01f7121cdb61339f6021f5c128e62a2 Signed-off-by: Sachin Grover --- arch/arm64/configs/msm8953-perf_defconfig | 1 - arch/arm64/configs/msm8953_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig index bb9817938aed..92e369e4f488 100644 --- a/arch/arm64/configs/msm8953-perf_defconfig +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -73,7 +73,6 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y -CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index fb1c316ce3fb..fc1eb458ffc8 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -76,7 +76,6 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y -CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y -- GitLab From 848f68e03280f5bdf83546f34f750e42c0457d7b Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Tue, 17 Apr 2018 23:45:13 -0700 Subject: [PATCH 833/855] power_supply: Add enums for POWER_SUPPLY_PROP_PD_ACTIVE Add enum definitions to use with POWER_SUPPLY_PROP_PD_ACTIVE to distinguish between whether a charger supports PD or not, and if PD, whether it also supports PPS. Change-Id: I4965292024cc48e13656f5bb30fa900af4174bc6 Signed-off-by: Jack Pham --- include/linux/power_supply.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 78c2a9ff4e84..63707e3d4193 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -125,6 +125,12 @@ enum { POWER_SUPPLY_PL_NON_STACKED_BATFET, }; +enum { + POWER_SUPPLY_PD_INACTIVE = 0, + POWER_SUPPLY_PD_ACTIVE, + POWER_SUPPLY_PD_PPS_ACTIVE, +}; + enum power_supply_property { /* Properties of type `int' */ POWER_SUPPLY_PROP_STATUS = 0, -- GitLab From 9660be9be7e263bb60e5d92a261d014959f5f02f Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Tue, 3 Apr 2018 16:06:40 -0700 Subject: [PATCH 834/855] usb: pd: notify charger if source is PPS capable The charger driver may need to perform different charging behavior depending on whether the source is PPS capable or not. This can be determined when evaluating the source capabilities. If PPS capable, set PD_ACTIVE to 2. Use the new enum definitions POWER_SUPPLY_PD_ACTIVE, POWER_SUPPLY_PD_PPS_ACTIVE and POWER_SUPPLY_PD_INACTIVE for better readability. Change-Id: I2255fe404951e88a342095de21303358ae8ea50b Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index d21823bac262..7b92f4822d1a 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -753,6 +753,7 @@ static int pd_eval_src_caps(struct usbpd *pd) { int i; union power_supply_propval val; + bool pps_found = false; u32 first_pdo = pd->received_pdos[0]; if (PD_SRC_PDO_TYPE(first_pdo) != PD_SRC_PDO_TYPE_FIXED) { @@ -768,10 +769,8 @@ static int pd_eval_src_caps(struct usbpd *pd) power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, &val); - if (pd->spec_rev == USBPD_REV_30 && !rev3_sink_only) { - bool pps_found = false; - - /* downgrade to 2.0 if no PPS */ + /* Check for PPS APDOs */ + if (pd->spec_rev == USBPD_REV_30) { for (i = 1; i < PD_MAX_DATA_OBJ; i++) { if ((PD_SRC_PDO_TYPE(pd->received_pdos[i]) == PD_SRC_PDO_TYPE_AUGMENTED) && @@ -780,10 +779,18 @@ static int pd_eval_src_caps(struct usbpd *pd) break; } } - if (!pps_found) + + /* downgrade to 2.0 if no PPS */ + if (!pps_found && !rev3_sink_only) pd->spec_rev = USBPD_REV_20; } + val.intval = pps_found ? + POWER_SUPPLY_PD_PPS_ACTIVE : + POWER_SUPPLY_PD_ACTIVE; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_ACTIVE, &val); + /* Select the first PDO (vSafe5V) immediately. */ pd_select_pdo(pd, 1, 0, 0); @@ -2140,7 +2147,7 @@ static void usbpd_sm(struct work_struct *w) usbpd_dbg(&pd->dev, "Src CapsCounter exceeded, disabling PD\n"); usbpd_set_state(pd, PE_SRC_DISABLED); - val.intval = 0; + val.intval = POWER_SUPPLY_PD_INACTIVE; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_ACTIVE, &val); @@ -2160,7 +2167,7 @@ static void usbpd_sm(struct work_struct *w) pd->current_state = PE_SRC_SEND_CAPABILITIES_WAIT; kick_sm(pd, SENDER_RESPONSE_TIME); - val.intval = 1; + val.intval = POWER_SUPPLY_PD_ACTIVE; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_ACTIVE, &val); break; @@ -2352,10 +2359,6 @@ static void usbpd_sm(struct work_struct *w) pd->src_cap_id++; usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY); - - val.intval = 1; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_ACTIVE, &val); } else if (pd->hard_reset_count < 3) { usbpd_set_state(pd, PE_SNK_HARD_RESET); } else { @@ -2366,7 +2369,7 @@ static void usbpd_sm(struct work_struct *w) POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); - val.intval = 0; + val.intval = POWER_SUPPLY_PD_INACTIVE; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_ACTIVE, &val); } -- GitLab From 6452ab111d2350228ce97e1a6ad65ae21241524d Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 4 Apr 2018 18:43:34 -0700 Subject: [PATCH 835/855] usb: pd: fix off-by-one in rdo_h_show When viewing rdo_h via sysfs, the request type is determined by looking up the type from the PDO list, however the obj_pos field is 1-based whereas the received_pdos is 0-based. This off-by-one error can result in misinterpretation of the request object, e.g. viewing a PPS request may show the fields for a Fixed request. Change-Id: If5f25cdadb7838b8f846ca90b16f8b17539d1e37 Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 7b92f4822d1a..6685f05bab57 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -3580,7 +3580,7 @@ static ssize_t rdo_h_show(struct device *dev, struct device_attribute *attr, { struct usbpd *pd = dev_get_drvdata(dev); int pos = PD_RDO_OBJ_POS(pd->rdo); - int type = PD_SRC_PDO_TYPE(pd->received_pdos[pos]); + int type = PD_SRC_PDO_TYPE(pd->received_pdos[pos - 1]); int len; len = scnprintf(buf, PAGE_SIZE, "Request Data Object\n" -- GitLab From e508fe353e8aeef190d438d2e3d5c50768e79cfd Mon Sep 17 00:00:00 2001 From: Kishor PK Date: Tue, 29 May 2018 17:34:37 +0530 Subject: [PATCH 836/855] defconfig: msm8937: Add msm_show_resume_irq related config Enable "QCOM_SHOW_RESUME_IRQ", to support msm_show_resume_irq. Change-Id: Iee799e88f0013985ba0951944bb0a8a61e85416d Signed-off-by: Kishor PK Signed-off-by: Rahul Shahare --- arch/arm/configs/msm8937_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 3c43fa39a474..6a6cbf851f2e 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -605,6 +605,7 @@ CONFIG_DEVFREQ_SPDM=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_SHOW_RESUME_IRQ=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y -- GitLab From 69494ec6e2735a5be5b9589fb0772c5e56e3c2ba Mon Sep 17 00:00:00 2001 From: Rama Krishna Phani A Date: Tue, 5 Jun 2018 19:15:56 +0530 Subject: [PATCH 837/855] msm: mhi_dev: Disable/Enable interrupts during suspend/resume Disable MHI IRQ during D3 HOT event and re-enable it after PERST Deassertion, D0 event handling. Change-Id: Ib7c32a95f0c20c52e15536ad49a8f7d3c8f7e855 Signed-off-by: Rama Krishna Phani A --- drivers/platform/msm/mhi_dev/mhi.c | 4 +++- drivers/platform/msm/mhi_dev/mhi.h | 2 ++ drivers/platform/msm/mhi_dev/mhi_sm.c | 31 +++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index ab43d326bc07..5f74f6b5a6bb 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -2403,8 +2403,10 @@ static void mhi_dev_enable(struct work_struct *work) return; } - if (mhi_ctx->config_iatu || mhi_ctx->mhi_int) + if (mhi_ctx->config_iatu || mhi_ctx->mhi_int) { + mhi_ctx->mhi_int_en = true; enable_irq(mhi_ctx->mhi_irq); + } mhi_update_state_info(MHI_DEV_UEVENT_CTRL, MHI_STATE_CONFIGURED); } diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h index 2dfa58da4ae3..2cc7809bfaaf 100644 --- a/drivers/platform/msm/mhi_dev/mhi.h +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -605,6 +605,8 @@ struct mhi_dev { /*Register for interrupt */ bool mhi_int; + bool mhi_int_en; + /* Registered client callback list */ struct list_head client_cb_list; diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.c b/drivers/platform/msm/mhi_dev/mhi_sm.c index 1200a3629bfc..af05c9edd00a 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.c +++ b/drivers/platform/msm/mhi_dev/mhi_sm.c @@ -19,6 +19,7 @@ #include #include "mhi_hwio.h" #include "mhi_sm.h" +#include #define MHI_SM_DBG(fmt, args...) \ mhi_log(MHI_MSG_DBG, fmt, ##args) @@ -775,6 +776,7 @@ static void mhi_sm_pcie_event_manager(struct work_struct *work) struct mhi_sm_ep_pcie_event *chg_event = container_of(work, struct mhi_sm_ep_pcie_event, work); enum ep_pcie_event pcie_event = chg_event->event; + unsigned long flags; MHI_SM_FUNC_ENTRY(); @@ -846,6 +848,15 @@ static void mhi_sm_pcie_event_manager(struct work_struct *work) mhi_dev_restore_mmio(mhi_sm_ctx->mhi_dev); + spin_lock_irqsave(&mhi_sm_ctx->mhi_dev->lock, flags); + if ((mhi_sm_ctx->mhi_dev->mhi_int) && + (!mhi_sm_ctx->mhi_dev->mhi_int_en)) { + enable_irq(mhi_sm_ctx->mhi_dev->mhi_irq); + mhi_sm_ctx->mhi_dev->mhi_int_en = true; + MHI_SM_DBG("Enable MHI IRQ during PCIe DEAST"); + } + spin_unlock_irqrestore(&mhi_sm_ctx->mhi_dev->lock, flags); + res = ep_pcie_enable_endpoint(mhi_sm_ctx->mhi_dev->phandle, EP_PCIE_OPT_ENUM); if (res) { @@ -1141,6 +1152,7 @@ void mhi_dev_sm_pcie_handler(struct ep_pcie_notify *notify) { struct mhi_sm_ep_pcie_event *dstate_change_evt; enum ep_pcie_event event; + unsigned long flags; MHI_SM_FUNC_ENTRY(); @@ -1173,6 +1185,16 @@ void mhi_dev_sm_pcie_handler(struct ep_pcie_notify *notify) break; case EP_PCIE_EVENT_PM_D3_HOT: mhi_sm_ctx->stats.d3_hot_event_cnt++; + + spin_lock_irqsave(&mhi_sm_ctx->mhi_dev->lock, flags); + if ((mhi_sm_ctx->mhi_dev->mhi_int) && + (mhi_sm_ctx->mhi_dev->mhi_int_en)) { + disable_irq(mhi_sm_ctx->mhi_dev->mhi_irq); + mhi_sm_ctx->mhi_dev->mhi_int_en = false; + MHI_SM_DBG("Disable MHI IRQ during D3 HOT"); + } + spin_unlock_irqrestore(&mhi_sm_ctx->mhi_dev->lock, flags); + mhi_dev_backup_mmio(mhi_sm_ctx->mhi_dev); break; case EP_PCIE_EVENT_PM_RST_DEAST: @@ -1180,6 +1202,15 @@ void mhi_dev_sm_pcie_handler(struct ep_pcie_notify *notify) break; case EP_PCIE_EVENT_PM_D0: mhi_sm_ctx->stats.d0_event_cnt++; + + spin_lock_irqsave(&mhi_sm_ctx->mhi_dev->lock, flags); + if ((mhi_sm_ctx->mhi_dev->mhi_int) && + (!mhi_sm_ctx->mhi_dev->mhi_int_en)) { + enable_irq(mhi_sm_ctx->mhi_dev->mhi_irq); + mhi_sm_ctx->mhi_dev->mhi_int_en = true; + MHI_SM_DBG("Enable MHI IRQ during D0"); + } + spin_unlock_irqrestore(&mhi_sm_ctx->mhi_dev->lock, flags); break; case EP_PCIE_EVENT_LINKDOWN: mhi_sm_ctx->stats.linkdown_event_cnt++; -- GitLab From 62cedde35f8144db5fa45d27d165e0855cd6cbbb Mon Sep 17 00:00:00 2001 From: Rama Krishna Phani A Date: Mon, 11 Jun 2018 19:57:00 +0530 Subject: [PATCH 838/855] msm: mhi_dev: Acquire wakelock to avoid device suspend Acquire wakelock in MHI ISR to avoid device suspend while MHI device is communicating with HOST. Change-Id: I6ae35c701502aabbc6a001e91bc7a92b2963b98d Signed-off-by: Rama Krishna Phani A --- drivers/platform/msm/mhi_dev/mhi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index ab43d326bc07..8dddfd2a9ca6 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -1572,6 +1572,12 @@ static irqreturn_t mhi_dev_isr(int irq, void *dev_id) { struct mhi_dev *mhi = dev_id; + if (!atomic_read(&mhi->mhi_dev_wake)) { + pm_stay_awake(mhi->dev); + atomic_set(&mhi->mhi_dev_wake, 1); + mhi_log(MHI_MSG_VERBOSE, "acquiring mhi wakelock in ISR\n"); + } + disable_irq_nosync(mhi->mhi_irq); schedule_work(&mhi->chdb_ctrl_work); mhi_log(MHI_MSG_VERBOSE, "mhi irq triggered\n"); -- GitLab From abc6f12dd23616d4809e07676838ad2b294f70be Mon Sep 17 00:00:00 2001 From: Hareesh Gundu Date: Wed, 13 Jun 2018 15:28:23 +0530 Subject: [PATCH 839/855] ARM: dts: msm: Add GPU 650Mhz clock support for MSM8917 MSM8917 can support 739.20Mhz DDR and 650Mhz GPU clock. Add this support for MSM8917 to improve performance. Change-Id: I96ebb12dedce34977547f0aabb44a1b9035b39c0 Signed-off-by: Hareesh Gundu --- arch/arm64/boot/dts/qcom/msm8917.dtsi | 138 ++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8917.dtsi b/arch/arm64/boot/dts/qcom/msm8917.dtsi index 242fd9c00327..c4b1ec3b02b0 100644 --- a/arch/arm64/boot/dts/qcom/msm8917.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917.dtsi @@ -1712,3 +1712,141 @@ qcom,clk-dis-wait-val = <0x5>; status = "okay"; }; + +/* GPU overrides */ +&msm_gpu { + + qcom,gpu-speed-bin = <0x6018 0x80000000 31>; + /delete-node/qcom,gpu-pwrlevels; + + qcom,gpu-pwrlevel-bins { + #address-cells = <1>; + #size-cells = <0>; + + compatible="qcom,gpu-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + qcom,initial-pwrlevel = <3>; + + /* TURBO */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <598000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <7>; + qcom,bus-max = <7>; + }; + + /* NOM+ */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <523200000>; + qcom,bus-freq = <6>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <484800000>; + qcom,bus-freq = <5>; + qcom,bus-min = <4>; + qcom,bus-max = <6>; + }; + + /* SVS+ */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <270000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <1>; + qcom,bus-max = <3>; + }; + + /* XO */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <1>; + qcom,initial-pwrlevel = <3>; + + /* TURBO */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <8>; + qcom,bus-max = <8>; + }; + + /* NOM+ */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <523200000>; + qcom,bus-freq = <6>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <484800000>; + qcom,bus-freq = <5>; + qcom,bus-min = <4>; + qcom,bus-max = <6>; + }; + + /* SVS+ */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <270000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <1>; + qcom,bus-max = <3>; + }; + + /* XO */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; +}; -- GitLab From 3ae5bd09c5cf082914ce87fef8773ddbf0f2ed2f Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Tue, 12 Jun 2018 09:17:58 +0530 Subject: [PATCH 840/855] power: qpnp-qg: Add support for PMI632 v2.0 Add the following changes for PMI632 v2.0 1. Support for external-sense 2. Update PON OCV handling Change-Id: Iaabf3de46ed72e33980d1e3e386e8ca0ae651c76 Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qg-core.h | 8 +++ drivers/power/supply/qcom/qpnp-qg.c | 88 ++++++++++++++++++++--------- include/uapi/linux/qg-profile.h | 2 + 3 files changed, 72 insertions(+), 26 deletions(-) diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index e834b8e65404..7bdc1b682f2c 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -60,6 +60,7 @@ struct qg_dt { bool cl_feedback_on; bool esr_disable; bool esr_discharge_enable; + bool qg_ext_sense; }; struct qg_esr_data { @@ -151,11 +152,18 @@ struct qpnp_qg { struct ttf *ttf; }; +struct ocv_all { + u32 ocv_uv; + u32 ocv_raw; + char ocv_type[20]; +}; + enum ocv_type { S7_PON_OCV, S3_GOOD_OCV, S3_LAST_OCV, SDAM_PON_OCV, + PON_OCV_MAX, }; enum debug_mask { diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index a8a7826ad8ae..755733498e00 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "fg-alg.h" #include "qg-sdam.h" #include "qg-core.h" @@ -685,6 +686,7 @@ static void qg_retrieve_esr_params(struct qpnp_qg *chip) rc = qg_sdam_read(SDAM_ESR_CHARGE_SF, &data); if (!rc && data) { + data = CAP(QG_ESR_SF_MIN, QG_ESR_SF_MAX, data); chip->kdata.param[QG_ESR_CHARGE_SF].data = data; chip->kdata.param[QG_ESR_CHARGE_SF].valid = true; qg_dbg(chip, QG_DEBUG_ESR, @@ -695,6 +697,7 @@ static void qg_retrieve_esr_params(struct qpnp_qg *chip) rc = qg_sdam_read(SDAM_ESR_DISCHARGE_SF, &data); if (!rc && data) { + data = CAP(QG_ESR_SF_MIN, QG_ESR_SF_MAX, data); chip->kdata.param[QG_ESR_DISCHARGE_SF].data = data; chip->kdata.param[QG_ESR_DISCHARGE_SF].valid = true; qg_dbg(chip, QG_DEBUG_ESR, @@ -1914,6 +1917,7 @@ static int qg_parallel_status_update(struct qpnp_qg *chip) { int rc; bool parallel_enabled = is_parallel_enabled(chip); + bool update_smb = false; if (parallel_enabled == chip->parallel_enabled) return 0; @@ -1924,7 +1928,14 @@ static int qg_parallel_status_update(struct qpnp_qg *chip) mutex_lock(&chip->data_lock); - rc = process_rt_fifo_data(chip, false, true); + /* + * Parallel charger uses the same external sense, hence do not + * enable SMB sensing if PMI632 is configured for external sense. + */ + if (!chip->dt.qg_ext_sense) + update_smb = true; + + rc = process_rt_fifo_data(chip, false, update_smb); if (rc < 0) pr_err("Failed to process RT FIFO data, rc=%d\n", rc); @@ -2380,12 +2391,21 @@ static int qg_setup_battery(struct qpnp_qg *chip) return 0; } + +static struct ocv_all ocv[] = { + [S7_PON_OCV] = { 0, 0, "S7_PON_OCV"}, + [S3_GOOD_OCV] = { 0, 0, "S3_GOOD_OCV"}, + [S3_LAST_OCV] = { 0, 0, "S3_LAST_OCV"}, + [SDAM_PON_OCV] = { 0, 0, "SDAM_PON_OCV"}, +}; + +#define S7_ERROR_MARGIN_UV 20000 static int qg_determine_pon_soc(struct qpnp_qg *chip) { - int rc = 0, batt_temp = 0; + int rc = 0, batt_temp = 0, i; bool use_pon_ocv = true; unsigned long rtc_sec = 0; - u32 ocv_uv = 0, ocv_raw = 0, soc = 0, shutdown[SDAM_MAX] = {0}; + u32 ocv_uv = 0, soc = 0, shutdown[SDAM_MAX] = {0}; char ocv_type[20] = "NONE"; if (!chip->profile_loaded) { @@ -2434,33 +2454,47 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) goto done; } - /* - * Read S3_LAST_OCV, if S3_LAST_OCV is invalid, - * read the SDAM_PON_OCV - * if SDAM is not-set, use S7_PON_OCV. - */ - strlcpy(ocv_type, "S3_LAST_SOC", 20); - rc = qg_read_ocv(chip, &ocv_uv, &ocv_raw, S3_LAST_OCV); - if (rc < 0) - goto done; - - if (ocv_raw == FIFO_V_RESET_VAL) { - /* S3_LAST_OCV is invalid */ - strlcpy(ocv_type, "SDAM_PON_SOC", 20); - rc = qg_read_ocv(chip, &ocv_uv, &ocv_raw, SDAM_PON_OCV); + /* read all OCVs */ + for (i = S7_PON_OCV; i < PON_OCV_MAX; i++) { + rc = qg_read_ocv(chip, &ocv[i].ocv_uv, + &ocv[i].ocv_raw, i); if (rc < 0) - goto done; + pr_err("Failed to read %s OCV rc=%d\n", + ocv[i].ocv_type, rc); + else + qg_dbg(chip, QG_DEBUG_PON, "%s OCV=%d\n", + ocv[i].ocv_type, ocv[i].ocv_uv); + } - if (!ocv_uv) { - /* SDAM_PON_OCV is not set */ + if (ocv[S3_LAST_OCV].ocv_raw == FIFO_V_RESET_VAL) { + if (!ocv[SDAM_PON_OCV].ocv_uv) { + strlcpy(ocv_type, "S7_PON_SOC", 20); + ocv_uv = ocv[S7_PON_OCV].ocv_uv; + } else if (ocv[SDAM_PON_OCV].ocv_uv <= + ocv[S7_PON_OCV].ocv_uv) { strlcpy(ocv_type, "S7_PON_SOC", 20); - rc = qg_read_ocv(chip, &ocv_uv, &ocv_raw, - S7_PON_OCV); - if (rc < 0) - goto done; + ocv_uv = ocv[S7_PON_OCV].ocv_uv; + } else if (!shutdown[SDAM_VALID] && + ((ocv[SDAM_PON_OCV].ocv_uv - + ocv[S7_PON_OCV].ocv_uv) > + S7_ERROR_MARGIN_UV)) { + strlcpy(ocv_type, "S7_PON_SOC", 20); + ocv_uv = ocv[S7_PON_OCV].ocv_uv; + } else { + strlcpy(ocv_type, "SDAM_PON_SOC", 20); + ocv_uv = ocv[SDAM_PON_OCV].ocv_uv; + } + } else { + if (ocv[S3_LAST_OCV].ocv_uv >= ocv[S7_PON_OCV].ocv_uv) { + strlcpy(ocv_type, "S3_LAST_SOC", 20); + ocv_uv = ocv[S3_LAST_OCV].ocv_uv; + } else { + strlcpy(ocv_type, "S7_PON_SOC", 20); + ocv_uv = ocv[S7_PON_OCV].ocv_uv; } } + ocv_uv = CAP(QG_MIN_OCV_UV, QG_MAX_OCV_UV, ocv_uv); rc = lookup_soc_ocv(&soc, ocv_uv, batt_temp, false); if (rc < 0) { pr_err("Failed to lookup SOC@PON rc=%d\n", rc); @@ -3117,6 +3151,8 @@ static int qg_parse_dt(struct qpnp_qg *chip) else chip->dt.esr_disable_soc = temp * 100; + chip->dt.qg_ext_sense = of_property_read_bool(node, "qcom,qg-ext-sns"); + /* Capacity learning params*/ if (!chip->dt.cl_disable) { chip->dt.cl_feedback_on = of_property_read_bool(node, @@ -3176,9 +3212,9 @@ static int qg_parse_dt(struct qpnp_qg *chip) chip->cl->dt.min_start_soc, chip->cl->dt.max_start_soc, chip->cl->dt.min_temp, chip->cl->dt.max_temp); } - qg_dbg(chip, QG_DEBUG_PON, "DT: vbatt_empty_mv=%dmV vbatt_low_mv=%dmV delta_soc=%d\n", + qg_dbg(chip, QG_DEBUG_PON, "DT: vbatt_empty_mv=%dmV vbatt_low_mv=%dmV delta_soc=%d ext-sns=%d\n", chip->dt.vbatt_empty_mv, chip->dt.vbatt_low_mv, - chip->dt.delta_soc); + chip->dt.delta_soc, chip->dt.qg_ext_sense); return 0; } diff --git a/include/uapi/linux/qg-profile.h b/include/uapi/linux/qg-profile.h index bffddbb038e0..0230b3227f78 100644 --- a/include/uapi/linux/qg-profile.h +++ b/include/uapi/linux/qg-profile.h @@ -55,6 +55,8 @@ struct battery_params { #define QG_MAX_FCC_MAH 16000 #define QG_MIN_SLOPE 1 #define QG_MAX_SLOPE 50000 +#define QG_ESR_SF_MIN 5000 +#define QG_ESR_SF_MAX 20000 /* IOCTLs to query battery profile data */ #define BPIOCXSOC _IOWR('B', 0x01, struct battery_params) /* SOC */ -- GitLab From 485ad23c4710ae35cc007a7d963ebf6c4b0f9e33 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Fri, 15 Jun 2018 09:01:32 +0530 Subject: [PATCH 841/855] power: qpnp-qg: Add battery hot-swap support in QG Support battery hot-swap (removal and re-insertion with USB present). Clear the userspace and SDAM data during hot-swap. Change-Id: Iaabf3de46ed72e33980d1e3e386e8ca0ae651c77 Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qg-reg.h | 9 ++ drivers/power/supply/qcom/qpnp-qg.c | 159 +++++++++++++++++++++++++--- include/uapi/linux/qg.h | 3 +- 3 files changed, 157 insertions(+), 14 deletions(-) diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h index 88572ca5d3bd..e0f400d05cd3 100644 --- a/drivers/power/supply/qcom/qg-reg.h +++ b/drivers/power/supply/qcom/qg-reg.h @@ -17,6 +17,7 @@ #define QG_TYPE 0x0D #define QG_STATUS1_REG 0x08 +#define QG_OK_BIT BIT(7) #define BATTERY_PRESENT_BIT BIT(0) #define ESR_MEAS_DONE_BIT BIT(4) @@ -32,6 +33,7 @@ #define QG_INT_RT_STS_REG 0x10 #define FIFO_UPDATE_DONE_RT_STS_BIT BIT(3) #define VBAT_LOW_INT_RT_STS_BIT BIT(1) +#define BATTERY_MISSING_INT_RT_STS_BIT BIT(0) #define QG_INT_LATCHED_STS_REG 0x18 #define FIFO_UPDATE_DONE_INT_LAT_STS_BIT BIT(3) @@ -64,6 +66,12 @@ #define QG_S3_ENTRY_IBAT_THRESHOLD_REG 0x5E #define QG_S3_EXIT_IBAT_THRESHOLD_REG 0x5F +#define QG_S5_OCV_VALIDATE_MEAS_CTL1_REG 0x60 +#define ALLOW_S5_BIT BIT(7) + +#define QG_S7_PON_OCV_MEAS_CTL1_REG 0x64 +#define ADC_CONV_DLY_MASK GENMASK(3, 0) + #define QG_ESR_MEAS_TRIG_REG 0x68 #define HW_ESR_MEAS_START_BIT BIT(0) @@ -105,6 +113,7 @@ #define QG_SDAM_ESR_DISCHARGE_DELTA_OFFSET 0x6E /* 4-byte 0x6E-0x71 */ #define QG_SDAM_ESR_CHARGE_SF_OFFSET 0x72 /* 2-byte 0x72-0x73 */ #define QG_SDAM_ESR_DISCHARGE_SF_OFFSET 0x74 /* 2-byte 0x74-0x75 */ +#define QG_SDAM_MAX_OFFSET 0xA4 /* Below offset is used by PBS */ #define QG_SDAM_PON_OCV_OFFSET 0xBC /* 2-byte 0xBC-0xBD */ diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 755733498e00..d91b1d4071b6 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1059,19 +1060,12 @@ static void process_udata_work(struct work_struct *work) qg_store_esr_params(chip); qg_dbg(chip, QG_DEBUG_STATUS, "udata update: batt_soc=%d cc_soc=%d full_soc=%d qg_esr=%d\n", - chip->batt_soc, chip->cc_soc, chip->full_soc, chip->esr_last); + (chip->batt_soc != INT_MIN) ? chip->batt_soc : -EINVAL, + (chip->cc_soc != INT_MIN) ? chip->cc_soc : -EINVAL, + chip->full_soc, chip->esr_last); vote(chip->awake_votable, UDATA_READY_VOTER, false, 0); } -static irqreturn_t qg_default_irq_handler(int irq, void *data) -{ - struct qpnp_qg *chip = data; - - qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n"); - - return IRQ_HANDLED; -} - #define MAX_FIFO_DELTA_PERCENT 10 static irqreturn_t qg_fifo_update_done_handler(int irq, void *data) { @@ -1157,6 +1151,11 @@ static irqreturn_t qg_vbat_low_handler(int irq, void *data) pr_err("Failed to read RT status, rc=%d\n", rc); goto done; } + /* ignore VBAT low if battery is missing */ + if ((status & BATTERY_MISSING_INT_RT_STS_BIT) || + chip->battery_missing) + goto done; + chip->vbat_low = !!(status & VBAT_LOW_INT_RT_STS_BIT); rc = process_rt_fifo_data(chip, chip->vbat_low, false); @@ -1173,8 +1172,20 @@ static irqreturn_t qg_vbat_empty_handler(int irq, void *data) { struct qpnp_qg *chip = data; u32 ocv_uv = 0; + int rc; + u8 status = 0; qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n"); + + rc = qg_read(chip, chip->qg_base + QG_INT_RT_STS_REG, &status, 1); + if (rc < 0) + pr_err("Failed to read RT status rc=%d\n", rc); + + /* ignore VBAT empty if battery is missing */ + if ((status & BATTERY_MISSING_INT_RT_STS_BIT) || + chip->battery_missing) + return IRQ_HANDLED; + pr_warn("VBATT EMPTY SOC = 0\n"); chip->catch_up_soc = 0; @@ -1235,7 +1246,6 @@ static irqreturn_t qg_good_ocv_handler(int irq, void *data) static struct qg_irq_info qg_irqs[] = { [QG_BATT_MISSING_IRQ] = { .name = "qg-batt-missing", - .handler = qg_default_irq_handler, }, [QG_VBATT_LOW_IRQ] = { .name = "qg-vbat-low", @@ -1259,11 +1269,9 @@ static struct qg_irq_info qg_irqs[] = { }, [QG_FSM_STAT_CHG_IRQ] = { .name = "qg-fsm-state-chg", - .handler = qg_default_irq_handler, }, [QG_EVENT_IRQ] = { .name = "qg-event", - .handler = qg_default_irq_handler, }, }; @@ -1960,6 +1968,110 @@ static int qg_usb_status_update(struct qpnp_qg *chip) return 0; } +static int qg_handle_battery_removal(struct qpnp_qg *chip) +{ + int rc, length = QG_SDAM_MAX_OFFSET - QG_SDAM_VALID_OFFSET; + u8 *data; + + /* clear SDAM */ + data = kcalloc(length, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + rc = qg_sdam_multibyte_write(QG_SDAM_VALID_OFFSET, data, length); + if (rc < 0) + pr_err("Failed to clear SDAM rc=%d\n", rc); + + return rc; +} + +#define MAX_QG_OK_RETRIES 20 +static int qg_handle_battery_insertion(struct qpnp_qg *chip) +{ + int rc, count = 0; + u32 ocv_uv = 0, ocv_raw = 0; + u8 reg = 0; + + do { + rc = qg_read(chip, chip->qg_base + QG_STATUS1_REG, ®, 1); + if (rc < 0) { + pr_err("Failed to read STATUS1_REG rc=%d\n", rc); + return rc; + } + + if (reg & QG_OK_BIT) + break; + + msleep(200); + count++; + } while (count < MAX_QG_OK_RETRIES); + + if (count == MAX_QG_OK_RETRIES) { + qg_dbg(chip, QG_DEBUG_STATUS, "QG_OK not set!\n"); + return 0; + } + + /* read S7 PON OCV */ + rc = qg_read_ocv(chip, &ocv_uv, &ocv_raw, S7_PON_OCV); + if (rc < 0) { + pr_err("Failed to read PON OCV rc=%d\n", rc); + return rc; + } + + qg_dbg(chip, QG_DEBUG_STATUS, + "S7_OCV on battery insertion = %duV\n", ocv_uv); + + chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv; + chip->kdata.param[QG_GOOD_OCV_UV].valid = true; + /* clear all the userspace data */ + chip->kdata.param[QG_CLEAR_LEARNT_DATA].data = 1; + chip->kdata.param[QG_CLEAR_LEARNT_DATA].valid = true; + + vote(chip->awake_votable, GOOD_OCV_VOTER, true, 0); + /* signal the read thread */ + chip->data_ready = true; + wake_up_interruptible(&chip->qg_wait_q); + + return 0; +} + +static int qg_battery_status_update(struct qpnp_qg *chip) +{ + int rc; + union power_supply_propval prop = {0, }; + + if (!is_batt_available(chip)) + return 0; + + mutex_lock(&chip->data_lock); + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_PRESENT, &prop); + if (rc < 0) { + pr_err("Failed to get battery-present, rc=%d\n", rc); + goto done; + } + + if (chip->battery_missing && prop.intval) { + pr_warn("Battery inserted!\n"); + rc = qg_handle_battery_insertion(chip); + if (rc < 0) + pr_err("Failed in battery-insertion rc=%d\n", rc); + } else if (!chip->battery_missing && !prop.intval) { + pr_warn("Battery removed!\n"); + rc = qg_handle_battery_removal(chip); + if (rc < 0) + pr_err("Failed in battery-removal rc=%d\n", rc); + } + + chip->battery_missing = !prop.intval; + +done: + mutex_unlock(&chip->data_lock); + return rc; +} + + static void qg_status_change_work(struct work_struct *work) { struct qpnp_qg *chip = container_of(work, @@ -1972,6 +2084,10 @@ static void qg_status_change_work(struct work_struct *work) goto out; } + rc = qg_battery_status_update(chip); + if (rc < 0) + pr_err("Failed to process battery status update rc=%d\n", rc); + rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &prop); if (rc < 0) @@ -2549,6 +2665,7 @@ static int qg_set_wa_flags(struct qpnp_qg *chip) return 0; } +#define ADC_CONV_DLY_512MS 0xA static int qg_hw_init(struct qpnp_qg *chip) { int rc, temp; @@ -2729,6 +2846,22 @@ static int qg_hw_init(struct qpnp_qg *chip) return rc; } + /* disable S5 */ + rc = qg_masked_write(chip, chip->qg_base + + QG_S5_OCV_VALIDATE_MEAS_CTL1_REG, + ALLOW_S5_BIT, 0); + if (rc < 0) + pr_err("Failed to disable S5 rc=%d\n", rc); + + /* change PON OCV time to 512ms */ + rc = qg_masked_write(chip, chip->qg_base + + QG_S7_PON_OCV_MEAS_CTL1_REG, + ADC_CONV_DLY_MASK, + ADC_CONV_DLY_512MS); + if (rc < 0) + pr_err("Failed to reconfigure S7-delay rc=%d\n", rc); + + return 0; } diff --git a/include/uapi/linux/qg.h b/include/uapi/linux/qg.h index 2194e1f1ac27..40882a7ae8c4 100644 --- a/include/uapi/linux/qg.h +++ b/include/uapi/linux/qg.h @@ -19,7 +19,7 @@ enum qg { QG_ESR_CHARGE_SF, QG_ESR_DISCHARGE_SF, QG_FULL_SOC, - QG_RESERVED_8, + QG_CLEAR_LEARNT_DATA, QG_RESERVED_9, QG_RESERVED_10, QG_MAX, @@ -32,6 +32,7 @@ enum qg { #define QG_ESR_CHARGE_SF QG_ESR_CHARGE_SF #define QG_ESR_DISCHARGE_SF QG_ESR_DISCHARGE_SF #define QG_FULL_SOC QG_FULL_SOC +#define QG_CLEAR_LEARNT_DATA QG_CLEAR_LEARNT_DATA struct fifo_data { unsigned int v; -- GitLab From 2561708fe27ab401f9cace152859eea9fa466d05 Mon Sep 17 00:00:00 2001 From: "Chinkit Kumar,Kirti Kumar Parmar" Date: Fri, 8 Jun 2018 12:06:53 +0530 Subject: [PATCH 842/855] ARM: dts: msm: Remove Legacy KTM related DTS changes for MSM8909 Remove Kernel Thermal Monitor(KTM) related dts changes as it is deprecated in 4.9 kernel. Change-Id: Ic2c9df72e9bf32176acd487b37dfd8d47f0ed201 Signed-off-by: Chinkit Kumar,Kirti Kumar Parmar --- arch/arm64/boot/dts/qcom/msm8909.dtsi | 77 --------------------------- 1 file changed, 77 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm8909.dtsi index a72fdbf17861..2b9c1e1122f0 100644 --- a/arch/arm64/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909.dtsi @@ -77,7 +77,6 @@ efficiency = <1024>; sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; qcom,sleep-status = <&cpu0_slp_sts>; - qcom,limits-info = <&mitigation_profile0>; }; CPU1: cpu@1 { @@ -87,7 +86,6 @@ efficiency = <1024>; sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; qcom,sleep-status = <&cpu1_slp_sts>; - qcom,limits-info = <&mitigation_profile2>; }; CPU2: cpu@2 { @@ -97,7 +95,6 @@ efficiency = <1024>; sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; qcom,sleep-status = <&cpu2_slp_sts>; - qcom,limits-info = <&mitigation_profile1>; }; CPU3: cpu@3 { @@ -107,7 +104,6 @@ efficiency = <1024>; sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; qcom,sleep-status = <&cpu3_slp_sts>; - qcom,limits-info = <&mitigation_profile2>; }; }; @@ -559,79 +555,6 @@ }; - qcom,sensor-information { - compatible = "qcom,sensor-information"; - sensor_information0: qcom,sensor-information-0 { - qcom,sensor-type = "tsens"; - qcom,sensor-name = "tsens_tz_sensor0"; - qcom,alias-name = "pop_mem"; - }; - - sensor_information1: qcom,sensor-information-1 { - qcom,sensor-type = "tsens"; - qcom,sensor-name = "tsens_tz_sensor1"; - }; - - sensor_information2: qcom,sensor-information-2 { - qcom,sensor-type = "tsens"; - qcom,sensor-name = "tsens_tz_sensor2"; - }; - - sensor_information3: qcom,sensor-information-3 { - qcom,sensor-type = "tsens"; - qcom,sensor-name = "tsens_tz_sensor3"; - }; - - sensor_information4: qcom,sensor-information-4 { - qcom,sensor-type = "tsens"; - qcom,sensor-name = "tsens_tz_sensor4"; - }; - - sensor_information5: qcom,sensor-information-5 { - qcom,sensor-type = "adc"; - qcom,sensor-name = "pa_therm0"; - }; - - sensor_information6: qcom,sensor-information-6 { - qcom,sensor-type = "adc"; - qcom,sensor-name = "case_therm"; - }; - - sensor_information7: qcom,sensor-information-7 { - qcom,sensor-type = "alarm"; - qcom,sensor-name = "pm8909_tz"; - qcom,scaling-factor = <1000>; - }; - - sensor_information8: qcom,sensor-information-8 { - qcom,sensor-type = "adc"; - qcom,sensor-name = "xo_therm"; - }; - - sensor_information9: qcom,sensor-information-9 { - qcom,sensor-type = "adc"; - qcom,sensor-name = "xo_therm_buf"; - }; - }; - - mitigation_profile0: qcom,limit_info-0 { - qcom,temperature-sensor = <&sensor_information3>; - qcom,boot-frequency-mitigate; - qcom,emergency-frequency-mitigate; - }; - - mitigation_profile1: qcom,limit_info-1 { - qcom,temperature-sensor = <&sensor_information3>; - qcom,boot-frequency-mitigate; - qcom,hotplug-mitigation-enable; - }; - - mitigation_profile2: qcom,limit_info-2 { - qcom,temperature-sensor = <&sensor_information4>; - qcom,boot-frequency-mitigate; - qcom,hotplug-mitigation-enable; - }; - qcom,ipc-spinlock@1905000 { compatible = "qcom,ipc-spinlock-sfpb"; reg = <0x1905000 0x8000>; -- GitLab From 6b5632e452a0c6e710ca9dc64dfc6520a0346dc2 Mon Sep 17 00:00:00 2001 From: Vamshi Krishna B V Date: Wed, 6 Jun 2018 14:02:11 +0530 Subject: [PATCH 843/855] power_supply: Add SOH, ESR_Actual and ESR_Nominal properties Add State of Health (SOH) property which indicates battery state of health based on ESR and learned capacity. Also add ESR_Actual and ESR_Nominal for SOH calculations. CRs-Fixed: 2259538 Change-Id: Icefa262627296b5dc232ea706a8253cb854288b6 Signed-off-by: Vamshi Krishna B V --- drivers/power/supply/power_supply_sysfs.c | 3 +++ include/linux/power_supply.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 3ab93fe7c2b9..cd76a09498e0 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -335,6 +335,9 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(battery_info), POWER_SUPPLY_ATTR(battery_info_id), POWER_SUPPLY_ATTR(enable_jeita_detection), + POWER_SUPPLY_ATTR(esr_actual), + POWER_SUPPLY_ATTR(esr_nominal), + POWER_SUPPLY_ATTR(soh), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 78c2a9ff4e84..ad6d53d310fb 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -286,6 +286,9 @@ enum power_supply_property { POWER_SUPPLY_PROP_BATTERY_INFO, POWER_SUPPLY_PROP_BATTERY_INFO_ID, POWER_SUPPLY_PROP_ENABLE_JEITA_DETECTION, + POWER_SUPPLY_PROP_ESR_ACTUAL, + POWER_SUPPLY_PROP_ESR_NOMINAL, + POWER_SUPPLY_PROP_SOH, /* Local extensions of type int64_t */ POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, /* Properties of type `const char *' */ -- GitLab From 5fd80ed0968c68327f4f62c2a8759c9e33edca34 Mon Sep 17 00:00:00 2001 From: Vamshi Krishna B V Date: Wed, 6 Jun 2018 17:12:05 +0530 Subject: [PATCH 844/855] power: qpnp-qg: Add SOH, ESR_Actual and ESR_Nominal properties Add State of health (SOH), property which indicates battery state of health. Also add SOC_reporting_ready, ESR_Actual and ESR_Nominal properties for SOH calculations. CRs-Fixed: 2259538 Change-Id: I32e1c42e58f739b277943ff07863249a1c40a4d0 Signed-off-by: Vamshi Krishna B V --- drivers/power/supply/qcom/qg-core.h | 4 +++ drivers/power/supply/qcom/qpnp-qg.c | 45 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index 7bdc1b682f2c..f21b2a8fcb21 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -121,6 +121,10 @@ struct qpnp_qg { int charge_type; int chg_iterm_ma; int next_wakeup_ms; + int esr_actual; + int esr_nominal; + int soh; + int soc_reporting_ready; u32 fifo_done_count; u32 wa_flags; u32 seq_no; diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index d91b1d4071b6..99e0f3346380 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -1006,6 +1006,7 @@ static int qg_esr_estimate(struct qpnp_qg *chip) qg_dbg(chip, QG_DEBUG_ESR, "ESR_SW=%d during %s\n", chip->esr_avg, is_charging ? "CHARGE" : "DISCHARGE"); qg_retrieve_esr_params(chip); + chip->esr_actual = chip->esr_avg; } return 0; @@ -1056,6 +1057,12 @@ static void process_udata_work(struct work_struct *work) if (chip->udata.param[QG_ESR].valid) chip->esr_last = chip->udata.param[QG_ESR].data; + if (chip->esr_actual != -EINVAL && chip->udata.param[QG_ESR].valid) { + chip->esr_nominal = chip->udata.param[QG_ESR].data; + if (chip->qg_psy) + power_supply_changed(chip->qg_psy); + } + if (!chip->dt.esr_disable) qg_store_esr_params(chip); @@ -1702,6 +1709,17 @@ static int qg_psy_set_property(struct power_supply *psy, chip->cl->learned_cap_uah = pval->intval; mutex_unlock(&chip->cl->lock); break; + case POWER_SUPPLY_PROP_SOH: + chip->soh = pval->intval; + qg_dbg(chip, QG_DEBUG_STATUS, "SOH update: SOH=%d esr_actual=%d esr_nominal=%d\n", + chip->soh, chip->esr_actual, chip->esr_nominal); + break; + case POWER_SUPPLY_PROP_ESR_ACTUAL: + chip->esr_actual = pval->intval; + break; + case POWER_SUPPLY_PROP_ESR_NOMINAL: + chip->esr_nominal = pval->intval; + break; default: break; } @@ -1748,6 +1766,9 @@ static int qg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_RESISTANCE_NOW: pval->intval = chip->esr_last; break; + case POWER_SUPPLY_PROP_SOC_REPORTING_READY: + pval->intval = chip->soc_reporting_ready; + break; case POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE: pval->intval = chip->dt.rbat_conn_mohm; break; @@ -1796,6 +1817,17 @@ static int qg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: rc = ttf_get_time_to_empty(chip->ttf, &pval->intval); break; + case POWER_SUPPLY_PROP_ESR_ACTUAL: + pval->intval = (chip->esr_actual == -EINVAL) ? -EINVAL : + (chip->esr_actual * 1000); + break; + case POWER_SUPPLY_PROP_ESR_NOMINAL: + pval->intval = (chip->esr_nominal == -EINVAL) ? -EINVAL : + (chip->esr_nominal * 1000); + break; + case POWER_SUPPLY_PROP_SOH: + pval->intval = chip->soh; + break; default: pr_debug("Unsupported property %d\n", psp); break; @@ -1809,6 +1841,9 @@ static int qg_property_is_writeable(struct power_supply *psy, { switch (psp) { case POWER_SUPPLY_PROP_CHARGE_FULL: + case POWER_SUPPLY_PROP_ESR_ACTUAL: + case POWER_SUPPLY_PROP_ESR_NOMINAL: + case POWER_SUPPLY_PROP_SOH: return 1; default: break; @@ -1826,6 +1861,7 @@ static enum power_supply_property qg_psy_props[] = { POWER_SUPPLY_PROP_RESISTANCE, POWER_SUPPLY_PROP_RESISTANCE_ID, POWER_SUPPLY_PROP_RESISTANCE_NOW, + POWER_SUPPLY_PROP_SOC_REPORTING_READY, POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE, POWER_SUPPLY_PROP_DEBUG_BATTERY, POWER_SUPPLY_PROP_BATTERY_TYPE, @@ -1839,6 +1875,9 @@ static enum power_supply_property qg_psy_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, + POWER_SUPPLY_PROP_ESR_ACTUAL, + POWER_SUPPLY_PROP_ESR_NOMINAL, + POWER_SUPPLY_PROP_SOH, }; static const struct power_supply_desc qg_psy_desc = { @@ -2643,6 +2682,9 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) pr_info("using %s @ PON ocv_uv=%duV soc=%d\n", ocv_type, ocv_uv, chip->msoc); + /* SOC reporting is now ready */ + chip->soc_reporting_ready = 1; + return 0; } @@ -3576,6 +3618,9 @@ static int qpnp_qg_probe(struct platform_device *pdev) chip->cc_soc = INT_MIN; chip->full_soc = QG_SOC_FULL; chip->chg_iterm_ma = INT_MIN; + chip->soh = -EINVAL; + chip->esr_actual = -EINVAL; + chip->esr_nominal = -EINVAL; rc = qg_alg_init(chip); if (rc < 0) { -- GitLab From 9b1dda1a2a0e2c82fb6c841ccd7f8e492fdb485b Mon Sep 17 00:00:00 2001 From: Bryan Huntsman Date: Mon, 12 Feb 2018 17:26:10 -0800 Subject: [PATCH 845/855] checkpatch: allow copyright statements > 80 columns Exempt copyright statements from the 80 column rule as line-splitting or other kinds of work-arounds decrease readability in diffs. Identify the copyright statement by looking for '+/* Copyright (c)', case-insensitive, at the beginning of the line. Change-Id: I57aafd569ff2173ca7aa3f636532060fc93b2be1 Signed-off-by: Bryan Huntsman --- scripts/checkpatch.pl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index cdfa754abd5b..0534378309ff 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -3012,6 +3012,10 @@ sub process { } elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/) { $msg_type = ""; + # Long copyright statements are another special case + } elsif ($rawline =~ /^\+.\*.*copyright.*\(c\).*$/i) { + $msg_type = ""; + # Otherwise set the alternate message types # a comment starts before $max_line_length -- GitLab From 4700217038c2b934a936a6f6a3f5a29bc344a903 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Tue, 19 Jun 2018 16:03:57 +0530 Subject: [PATCH 846/855] defconfig: msm8937/53: enable SMB1355 charger driver Enable SMB1355 charger driver and it's dependencies. SMB1355 is a parallel charger running in slave mode. Change-Id: Ie7d0ac7883eafca4fb2e3593f10c8cf8a6e9a149 Signed-off-by: Ashay Jaiswal --- arch/arm/configs/msm8937-perf_defconfig | 3 +++ arch/arm/configs/msm8937_defconfig | 3 +++ arch/arm/configs/msm8953-perf_defconfig | 3 +++ arch/arm/configs/msm8953_defconfig | 3 +++ 4 files changed, 12 insertions(+) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index ced854d108db..f4b80f07a719 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -353,6 +353,7 @@ CONFIG_POWER_RESET_SYSCON=y CONFIG_POWER_SUPPLY=y CONFIG_QPNP_FG=y CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1355_SLAVE_CHARGER=y CONFIG_SMB1351_USB_CHARGER=y CONFIG_QPNP_SMB5=y CONFIG_QPNP_SMBCHARGER=y @@ -374,6 +375,7 @@ CONFIG_QTI_QMI_COOLING_DEVICE=y CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y @@ -584,6 +586,7 @@ CONFIG_DEVFREQ_SIMPLE_DEV=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_SPDM_SCM=y CONFIG_DEVFREQ_SPDM=y +CONFIG_IIO=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_PWM_QTI_LPG=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 40d5cb156e26..c2918a5ae517 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -360,6 +360,7 @@ CONFIG_POWER_RESET_SYSCON=y CONFIG_POWER_SUPPLY=y CONFIG_QPNP_FG=y CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1355_SLAVE_CHARGER=y CONFIG_SMB1351_USB_CHARGER=y CONFIG_QPNP_SMB5=y CONFIG_QPNP_SMBCHARGER=y @@ -381,6 +382,7 @@ CONFIG_QTI_QMI_COOLING_DEVICE=y CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y @@ -603,6 +605,7 @@ CONFIG_DEVFREQ_SIMPLE_DEV=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_SPDM_SCM=y CONFIG_DEVFREQ_SPDM=y +CONFIG_IIO=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_PWM_QTI_LPG=y diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index 8caee2f09f96..dece1c40677d 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -349,6 +349,7 @@ CONFIG_POWER_RESET_SYSCON=y CONFIG_POWER_SUPPLY=y CONFIG_QPNP_FG=y CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1355_SLAVE_CHARGER=y CONFIG_SMB1351_USB_CHARGER=y CONFIG_QPNP_SMB5=y CONFIG_QPNP_SMBCHARGER=y @@ -370,6 +371,7 @@ CONFIG_QTI_QMI_COOLING_DEVICE=y CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y @@ -586,6 +588,7 @@ CONFIG_DEVFREQ_SIMPLE_DEV=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_SPDM_SCM=y CONFIG_DEVFREQ_SPDM=y +CONFIG_IIO=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_PWM_QTI_LPG=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index e76f0458eeb8..c64bc6eb3f0b 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -356,6 +356,7 @@ CONFIG_POWER_RESET_SYSCON=y CONFIG_POWER_SUPPLY=y CONFIG_QPNP_FG=y CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1355_SLAVE_CHARGER=y CONFIG_SMB1351_USB_CHARGER=y CONFIG_QPNP_SMB5=y CONFIG_QPNP_SMBCHARGER=y @@ -377,6 +378,7 @@ CONFIG_QTI_QMI_COOLING_DEVICE=y CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y @@ -604,6 +606,7 @@ CONFIG_DEVFREQ_SIMPLE_DEV=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_SPDM_SCM=y CONFIG_DEVFREQ_SPDM=y +CONFIG_IIO=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_PWM_QTI_LPG=y -- GitLab From 9c32e5cdfee33f1c2d263dd557b3bd4ae06c58fe Mon Sep 17 00:00:00 2001 From: Arulpandiyan Vadivel Date: Sat, 9 Jun 2018 18:11:25 +0530 Subject: [PATCH 847/855] ARM: dts: msm: Add thermal zone support for apq8909 Add target specific thermal configuration for APQ8909 platform. Add thermal zone nodes pa_therm0, xo-therm, xo-therm-buf. Change-Id: I8be9f7616b6c0dd642cfe39d0506d3a8181fc26f Signed-off-by: Arulpandiyan Vadivel Signed-off-by: Sundara Vinayagam --- arch/arm64/boot/dts/qcom/8909-pm8916.dtsi | 52 +++++++++++++++++++++++ arch/arm64/boot/dts/qcom/pm8916.dtsi | 12 +++--- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/8909-pm8916.dtsi b/arch/arm64/boot/dts/qcom/8909-pm8916.dtsi index 3247d0d1e07a..573aaac9a179 100644 --- a/arch/arm64/boot/dts/qcom/8909-pm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/8909-pm8916.dtsi @@ -296,6 +296,7 @@ qcom,scale-function = <2>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; }; chan@32 { @@ -307,6 +308,7 @@ qcom,scale-function = <4>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; }; chan@3c { @@ -318,6 +320,7 @@ qcom,scale-function = <4>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; }; }; @@ -350,3 +353,52 @@ #include "msm8909-pm8916-pm.dtsi" +&soc { + thermal-zones { + xo-therm-buf-adc { + polling-delay-passive = <0>; + polling-delay = <1000>; + thermal-sensors = <&pm8916_vadc 0x3c>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + + xo-therm-adc { + polling-delay-passive = <0>; + polling-delay = <1000>; + thermal-sensors = <&pm8916_vadc 0x32>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa-therm0-adc { + polling-delay-passive = <0>; + polling-delay = <1000>; + thermal-sensors = <&pm8916_vadc 0x36>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8916.dtsi b/arch/arm64/boot/dts/qcom/pm8916.dtsi index af290809edd3..5204137e75eb 100644 --- a/arch/arm64/boot/dts/qcom/pm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8916.dtsi @@ -101,12 +101,13 @@ reg = <0x3100 0x100>; #address-cells = <1>; #size-cells = <0>; - interrupts = <0x0 0x31 0x0 IRQ_TYPE_NONE>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; interrupt-names = "eoc-int-en-set"; qcom,adc-bit-resolution = <15>; qcom,adc-vdd-reference = <1800>; qcom,vadc-poll-eoc; qcom,pmic-revid = <&pm8916_revid>; + #thermal-sensor-cells = <1>; chan@8 { label = "die_temp"; @@ -145,11 +146,12 @@ pm8916_tz: qcom,temp-alarm@2400 { compatible = "qcom,qpnp-temp-alarm"; reg = <0x2400 0x100>; - interrupts = <0x0 0x24 0x0 IRQ_TYPE_NONE>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>; label = "pm8916_tz"; qcom,channel-num = <8>; qcom,threshold-set = <0>; qcom,temp_alarm-vadc = <&pm8916_vadc>; + #thermal-sensor-cells = <0>; }; pm8916_adc_tm: vadc@3400 { @@ -157,9 +159,9 @@ reg = <0x3400 0x100>; #address-cells = <1>; #size-cells = <0>; - interrupts = <0x0 0x34 0x0 IRQ_TYPE_NONE>, - <0x0 0x34 0x3 IRQ_TYPE_NONE>, - <0x0 0x34 0x4 IRQ_TYPE_NONE>; + interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x34 0x3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x34 0x4 IRQ_TYPE_EDGE_RISING>; interrupt-names = "eoc-int-en-set", "high-thr-en-set", "low-thr-en-set"; -- GitLab From 718993e5d30f349892fff29377ba6b28288fd6ee Mon Sep 17 00:00:00 2001 From: gaolez Date: Fri, 8 Jun 2018 13:46:03 +0800 Subject: [PATCH 848/855] ARM: dts: msm: Add sdhc_2 and cnss_sdio node for apq8009 dragon board Add sdhc_2 and cnss_sdio node on apq8009 to enable sdio controller and cnss sdio platform driver to enable sdio wlan card. Change-Id: I4dda3ad3676efe58b7830f2bf804a7a14eb3cc46 Signed-off-by: Gaole Zhang --- arch/arm64/boot/dts/qcom/apq8009-dragon.dts | 80 ++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/apq8009-dragon.dts b/arch/arm64/boot/dts/qcom/apq8009-dragon.dts index 12a4363c3115..ba12854b62fb 100644 --- a/arch/arm64/boot/dts/qcom/apq8009-dragon.dts +++ b/arch/arm64/boot/dts/qcom/apq8009-dragon.dts @@ -71,12 +71,90 @@ compatible = "qca,qca9379"; qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */ }; + + cnss_sdio: qcom,cnss_sdio { + compatible = "qcom,cnss_sdio"; + subsys-name = "AR6320"; + /** + * There is no vdd-wlan on board and this is not for DSRC. + * IO and XTAL share the same vreg. + **/ + vdd-wlan-io-supply = <&pm8916_l5>; + qcom,cap-tsf-gpio = <&msm_gpio 42 1>; + qcom,wlan-ramdump-dynamic = <0x200000>; + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <79 512 0 0>, /* No vote */ + <79 512 6250 200000>, /* 50 Mbps */ + <79 512 25000 200000>, /* 200 Mbps */ + <79 512 2048000 4096000>; /* MAX */ + }; }; -&sdhc_2 { +&wcnss { status = "disabled"; }; +&msm_gpio { + sdc2_wlan_gpio_on: sdc2_wlan_gpio_on { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + }; + + sdc2_wlan_gpio_off: sdc2_wlan_gpio_off { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; +}; + +&sdhc_2 { + /delete-property/cd-gpios; + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &msm_gpio 40 0x1>; + interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; + + qcom,vdd-voltage-level = <1800000 2950000>; + qcom,vdd-current-level = <15000 400000>; + + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 50000>; + qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_wlan_gpio_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_wlan_gpio_off>; + qcom,nonremovable; + qcom,core_3_0v_support; + status = "ok"; +}; + &usb_otg { interrupts = <0 134 0>,<0 140 0>,<0 136 0>; interrupt-names = "core_irq", "async_irq", "phy_irq"; -- GitLab From 9bc21a63bcf974ff73f0e556cf2350b4c173c383 Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Tue, 19 Jun 2018 18:39:09 +0530 Subject: [PATCH 849/855] defconfig: msm8953: Enable CONFIG_NETFILTER_XT_MATCH_BPF Enable bpf match support for targets with kernel 4.9 and above so that iptable command from netd (userspace module) with -m bpf doesn't fail. Change-Id: I48d973f904a9fd98580fbf8c4d6e24124145b357 Signed-off-by: Devi Sandeep Endluri V V --- arch/arm/configs/msm8953-perf_defconfig | 1 + arch/arm/configs/msm8953_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index 8caee2f09f96..cc2f39ac9381 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -145,6 +145,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index e76f0458eeb8..d98ad3a56efc 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -149,6 +149,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y -- GitLab From 057d6f1146fc04e2930c9149616a487144e25c05 Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Tue, 19 Jun 2018 18:39:09 +0530 Subject: [PATCH 850/855] defconfig: msm8937: Enable CONFIG_NETFILTER_XT_MATCH_BPF Enable bpf match support for targets with kernel 4.9 and above so that iptable command from netd (userspace module) with -m bpf doesn't fail. Change-Id: Ic14ca3d71bb73c9e3dd45a4f54cb27f9c8686b76 Signed-off-by: Devi Sandeep Endluri V V --- arch/arm/configs/msm8937-perf_defconfig | 1 + arch/arm/configs/msm8937_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index ced854d108db..2188c26e4010 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -148,6 +148,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 40d5cb156e26..258c8d773f44 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -152,6 +152,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y -- GitLab From dc89dbed6153e75906329c2e4f3d3079cfc34497 Mon Sep 17 00:00:00 2001 From: Amit Nischal Date: Wed, 20 Jun 2018 13:24:41 +0530 Subject: [PATCH 851/855] ARM: dts: msm: Populate OPP table for GFX clock on MSM8909 For GPU thermal mitigation, there is need to populate OPP table for gfx3d clock source so add support for the same. Change-Id: I36b38f6c7a8a690e303cdf844f3b2a0d467117ed Signed-off-by: Chinkit Kumar,Kirti Kumar Parmar --- arch/arm64/boot/dts/qcom/msm8909.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm8909.dtsi index 2b9c1e1122f0..32735efe802b 100644 --- a/arch/arm64/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909.dtsi @@ -353,6 +353,7 @@ reg = <0x1800000 0x80000>, <0xb016000 0x00040>; reg-names = "cc_base", "apcs_base"; + qcom,gfx3d_clk_src-opp-store-vcorner = <&msm_gpu>; vdd_dig-supply = <&pm8909_s1_corner>; vdd_sr2_dig-supply = <&pm8909_s1_corner_ao>; vdd_sr2_pll-supply = <&pm8909_l7_ao>; -- GitLab From 01e83bcde2f822c15988a1c865e24c4e31509dd2 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Wed, 20 Jun 2018 17:44:39 +0800 Subject: [PATCH 852/855] ARM: dts: msm: Remove wrong modem cpu cti for MSM8937 On msm8937, there is only one modem cpu cti. Remove the wrong modem cpu cti to fix system reset issue when do cti test. CRs-Fixed: 2263288 Change-Id: I41688a6cea50dace7ac265315cfce7938b6ce916 Signed-off-by: Mao Jinlong --- arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi index d085d2de0629..e64af14bde3a 100644 --- a/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937-coresight.dtsi @@ -973,26 +973,13 @@ clock-names = "apb_pclk"; }; - cti_modem_cpu0: cti@6128000 { - compatible = "arm,primecell"; - arm,primecell-periphid = <0x0003b966>; - - reg = <0x6128000 0x1000>; - reg-names = "cti-base"; - coresight-name = "coresight-cti-modem-cpu0"; - - clocks = <&clock_gcc clk_qdss_clk>, - <&clock_gcc clk_qdss_a_clk>; - clock-names = "apb_pclk"; - }; - - cti_modem_cpu1: cti@6124000{ + cti_modem_cpu0: cti@6124000{ compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b966>; reg = <0x6124000 0x1000>; reg-names = "cti-base"; - coresight-name = "coresight-cti-modem-cpu1"; + coresight-name = "coresight-cti-modem-cpu0"; clocks = <&clock_gcc clk_qdss_clk>, <&clock_gcc clk_qdss_a_clk>; -- GitLab From ce305983575437b837d834df1893093da0c6db63 Mon Sep 17 00:00:00 2001 From: Arulpandiyan Vadivel Date: Sat, 9 Jun 2018 17:54:14 +0530 Subject: [PATCH 853/855] defconfig: msm: Add Thermal configs for MSM8909 Enable Userspace and Low limits governor configurations. Enable CPU, Devfreq, QMI and regulator cooling device configurations. Change-Id: I52929d540b9f58af7f623a5ddeb72d0f6fb529ea Signed-off-by: Arulpandiyan Vadivel Signed-off-by: Sundara Vinayagam --- arch/arm/configs/msm8909-perf_defconfig | 8 +++++++- arch/arm/configs/msm8909_defconfig | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index b0c2adc9121c..453212e46f98 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -304,11 +304,17 @@ CONFIG_QPNP_VM_BMS=y CONFIG_QPNP_LINEAR_CHARGER=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y CONFIG_THERMAL_TSENS=y CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_MFD_QCOM_RPM=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index 9eb0afd7bffd..accc81486d6b 100644 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -305,11 +305,17 @@ CONFIG_QPNP_VM_BMS=y CONFIG_QPNP_LINEAR_CHARGER=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y CONFIG_THERMAL_TSENS=y CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_MFD_QCOM_RPM=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y -- GitLab From 7f5dee81a47b1585b06177cb9b278fa73d0d55af Mon Sep 17 00:00:00 2001 From: zhaochen Date: Fri, 15 Jun 2018 14:59:14 +0800 Subject: [PATCH 854/855] icm20602: clear up some parentheses warning in driver Icm20602 has some warning need to be clear up: warning: suggest parentheses around comparison in operand of '&' [-Wparentheses] Change-Id: I1a2e76b28aaf5a23afb141ec4d50f898da7fd267 Signed-off-by: zhaochen --- drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c index 0ebc9ab6dd46..03e96702ae0b 100644 --- a/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c @@ -224,7 +224,7 @@ int icm20602_read_raw(struct inv_icm20602_state *st, { struct struct_icm20602_raw_data raw_data; - if ((type) & (ACCEL) != 0) { + if ((type & ACCEL) != 0) { icm20602_read_reg(st, reg_set_20602.ACCEL_XOUT_H.address, &raw_data.ACCEL_XOUT_H); @@ -256,7 +256,7 @@ int icm20602_read_raw(struct inv_icm20602_state *st, raw_data.ACCEL_ZOUT_L); } - if ((type) & (GYRO) != 0) { + if ((type & GYRO) != 0) { icm20602_read_reg(st, reg_set_20602.GYRO_XOUT_H.address, &raw_data.GYRO_XOUT_H); @@ -432,7 +432,6 @@ static int icm20602_read_ST_code(struct inv_icm20602_state *st) static int icm20602_set_self_test(struct inv_icm20602_state *st) { - uint8_t raw_data[6] = {0, 0, 0, 0, 0, 0}; int result = 0; reg_set_20602.SMPLRT_DIV.reg_u.REG.SMPLRT_DIV = 0; @@ -565,7 +564,7 @@ static bool icm20602_check_acc_selftest(struct inv_icm20602_state *st, st_otp.Y = (st_otp.Y != 0) ? mpu_st_tb[acc_ST_code.Y - 1] : 0; st_otp.Z = (st_otp.Z != 0) ? mpu_st_tb[acc_ST_code.Z - 1] : 0; - if ((st_otp.X) & (st_otp.Y) & (st_otp.Z) == 0) + if ((st_otp.X & st_otp.Y & st_otp.Z) == 0) otp_value_zero = true; st_shift_cust.X = acc_st->X - acc->X; @@ -626,7 +625,7 @@ static int icm20602_check_gyro_selftest(struct inv_icm20602_state *st, st_otp.Y = (gyro_ST_code.Y != 0) ? mpu_st_tb[gyro_ST_code.Y - 1] : 0; st_otp.Z = (gyro_ST_code.Z != 0) ? mpu_st_tb[gyro_ST_code.Z - 1] : 0; - if ((st_otp.X) & (st_otp.Y) & (st_otp.Z) == 0) + if ((st_otp.X & st_otp.Y & st_otp.Z) == 0) otp_value_zero = true; st_shift_cust.X = gyro_st->X - gyro->X; -- GitLab From 3d9215630ba86257c096f5c1f42e78674f76f7d8 Mon Sep 17 00:00:00 2001 From: Chetan C R Date: Tue, 15 May 2018 18:08:38 +0530 Subject: [PATCH 855/855] audit: Checks valid value of audit_signals and tsk->audit_context There can be a case when current task's audit context may be NULL or even if it is not NULL, it can have invalid non-zero value of dummy variable and also we should audit the signal only if we have non-zero value of audit_signals. Issue has been seen during power on/off tests. So, better to add explicit check on these variables. Change-Id: I2f3e17d933fca8e3b8f4013f44f942f11c68f440 Signed-off-by: Chetan C R --- kernel/auditsc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 2cd5256dbff7..93648f6127e6 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -2252,10 +2252,11 @@ int __audit_signal_info(int sig, struct task_struct *t) audit_sig_uid = uid; security_task_getsecid(tsk, &audit_sig_sid); } - if (!audit_signals || audit_dummy_context()) - return 0; } + if (!audit_signals || audit_dummy_context()) + return 0; + /* optimize the common case by putting first signal recipient directly * in audit_context */ if (!ctx->target_pid) { -- GitLab