mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-27 09:11:49 +00:00
5357 lines
165 KiB
Diff
5357 lines
165 KiB
Diff
diff --git a/Makefile b/Makefile
|
|
index 9c60120dd9fd..71acaecd7899 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,6 +1,6 @@
|
|
VERSION = 4
|
|
PATCHLEVEL = 4
|
|
-SUBLEVEL = 115
|
|
+SUBLEVEL = 116
|
|
EXTRAVERSION =
|
|
NAME = Blurry Fish Butt
|
|
|
|
diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h
|
|
index 2b0ac429f5eb..412bb3c24f36 100644
|
|
--- a/arch/alpha/kernel/pci_impl.h
|
|
+++ b/arch/alpha/kernel/pci_impl.h
|
|
@@ -143,7 +143,8 @@ struct pci_iommu_arena
|
|
};
|
|
|
|
#if defined(CONFIG_ALPHA_SRM) && \
|
|
- (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA))
|
|
+ (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA) || \
|
|
+ defined(CONFIG_ALPHA_AVANTI))
|
|
# define NEED_SRM_SAVE_RESTORE
|
|
#else
|
|
# undef NEED_SRM_SAVE_RESTORE
|
|
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
|
|
index 84d13263ce46..8095fb2c5c94 100644
|
|
--- a/arch/alpha/kernel/process.c
|
|
+++ b/arch/alpha/kernel/process.c
|
|
@@ -273,12 +273,13 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
|
|
application calling fork. */
|
|
if (clone_flags & CLONE_SETTLS)
|
|
childti->pcb.unique = regs->r20;
|
|
+ else
|
|
+ regs->r20 = 0; /* OSF/1 has some strange fork() semantics. */
|
|
childti->pcb.usp = usp ?: rdusp();
|
|
*childregs = *regs;
|
|
childregs->r0 = 0;
|
|
childregs->r19 = 0;
|
|
childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */
|
|
- regs->r20 = 0;
|
|
stack = ((struct switch_stack *) regs) - 1;
|
|
*childstack = *stack;
|
|
childstack->r26 = (unsigned long) ret_from_fork;
|
|
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
|
|
index f36b5b1acd1f..05b2f8294968 100644
|
|
--- a/arch/arm/kvm/handle_exit.c
|
|
+++ b/arch/arm/kvm/handle_exit.c
|
|
@@ -45,7 +45,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|
|
|
ret = kvm_psci_call(vcpu);
|
|
if (ret < 0) {
|
|
- kvm_inject_undefined(vcpu);
|
|
+ vcpu_set_reg(vcpu, 0, ~0UL);
|
|
return 1;
|
|
}
|
|
|
|
@@ -54,7 +54,16 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|
|
|
static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|
{
|
|
- kvm_inject_undefined(vcpu);
|
|
+ /*
|
|
+ * "If an SMC instruction executed at Non-secure EL1 is
|
|
+ * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a
|
|
+ * Trap exception, not a Secure Monitor Call exception [...]"
|
|
+ *
|
|
+ * We need to advance the PC after the trap, as it would
|
|
+ * otherwise return to the same address...
|
|
+ */
|
|
+ vcpu_set_reg(vcpu, 0, ~0UL);
|
|
+ kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
|
|
return 1;
|
|
}
|
|
|
|
diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c
|
|
index b9920b1edd5a..70cef54dc40f 100644
|
|
--- a/arch/mn10300/mm/misalignment.c
|
|
+++ b/arch/mn10300/mm/misalignment.c
|
|
@@ -437,7 +437,7 @@ transfer_failed:
|
|
|
|
info.si_signo = SIGSEGV;
|
|
info.si_errno = 0;
|
|
- info.si_code = 0;
|
|
+ info.si_code = SEGV_MAPERR;
|
|
info.si_addr = (void *) regs->pc;
|
|
force_sig_info(SIGSEGV, &info, current);
|
|
return;
|
|
diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c
|
|
index 3d3f6062f49c..605a284922fb 100644
|
|
--- a/arch/openrisc/kernel/traps.c
|
|
+++ b/arch/openrisc/kernel/traps.c
|
|
@@ -302,12 +302,12 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)
|
|
siginfo_t info;
|
|
|
|
if (user_mode(regs)) {
|
|
- /* Send a SIGSEGV */
|
|
- info.si_signo = SIGSEGV;
|
|
+ /* Send a SIGBUS */
|
|
+ info.si_signo = SIGBUS;
|
|
info.si_errno = 0;
|
|
- /* info.si_code has been set above */
|
|
- info.si_addr = (void *)address;
|
|
- force_sig_info(SIGSEGV, &info, current);
|
|
+ info.si_code = BUS_ADRALN;
|
|
+ info.si_addr = (void __user *)address;
|
|
+ force_sig_info(SIGBUS, &info, current);
|
|
} else {
|
|
printk("KERNEL: Unaligned Access 0x%.8lx\n", address);
|
|
show_registers(regs);
|
|
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
|
|
index dfb1ee8c3e06..58a1fa979655 100644
|
|
--- a/arch/powerpc/Kconfig
|
|
+++ b/arch/powerpc/Kconfig
|
|
@@ -129,13 +129,14 @@ config PPC
|
|
select IRQ_FORCED_THREADING
|
|
select HAVE_RCU_TABLE_FREE if SMP
|
|
select HAVE_SYSCALL_TRACEPOINTS
|
|
- select HAVE_BPF_JIT
|
|
+ select HAVE_BPF_JIT if CPU_BIG_ENDIAN
|
|
select HAVE_ARCH_JUMP_LABEL
|
|
select ARCH_HAVE_NMI_SAFE_CMPXCHG
|
|
select ARCH_HAS_GCOV_PROFILE_ALL
|
|
select GENERIC_SMP_IDLE_THREAD
|
|
select GENERIC_CMOS_UPDATE
|
|
select GENERIC_TIME_VSYSCALL_OLD
|
|
+ select GENERIC_CPU_VULNERABILITIES if PPC_BOOK3S_64
|
|
select GENERIC_CLOCKEVENTS
|
|
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
|
|
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
|
|
diff --git a/arch/powerpc/include/asm/exception-64e.h b/arch/powerpc/include/asm/exception-64e.h
|
|
index a703452d67b6..555e22d5e07f 100644
|
|
--- a/arch/powerpc/include/asm/exception-64e.h
|
|
+++ b/arch/powerpc/include/asm/exception-64e.h
|
|
@@ -209,5 +209,11 @@ exc_##label##_book3e:
|
|
ori r3,r3,vector_offset@l; \
|
|
mtspr SPRN_IVOR##vector_number,r3;
|
|
|
|
+#define RFI_TO_KERNEL \
|
|
+ rfi
|
|
+
|
|
+#define RFI_TO_USER \
|
|
+ rfi
|
|
+
|
|
#endif /* _ASM_POWERPC_EXCEPTION_64E_H */
|
|
|
|
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
|
|
index 77f52b26dad6..9bddbec441b8 100644
|
|
--- a/arch/powerpc/include/asm/exception-64s.h
|
|
+++ b/arch/powerpc/include/asm/exception-64s.h
|
|
@@ -50,6 +50,59 @@
|
|
#define EX_PPR 88 /* SMT thread status register (priority) */
|
|
#define EX_CTR 96
|
|
|
|
+/*
|
|
+ * Macros for annotating the expected destination of (h)rfid
|
|
+ *
|
|
+ * The nop instructions allow us to insert one or more instructions to flush the
|
|
+ * L1-D cache when returning to userspace or a guest.
|
|
+ */
|
|
+#define RFI_FLUSH_SLOT \
|
|
+ RFI_FLUSH_FIXUP_SECTION; \
|
|
+ nop; \
|
|
+ nop; \
|
|
+ nop
|
|
+
|
|
+#define RFI_TO_KERNEL \
|
|
+ rfid
|
|
+
|
|
+#define RFI_TO_USER \
|
|
+ RFI_FLUSH_SLOT; \
|
|
+ rfid; \
|
|
+ b rfi_flush_fallback
|
|
+
|
|
+#define RFI_TO_USER_OR_KERNEL \
|
|
+ RFI_FLUSH_SLOT; \
|
|
+ rfid; \
|
|
+ b rfi_flush_fallback
|
|
+
|
|
+#define RFI_TO_GUEST \
|
|
+ RFI_FLUSH_SLOT; \
|
|
+ rfid; \
|
|
+ b rfi_flush_fallback
|
|
+
|
|
+#define HRFI_TO_KERNEL \
|
|
+ hrfid
|
|
+
|
|
+#define HRFI_TO_USER \
|
|
+ RFI_FLUSH_SLOT; \
|
|
+ hrfid; \
|
|
+ b hrfi_flush_fallback
|
|
+
|
|
+#define HRFI_TO_USER_OR_KERNEL \
|
|
+ RFI_FLUSH_SLOT; \
|
|
+ hrfid; \
|
|
+ b hrfi_flush_fallback
|
|
+
|
|
+#define HRFI_TO_GUEST \
|
|
+ RFI_FLUSH_SLOT; \
|
|
+ hrfid; \
|
|
+ b hrfi_flush_fallback
|
|
+
|
|
+#define HRFI_TO_UNKNOWN \
|
|
+ RFI_FLUSH_SLOT; \
|
|
+ hrfid; \
|
|
+ b hrfi_flush_fallback
|
|
+
|
|
#ifdef CONFIG_RELOCATABLE
|
|
#define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \
|
|
ld r12,PACAKBASE(r13); /* get high part of &label */ \
|
|
@@ -191,7 +244,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
|
|
mtspr SPRN_##h##SRR0,r12; \
|
|
mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \
|
|
mtspr SPRN_##h##SRR1,r10; \
|
|
- h##rfid; \
|
|
+ h##RFI_TO_KERNEL; \
|
|
b . /* prevent speculative execution */
|
|
#define EXCEPTION_PROLOG_PSERIES_1(label, h) \
|
|
__EXCEPTION_PROLOG_PSERIES_1(label, h)
|
|
diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h
|
|
index 9a67a38bf7b9..7068bafbb2d6 100644
|
|
--- a/arch/powerpc/include/asm/feature-fixups.h
|
|
+++ b/arch/powerpc/include/asm/feature-fixups.h
|
|
@@ -184,4 +184,19 @@ label##3: \
|
|
FTR_ENTRY_OFFSET label##1b-label##3b; \
|
|
.popsection;
|
|
|
|
+#define RFI_FLUSH_FIXUP_SECTION \
|
|
+951: \
|
|
+ .pushsection __rfi_flush_fixup,"a"; \
|
|
+ .align 2; \
|
|
+952: \
|
|
+ FTR_ENTRY_OFFSET 951b-952b; \
|
|
+ .popsection;
|
|
+
|
|
+
|
|
+#ifndef __ASSEMBLY__
|
|
+
|
|
+extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup;
|
|
+
|
|
+#endif
|
|
+
|
|
#endif /* __ASM_POWERPC_FEATURE_FIXUPS_H */
|
|
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
|
|
index 85bc8c0d257b..449bbb87c257 100644
|
|
--- a/arch/powerpc/include/asm/hvcall.h
|
|
+++ b/arch/powerpc/include/asm/hvcall.h
|
|
@@ -239,6 +239,7 @@
|
|
#define H_GET_HCA_INFO 0x1B8
|
|
#define H_GET_PERF_COUNT 0x1BC
|
|
#define H_MANAGE_TRACE 0x1C0
|
|
+#define H_GET_CPU_CHARACTERISTICS 0x1C8
|
|
#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
|
|
#define H_QUERY_INT_STATE 0x1E4
|
|
#define H_POLL_PENDING 0x1D8
|
|
@@ -285,7 +286,19 @@
|
|
#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE 3
|
|
#define H_SET_MODE_RESOURCE_LE 4
|
|
|
|
+/* H_GET_CPU_CHARACTERISTICS return values */
|
|
+#define H_CPU_CHAR_SPEC_BAR_ORI31 (1ull << 63) // IBM bit 0
|
|
+#define H_CPU_CHAR_BCCTRL_SERIALISED (1ull << 62) // IBM bit 1
|
|
+#define H_CPU_CHAR_L1D_FLUSH_ORI30 (1ull << 61) // IBM bit 2
|
|
+#define H_CPU_CHAR_L1D_FLUSH_TRIG2 (1ull << 60) // IBM bit 3
|
|
+#define H_CPU_CHAR_L1D_THREAD_PRIV (1ull << 59) // IBM bit 4
|
|
+
|
|
+#define H_CPU_BEHAV_FAVOUR_SECURITY (1ull << 63) // IBM bit 0
|
|
+#define H_CPU_BEHAV_L1D_FLUSH_PR (1ull << 62) // IBM bit 1
|
|
+#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR (1ull << 61) // IBM bit 2
|
|
+
|
|
#ifndef __ASSEMBLY__
|
|
+#include <linux/types.h>
|
|
|
|
/**
|
|
* plpar_hcall_norets: - Make a pseries hypervisor call with no return arguments
|
|
@@ -423,6 +436,11 @@ extern long pseries_big_endian_exceptions(void);
|
|
|
|
#endif /* CONFIG_PPC_PSERIES */
|
|
|
|
+struct h_cpu_char_result {
|
|
+ u64 character;
|
|
+ u64 behaviour;
|
|
+};
|
|
+
|
|
#endif /* __ASSEMBLY__ */
|
|
#endif /* __KERNEL__ */
|
|
#endif /* _ASM_POWERPC_HVCALL_H */
|
|
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
|
|
index 70bd4381f8e6..45e2aefece16 100644
|
|
--- a/arch/powerpc/include/asm/paca.h
|
|
+++ b/arch/powerpc/include/asm/paca.h
|
|
@@ -192,6 +192,16 @@ struct paca_struct {
|
|
#endif
|
|
struct kvmppc_host_state kvm_hstate;
|
|
#endif
|
|
+#ifdef CONFIG_PPC_BOOK3S_64
|
|
+ /*
|
|
+ * rfi fallback flush must be in its own cacheline to prevent
|
|
+ * other paca data leaking into the L1d
|
|
+ */
|
|
+ u64 exrfi[13] __aligned(0x80);
|
|
+ void *rfi_flush_fallback_area;
|
|
+ u64 l1d_flush_congruence;
|
|
+ u64 l1d_flush_sets;
|
|
+#endif
|
|
};
|
|
|
|
extern struct paca_struct *paca;
|
|
diff --git a/arch/powerpc/include/asm/plpar_wrappers.h b/arch/powerpc/include/asm/plpar_wrappers.h
|
|
index 67859edbf8fd..6e05cb397a5c 100644
|
|
--- a/arch/powerpc/include/asm/plpar_wrappers.h
|
|
+++ b/arch/powerpc/include/asm/plpar_wrappers.h
|
|
@@ -323,4 +323,18 @@ static inline long plapr_set_watchpoint0(unsigned long dawr0, unsigned long dawr
|
|
return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_DAWR, dawr0, dawrx0);
|
|
}
|
|
|
|
+static inline long plpar_get_cpu_characteristics(struct h_cpu_char_result *p)
|
|
+{
|
|
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
|
|
+ long rc;
|
|
+
|
|
+ rc = plpar_hcall(H_GET_CPU_CHARACTERISTICS, retbuf);
|
|
+ if (rc == H_SUCCESS) {
|
|
+ p->character = retbuf[0];
|
|
+ p->behaviour = retbuf[1];
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
#endif /* _ASM_POWERPC_PLPAR_WRAPPERS_H */
|
|
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
|
|
index dd0fc18d8103..160bb2311bbb 100644
|
|
--- a/arch/powerpc/include/asm/ppc_asm.h
|
|
+++ b/arch/powerpc/include/asm/ppc_asm.h
|
|
@@ -224,6 +224,16 @@ name: \
|
|
.globl name; \
|
|
name:
|
|
|
|
+#define _KPROBE_TOC(name) \
|
|
+ .section ".kprobes.text","a"; \
|
|
+ .align 2 ; \
|
|
+ .type name,@function; \
|
|
+ .globl name; \
|
|
+name: \
|
|
+0: addis r2,r12,(.TOC.-0b)@ha; \
|
|
+ addi r2,r2,(.TOC.-0b)@l; \
|
|
+ .localentry name,.-name
|
|
+
|
|
#define DOTSYM(a) a
|
|
|
|
#else
|
|
@@ -261,6 +271,8 @@ name: \
|
|
.type GLUE(.,name),@function; \
|
|
GLUE(.,name):
|
|
|
|
+#define _KPROBE_TOC(n) _KPROBE(n)
|
|
+
|
|
#define DOTSYM(a) GLUE(.,a)
|
|
|
|
#endif
|
|
diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h
|
|
index e9d384cbd021..7916b56f2e60 100644
|
|
--- a/arch/powerpc/include/asm/setup.h
|
|
+++ b/arch/powerpc/include/asm/setup.h
|
|
@@ -26,6 +26,19 @@ void initmem_init(void);
|
|
void setup_panic(void);
|
|
#define ARCH_PANIC_TIMEOUT 180
|
|
|
|
+void rfi_flush_enable(bool enable);
|
|
+
|
|
+/* These are bit flags */
|
|
+enum l1d_flush_type {
|
|
+ L1D_FLUSH_NONE = 0x1,
|
|
+ L1D_FLUSH_FALLBACK = 0x2,
|
|
+ L1D_FLUSH_ORI = 0x4,
|
|
+ L1D_FLUSH_MTTRIG = 0x8,
|
|
+};
|
|
+
|
|
+void __init setup_rfi_flush(enum l1d_flush_type, bool enable);
|
|
+void do_rfi_flush_fixups(enum l1d_flush_type types);
|
|
+
|
|
#endif /* !__ASSEMBLY__ */
|
|
|
|
#endif /* _ASM_POWERPC_SETUP_H */
|
|
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
|
|
index 40da69163d51..d92705e3a0c1 100644
|
|
--- a/arch/powerpc/kernel/asm-offsets.c
|
|
+++ b/arch/powerpc/kernel/asm-offsets.c
|
|
@@ -243,6 +243,10 @@ int main(void)
|
|
#ifdef CONFIG_PPC_BOOK3S_64
|
|
DEFINE(PACAMCEMERGSP, offsetof(struct paca_struct, mc_emergency_sp));
|
|
DEFINE(PACA_IN_MCE, offsetof(struct paca_struct, in_mce));
|
|
+ DEFINE(PACA_RFI_FLUSH_FALLBACK_AREA, offsetof(struct paca_struct, rfi_flush_fallback_area));
|
|
+ DEFINE(PACA_EXRFI, offsetof(struct paca_struct, exrfi));
|
|
+ DEFINE(PACA_L1D_FLUSH_CONGRUENCE, offsetof(struct paca_struct, l1d_flush_congruence));
|
|
+ DEFINE(PACA_L1D_FLUSH_SETS, offsetof(struct paca_struct, l1d_flush_sets));
|
|
#endif
|
|
DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
|
|
DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state));
|
|
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
|
|
index f6fd0332c3a2..2837232bbffb 100644
|
|
--- a/arch/powerpc/kernel/entry_64.S
|
|
+++ b/arch/powerpc/kernel/entry_64.S
|
|
@@ -36,6 +36,11 @@
|
|
#include <asm/hw_irq.h>
|
|
#include <asm/context_tracking.h>
|
|
#include <asm/tm.h>
|
|
+#ifdef CONFIG_PPC_BOOK3S
|
|
+#include <asm/exception-64s.h>
|
|
+#else
|
|
+#include <asm/exception-64e.h>
|
|
+#endif
|
|
|
|
/*
|
|
* System calls.
|
|
@@ -225,13 +230,23 @@ END_FTR_SECTION_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
|
|
ACCOUNT_CPU_USER_EXIT(r11, r12)
|
|
HMT_MEDIUM_LOW_HAS_PPR
|
|
ld r13,GPR13(r1) /* only restore r13 if returning to usermode */
|
|
+ ld r2,GPR2(r1)
|
|
+ ld r1,GPR1(r1)
|
|
+ mtlr r4
|
|
+ mtcr r5
|
|
+ mtspr SPRN_SRR0,r7
|
|
+ mtspr SPRN_SRR1,r8
|
|
+ RFI_TO_USER
|
|
+ b . /* prevent speculative execution */
|
|
+
|
|
+ /* exit to kernel */
|
|
1: ld r2,GPR2(r1)
|
|
ld r1,GPR1(r1)
|
|
mtlr r4
|
|
mtcr r5
|
|
mtspr SPRN_SRR0,r7
|
|
mtspr SPRN_SRR1,r8
|
|
- RFI
|
|
+ RFI_TO_KERNEL
|
|
b . /* prevent speculative execution */
|
|
|
|
syscall_error:
|
|
@@ -353,8 +368,7 @@ tabort_syscall:
|
|
mtmsrd r10, 1
|
|
mtspr SPRN_SRR0, r11
|
|
mtspr SPRN_SRR1, r12
|
|
-
|
|
- rfid
|
|
+ RFI_TO_USER
|
|
b . /* prevent speculative execution */
|
|
#endif
|
|
|
|
@@ -887,7 +901,7 @@ BEGIN_FTR_SECTION
|
|
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
|
|
ACCOUNT_CPU_USER_EXIT(r2, r4)
|
|
REST_GPR(13, r1)
|
|
-1:
|
|
+
|
|
mtspr SPRN_SRR1,r3
|
|
|
|
ld r2,_CCR(r1)
|
|
@@ -900,8 +914,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
|
|
ld r3,GPR3(r1)
|
|
ld r4,GPR4(r1)
|
|
ld r1,GPR1(r1)
|
|
+ RFI_TO_USER
|
|
+ b . /* prevent speculative execution */
|
|
|
|
- rfid
|
|
+1: mtspr SPRN_SRR1,r3
|
|
+
|
|
+ ld r2,_CCR(r1)
|
|
+ mtcrf 0xFF,r2
|
|
+ ld r2,_NIP(r1)
|
|
+ mtspr SPRN_SRR0,r2
|
|
+
|
|
+ ld r0,GPR0(r1)
|
|
+ ld r2,GPR2(r1)
|
|
+ ld r3,GPR3(r1)
|
|
+ ld r4,GPR4(r1)
|
|
+ ld r1,GPR1(r1)
|
|
+ RFI_TO_KERNEL
|
|
b . /* prevent speculative execution */
|
|
|
|
#endif /* CONFIG_PPC_BOOK3E */
|
|
@@ -1077,7 +1105,7 @@ _GLOBAL(enter_rtas)
|
|
|
|
mtspr SPRN_SRR0,r5
|
|
mtspr SPRN_SRR1,r6
|
|
- rfid
|
|
+ RFI_TO_KERNEL
|
|
b . /* prevent speculative execution */
|
|
|
|
rtas_return_loc:
|
|
@@ -1102,7 +1130,7 @@ rtas_return_loc:
|
|
|
|
mtspr SPRN_SRR0,r3
|
|
mtspr SPRN_SRR1,r4
|
|
- rfid
|
|
+ RFI_TO_KERNEL
|
|
b . /* prevent speculative execution */
|
|
|
|
.align 3
|
|
@@ -1173,7 +1201,7 @@ _GLOBAL(enter_prom)
|
|
LOAD_REG_IMMEDIATE(r12, MSR_SF | MSR_ISF | MSR_LE)
|
|
andc r11,r11,r12
|
|
mtsrr1 r11
|
|
- rfid
|
|
+ RFI_TO_KERNEL
|
|
#endif /* CONFIG_PPC_BOOK3E */
|
|
|
|
1: /* Return from OF */
|
|
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
|
|
index b81ccc5fb32d..938a30fef031 100644
|
|
--- a/arch/powerpc/kernel/exceptions-64s.S
|
|
+++ b/arch/powerpc/kernel/exceptions-64s.S
|
|
@@ -46,7 +46,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \
|
|
mtspr SPRN_SRR0,r10 ; \
|
|
ld r10,PACAKMSR(r13) ; \
|
|
mtspr SPRN_SRR1,r10 ; \
|
|
- rfid ; \
|
|
+ RFI_TO_KERNEL ; \
|
|
b . ; /* prevent speculative execution */
|
|
|
|
#define SYSCALL_PSERIES_3 \
|
|
@@ -54,7 +54,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \
|
|
1: mfspr r12,SPRN_SRR1 ; \
|
|
xori r12,r12,MSR_LE ; \
|
|
mtspr SPRN_SRR1,r12 ; \
|
|
- rfid ; /* return to userspace */ \
|
|
+ RFI_TO_USER ; /* return to userspace */ \
|
|
b . ; /* prevent speculative execution */
|
|
|
|
#if defined(CONFIG_RELOCATABLE)
|
|
@@ -507,7 +507,7 @@ BEGIN_FTR_SECTION
|
|
LOAD_HANDLER(r12, machine_check_handle_early)
|
|
1: mtspr SPRN_SRR0,r12
|
|
mtspr SPRN_SRR1,r11
|
|
- rfid
|
|
+ RFI_TO_KERNEL
|
|
b . /* prevent speculative execution */
|
|
2:
|
|
/* Stack overflow. Stay on emergency stack and panic.
|
|
@@ -601,7 +601,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
|
|
ld r11,PACA_EXGEN+EX_R11(r13)
|
|
ld r12,PACA_EXGEN+EX_R12(r13)
|
|
ld r13,PACA_EXGEN+EX_R13(r13)
|
|
- HRFID
|
|
+ HRFI_TO_UNKNOWN
|
|
b .
|
|
#endif
|
|
|
|
@@ -666,7 +666,7 @@ masked_##_H##interrupt: \
|
|
ld r10,PACA_EXGEN+EX_R10(r13); \
|
|
ld r11,PACA_EXGEN+EX_R11(r13); \
|
|
GET_SCRATCH0(r13); \
|
|
- ##_H##rfid; \
|
|
+ ##_H##RFI_TO_KERNEL; \
|
|
b .
|
|
|
|
MASKED_INTERRUPT()
|
|
@@ -756,7 +756,7 @@ kvmppc_skip_interrupt:
|
|
addi r13, r13, 4
|
|
mtspr SPRN_SRR0, r13
|
|
GET_SCRATCH0(r13)
|
|
- rfid
|
|
+ RFI_TO_KERNEL
|
|
b .
|
|
|
|
kvmppc_skip_Hinterrupt:
|
|
@@ -768,7 +768,7 @@ kvmppc_skip_Hinterrupt:
|
|
addi r13, r13, 4
|
|
mtspr SPRN_HSRR0, r13
|
|
GET_SCRATCH0(r13)
|
|
- hrfid
|
|
+ HRFI_TO_KERNEL
|
|
b .
|
|
#endif
|
|
|
|
@@ -1439,7 +1439,7 @@ machine_check_handle_early:
|
|
li r3,MSR_ME
|
|
andc r10,r10,r3 /* Turn off MSR_ME */
|
|
mtspr SPRN_SRR1,r10
|
|
- rfid
|
|
+ RFI_TO_KERNEL
|
|
b .
|
|
2:
|
|
/*
|
|
@@ -1457,7 +1457,7 @@ machine_check_handle_early:
|
|
*/
|
|
bl machine_check_queue_event
|
|
MACHINE_CHECK_HANDLER_WINDUP
|
|
- rfid
|
|
+ RFI_TO_USER_OR_KERNEL
|
|
9:
|
|
/* Deliver the machine check to host kernel in V mode. */
|
|
MACHINE_CHECK_HANDLER_WINDUP
|
|
@@ -1503,6 +1503,8 @@ slb_miss_realmode:
|
|
|
|
andi. r10,r12,MSR_RI /* check for unrecoverable exception */
|
|
beq- 2f
|
|
+ andi. r10,r12,MSR_PR /* check for user mode (PR != 0) */
|
|
+ bne 1f
|
|
|
|
.machine push
|
|
.machine "power4"
|
|
@@ -1516,7 +1518,23 @@ slb_miss_realmode:
|
|
ld r11,PACA_EXSLB+EX_R11(r13)
|
|
ld r12,PACA_EXSLB+EX_R12(r13)
|
|
ld r13,PACA_EXSLB+EX_R13(r13)
|
|
- rfid
|
|
+ RFI_TO_KERNEL
|
|
+ b . /* prevent speculative execution */
|
|
+
|
|
+1:
|
|
+.machine push
|
|
+.machine "power4"
|
|
+ mtcrf 0x80,r9
|
|
+ mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */
|
|
+.machine pop
|
|
+
|
|
+ RESTORE_PPR_PACA(PACA_EXSLB, r9)
|
|
+ ld r9,PACA_EXSLB+EX_R9(r13)
|
|
+ ld r10,PACA_EXSLB+EX_R10(r13)
|
|
+ ld r11,PACA_EXSLB+EX_R11(r13)
|
|
+ ld r12,PACA_EXSLB+EX_R12(r13)
|
|
+ ld r13,PACA_EXSLB+EX_R13(r13)
|
|
+ RFI_TO_USER
|
|
b . /* prevent speculative execution */
|
|
|
|
2: mfspr r11,SPRN_SRR0
|
|
@@ -1525,7 +1543,7 @@ slb_miss_realmode:
|
|
mtspr SPRN_SRR0,r10
|
|
ld r10,PACAKMSR(r13)
|
|
mtspr SPRN_SRR1,r10
|
|
- rfid
|
|
+ RFI_TO_KERNEL
|
|
b .
|
|
|
|
unrecov_slb:
|
|
@@ -1546,6 +1564,92 @@ power4_fixup_nap:
|
|
blr
|
|
#endif
|
|
|
|
+ .globl rfi_flush_fallback
|
|
+rfi_flush_fallback:
|
|
+ SET_SCRATCH0(r13);
|
|
+ GET_PACA(r13);
|
|
+ std r9,PACA_EXRFI+EX_R9(r13)
|
|
+ std r10,PACA_EXRFI+EX_R10(r13)
|
|
+ std r11,PACA_EXRFI+EX_R11(r13)
|
|
+ std r12,PACA_EXRFI+EX_R12(r13)
|
|
+ std r8,PACA_EXRFI+EX_R13(r13)
|
|
+ mfctr r9
|
|
+ ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13)
|
|
+ ld r11,PACA_L1D_FLUSH_SETS(r13)
|
|
+ ld r12,PACA_L1D_FLUSH_CONGRUENCE(r13)
|
|
+ /*
|
|
+ * The load adresses are at staggered offsets within cachelines,
|
|
+ * which suits some pipelines better (on others it should not
|
|
+ * hurt).
|
|
+ */
|
|
+ addi r12,r12,8
|
|
+ mtctr r11
|
|
+ DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */
|
|
+
|
|
+ /* order ld/st prior to dcbt stop all streams with flushing */
|
|
+ sync
|
|
+1: li r8,0
|
|
+ .rept 8 /* 8-way set associative */
|
|
+ ldx r11,r10,r8
|
|
+ add r8,r8,r12
|
|
+ xor r11,r11,r11 // Ensure r11 is 0 even if fallback area is not
|
|
+ add r8,r8,r11 // Add 0, this creates a dependency on the ldx
|
|
+ .endr
|
|
+ addi r10,r10,128 /* 128 byte cache line */
|
|
+ bdnz 1b
|
|
+
|
|
+ mtctr r9
|
|
+ ld r9,PACA_EXRFI+EX_R9(r13)
|
|
+ ld r10,PACA_EXRFI+EX_R10(r13)
|
|
+ ld r11,PACA_EXRFI+EX_R11(r13)
|
|
+ ld r12,PACA_EXRFI+EX_R12(r13)
|
|
+ ld r8,PACA_EXRFI+EX_R13(r13)
|
|
+ GET_SCRATCH0(r13);
|
|
+ rfid
|
|
+
|
|
+ .globl hrfi_flush_fallback
|
|
+hrfi_flush_fallback:
|
|
+ SET_SCRATCH0(r13);
|
|
+ GET_PACA(r13);
|
|
+ std r9,PACA_EXRFI+EX_R9(r13)
|
|
+ std r10,PACA_EXRFI+EX_R10(r13)
|
|
+ std r11,PACA_EXRFI+EX_R11(r13)
|
|
+ std r12,PACA_EXRFI+EX_R12(r13)
|
|
+ std r8,PACA_EXRFI+EX_R13(r13)
|
|
+ mfctr r9
|
|
+ ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13)
|
|
+ ld r11,PACA_L1D_FLUSH_SETS(r13)
|
|
+ ld r12,PACA_L1D_FLUSH_CONGRUENCE(r13)
|
|
+ /*
|
|
+ * The load adresses are at staggered offsets within cachelines,
|
|
+ * which suits some pipelines better (on others it should not
|
|
+ * hurt).
|
|
+ */
|
|
+ addi r12,r12,8
|
|
+ mtctr r11
|
|
+ DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */
|
|
+
|
|
+ /* order ld/st prior to dcbt stop all streams with flushing */
|
|
+ sync
|
|
+1: li r8,0
|
|
+ .rept 8 /* 8-way set associative */
|
|
+ ldx r11,r10,r8
|
|
+ add r8,r8,r12
|
|
+ xor r11,r11,r11 // Ensure r11 is 0 even if fallback area is not
|
|
+ add r8,r8,r11 // Add 0, this creates a dependency on the ldx
|
|
+ .endr
|
|
+ addi r10,r10,128 /* 128 byte cache line */
|
|
+ bdnz 1b
|
|
+
|
|
+ mtctr r9
|
|
+ ld r9,PACA_EXRFI+EX_R9(r13)
|
|
+ ld r10,PACA_EXRFI+EX_R10(r13)
|
|
+ ld r11,PACA_EXRFI+EX_R11(r13)
|
|
+ ld r12,PACA_EXRFI+EX_R12(r13)
|
|
+ ld r8,PACA_EXRFI+EX_R13(r13)
|
|
+ GET_SCRATCH0(r13);
|
|
+ hrfid
|
|
+
|
|
/*
|
|
* Hash table stuff
|
|
*/
|
|
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
|
|
index db475d41b57a..107588295b39 100644
|
|
--- a/arch/powerpc/kernel/misc_64.S
|
|
+++ b/arch/powerpc/kernel/misc_64.S
|
|
@@ -66,7 +66,7 @@ PPC64_CACHES:
|
|
* flush all bytes from start through stop-1 inclusive
|
|
*/
|
|
|
|
-_KPROBE(flush_icache_range)
|
|
+_KPROBE_TOC(flush_icache_range)
|
|
BEGIN_FTR_SECTION
|
|
PURGE_PREFETCHED_INS
|
|
blr
|
|
@@ -117,7 +117,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
|
|
*
|
|
* flush all bytes from start to stop-1 inclusive
|
|
*/
|
|
-_GLOBAL(flush_dcache_range)
|
|
+_GLOBAL_TOC(flush_dcache_range)
|
|
|
|
/*
|
|
* Flush the data cache to memory
|
|
@@ -701,31 +701,3 @@ _GLOBAL(kexec_sequence)
|
|
li r5,0
|
|
blr /* image->start(physid, image->start, 0); */
|
|
#endif /* CONFIG_KEXEC */
|
|
-
|
|
-#ifdef CONFIG_MODULES
|
|
-#if defined(_CALL_ELF) && _CALL_ELF == 2
|
|
-
|
|
-#ifdef CONFIG_MODVERSIONS
|
|
-.weak __crc_TOC.
|
|
-.section "___kcrctab+TOC.","a"
|
|
-.globl __kcrctab_TOC.
|
|
-__kcrctab_TOC.:
|
|
- .llong __crc_TOC.
|
|
-#endif
|
|
-
|
|
-/*
|
|
- * Export a fake .TOC. since both modpost and depmod will complain otherwise.
|
|
- * Both modpost and depmod strip the leading . so we do the same here.
|
|
- */
|
|
-.section "__ksymtab_strings","a"
|
|
-__kstrtab_TOC.:
|
|
- .asciz "TOC."
|
|
-
|
|
-.section "___ksymtab+TOC.","a"
|
|
-/* This symbol name is important: it's used by modpost to find exported syms */
|
|
-.globl __ksymtab_TOC.
|
|
-__ksymtab_TOC.:
|
|
- .llong 0 /* .value */
|
|
- .llong __kstrtab_TOC.
|
|
-#endif /* ELFv2 */
|
|
-#endif /* MODULES */
|
|
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
|
|
index e4f7d4eed20c..08b7a40de5f8 100644
|
|
--- a/arch/powerpc/kernel/module_64.c
|
|
+++ b/arch/powerpc/kernel/module_64.c
|
|
@@ -326,7 +326,10 @@ static void dedotify_versions(struct modversion_info *vers,
|
|
}
|
|
}
|
|
|
|
-/* Undefined symbols which refer to .funcname, hack to funcname (or .TOC.) */
|
|
+/*
|
|
+ * Undefined symbols which refer to .funcname, hack to funcname. Make .TOC.
|
|
+ * seem to be defined (value set later).
|
|
+ */
|
|
static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab)
|
|
{
|
|
unsigned int i;
|
|
@@ -334,8 +337,11 @@ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab)
|
|
for (i = 1; i < numsyms; i++) {
|
|
if (syms[i].st_shndx == SHN_UNDEF) {
|
|
char *name = strtab + syms[i].st_name;
|
|
- if (name[0] == '.')
|
|
+ if (name[0] == '.') {
|
|
+ if (strcmp(name+1, "TOC.") == 0)
|
|
+ syms[i].st_shndx = SHN_ABS;
|
|
syms[i].st_name++;
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
@@ -351,7 +357,7 @@ static Elf64_Sym *find_dot_toc(Elf64_Shdr *sechdrs,
|
|
numsyms = sechdrs[symindex].sh_size / sizeof(Elf64_Sym);
|
|
|
|
for (i = 1; i < numsyms; i++) {
|
|
- if (syms[i].st_shndx == SHN_UNDEF
|
|
+ if (syms[i].st_shndx == SHN_ABS
|
|
&& strcmp(strtab + syms[i].st_name, "TOC.") == 0)
|
|
return &syms[i];
|
|
}
|
|
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
|
|
index cf788d7d7e56..a9b10812cbfd 100644
|
|
--- a/arch/powerpc/kernel/process.c
|
|
+++ b/arch/powerpc/kernel/process.c
|
|
@@ -209,7 +209,8 @@ void enable_kernel_vsx(void)
|
|
WARN_ON(preemptible());
|
|
|
|
#ifdef CONFIG_SMP
|
|
- if (current->thread.regs && (current->thread.regs->msr & MSR_VSX))
|
|
+ if (current->thread.regs &&
|
|
+ (current->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP)))
|
|
giveup_vsx(current);
|
|
else
|
|
giveup_vsx(NULL); /* just enable vsx for kernel - force */
|
|
@@ -231,7 +232,7 @@ void flush_vsx_to_thread(struct task_struct *tsk)
|
|
{
|
|
if (tsk->thread.regs) {
|
|
preempt_disable();
|
|
- if (tsk->thread.regs->msr & MSR_VSX) {
|
|
+ if (tsk->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP)) {
|
|
#ifdef CONFIG_SMP
|
|
BUG_ON(tsk != current);
|
|
#endif
|
|
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
|
|
index a20823210ac0..df4a87eb8da4 100644
|
|
--- a/arch/powerpc/kernel/setup_64.c
|
|
+++ b/arch/powerpc/kernel/setup_64.c
|
|
@@ -38,6 +38,7 @@
|
|
#include <linux/hugetlb.h>
|
|
#include <linux/memory.h>
|
|
#include <linux/nmi.h>
|
|
+#include <linux/debugfs.h>
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/kdump.h>
|
|
@@ -834,4 +835,142 @@ static int __init disable_hardlockup_detector(void)
|
|
return 0;
|
|
}
|
|
early_initcall(disable_hardlockup_detector);
|
|
+
|
|
+#ifdef CONFIG_PPC_BOOK3S_64
|
|
+static enum l1d_flush_type enabled_flush_types;
|
|
+static void *l1d_flush_fallback_area;
|
|
+static bool no_rfi_flush;
|
|
+bool rfi_flush;
|
|
+
|
|
+static int __init handle_no_rfi_flush(char *p)
|
|
+{
|
|
+ pr_info("rfi-flush: disabled on command line.");
|
|
+ no_rfi_flush = true;
|
|
+ return 0;
|
|
+}
|
|
+early_param("no_rfi_flush", handle_no_rfi_flush);
|
|
+
|
|
+/*
|
|
+ * The RFI flush is not KPTI, but because users will see doco that says to use
|
|
+ * nopti we hijack that option here to also disable the RFI flush.
|
|
+ */
|
|
+static int __init handle_no_pti(char *p)
|
|
+{
|
|
+ pr_info("rfi-flush: disabling due to 'nopti' on command line.\n");
|
|
+ handle_no_rfi_flush(NULL);
|
|
+ return 0;
|
|
+}
|
|
+early_param("nopti", handle_no_pti);
|
|
+
|
|
+static void do_nothing(void *unused)
|
|
+{
|
|
+ /*
|
|
+ * We don't need to do the flush explicitly, just enter+exit kernel is
|
|
+ * sufficient, the RFI exit handlers will do the right thing.
|
|
+ */
|
|
+}
|
|
+
|
|
+void rfi_flush_enable(bool enable)
|
|
+{
|
|
+ if (rfi_flush == enable)
|
|
+ return;
|
|
+
|
|
+ if (enable) {
|
|
+ do_rfi_flush_fixups(enabled_flush_types);
|
|
+ on_each_cpu(do_nothing, NULL, 1);
|
|
+ } else
|
|
+ do_rfi_flush_fixups(L1D_FLUSH_NONE);
|
|
+
|
|
+ rfi_flush = enable;
|
|
+}
|
|
+
|
|
+static void init_fallback_flush(void)
|
|
+{
|
|
+ u64 l1d_size, limit;
|
|
+ int cpu;
|
|
+
|
|
+ l1d_size = ppc64_caches.dsize;
|
|
+ limit = min(safe_stack_limit(), ppc64_rma_size);
|
|
+
|
|
+ /*
|
|
+ * Align to L1d size, and size it at 2x L1d size, to catch possible
|
|
+ * hardware prefetch runoff. We don't have a recipe for load patterns to
|
|
+ * reliably avoid the prefetcher.
|
|
+ */
|
|
+ l1d_flush_fallback_area = __va(memblock_alloc_base(l1d_size * 2, l1d_size, limit));
|
|
+ memset(l1d_flush_fallback_area, 0, l1d_size * 2);
|
|
+
|
|
+ for_each_possible_cpu(cpu) {
|
|
+ /*
|
|
+ * The fallback flush is currently coded for 8-way
|
|
+ * associativity. Different associativity is possible, but it
|
|
+ * will be treated as 8-way and may not evict the lines as
|
|
+ * effectively.
|
|
+ *
|
|
+ * 128 byte lines are mandatory.
|
|
+ */
|
|
+ u64 c = l1d_size / 8;
|
|
+
|
|
+ paca[cpu].rfi_flush_fallback_area = l1d_flush_fallback_area;
|
|
+ paca[cpu].l1d_flush_congruence = c;
|
|
+ paca[cpu].l1d_flush_sets = c / 128;
|
|
+ }
|
|
+}
|
|
+
|
|
+void __init setup_rfi_flush(enum l1d_flush_type types, bool enable)
|
|
+{
|
|
+ if (types & L1D_FLUSH_FALLBACK) {
|
|
+ pr_info("rfi-flush: Using fallback displacement flush\n");
|
|
+ init_fallback_flush();
|
|
+ }
|
|
+
|
|
+ if (types & L1D_FLUSH_ORI)
|
|
+ pr_info("rfi-flush: Using ori type flush\n");
|
|
+
|
|
+ if (types & L1D_FLUSH_MTTRIG)
|
|
+ pr_info("rfi-flush: Using mttrig type flush\n");
|
|
+
|
|
+ enabled_flush_types = types;
|
|
+
|
|
+ if (!no_rfi_flush)
|
|
+ rfi_flush_enable(enable);
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_DEBUG_FS
|
|
+static int rfi_flush_set(void *data, u64 val)
|
|
+{
|
|
+ if (val == 1)
|
|
+ rfi_flush_enable(true);
|
|
+ else if (val == 0)
|
|
+ rfi_flush_enable(false);
|
|
+ else
|
|
+ return -EINVAL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int rfi_flush_get(void *data, u64 *val)
|
|
+{
|
|
+ *val = rfi_flush ? 1 : 0;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+DEFINE_SIMPLE_ATTRIBUTE(fops_rfi_flush, rfi_flush_get, rfi_flush_set, "%llu\n");
|
|
+
|
|
+static __init int rfi_flush_debugfs_init(void)
|
|
+{
|
|
+ debugfs_create_file("rfi_flush", 0600, powerpc_debugfs_root, NULL, &fops_rfi_flush);
|
|
+ return 0;
|
|
+}
|
|
+device_initcall(rfi_flush_debugfs_init);
|
|
+#endif
|
|
+
|
|
+ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ if (rfi_flush)
|
|
+ return sprintf(buf, "Mitigation: RFI Flush\n");
|
|
+
|
|
+ return sprintf(buf, "Vulnerable\n");
|
|
+}
|
|
+#endif /* CONFIG_PPC_BOOK3S_64 */
|
|
#endif
|
|
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
|
|
index d41fd0af8980..072a23a17350 100644
|
|
--- a/arch/powerpc/kernel/vmlinux.lds.S
|
|
+++ b/arch/powerpc/kernel/vmlinux.lds.S
|
|
@@ -72,6 +72,15 @@ SECTIONS
|
|
/* Read-only data */
|
|
RODATA
|
|
|
|
+#ifdef CONFIG_PPC64
|
|
+ . = ALIGN(8);
|
|
+ __rfi_flush_fixup : AT(ADDR(__rfi_flush_fixup) - LOAD_OFFSET) {
|
|
+ __start___rfi_flush_fixup = .;
|
|
+ *(__rfi_flush_fixup)
|
|
+ __stop___rfi_flush_fixup = .;
|
|
+ }
|
|
+#endif
|
|
+
|
|
EXCEPTION_TABLE(0)
|
|
|
|
NOTES :kernel :notes
|
|
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
|
|
index ffab9269bfe4..4463718ae614 100644
|
|
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
|
|
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
|
|
@@ -64,7 +64,7 @@ _GLOBAL_TOC(kvmppc_hv_entry_trampoline)
|
|
mtmsrd r0,1 /* clear RI in MSR */
|
|
mtsrr0 r5
|
|
mtsrr1 r6
|
|
- RFI
|
|
+ RFI_TO_KERNEL
|
|
|
|
kvmppc_call_hv_entry:
|
|
ld r4, HSTATE_KVM_VCPU(r13)
|
|
@@ -170,7 +170,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
|
|
mtsrr0 r8
|
|
mtsrr1 r7
|
|
beq cr1, 13f /* machine check */
|
|
- RFI
|
|
+ RFI_TO_KERNEL
|
|
|
|
/* On POWER7, we have external interrupts set to use HSRR0/1 */
|
|
11: mtspr SPRN_HSRR0, r8
|
|
@@ -965,8 +965,7 @@ BEGIN_FTR_SECTION
|
|
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
|
|
ld r0, VCPU_GPR(R0)(r4)
|
|
ld r4, VCPU_GPR(R4)(r4)
|
|
-
|
|
- hrfid
|
|
+ HRFI_TO_GUEST
|
|
b .
|
|
|
|
secondary_too_late:
|
|
diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S
|
|
index 16c4d88ba27d..a328f99a887c 100644
|
|
--- a/arch/powerpc/kvm/book3s_rmhandlers.S
|
|
+++ b/arch/powerpc/kvm/book3s_rmhandlers.S
|
|
@@ -46,6 +46,9 @@
|
|
|
|
#define FUNC(name) name
|
|
|
|
+#define RFI_TO_KERNEL RFI
|
|
+#define RFI_TO_GUEST RFI
|
|
+
|
|
.macro INTERRUPT_TRAMPOLINE intno
|
|
|
|
.global kvmppc_trampoline_\intno
|
|
@@ -141,7 +144,7 @@ kvmppc_handler_skip_ins:
|
|
GET_SCRATCH0(r13)
|
|
|
|
/* And get back into the code */
|
|
- RFI
|
|
+ RFI_TO_KERNEL
|
|
#endif
|
|
|
|
/*
|
|
@@ -164,6 +167,6 @@ _GLOBAL_TOC(kvmppc_entry_trampoline)
|
|
ori r5, r5, MSR_EE
|
|
mtsrr0 r7
|
|
mtsrr1 r6
|
|
- RFI
|
|
+ RFI_TO_KERNEL
|
|
|
|
#include "book3s_segment.S"
|
|
diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S
|
|
index ca8f174289bb..7c982956d709 100644
|
|
--- a/arch/powerpc/kvm/book3s_segment.S
|
|
+++ b/arch/powerpc/kvm/book3s_segment.S
|
|
@@ -156,7 +156,7 @@ no_dcbz32_on:
|
|
PPC_LL r9, SVCPU_R9(r3)
|
|
PPC_LL r3, (SVCPU_R3)(r3)
|
|
|
|
- RFI
|
|
+ RFI_TO_GUEST
|
|
kvmppc_handler_trampoline_enter_end:
|
|
|
|
|
|
@@ -389,5 +389,5 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
|
|
cmpwi r12, BOOK3S_INTERRUPT_DOORBELL
|
|
beqa BOOK3S_INTERRUPT_DOORBELL
|
|
|
|
- RFI
|
|
+ RFI_TO_KERNEL
|
|
kvmppc_handler_trampoline_exit_end:
|
|
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
|
|
index 7ce3870d7ddd..a18d648d31a6 100644
|
|
--- a/arch/powerpc/lib/feature-fixups.c
|
|
+++ b/arch/powerpc/lib/feature-fixups.c
|
|
@@ -20,6 +20,7 @@
|
|
#include <asm/code-patching.h>
|
|
#include <asm/page.h>
|
|
#include <asm/sections.h>
|
|
+#include <asm/setup.h>
|
|
|
|
|
|
struct fixup_entry {
|
|
@@ -113,6 +114,47 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
|
|
}
|
|
}
|
|
|
|
+#ifdef CONFIG_PPC_BOOK3S_64
|
|
+void do_rfi_flush_fixups(enum l1d_flush_type types)
|
|
+{
|
|
+ unsigned int instrs[3], *dest;
|
|
+ long *start, *end;
|
|
+ int i;
|
|
+
|
|
+ start = PTRRELOC(&__start___rfi_flush_fixup),
|
|
+ end = PTRRELOC(&__stop___rfi_flush_fixup);
|
|
+
|
|
+ instrs[0] = 0x60000000; /* nop */
|
|
+ instrs[1] = 0x60000000; /* nop */
|
|
+ instrs[2] = 0x60000000; /* nop */
|
|
+
|
|
+ if (types & L1D_FLUSH_FALLBACK)
|
|
+ /* b .+16 to fallback flush */
|
|
+ instrs[0] = 0x48000010;
|
|
+
|
|
+ i = 0;
|
|
+ if (types & L1D_FLUSH_ORI) {
|
|
+ instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
|
|
+ instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
|
|
+ }
|
|
+
|
|
+ if (types & L1D_FLUSH_MTTRIG)
|
|
+ instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
|
|
+
|
|
+ for (i = 0; start < end; start++, i++) {
|
|
+ dest = (void *)start + *start;
|
|
+
|
|
+ pr_devel("patching dest %lx\n", (unsigned long)dest);
|
|
+
|
|
+ patch_instruction(dest, instrs[0]);
|
|
+ patch_instruction(dest + 1, instrs[1]);
|
|
+ patch_instruction(dest + 2, instrs[2]);
|
|
+ }
|
|
+
|
|
+ printk(KERN_DEBUG "rfi-flush: patched %d locations\n", i);
|
|
+}
|
|
+#endif /* CONFIG_PPC_BOOK3S_64 */
|
|
+
|
|
void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
|
|
{
|
|
long *start, *end;
|
|
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
|
|
index f48afc06ba14..30c6b3b7be90 100644
|
|
--- a/arch/powerpc/platforms/powernv/setup.c
|
|
+++ b/arch/powerpc/platforms/powernv/setup.c
|
|
@@ -35,13 +35,63 @@
|
|
#include <asm/opal.h>
|
|
#include <asm/kexec.h>
|
|
#include <asm/smp.h>
|
|
+#include <asm/tm.h>
|
|
+#include <asm/setup.h>
|
|
|
|
#include "powernv.h"
|
|
|
|
+static void pnv_setup_rfi_flush(void)
|
|
+{
|
|
+ struct device_node *np, *fw_features;
|
|
+ enum l1d_flush_type type;
|
|
+ int enable;
|
|
+
|
|
+ /* Default to fallback in case fw-features are not available */
|
|
+ type = L1D_FLUSH_FALLBACK;
|
|
+ enable = 1;
|
|
+
|
|
+ np = of_find_node_by_name(NULL, "ibm,opal");
|
|
+ fw_features = of_get_child_by_name(np, "fw-features");
|
|
+ of_node_put(np);
|
|
+
|
|
+ if (fw_features) {
|
|
+ np = of_get_child_by_name(fw_features, "inst-l1d-flush-trig2");
|
|
+ if (np && of_property_read_bool(np, "enabled"))
|
|
+ type = L1D_FLUSH_MTTRIG;
|
|
+
|
|
+ of_node_put(np);
|
|
+
|
|
+ np = of_get_child_by_name(fw_features, "inst-l1d-flush-ori30,30,0");
|
|
+ if (np && of_property_read_bool(np, "enabled"))
|
|
+ type = L1D_FLUSH_ORI;
|
|
+
|
|
+ of_node_put(np);
|
|
+
|
|
+ /* Enable unless firmware says NOT to */
|
|
+ enable = 2;
|
|
+ np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-hv-1-to-0");
|
|
+ if (np && of_property_read_bool(np, "disabled"))
|
|
+ enable--;
|
|
+
|
|
+ of_node_put(np);
|
|
+
|
|
+ np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-pr-0-to-1");
|
|
+ if (np && of_property_read_bool(np, "disabled"))
|
|
+ enable--;
|
|
+
|
|
+ of_node_put(np);
|
|
+ of_node_put(fw_features);
|
|
+ }
|
|
+
|
|
+ setup_rfi_flush(type, enable > 0);
|
|
+}
|
|
+
|
|
static void __init pnv_setup_arch(void)
|
|
{
|
|
set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
|
|
|
|
+ pnv_setup_rfi_flush();
|
|
+
|
|
/* Initialize SMP */
|
|
pnv_smp_init();
|
|
|
|
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
|
|
index 36df46eaba24..dd2545fc9947 100644
|
|
--- a/arch/powerpc/platforms/pseries/setup.c
|
|
+++ b/arch/powerpc/platforms/pseries/setup.c
|
|
@@ -499,6 +499,39 @@ static void __init find_and_init_phbs(void)
|
|
of_pci_check_probe_only();
|
|
}
|
|
|
|
+static void pseries_setup_rfi_flush(void)
|
|
+{
|
|
+ struct h_cpu_char_result result;
|
|
+ enum l1d_flush_type types;
|
|
+ bool enable;
|
|
+ long rc;
|
|
+
|
|
+ /* Enable by default */
|
|
+ enable = true;
|
|
+
|
|
+ rc = plpar_get_cpu_characteristics(&result);
|
|
+ if (rc == H_SUCCESS) {
|
|
+ types = L1D_FLUSH_NONE;
|
|
+
|
|
+ if (result.character & H_CPU_CHAR_L1D_FLUSH_TRIG2)
|
|
+ types |= L1D_FLUSH_MTTRIG;
|
|
+ if (result.character & H_CPU_CHAR_L1D_FLUSH_ORI30)
|
|
+ types |= L1D_FLUSH_ORI;
|
|
+
|
|
+ /* Use fallback if nothing set in hcall */
|
|
+ if (types == L1D_FLUSH_NONE)
|
|
+ types = L1D_FLUSH_FALLBACK;
|
|
+
|
|
+ if (!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR))
|
|
+ enable = false;
|
|
+ } else {
|
|
+ /* Default to fallback if case hcall is not available */
|
|
+ types = L1D_FLUSH_FALLBACK;
|
|
+ }
|
|
+
|
|
+ setup_rfi_flush(types, enable);
|
|
+}
|
|
+
|
|
static void __init pSeries_setup_arch(void)
|
|
{
|
|
set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
|
|
@@ -515,7 +548,9 @@ static void __init pSeries_setup_arch(void)
|
|
|
|
fwnmi_init();
|
|
|
|
- /* By default, only probe PCI (can be overriden by rtas_pci) */
|
|
+ pseries_setup_rfi_flush();
|
|
+
|
|
+ /* By default, only probe PCI (can be overridden by rtas_pci) */
|
|
pci_add_flags(PCI_PROBE_ONLY);
|
|
|
|
/* Find and initialize PCI host bridges */
|
|
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
|
|
index ff639342a8be..c5b997757988 100644
|
|
--- a/arch/sh/kernel/traps_32.c
|
|
+++ b/arch/sh/kernel/traps_32.c
|
|
@@ -607,7 +607,8 @@ asmlinkage void do_divide_error(unsigned long r4)
|
|
break;
|
|
}
|
|
|
|
- force_sig_info(SIGFPE, &info, current);
|
|
+ info.si_signo = SIGFPE;
|
|
+ force_sig_info(info.si_signo, &info, current);
|
|
}
|
|
#endif
|
|
|
|
diff --git a/arch/x86/crypto/poly1305_glue.c b/arch/x86/crypto/poly1305_glue.c
|
|
index 4264a3d59589..7c064887b783 100644
|
|
--- a/arch/x86/crypto/poly1305_glue.c
|
|
+++ b/arch/x86/crypto/poly1305_glue.c
|
|
@@ -164,7 +164,6 @@ static struct shash_alg alg = {
|
|
.init = poly1305_simd_init,
|
|
.update = poly1305_simd_update,
|
|
.final = crypto_poly1305_final,
|
|
- .setkey = crypto_poly1305_setkey,
|
|
.descsize = sizeof(struct poly1305_simd_desc_ctx),
|
|
.base = {
|
|
.cra_name = "poly1305",
|
|
diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h
|
|
index b9c6c7a6f5a6..1c79c8add0eb 100644
|
|
--- a/arch/x86/include/asm/asm.h
|
|
+++ b/arch/x86/include/asm/asm.h
|
|
@@ -11,10 +11,12 @@
|
|
# define __ASM_FORM_COMMA(x) " " #x ","
|
|
#endif
|
|
|
|
-#ifdef CONFIG_X86_32
|
|
+#ifndef __x86_64__
|
|
+/* 32 bit */
|
|
# define __ASM_SEL(a,b) __ASM_FORM(a)
|
|
# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a)
|
|
#else
|
|
+/* 64 bit */
|
|
# define __ASM_SEL(a,b) __ASM_FORM(b)
|
|
# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b)
|
|
#endif
|
|
diff --git a/arch/x86/include/asm/vsyscall.h b/arch/x86/include/asm/vsyscall.h
|
|
index 9ee85066f407..62210da19a92 100644
|
|
--- a/arch/x86/include/asm/vsyscall.h
|
|
+++ b/arch/x86/include/asm/vsyscall.h
|
|
@@ -13,7 +13,6 @@ extern void map_vsyscall(void);
|
|
*/
|
|
extern bool emulate_vsyscall(struct pt_regs *regs, unsigned long address);
|
|
extern bool vsyscall_enabled(void);
|
|
-extern unsigned long vsyscall_pgprot;
|
|
#else
|
|
static inline void map_vsyscall(void) {}
|
|
static inline bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
|
|
@@ -22,5 +21,6 @@ static inline bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
|
|
}
|
|
static inline bool vsyscall_enabled(void) { return false; }
|
|
#endif
|
|
+extern unsigned long vsyscall_pgprot;
|
|
|
|
#endif /* _ASM_X86_VSYSCALL_H */
|
|
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
|
|
index b3e94ef461fd..ce5f8a2e7ae6 100644
|
|
--- a/arch/x86/kernel/cpu/microcode/core.c
|
|
+++ b/arch/x86/kernel/cpu/microcode/core.c
|
|
@@ -44,7 +44,7 @@
|
|
|
|
static struct microcode_ops *microcode_ops;
|
|
|
|
-static bool dis_ucode_ldr;
|
|
+static bool dis_ucode_ldr = true;
|
|
|
|
static int __init disable_loader(char *str)
|
|
{
|
|
@@ -81,6 +81,7 @@ struct cpu_info_ctx {
|
|
|
|
static bool __init check_loader_disabled_bsp(void)
|
|
{
|
|
+ u32 a, b, c, d;
|
|
#ifdef CONFIG_X86_32
|
|
const char *cmdline = (const char *)__pa_nodebug(boot_command_line);
|
|
const char *opt = "dis_ucode_ldr";
|
|
@@ -93,8 +94,20 @@ static bool __init check_loader_disabled_bsp(void)
|
|
bool *res = &dis_ucode_ldr;
|
|
#endif
|
|
|
|
- if (cmdline_find_option_bool(cmdline, option))
|
|
- *res = true;
|
|
+ a = 1;
|
|
+ c = 0;
|
|
+ native_cpuid(&a, &b, &c, &d);
|
|
+
|
|
+ /*
|
|
+ * CPUID(1).ECX[31]: reserved for hypervisor use. This is still not
|
|
+ * completely accurate as xen pv guests don't see that CPUID bit set but
|
|
+ * that's good enough as they don't land on the BSP path anyway.
|
|
+ */
|
|
+ if (c & BIT(31))
|
|
+ return *res;
|
|
+
|
|
+ if (cmdline_find_option_bool(cmdline, option) <= 0)
|
|
+ *res = false;
|
|
|
|
return *res;
|
|
}
|
|
@@ -122,9 +135,7 @@ void __init load_ucode_bsp(void)
|
|
{
|
|
int vendor;
|
|
unsigned int family;
|
|
-
|
|
- if (check_loader_disabled_bsp())
|
|
- return;
|
|
+ bool intel = true;
|
|
|
|
if (!have_cpuid_p())
|
|
return;
|
|
@@ -134,16 +145,27 @@ void __init load_ucode_bsp(void)
|
|
|
|
switch (vendor) {
|
|
case X86_VENDOR_INTEL:
|
|
- if (family >= 6)
|
|
- load_ucode_intel_bsp();
|
|
+ if (family < 6)
|
|
+ return;
|
|
break;
|
|
+
|
|
case X86_VENDOR_AMD:
|
|
- if (family >= 0x10)
|
|
- load_ucode_amd_bsp(family);
|
|
+ if (family < 0x10)
|
|
+ return;
|
|
+ intel = false;
|
|
break;
|
|
+
|
|
default:
|
|
- break;
|
|
+ return;
|
|
}
|
|
+
|
|
+ if (check_loader_disabled_bsp())
|
|
+ return;
|
|
+
|
|
+ if (intel)
|
|
+ load_ucode_intel_bsp();
|
|
+ else
|
|
+ load_ucode_amd_bsp(family);
|
|
}
|
|
|
|
static bool check_loader_disabled_ap(void)
|
|
@@ -162,9 +184,6 @@ void load_ucode_ap(void)
|
|
if (check_loader_disabled_ap())
|
|
return;
|
|
|
|
- if (!have_cpuid_p())
|
|
- return;
|
|
-
|
|
vendor = x86_vendor();
|
|
family = x86_family();
|
|
|
|
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
|
|
index f8d785aa2e96..2a1a8737015b 100644
|
|
--- a/arch/x86/kvm/vmx.c
|
|
+++ b/arch/x86/kvm/vmx.c
|
|
@@ -4595,14 +4595,15 @@ static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
|
|
|
|
if (is_guest_mode(vcpu) &&
|
|
vector == vmx->nested.posted_intr_nv) {
|
|
- /* the PIR and ON have been set by L1. */
|
|
- kvm_vcpu_trigger_posted_interrupt(vcpu);
|
|
/*
|
|
* If a posted intr is not recognized by hardware,
|
|
* we will accomplish it in the next vmentry.
|
|
*/
|
|
vmx->nested.pi_pending = true;
|
|
kvm_make_request(KVM_REQ_EVENT, vcpu);
|
|
+ /* the PIR and ON have been set by L1. */
|
|
+ if (!kvm_vcpu_trigger_posted_interrupt(vcpu))
|
|
+ kvm_vcpu_kick(vcpu);
|
|
return 0;
|
|
}
|
|
return -1;
|
|
diff --git a/arch/x86/mm/kaiser.c b/arch/x86/mm/kaiser.c
|
|
index 2298434f7bdb..7a72e32e4806 100644
|
|
--- a/arch/x86/mm/kaiser.c
|
|
+++ b/arch/x86/mm/kaiser.c
|
|
@@ -363,7 +363,7 @@ void __init kaiser_init(void)
|
|
kaiser_add_user_map_ptrs_early(__entry_text_start, __entry_text_end,
|
|
__PAGE_KERNEL_RX);
|
|
|
|
-#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN)
|
|
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
|
kaiser_add_user_map_ptrs_early(__irqentry_text_start,
|
|
__irqentry_text_end,
|
|
__PAGE_KERNEL_RX);
|
|
diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h
|
|
index b39531babec0..72bfc1cbc2b5 100644
|
|
--- a/arch/xtensa/include/asm/futex.h
|
|
+++ b/arch/xtensa/include/asm/futex.h
|
|
@@ -109,7 +109,6 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
|
|
u32 oldval, u32 newval)
|
|
{
|
|
int ret = 0;
|
|
- u32 prev;
|
|
|
|
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
return -EFAULT;
|
|
@@ -120,26 +119,24 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
|
|
|
|
__asm__ __volatile__ (
|
|
" # futex_atomic_cmpxchg_inatomic\n"
|
|
- "1: l32i %1, %3, 0\n"
|
|
- " mov %0, %5\n"
|
|
- " wsr %1, scompare1\n"
|
|
- "2: s32c1i %0, %3, 0\n"
|
|
- "3:\n"
|
|
+ " wsr %5, scompare1\n"
|
|
+ "1: s32c1i %1, %4, 0\n"
|
|
+ " s32i %1, %6, 0\n"
|
|
+ "2:\n"
|
|
" .section .fixup,\"ax\"\n"
|
|
" .align 4\n"
|
|
- "4: .long 3b\n"
|
|
- "5: l32r %1, 4b\n"
|
|
- " movi %0, %6\n"
|
|
+ "3: .long 2b\n"
|
|
+ "4: l32r %1, 3b\n"
|
|
+ " movi %0, %7\n"
|
|
" jx %1\n"
|
|
" .previous\n"
|
|
" .section __ex_table,\"a\"\n"
|
|
- " .long 1b,5b,2b,5b\n"
|
|
+ " .long 1b,4b\n"
|
|
" .previous\n"
|
|
- : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
|
|
- : "r" (uaddr), "r" (oldval), "r" (newval), "I" (-EFAULT)
|
|
+ : "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval)
|
|
+ : "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT)
|
|
: "memory");
|
|
|
|
- *uval = prev;
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/crypto/ahash.c b/crypto/ahash.c
|
|
index f9caf0f74199..7006dbfd39bd 100644
|
|
--- a/crypto/ahash.c
|
|
+++ b/crypto/ahash.c
|
|
@@ -637,5 +637,16 @@ struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask)
|
|
}
|
|
EXPORT_SYMBOL_GPL(ahash_attr_alg);
|
|
|
|
+bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg)
|
|
+{
|
|
+ struct crypto_alg *alg = &halg->base;
|
|
+
|
|
+ if (alg->cra_type != &crypto_ahash_type)
|
|
+ return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg));
|
|
+
|
|
+ return __crypto_ahash_alg(alg)->setkey != NULL;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey);
|
|
+
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
|
|
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
|
|
index 26a504db3f53..10a5a3eb675a 100644
|
|
--- a/crypto/cryptd.c
|
|
+++ b/crypto/cryptd.c
|
|
@@ -654,7 +654,8 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb,
|
|
inst->alg.finup = cryptd_hash_finup_enqueue;
|
|
inst->alg.export = cryptd_hash_export;
|
|
inst->alg.import = cryptd_hash_import;
|
|
- inst->alg.setkey = cryptd_hash_setkey;
|
|
+ if (crypto_shash_alg_has_setkey(salg))
|
|
+ inst->alg.setkey = cryptd_hash_setkey;
|
|
inst->alg.digest = cryptd_hash_digest_enqueue;
|
|
|
|
err = ahash_register_instance(tmpl, inst);
|
|
diff --git a/crypto/poly1305_generic.c b/crypto/poly1305_generic.c
|
|
index 2df9835dfbc0..bca99238948f 100644
|
|
--- a/crypto/poly1305_generic.c
|
|
+++ b/crypto/poly1305_generic.c
|
|
@@ -51,17 +51,6 @@ int crypto_poly1305_init(struct shash_desc *desc)
|
|
}
|
|
EXPORT_SYMBOL_GPL(crypto_poly1305_init);
|
|
|
|
-int crypto_poly1305_setkey(struct crypto_shash *tfm,
|
|
- const u8 *key, unsigned int keylen)
|
|
-{
|
|
- /* Poly1305 requires a unique key for each tag, which implies that
|
|
- * we can't set it on the tfm that gets accessed by multiple users
|
|
- * simultaneously. Instead we expect the key as the first 32 bytes in
|
|
- * the update() call. */
|
|
- return -ENOTSUPP;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(crypto_poly1305_setkey);
|
|
-
|
|
static void poly1305_setrkey(struct poly1305_desc_ctx *dctx, const u8 *key)
|
|
{
|
|
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
|
|
@@ -80,6 +69,11 @@ static void poly1305_setskey(struct poly1305_desc_ctx *dctx, const u8 *key)
|
|
dctx->s[3] = le32_to_cpuvp(key + 12);
|
|
}
|
|
|
|
+/*
|
|
+ * Poly1305 requires a unique key for each tag, which implies that we can't set
|
|
+ * it on the tfm that gets accessed by multiple users simultaneously. Instead we
|
|
+ * expect the key as the first 32 bytes in the update() call.
|
|
+ */
|
|
unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
|
|
const u8 *src, unsigned int srclen)
|
|
{
|
|
@@ -285,7 +279,6 @@ static struct shash_alg poly1305_alg = {
|
|
.init = crypto_poly1305_init,
|
|
.update = crypto_poly1305_update,
|
|
.final = crypto_poly1305_final,
|
|
- .setkey = crypto_poly1305_setkey,
|
|
.descsize = sizeof(struct poly1305_desc_ctx),
|
|
.base = {
|
|
.cra_name = "poly1305",
|
|
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
|
|
index f522828d45c9..1d92b5d2d6bd 100644
|
|
--- a/crypto/tcrypt.c
|
|
+++ b/crypto/tcrypt.c
|
|
@@ -291,11 +291,13 @@ static void sg_init_aead(struct scatterlist *sg, char *xbuf[XBUFSIZE],
|
|
}
|
|
|
|
sg_init_table(sg, np + 1);
|
|
- np--;
|
|
+ if (rem)
|
|
+ np--;
|
|
for (k = 0; k < np; k++)
|
|
sg_set_buf(&sg[k + 1], xbuf[k], PAGE_SIZE);
|
|
|
|
- sg_set_buf(&sg[k + 1], xbuf[k], rem);
|
|
+ if (rem)
|
|
+ sg_set_buf(&sg[k + 1], xbuf[k], rem);
|
|
}
|
|
|
|
static void test_aead_speed(const char *algo, int enc, unsigned int secs,
|
|
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
|
|
index 2fa8304171e0..7a3431018e0a 100644
|
|
--- a/drivers/acpi/sbshc.c
|
|
+++ b/drivers/acpi/sbshc.c
|
|
@@ -275,8 +275,8 @@ static int acpi_smbus_hc_add(struct acpi_device *device)
|
|
device->driver_data = hc;
|
|
|
|
acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc);
|
|
- printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n",
|
|
- hc->ec, hc->offset, hc->query_bit);
|
|
+ dev_info(&device->dev, "SBS HC: offset = 0x%0x, query_bit = 0x%0x\n",
|
|
+ hc->offset, hc->query_bit);
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
|
|
index 60a15831c009..8ddf5d5c94fd 100644
|
|
--- a/drivers/ata/ahci.c
|
|
+++ b/drivers/ata/ahci.c
|
|
@@ -260,9 +260,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
|
{ PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
|
|
- { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
|
|
+ { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH M AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
|
|
- { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
|
|
+ { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH M RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */
|
|
@@ -285,9 +285,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
|
{ PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
|
|
- { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
|
|
+ { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT M AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
|
|
- { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */
|
|
+ { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT M RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
|
|
@@ -296,20 +296,20 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
|
{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
|
|
- { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */
|
|
+ { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point M AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
|
|
- { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
|
|
+ { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point M RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */
|
|
- { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */
|
|
+ { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point M AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */
|
|
- { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */
|
|
+ { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point M RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */
|
|
- { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */
|
|
+ { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point M RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
|
|
- { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */
|
|
+ { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point M RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */
|
|
@@ -350,21 +350,21 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
|
{ PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */
|
|
- { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */
|
|
+ { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series M AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */
|
|
- { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */
|
|
+ { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series M RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */
|
|
- { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
|
|
+ { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series M RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
|
|
- { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
|
|
+ { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series M RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
|
|
{ PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */
|
|
- { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
|
|
+ { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H M AHCI */
|
|
{ PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
|
|
{ PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */
|
|
- { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
|
|
+ { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H M RAID */
|
|
{ PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
|
|
{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
|
|
{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/
|
|
@@ -382,6 +382,11 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
|
{ PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/
|
|
{ PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
|
|
{ PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
|
|
+ { PCI_VDEVICE(INTEL, 0xa356), board_ahci }, /* Cannon Lake PCH-H RAID */
|
|
+ { PCI_VDEVICE(INTEL, 0x0f22), board_ahci }, /* Bay Trail AHCI */
|
|
+ { PCI_VDEVICE(INTEL, 0x0f23), board_ahci }, /* Bay Trail AHCI */
|
|
+ { PCI_VDEVICE(INTEL, 0x22a3), board_ahci }, /* Cherry Trail AHCI */
|
|
+ { PCI_VDEVICE(INTEL, 0x5ae3), board_ahci }, /* Apollo Lake AHCI */
|
|
|
|
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
|
|
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
|
|
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
|
|
index d06c62eccdf0..156968a6655d 100644
|
|
--- a/drivers/block/pktcdvd.c
|
|
+++ b/drivers/block/pktcdvd.c
|
|
@@ -2779,7 +2779,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
|
|
pd->pkt_dev = MKDEV(pktdev_major, idx);
|
|
ret = pkt_new_dev(pd, dev);
|
|
if (ret)
|
|
- goto out_new_dev;
|
|
+ goto out_mem2;
|
|
|
|
/* inherit events of the host device */
|
|
disk->events = pd->bdev->bd_disk->events;
|
|
@@ -2797,8 +2797,6 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
|
|
mutex_unlock(&ctl_mutex);
|
|
return 0;
|
|
|
|
-out_new_dev:
|
|
- blk_cleanup_queue(disk->queue);
|
|
out_mem2:
|
|
put_disk(disk);
|
|
out_mem:
|
|
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
|
|
index 7b624423a7e8..89ccb604045c 100644
|
|
--- a/drivers/bluetooth/btsdio.c
|
|
+++ b/drivers/bluetooth/btsdio.c
|
|
@@ -31,6 +31,7 @@
|
|
#include <linux/errno.h>
|
|
#include <linux/skbuff.h>
|
|
|
|
+#include <linux/mmc/host.h>
|
|
#include <linux/mmc/sdio_ids.h>
|
|
#include <linux/mmc/sdio_func.h>
|
|
|
|
@@ -291,6 +292,14 @@ static int btsdio_probe(struct sdio_func *func,
|
|
tuple = tuple->next;
|
|
}
|
|
|
|
+ /* BCM43341 devices soldered onto the PCB (non-removable) use an
|
|
+ * uart connection for bluetooth, ignore the BT SDIO interface.
|
|
+ */
|
|
+ if (func->vendor == SDIO_VENDOR_ID_BROADCOM &&
|
|
+ func->device == SDIO_DEVICE_ID_BROADCOM_43341 &&
|
|
+ !mmc_card_is_removable(func->card->host))
|
|
+ return -ENODEV;
|
|
+
|
|
data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
|
|
if (!data)
|
|
return -ENOMEM;
|
|
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
|
|
index 1ccad79ce77c..54cef3dc0beb 100644
|
|
--- a/drivers/bluetooth/btusb.c
|
|
+++ b/drivers/bluetooth/btusb.c
|
|
@@ -23,6 +23,7 @@
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/usb.h>
|
|
+#include <linux/usb/quirks.h>
|
|
#include <linux/firmware.h>
|
|
#include <asm/unaligned.h>
|
|
|
|
@@ -360,8 +361,8 @@ static const struct usb_device_id blacklist_table[] = {
|
|
#define BTUSB_FIRMWARE_LOADED 7
|
|
#define BTUSB_FIRMWARE_FAILED 8
|
|
#define BTUSB_BOOTING 9
|
|
-#define BTUSB_RESET_RESUME 10
|
|
-#define BTUSB_DIAG_RUNNING 11
|
|
+#define BTUSB_DIAG_RUNNING 10
|
|
+#define BTUSB_OOB_WAKE_ENABLED 11
|
|
|
|
struct btusb_data {
|
|
struct hci_dev *hdev;
|
|
@@ -2972,9 +2973,9 @@ static int btusb_probe(struct usb_interface *intf,
|
|
|
|
/* QCA Rome devices lose their updated firmware over suspend,
|
|
* but the USB hub doesn't notice any status change.
|
|
- * Explicitly request a device reset on resume.
|
|
+ * explicitly request a device reset on resume.
|
|
*/
|
|
- set_bit(BTUSB_RESET_RESUME, &data->flags);
|
|
+ interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
|
|
}
|
|
|
|
#ifdef CONFIG_BT_HCIBTUSB_RTL
|
|
@@ -2985,7 +2986,7 @@ static int btusb_probe(struct usb_interface *intf,
|
|
* but the USB hub doesn't notice any status change.
|
|
* Explicitly request a device reset on resume.
|
|
*/
|
|
- set_bit(BTUSB_RESET_RESUME, &data->flags);
|
|
+ interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
|
|
}
|
|
#endif
|
|
|
|
@@ -3142,14 +3143,6 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
|
|
btusb_stop_traffic(data);
|
|
usb_kill_anchored_urbs(&data->tx_anchor);
|
|
|
|
- /* Optionally request a device reset on resume, but only when
|
|
- * wakeups are disabled. If wakeups are enabled we assume the
|
|
- * device will stay powered up throughout suspend.
|
|
- */
|
|
- if (test_bit(BTUSB_RESET_RESUME, &data->flags) &&
|
|
- !device_may_wakeup(&data->udev->dev))
|
|
- data->udev->reset_resume = 1;
|
|
-
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
|
|
index 53e61459c69f..ee87eb77095c 100644
|
|
--- a/drivers/crypto/caam/ctrl.c
|
|
+++ b/drivers/crypto/caam/ctrl.c
|
|
@@ -224,12 +224,16 @@ static int instantiate_rng(struct device *ctrldev, int state_handle_mask,
|
|
* without any error (HW optimizations for later
|
|
* CAAM eras), then try again.
|
|
*/
|
|
+ if (ret)
|
|
+ break;
|
|
+
|
|
rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
|
|
if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) ||
|
|
- !(rdsta_val & (1 << sh_idx)))
|
|
+ !(rdsta_val & (1 << sh_idx))) {
|
|
ret = -EAGAIN;
|
|
- if (ret)
|
|
break;
|
|
+ }
|
|
+
|
|
dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx);
|
|
/* Clear the contents before recreating the descriptor */
|
|
memset(desc, 0x00, CAAM_CMD_SZ * 7);
|
|
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
|
|
index 7254c20007f8..6796eb1a8a4c 100644
|
|
--- a/drivers/dma/dmatest.c
|
|
+++ b/drivers/dma/dmatest.c
|
|
@@ -329,7 +329,7 @@ static void dmatest_callback(void *arg)
|
|
{
|
|
struct dmatest_done *done = arg;
|
|
struct dmatest_thread *thread =
|
|
- container_of(arg, struct dmatest_thread, done_wait);
|
|
+ container_of(done, struct dmatest_thread, test_done);
|
|
if (!thread->done) {
|
|
done->done = true;
|
|
wake_up_all(done->wait);
|
|
diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c
|
|
index cda6dab5067a..6b65a102b49d 100644
|
|
--- a/drivers/edac/octeon_edac-lmc.c
|
|
+++ b/drivers/edac/octeon_edac-lmc.c
|
|
@@ -79,6 +79,7 @@ static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci)
|
|
if (!pvt->inject)
|
|
int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx));
|
|
else {
|
|
+ int_reg.u64 = 0;
|
|
if (pvt->error_type == 1)
|
|
int_reg.s.sec_err = 1;
|
|
if (pvt->error_type == 2)
|
|
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
|
|
index 9befd624a5f0..6fab07935d16 100644
|
|
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
|
|
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
|
|
@@ -371,6 +371,31 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
|
|
rcrtc->started = true;
|
|
}
|
|
|
|
+static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc)
|
|
+{
|
|
+ struct rcar_du_device *rcdu = rcrtc->group->dev;
|
|
+ struct drm_crtc *crtc = &rcrtc->crtc;
|
|
+ u32 status;
|
|
+ /* Make sure vblank interrupts are enabled. */
|
|
+ drm_crtc_vblank_get(crtc);
|
|
+ /*
|
|
+ * Disable planes and calculate how many vertical blanking interrupts we
|
|
+ * have to wait for. If a vertical blanking interrupt has been triggered
|
|
+ * but not processed yet, we don't know whether it occurred before or
|
|
+ * after the planes got disabled. We thus have to wait for two vblank
|
|
+ * interrupts in that case.
|
|
+ */
|
|
+ spin_lock_irq(&rcrtc->vblank_lock);
|
|
+ rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
|
|
+ status = rcar_du_crtc_read(rcrtc, DSSR);
|
|
+ rcrtc->vblank_count = status & DSSR_VBK ? 2 : 1;
|
|
+ spin_unlock_irq(&rcrtc->vblank_lock);
|
|
+ if (!wait_event_timeout(rcrtc->vblank_wait, rcrtc->vblank_count == 0,
|
|
+ msecs_to_jiffies(100)))
|
|
+ dev_warn(rcdu->dev, "vertical blanking timeout\n");
|
|
+ drm_crtc_vblank_put(crtc);
|
|
+}
|
|
+
|
|
static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
|
|
{
|
|
struct drm_crtc *crtc = &rcrtc->crtc;
|
|
@@ -379,17 +404,16 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
|
|
return;
|
|
|
|
/* Disable all planes and wait for the change to take effect. This is
|
|
- * required as the DSnPR registers are updated on vblank, and no vblank
|
|
- * will occur once the CRTC is stopped. Disabling planes when starting
|
|
- * the CRTC thus wouldn't be enough as it would start scanning out
|
|
- * immediately from old frame buffers until the next vblank.
|
|
+ * required as the plane enable registers are updated on vblank, and no
|
|
+ * vblank will occur once the CRTC is stopped. Disabling planes when
|
|
+ * starting the CRTC thus wouldn't be enough as it would start scanning
|
|
+ * out immediately from old frame buffers until the next vblank.
|
|
*
|
|
* This increases the CRTC stop delay, especially when multiple CRTCs
|
|
* are stopped in one operation as we now wait for one vblank per CRTC.
|
|
* Whether this can be improved needs to be researched.
|
|
*/
|
|
- rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
|
|
- drm_crtc_wait_one_vblank(crtc);
|
|
+ rcar_du_crtc_disable_planes(rcrtc);
|
|
|
|
/* Disable vertical blanking interrupt reporting. We first need to wait
|
|
* for page flip completion before stopping the CRTC as userspace
|
|
@@ -528,10 +552,26 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
|
|
irqreturn_t ret = IRQ_NONE;
|
|
u32 status;
|
|
|
|
+ spin_lock(&rcrtc->vblank_lock);
|
|
+
|
|
status = rcar_du_crtc_read(rcrtc, DSSR);
|
|
rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
|
|
|
|
- if (status & DSSR_FRM) {
|
|
+ if (status & DSSR_VBK) {
|
|
+ /*
|
|
+ * Wake up the vblank wait if the counter reaches 0. This must
|
|
+ * be protected by the vblank_lock to avoid races in
|
|
+ * rcar_du_crtc_disable_planes().
|
|
+ */
|
|
+ if (rcrtc->vblank_count) {
|
|
+ if (--rcrtc->vblank_count == 0)
|
|
+ wake_up(&rcrtc->vblank_wait);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ spin_unlock(&rcrtc->vblank_lock);
|
|
+
|
|
+ if (status & DSSR_VBK) {
|
|
drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index);
|
|
rcar_du_crtc_finish_page_flip(rcrtc);
|
|
ret = IRQ_HANDLED;
|
|
@@ -585,6 +625,8 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
|
|
}
|
|
|
|
init_waitqueue_head(&rcrtc->flip_wait);
|
|
+ init_waitqueue_head(&rcrtc->vblank_wait);
|
|
+ spin_lock_init(&rcrtc->vblank_lock);
|
|
|
|
rcrtc->group = rgrp;
|
|
rcrtc->mmio_offset = mmio_offsets[index];
|
|
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
|
|
index 2bbe3f5aab65..be22ce33b70a 100644
|
|
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
|
|
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
|
|
@@ -15,6 +15,7 @@
|
|
#define __RCAR_DU_CRTC_H__
|
|
|
|
#include <linux/mutex.h>
|
|
+#include <linux/spinlock.h>
|
|
#include <linux/wait.h>
|
|
|
|
#include <drm/drmP.h>
|
|
@@ -32,6 +33,9 @@ struct rcar_du_group;
|
|
* @started: whether the CRTC has been started and is running
|
|
* @event: event to post when the pending page flip completes
|
|
* @flip_wait: wait queue used to signal page flip completion
|
|
+ * @vblank_lock: protects vblank_wait and vblank_count
|
|
+ * @vblank_wait: wait queue used to signal vertical blanking
|
|
+ * @vblank_count: number of vertical blanking interrupts to wait for
|
|
* @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC
|
|
* @enabled: whether the CRTC is enabled, used to control system resume
|
|
* @group: CRTC group this CRTC belongs to
|
|
@@ -48,6 +52,10 @@ struct rcar_du_crtc {
|
|
struct drm_pending_vblank_event *event;
|
|
wait_queue_head_t flip_wait;
|
|
|
|
+ spinlock_t vblank_lock;
|
|
+ wait_queue_head_t vblank_wait;
|
|
+ unsigned int vblank_count;
|
|
+
|
|
unsigned int outputs;
|
|
bool enabled;
|
|
|
|
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
|
|
index 3ba486d0ec6f..6861b74e2b61 100644
|
|
--- a/drivers/hid/hid-core.c
|
|
+++ b/drivers/hid/hid-core.c
|
|
@@ -2308,7 +2308,6 @@ static const struct hid_device_id hid_ignore_list[] = {
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x000a) },
|
|
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) },
|
|
- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
|
|
@@ -2578,6 +2577,17 @@ bool hid_ignore(struct hid_device *hdev)
|
|
strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0)
|
|
return true;
|
|
break;
|
|
+ case USB_VENDOR_ID_ELAN:
|
|
+ /*
|
|
+ * Many Elan devices have a product id of 0x0401 and are handled
|
|
+ * by the elan_i2c input driver. But the ACPI HID ELAN0800 dev
|
|
+ * is not (and cannot be) handled by that driver ->
|
|
+ * Ignore all 0x0401 devs except for the ELAN0800 dev.
|
|
+ */
|
|
+ if (hdev->product == 0x0401 &&
|
|
+ strncmp(hdev->name, "ELAN0800", 8) != 0)
|
|
+ return true;
|
|
+ break;
|
|
}
|
|
|
|
if (hdev->type == HID_TYPE_USBMOUSE &&
|
|
diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c
|
|
index 7979e5d6498b..7ca359391535 100644
|
|
--- a/drivers/media/dvb-frontends/ts2020.c
|
|
+++ b/drivers/media/dvb-frontends/ts2020.c
|
|
@@ -369,7 +369,7 @@ static int ts2020_read_tuner_gain(struct dvb_frontend *fe, unsigned v_agc,
|
|
gain2 = clamp_t(long, gain2, 0, 13);
|
|
v_agc = clamp_t(long, v_agc, 400, 1100);
|
|
|
|
- *_gain = -(gain1 * 2330 +
|
|
+ *_gain = -((__s64)gain1 * 2330 +
|
|
gain2 * 3500 +
|
|
v_agc * 24 / 10 * 10 +
|
|
10000);
|
|
@@ -387,7 +387,7 @@ static int ts2020_read_tuner_gain(struct dvb_frontend *fe, unsigned v_agc,
|
|
gain3 = clamp_t(long, gain3, 0, 6);
|
|
v_agc = clamp_t(long, v_agc, 600, 1600);
|
|
|
|
- *_gain = -(gain1 * 2650 +
|
|
+ *_gain = -((__s64)gain1 * 2650 +
|
|
gain2 * 3380 +
|
|
gain3 * 2850 +
|
|
v_agc * 176 / 100 * 10 -
|
|
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c
|
|
index bda29bc1b933..2f74a5ac0147 100644
|
|
--- a/drivers/media/platform/soc_camera/soc_scale_crop.c
|
|
+++ b/drivers/media/platform/soc_camera/soc_scale_crop.c
|
|
@@ -405,3 +405,7 @@ void soc_camera_calc_client_output(struct soc_camera_device *icd,
|
|
mf->height = soc_camera_shift_scale(rect->height, shift, scale_v);
|
|
}
|
|
EXPORT_SYMBOL(soc_camera_calc_client_output);
|
|
+
|
|
+MODULE_DESCRIPTION("soc-camera scaling-cropping functions");
|
|
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
|
|
index 3721ee63b8fb..09c97847bf95 100644
|
|
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
|
|
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
|
|
@@ -503,18 +503,23 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
|
|
|
|
static int lme2510_return_status(struct dvb_usb_device *d)
|
|
{
|
|
- int ret = 0;
|
|
+ int ret;
|
|
u8 *data;
|
|
|
|
- data = kzalloc(10, GFP_KERNEL);
|
|
+ data = kzalloc(6, GFP_KERNEL);
|
|
if (!data)
|
|
return -ENOMEM;
|
|
|
|
- ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
|
|
- 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
|
|
- info("Firmware Status: %x (%x)", ret , data[2]);
|
|
+ ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
|
|
+ 0x06, 0x80, 0x0302, 0x00,
|
|
+ data, 0x6, 200);
|
|
+ if (ret != 6)
|
|
+ ret = -EINVAL;
|
|
+ else
|
|
+ ret = data[2];
|
|
+
|
|
+ info("Firmware Status: %6ph", data);
|
|
|
|
- ret = (ret < 0) ? -ENODEV : data[2];
|
|
kfree(data);
|
|
return ret;
|
|
}
|
|
@@ -1078,8 +1083,6 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
|
|
|
|
if (adap->fe[0]) {
|
|
info("FE Found M88RS2000");
|
|
- dvb_attach(ts2020_attach, adap->fe[0], &ts2020_config,
|
|
- &d->i2c_adap);
|
|
st->i2c_tuner_gate_w = 5;
|
|
st->i2c_tuner_gate_r = 5;
|
|
st->i2c_tuner_addr = 0x60;
|
|
@@ -1145,17 +1148,18 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
|
|
ret = st->tuner_config;
|
|
break;
|
|
case TUNER_RS2000:
|
|
- ret = st->tuner_config;
|
|
+ if (dvb_attach(ts2020_attach, adap->fe[0],
|
|
+ &ts2020_config, &d->i2c_adap))
|
|
+ ret = st->tuner_config;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
- if (ret)
|
|
+ if (ret) {
|
|
info("TUN Found %s tuner", tun_msg[ret]);
|
|
- else {
|
|
- info("TUN No tuner found --- resetting device");
|
|
- lme_coldreset(d);
|
|
+ } else {
|
|
+ info("TUN No tuner found");
|
|
return -ENODEV;
|
|
}
|
|
|
|
@@ -1199,6 +1203,7 @@ static int lme2510_get_adapter_count(struct dvb_usb_device *d)
|
|
static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
|
|
{
|
|
struct lme2510_state *st = d->priv;
|
|
+ int status;
|
|
|
|
usb_reset_configuration(d->udev);
|
|
|
|
@@ -1207,12 +1212,16 @@ static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
|
|
|
|
st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware;
|
|
|
|
- if (lme2510_return_status(d) == 0x44) {
|
|
+ status = lme2510_return_status(d);
|
|
+ if (status == 0x44) {
|
|
*name = lme_firmware_switch(d, 0);
|
|
return COLD;
|
|
}
|
|
|
|
- return 0;
|
|
+ if (status != 0x47)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return WARM;
|
|
}
|
|
|
|
static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
|
|
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
|
|
index ab7151181728..d00b27ed73a6 100644
|
|
--- a/drivers/media/usb/dvb-usb/cxusb.c
|
|
+++ b/drivers/media/usb/dvb-usb/cxusb.c
|
|
@@ -818,6 +818,8 @@ static int dvico_bluebird_xc2028_callback(void *ptr, int component,
|
|
case XC2028_RESET_CLK:
|
|
deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg);
|
|
break;
|
|
+ case XC2028_I2C_FLUSH:
|
|
+ break;
|
|
default:
|
|
deb_info("%s: unknown command %d, arg %d\n", __func__,
|
|
command, arg);
|
|
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
|
|
index 7df0707a0455..38c03283a441 100644
|
|
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
|
|
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
|
|
@@ -431,6 +431,7 @@ static int stk7700ph_xc3028_callback(void *ptr, int component,
|
|
state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
|
|
break;
|
|
case XC2028_RESET_CLK:
|
|
+ case XC2028_I2C_FLUSH:
|
|
break;
|
|
default:
|
|
err("%s: unknown command %d, arg %d\n", __func__,
|
|
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
|
|
index 4379b949bb93..943f90e392a7 100644
|
|
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
|
|
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
|
|
@@ -18,8 +18,18 @@
|
|
#include <linux/videodev2.h>
|
|
#include <linux/v4l2-subdev.h>
|
|
#include <media/v4l2-dev.h>
|
|
+#include <media/v4l2-fh.h>
|
|
+#include <media/v4l2-ctrls.h>
|
|
#include <media/v4l2-ioctl.h>
|
|
|
|
+/* Use the same argument order as copy_in_user */
|
|
+#define assign_in_user(to, from) \
|
|
+({ \
|
|
+ typeof(*from) __assign_tmp; \
|
|
+ \
|
|
+ get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \
|
|
+})
|
|
+
|
|
static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
{
|
|
long ret = -ENOIOCTLCMD;
|
|
@@ -33,131 +43,88 @@ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
|
|
struct v4l2_clip32 {
|
|
struct v4l2_rect c;
|
|
- compat_caddr_t next;
|
|
+ compat_caddr_t next;
|
|
};
|
|
|
|
struct v4l2_window32 {
|
|
struct v4l2_rect w;
|
|
- __u32 field; /* enum v4l2_field */
|
|
+ __u32 field; /* enum v4l2_field */
|
|
__u32 chromakey;
|
|
compat_caddr_t clips; /* actually struct v4l2_clip32 * */
|
|
__u32 clipcount;
|
|
compat_caddr_t bitmap;
|
|
+ __u8 global_alpha;
|
|
};
|
|
|
|
-static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
|
|
-{
|
|
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
|
|
- copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
|
|
- get_user(kp->field, &up->field) ||
|
|
- get_user(kp->chromakey, &up->chromakey) ||
|
|
- get_user(kp->clipcount, &up->clipcount))
|
|
- return -EFAULT;
|
|
- if (kp->clipcount > 2048)
|
|
- return -EINVAL;
|
|
- if (kp->clipcount) {
|
|
- struct v4l2_clip32 __user *uclips;
|
|
- struct v4l2_clip __user *kclips;
|
|
- int n = kp->clipcount;
|
|
- compat_caddr_t p;
|
|
-
|
|
- if (get_user(p, &up->clips))
|
|
- return -EFAULT;
|
|
- uclips = compat_ptr(p);
|
|
- kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
|
|
- kp->clips = kclips;
|
|
- while (--n >= 0) {
|
|
- if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
|
|
- return -EFAULT;
|
|
- if (put_user(n ? kclips + 1 : NULL, &kclips->next))
|
|
- return -EFAULT;
|
|
- uclips += 1;
|
|
- kclips += 1;
|
|
- }
|
|
- } else
|
|
- kp->clips = NULL;
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
|
|
-{
|
|
- if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
|
|
- put_user(kp->field, &up->field) ||
|
|
- put_user(kp->chromakey, &up->chromakey) ||
|
|
- put_user(kp->clipcount, &up->clipcount))
|
|
- return -EFAULT;
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
|
|
-{
|
|
- if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
|
|
- return -EFAULT;
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
|
|
- struct v4l2_pix_format_mplane __user *up)
|
|
-{
|
|
- if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
|
|
- return -EFAULT;
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
|
|
-{
|
|
- if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
|
|
- return -EFAULT;
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
|
|
- struct v4l2_pix_format_mplane __user *up)
|
|
+static int get_v4l2_window32(struct v4l2_window __user *kp,
|
|
+ struct v4l2_window32 __user *up,
|
|
+ void __user *aux_buf, u32 aux_space)
|
|
{
|
|
- if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
|
|
+ struct v4l2_clip32 __user *uclips;
|
|
+ struct v4l2_clip __user *kclips;
|
|
+ compat_caddr_t p;
|
|
+ u32 clipcount;
|
|
+
|
|
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
|
|
+ copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
|
|
+ assign_in_user(&kp->field, &up->field) ||
|
|
+ assign_in_user(&kp->chromakey, &up->chromakey) ||
|
|
+ assign_in_user(&kp->global_alpha, &up->global_alpha) ||
|
|
+ get_user(clipcount, &up->clipcount) ||
|
|
+ put_user(clipcount, &kp->clipcount))
|
|
return -EFAULT;
|
|
- return 0;
|
|
-}
|
|
+ if (clipcount > 2048)
|
|
+ return -EINVAL;
|
|
+ if (!clipcount)
|
|
+ return put_user(NULL, &kp->clips);
|
|
|
|
-static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
|
|
-{
|
|
- if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
|
|
+ if (get_user(p, &up->clips))
|
|
return -EFAULT;
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
|
|
-{
|
|
- if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
|
|
+ uclips = compat_ptr(p);
|
|
+ if (aux_space < clipcount * sizeof(*kclips))
|
|
return -EFAULT;
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
|
|
-{
|
|
- if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
|
|
+ kclips = aux_buf;
|
|
+ if (put_user(kclips, &kp->clips))
|
|
return -EFAULT;
|
|
- return 0;
|
|
-}
|
|
|
|
-static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
|
|
-{
|
|
- if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
|
|
- return -EFAULT;
|
|
+ while (clipcount--) {
|
|
+ if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
|
|
+ return -EFAULT;
|
|
+ if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next))
|
|
+ return -EFAULT;
|
|
+ uclips++;
|
|
+ kclips++;
|
|
+ }
|
|
return 0;
|
|
}
|
|
|
|
-static inline int get_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
|
|
+static int put_v4l2_window32(struct v4l2_window __user *kp,
|
|
+ struct v4l2_window32 __user *up)
|
|
{
|
|
- if (copy_from_user(kp, up, sizeof(struct v4l2_sdr_format)))
|
|
+ struct v4l2_clip __user *kclips = kp->clips;
|
|
+ struct v4l2_clip32 __user *uclips;
|
|
+ compat_caddr_t p;
|
|
+ u32 clipcount;
|
|
+
|
|
+ if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) ||
|
|
+ assign_in_user(&up->field, &kp->field) ||
|
|
+ assign_in_user(&up->chromakey, &kp->chromakey) ||
|
|
+ assign_in_user(&up->global_alpha, &kp->global_alpha) ||
|
|
+ get_user(clipcount, &kp->clipcount) ||
|
|
+ put_user(clipcount, &up->clipcount))
|
|
return -EFAULT;
|
|
- return 0;
|
|
-}
|
|
+ if (!clipcount)
|
|
+ return 0;
|
|
|
|
-static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
|
|
-{
|
|
- if (copy_to_user(up, kp, sizeof(struct v4l2_sdr_format)))
|
|
+ if (get_user(p, &up->clips))
|
|
return -EFAULT;
|
|
+ uclips = compat_ptr(p);
|
|
+ while (clipcount--) {
|
|
+ if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
|
|
+ return -EFAULT;
|
|
+ uclips++;
|
|
+ kclips++;
|
|
+ }
|
|
return 0;
|
|
}
|
|
|
|
@@ -191,97 +158,158 @@ struct v4l2_create_buffers32 {
|
|
__u32 reserved[8];
|
|
};
|
|
|
|
-static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
|
|
+static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
|
|
+{
|
|
+ u32 type;
|
|
+
|
|
+ if (get_user(type, &up->type))
|
|
+ return -EFAULT;
|
|
+
|
|
+ switch (type) {
|
|
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
|
|
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
|
|
+ u32 clipcount;
|
|
+
|
|
+ if (get_user(clipcount, &up->fmt.win.clipcount))
|
|
+ return -EFAULT;
|
|
+ if (clipcount > 2048)
|
|
+ return -EINVAL;
|
|
+ *size = clipcount * sizeof(struct v4l2_clip);
|
|
+ return 0;
|
|
+ }
|
|
+ default:
|
|
+ *size = 0;
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
|
|
{
|
|
- if (get_user(kp->type, &up->type))
|
|
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)))
|
|
return -EFAULT;
|
|
+ return __bufsize_v4l2_format(up, size);
|
|
+}
|
|
|
|
- switch (kp->type) {
|
|
+static int __get_v4l2_format32(struct v4l2_format __user *kp,
|
|
+ struct v4l2_format32 __user *up,
|
|
+ void __user *aux_buf, u32 aux_space)
|
|
+{
|
|
+ u32 type;
|
|
+
|
|
+ if (get_user(type, &up->type) || put_user(type, &kp->type))
|
|
+ return -EFAULT;
|
|
+
|
|
+ switch (type) {
|
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
|
- return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
|
|
+ return copy_in_user(&kp->fmt.pix, &up->fmt.pix,
|
|
+ sizeof(kp->fmt.pix)) ? -EFAULT : 0;
|
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
|
- return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
|
|
- &up->fmt.pix_mp);
|
|
+ return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
|
|
+ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
|
|
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
|
- return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
|
|
+ return get_v4l2_window32(&kp->fmt.win, &up->fmt.win,
|
|
+ aux_buf, aux_space);
|
|
case V4L2_BUF_TYPE_VBI_CAPTURE:
|
|
case V4L2_BUF_TYPE_VBI_OUTPUT:
|
|
- return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
|
|
+ return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi,
|
|
+ sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
|
|
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
|
|
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
|
|
- return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
|
|
+ return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced,
|
|
+ sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
|
|
case V4L2_BUF_TYPE_SDR_CAPTURE:
|
|
case V4L2_BUF_TYPE_SDR_OUTPUT:
|
|
- return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
|
|
+ return copy_in_user(&kp->fmt.sdr, &up->fmt.sdr,
|
|
+ sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
|
|
default:
|
|
- pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
|
|
- kp->type);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
|
|
+static int get_v4l2_format32(struct v4l2_format __user *kp,
|
|
+ struct v4l2_format32 __user *up,
|
|
+ void __user *aux_buf, u32 aux_space)
|
|
{
|
|
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)))
|
|
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)))
|
|
return -EFAULT;
|
|
- return __get_v4l2_format32(kp, up);
|
|
+ return __get_v4l2_format32(kp, up, aux_buf, aux_space);
|
|
}
|
|
|
|
-static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
|
|
+static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up,
|
|
+ u32 *size)
|
|
{
|
|
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
|
|
- copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format)))
|
|
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)))
|
|
return -EFAULT;
|
|
- return __get_v4l2_format32(&kp->format, &up->format);
|
|
+ return __bufsize_v4l2_format(&up->format, size);
|
|
}
|
|
|
|
-static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
|
|
+static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
|
|
+ struct v4l2_create_buffers32 __user *up,
|
|
+ void __user *aux_buf, u32 aux_space)
|
|
{
|
|
- if (put_user(kp->type, &up->type))
|
|
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
|
|
+ copy_in_user(kp, up,
|
|
+ offsetof(struct v4l2_create_buffers32, format)))
|
|
return -EFAULT;
|
|
+ return __get_v4l2_format32(&kp->format, &up->format,
|
|
+ aux_buf, aux_space);
|
|
+}
|
|
+
|
|
+static int __put_v4l2_format32(struct v4l2_format __user *kp,
|
|
+ struct v4l2_format32 __user *up)
|
|
+{
|
|
+ u32 type;
|
|
|
|
- switch (kp->type) {
|
|
+ if (get_user(type, &kp->type))
|
|
+ return -EFAULT;
|
|
+
|
|
+ switch (type) {
|
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
|
- return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
|
|
+ return copy_in_user(&up->fmt.pix, &kp->fmt.pix,
|
|
+ sizeof(kp->fmt.pix)) ? -EFAULT : 0;
|
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
|
- return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
|
|
- &up->fmt.pix_mp);
|
|
+ return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
|
|
+ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
|
|
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
|
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
|
return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
|
|
case V4L2_BUF_TYPE_VBI_CAPTURE:
|
|
case V4L2_BUF_TYPE_VBI_OUTPUT:
|
|
- return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
|
|
+ return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi,
|
|
+ sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
|
|
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
|
|
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
|
|
- return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
|
|
+ return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced,
|
|
+ sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
|
|
case V4L2_BUF_TYPE_SDR_CAPTURE:
|
|
case V4L2_BUF_TYPE_SDR_OUTPUT:
|
|
- return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
|
|
+ return copy_in_user(&up->fmt.sdr, &kp->fmt.sdr,
|
|
+ sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
|
|
default:
|
|
- pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
|
|
- kp->type);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
|
|
+static int put_v4l2_format32(struct v4l2_format __user *kp,
|
|
+ struct v4l2_format32 __user *up)
|
|
{
|
|
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)))
|
|
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
|
|
return -EFAULT;
|
|
return __put_v4l2_format32(kp, up);
|
|
}
|
|
|
|
-static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
|
|
+static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
|
|
+ struct v4l2_create_buffers32 __user *up)
|
|
{
|
|
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
|
|
- copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) ||
|
|
- copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
|
|
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
|
|
+ copy_in_user(up, kp,
|
|
+ offsetof(struct v4l2_create_buffers32, format)) ||
|
|
+ copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
|
|
return -EFAULT;
|
|
return __put_v4l2_format32(&kp->format, &up->format);
|
|
}
|
|
@@ -295,25 +323,28 @@ struct v4l2_standard32 {
|
|
__u32 reserved[4];
|
|
};
|
|
|
|
-static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
|
|
+static int get_v4l2_standard32(struct v4l2_standard __user *kp,
|
|
+ struct v4l2_standard32 __user *up)
|
|
{
|
|
/* other fields are not set by the user, nor used by the driver */
|
|
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
|
|
- get_user(kp->index, &up->index))
|
|
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
|
|
+ assign_in_user(&kp->index, &up->index))
|
|
return -EFAULT;
|
|
return 0;
|
|
}
|
|
|
|
-static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
|
|
+static int put_v4l2_standard32(struct v4l2_standard __user *kp,
|
|
+ struct v4l2_standard32 __user *up)
|
|
{
|
|
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
|
|
- put_user(kp->index, &up->index) ||
|
|
- put_user(kp->id, &up->id) ||
|
|
- copy_to_user(up->name, kp->name, 24) ||
|
|
- copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
|
|
- put_user(kp->framelines, &up->framelines) ||
|
|
- copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
|
|
- return -EFAULT;
|
|
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
|
|
+ assign_in_user(&up->index, &kp->index) ||
|
|
+ assign_in_user(&up->id, &kp->id) ||
|
|
+ copy_in_user(up->name, kp->name, sizeof(up->name)) ||
|
|
+ copy_in_user(&up->frameperiod, &kp->frameperiod,
|
|
+ sizeof(up->frameperiod)) ||
|
|
+ assign_in_user(&up->framelines, &kp->framelines) ||
|
|
+ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
|
|
+ return -EFAULT;
|
|
return 0;
|
|
}
|
|
|
|
@@ -352,134 +383,186 @@ struct v4l2_buffer32 {
|
|
__u32 reserved;
|
|
};
|
|
|
|
-static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
|
|
- enum v4l2_memory memory)
|
|
+static int get_v4l2_plane32(struct v4l2_plane __user *up,
|
|
+ struct v4l2_plane32 __user *up32,
|
|
+ enum v4l2_memory memory)
|
|
{
|
|
- void __user *up_pln;
|
|
- compat_long_t p;
|
|
+ compat_ulong_t p;
|
|
|
|
if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
|
|
- copy_in_user(&up->data_offset, &up32->data_offset,
|
|
- sizeof(__u32)))
|
|
+ copy_in_user(&up->data_offset, &up32->data_offset,
|
|
+ sizeof(up->data_offset)))
|
|
return -EFAULT;
|
|
|
|
- if (memory == V4L2_MEMORY_USERPTR) {
|
|
- if (get_user(p, &up32->m.userptr))
|
|
- return -EFAULT;
|
|
- up_pln = compat_ptr(p);
|
|
- if (put_user((unsigned long)up_pln, &up->m.userptr))
|
|
+ switch (memory) {
|
|
+ case V4L2_MEMORY_MMAP:
|
|
+ case V4L2_MEMORY_OVERLAY:
|
|
+ if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
|
|
+ sizeof(up32->m.mem_offset)))
|
|
return -EFAULT;
|
|
- } else if (memory == V4L2_MEMORY_DMABUF) {
|
|
- if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int)))
|
|
+ break;
|
|
+ case V4L2_MEMORY_USERPTR:
|
|
+ if (get_user(p, &up32->m.userptr) ||
|
|
+ put_user((unsigned long)compat_ptr(p), &up->m.userptr))
|
|
return -EFAULT;
|
|
- } else {
|
|
- if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
|
|
- sizeof(__u32)))
|
|
+ break;
|
|
+ case V4L2_MEMORY_DMABUF:
|
|
+ if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd)))
|
|
return -EFAULT;
|
|
+ break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
-static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
|
|
- enum v4l2_memory memory)
|
|
+static int put_v4l2_plane32(struct v4l2_plane __user *up,
|
|
+ struct v4l2_plane32 __user *up32,
|
|
+ enum v4l2_memory memory)
|
|
{
|
|
+ unsigned long p;
|
|
+
|
|
if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
|
|
- copy_in_user(&up32->data_offset, &up->data_offset,
|
|
- sizeof(__u32)))
|
|
+ copy_in_user(&up32->data_offset, &up->data_offset,
|
|
+ sizeof(up->data_offset)))
|
|
return -EFAULT;
|
|
|
|
- /* For MMAP, driver might've set up the offset, so copy it back.
|
|
- * USERPTR stays the same (was userspace-provided), so no copying. */
|
|
- if (memory == V4L2_MEMORY_MMAP)
|
|
+ switch (memory) {
|
|
+ case V4L2_MEMORY_MMAP:
|
|
+ case V4L2_MEMORY_OVERLAY:
|
|
if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
|
|
- sizeof(__u32)))
|
|
+ sizeof(up->m.mem_offset)))
|
|
return -EFAULT;
|
|
- /* For DMABUF, driver might've set up the fd, so copy it back. */
|
|
- if (memory == V4L2_MEMORY_DMABUF)
|
|
- if (copy_in_user(&up32->m.fd, &up->m.fd,
|
|
- sizeof(int)))
|
|
+ break;
|
|
+ case V4L2_MEMORY_USERPTR:
|
|
+ if (get_user(p, &up->m.userptr) ||
|
|
+ put_user((compat_ulong_t)ptr_to_compat((__force void *)p),
|
|
+ &up32->m.userptr))
|
|
+ return -EFAULT;
|
|
+ break;
|
|
+ case V4L2_MEMORY_DMABUF:
|
|
+ if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd)))
|
|
return -EFAULT;
|
|
+ break;
|
|
+ }
|
|
|
|
return 0;
|
|
}
|
|
|
|
-static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
|
|
+static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size)
|
|
{
|
|
+ u32 type;
|
|
+ u32 length;
|
|
+
|
|
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
|
|
+ get_user(type, &up->type) ||
|
|
+ get_user(length, &up->length))
|
|
+ return -EFAULT;
|
|
+
|
|
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
|
|
+ if (length > VIDEO_MAX_PLANES)
|
|
+ return -EINVAL;
|
|
+
|
|
+ /*
|
|
+ * We don't really care if userspace decides to kill itself
|
|
+ * by passing a very big length value
|
|
+ */
|
|
+ *size = length * sizeof(struct v4l2_plane);
|
|
+ } else {
|
|
+ *size = 0;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
|
|
+ struct v4l2_buffer32 __user *up,
|
|
+ void __user *aux_buf, u32 aux_space)
|
|
+{
|
|
+ u32 type;
|
|
+ u32 length;
|
|
+ enum v4l2_memory memory;
|
|
struct v4l2_plane32 __user *uplane32;
|
|
struct v4l2_plane __user *uplane;
|
|
compat_caddr_t p;
|
|
- int num_planes;
|
|
int ret;
|
|
|
|
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
|
|
- get_user(kp->index, &up->index) ||
|
|
- get_user(kp->type, &up->type) ||
|
|
- get_user(kp->flags, &up->flags) ||
|
|
- get_user(kp->memory, &up->memory) ||
|
|
- get_user(kp->length, &up->length))
|
|
- return -EFAULT;
|
|
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
|
|
+ assign_in_user(&kp->index, &up->index) ||
|
|
+ get_user(type, &up->type) ||
|
|
+ put_user(type, &kp->type) ||
|
|
+ assign_in_user(&kp->flags, &up->flags) ||
|
|
+ get_user(memory, &up->memory) ||
|
|
+ put_user(memory, &kp->memory) ||
|
|
+ get_user(length, &up->length) ||
|
|
+ put_user(length, &kp->length))
|
|
+ return -EFAULT;
|
|
|
|
- if (V4L2_TYPE_IS_OUTPUT(kp->type))
|
|
- if (get_user(kp->bytesused, &up->bytesused) ||
|
|
- get_user(kp->field, &up->field) ||
|
|
- get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
|
|
- get_user(kp->timestamp.tv_usec,
|
|
- &up->timestamp.tv_usec))
|
|
+ if (V4L2_TYPE_IS_OUTPUT(type))
|
|
+ if (assign_in_user(&kp->bytesused, &up->bytesused) ||
|
|
+ assign_in_user(&kp->field, &up->field) ||
|
|
+ assign_in_user(&kp->timestamp.tv_sec,
|
|
+ &up->timestamp.tv_sec) ||
|
|
+ assign_in_user(&kp->timestamp.tv_usec,
|
|
+ &up->timestamp.tv_usec))
|
|
return -EFAULT;
|
|
|
|
- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
|
|
- num_planes = kp->length;
|
|
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
|
|
+ u32 num_planes = length;
|
|
+
|
|
if (num_planes == 0) {
|
|
- kp->m.planes = NULL;
|
|
- /* num_planes == 0 is legal, e.g. when userspace doesn't
|
|
- * need planes array on DQBUF*/
|
|
- return 0;
|
|
+ /*
|
|
+ * num_planes == 0 is legal, e.g. when userspace doesn't
|
|
+ * need planes array on DQBUF
|
|
+ */
|
|
+ return put_user(NULL, &kp->m.planes);
|
|
}
|
|
+ if (num_planes > VIDEO_MAX_PLANES)
|
|
+ return -EINVAL;
|
|
|
|
if (get_user(p, &up->m.planes))
|
|
return -EFAULT;
|
|
|
|
uplane32 = compat_ptr(p);
|
|
if (!access_ok(VERIFY_READ, uplane32,
|
|
- num_planes * sizeof(struct v4l2_plane32)))
|
|
+ num_planes * sizeof(*uplane32)))
|
|
return -EFAULT;
|
|
|
|
- /* We don't really care if userspace decides to kill itself
|
|
- * by passing a very big num_planes value */
|
|
- uplane = compat_alloc_user_space(num_planes *
|
|
- sizeof(struct v4l2_plane));
|
|
- kp->m.planes = (__force struct v4l2_plane *)uplane;
|
|
+ /*
|
|
+ * We don't really care if userspace decides to kill itself
|
|
+ * by passing a very big num_planes value
|
|
+ */
|
|
+ if (aux_space < num_planes * sizeof(*uplane))
|
|
+ return -EFAULT;
|
|
+
|
|
+ uplane = aux_buf;
|
|
+ if (put_user((__force struct v4l2_plane *)uplane,
|
|
+ &kp->m.planes))
|
|
+ return -EFAULT;
|
|
|
|
- while (--num_planes >= 0) {
|
|
- ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
|
|
+ while (num_planes--) {
|
|
+ ret = get_v4l2_plane32(uplane, uplane32, memory);
|
|
if (ret)
|
|
return ret;
|
|
- ++uplane;
|
|
- ++uplane32;
|
|
+ uplane++;
|
|
+ uplane32++;
|
|
}
|
|
} else {
|
|
- switch (kp->memory) {
|
|
+ switch (memory) {
|
|
case V4L2_MEMORY_MMAP:
|
|
- if (get_user(kp->m.offset, &up->m.offset))
|
|
+ case V4L2_MEMORY_OVERLAY:
|
|
+ if (assign_in_user(&kp->m.offset, &up->m.offset))
|
|
return -EFAULT;
|
|
break;
|
|
- case V4L2_MEMORY_USERPTR:
|
|
- {
|
|
- compat_long_t tmp;
|
|
+ case V4L2_MEMORY_USERPTR: {
|
|
+ compat_ulong_t userptr;
|
|
|
|
- if (get_user(tmp, &up->m.userptr))
|
|
- return -EFAULT;
|
|
-
|
|
- kp->m.userptr = (unsigned long)compat_ptr(tmp);
|
|
- }
|
|
- break;
|
|
- case V4L2_MEMORY_OVERLAY:
|
|
- if (get_user(kp->m.offset, &up->m.offset))
|
|
+ if (get_user(userptr, &up->m.userptr) ||
|
|
+ put_user((unsigned long)compat_ptr(userptr),
|
|
+ &kp->m.userptr))
|
|
return -EFAULT;
|
|
break;
|
|
+ }
|
|
case V4L2_MEMORY_DMABUF:
|
|
- if (get_user(kp->m.fd, &up->m.fd))
|
|
+ if (assign_in_user(&kp->m.fd, &up->m.fd))
|
|
return -EFAULT;
|
|
break;
|
|
}
|
|
@@ -488,65 +571,70 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
|
|
return 0;
|
|
}
|
|
|
|
-static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
|
|
+static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
|
|
+ struct v4l2_buffer32 __user *up)
|
|
{
|
|
+ u32 type;
|
|
+ u32 length;
|
|
+ enum v4l2_memory memory;
|
|
struct v4l2_plane32 __user *uplane32;
|
|
struct v4l2_plane __user *uplane;
|
|
compat_caddr_t p;
|
|
- int num_planes;
|
|
int ret;
|
|
|
|
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
|
|
- put_user(kp->index, &up->index) ||
|
|
- put_user(kp->type, &up->type) ||
|
|
- put_user(kp->flags, &up->flags) ||
|
|
- put_user(kp->memory, &up->memory))
|
|
- return -EFAULT;
|
|
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
|
|
+ assign_in_user(&up->index, &kp->index) ||
|
|
+ get_user(type, &kp->type) ||
|
|
+ put_user(type, &up->type) ||
|
|
+ assign_in_user(&up->flags, &kp->flags) ||
|
|
+ get_user(memory, &kp->memory) ||
|
|
+ put_user(memory, &up->memory))
|
|
+ return -EFAULT;
|
|
|
|
- if (put_user(kp->bytesused, &up->bytesused) ||
|
|
- put_user(kp->field, &up->field) ||
|
|
- put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
|
|
- put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
|
|
- copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
|
|
- put_user(kp->sequence, &up->sequence) ||
|
|
- put_user(kp->reserved2, &up->reserved2) ||
|
|
- put_user(kp->reserved, &up->reserved) ||
|
|
- put_user(kp->length, &up->length))
|
|
- return -EFAULT;
|
|
+ if (assign_in_user(&up->bytesused, &kp->bytesused) ||
|
|
+ assign_in_user(&up->field, &kp->field) ||
|
|
+ assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
|
|
+ assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
|
|
+ copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
|
|
+ assign_in_user(&up->sequence, &kp->sequence) ||
|
|
+ assign_in_user(&up->reserved2, &kp->reserved2) ||
|
|
+ assign_in_user(&up->reserved, &kp->reserved) ||
|
|
+ get_user(length, &kp->length) ||
|
|
+ put_user(length, &up->length))
|
|
+ return -EFAULT;
|
|
+
|
|
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
|
|
+ u32 num_planes = length;
|
|
|
|
- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
|
|
- num_planes = kp->length;
|
|
if (num_planes == 0)
|
|
return 0;
|
|
|
|
- uplane = (__force struct v4l2_plane __user *)kp->m.planes;
|
|
+ if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes)))
|
|
+ return -EFAULT;
|
|
if (get_user(p, &up->m.planes))
|
|
return -EFAULT;
|
|
uplane32 = compat_ptr(p);
|
|
|
|
- while (--num_planes >= 0) {
|
|
- ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
|
|
+ while (num_planes--) {
|
|
+ ret = put_v4l2_plane32(uplane, uplane32, memory);
|
|
if (ret)
|
|
return ret;
|
|
++uplane;
|
|
++uplane32;
|
|
}
|
|
} else {
|
|
- switch (kp->memory) {
|
|
+ switch (memory) {
|
|
case V4L2_MEMORY_MMAP:
|
|
- if (put_user(kp->m.offset, &up->m.offset))
|
|
+ case V4L2_MEMORY_OVERLAY:
|
|
+ if (assign_in_user(&up->m.offset, &kp->m.offset))
|
|
return -EFAULT;
|
|
break;
|
|
case V4L2_MEMORY_USERPTR:
|
|
- if (put_user(kp->m.userptr, &up->m.userptr))
|
|
- return -EFAULT;
|
|
- break;
|
|
- case V4L2_MEMORY_OVERLAY:
|
|
- if (put_user(kp->m.offset, &up->m.offset))
|
|
+ if (assign_in_user(&up->m.userptr, &kp->m.userptr))
|
|
return -EFAULT;
|
|
break;
|
|
case V4L2_MEMORY_DMABUF:
|
|
- if (put_user(kp->m.fd, &up->m.fd))
|
|
+ if (assign_in_user(&up->m.fd, &kp->m.fd))
|
|
return -EFAULT;
|
|
break;
|
|
}
|
|
@@ -558,7 +646,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
|
|
struct v4l2_framebuffer32 {
|
|
__u32 capability;
|
|
__u32 flags;
|
|
- compat_caddr_t base;
|
|
+ compat_caddr_t base;
|
|
struct {
|
|
__u32 width;
|
|
__u32 height;
|
|
@@ -571,30 +659,33 @@ struct v4l2_framebuffer32 {
|
|
} fmt;
|
|
};
|
|
|
|
-static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
|
|
+static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
|
|
+ struct v4l2_framebuffer32 __user *up)
|
|
{
|
|
- u32 tmp;
|
|
-
|
|
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
|
|
- get_user(tmp, &up->base) ||
|
|
- get_user(kp->capability, &up->capability) ||
|
|
- get_user(kp->flags, &up->flags) ||
|
|
- copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
|
|
- return -EFAULT;
|
|
- kp->base = (__force void *)compat_ptr(tmp);
|
|
+ compat_caddr_t tmp;
|
|
+
|
|
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
|
|
+ get_user(tmp, &up->base) ||
|
|
+ put_user((__force void *)compat_ptr(tmp), &kp->base) ||
|
|
+ assign_in_user(&kp->capability, &up->capability) ||
|
|
+ assign_in_user(&kp->flags, &up->flags) ||
|
|
+ copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
|
|
+ return -EFAULT;
|
|
return 0;
|
|
}
|
|
|
|
-static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
|
|
+static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
|
|
+ struct v4l2_framebuffer32 __user *up)
|
|
{
|
|
- u32 tmp = (u32)((unsigned long)kp->base);
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
|
|
- put_user(tmp, &up->base) ||
|
|
- put_user(kp->capability, &up->capability) ||
|
|
- put_user(kp->flags, &up->flags) ||
|
|
- copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
|
|
- return -EFAULT;
|
|
+ void *base;
|
|
+
|
|
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
|
|
+ get_user(base, &kp->base) ||
|
|
+ put_user(ptr_to_compat(base), &up->base) ||
|
|
+ assign_in_user(&up->capability, &kp->capability) ||
|
|
+ assign_in_user(&up->flags, &kp->flags) ||
|
|
+ copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt)))
|
|
+ return -EFAULT;
|
|
return 0;
|
|
}
|
|
|
|
@@ -606,21 +697,26 @@ struct v4l2_input32 {
|
|
__u32 tuner; /* Associated tuner */
|
|
compat_u64 std;
|
|
__u32 status;
|
|
- __u32 reserved[4];
|
|
+ __u32 capabilities;
|
|
+ __u32 reserved[3];
|
|
};
|
|
|
|
-/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
|
|
- Otherwise it is identical to the 32-bit version. */
|
|
-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
|
|
+/*
|
|
+ * The 64-bit v4l2_input struct has extra padding at the end of the struct.
|
|
+ * Otherwise it is identical to the 32-bit version.
|
|
+ */
|
|
+static inline int get_v4l2_input32(struct v4l2_input __user *kp,
|
|
+ struct v4l2_input32 __user *up)
|
|
{
|
|
- if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
|
|
+ if (copy_in_user(kp, up, sizeof(*up)))
|
|
return -EFAULT;
|
|
return 0;
|
|
}
|
|
|
|
-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
|
|
+static inline int put_v4l2_input32(struct v4l2_input __user *kp,
|
|
+ struct v4l2_input32 __user *up)
|
|
{
|
|
- if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
|
|
+ if (copy_in_user(up, kp, sizeof(*up)))
|
|
return -EFAULT;
|
|
return 0;
|
|
}
|
|
@@ -644,58 +740,95 @@ struct v4l2_ext_control32 {
|
|
};
|
|
} __attribute__ ((packed));
|
|
|
|
-/* The following function really belong in v4l2-common, but that causes
|
|
- a circular dependency between modules. We need to think about this, but
|
|
- for now this will do. */
|
|
-
|
|
-/* Return non-zero if this control is a pointer type. Currently only
|
|
- type STRING is a pointer type. */
|
|
-static inline int ctrl_is_pointer(u32 id)
|
|
+/* Return true if this control is a pointer type. */
|
|
+static inline bool ctrl_is_pointer(struct file *file, u32 id)
|
|
{
|
|
- switch (id) {
|
|
- case V4L2_CID_RDS_TX_PS_NAME:
|
|
- case V4L2_CID_RDS_TX_RADIO_TEXT:
|
|
- return 1;
|
|
- default:
|
|
- return 0;
|
|
+ struct video_device *vdev = video_devdata(file);
|
|
+ struct v4l2_fh *fh = NULL;
|
|
+ struct v4l2_ctrl_handler *hdl = NULL;
|
|
+ struct v4l2_query_ext_ctrl qec = { id };
|
|
+ const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
|
|
+
|
|
+ if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
|
|
+ fh = file->private_data;
|
|
+
|
|
+ if (fh && fh->ctrl_handler)
|
|
+ hdl = fh->ctrl_handler;
|
|
+ else if (vdev->ctrl_handler)
|
|
+ hdl = vdev->ctrl_handler;
|
|
+
|
|
+ if (hdl) {
|
|
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
|
|
+
|
|
+ return ctrl && ctrl->is_ptr;
|
|
}
|
|
+
|
|
+ if (!ops || !ops->vidioc_query_ext_ctrl)
|
|
+ return false;
|
|
+
|
|
+ return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
|
|
+ (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
|
|
+}
|
|
+
|
|
+static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up,
|
|
+ u32 *size)
|
|
+{
|
|
+ u32 count;
|
|
+
|
|
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
|
|
+ get_user(count, &up->count))
|
|
+ return -EFAULT;
|
|
+ if (count > V4L2_CID_MAX_CTRLS)
|
|
+ return -EINVAL;
|
|
+ *size = count * sizeof(struct v4l2_ext_control);
|
|
+ return 0;
|
|
}
|
|
|
|
-static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
|
|
+static int get_v4l2_ext_controls32(struct file *file,
|
|
+ struct v4l2_ext_controls __user *kp,
|
|
+ struct v4l2_ext_controls32 __user *up,
|
|
+ void __user *aux_buf, u32 aux_space)
|
|
{
|
|
struct v4l2_ext_control32 __user *ucontrols;
|
|
struct v4l2_ext_control __user *kcontrols;
|
|
- int n;
|
|
+ u32 count;
|
|
+ u32 n;
|
|
compat_caddr_t p;
|
|
|
|
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
|
|
- get_user(kp->ctrl_class, &up->ctrl_class) ||
|
|
- get_user(kp->count, &up->count) ||
|
|
- get_user(kp->error_idx, &up->error_idx) ||
|
|
- copy_from_user(kp->reserved, up->reserved,
|
|
- sizeof(kp->reserved)))
|
|
- return -EFAULT;
|
|
- n = kp->count;
|
|
- if (n == 0) {
|
|
- kp->controls = NULL;
|
|
- return 0;
|
|
- }
|
|
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
|
|
+ assign_in_user(&kp->ctrl_class, &up->ctrl_class) ||
|
|
+ get_user(count, &up->count) ||
|
|
+ put_user(count, &kp->count) ||
|
|
+ assign_in_user(&kp->error_idx, &up->error_idx) ||
|
|
+ copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
|
|
+ return -EFAULT;
|
|
+
|
|
+ if (count == 0)
|
|
+ return put_user(NULL, &kp->controls);
|
|
+ if (count > V4L2_CID_MAX_CTRLS)
|
|
+ return -EINVAL;
|
|
if (get_user(p, &up->controls))
|
|
return -EFAULT;
|
|
ucontrols = compat_ptr(p);
|
|
- if (!access_ok(VERIFY_READ, ucontrols,
|
|
- n * sizeof(struct v4l2_ext_control32)))
|
|
+ if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols)))
|
|
+ return -EFAULT;
|
|
+ if (aux_space < count * sizeof(*kcontrols))
|
|
return -EFAULT;
|
|
- kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
|
|
- kp->controls = (__force struct v4l2_ext_control *)kcontrols;
|
|
- while (--n >= 0) {
|
|
+ kcontrols = aux_buf;
|
|
+ if (put_user((__force struct v4l2_ext_control *)kcontrols,
|
|
+ &kp->controls))
|
|
+ return -EFAULT;
|
|
+
|
|
+ for (n = 0; n < count; n++) {
|
|
u32 id;
|
|
|
|
if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
|
|
return -EFAULT;
|
|
+
|
|
if (get_user(id, &kcontrols->id))
|
|
return -EFAULT;
|
|
- if (ctrl_is_pointer(id)) {
|
|
+
|
|
+ if (ctrl_is_pointer(file, id)) {
|
|
void __user *s;
|
|
|
|
if (get_user(p, &ucontrols->string))
|
|
@@ -710,43 +843,55 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
|
|
return 0;
|
|
}
|
|
|
|
-static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
|
|
+static int put_v4l2_ext_controls32(struct file *file,
|
|
+ struct v4l2_ext_controls __user *kp,
|
|
+ struct v4l2_ext_controls32 __user *up)
|
|
{
|
|
struct v4l2_ext_control32 __user *ucontrols;
|
|
- struct v4l2_ext_control __user *kcontrols =
|
|
- (__force struct v4l2_ext_control __user *)kp->controls;
|
|
- int n = kp->count;
|
|
+ struct v4l2_ext_control __user *kcontrols;
|
|
+ u32 count;
|
|
+ u32 n;
|
|
compat_caddr_t p;
|
|
|
|
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
|
|
- put_user(kp->ctrl_class, &up->ctrl_class) ||
|
|
- put_user(kp->count, &up->count) ||
|
|
- put_user(kp->error_idx, &up->error_idx) ||
|
|
- copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
|
|
- return -EFAULT;
|
|
- if (!kp->count)
|
|
- return 0;
|
|
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
|
|
+ assign_in_user(&up->ctrl_class, &kp->ctrl_class) ||
|
|
+ get_user(count, &kp->count) ||
|
|
+ put_user(count, &up->count) ||
|
|
+ assign_in_user(&up->error_idx, &kp->error_idx) ||
|
|
+ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) ||
|
|
+ get_user(kcontrols, &kp->controls))
|
|
+ return -EFAULT;
|
|
|
|
+ if (!count)
|
|
+ return 0;
|
|
if (get_user(p, &up->controls))
|
|
return -EFAULT;
|
|
ucontrols = compat_ptr(p);
|
|
- if (!access_ok(VERIFY_WRITE, ucontrols,
|
|
- n * sizeof(struct v4l2_ext_control32)))
|
|
+ if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols)))
|
|
return -EFAULT;
|
|
|
|
- while (--n >= 0) {
|
|
- unsigned size = sizeof(*ucontrols);
|
|
+ for (n = 0; n < count; n++) {
|
|
+ unsigned int size = sizeof(*ucontrols);
|
|
u32 id;
|
|
|
|
- if (get_user(id, &kcontrols->id))
|
|
+ if (get_user(id, &kcontrols->id) ||
|
|
+ put_user(id, &ucontrols->id) ||
|
|
+ assign_in_user(&ucontrols->size, &kcontrols->size) ||
|
|
+ copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
|
|
+ sizeof(ucontrols->reserved2)))
|
|
return -EFAULT;
|
|
- /* Do not modify the pointer when copying a pointer control.
|
|
- The contents of the pointer was changed, not the pointer
|
|
- itself. */
|
|
- if (ctrl_is_pointer(id))
|
|
+
|
|
+ /*
|
|
+ * Do not modify the pointer when copying a pointer control.
|
|
+ * The contents of the pointer was changed, not the pointer
|
|
+ * itself.
|
|
+ */
|
|
+ if (ctrl_is_pointer(file, id))
|
|
size -= sizeof(ucontrols->value64);
|
|
+
|
|
if (copy_in_user(ucontrols, kcontrols, size))
|
|
return -EFAULT;
|
|
+
|
|
ucontrols++;
|
|
kcontrols++;
|
|
}
|
|
@@ -766,18 +911,19 @@ struct v4l2_event32 {
|
|
__u32 reserved[8];
|
|
};
|
|
|
|
-static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
|
|
+static int put_v4l2_event32(struct v4l2_event __user *kp,
|
|
+ struct v4l2_event32 __user *up)
|
|
{
|
|
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
|
|
- put_user(kp->type, &up->type) ||
|
|
- copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
|
|
- put_user(kp->pending, &up->pending) ||
|
|
- put_user(kp->sequence, &up->sequence) ||
|
|
- put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
|
|
- put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) ||
|
|
- put_user(kp->id, &up->id) ||
|
|
- copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
|
|
- return -EFAULT;
|
|
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
|
|
+ assign_in_user(&up->type, &kp->type) ||
|
|
+ copy_in_user(&up->u, &kp->u, sizeof(kp->u)) ||
|
|
+ assign_in_user(&up->pending, &kp->pending) ||
|
|
+ assign_in_user(&up->sequence, &kp->sequence) ||
|
|
+ assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
|
|
+ assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) ||
|
|
+ assign_in_user(&up->id, &kp->id) ||
|
|
+ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
|
|
+ return -EFAULT;
|
|
return 0;
|
|
}
|
|
|
|
@@ -789,32 +935,35 @@ struct v4l2_edid32 {
|
|
compat_caddr_t edid;
|
|
};
|
|
|
|
-static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
|
|
+static int get_v4l2_edid32(struct v4l2_edid __user *kp,
|
|
+ struct v4l2_edid32 __user *up)
|
|
{
|
|
- u32 tmp;
|
|
-
|
|
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) ||
|
|
- get_user(kp->pad, &up->pad) ||
|
|
- get_user(kp->start_block, &up->start_block) ||
|
|
- get_user(kp->blocks, &up->blocks) ||
|
|
- get_user(tmp, &up->edid) ||
|
|
- copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
|
|
- return -EFAULT;
|
|
- kp->edid = (__force u8 *)compat_ptr(tmp);
|
|
+ compat_uptr_t tmp;
|
|
+
|
|
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
|
|
+ assign_in_user(&kp->pad, &up->pad) ||
|
|
+ assign_in_user(&kp->start_block, &up->start_block) ||
|
|
+ assign_in_user(&kp->blocks, &up->blocks) ||
|
|
+ get_user(tmp, &up->edid) ||
|
|
+ put_user(compat_ptr(tmp), &kp->edid) ||
|
|
+ copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
|
|
+ return -EFAULT;
|
|
return 0;
|
|
}
|
|
|
|
-static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
|
|
+static int put_v4l2_edid32(struct v4l2_edid __user *kp,
|
|
+ struct v4l2_edid32 __user *up)
|
|
{
|
|
- u32 tmp = (u32)((unsigned long)kp->edid);
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
|
|
- put_user(kp->pad, &up->pad) ||
|
|
- put_user(kp->start_block, &up->start_block) ||
|
|
- put_user(kp->blocks, &up->blocks) ||
|
|
- put_user(tmp, &up->edid) ||
|
|
- copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
|
|
- return -EFAULT;
|
|
+ void *edid;
|
|
+
|
|
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
|
|
+ assign_in_user(&up->pad, &kp->pad) ||
|
|
+ assign_in_user(&up->start_block, &kp->start_block) ||
|
|
+ assign_in_user(&up->blocks, &kp->blocks) ||
|
|
+ get_user(edid, &kp->edid) ||
|
|
+ put_user(ptr_to_compat(edid), &up->edid) ||
|
|
+ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
|
|
+ return -EFAULT;
|
|
return 0;
|
|
}
|
|
|
|
@@ -830,7 +979,7 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
|
|
#define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32)
|
|
#define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32)
|
|
#define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32)
|
|
-#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
|
|
+#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
|
|
#define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32)
|
|
#define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32)
|
|
#define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32)
|
|
@@ -846,22 +995,23 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
|
|
#define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32)
|
|
#define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32)
|
|
|
|
+static int alloc_userspace(unsigned int size, u32 aux_space,
|
|
+ void __user **up_native)
|
|
+{
|
|
+ *up_native = compat_alloc_user_space(size + aux_space);
|
|
+ if (!*up_native)
|
|
+ return -ENOMEM;
|
|
+ if (clear_user(*up_native, size))
|
|
+ return -EFAULT;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
{
|
|
- union {
|
|
- struct v4l2_format v2f;
|
|
- struct v4l2_buffer v2b;
|
|
- struct v4l2_framebuffer v2fb;
|
|
- struct v4l2_input v2i;
|
|
- struct v4l2_standard v2s;
|
|
- struct v4l2_ext_controls v2ecs;
|
|
- struct v4l2_event v2ev;
|
|
- struct v4l2_create_buffers v2crt;
|
|
- struct v4l2_edid v2edid;
|
|
- unsigned long vx;
|
|
- int vi;
|
|
- } karg;
|
|
void __user *up = compat_ptr(arg);
|
|
+ void __user *up_native = NULL;
|
|
+ void __user *aux_buf;
|
|
+ u32 aux_space;
|
|
int compatible_arg = 1;
|
|
long err = 0;
|
|
|
|
@@ -900,30 +1050,52 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
|
|
case VIDIOC_STREAMOFF:
|
|
case VIDIOC_S_INPUT:
|
|
case VIDIOC_S_OUTPUT:
|
|
- err = get_user(karg.vi, (s32 __user *)up);
|
|
+ err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
|
|
+ if (!err && assign_in_user((unsigned int __user *)up_native,
|
|
+ (compat_uint_t __user *)up))
|
|
+ err = -EFAULT;
|
|
compatible_arg = 0;
|
|
break;
|
|
|
|
case VIDIOC_G_INPUT:
|
|
case VIDIOC_G_OUTPUT:
|
|
+ err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
|
|
compatible_arg = 0;
|
|
break;
|
|
|
|
case VIDIOC_G_EDID:
|
|
case VIDIOC_S_EDID:
|
|
- err = get_v4l2_edid32(&karg.v2edid, up);
|
|
+ err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native);
|
|
+ if (!err)
|
|
+ err = get_v4l2_edid32(up_native, up);
|
|
compatible_arg = 0;
|
|
break;
|
|
|
|
case VIDIOC_G_FMT:
|
|
case VIDIOC_S_FMT:
|
|
case VIDIOC_TRY_FMT:
|
|
- err = get_v4l2_format32(&karg.v2f, up);
|
|
+ err = bufsize_v4l2_format(up, &aux_space);
|
|
+ if (!err)
|
|
+ err = alloc_userspace(sizeof(struct v4l2_format),
|
|
+ aux_space, &up_native);
|
|
+ if (!err) {
|
|
+ aux_buf = up_native + sizeof(struct v4l2_format);
|
|
+ err = get_v4l2_format32(up_native, up,
|
|
+ aux_buf, aux_space);
|
|
+ }
|
|
compatible_arg = 0;
|
|
break;
|
|
|
|
case VIDIOC_CREATE_BUFS:
|
|
- err = get_v4l2_create32(&karg.v2crt, up);
|
|
+ err = bufsize_v4l2_create(up, &aux_space);
|
|
+ if (!err)
|
|
+ err = alloc_userspace(sizeof(struct v4l2_create_buffers),
|
|
+ aux_space, &up_native);
|
|
+ if (!err) {
|
|
+ aux_buf = up_native + sizeof(struct v4l2_create_buffers);
|
|
+ err = get_v4l2_create32(up_native, up,
|
|
+ aux_buf, aux_space);
|
|
+ }
|
|
compatible_arg = 0;
|
|
break;
|
|
|
|
@@ -931,36 +1103,63 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
|
|
case VIDIOC_QUERYBUF:
|
|
case VIDIOC_QBUF:
|
|
case VIDIOC_DQBUF:
|
|
- err = get_v4l2_buffer32(&karg.v2b, up);
|
|
+ err = bufsize_v4l2_buffer(up, &aux_space);
|
|
+ if (!err)
|
|
+ err = alloc_userspace(sizeof(struct v4l2_buffer),
|
|
+ aux_space, &up_native);
|
|
+ if (!err) {
|
|
+ aux_buf = up_native + sizeof(struct v4l2_buffer);
|
|
+ err = get_v4l2_buffer32(up_native, up,
|
|
+ aux_buf, aux_space);
|
|
+ }
|
|
compatible_arg = 0;
|
|
break;
|
|
|
|
case VIDIOC_S_FBUF:
|
|
- err = get_v4l2_framebuffer32(&karg.v2fb, up);
|
|
+ err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
|
|
+ &up_native);
|
|
+ if (!err)
|
|
+ err = get_v4l2_framebuffer32(up_native, up);
|
|
compatible_arg = 0;
|
|
break;
|
|
|
|
case VIDIOC_G_FBUF:
|
|
+ err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
|
|
+ &up_native);
|
|
compatible_arg = 0;
|
|
break;
|
|
|
|
case VIDIOC_ENUMSTD:
|
|
- err = get_v4l2_standard32(&karg.v2s, up);
|
|
+ err = alloc_userspace(sizeof(struct v4l2_standard), 0,
|
|
+ &up_native);
|
|
+ if (!err)
|
|
+ err = get_v4l2_standard32(up_native, up);
|
|
compatible_arg = 0;
|
|
break;
|
|
|
|
case VIDIOC_ENUMINPUT:
|
|
- err = get_v4l2_input32(&karg.v2i, up);
|
|
+ err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native);
|
|
+ if (!err)
|
|
+ err = get_v4l2_input32(up_native, up);
|
|
compatible_arg = 0;
|
|
break;
|
|
|
|
case VIDIOC_G_EXT_CTRLS:
|
|
case VIDIOC_S_EXT_CTRLS:
|
|
case VIDIOC_TRY_EXT_CTRLS:
|
|
- err = get_v4l2_ext_controls32(&karg.v2ecs, up);
|
|
+ err = bufsize_v4l2_ext_controls(up, &aux_space);
|
|
+ if (!err)
|
|
+ err = alloc_userspace(sizeof(struct v4l2_ext_controls),
|
|
+ aux_space, &up_native);
|
|
+ if (!err) {
|
|
+ aux_buf = up_native + sizeof(struct v4l2_ext_controls);
|
|
+ err = get_v4l2_ext_controls32(file, up_native, up,
|
|
+ aux_buf, aux_space);
|
|
+ }
|
|
compatible_arg = 0;
|
|
break;
|
|
case VIDIOC_DQEVENT:
|
|
+ err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native);
|
|
compatible_arg = 0;
|
|
break;
|
|
}
|
|
@@ -969,22 +1168,26 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
|
|
|
|
if (compatible_arg)
|
|
err = native_ioctl(file, cmd, (unsigned long)up);
|
|
- else {
|
|
- mm_segment_t old_fs = get_fs();
|
|
+ else
|
|
+ err = native_ioctl(file, cmd, (unsigned long)up_native);
|
|
|
|
- set_fs(KERNEL_DS);
|
|
- err = native_ioctl(file, cmd, (unsigned long)&karg);
|
|
- set_fs(old_fs);
|
|
- }
|
|
+ if (err == -ENOTTY)
|
|
+ return err;
|
|
|
|
- /* Special case: even after an error we need to put the
|
|
- results back for these ioctls since the error_idx will
|
|
- contain information on which control failed. */
|
|
+ /*
|
|
+ * Special case: even after an error we need to put the
|
|
+ * results back for these ioctls since the error_idx will
|
|
+ * contain information on which control failed.
|
|
+ */
|
|
switch (cmd) {
|
|
case VIDIOC_G_EXT_CTRLS:
|
|
case VIDIOC_S_EXT_CTRLS:
|
|
case VIDIOC_TRY_EXT_CTRLS:
|
|
- if (put_v4l2_ext_controls32(&karg.v2ecs, up))
|
|
+ if (put_v4l2_ext_controls32(file, up_native, up))
|
|
+ err = -EFAULT;
|
|
+ break;
|
|
+ case VIDIOC_S_EDID:
|
|
+ if (put_v4l2_edid32(up_native, up))
|
|
err = -EFAULT;
|
|
break;
|
|
}
|
|
@@ -996,44 +1199,46 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
|
|
case VIDIOC_S_OUTPUT:
|
|
case VIDIOC_G_INPUT:
|
|
case VIDIOC_G_OUTPUT:
|
|
- err = put_user(((s32)karg.vi), (s32 __user *)up);
|
|
+ if (assign_in_user((compat_uint_t __user *)up,
|
|
+ ((unsigned int __user *)up_native)))
|
|
+ err = -EFAULT;
|
|
break;
|
|
|
|
case VIDIOC_G_FBUF:
|
|
- err = put_v4l2_framebuffer32(&karg.v2fb, up);
|
|
+ err = put_v4l2_framebuffer32(up_native, up);
|
|
break;
|
|
|
|
case VIDIOC_DQEVENT:
|
|
- err = put_v4l2_event32(&karg.v2ev, up);
|
|
+ err = put_v4l2_event32(up_native, up);
|
|
break;
|
|
|
|
case VIDIOC_G_EDID:
|
|
- case VIDIOC_S_EDID:
|
|
- err = put_v4l2_edid32(&karg.v2edid, up);
|
|
+ err = put_v4l2_edid32(up_native, up);
|
|
break;
|
|
|
|
case VIDIOC_G_FMT:
|
|
case VIDIOC_S_FMT:
|
|
case VIDIOC_TRY_FMT:
|
|
- err = put_v4l2_format32(&karg.v2f, up);
|
|
+ err = put_v4l2_format32(up_native, up);
|
|
break;
|
|
|
|
case VIDIOC_CREATE_BUFS:
|
|
- err = put_v4l2_create32(&karg.v2crt, up);
|
|
+ err = put_v4l2_create32(up_native, up);
|
|
break;
|
|
|
|
+ case VIDIOC_PREPARE_BUF:
|
|
case VIDIOC_QUERYBUF:
|
|
case VIDIOC_QBUF:
|
|
case VIDIOC_DQBUF:
|
|
- err = put_v4l2_buffer32(&karg.v2b, up);
|
|
+ err = put_v4l2_buffer32(up_native, up);
|
|
break;
|
|
|
|
case VIDIOC_ENUMSTD:
|
|
- err = put_v4l2_standard32(&karg.v2s, up);
|
|
+ err = put_v4l2_standard32(up_native, up);
|
|
break;
|
|
|
|
case VIDIOC_ENUMINPUT:
|
|
- err = put_v4l2_input32(&karg.v2i, up);
|
|
+ err = put_v4l2_input32(up_native, up);
|
|
break;
|
|
}
|
|
return err;
|
|
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
|
|
index 7486af2c8ae4..5e2a7e59f578 100644
|
|
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
|
|
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
|
|
@@ -2783,8 +2783,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
|
|
|
|
/* Handles IOCTL */
|
|
err = func(file, cmd, parg);
|
|
- if (err == -ENOIOCTLCMD)
|
|
+ if (err == -ENOTTY || err == -ENOIOCTLCMD) {
|
|
err = -ENOTTY;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
if (err == 0) {
|
|
if (cmd == VIDIOC_DQBUF)
|
|
trace_v4l2_dqbuf(video_devdata(file)->minor, parg);
|
|
diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c
|
|
index 6c441be8f893..bf23234d957e 100644
|
|
--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
|
|
+++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
|
|
@@ -593,6 +593,12 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b,
|
|
b->flags & V4L2_BUF_FLAG_LAST)
|
|
q->last_buffer_dequeued = true;
|
|
|
|
+ /*
|
|
+ * After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be
|
|
+ * cleared.
|
|
+ */
|
|
+ b->flags &= ~V4L2_BUF_FLAG_DONE;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
|
|
index 4a07ba1195b5..d125d19a35e4 100644
|
|
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
|
|
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
|
|
@@ -1922,16 +1922,9 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
|
|
tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
|
|
tmp &= ~ACC_CONTROL_RD_ERASED;
|
|
tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
|
|
- if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
|
|
- /*
|
|
- * FIXME: Flash DMA + prefetch may see spurious erased-page ECC
|
|
- * errors
|
|
- */
|
|
- if (has_flash_dma(ctrl))
|
|
- tmp &= ~ACC_CONTROL_PREFETCH;
|
|
- else
|
|
- tmp |= ACC_CONTROL_PREFETCH;
|
|
- }
|
|
+ if (ctrl->features & BRCMNAND_HAS_PREFETCH)
|
|
+ tmp &= ~ACC_CONTROL_PREFETCH;
|
|
+
|
|
nand_writereg(ctrl, offs, tmp);
|
|
|
|
return 0;
|
|
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
|
|
index 7ba109e8cf88..27864c0863ef 100644
|
|
--- a/drivers/mtd/nand/nand_base.c
|
|
+++ b/drivers/mtd/nand/nand_base.c
|
|
@@ -2023,6 +2023,7 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
|
|
static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
|
struct mtd_oob_ops *ops)
|
|
{
|
|
+ unsigned int max_bitflips = 0;
|
|
int page, realpage, chipnr;
|
|
struct nand_chip *chip = mtd->priv;
|
|
struct mtd_ecc_stats stats;
|
|
@@ -2083,6 +2084,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
|
nand_wait_ready(mtd);
|
|
}
|
|
|
|
+ max_bitflips = max_t(unsigned int, max_bitflips, ret);
|
|
+
|
|
readlen -= len;
|
|
if (!readlen)
|
|
break;
|
|
@@ -2108,7 +2111,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
|
if (mtd->ecc_stats.failed - stats.failed)
|
|
return -EBADMSG;
|
|
|
|
- return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
|
|
+ return max_bitflips;
|
|
}
|
|
|
|
/**
|
|
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
|
|
index 824711845c44..3bb9b34d9e77 100644
|
|
--- a/drivers/mtd/nand/sunxi_nand.c
|
|
+++ b/drivers/mtd/nand/sunxi_nand.c
|
|
@@ -1046,8 +1046,14 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
|
|
|
|
/* Add ECC info retrieval from DT */
|
|
for (i = 0; i < ARRAY_SIZE(strengths); i++) {
|
|
- if (ecc->strength <= strengths[i])
|
|
+ if (ecc->strength <= strengths[i]) {
|
|
+ /*
|
|
+ * Update ecc->strength value with the actual strength
|
|
+ * that will be used by the ECC engine.
|
|
+ */
|
|
+ ecc->strength = strengths[i];
|
|
break;
|
|
+ }
|
|
}
|
|
|
|
if (i >= ARRAY_SIZE(strengths)) {
|
|
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
|
|
index ebf46ad2d513..b2fb0528c092 100644
|
|
--- a/drivers/mtd/ubi/block.c
|
|
+++ b/drivers/mtd/ubi/block.c
|
|
@@ -99,6 +99,8 @@ struct ubiblock {
|
|
|
|
/* Linked list of all ubiblock instances */
|
|
static LIST_HEAD(ubiblock_devices);
|
|
+static DEFINE_IDR(ubiblock_minor_idr);
|
|
+/* Protects ubiblock_devices and ubiblock_minor_idr */
|
|
static DEFINE_MUTEX(devices_mutex);
|
|
static int ubiblock_major;
|
|
|
|
@@ -354,8 +356,6 @@ static struct blk_mq_ops ubiblock_mq_ops = {
|
|
.map_queue = blk_mq_map_queue,
|
|
};
|
|
|
|
-static DEFINE_IDR(ubiblock_minor_idr);
|
|
-
|
|
int ubiblock_create(struct ubi_volume_info *vi)
|
|
{
|
|
struct ubiblock *dev;
|
|
@@ -368,14 +368,15 @@ int ubiblock_create(struct ubi_volume_info *vi)
|
|
/* Check that the volume isn't already handled */
|
|
mutex_lock(&devices_mutex);
|
|
if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
|
|
- mutex_unlock(&devices_mutex);
|
|
- return -EEXIST;
|
|
+ ret = -EEXIST;
|
|
+ goto out_unlock;
|
|
}
|
|
- mutex_unlock(&devices_mutex);
|
|
|
|
dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL);
|
|
- if (!dev)
|
|
- return -ENOMEM;
|
|
+ if (!dev) {
|
|
+ ret = -ENOMEM;
|
|
+ goto out_unlock;
|
|
+ }
|
|
|
|
mutex_init(&dev->dev_mutex);
|
|
|
|
@@ -440,14 +441,13 @@ int ubiblock_create(struct ubi_volume_info *vi)
|
|
goto out_free_queue;
|
|
}
|
|
|
|
- mutex_lock(&devices_mutex);
|
|
list_add_tail(&dev->list, &ubiblock_devices);
|
|
- mutex_unlock(&devices_mutex);
|
|
|
|
/* Must be the last step: anyone can call file ops from now on */
|
|
add_disk(dev->gd);
|
|
dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
|
|
dev->ubi_num, dev->vol_id, vi->name);
|
|
+ mutex_unlock(&devices_mutex);
|
|
return 0;
|
|
|
|
out_free_queue:
|
|
@@ -460,6 +460,8 @@ out_put_disk:
|
|
put_disk(dev->gd);
|
|
out_free_dev:
|
|
kfree(dev);
|
|
+out_unlock:
|
|
+ mutex_unlock(&devices_mutex);
|
|
|
|
return ret;
|
|
}
|
|
@@ -481,30 +483,36 @@ static void ubiblock_cleanup(struct ubiblock *dev)
|
|
int ubiblock_remove(struct ubi_volume_info *vi)
|
|
{
|
|
struct ubiblock *dev;
|
|
+ int ret;
|
|
|
|
mutex_lock(&devices_mutex);
|
|
dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
|
|
if (!dev) {
|
|
- mutex_unlock(&devices_mutex);
|
|
- return -ENODEV;
|
|
+ ret = -ENODEV;
|
|
+ goto out_unlock;
|
|
}
|
|
|
|
/* Found a device, let's lock it so we can check if it's busy */
|
|
mutex_lock(&dev->dev_mutex);
|
|
if (dev->refcnt > 0) {
|
|
- mutex_unlock(&dev->dev_mutex);
|
|
- mutex_unlock(&devices_mutex);
|
|
- return -EBUSY;
|
|
+ ret = -EBUSY;
|
|
+ goto out_unlock_dev;
|
|
}
|
|
|
|
/* Remove from device list */
|
|
list_del(&dev->list);
|
|
- mutex_unlock(&devices_mutex);
|
|
-
|
|
ubiblock_cleanup(dev);
|
|
mutex_unlock(&dev->dev_mutex);
|
|
+ mutex_unlock(&devices_mutex);
|
|
+
|
|
kfree(dev);
|
|
return 0;
|
|
+
|
|
+out_unlock_dev:
|
|
+ mutex_unlock(&dev->dev_mutex);
|
|
+out_unlock:
|
|
+ mutex_unlock(&devices_mutex);
|
|
+ return ret;
|
|
}
|
|
|
|
static int ubiblock_resize(struct ubi_volume_info *vi)
|
|
@@ -633,6 +641,7 @@ static void ubiblock_remove_all(void)
|
|
struct ubiblock *next;
|
|
struct ubiblock *dev;
|
|
|
|
+ mutex_lock(&devices_mutex);
|
|
list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
|
|
/* The module is being forcefully removed */
|
|
WARN_ON(dev->desc);
|
|
@@ -641,6 +650,7 @@ static void ubiblock_remove_all(void)
|
|
ubiblock_cleanup(dev);
|
|
kfree(dev);
|
|
}
|
|
+ mutex_unlock(&devices_mutex);
|
|
}
|
|
|
|
int __init ubiblock_init(void)
|
|
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
|
|
index f9640d5ce6ba..b4f3cb55605e 100644
|
|
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
|
|
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
|
|
@@ -3850,7 +3850,7 @@ static void qlcnic_83xx_flush_mbx_queue(struct qlcnic_adapter *adapter)
|
|
struct list_head *head = &mbx->cmd_q;
|
|
struct qlcnic_cmd_args *cmd = NULL;
|
|
|
|
- spin_lock(&mbx->queue_lock);
|
|
+ spin_lock_bh(&mbx->queue_lock);
|
|
|
|
while (!list_empty(head)) {
|
|
cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
|
|
@@ -3861,7 +3861,7 @@ static void qlcnic_83xx_flush_mbx_queue(struct qlcnic_adapter *adapter)
|
|
qlcnic_83xx_notify_cmd_completion(adapter, cmd);
|
|
}
|
|
|
|
- spin_unlock(&mbx->queue_lock);
|
|
+ spin_unlock_bh(&mbx->queue_lock);
|
|
}
|
|
|
|
static int qlcnic_83xx_check_mbx_status(struct qlcnic_adapter *adapter)
|
|
@@ -3897,12 +3897,12 @@ static void qlcnic_83xx_dequeue_mbx_cmd(struct qlcnic_adapter *adapter,
|
|
{
|
|
struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
|
|
|
|
- spin_lock(&mbx->queue_lock);
|
|
+ spin_lock_bh(&mbx->queue_lock);
|
|
|
|
list_del(&cmd->list);
|
|
mbx->num_cmds--;
|
|
|
|
- spin_unlock(&mbx->queue_lock);
|
|
+ spin_unlock_bh(&mbx->queue_lock);
|
|
|
|
qlcnic_83xx_notify_cmd_completion(adapter, cmd);
|
|
}
|
|
@@ -3967,7 +3967,7 @@ static int qlcnic_83xx_enqueue_mbx_cmd(struct qlcnic_adapter *adapter,
|
|
init_completion(&cmd->completion);
|
|
cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_UNKNOWN;
|
|
|
|
- spin_lock(&mbx->queue_lock);
|
|
+ spin_lock_bh(&mbx->queue_lock);
|
|
|
|
list_add_tail(&cmd->list, &mbx->cmd_q);
|
|
mbx->num_cmds++;
|
|
@@ -3975,7 +3975,7 @@ static int qlcnic_83xx_enqueue_mbx_cmd(struct qlcnic_adapter *adapter,
|
|
*timeout = cmd->total_cmds * QLC_83XX_MBX_TIMEOUT;
|
|
queue_work(mbx->work_q, &mbx->work);
|
|
|
|
- spin_unlock(&mbx->queue_lock);
|
|
+ spin_unlock_bh(&mbx->queue_lock);
|
|
|
|
return 0;
|
|
}
|
|
@@ -4071,15 +4071,15 @@ static void qlcnic_83xx_mailbox_worker(struct work_struct *work)
|
|
mbx->rsp_status = QLC_83XX_MBX_RESPONSE_WAIT;
|
|
spin_unlock_irqrestore(&mbx->aen_lock, flags);
|
|
|
|
- spin_lock(&mbx->queue_lock);
|
|
+ spin_lock_bh(&mbx->queue_lock);
|
|
|
|
if (list_empty(head)) {
|
|
- spin_unlock(&mbx->queue_lock);
|
|
+ spin_unlock_bh(&mbx->queue_lock);
|
|
return;
|
|
}
|
|
cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
|
|
|
|
- spin_unlock(&mbx->queue_lock);
|
|
+ spin_unlock_bh(&mbx->queue_lock);
|
|
|
|
mbx_ops->encode_cmd(adapter, cmd);
|
|
mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_REQUEST);
|
|
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
|
|
index 24155380e43c..3783c40f568b 100644
|
|
--- a/drivers/net/ethernet/realtek/r8169.c
|
|
+++ b/drivers/net/ethernet/realtek/r8169.c
|
|
@@ -1387,7 +1387,7 @@ DECLARE_RTL_COND(rtl_ocp_tx_cond)
|
|
{
|
|
void __iomem *ioaddr = tp->mmio_addr;
|
|
|
|
- return RTL_R8(IBISR0) & 0x02;
|
|
+ return RTL_R8(IBISR0) & 0x20;
|
|
}
|
|
|
|
static void rtl8168ep_stop_cmac(struct rtl8169_private *tp)
|
|
@@ -1395,7 +1395,7 @@ static void rtl8168ep_stop_cmac(struct rtl8169_private *tp)
|
|
void __iomem *ioaddr = tp->mmio_addr;
|
|
|
|
RTL_W8(IBCR2, RTL_R8(IBCR2) & ~0x01);
|
|
- rtl_msleep_loop_wait_low(tp, &rtl_ocp_tx_cond, 50, 2000);
|
|
+ rtl_msleep_loop_wait_high(tp, &rtl_ocp_tx_cond, 50, 2000);
|
|
RTL_W8(IBISR0, RTL_R8(IBISR0) | 0x20);
|
|
RTL_W8(IBCR0, RTL_R8(IBCR0) & ~0x01);
|
|
}
|
|
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
|
|
index 1228d0da4075..72cb30828a12 100644
|
|
--- a/drivers/net/usb/cdc_ncm.c
|
|
+++ b/drivers/net/usb/cdc_ncm.c
|
|
@@ -825,6 +825,9 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
|
|
goto error2;
|
|
}
|
|
|
|
+ /* Device-specific flags */
|
|
+ ctx->drvflags = drvflags;
|
|
+
|
|
/*
|
|
* Some Huawei devices have been observed to come out of reset in NDP32 mode.
|
|
* Let's check if this is the case, and set the device to NDP16 mode again if
|
|
@@ -873,9 +876,6 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
|
|
/* finish setting up the device specific data */
|
|
cdc_ncm_setup(dev);
|
|
|
|
- /* Device-specific flags */
|
|
- ctx->drvflags = drvflags;
|
|
-
|
|
/* Allocate the delayed NDP if needed. */
|
|
if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
|
|
ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
|
|
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
|
|
index d6ceb8b91cd6..1c8aedf21370 100644
|
|
--- a/drivers/nvme/host/pci.c
|
|
+++ b/drivers/nvme/host/pci.c
|
|
@@ -2976,10 +2976,16 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
|
|
mutex_unlock(&dev->shutdown_lock);
|
|
}
|
|
|
|
-static void nvme_dev_remove(struct nvme_dev *dev)
|
|
+static void nvme_remove_namespaces(struct nvme_dev *dev)
|
|
{
|
|
struct nvme_ns *ns, *next;
|
|
|
|
+ list_for_each_entry_safe(ns, next, &dev->namespaces, list)
|
|
+ nvme_ns_remove(ns);
|
|
+}
|
|
+
|
|
+static void nvme_dev_remove(struct nvme_dev *dev)
|
|
+{
|
|
if (nvme_io_incapable(dev)) {
|
|
/*
|
|
* If the device is not capable of IO (surprise hot-removal,
|
|
@@ -2989,8 +2995,7 @@ static void nvme_dev_remove(struct nvme_dev *dev)
|
|
*/
|
|
nvme_dev_shutdown(dev);
|
|
}
|
|
- list_for_each_entry_safe(ns, next, &dev->namespaces, list)
|
|
- nvme_ns_remove(ns);
|
|
+ nvme_remove_namespaces(dev);
|
|
}
|
|
|
|
static int nvme_setup_prp_pools(struct nvme_dev *dev)
|
|
@@ -3174,7 +3179,7 @@ static void nvme_probe_work(struct work_struct *work)
|
|
*/
|
|
if (dev->online_queues < 2) {
|
|
dev_warn(dev->dev, "IO queues not created\n");
|
|
- nvme_dev_remove(dev);
|
|
+ nvme_remove_namespaces(dev);
|
|
} else {
|
|
nvme_unfreeze_queues(dev);
|
|
nvme_dev_add(dev);
|
|
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
|
|
index ad8c9b05572d..01656f1c6d65 100644
|
|
--- a/drivers/usb/gadget/function/uvc_configfs.c
|
|
+++ b/drivers/usb/gadget/function/uvc_configfs.c
|
|
@@ -2202,7 +2202,7 @@ static struct configfs_item_operations uvc_item_ops = {
|
|
.release = uvc_attr_release,
|
|
};
|
|
|
|
-#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit) \
|
|
+#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \
|
|
static ssize_t f_uvc_opts_##cname##_show( \
|
|
struct config_item *item, char *page) \
|
|
{ \
|
|
@@ -2245,16 +2245,16 @@ end: \
|
|
return ret; \
|
|
} \
|
|
\
|
|
-UVC_ATTR(f_uvc_opts_, cname, aname)
|
|
+UVC_ATTR(f_uvc_opts_, cname, cname)
|
|
|
|
#define identity_conv(x) (x)
|
|
|
|
-UVCG_OPTS_ATTR(streaming_interval, identity_conv, kstrtou8, u8, identity_conv,
|
|
- 16);
|
|
-UVCG_OPTS_ATTR(streaming_maxpacket, le16_to_cpu, kstrtou16, u16, le16_to_cpu,
|
|
- 3072);
|
|
-UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv,
|
|
- 15);
|
|
+UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv,
|
|
+ kstrtou8, u8, identity_conv, 16);
|
|
+UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu,
|
|
+ kstrtou16, u16, le16_to_cpu, 3072);
|
|
+UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv,
|
|
+ kstrtou8, u8, identity_conv, 15);
|
|
|
|
#undef identity_conv
|
|
|
|
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
|
|
index 00d68945548e..2d96bfd34138 100644
|
|
--- a/drivers/usb/usbip/vhci_hcd.c
|
|
+++ b/drivers/usb/usbip/vhci_hcd.c
|
|
@@ -285,7 +285,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|
case USB_PORT_FEAT_POWER:
|
|
usbip_dbg_vhci_rh(
|
|
" ClearPortFeature: USB_PORT_FEAT_POWER\n");
|
|
- dum->port_status[rhport] = 0;
|
|
+ dum->port_status[rhport] &= ~USB_PORT_STAT_POWER;
|
|
dum->resuming = 0;
|
|
break;
|
|
case USB_PORT_FEAT_C_RESET:
|
|
diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c
|
|
index 1c7f41a65565..b9432fdec775 100644
|
|
--- a/drivers/usb/usbip/vhci_sysfs.c
|
|
+++ b/drivers/usb/usbip/vhci_sysfs.c
|
|
@@ -53,7 +53,7 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
|
|
* a security hole, the change is made to use sockfd instead.
|
|
*/
|
|
out += sprintf(out,
|
|
- "prt sta spd bus dev sockfd local_busid\n");
|
|
+ "prt sta spd dev sockfd local_busid\n");
|
|
|
|
for (i = 0; i < VHCI_NPORTS; i++) {
|
|
struct vhci_device *vdev = port_to_vdev(i);
|
|
@@ -64,12 +64,11 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
|
|
if (vdev->ud.status == VDEV_ST_USED) {
|
|
out += sprintf(out, "%03u %08x ",
|
|
vdev->speed, vdev->devid);
|
|
- out += sprintf(out, "%16p ", vdev->ud.tcp_socket);
|
|
- out += sprintf(out, "%06u", vdev->ud.sockfd);
|
|
+ out += sprintf(out, "%06u ", vdev->ud.sockfd);
|
|
out += sprintf(out, "%s", dev_name(&vdev->udev->dev));
|
|
|
|
} else
|
|
- out += sprintf(out, "000 000 000 000000 0-0");
|
|
+ out += sprintf(out, "000 00000000 000000 0-0");
|
|
|
|
out += sprintf(out, "\n");
|
|
spin_unlock(&vdev->ud.lock);
|
|
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
|
|
index 9eda69e40678..44a5a8777053 100644
|
|
--- a/drivers/vhost/net.c
|
|
+++ b/drivers/vhost/net.c
|
|
@@ -981,6 +981,7 @@ static long vhost_net_reset_owner(struct vhost_net *n)
|
|
}
|
|
vhost_net_stop(n, &tx_sock, &rx_sock);
|
|
vhost_net_flush(n);
|
|
+ vhost_dev_stop(&n->dev);
|
|
vhost_dev_reset_owner(&n->dev, memory);
|
|
vhost_net_vq_reset(n);
|
|
done:
|
|
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
|
|
index 29ef719a6a3c..d69ab1e28d7d 100644
|
|
--- a/drivers/watchdog/imx2_wdt.c
|
|
+++ b/drivers/watchdog/imx2_wdt.c
|
|
@@ -161,15 +161,21 @@ static void imx2_wdt_timer_ping(unsigned long arg)
|
|
mod_timer(&wdev->timer, jiffies + wdog->timeout * HZ / 2);
|
|
}
|
|
|
|
-static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
|
|
- unsigned int new_timeout)
|
|
+static void __imx2_wdt_set_timeout(struct watchdog_device *wdog,
|
|
+ unsigned int new_timeout)
|
|
{
|
|
struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
|
|
|
|
- wdog->timeout = new_timeout;
|
|
-
|
|
regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
|
|
WDOG_SEC_TO_COUNT(new_timeout));
|
|
+}
|
|
+
|
|
+static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
|
|
+ unsigned int new_timeout)
|
|
+{
|
|
+ __imx2_wdt_set_timeout(wdog, new_timeout);
|
|
+
|
|
+ wdog->timeout = new_timeout;
|
|
return 0;
|
|
}
|
|
|
|
@@ -353,7 +359,11 @@ static int imx2_wdt_suspend(struct device *dev)
|
|
|
|
/* The watchdog IP block is running */
|
|
if (imx2_wdt_is_running(wdev)) {
|
|
- imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
|
|
+ /*
|
|
+ * Don't update wdog->timeout, we'll restore the current value
|
|
+ * during resume.
|
|
+ */
|
|
+ __imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
|
|
imx2_wdt_ping(wdog);
|
|
|
|
/* The watchdog is not active */
|
|
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
|
|
index af1da85da509..86d209fc4992 100644
|
|
--- a/fs/btrfs/inode.c
|
|
+++ b/fs/btrfs/inode.c
|
|
@@ -2015,7 +2015,15 @@ again:
|
|
goto out;
|
|
}
|
|
|
|
- btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state);
|
|
+ ret = btrfs_set_extent_delalloc(inode, page_start, page_end,
|
|
+ &cached_state);
|
|
+ if (ret) {
|
|
+ mapping_set_error(page->mapping, ret);
|
|
+ end_extent_writepage(page, ret, page_start, page_end);
|
|
+ ClearPageChecked(page);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
ClearPageChecked(page);
|
|
set_page_dirty(page);
|
|
out:
|
|
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
|
|
index 4acbc390a7d6..1d707a67f8ac 100644
|
|
--- a/fs/cifs/cifsencrypt.c
|
|
+++ b/fs/cifs/cifsencrypt.c
|
|
@@ -306,9 +306,8 @@ int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
|
|
{
|
|
int i;
|
|
int rc;
|
|
- char password_with_pad[CIFS_ENCPWD_SIZE];
|
|
+ char password_with_pad[CIFS_ENCPWD_SIZE] = {0};
|
|
|
|
- memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
|
if (password)
|
|
strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
|
|
|
|
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
|
|
index 0a2bf9462637..077ad3a06c9a 100644
|
|
--- a/fs/cifs/connect.c
|
|
+++ b/fs/cifs/connect.c
|
|
@@ -1695,7 +1695,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
|
tmp_end++;
|
|
if (!(tmp_end < end && tmp_end[1] == delim)) {
|
|
/* No it is not. Set the password to NULL */
|
|
- kfree(vol->password);
|
|
+ kzfree(vol->password);
|
|
vol->password = NULL;
|
|
break;
|
|
}
|
|
@@ -1733,7 +1733,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
|
options = end;
|
|
}
|
|
|
|
- kfree(vol->password);
|
|
+ kzfree(vol->password);
|
|
/* Now build new password string */
|
|
temp_len = strlen(value);
|
|
vol->password = kzalloc(temp_len+1, GFP_KERNEL);
|
|
@@ -4148,7 +4148,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
|
|
reset_cifs_unix_caps(0, tcon, NULL, vol_info);
|
|
out:
|
|
kfree(vol_info->username);
|
|
- kfree(vol_info->password);
|
|
+ kzfree(vol_info->password);
|
|
kfree(vol_info);
|
|
|
|
return tcon;
|
|
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
|
|
index ec2d07bb9beb..744be3c146f5 100644
|
|
--- a/fs/cifs/file.c
|
|
+++ b/fs/cifs/file.c
|
|
@@ -3241,20 +3241,18 @@ static const struct vm_operations_struct cifs_file_vm_ops = {
|
|
|
|
int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
|
|
{
|
|
- int rc, xid;
|
|
+ int xid, rc = 0;
|
|
struct inode *inode = file_inode(file);
|
|
|
|
xid = get_xid();
|
|
|
|
- if (!CIFS_CACHE_READ(CIFS_I(inode))) {
|
|
+ if (!CIFS_CACHE_READ(CIFS_I(inode)))
|
|
rc = cifs_zap_mapping(inode);
|
|
- if (rc)
|
|
- return rc;
|
|
- }
|
|
-
|
|
- rc = generic_file_mmap(file, vma);
|
|
- if (rc == 0)
|
|
+ if (!rc)
|
|
+ rc = generic_file_mmap(file, vma);
|
|
+ if (!rc)
|
|
vma->vm_ops = &cifs_file_vm_ops;
|
|
+
|
|
free_xid(xid);
|
|
return rc;
|
|
}
|
|
@@ -3264,16 +3262,16 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
|
int rc, xid;
|
|
|
|
xid = get_xid();
|
|
+
|
|
rc = cifs_revalidate_file(file);
|
|
- if (rc) {
|
|
+ if (rc)
|
|
cifs_dbg(FYI, "Validation prior to mmap failed, error=%d\n",
|
|
rc);
|
|
- free_xid(xid);
|
|
- return rc;
|
|
- }
|
|
- rc = generic_file_mmap(file, vma);
|
|
- if (rc == 0)
|
|
+ if (!rc)
|
|
+ rc = generic_file_mmap(file, vma);
|
|
+ if (!rc)
|
|
vma->vm_ops = &cifs_file_vm_ops;
|
|
+
|
|
free_xid(xid);
|
|
return rc;
|
|
}
|
|
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
|
|
index 2396ab099849..0cc699d9b932 100644
|
|
--- a/fs/cifs/misc.c
|
|
+++ b/fs/cifs/misc.c
|
|
@@ -99,14 +99,11 @@ sesInfoFree(struct cifs_ses *buf_to_free)
|
|
kfree(buf_to_free->serverOS);
|
|
kfree(buf_to_free->serverDomain);
|
|
kfree(buf_to_free->serverNOS);
|
|
- if (buf_to_free->password) {
|
|
- memset(buf_to_free->password, 0, strlen(buf_to_free->password));
|
|
- kfree(buf_to_free->password);
|
|
- }
|
|
+ kzfree(buf_to_free->password);
|
|
kfree(buf_to_free->user_name);
|
|
kfree(buf_to_free->domainName);
|
|
- kfree(buf_to_free->auth_key.response);
|
|
- kfree(buf_to_free);
|
|
+ kzfree(buf_to_free->auth_key.response);
|
|
+ kzfree(buf_to_free);
|
|
}
|
|
|
|
struct cifs_tcon *
|
|
@@ -137,10 +134,7 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
|
|
}
|
|
atomic_dec(&tconInfoAllocCount);
|
|
kfree(buf_to_free->nativeFileSystem);
|
|
- if (buf_to_free->password) {
|
|
- memset(buf_to_free->password, 0, strlen(buf_to_free->password));
|
|
- kfree(buf_to_free->password);
|
|
- }
|
|
+ kzfree(buf_to_free->password);
|
|
kfree(buf_to_free);
|
|
}
|
|
|
|
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
|
|
index f2ff60e58ec8..84614a5edb87 100644
|
|
--- a/fs/cifs/smb2pdu.c
|
|
+++ b/fs/cifs/smb2pdu.c
|
|
@@ -580,8 +580,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|
}
|
|
|
|
/* check validate negotiate info response matches what we got earlier */
|
|
- if (pneg_rsp->Dialect !=
|
|
- cpu_to_le16(tcon->ses->server->vals->protocol_id))
|
|
+ if (pneg_rsp->Dialect != cpu_to_le16(tcon->ses->server->dialect))
|
|
goto vneg_out;
|
|
|
|
if (pneg_rsp->SecurityMode != cpu_to_le16(tcon->ses->server->sec_mode))
|
|
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
|
|
index 4df1cb19a243..f0cabc8c96cb 100644
|
|
--- a/fs/ext4/inode.c
|
|
+++ b/fs/ext4/inode.c
|
|
@@ -4417,6 +4417,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
|
inode->i_op = &ext4_symlink_inode_operations;
|
|
ext4_set_aops(inode);
|
|
}
|
|
+ inode_nohighmem(inode);
|
|
} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
|
|
S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
|
|
inode->i_op = &ext4_special_inode_operations;
|
|
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
|
|
index 4c36dca486cc..32960b3ecd4f 100644
|
|
--- a/fs/ext4/namei.c
|
|
+++ b/fs/ext4/namei.c
|
|
@@ -3151,6 +3151,7 @@ static int ext4_symlink(struct inode *dir,
|
|
if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
|
|
if (!encryption_required)
|
|
inode->i_op = &ext4_symlink_inode_operations;
|
|
+ inode_nohighmem(inode);
|
|
ext4_set_aops(inode);
|
|
/*
|
|
* We cannot call page_symlink() with transaction started
|
|
diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
|
|
index e8e7af62ac95..287c3980fa0b 100644
|
|
--- a/fs/ext4/symlink.c
|
|
+++ b/fs/ext4/symlink.c
|
|
@@ -45,7 +45,7 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook
|
|
cpage = read_mapping_page(inode->i_mapping, 0, NULL);
|
|
if (IS_ERR(cpage))
|
|
return ERR_CAST(cpage);
|
|
- caddr = kmap(cpage);
|
|
+ caddr = page_address(cpage);
|
|
caddr[size] = 0;
|
|
}
|
|
|
|
@@ -75,16 +75,12 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook
|
|
/* Null-terminate the name */
|
|
if (res <= plen)
|
|
paddr[res] = '\0';
|
|
- if (cpage) {
|
|
- kunmap(cpage);
|
|
+ if (cpage)
|
|
page_cache_release(cpage);
|
|
- }
|
|
return *cookie = paddr;
|
|
errout:
|
|
- if (cpage) {
|
|
- kunmap(cpage);
|
|
+ if (cpage)
|
|
page_cache_release(cpage);
|
|
- }
|
|
kfree(paddr);
|
|
return ERR_PTR(res);
|
|
}
|
|
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
|
|
index 97e20decacb4..5528801a5baf 100644
|
|
--- a/fs/f2fs/inode.c
|
|
+++ b/fs/f2fs/inode.c
|
|
@@ -202,6 +202,7 @@ make_now:
|
|
inode->i_op = &f2fs_encrypted_symlink_inode_operations;
|
|
else
|
|
inode->i_op = &f2fs_symlink_inode_operations;
|
|
+ inode_nohighmem(inode);
|
|
inode->i_mapping->a_ops = &f2fs_dblock_aops;
|
|
} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
|
|
S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
|
|
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
|
|
index 2c32110f9fc0..484df6850747 100644
|
|
--- a/fs/f2fs/namei.c
|
|
+++ b/fs/f2fs/namei.c
|
|
@@ -351,6 +351,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
|
|
inode->i_op = &f2fs_encrypted_symlink_inode_operations;
|
|
else
|
|
inode->i_op = &f2fs_symlink_inode_operations;
|
|
+ inode_nohighmem(inode);
|
|
inode->i_mapping->a_ops = &f2fs_dblock_aops;
|
|
|
|
f2fs_lock_op(sbi);
|
|
@@ -942,7 +943,7 @@ static const char *f2fs_encrypted_follow_link(struct dentry *dentry, void **cook
|
|
cpage = read_mapping_page(inode->i_mapping, 0, NULL);
|
|
if (IS_ERR(cpage))
|
|
return ERR_CAST(cpage);
|
|
- caddr = kmap(cpage);
|
|
+ caddr = page_address(cpage);
|
|
caddr[size] = 0;
|
|
|
|
/* Symlink is encrypted */
|
|
@@ -982,13 +983,11 @@ static const char *f2fs_encrypted_follow_link(struct dentry *dentry, void **cook
|
|
/* Null-terminate the name */
|
|
paddr[res] = '\0';
|
|
|
|
- kunmap(cpage);
|
|
page_cache_release(cpage);
|
|
return *cookie = paddr;
|
|
errout:
|
|
kfree(cstr.name);
|
|
f2fs_fname_crypto_free_buffer(&pstr);
|
|
- kunmap(cpage);
|
|
page_cache_release(cpage);
|
|
return ERR_PTR(res);
|
|
}
|
|
diff --git a/fs/inode.c b/fs/inode.c
|
|
index b0edef500590..b95615f3fc50 100644
|
|
--- a/fs/inode.c
|
|
+++ b/fs/inode.c
|
|
@@ -2028,3 +2028,9 @@ void inode_set_flags(struct inode *inode, unsigned int flags,
|
|
new_flags) != old_flags));
|
|
}
|
|
EXPORT_SYMBOL(inode_set_flags);
|
|
+
|
|
+void inode_nohighmem(struct inode *inode)
|
|
+{
|
|
+ mapping_set_gfp_mask(inode->i_mapping, GFP_USER);
|
|
+}
|
|
+EXPORT_SYMBOL(inode_nohighmem);
|
|
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
|
|
index 6e9a912d394c..6875bd5d35f6 100644
|
|
--- a/fs/kernfs/file.c
|
|
+++ b/fs/kernfs/file.c
|
|
@@ -272,7 +272,7 @@ static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
|
|
{
|
|
struct kernfs_open_file *of = kernfs_of(file);
|
|
const struct kernfs_ops *ops;
|
|
- size_t len;
|
|
+ ssize_t len;
|
|
char *buf;
|
|
|
|
if (of->atomic_write_len) {
|
|
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
|
|
index 4b1d08f56aba..5fd3cf54b2b3 100644
|
|
--- a/fs/nfs/direct.c
|
|
+++ b/fs/nfs/direct.c
|
|
@@ -787,10 +787,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
|
|
|
|
spin_lock(&dreq->lock);
|
|
|
|
- if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
|
|
- dreq->flags = 0;
|
|
+ if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
|
|
dreq->error = hdr->error;
|
|
- }
|
|
if (dreq->error == 0) {
|
|
nfs_direct_good_bytes(dreq, hdr);
|
|
if (nfs_write_need_commit(hdr)) {
|
|
diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
|
|
index 5ba22c6b0ffa..1ee62e62ea76 100644
|
|
--- a/fs/nfs/nfs4idmap.c
|
|
+++ b/fs/nfs/nfs4idmap.c
|
|
@@ -567,9 +567,13 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
|
|
struct idmap_msg *im;
|
|
struct idmap *idmap = (struct idmap *)aux;
|
|
struct key *key = cons->key;
|
|
- int ret = -ENOMEM;
|
|
+ int ret = -ENOKEY;
|
|
+
|
|
+ if (!aux)
|
|
+ goto out1;
|
|
|
|
/* msg and im are freed in idmap_pipe_destroy_msg */
|
|
+ ret = -ENOMEM;
|
|
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
|
if (!data)
|
|
goto out1;
|
|
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
|
|
index 7af7bedd7c02..c8e75e5e6a67 100644
|
|
--- a/fs/nfs/pnfs.c
|
|
+++ b/fs/nfs/pnfs.c
|
|
@@ -1943,7 +1943,7 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
|
|
nfs_pageio_reset_write_mds(desc);
|
|
mirror->pg_recoalesce = 1;
|
|
}
|
|
- hdr->release(hdr);
|
|
+ hdr->completion_ops->completion(hdr);
|
|
}
|
|
|
|
static enum pnfs_try_status
|
|
@@ -2058,7 +2058,7 @@ pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
|
|
nfs_pageio_reset_read_mds(desc);
|
|
mirror->pg_recoalesce = 1;
|
|
}
|
|
- hdr->release(hdr);
|
|
+ hdr->completion_ops->completion(hdr);
|
|
}
|
|
|
|
/*
|
|
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
|
|
index 7a9b6e347249..6e81a5b5858e 100644
|
|
--- a/fs/nfs/write.c
|
|
+++ b/fs/nfs/write.c
|
|
@@ -1746,6 +1746,8 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
|
|
set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags);
|
|
next:
|
|
nfs_unlock_and_release_request(req);
|
|
+ /* Latency breaker */
|
|
+ cond_resched();
|
|
}
|
|
nfss = NFS_SERVER(data->inode);
|
|
if (atomic_long_read(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)
|
|
diff --git a/fs/nsfs.c b/fs/nsfs.c
|
|
index 8f20d6016e20..914ca6b2794d 100644
|
|
--- a/fs/nsfs.c
|
|
+++ b/fs/nsfs.c
|
|
@@ -95,6 +95,7 @@ slow:
|
|
return ERR_PTR(-ENOMEM);
|
|
}
|
|
d_instantiate(dentry, inode);
|
|
+ dentry->d_flags |= DCACHE_RCUACCESS;
|
|
dentry->d_fsdata = (void *)ns_ops;
|
|
d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
|
|
if (d) {
|
|
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
|
|
index adcb1398c481..299a6e1d6b77 100644
|
|
--- a/fs/overlayfs/readdir.c
|
|
+++ b/fs/overlayfs/readdir.c
|
|
@@ -441,10 +441,14 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
|
|
struct dentry *dentry = file->f_path.dentry;
|
|
struct file *realfile = od->realfile;
|
|
|
|
+ /* Nothing to sync for lower */
|
|
+ if (!OVL_TYPE_UPPER(ovl_path_type(dentry)))
|
|
+ return 0;
|
|
+
|
|
/*
|
|
* Need to check if we started out being a lower dir, but got copied up
|
|
*/
|
|
- if (!od->is_upper && OVL_TYPE_UPPER(ovl_path_type(dentry))) {
|
|
+ if (!od->is_upper) {
|
|
struct inode *inode = file_inode(file);
|
|
|
|
realfile = lockless_dereference(od->upperfile);
|
|
diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
|
|
index 9779c35f8454..dab9569f22bf 100644
|
|
--- a/include/crypto/internal/hash.h
|
|
+++ b/include/crypto/internal/hash.h
|
|
@@ -91,6 +91,8 @@ static inline bool crypto_shash_alg_has_setkey(struct shash_alg *alg)
|
|
return alg->setkey != shash_no_setkey;
|
|
}
|
|
|
|
+bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg);
|
|
+
|
|
int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn,
|
|
struct hash_alg_common *alg,
|
|
struct crypto_instance *inst);
|
|
diff --git a/include/crypto/poly1305.h b/include/crypto/poly1305.h
|
|
index 894df59b74e4..d586f741cab5 100644
|
|
--- a/include/crypto/poly1305.h
|
|
+++ b/include/crypto/poly1305.h
|
|
@@ -30,8 +30,6 @@ struct poly1305_desc_ctx {
|
|
};
|
|
|
|
int crypto_poly1305_init(struct shash_desc *desc);
|
|
-int crypto_poly1305_setkey(struct crypto_shash *tfm,
|
|
- const u8 *key, unsigned int keylen);
|
|
unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
|
|
const u8 *src, unsigned int srclen);
|
|
int crypto_poly1305_update(struct shash_desc *desc,
|
|
diff --git a/include/linux/fs.h b/include/linux/fs.h
|
|
index c8decb7075d6..f746a59fcc88 100644
|
|
--- a/include/linux/fs.h
|
|
+++ b/include/linux/fs.h
|
|
@@ -3066,5 +3066,6 @@ static inline bool dir_relax(struct inode *inode)
|
|
}
|
|
|
|
extern bool path_noexec(const struct path *path);
|
|
+extern void inode_nohighmem(struct inode *inode);
|
|
|
|
#endif /* _LINUX_FS_H */
|
|
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
|
|
index 806d0ab845e0..676d3d2a1a0a 100644
|
|
--- a/include/linux/mtd/map.h
|
|
+++ b/include/linux/mtd/map.h
|
|
@@ -265,75 +265,67 @@ void map_destroy(struct mtd_info *mtd);
|
|
#define INVALIDATE_CACHED_RANGE(map, from, size) \
|
|
do { if (map->inval_cache) map->inval_cache(map, from, size); } while (0)
|
|
|
|
-
|
|
-static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2)
|
|
-{
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < map_words(map); i++) {
|
|
- if (val1.x[i] != val2.x[i])
|
|
- return 0;
|
|
- }
|
|
-
|
|
- return 1;
|
|
-}
|
|
-
|
|
-static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2)
|
|
-{
|
|
- map_word r;
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < map_words(map); i++)
|
|
- r.x[i] = val1.x[i] & val2.x[i];
|
|
-
|
|
- return r;
|
|
-}
|
|
-
|
|
-static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2)
|
|
-{
|
|
- map_word r;
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < map_words(map); i++)
|
|
- r.x[i] = val1.x[i] & ~val2.x[i];
|
|
-
|
|
- return r;
|
|
-}
|
|
-
|
|
-static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
|
|
-{
|
|
- map_word r;
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < map_words(map); i++)
|
|
- r.x[i] = val1.x[i] | val2.x[i];
|
|
-
|
|
- return r;
|
|
-}
|
|
-
|
|
-static inline int map_word_andequal(struct map_info *map, map_word val1, map_word val2, map_word val3)
|
|
-{
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < map_words(map); i++) {
|
|
- if ((val1.x[i] & val2.x[i]) != val3.x[i])
|
|
- return 0;
|
|
- }
|
|
-
|
|
- return 1;
|
|
-}
|
|
-
|
|
-static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
|
|
-{
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < map_words(map); i++) {
|
|
- if (val1.x[i] & val2.x[i])
|
|
- return 1;
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
+#define map_word_equal(map, val1, val2) \
|
|
+({ \
|
|
+ int i, ret = 1; \
|
|
+ for (i = 0; i < map_words(map); i++) \
|
|
+ if ((val1).x[i] != (val2).x[i]) { \
|
|
+ ret = 0; \
|
|
+ break; \
|
|
+ } \
|
|
+ ret; \
|
|
+})
|
|
+
|
|
+#define map_word_and(map, val1, val2) \
|
|
+({ \
|
|
+ map_word r; \
|
|
+ int i; \
|
|
+ for (i = 0; i < map_words(map); i++) \
|
|
+ r.x[i] = (val1).x[i] & (val2).x[i]; \
|
|
+ r; \
|
|
+})
|
|
+
|
|
+#define map_word_clr(map, val1, val2) \
|
|
+({ \
|
|
+ map_word r; \
|
|
+ int i; \
|
|
+ for (i = 0; i < map_words(map); i++) \
|
|
+ r.x[i] = (val1).x[i] & ~(val2).x[i]; \
|
|
+ r; \
|
|
+})
|
|
+
|
|
+#define map_word_or(map, val1, val2) \
|
|
+({ \
|
|
+ map_word r; \
|
|
+ int i; \
|
|
+ for (i = 0; i < map_words(map); i++) \
|
|
+ r.x[i] = (val1).x[i] | (val2).x[i]; \
|
|
+ r; \
|
|
+})
|
|
+
|
|
+#define map_word_andequal(map, val1, val2, val3) \
|
|
+({ \
|
|
+ int i, ret = 1; \
|
|
+ for (i = 0; i < map_words(map); i++) { \
|
|
+ if (((val1).x[i] & (val2).x[i]) != (val2).x[i]) { \
|
|
+ ret = 0; \
|
|
+ break; \
|
|
+ } \
|
|
+ } \
|
|
+ ret; \
|
|
+})
|
|
+
|
|
+#define map_word_bitsset(map, val1, val2) \
|
|
+({ \
|
|
+ int i, ret = 0; \
|
|
+ for (i = 0; i < map_words(map); i++) { \
|
|
+ if ((val1).x[i] & (val2).x[i]) { \
|
|
+ ret = 1; \
|
|
+ break; \
|
|
+ } \
|
|
+ } \
|
|
+ ret; \
|
|
+})
|
|
|
|
static inline map_word map_word_load(struct map_info *map, const void *ptr)
|
|
{
|
|
diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h
|
|
index 9c5638ad872e..0dbce55437f2 100644
|
|
--- a/include/net/netfilter/nf_queue.h
|
|
+++ b/include/net/netfilter/nf_queue.h
|
|
@@ -28,8 +28,8 @@ struct nf_queue_handler {
|
|
struct nf_hook_ops *ops);
|
|
};
|
|
|
|
-void nf_register_queue_handler(const struct nf_queue_handler *qh);
|
|
-void nf_unregister_queue_handler(void);
|
|
+void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh);
|
|
+void nf_unregister_queue_handler(struct net *net);
|
|
void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
|
|
|
|
void nf_queue_entry_get_refs(struct nf_queue_entry *entry);
|
|
diff --git a/include/net/netns/netfilter.h b/include/net/netns/netfilter.h
|
|
index 38aa4983e2a9..36d723579af2 100644
|
|
--- a/include/net/netns/netfilter.h
|
|
+++ b/include/net/netns/netfilter.h
|
|
@@ -5,11 +5,13 @@
|
|
|
|
struct proc_dir_entry;
|
|
struct nf_logger;
|
|
+struct nf_queue_handler;
|
|
|
|
struct netns_nf {
|
|
#if defined CONFIG_PROC_FS
|
|
struct proc_dir_entry *proc_netfilter;
|
|
#endif
|
|
+ const struct nf_queue_handler __rcu *queue_handler;
|
|
const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO];
|
|
#ifdef CONFIG_SYSCTL
|
|
struct ctl_table_header *nf_log_dir_header;
|
|
diff --git a/kernel/async.c b/kernel/async.c
|
|
index 4c3773c0bf63..f1fd155abff6 100644
|
|
--- a/kernel/async.c
|
|
+++ b/kernel/async.c
|
|
@@ -84,20 +84,24 @@ static atomic_t entry_count;
|
|
|
|
static async_cookie_t lowest_in_progress(struct async_domain *domain)
|
|
{
|
|
- struct list_head *pending;
|
|
+ struct async_entry *first = NULL;
|
|
async_cookie_t ret = ASYNC_COOKIE_MAX;
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&async_lock, flags);
|
|
|
|
- if (domain)
|
|
- pending = &domain->pending;
|
|
- else
|
|
- pending = &async_global_pending;
|
|
+ if (domain) {
|
|
+ if (!list_empty(&domain->pending))
|
|
+ first = list_first_entry(&domain->pending,
|
|
+ struct async_entry, domain_list);
|
|
+ } else {
|
|
+ if (!list_empty(&async_global_pending))
|
|
+ first = list_first_entry(&async_global_pending,
|
|
+ struct async_entry, global_list);
|
|
+ }
|
|
|
|
- if (!list_empty(pending))
|
|
- ret = list_first_entry(pending, struct async_entry,
|
|
- domain_list)->cookie;
|
|
+ if (first)
|
|
+ ret = first->cookie;
|
|
|
|
spin_unlock_irqrestore(&async_lock, flags);
|
|
return ret;
|
|
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
|
|
index e6d1173a2046..c5b1c62623cf 100644
|
|
--- a/kernel/sched/core.c
|
|
+++ b/kernel/sched/core.c
|
|
@@ -5896,6 +5896,19 @@ static void rq_attach_root(struct rq *rq, struct root_domain *rd)
|
|
call_rcu_sched(&old_rd->rcu, free_rootdomain);
|
|
}
|
|
|
|
+void sched_get_rd(struct root_domain *rd)
|
|
+{
|
|
+ atomic_inc(&rd->refcount);
|
|
+}
|
|
+
|
|
+void sched_put_rd(struct root_domain *rd)
|
|
+{
|
|
+ if (!atomic_dec_and_test(&rd->refcount))
|
|
+ return;
|
|
+
|
|
+ call_rcu_sched(&rd->rcu, free_rootdomain);
|
|
+}
|
|
+
|
|
static int init_rootdomain(struct root_domain *rd)
|
|
{
|
|
memset(rd, 0, sizeof(*rd));
|
|
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
|
|
index 95fefb364dab..e0b5169aeac4 100644
|
|
--- a/kernel/sched/rt.c
|
|
+++ b/kernel/sched/rt.c
|
|
@@ -1833,9 +1833,8 @@ static void push_rt_tasks(struct rq *rq)
|
|
* the rt_loop_next will cause the iterator to perform another scan.
|
|
*
|
|
*/
|
|
-static int rto_next_cpu(struct rq *rq)
|
|
+static int rto_next_cpu(struct root_domain *rd)
|
|
{
|
|
- struct root_domain *rd = rq->rd;
|
|
int next;
|
|
int cpu;
|
|
|
|
@@ -1911,19 +1910,24 @@ static void tell_cpu_to_push(struct rq *rq)
|
|
* Otherwise it is finishing up and an ipi needs to be sent.
|
|
*/
|
|
if (rq->rd->rto_cpu < 0)
|
|
- cpu = rto_next_cpu(rq);
|
|
+ cpu = rto_next_cpu(rq->rd);
|
|
|
|
raw_spin_unlock(&rq->rd->rto_lock);
|
|
|
|
rto_start_unlock(&rq->rd->rto_loop_start);
|
|
|
|
- if (cpu >= 0)
|
|
+ if (cpu >= 0) {
|
|
+ /* Make sure the rd does not get freed while pushing */
|
|
+ sched_get_rd(rq->rd);
|
|
irq_work_queue_on(&rq->rd->rto_push_work, cpu);
|
|
+ }
|
|
}
|
|
|
|
/* Called from hardirq context */
|
|
void rto_push_irq_work_func(struct irq_work *work)
|
|
{
|
|
+ struct root_domain *rd =
|
|
+ container_of(work, struct root_domain, rto_push_work);
|
|
struct rq *rq;
|
|
int cpu;
|
|
|
|
@@ -1939,18 +1943,20 @@ void rto_push_irq_work_func(struct irq_work *work)
|
|
raw_spin_unlock(&rq->lock);
|
|
}
|
|
|
|
- raw_spin_lock(&rq->rd->rto_lock);
|
|
+ raw_spin_lock(&rd->rto_lock);
|
|
|
|
/* Pass the IPI to the next rt overloaded queue */
|
|
- cpu = rto_next_cpu(rq);
|
|
+ cpu = rto_next_cpu(rd);
|
|
|
|
- raw_spin_unlock(&rq->rd->rto_lock);
|
|
+ raw_spin_unlock(&rd->rto_lock);
|
|
|
|
- if (cpu < 0)
|
|
+ if (cpu < 0) {
|
|
+ sched_put_rd(rd);
|
|
return;
|
|
+ }
|
|
|
|
/* Try the next RT overloaded CPU */
|
|
- irq_work_queue_on(&rq->rd->rto_push_work, cpu);
|
|
+ irq_work_queue_on(&rd->rto_push_work, cpu);
|
|
}
|
|
#endif /* HAVE_RT_PUSH_IPI */
|
|
|
|
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
|
|
index 448a8266ceea..0c9ebd82a684 100644
|
|
--- a/kernel/sched/sched.h
|
|
+++ b/kernel/sched/sched.h
|
|
@@ -553,6 +553,8 @@ struct root_domain {
|
|
};
|
|
|
|
extern struct root_domain def_root_domain;
|
|
+extern void sched_get_rd(struct root_domain *rd);
|
|
+extern void sched_put_rd(struct root_domain *rd);
|
|
|
|
#ifdef HAVE_RT_PUSH_IPI
|
|
extern void rto_push_irq_work_func(struct irq_work *work);
|
|
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
|
|
index f2826c35e918..fc7c37ad90a0 100644
|
|
--- a/kernel/time/posix-timers.c
|
|
+++ b/kernel/time/posix-timers.c
|
|
@@ -507,17 +507,22 @@ static struct pid *good_sigevent(sigevent_t * event)
|
|
{
|
|
struct task_struct *rtn = current->group_leader;
|
|
|
|
- if ((event->sigev_notify & SIGEV_THREAD_ID ) &&
|
|
- (!(rtn = find_task_by_vpid(event->sigev_notify_thread_id)) ||
|
|
- !same_thread_group(rtn, current) ||
|
|
- (event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_SIGNAL))
|
|
+ switch (event->sigev_notify) {
|
|
+ case SIGEV_SIGNAL | SIGEV_THREAD_ID:
|
|
+ rtn = find_task_by_vpid(event->sigev_notify_thread_id);
|
|
+ if (!rtn || !same_thread_group(rtn, current))
|
|
+ return NULL;
|
|
+ /* FALLTHRU */
|
|
+ case SIGEV_SIGNAL:
|
|
+ case SIGEV_THREAD:
|
|
+ if (event->sigev_signo <= 0 || event->sigev_signo > SIGRTMAX)
|
|
+ return NULL;
|
|
+ /* FALLTHRU */
|
|
+ case SIGEV_NONE:
|
|
+ return task_pid(rtn);
|
|
+ default:
|
|
return NULL;
|
|
-
|
|
- if (((event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) &&
|
|
- ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX)))
|
|
- return NULL;
|
|
-
|
|
- return task_pid(rtn);
|
|
+ }
|
|
}
|
|
|
|
void posix_timers_register_clock(const clockid_t clock_id,
|
|
@@ -745,8 +750,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
|
|
/* interval timer ? */
|
|
if (iv.tv64)
|
|
cur_setting->it_interval = ktime_to_timespec(iv);
|
|
- else if (!hrtimer_active(timer) &&
|
|
- (timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
|
|
+ else if (!hrtimer_active(timer) && timr->it_sigev_notify != SIGEV_NONE)
|
|
return;
|
|
|
|
now = timer->base->get_time();
|
|
@@ -757,7 +761,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
|
|
* expiry is > now.
|
|
*/
|
|
if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING ||
|
|
- (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE))
|
|
+ timr->it_sigev_notify == SIGEV_NONE))
|
|
timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv);
|
|
|
|
remaining = __hrtimer_expires_remaining_adjusted(timer, now);
|
|
@@ -767,7 +771,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
|
|
* A single shot SIGEV_NONE timer must return 0, when
|
|
* it is expired !
|
|
*/
|
|
- if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
|
|
+ if (timr->it_sigev_notify != SIGEV_NONE)
|
|
cur_setting->it_value.tv_nsec = 1;
|
|
} else
|
|
cur_setting->it_value = ktime_to_timespec(remaining);
|
|
@@ -865,7 +869,7 @@ common_timer_set(struct k_itimer *timr, int flags,
|
|
timr->it.real.interval = timespec_to_ktime(new_setting->it_interval);
|
|
|
|
/* SIGEV_NONE timers are not queued ! See common_timer_get */
|
|
- if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) {
|
|
+ if (timr->it_sigev_notify == SIGEV_NONE) {
|
|
/* Setup correct expiry time for relative timers */
|
|
if (mode == HRTIMER_MODE_REL) {
|
|
hrtimer_add_expires(timer, timer->base->get_time());
|
|
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
|
|
index fc0051fd672d..ac758a53fcea 100644
|
|
--- a/kernel/trace/ftrace.c
|
|
+++ b/kernel/trace/ftrace.c
|
|
@@ -3845,7 +3845,6 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
|
|
func_g.type = filter_parse_regex(glob, strlen(glob),
|
|
&func_g.search, ¬);
|
|
func_g.len = strlen(func_g.search);
|
|
- func_g.search = glob;
|
|
|
|
/* we do not support '!' for function probes */
|
|
if (WARN_ON(not))
|
|
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
|
|
index b68168fcc06a..9d43c1f40274 100644
|
|
--- a/net/dccp/proto.c
|
|
+++ b/net/dccp/proto.c
|
|
@@ -259,6 +259,7 @@ int dccp_disconnect(struct sock *sk, int flags)
|
|
{
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
|
struct inet_sock *inet = inet_sk(sk);
|
|
+ struct dccp_sock *dp = dccp_sk(sk);
|
|
int err = 0;
|
|
const int old_state = sk->sk_state;
|
|
|
|
@@ -278,6 +279,10 @@ int dccp_disconnect(struct sock *sk, int flags)
|
|
sk->sk_err = ECONNRESET;
|
|
|
|
dccp_clear_xmit_timers(sk);
|
|
+ ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
|
|
+ ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
|
|
+ dp->dccps_hc_rx_ccid = NULL;
|
|
+ dp->dccps_hc_tx_ccid = NULL;
|
|
|
|
__skb_queue_purge(&sk->sk_receive_queue);
|
|
__skb_queue_purge(&sk->sk_write_queue);
|
|
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
|
|
index 8212ed80da48..c67efa3e79dd 100644
|
|
--- a/net/ipv4/igmp.c
|
|
+++ b/net/ipv4/igmp.c
|
|
@@ -392,7 +392,11 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
|
|
pip->frag_off = htons(IP_DF);
|
|
pip->ttl = 1;
|
|
pip->daddr = fl4.daddr;
|
|
+
|
|
+ rcu_read_lock();
|
|
pip->saddr = igmpv3_get_srcaddr(dev, &fl4);
|
|
+ rcu_read_unlock();
|
|
+
|
|
pip->protocol = IPPROTO_IGMP;
|
|
pip->tot_len = 0; /* filled in later */
|
|
ip_select_ident(net, skb, NULL);
|
|
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
|
|
index 37e8966a457b..23d77ff1da59 100644
|
|
--- a/net/ipv4/tcp.c
|
|
+++ b/net/ipv4/tcp.c
|
|
@@ -2276,6 +2276,12 @@ int tcp_disconnect(struct sock *sk, int flags)
|
|
|
|
WARN_ON(inet->inet_num && !icsk->icsk_bind_hash);
|
|
|
|
+ if (sk->sk_frag.page) {
|
|
+ put_page(sk->sk_frag.page);
|
|
+ sk->sk_frag.page = NULL;
|
|
+ sk->sk_frag.offset = 0;
|
|
+ }
|
|
+
|
|
sk->sk_error_report(sk);
|
|
return err;
|
|
}
|
|
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
|
|
index 8361d73ab653..e5846d1f9b55 100644
|
|
--- a/net/ipv6/ip6mr.c
|
|
+++ b/net/ipv6/ip6mr.c
|
|
@@ -495,6 +495,7 @@ static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
|
|
return ERR_PTR(-ENOENT);
|
|
|
|
it->mrt = mrt;
|
|
+ it->cache = NULL;
|
|
return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
|
|
: SEQ_START_TOKEN;
|
|
}
|
|
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
|
|
index 5baa8e24e6ac..b19ad20a705c 100644
|
|
--- a/net/netfilter/nf_queue.c
|
|
+++ b/net/netfilter/nf_queue.c
|
|
@@ -26,23 +26,21 @@
|
|
* Once the queue is registered it must reinject all packets it
|
|
* receives, no matter what.
|
|
*/
|
|
-static const struct nf_queue_handler __rcu *queue_handler __read_mostly;
|
|
|
|
/* return EBUSY when somebody else is registered, return EEXIST if the
|
|
* same handler is registered, return 0 in case of success. */
|
|
-void nf_register_queue_handler(const struct nf_queue_handler *qh)
|
|
+void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh)
|
|
{
|
|
/* should never happen, we only have one queueing backend in kernel */
|
|
- WARN_ON(rcu_access_pointer(queue_handler));
|
|
- rcu_assign_pointer(queue_handler, qh);
|
|
+ WARN_ON(rcu_access_pointer(net->nf.queue_handler));
|
|
+ rcu_assign_pointer(net->nf.queue_handler, qh);
|
|
}
|
|
EXPORT_SYMBOL(nf_register_queue_handler);
|
|
|
|
/* The caller must flush their queue before this */
|
|
-void nf_unregister_queue_handler(void)
|
|
+void nf_unregister_queue_handler(struct net *net)
|
|
{
|
|
- RCU_INIT_POINTER(queue_handler, NULL);
|
|
- synchronize_rcu();
|
|
+ RCU_INIT_POINTER(net->nf.queue_handler, NULL);
|
|
}
|
|
EXPORT_SYMBOL(nf_unregister_queue_handler);
|
|
|
|
@@ -103,7 +101,7 @@ void nf_queue_nf_hook_drop(struct net *net, struct nf_hook_ops *ops)
|
|
const struct nf_queue_handler *qh;
|
|
|
|
rcu_read_lock();
|
|
- qh = rcu_dereference(queue_handler);
|
|
+ qh = rcu_dereference(net->nf.queue_handler);
|
|
if (qh)
|
|
qh->nf_hook_drop(net, ops);
|
|
rcu_read_unlock();
|
|
@@ -122,9 +120,10 @@ int nf_queue(struct sk_buff *skb,
|
|
struct nf_queue_entry *entry = NULL;
|
|
const struct nf_afinfo *afinfo;
|
|
const struct nf_queue_handler *qh;
|
|
+ struct net *net = state->net;
|
|
|
|
/* QUEUE == DROP if no one is waiting, to be safe. */
|
|
- qh = rcu_dereference(queue_handler);
|
|
+ qh = rcu_dereference(net->nf.queue_handler);
|
|
if (!qh) {
|
|
status = -ESRCH;
|
|
goto err;
|
|
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
|
|
index c14d2e8eaec3..f853b55bf877 100644
|
|
--- a/net/netfilter/nfnetlink_queue.c
|
|
+++ b/net/netfilter/nfnetlink_queue.c
|
|
@@ -1382,21 +1382,29 @@ static int __net_init nfnl_queue_net_init(struct net *net)
|
|
net->nf.proc_netfilter, &nfqnl_file_ops))
|
|
return -ENOMEM;
|
|
#endif
|
|
+ nf_register_queue_handler(net, &nfqh);
|
|
return 0;
|
|
}
|
|
|
|
static void __net_exit nfnl_queue_net_exit(struct net *net)
|
|
{
|
|
+ nf_unregister_queue_handler(net);
|
|
#ifdef CONFIG_PROC_FS
|
|
remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter);
|
|
#endif
|
|
}
|
|
|
|
+static void nfnl_queue_net_exit_batch(struct list_head *net_exit_list)
|
|
+{
|
|
+ synchronize_rcu();
|
|
+}
|
|
+
|
|
static struct pernet_operations nfnl_queue_net_ops = {
|
|
- .init = nfnl_queue_net_init,
|
|
- .exit = nfnl_queue_net_exit,
|
|
- .id = &nfnl_queue_net_id,
|
|
- .size = sizeof(struct nfnl_queue_net),
|
|
+ .init = nfnl_queue_net_init,
|
|
+ .exit = nfnl_queue_net_exit,
|
|
+ .exit_batch = nfnl_queue_net_exit_batch,
|
|
+ .id = &nfnl_queue_net_id,
|
|
+ .size = sizeof(struct nfnl_queue_net),
|
|
};
|
|
|
|
static int __init nfnetlink_queue_init(void)
|
|
@@ -1417,7 +1425,6 @@ static int __init nfnetlink_queue_init(void)
|
|
}
|
|
|
|
register_netdevice_notifier(&nfqnl_dev_notifier);
|
|
- nf_register_queue_handler(&nfqh);
|
|
return status;
|
|
|
|
cleanup_netlink_notifier:
|
|
@@ -1429,7 +1436,6 @@ out:
|
|
|
|
static void __exit nfnetlink_queue_fini(void)
|
|
{
|
|
- nf_unregister_queue_handler();
|
|
unregister_netdevice_notifier(&nfqnl_dev_notifier);
|
|
nfnetlink_subsys_unregister(&nfqnl_subsys);
|
|
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
|
|
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
|
|
index e080746e1a6b..48958d3cec9e 100644
|
|
--- a/scripts/mod/modpost.c
|
|
+++ b/scripts/mod/modpost.c
|
|
@@ -594,7 +594,8 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname)
|
|
if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 ||
|
|
strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 ||
|
|
strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
|
|
- strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)
|
|
+ strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0 ||
|
|
+ strcmp(symname, ".TOC.") == 0)
|
|
return 1;
|
|
/* Do not ignore this symbol */
|
|
return 0;
|
|
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
|
|
index ce295c0c1da0..e44e844c8ec4 100644
|
|
--- a/security/keys/encrypted-keys/encrypted.c
|
|
+++ b/security/keys/encrypted-keys/encrypted.c
|
|
@@ -141,23 +141,22 @@ static int valid_ecryptfs_desc(const char *ecryptfs_desc)
|
|
*/
|
|
static int valid_master_desc(const char *new_desc, const char *orig_desc)
|
|
{
|
|
- if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) {
|
|
- if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN)
|
|
- goto out;
|
|
- if (orig_desc)
|
|
- if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN))
|
|
- goto out;
|
|
- } else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) {
|
|
- if (strlen(new_desc) == KEY_USER_PREFIX_LEN)
|
|
- goto out;
|
|
- if (orig_desc)
|
|
- if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN))
|
|
- goto out;
|
|
- } else
|
|
- goto out;
|
|
+ int prefix_len;
|
|
+
|
|
+ if (!strncmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN))
|
|
+ prefix_len = KEY_TRUSTED_PREFIX_LEN;
|
|
+ else if (!strncmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN))
|
|
+ prefix_len = KEY_USER_PREFIX_LEN;
|
|
+ else
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!new_desc[prefix_len])
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (orig_desc && strncmp(new_desc, orig_desc, prefix_len))
|
|
+ return -EINVAL;
|
|
+
|
|
return 0;
|
|
-out:
|
|
- return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c
|
|
index 712ed6598c48..ebdf9bd5a64c 100644
|
|
--- a/sound/soc/codecs/pcm512x-spi.c
|
|
+++ b/sound/soc/codecs/pcm512x-spi.c
|
|
@@ -70,3 +70,7 @@ static struct spi_driver pcm512x_spi_driver = {
|
|
};
|
|
|
|
module_spi_driver(pcm512x_spi_driver);
|
|
+
|
|
+MODULE_DESCRIPTION("ASoC PCM512x codec driver - SPI");
|
|
+MODULE_AUTHOR("Mark Brown <broonie@kernel.org>");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
|
|
index ff6fcd9f92f7..0b1b6fcb7500 100644
|
|
--- a/sound/soc/generic/simple-card.c
|
|
+++ b/sound/soc/generic/simple-card.c
|
|
@@ -343,13 +343,19 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
|
|
snprintf(prop, sizeof(prop), "%scpu", prefix);
|
|
cpu = of_get_child_by_name(node, prop);
|
|
|
|
+ if (!cpu) {
|
|
+ ret = -EINVAL;
|
|
+ dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
|
|
+ goto dai_link_of_err;
|
|
+ }
|
|
+
|
|
snprintf(prop, sizeof(prop), "%splat", prefix);
|
|
plat = of_get_child_by_name(node, prop);
|
|
|
|
snprintf(prop, sizeof(prop), "%scodec", prefix);
|
|
codec = of_get_child_by_name(node, prop);
|
|
|
|
- if (!cpu || !codec) {
|
|
+ if (!codec) {
|
|
ret = -EINVAL;
|
|
dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
|
|
goto dai_link_of_err;
|
|
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
|
|
index 085329878525..5976e3992dd1 100644
|
|
--- a/sound/soc/sh/rcar/rsnd.h
|
|
+++ b/sound/soc/sh/rcar/rsnd.h
|
|
@@ -235,6 +235,7 @@ enum rsnd_mod_type {
|
|
RSND_MOD_MIX,
|
|
RSND_MOD_CTU,
|
|
RSND_MOD_SRC,
|
|
+ RSND_MOD_SSIP, /* SSI parent */
|
|
RSND_MOD_SSI,
|
|
RSND_MOD_MAX,
|
|
};
|
|
@@ -365,6 +366,7 @@ struct rsnd_dai_stream {
|
|
};
|
|
#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
|
|
#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
|
|
+#define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP)
|
|
#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC)
|
|
#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU)
|
|
#define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX)
|
|
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
|
|
index c62a2947ac14..38aae96267c9 100644
|
|
--- a/sound/soc/sh/rcar/ssi.c
|
|
+++ b/sound/soc/sh/rcar/ssi.c
|
|
@@ -550,11 +550,16 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
|
|
struct rsnd_priv *priv)
|
|
{
|
|
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
|
|
+ struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io);
|
|
struct device *dev = rsnd_priv_to_dev(priv);
|
|
int irq = ssi->info->irq;
|
|
|
|
rsnd_dma_quit(io, rsnd_mod_to_dma(mod));
|
|
|
|
+ /* Do nothing if non SSI (= SSI parent, multi SSI) mod */
|
|
+ if (pure_ssi_mod != mod)
|
|
+ return 0;
|
|
+
|
|
/* PIO will request IRQ again */
|
|
devm_free_irq(dev, irq, mod);
|
|
|