mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-27 09:11:49 +00:00
4939 lines
153 KiB
Diff
4939 lines
153 KiB
Diff
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
|
|
index 0380a45ecf4b..d6d7669e667f 100644
|
|
--- a/Documentation/admin-guide/kernel-parameters.txt
|
|
+++ b/Documentation/admin-guide/kernel-parameters.txt
|
|
@@ -3997,6 +3997,23 @@
|
|
expediting. Set to zero to disable automatic
|
|
expediting.
|
|
|
|
+ ssbd= [ARM64,HW]
|
|
+ Speculative Store Bypass Disable control
|
|
+
|
|
+ On CPUs that are vulnerable to the Speculative
|
|
+ Store Bypass vulnerability and offer a
|
|
+ firmware based mitigation, this parameter
|
|
+ indicates how the mitigation should be used:
|
|
+
|
|
+ force-on: Unconditionally enable mitigation for
|
|
+ for both kernel and userspace
|
|
+ force-off: Unconditionally disable mitigation for
|
|
+ for both kernel and userspace
|
|
+ kernel: Always enable mitigation in the
|
|
+ kernel, and offer a prctl interface
|
|
+ to allow userspace to register its
|
|
+ interest in being mitigated too.
|
|
+
|
|
stack_guard_gap= [MM]
|
|
override the default stack gap protection. The value
|
|
is in page units and it defines how many pages prior
|
|
diff --git a/Makefile b/Makefile
|
|
index acbb0e3d29c9..a44d6b2adb76 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,7 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
VERSION = 4
|
|
PATCHLEVEL = 14
|
|
-SUBLEVEL = 56
|
|
+SUBLEVEL = 57
|
|
EXTRAVERSION =
|
|
NAME = Petit Gorille
|
|
|
|
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
|
|
index 8f973e3b7348..65572e14306c 100644
|
|
--- a/arch/arm/include/asm/kvm_host.h
|
|
+++ b/arch/arm/include/asm/kvm_host.h
|
|
@@ -302,4 +302,16 @@ static inline bool kvm_arm_harden_branch_predictor(void)
|
|
return false;
|
|
}
|
|
|
|
+#define KVM_SSBD_UNKNOWN -1
|
|
+#define KVM_SSBD_FORCE_DISABLE 0
|
|
+#define KVM_SSBD_KERNEL 1
|
|
+#define KVM_SSBD_FORCE_ENABLE 2
|
|
+#define KVM_SSBD_MITIGATED 3
|
|
+
|
|
+static inline int kvm_arm_have_ssbd(void)
|
|
+{
|
|
+ /* No way to detect it yet, pretend it is not there. */
|
|
+ return KVM_SSBD_UNKNOWN;
|
|
+}
|
|
+
|
|
#endif /* __ARM_KVM_HOST_H__ */
|
|
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
|
|
index 08cd720eae01..8a098e65f5f8 100644
|
|
--- a/arch/arm/include/asm/kvm_mmu.h
|
|
+++ b/arch/arm/include/asm/kvm_mmu.h
|
|
@@ -28,6 +28,13 @@
|
|
*/
|
|
#define kern_hyp_va(kva) (kva)
|
|
|
|
+/* Contrary to arm64, there is no need to generate a PC-relative address */
|
|
+#define hyp_symbol_addr(s) \
|
|
+ ({ \
|
|
+ typeof(s) *addr = &(s); \
|
|
+ addr; \
|
|
+ })
|
|
+
|
|
/*
|
|
* KVM_MMU_CACHE_MIN_PAGES is the number of stage2 page table translation levels.
|
|
*/
|
|
@@ -247,6 +254,11 @@ static inline int kvm_map_vectors(void)
|
|
return 0;
|
|
}
|
|
|
|
+static inline int hyp_map_aux_data(void)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
#endif /* !__ASSEMBLY__ */
|
|
|
|
#endif /* __ARM_KVM_MMU_H__ */
|
|
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
|
|
index 2d5f7aca156d..1bbb89d37f57 100644
|
|
--- a/arch/arm64/Kconfig
|
|
+++ b/arch/arm64/Kconfig
|
|
@@ -849,6 +849,15 @@ config HARDEN_BRANCH_PREDICTOR
|
|
|
|
If unsure, say Y.
|
|
|
|
+config ARM64_SSBD
|
|
+ bool "Speculative Store Bypass Disable" if EXPERT
|
|
+ default y
|
|
+ help
|
|
+ This enables mitigation of the bypassing of previous stores
|
|
+ by speculative loads.
|
|
+
|
|
+ If unsure, say Y.
|
|
+
|
|
menuconfig ARMV8_DEPRECATED
|
|
bool "Emulate deprecated/obsolete ARMv8 instructions"
|
|
depends on COMPAT
|
|
diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h
|
|
index 4a85c6952a22..a91933b1e2e6 100644
|
|
--- a/arch/arm64/include/asm/alternative.h
|
|
+++ b/arch/arm64/include/asm/alternative.h
|
|
@@ -5,6 +5,8 @@
|
|
#include <asm/cpucaps.h>
|
|
#include <asm/insn.h>
|
|
|
|
+#define ARM64_CB_PATCH ARM64_NCAPS
|
|
+
|
|
#ifndef __ASSEMBLY__
|
|
|
|
#include <linux/init.h>
|
|
@@ -12,6 +14,8 @@
|
|
#include <linux/stddef.h>
|
|
#include <linux/stringify.h>
|
|
|
|
+extern int alternatives_applied;
|
|
+
|
|
struct alt_instr {
|
|
s32 orig_offset; /* offset to original instruction */
|
|
s32 alt_offset; /* offset to replacement instruction */
|
|
@@ -20,12 +24,19 @@ struct alt_instr {
|
|
u8 alt_len; /* size of new instruction(s), <= orig_len */
|
|
};
|
|
|
|
+typedef void (*alternative_cb_t)(struct alt_instr *alt,
|
|
+ __le32 *origptr, __le32 *updptr, int nr_inst);
|
|
+
|
|
void __init apply_alternatives_all(void);
|
|
void apply_alternatives(void *start, size_t length);
|
|
|
|
-#define ALTINSTR_ENTRY(feature) \
|
|
+#define ALTINSTR_ENTRY(feature,cb) \
|
|
" .word 661b - .\n" /* label */ \
|
|
+ " .if " __stringify(cb) " == 0\n" \
|
|
" .word 663f - .\n" /* new instruction */ \
|
|
+ " .else\n" \
|
|
+ " .word " __stringify(cb) "- .\n" /* callback */ \
|
|
+ " .endif\n" \
|
|
" .hword " __stringify(feature) "\n" /* feature bit */ \
|
|
" .byte 662b-661b\n" /* source len */ \
|
|
" .byte 664f-663f\n" /* replacement len */
|
|
@@ -43,15 +54,18 @@ void apply_alternatives(void *start, size_t length);
|
|
* but most assemblers die if insn1 or insn2 have a .inst. This should
|
|
* be fixed in a binutils release posterior to 2.25.51.0.2 (anything
|
|
* containing commit 4e4d08cf7399b606 or c1baaddf8861).
|
|
+ *
|
|
+ * Alternatives with callbacks do not generate replacement instructions.
|
|
*/
|
|
-#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled) \
|
|
+#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled, cb) \
|
|
".if "__stringify(cfg_enabled)" == 1\n" \
|
|
"661:\n\t" \
|
|
oldinstr "\n" \
|
|
"662:\n" \
|
|
".pushsection .altinstructions,\"a\"\n" \
|
|
- ALTINSTR_ENTRY(feature) \
|
|
+ ALTINSTR_ENTRY(feature,cb) \
|
|
".popsection\n" \
|
|
+ " .if " __stringify(cb) " == 0\n" \
|
|
".pushsection .altinstr_replacement, \"a\"\n" \
|
|
"663:\n\t" \
|
|
newinstr "\n" \
|
|
@@ -59,11 +73,17 @@ void apply_alternatives(void *start, size_t length);
|
|
".popsection\n\t" \
|
|
".org . - (664b-663b) + (662b-661b)\n\t" \
|
|
".org . - (662b-661b) + (664b-663b)\n" \
|
|
+ ".else\n\t" \
|
|
+ "663:\n\t" \
|
|
+ "664:\n\t" \
|
|
+ ".endif\n" \
|
|
".endif\n"
|
|
|
|
#define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...) \
|
|
- __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg))
|
|
+ __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg), 0)
|
|
|
|
+#define ALTERNATIVE_CB(oldinstr, cb) \
|
|
+ __ALTERNATIVE_CFG(oldinstr, "NOT_AN_INSTRUCTION", ARM64_CB_PATCH, 1, cb)
|
|
#else
|
|
|
|
#include <asm/assembler.h>
|
|
@@ -130,6 +150,14 @@ void apply_alternatives(void *start, size_t length);
|
|
661:
|
|
.endm
|
|
|
|
+.macro alternative_cb cb
|
|
+ .set .Lasm_alt_mode, 0
|
|
+ .pushsection .altinstructions, "a"
|
|
+ altinstruction_entry 661f, \cb, ARM64_CB_PATCH, 662f-661f, 0
|
|
+ .popsection
|
|
+661:
|
|
+.endm
|
|
+
|
|
/*
|
|
* Provide the other half of the alternative code sequence.
|
|
*/
|
|
@@ -155,6 +183,13 @@ void apply_alternatives(void *start, size_t length);
|
|
.org . - (662b-661b) + (664b-663b)
|
|
.endm
|
|
|
|
+/*
|
|
+ * Callback-based alternative epilogue
|
|
+ */
|
|
+.macro alternative_cb_end
|
|
+662:
|
|
+.endm
|
|
+
|
|
/*
|
|
* Provides a trivial alternative or default sequence consisting solely
|
|
* of NOPs. The number of NOPs is chosen automatically to match the
|
|
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
|
|
index 25b2a4161c7a..66aea4aa455d 100644
|
|
--- a/arch/arm64/include/asm/assembler.h
|
|
+++ b/arch/arm64/include/asm/assembler.h
|
|
@@ -260,7 +260,11 @@ lr .req x30 // link register
|
|
#else
|
|
adr_l \dst, \sym
|
|
#endif
|
|
+alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
|
|
mrs \tmp, tpidr_el1
|
|
+alternative_else
|
|
+ mrs \tmp, tpidr_el2
|
|
+alternative_endif
|
|
add \dst, \dst, \tmp
|
|
.endm
|
|
|
|
@@ -271,7 +275,11 @@ lr .req x30 // link register
|
|
*/
|
|
.macro ldr_this_cpu dst, sym, tmp
|
|
adr_l \dst, \sym
|
|
+alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
|
|
mrs \tmp, tpidr_el1
|
|
+alternative_else
|
|
+ mrs \tmp, tpidr_el2
|
|
+alternative_endif
|
|
ldr \dst, [\dst, \tmp]
|
|
.endm
|
|
|
|
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
|
|
index 2e7b236bc596..76c0d23ca161 100644
|
|
--- a/arch/arm64/include/asm/cpucaps.h
|
|
+++ b/arch/arm64/include/asm/cpucaps.h
|
|
@@ -43,7 +43,8 @@
|
|
#define ARM64_UNMAP_KERNEL_AT_EL0 23
|
|
#define ARM64_HARDEN_BRANCH_PREDICTOR 24
|
|
#define ARM64_HARDEN_BP_POST_GUEST_EXIT 25
|
|
+#define ARM64_SSBD 26
|
|
|
|
-#define ARM64_NCAPS 26
|
|
+#define ARM64_NCAPS 27
|
|
|
|
#endif /* __ASM_CPUCAPS_H */
|
|
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
|
|
index 428ee1f2468c..c5bc80a03515 100644
|
|
--- a/arch/arm64/include/asm/cpufeature.h
|
|
+++ b/arch/arm64/include/asm/cpufeature.h
|
|
@@ -262,6 +262,28 @@ static inline bool system_uses_ttbr0_pan(void)
|
|
!cpus_have_const_cap(ARM64_HAS_PAN);
|
|
}
|
|
|
|
+#define ARM64_SSBD_UNKNOWN -1
|
|
+#define ARM64_SSBD_FORCE_DISABLE 0
|
|
+#define ARM64_SSBD_KERNEL 1
|
|
+#define ARM64_SSBD_FORCE_ENABLE 2
|
|
+#define ARM64_SSBD_MITIGATED 3
|
|
+
|
|
+static inline int arm64_get_ssbd_state(void)
|
|
+{
|
|
+#ifdef CONFIG_ARM64_SSBD
|
|
+ extern int ssbd_state;
|
|
+ return ssbd_state;
|
|
+#else
|
|
+ return ARM64_SSBD_UNKNOWN;
|
|
+#endif
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_ARM64_SSBD
|
|
+void arm64_set_ssbd_mitigation(bool state);
|
|
+#else
|
|
+static inline void arm64_set_ssbd_mitigation(bool state) {}
|
|
+#endif
|
|
+
|
|
#endif /* __ASSEMBLY__ */
|
|
|
|
#endif
|
|
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
|
|
index a7ef5a051911..1a6d02350fc6 100644
|
|
--- a/arch/arm64/include/asm/kvm_asm.h
|
|
+++ b/arch/arm64/include/asm/kvm_asm.h
|
|
@@ -33,6 +33,10 @@
|
|
#define KVM_ARM64_DEBUG_DIRTY_SHIFT 0
|
|
#define KVM_ARM64_DEBUG_DIRTY (1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
|
|
|
|
+#define VCPU_WORKAROUND_2_FLAG_SHIFT 0
|
|
+#define VCPU_WORKAROUND_2_FLAG (_AC(1, UL) << VCPU_WORKAROUND_2_FLAG_SHIFT)
|
|
+
|
|
+/* Translate a kernel address of @sym into its equivalent linear mapping */
|
|
#define kvm_ksym_ref(sym) \
|
|
({ \
|
|
void *val = &sym; \
|
|
@@ -68,6 +72,43 @@ extern u32 __init_stage2_translation(void);
|
|
|
|
extern void __qcom_hyp_sanitize_btac_predictors(void);
|
|
|
|
+/* Home-grown __this_cpu_{ptr,read} variants that always work at HYP */
|
|
+#define __hyp_this_cpu_ptr(sym) \
|
|
+ ({ \
|
|
+ void *__ptr = hyp_symbol_addr(sym); \
|
|
+ __ptr += read_sysreg(tpidr_el2); \
|
|
+ (typeof(&sym))__ptr; \
|
|
+ })
|
|
+
|
|
+#define __hyp_this_cpu_read(sym) \
|
|
+ ({ \
|
|
+ *__hyp_this_cpu_ptr(sym); \
|
|
+ })
|
|
+
|
|
+#else /* __ASSEMBLY__ */
|
|
+
|
|
+.macro hyp_adr_this_cpu reg, sym, tmp
|
|
+ adr_l \reg, \sym
|
|
+ mrs \tmp, tpidr_el2
|
|
+ add \reg, \reg, \tmp
|
|
+.endm
|
|
+
|
|
+.macro hyp_ldr_this_cpu reg, sym, tmp
|
|
+ adr_l \reg, \sym
|
|
+ mrs \tmp, tpidr_el2
|
|
+ ldr \reg, [\reg, \tmp]
|
|
+.endm
|
|
+
|
|
+.macro get_host_ctxt reg, tmp
|
|
+ hyp_adr_this_cpu \reg, kvm_host_cpu_state, \tmp
|
|
+.endm
|
|
+
|
|
+.macro get_vcpu_ptr vcpu, ctxt
|
|
+ get_host_ctxt \ctxt, \vcpu
|
|
+ ldr \vcpu, [\ctxt, #HOST_CONTEXT_VCPU]
|
|
+ kern_hyp_va \vcpu
|
|
+.endm
|
|
+
|
|
#endif
|
|
|
|
#endif /* __ARM_KVM_ASM_H__ */
|
|
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
|
|
index 8abec9f7f430..b01ad3489bd8 100644
|
|
--- a/arch/arm64/include/asm/kvm_host.h
|
|
+++ b/arch/arm64/include/asm/kvm_host.h
|
|
@@ -194,6 +194,8 @@ struct kvm_cpu_context {
|
|
u64 sys_regs[NR_SYS_REGS];
|
|
u32 copro[NR_COPRO_REGS];
|
|
};
|
|
+
|
|
+ struct kvm_vcpu *__hyp_running_vcpu;
|
|
};
|
|
|
|
typedef struct kvm_cpu_context kvm_cpu_context_t;
|
|
@@ -208,6 +210,9 @@ struct kvm_vcpu_arch {
|
|
/* Exception Information */
|
|
struct kvm_vcpu_fault_info fault;
|
|
|
|
+ /* State of various workarounds, see kvm_asm.h for bit assignment */
|
|
+ u64 workaround_flags;
|
|
+
|
|
/* Guest debug state */
|
|
u64 debug_flags;
|
|
|
|
@@ -348,10 +353,15 @@ int kvm_perf_teardown(void);
|
|
|
|
struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
|
|
|
|
+void __kvm_set_tpidr_el2(u64 tpidr_el2);
|
|
+DECLARE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
|
|
+
|
|
static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
|
|
unsigned long hyp_stack_ptr,
|
|
unsigned long vector_ptr)
|
|
{
|
|
+ u64 tpidr_el2;
|
|
+
|
|
/*
|
|
* Call initialization code, and switch to the full blown HYP code.
|
|
* If the cpucaps haven't been finalized yet, something has gone very
|
|
@@ -360,6 +370,16 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
|
|
*/
|
|
BUG_ON(!static_branch_likely(&arm64_const_caps_ready));
|
|
__kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr);
|
|
+
|
|
+ /*
|
|
+ * Calculate the raw per-cpu offset without a translation from the
|
|
+ * kernel's mapping to the linear mapping, and store it in tpidr_el2
|
|
+ * so that we can use adr_l to access per-cpu variables in EL2.
|
|
+ */
|
|
+ tpidr_el2 = (u64)this_cpu_ptr(&kvm_host_cpu_state)
|
|
+ - (u64)kvm_ksym_ref(kvm_host_cpu_state);
|
|
+
|
|
+ kvm_call_hyp(__kvm_set_tpidr_el2, tpidr_el2);
|
|
}
|
|
|
|
static inline void kvm_arch_hardware_unsetup(void) {}
|
|
@@ -392,4 +412,27 @@ static inline bool kvm_arm_harden_branch_predictor(void)
|
|
return cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR);
|
|
}
|
|
|
|
+#define KVM_SSBD_UNKNOWN -1
|
|
+#define KVM_SSBD_FORCE_DISABLE 0
|
|
+#define KVM_SSBD_KERNEL 1
|
|
+#define KVM_SSBD_FORCE_ENABLE 2
|
|
+#define KVM_SSBD_MITIGATED 3
|
|
+
|
|
+static inline int kvm_arm_have_ssbd(void)
|
|
+{
|
|
+ switch (arm64_get_ssbd_state()) {
|
|
+ case ARM64_SSBD_FORCE_DISABLE:
|
|
+ return KVM_SSBD_FORCE_DISABLE;
|
|
+ case ARM64_SSBD_KERNEL:
|
|
+ return KVM_SSBD_KERNEL;
|
|
+ case ARM64_SSBD_FORCE_ENABLE:
|
|
+ return KVM_SSBD_FORCE_ENABLE;
|
|
+ case ARM64_SSBD_MITIGATED:
|
|
+ return KVM_SSBD_MITIGATED;
|
|
+ case ARM64_SSBD_UNKNOWN:
|
|
+ default:
|
|
+ return KVM_SSBD_UNKNOWN;
|
|
+ }
|
|
+}
|
|
+
|
|
#endif /* __ARM64_KVM_HOST_H__ */
|
|
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
|
|
index fe55b516f018..e42c1f0ae6cf 100644
|
|
--- a/arch/arm64/include/asm/kvm_mmu.h
|
|
+++ b/arch/arm64/include/asm/kvm_mmu.h
|
|
@@ -130,6 +130,26 @@ static inline unsigned long __kern_hyp_va(unsigned long v)
|
|
|
|
#define kern_hyp_va(v) ((typeof(v))(__kern_hyp_va((unsigned long)(v))))
|
|
|
|
+/*
|
|
+ * Obtain the PC-relative address of a kernel symbol
|
|
+ * s: symbol
|
|
+ *
|
|
+ * The goal of this macro is to return a symbol's address based on a
|
|
+ * PC-relative computation, as opposed to a loading the VA from a
|
|
+ * constant pool or something similar. This works well for HYP, as an
|
|
+ * absolute VA is guaranteed to be wrong. Only use this if trying to
|
|
+ * obtain the address of a symbol (i.e. not something you obtained by
|
|
+ * following a pointer).
|
|
+ */
|
|
+#define hyp_symbol_addr(s) \
|
|
+ ({ \
|
|
+ typeof(s) *addr; \
|
|
+ asm("adrp %0, %1\n" \
|
|
+ "add %0, %0, :lo12:%1\n" \
|
|
+ : "=r" (addr) : "S" (&s)); \
|
|
+ addr; \
|
|
+ })
|
|
+
|
|
/*
|
|
* We currently only support a 40bit IPA.
|
|
*/
|
|
@@ -363,5 +383,29 @@ static inline int kvm_map_vectors(void)
|
|
}
|
|
#endif
|
|
|
|
+#ifdef CONFIG_ARM64_SSBD
|
|
+DECLARE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required);
|
|
+
|
|
+static inline int hyp_map_aux_data(void)
|
|
+{
|
|
+ int cpu, err;
|
|
+
|
|
+ for_each_possible_cpu(cpu) {
|
|
+ u64 *ptr;
|
|
+
|
|
+ ptr = per_cpu_ptr(&arm64_ssbd_callback_required, cpu);
|
|
+ err = create_hyp_mappings(ptr, ptr + 1, PAGE_HYP);
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+#else
|
|
+static inline int hyp_map_aux_data(void)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
#endif /* __ASSEMBLY__ */
|
|
#endif /* __ARM64_KVM_MMU_H__ */
|
|
diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h
|
|
index 3bd498e4de4c..43393208229e 100644
|
|
--- a/arch/arm64/include/asm/percpu.h
|
|
+++ b/arch/arm64/include/asm/percpu.h
|
|
@@ -16,11 +16,15 @@
|
|
#ifndef __ASM_PERCPU_H
|
|
#define __ASM_PERCPU_H
|
|
|
|
+#include <asm/alternative.h>
|
|
#include <asm/stack_pointer.h>
|
|
|
|
static inline void set_my_cpu_offset(unsigned long off)
|
|
{
|
|
- asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory");
|
|
+ asm volatile(ALTERNATIVE("msr tpidr_el1, %0",
|
|
+ "msr tpidr_el2, %0",
|
|
+ ARM64_HAS_VIRT_HOST_EXTN)
|
|
+ :: "r" (off) : "memory");
|
|
}
|
|
|
|
static inline unsigned long __my_cpu_offset(void)
|
|
@@ -31,7 +35,10 @@ static inline unsigned long __my_cpu_offset(void)
|
|
* We want to allow caching the value, so avoid using volatile and
|
|
* instead use a fake stack read to hazard against barrier().
|
|
*/
|
|
- asm("mrs %0, tpidr_el1" : "=r" (off) :
|
|
+ asm(ALTERNATIVE("mrs %0, tpidr_el1",
|
|
+ "mrs %0, tpidr_el2",
|
|
+ ARM64_HAS_VIRT_HOST_EXTN)
|
|
+ : "=r" (off) :
|
|
"Q" (*(const unsigned long *)current_stack_pointer));
|
|
|
|
return off;
|
|
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
|
|
index ddded6497a8a..fc786d344e46 100644
|
|
--- a/arch/arm64/include/asm/thread_info.h
|
|
+++ b/arch/arm64/include/asm/thread_info.h
|
|
@@ -92,6 +92,7 @@ void arch_setup_new_exec(void);
|
|
#define TIF_RESTORE_SIGMASK 20
|
|
#define TIF_SINGLESTEP 21
|
|
#define TIF_32BIT 22 /* 32bit process */
|
|
+#define TIF_SSBD 23 /* Wants SSB mitigation */
|
|
|
|
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
|
|
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
|
|
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
|
|
index def8d5623fd1..714fe90dbf66 100644
|
|
--- a/arch/arm64/kernel/Makefile
|
|
+++ b/arch/arm64/kernel/Makefile
|
|
@@ -54,6 +54,7 @@ arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o \
|
|
arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o
|
|
arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
|
|
arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
|
|
+arm64-obj-$(CONFIG_ARM64_SSBD) += ssbd.o
|
|
|
|
ifeq ($(CONFIG_KVM),y)
|
|
arm64-obj-$(CONFIG_HARDEN_BRANCH_PREDICTOR) += bpi.o
|
|
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
|
|
index 6dd0a3a3e5c9..5c4bce4ac381 100644
|
|
--- a/arch/arm64/kernel/alternative.c
|
|
+++ b/arch/arm64/kernel/alternative.c
|
|
@@ -32,6 +32,8 @@
|
|
#define ALT_ORIG_PTR(a) __ALT_PTR(a, orig_offset)
|
|
#define ALT_REPL_PTR(a) __ALT_PTR(a, alt_offset)
|
|
|
|
+int alternatives_applied;
|
|
+
|
|
struct alt_region {
|
|
struct alt_instr *begin;
|
|
struct alt_instr *end;
|
|
@@ -105,32 +107,53 @@ static u32 get_alt_insn(struct alt_instr *alt, __le32 *insnptr, __le32 *altinsnp
|
|
return insn;
|
|
}
|
|
|
|
+static void patch_alternative(struct alt_instr *alt,
|
|
+ __le32 *origptr, __le32 *updptr, int nr_inst)
|
|
+{
|
|
+ __le32 *replptr;
|
|
+ int i;
|
|
+
|
|
+ replptr = ALT_REPL_PTR(alt);
|
|
+ for (i = 0; i < nr_inst; i++) {
|
|
+ u32 insn;
|
|
+
|
|
+ insn = get_alt_insn(alt, origptr + i, replptr + i);
|
|
+ updptr[i] = cpu_to_le32(insn);
|
|
+ }
|
|
+}
|
|
+
|
|
static void __apply_alternatives(void *alt_region, bool use_linear_alias)
|
|
{
|
|
struct alt_instr *alt;
|
|
struct alt_region *region = alt_region;
|
|
- __le32 *origptr, *replptr, *updptr;
|
|
+ __le32 *origptr, *updptr;
|
|
+ alternative_cb_t alt_cb;
|
|
|
|
for (alt = region->begin; alt < region->end; alt++) {
|
|
- u32 insn;
|
|
- int i, nr_inst;
|
|
+ int nr_inst;
|
|
|
|
- if (!cpus_have_cap(alt->cpufeature))
|
|
+ /* Use ARM64_CB_PATCH as an unconditional patch */
|
|
+ if (alt->cpufeature < ARM64_CB_PATCH &&
|
|
+ !cpus_have_cap(alt->cpufeature))
|
|
continue;
|
|
|
|
- BUG_ON(alt->alt_len != alt->orig_len);
|
|
+ if (alt->cpufeature == ARM64_CB_PATCH)
|
|
+ BUG_ON(alt->alt_len != 0);
|
|
+ else
|
|
+ BUG_ON(alt->alt_len != alt->orig_len);
|
|
|
|
pr_info_once("patching kernel code\n");
|
|
|
|
origptr = ALT_ORIG_PTR(alt);
|
|
- replptr = ALT_REPL_PTR(alt);
|
|
updptr = use_linear_alias ? lm_alias(origptr) : origptr;
|
|
- nr_inst = alt->alt_len / sizeof(insn);
|
|
+ nr_inst = alt->orig_len / AARCH64_INSN_SIZE;
|
|
|
|
- for (i = 0; i < nr_inst; i++) {
|
|
- insn = get_alt_insn(alt, origptr + i, replptr + i);
|
|
- updptr[i] = cpu_to_le32(insn);
|
|
- }
|
|
+ if (alt->cpufeature < ARM64_CB_PATCH)
|
|
+ alt_cb = patch_alternative;
|
|
+ else
|
|
+ alt_cb = ALT_REPL_PTR(alt);
|
|
+
|
|
+ alt_cb(alt, origptr, updptr, nr_inst);
|
|
|
|
flush_icache_range((uintptr_t)origptr,
|
|
(uintptr_t)(origptr + nr_inst));
|
|
@@ -143,7 +166,6 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias)
|
|
*/
|
|
static int __apply_alternatives_multi_stop(void *unused)
|
|
{
|
|
- static int patched = 0;
|
|
struct alt_region region = {
|
|
.begin = (struct alt_instr *)__alt_instructions,
|
|
.end = (struct alt_instr *)__alt_instructions_end,
|
|
@@ -151,14 +173,14 @@ static int __apply_alternatives_multi_stop(void *unused)
|
|
|
|
/* We always have a CPU 0 at this point (__init) */
|
|
if (smp_processor_id()) {
|
|
- while (!READ_ONCE(patched))
|
|
+ while (!READ_ONCE(alternatives_applied))
|
|
cpu_relax();
|
|
isb();
|
|
} else {
|
|
- BUG_ON(patched);
|
|
+ BUG_ON(alternatives_applied);
|
|
__apply_alternatives(®ion, true);
|
|
/* Barriers provided by the cache flushing */
|
|
- WRITE_ONCE(patched, 1);
|
|
+ WRITE_ONCE(alternatives_applied, 1);
|
|
}
|
|
|
|
return 0;
|
|
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
|
|
index af247d10252f..b5e43b01b396 100644
|
|
--- a/arch/arm64/kernel/asm-offsets.c
|
|
+++ b/arch/arm64/kernel/asm-offsets.c
|
|
@@ -131,11 +131,13 @@ int main(void)
|
|
BLANK();
|
|
#ifdef CONFIG_KVM_ARM_HOST
|
|
DEFINE(VCPU_CONTEXT, offsetof(struct kvm_vcpu, arch.ctxt));
|
|
+ DEFINE(VCPU_WORKAROUND_FLAGS, offsetof(struct kvm_vcpu, arch.workaround_flags));
|
|
DEFINE(CPU_GP_REGS, offsetof(struct kvm_cpu_context, gp_regs));
|
|
DEFINE(CPU_USER_PT_REGS, offsetof(struct kvm_regs, regs));
|
|
DEFINE(CPU_FP_REGS, offsetof(struct kvm_regs, fp_regs));
|
|
DEFINE(VCPU_FPEXC32_EL2, offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2]));
|
|
DEFINE(VCPU_HOST_CONTEXT, offsetof(struct kvm_vcpu, arch.host_cpu_context));
|
|
+ DEFINE(HOST_CONTEXT_VCPU, offsetof(struct kvm_cpu_context, __hyp_running_vcpu));
|
|
#endif
|
|
#ifdef CONFIG_CPU_PM
|
|
DEFINE(CPU_SUSPEND_SZ, sizeof(struct cpu_suspend_ctx));
|
|
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
|
|
index b5a28336c077..eccdb28b4a39 100644
|
|
--- a/arch/arm64/kernel/cpu_errata.c
|
|
+++ b/arch/arm64/kernel/cpu_errata.c
|
|
@@ -228,6 +228,178 @@ static int qcom_enable_link_stack_sanitization(void *data)
|
|
}
|
|
#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */
|
|
|
|
+#ifdef CONFIG_ARM64_SSBD
|
|
+DEFINE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required);
|
|
+
|
|
+int ssbd_state __read_mostly = ARM64_SSBD_KERNEL;
|
|
+
|
|
+static const struct ssbd_options {
|
|
+ const char *str;
|
|
+ int state;
|
|
+} ssbd_options[] = {
|
|
+ { "force-on", ARM64_SSBD_FORCE_ENABLE, },
|
|
+ { "force-off", ARM64_SSBD_FORCE_DISABLE, },
|
|
+ { "kernel", ARM64_SSBD_KERNEL, },
|
|
+};
|
|
+
|
|
+static int __init ssbd_cfg(char *buf)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ if (!buf || !buf[0])
|
|
+ return -EINVAL;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(ssbd_options); i++) {
|
|
+ int len = strlen(ssbd_options[i].str);
|
|
+
|
|
+ if (strncmp(buf, ssbd_options[i].str, len))
|
|
+ continue;
|
|
+
|
|
+ ssbd_state = ssbd_options[i].state;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return -EINVAL;
|
|
+}
|
|
+early_param("ssbd", ssbd_cfg);
|
|
+
|
|
+void __init arm64_update_smccc_conduit(struct alt_instr *alt,
|
|
+ __le32 *origptr, __le32 *updptr,
|
|
+ int nr_inst)
|
|
+{
|
|
+ u32 insn;
|
|
+
|
|
+ BUG_ON(nr_inst != 1);
|
|
+
|
|
+ switch (psci_ops.conduit) {
|
|
+ case PSCI_CONDUIT_HVC:
|
|
+ insn = aarch64_insn_get_hvc_value();
|
|
+ break;
|
|
+ case PSCI_CONDUIT_SMC:
|
|
+ insn = aarch64_insn_get_smc_value();
|
|
+ break;
|
|
+ default:
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ *updptr = cpu_to_le32(insn);
|
|
+}
|
|
+
|
|
+void __init arm64_enable_wa2_handling(struct alt_instr *alt,
|
|
+ __le32 *origptr, __le32 *updptr,
|
|
+ int nr_inst)
|
|
+{
|
|
+ BUG_ON(nr_inst != 1);
|
|
+ /*
|
|
+ * Only allow mitigation on EL1 entry/exit and guest
|
|
+ * ARCH_WORKAROUND_2 handling if the SSBD state allows it to
|
|
+ * be flipped.
|
|
+ */
|
|
+ if (arm64_get_ssbd_state() == ARM64_SSBD_KERNEL)
|
|
+ *updptr = cpu_to_le32(aarch64_insn_gen_nop());
|
|
+}
|
|
+
|
|
+void arm64_set_ssbd_mitigation(bool state)
|
|
+{
|
|
+ switch (psci_ops.conduit) {
|
|
+ case PSCI_CONDUIT_HVC:
|
|
+ arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_2, state, NULL);
|
|
+ break;
|
|
+
|
|
+ case PSCI_CONDUIT_SMC:
|
|
+ arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2, state, NULL);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ WARN_ON_ONCE(1);
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry,
|
|
+ int scope)
|
|
+{
|
|
+ struct arm_smccc_res res;
|
|
+ bool required = true;
|
|
+ s32 val;
|
|
+
|
|
+ WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
|
|
+
|
|
+ if (psci_ops.smccc_version == SMCCC_VERSION_1_0) {
|
|
+ ssbd_state = ARM64_SSBD_UNKNOWN;
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ switch (psci_ops.conduit) {
|
|
+ case PSCI_CONDUIT_HVC:
|
|
+ arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
|
|
+ ARM_SMCCC_ARCH_WORKAROUND_2, &res);
|
|
+ break;
|
|
+
|
|
+ case PSCI_CONDUIT_SMC:
|
|
+ arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
|
|
+ ARM_SMCCC_ARCH_WORKAROUND_2, &res);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ ssbd_state = ARM64_SSBD_UNKNOWN;
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ val = (s32)res.a0;
|
|
+
|
|
+ switch (val) {
|
|
+ case SMCCC_RET_NOT_SUPPORTED:
|
|
+ ssbd_state = ARM64_SSBD_UNKNOWN;
|
|
+ return false;
|
|
+
|
|
+ case SMCCC_RET_NOT_REQUIRED:
|
|
+ pr_info_once("%s mitigation not required\n", entry->desc);
|
|
+ ssbd_state = ARM64_SSBD_MITIGATED;
|
|
+ return false;
|
|
+
|
|
+ case SMCCC_RET_SUCCESS:
|
|
+ required = true;
|
|
+ break;
|
|
+
|
|
+ case 1: /* Mitigation not required on this CPU */
|
|
+ required = false;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ WARN_ON(1);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ switch (ssbd_state) {
|
|
+ case ARM64_SSBD_FORCE_DISABLE:
|
|
+ pr_info_once("%s disabled from command-line\n", entry->desc);
|
|
+ arm64_set_ssbd_mitigation(false);
|
|
+ required = false;
|
|
+ break;
|
|
+
|
|
+ case ARM64_SSBD_KERNEL:
|
|
+ if (required) {
|
|
+ __this_cpu_write(arm64_ssbd_callback_required, 1);
|
|
+ arm64_set_ssbd_mitigation(true);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case ARM64_SSBD_FORCE_ENABLE:
|
|
+ pr_info_once("%s forced from command-line\n", entry->desc);
|
|
+ arm64_set_ssbd_mitigation(true);
|
|
+ required = true;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ WARN_ON(1);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return required;
|
|
+}
|
|
+#endif /* CONFIG_ARM64_SSBD */
|
|
+
|
|
#define MIDR_RANGE(model, min, max) \
|
|
.def_scope = SCOPE_LOCAL_CPU, \
|
|
.matches = is_affected_midr_range, \
|
|
@@ -425,6 +597,14 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
|
|
MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2),
|
|
.enable = enable_smccc_arch_workaround_1,
|
|
},
|
|
+#endif
|
|
+#ifdef CONFIG_ARM64_SSBD
|
|
+ {
|
|
+ .desc = "Speculative Store Bypass Disable",
|
|
+ .def_scope = SCOPE_LOCAL_CPU,
|
|
+ .capability = ARM64_SSBD,
|
|
+ .matches = has_ssbd_mitigation,
|
|
+ },
|
|
#endif
|
|
{
|
|
}
|
|
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
|
|
index 718822ab6e4b..376cf12edf0c 100644
|
|
--- a/arch/arm64/kernel/cpufeature.c
|
|
+++ b/arch/arm64/kernel/cpufeature.c
|
|
@@ -880,6 +880,22 @@ static int __init parse_kpti(char *str)
|
|
early_param("kpti", parse_kpti);
|
|
#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
|
|
|
|
+static int cpu_copy_el2regs(void *__unused)
|
|
+{
|
|
+ /*
|
|
+ * Copy register values that aren't redirected by hardware.
|
|
+ *
|
|
+ * Before code patching, we only set tpidr_el1, all CPUs need to copy
|
|
+ * this value to tpidr_el2 before we patch the code. Once we've done
|
|
+ * that, freshly-onlined CPUs will set tpidr_el2, so we don't need to
|
|
+ * do anything here.
|
|
+ */
|
|
+ if (!alternatives_applied)
|
|
+ write_sysreg(read_sysreg(tpidr_el1), tpidr_el2);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static const struct arm64_cpu_capabilities arm64_features[] = {
|
|
{
|
|
.desc = "GIC system register CPU interface",
|
|
@@ -949,6 +965,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
|
.capability = ARM64_HAS_VIRT_HOST_EXTN,
|
|
.def_scope = SCOPE_SYSTEM,
|
|
.matches = runs_at_el2,
|
|
+ .enable = cpu_copy_el2regs,
|
|
},
|
|
{
|
|
.desc = "32-bit EL0 Support",
|
|
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
|
|
index 93958d1341bb..c1ffa95c0ad2 100644
|
|
--- a/arch/arm64/kernel/entry.S
|
|
+++ b/arch/arm64/kernel/entry.S
|
|
@@ -18,6 +18,7 @@
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
+#include <linux/arm-smccc.h>
|
|
#include <linux/init.h>
|
|
#include <linux/linkage.h>
|
|
|
|
@@ -137,6 +138,25 @@ alternative_else_nop_endif
|
|
add \dst, \dst, #(\sym - .entry.tramp.text)
|
|
.endm
|
|
|
|
+ // This macro corrupts x0-x3. It is the caller's duty
|
|
+ // to save/restore them if required.
|
|
+ .macro apply_ssbd, state, targ, tmp1, tmp2
|
|
+#ifdef CONFIG_ARM64_SSBD
|
|
+alternative_cb arm64_enable_wa2_handling
|
|
+ b \targ
|
|
+alternative_cb_end
|
|
+ ldr_this_cpu \tmp2, arm64_ssbd_callback_required, \tmp1
|
|
+ cbz \tmp2, \targ
|
|
+ ldr \tmp2, [tsk, #TSK_TI_FLAGS]
|
|
+ tbnz \tmp2, #TIF_SSBD, \targ
|
|
+ mov w0, #ARM_SMCCC_ARCH_WORKAROUND_2
|
|
+ mov w1, #\state
|
|
+alternative_cb arm64_update_smccc_conduit
|
|
+ nop // Patched to SMC/HVC #0
|
|
+alternative_cb_end
|
|
+#endif
|
|
+ .endm
|
|
+
|
|
.macro kernel_entry, el, regsize = 64
|
|
.if \regsize == 32
|
|
mov w0, w0 // zero upper 32 bits of x0
|
|
@@ -163,6 +183,14 @@ alternative_else_nop_endif
|
|
ldr x19, [tsk, #TSK_TI_FLAGS] // since we can unmask debug
|
|
disable_step_tsk x19, x20 // exceptions when scheduling.
|
|
|
|
+ apply_ssbd 1, 1f, x22, x23
|
|
+
|
|
+#ifdef CONFIG_ARM64_SSBD
|
|
+ ldp x0, x1, [sp, #16 * 0]
|
|
+ ldp x2, x3, [sp, #16 * 1]
|
|
+#endif
|
|
+1:
|
|
+
|
|
mov x29, xzr // fp pointed to user-space
|
|
.else
|
|
add x21, sp, #S_FRAME_SIZE
|
|
@@ -301,6 +329,8 @@ alternative_if ARM64_WORKAROUND_845719
|
|
alternative_else_nop_endif
|
|
#endif
|
|
3:
|
|
+ apply_ssbd 0, 5f, x0, x1
|
|
+5:
|
|
.endif
|
|
|
|
msr elr_el1, x21 // set up the return data
|
|
diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
|
|
index 095d3c170f5d..a028cc95afe1 100644
|
|
--- a/arch/arm64/kernel/hibernate.c
|
|
+++ b/arch/arm64/kernel/hibernate.c
|
|
@@ -313,6 +313,17 @@ int swsusp_arch_suspend(void)
|
|
|
|
sleep_cpu = -EINVAL;
|
|
__cpu_suspend_exit();
|
|
+
|
|
+ /*
|
|
+ * Just in case the boot kernel did turn the SSBD
|
|
+ * mitigation off behind our back, let's set the state
|
|
+ * to what we expect it to be.
|
|
+ */
|
|
+ switch (arm64_get_ssbd_state()) {
|
|
+ case ARM64_SSBD_FORCE_ENABLE:
|
|
+ case ARM64_SSBD_KERNEL:
|
|
+ arm64_set_ssbd_mitigation(true);
|
|
+ }
|
|
}
|
|
|
|
local_dbg_restore(flags);
|
|
diff --git a/arch/arm64/kernel/ssbd.c b/arch/arm64/kernel/ssbd.c
|
|
new file mode 100644
|
|
index 000000000000..0560738c1d5c
|
|
--- /dev/null
|
|
+++ b/arch/arm64/kernel/ssbd.c
|
|
@@ -0,0 +1,108 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright (C) 2018 ARM Ltd, All Rights Reserved.
|
|
+ */
|
|
+
|
|
+#include <linux/errno.h>
|
|
+#include <linux/prctl.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/thread_info.h>
|
|
+
|
|
+#include <asm/cpufeature.h>
|
|
+
|
|
+/*
|
|
+ * prctl interface for SSBD
|
|
+ */
|
|
+static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
|
|
+{
|
|
+ int state = arm64_get_ssbd_state();
|
|
+
|
|
+ /* Unsupported */
|
|
+ if (state == ARM64_SSBD_UNKNOWN)
|
|
+ return -EINVAL;
|
|
+
|
|
+ /* Treat the unaffected/mitigated state separately */
|
|
+ if (state == ARM64_SSBD_MITIGATED) {
|
|
+ switch (ctrl) {
|
|
+ case PR_SPEC_ENABLE:
|
|
+ return -EPERM;
|
|
+ case PR_SPEC_DISABLE:
|
|
+ case PR_SPEC_FORCE_DISABLE:
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Things are a bit backward here: the arm64 internal API
|
|
+ * *enables the mitigation* when the userspace API *disables
|
|
+ * speculation*. So much fun.
|
|
+ */
|
|
+ switch (ctrl) {
|
|
+ case PR_SPEC_ENABLE:
|
|
+ /* If speculation is force disabled, enable is not allowed */
|
|
+ if (state == ARM64_SSBD_FORCE_ENABLE ||
|
|
+ task_spec_ssb_force_disable(task))
|
|
+ return -EPERM;
|
|
+ task_clear_spec_ssb_disable(task);
|
|
+ clear_tsk_thread_flag(task, TIF_SSBD);
|
|
+ break;
|
|
+ case PR_SPEC_DISABLE:
|
|
+ if (state == ARM64_SSBD_FORCE_DISABLE)
|
|
+ return -EPERM;
|
|
+ task_set_spec_ssb_disable(task);
|
|
+ set_tsk_thread_flag(task, TIF_SSBD);
|
|
+ break;
|
|
+ case PR_SPEC_FORCE_DISABLE:
|
|
+ if (state == ARM64_SSBD_FORCE_DISABLE)
|
|
+ return -EPERM;
|
|
+ task_set_spec_ssb_disable(task);
|
|
+ task_set_spec_ssb_force_disable(task);
|
|
+ set_tsk_thread_flag(task, TIF_SSBD);
|
|
+ break;
|
|
+ default:
|
|
+ return -ERANGE;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
|
|
+ unsigned long ctrl)
|
|
+{
|
|
+ switch (which) {
|
|
+ case PR_SPEC_STORE_BYPASS:
|
|
+ return ssbd_prctl_set(task, ctrl);
|
|
+ default:
|
|
+ return -ENODEV;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int ssbd_prctl_get(struct task_struct *task)
|
|
+{
|
|
+ switch (arm64_get_ssbd_state()) {
|
|
+ case ARM64_SSBD_UNKNOWN:
|
|
+ return -EINVAL;
|
|
+ case ARM64_SSBD_FORCE_ENABLE:
|
|
+ return PR_SPEC_DISABLE;
|
|
+ case ARM64_SSBD_KERNEL:
|
|
+ if (task_spec_ssb_force_disable(task))
|
|
+ return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
|
|
+ if (task_spec_ssb_disable(task))
|
|
+ return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
|
|
+ return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
|
|
+ case ARM64_SSBD_FORCE_DISABLE:
|
|
+ return PR_SPEC_ENABLE;
|
|
+ default:
|
|
+ return PR_SPEC_NOT_AFFECTED;
|
|
+ }
|
|
+}
|
|
+
|
|
+int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
|
|
+{
|
|
+ switch (which) {
|
|
+ case PR_SPEC_STORE_BYPASS:
|
|
+ return ssbd_prctl_get(task);
|
|
+ default:
|
|
+ return -ENODEV;
|
|
+ }
|
|
+}
|
|
diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c
|
|
index 77cd655e6eb7..7a655e60cf4b 100644
|
|
--- a/arch/arm64/kernel/suspend.c
|
|
+++ b/arch/arm64/kernel/suspend.c
|
|
@@ -62,6 +62,14 @@ void notrace __cpu_suspend_exit(void)
|
|
*/
|
|
if (hw_breakpoint_restore)
|
|
hw_breakpoint_restore(cpu);
|
|
+
|
|
+ /*
|
|
+ * On resume, firmware implementing dynamic mitigation will
|
|
+ * have turned the mitigation on. If the user has forcefully
|
|
+ * disabled it, make sure their wishes are obeyed.
|
|
+ */
|
|
+ if (arm64_get_ssbd_state() == ARM64_SSBD_FORCE_DISABLE)
|
|
+ arm64_set_ssbd_mitigation(false);
|
|
}
|
|
|
|
/*
|
|
diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S
|
|
index 870828c364c5..dea20651a5f1 100644
|
|
--- a/arch/arm64/kvm/hyp-init.S
|
|
+++ b/arch/arm64/kvm/hyp-init.S
|
|
@@ -122,6 +122,10 @@ CPU_BE( orr x4, x4, #SCTLR_ELx_EE)
|
|
kern_hyp_va x2
|
|
msr vbar_el2, x2
|
|
|
|
+ /* copy tpidr_el1 into tpidr_el2 for use by HYP */
|
|
+ mrs x1, tpidr_el1
|
|
+ msr tpidr_el2, x1
|
|
+
|
|
/* Hello, World! */
|
|
eret
|
|
ENDPROC(__kvm_hyp_init)
|
|
diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
|
|
index 9c45c6af1f58..a7b3c198d4de 100644
|
|
--- a/arch/arm64/kvm/hyp/entry.S
|
|
+++ b/arch/arm64/kvm/hyp/entry.S
|
|
@@ -62,9 +62,6 @@ ENTRY(__guest_enter)
|
|
// Store the host regs
|
|
save_callee_saved_regs x1
|
|
|
|
- // Store the host_ctxt for use at exit time
|
|
- str x1, [sp, #-16]!
|
|
-
|
|
add x18, x0, #VCPU_CONTEXT
|
|
|
|
// Restore guest regs x0-x17
|
|
@@ -118,8 +115,7 @@ ENTRY(__guest_exit)
|
|
// Store the guest regs x19-x29, lr
|
|
save_callee_saved_regs x1
|
|
|
|
- // Restore the host_ctxt from the stack
|
|
- ldr x2, [sp], #16
|
|
+ get_host_ctxt x2, x3
|
|
|
|
// Now restore the host regs
|
|
restore_callee_saved_regs x2
|
|
@@ -159,6 +155,10 @@ abort_guest_exit_end:
|
|
ENDPROC(__guest_exit)
|
|
|
|
ENTRY(__fpsimd_guest_restore)
|
|
+ // x0: esr
|
|
+ // x1: vcpu
|
|
+ // x2-x29,lr: vcpu regs
|
|
+ // vcpu x0-x1 on the stack
|
|
stp x2, x3, [sp, #-16]!
|
|
stp x4, lr, [sp, #-16]!
|
|
|
|
@@ -173,7 +173,7 @@ alternative_else
|
|
alternative_endif
|
|
isb
|
|
|
|
- mrs x3, tpidr_el2
|
|
+ mov x3, x1
|
|
|
|
ldr x0, [x3, #VCPU_HOST_CONTEXT]
|
|
kern_hyp_va x0
|
|
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
|
|
index f49b53331d28..3c283fd8c8f5 100644
|
|
--- a/arch/arm64/kvm/hyp/hyp-entry.S
|
|
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
|
|
@@ -57,13 +57,8 @@ ENDPROC(__vhe_hyp_call)
|
|
el1_sync: // Guest trapped into EL2
|
|
stp x0, x1, [sp, #-16]!
|
|
|
|
-alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
|
|
- mrs x1, esr_el2
|
|
-alternative_else
|
|
- mrs x1, esr_el1
|
|
-alternative_endif
|
|
- lsr x0, x1, #ESR_ELx_EC_SHIFT
|
|
-
|
|
+ mrs x0, esr_el2
|
|
+ lsr x0, x0, #ESR_ELx_EC_SHIFT
|
|
cmp x0, #ESR_ELx_EC_HVC64
|
|
ccmp x0, #ESR_ELx_EC_HVC32, #4, ne
|
|
b.ne el1_trap
|
|
@@ -111,14 +106,55 @@ el1_hvc_guest:
|
|
*/
|
|
ldr x1, [sp] // Guest's x0
|
|
eor w1, w1, #ARM_SMCCC_ARCH_WORKAROUND_1
|
|
+ cbz w1, wa_epilogue
|
|
+
|
|
+ /* ARM_SMCCC_ARCH_WORKAROUND_2 handling */
|
|
+ eor w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_1 ^ \
|
|
+ ARM_SMCCC_ARCH_WORKAROUND_2)
|
|
cbnz w1, el1_trap
|
|
- mov x0, x1
|
|
+
|
|
+#ifdef CONFIG_ARM64_SSBD
|
|
+alternative_cb arm64_enable_wa2_handling
|
|
+ b wa2_end
|
|
+alternative_cb_end
|
|
+ get_vcpu_ptr x2, x0
|
|
+ ldr x0, [x2, #VCPU_WORKAROUND_FLAGS]
|
|
+
|
|
+ // Sanitize the argument and update the guest flags
|
|
+ ldr x1, [sp, #8] // Guest's x1
|
|
+ clz w1, w1 // Murphy's device:
|
|
+ lsr w1, w1, #5 // w1 = !!w1 without using
|
|
+ eor w1, w1, #1 // the flags...
|
|
+ bfi x0, x1, #VCPU_WORKAROUND_2_FLAG_SHIFT, #1
|
|
+ str x0, [x2, #VCPU_WORKAROUND_FLAGS]
|
|
+
|
|
+ /* Check that we actually need to perform the call */
|
|
+ hyp_ldr_this_cpu x0, arm64_ssbd_callback_required, x2
|
|
+ cbz x0, wa2_end
|
|
+
|
|
+ mov w0, #ARM_SMCCC_ARCH_WORKAROUND_2
|
|
+ smc #0
|
|
+
|
|
+ /* Don't leak data from the SMC call */
|
|
+ mov x3, xzr
|
|
+wa2_end:
|
|
+ mov x2, xzr
|
|
+ mov x1, xzr
|
|
+#endif
|
|
+
|
|
+wa_epilogue:
|
|
+ mov x0, xzr
|
|
add sp, sp, #16
|
|
eret
|
|
|
|
el1_trap:
|
|
+ get_vcpu_ptr x1, x0
|
|
+
|
|
+ mrs x0, esr_el2
|
|
+ lsr x0, x0, #ESR_ELx_EC_SHIFT
|
|
/*
|
|
* x0: ESR_EC
|
|
+ * x1: vcpu pointer
|
|
*/
|
|
|
|
/*
|
|
@@ -132,19 +168,18 @@ alternative_if_not ARM64_HAS_NO_FPSIMD
|
|
b.eq __fpsimd_guest_restore
|
|
alternative_else_nop_endif
|
|
|
|
- mrs x1, tpidr_el2
|
|
mov x0, #ARM_EXCEPTION_TRAP
|
|
b __guest_exit
|
|
|
|
el1_irq:
|
|
stp x0, x1, [sp, #-16]!
|
|
- mrs x1, tpidr_el2
|
|
+ get_vcpu_ptr x1, x0
|
|
mov x0, #ARM_EXCEPTION_IRQ
|
|
b __guest_exit
|
|
|
|
el1_error:
|
|
stp x0, x1, [sp, #-16]!
|
|
- mrs x1, tpidr_el2
|
|
+ get_vcpu_ptr x1, x0
|
|
mov x0, #ARM_EXCEPTION_EL1_SERROR
|
|
b __guest_exit
|
|
|
|
@@ -179,6 +214,11 @@ ENTRY(__hyp_do_panic)
|
|
eret
|
|
ENDPROC(__hyp_do_panic)
|
|
|
|
+ENTRY(__hyp_panic)
|
|
+ get_host_ctxt x0, x1
|
|
+ b hyp_panic
|
|
+ENDPROC(__hyp_panic)
|
|
+
|
|
.macro invalid_vector label, target = __hyp_panic
|
|
.align 2
|
|
\label:
|
|
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
|
|
index e08ae6b6b63e..b2f1992c6234 100644
|
|
--- a/arch/arm64/kvm/hyp/switch.c
|
|
+++ b/arch/arm64/kvm/hyp/switch.c
|
|
@@ -15,6 +15,7 @@
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
+#include <linux/arm-smccc.h>
|
|
#include <linux/types.h>
|
|
#include <linux/jump_label.h>
|
|
#include <uapi/linux/psci.h>
|
|
@@ -281,6 +282,39 @@ static void __hyp_text __skip_instr(struct kvm_vcpu *vcpu)
|
|
write_sysreg_el2(*vcpu_pc(vcpu), elr);
|
|
}
|
|
|
|
+static inline bool __hyp_text __needs_ssbd_off(struct kvm_vcpu *vcpu)
|
|
+{
|
|
+ if (!cpus_have_const_cap(ARM64_SSBD))
|
|
+ return false;
|
|
+
|
|
+ return !(vcpu->arch.workaround_flags & VCPU_WORKAROUND_2_FLAG);
|
|
+}
|
|
+
|
|
+static void __hyp_text __set_guest_arch_workaround_state(struct kvm_vcpu *vcpu)
|
|
+{
|
|
+#ifdef CONFIG_ARM64_SSBD
|
|
+ /*
|
|
+ * The host runs with the workaround always present. If the
|
|
+ * guest wants it disabled, so be it...
|
|
+ */
|
|
+ if (__needs_ssbd_off(vcpu) &&
|
|
+ __hyp_this_cpu_read(arm64_ssbd_callback_required))
|
|
+ arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2, 0, NULL);
|
|
+#endif
|
|
+}
|
|
+
|
|
+static void __hyp_text __set_host_arch_workaround_state(struct kvm_vcpu *vcpu)
|
|
+{
|
|
+#ifdef CONFIG_ARM64_SSBD
|
|
+ /*
|
|
+ * If the guest has disabled the workaround, bring it back on.
|
|
+ */
|
|
+ if (__needs_ssbd_off(vcpu) &&
|
|
+ __hyp_this_cpu_read(arm64_ssbd_callback_required))
|
|
+ arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2, 1, NULL);
|
|
+#endif
|
|
+}
|
|
+
|
|
int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
|
|
{
|
|
struct kvm_cpu_context *host_ctxt;
|
|
@@ -289,9 +323,9 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
|
|
u64 exit_code;
|
|
|
|
vcpu = kern_hyp_va(vcpu);
|
|
- write_sysreg(vcpu, tpidr_el2);
|
|
|
|
host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
|
|
+ host_ctxt->__hyp_running_vcpu = vcpu;
|
|
guest_ctxt = &vcpu->arch.ctxt;
|
|
|
|
__sysreg_save_host_state(host_ctxt);
|
|
@@ -311,6 +345,8 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
|
|
__sysreg_restore_guest_state(guest_ctxt);
|
|
__debug_restore_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt);
|
|
|
|
+ __set_guest_arch_workaround_state(vcpu);
|
|
+
|
|
/* Jump in the fire! */
|
|
again:
|
|
exit_code = __guest_enter(vcpu, host_ctxt);
|
|
@@ -367,6 +403,8 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
|
|
/* 0 falls through to be handled out of EL2 */
|
|
}
|
|
|
|
+ __set_host_arch_workaround_state(vcpu);
|
|
+
|
|
if (cpus_have_const_cap(ARM64_HARDEN_BP_POST_GUEST_EXIT)) {
|
|
u32 midr = read_cpuid_id();
|
|
|
|
@@ -406,7 +444,8 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
|
|
|
|
static const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n";
|
|
|
|
-static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par)
|
|
+static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par,
|
|
+ struct kvm_vcpu *vcpu)
|
|
{
|
|
unsigned long str_va;
|
|
|
|
@@ -420,35 +459,32 @@ static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par)
|
|
__hyp_do_panic(str_va,
|
|
spsr, elr,
|
|
read_sysreg(esr_el2), read_sysreg_el2(far),
|
|
- read_sysreg(hpfar_el2), par,
|
|
- (void *)read_sysreg(tpidr_el2));
|
|
+ read_sysreg(hpfar_el2), par, vcpu);
|
|
}
|
|
|
|
-static void __hyp_text __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par)
|
|
+static void __hyp_text __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par,
|
|
+ struct kvm_vcpu *vcpu)
|
|
{
|
|
panic(__hyp_panic_string,
|
|
spsr, elr,
|
|
read_sysreg_el2(esr), read_sysreg_el2(far),
|
|
- read_sysreg(hpfar_el2), par,
|
|
- (void *)read_sysreg(tpidr_el2));
|
|
+ read_sysreg(hpfar_el2), par, vcpu);
|
|
}
|
|
|
|
static hyp_alternate_select(__hyp_call_panic,
|
|
__hyp_call_panic_nvhe, __hyp_call_panic_vhe,
|
|
ARM64_HAS_VIRT_HOST_EXTN);
|
|
|
|
-void __hyp_text __noreturn __hyp_panic(void)
|
|
+void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
|
|
{
|
|
+ struct kvm_vcpu *vcpu = NULL;
|
|
+
|
|
u64 spsr = read_sysreg_el2(spsr);
|
|
u64 elr = read_sysreg_el2(elr);
|
|
u64 par = read_sysreg(par_el1);
|
|
|
|
if (read_sysreg(vttbr_el2)) {
|
|
- struct kvm_vcpu *vcpu;
|
|
- struct kvm_cpu_context *host_ctxt;
|
|
-
|
|
- vcpu = (struct kvm_vcpu *)read_sysreg(tpidr_el2);
|
|
- host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
|
|
+ vcpu = host_ctxt->__hyp_running_vcpu;
|
|
__timer_save_state(vcpu);
|
|
__deactivate_traps(vcpu);
|
|
__deactivate_vm(vcpu);
|
|
@@ -456,7 +492,7 @@ void __hyp_text __noreturn __hyp_panic(void)
|
|
}
|
|
|
|
/* Call panic for real */
|
|
- __hyp_call_panic()(spsr, elr, par);
|
|
+ __hyp_call_panic()(spsr, elr, par, vcpu);
|
|
|
|
unreachable();
|
|
}
|
|
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
|
|
index 934137647837..e19d89cabf2a 100644
|
|
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
|
|
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
|
|
@@ -27,8 +27,8 @@ static void __hyp_text __sysreg_do_nothing(struct kvm_cpu_context *ctxt) { }
|
|
/*
|
|
* Non-VHE: Both host and guest must save everything.
|
|
*
|
|
- * VHE: Host must save tpidr*_el[01], actlr_el1, mdscr_el1, sp0, pc,
|
|
- * pstate, and guest must save everything.
|
|
+ * VHE: Host must save tpidr*_el0, actlr_el1, mdscr_el1, sp_el0,
|
|
+ * and guest must save everything.
|
|
*/
|
|
|
|
static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
|
|
@@ -36,11 +36,8 @@ static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
|
|
ctxt->sys_regs[ACTLR_EL1] = read_sysreg(actlr_el1);
|
|
ctxt->sys_regs[TPIDR_EL0] = read_sysreg(tpidr_el0);
|
|
ctxt->sys_regs[TPIDRRO_EL0] = read_sysreg(tpidrro_el0);
|
|
- ctxt->sys_regs[TPIDR_EL1] = read_sysreg(tpidr_el1);
|
|
ctxt->sys_regs[MDSCR_EL1] = read_sysreg(mdscr_el1);
|
|
ctxt->gp_regs.regs.sp = read_sysreg(sp_el0);
|
|
- ctxt->gp_regs.regs.pc = read_sysreg_el2(elr);
|
|
- ctxt->gp_regs.regs.pstate = read_sysreg_el2(spsr);
|
|
}
|
|
|
|
static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
|
|
@@ -62,10 +59,13 @@ static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
|
|
ctxt->sys_regs[AMAIR_EL1] = read_sysreg_el1(amair);
|
|
ctxt->sys_regs[CNTKCTL_EL1] = read_sysreg_el1(cntkctl);
|
|
ctxt->sys_regs[PAR_EL1] = read_sysreg(par_el1);
|
|
+ ctxt->sys_regs[TPIDR_EL1] = read_sysreg(tpidr_el1);
|
|
|
|
ctxt->gp_regs.sp_el1 = read_sysreg(sp_el1);
|
|
ctxt->gp_regs.elr_el1 = read_sysreg_el1(elr);
|
|
ctxt->gp_regs.spsr[KVM_SPSR_EL1]= read_sysreg_el1(spsr);
|
|
+ ctxt->gp_regs.regs.pc = read_sysreg_el2(elr);
|
|
+ ctxt->gp_regs.regs.pstate = read_sysreg_el2(spsr);
|
|
}
|
|
|
|
static hyp_alternate_select(__sysreg_call_save_host_state,
|
|
@@ -89,11 +89,8 @@ static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctx
|
|
write_sysreg(ctxt->sys_regs[ACTLR_EL1], actlr_el1);
|
|
write_sysreg(ctxt->sys_regs[TPIDR_EL0], tpidr_el0);
|
|
write_sysreg(ctxt->sys_regs[TPIDRRO_EL0], tpidrro_el0);
|
|
- write_sysreg(ctxt->sys_regs[TPIDR_EL1], tpidr_el1);
|
|
write_sysreg(ctxt->sys_regs[MDSCR_EL1], mdscr_el1);
|
|
write_sysreg(ctxt->gp_regs.regs.sp, sp_el0);
|
|
- write_sysreg_el2(ctxt->gp_regs.regs.pc, elr);
|
|
- write_sysreg_el2(ctxt->gp_regs.regs.pstate, spsr);
|
|
}
|
|
|
|
static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
|
|
@@ -115,10 +112,13 @@ static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
|
|
write_sysreg_el1(ctxt->sys_regs[AMAIR_EL1], amair);
|
|
write_sysreg_el1(ctxt->sys_regs[CNTKCTL_EL1], cntkctl);
|
|
write_sysreg(ctxt->sys_regs[PAR_EL1], par_el1);
|
|
+ write_sysreg(ctxt->sys_regs[TPIDR_EL1], tpidr_el1);
|
|
|
|
write_sysreg(ctxt->gp_regs.sp_el1, sp_el1);
|
|
write_sysreg_el1(ctxt->gp_regs.elr_el1, elr);
|
|
write_sysreg_el1(ctxt->gp_regs.spsr[KVM_SPSR_EL1],spsr);
|
|
+ write_sysreg_el2(ctxt->gp_regs.regs.pc, elr);
|
|
+ write_sysreg_el2(ctxt->gp_regs.regs.pstate, spsr);
|
|
}
|
|
|
|
static hyp_alternate_select(__sysreg_call_restore_host_state,
|
|
@@ -183,3 +183,8 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
|
|
if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
|
|
write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
|
|
}
|
|
+
|
|
+void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
|
|
+{
|
|
+ asm("msr tpidr_el2, %0": : "r" (tpidr_el2));
|
|
+}
|
|
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
|
|
index 3256b9228e75..a74311beda35 100644
|
|
--- a/arch/arm64/kvm/reset.c
|
|
+++ b/arch/arm64/kvm/reset.c
|
|
@@ -122,6 +122,10 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
|
|
/* Reset PMU */
|
|
kvm_pmu_vcpu_reset(vcpu);
|
|
|
|
+ /* Default workaround setup is enabled (if supported) */
|
|
+ if (kvm_arm_have_ssbd() == KVM_SSBD_KERNEL)
|
|
+ vcpu->arch.workaround_flags |= VCPU_WORKAROUND_2_FLAG;
|
|
+
|
|
/* Reset timer */
|
|
return kvm_timer_vcpu_reset(vcpu);
|
|
}
|
|
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
|
|
index bf0821b7b1ab..10c835f13f62 100644
|
|
--- a/arch/arm64/mm/proc.S
|
|
+++ b/arch/arm64/mm/proc.S
|
|
@@ -70,7 +70,11 @@ ENTRY(cpu_do_suspend)
|
|
mrs x8, mdscr_el1
|
|
mrs x9, oslsr_el1
|
|
mrs x10, sctlr_el1
|
|
+alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
|
|
mrs x11, tpidr_el1
|
|
+alternative_else
|
|
+ mrs x11, tpidr_el2
|
|
+alternative_endif
|
|
mrs x12, sp_el0
|
|
stp x2, x3, [x0]
|
|
stp x4, xzr, [x0, #16]
|
|
@@ -116,7 +120,11 @@ ENTRY(cpu_do_resume)
|
|
msr mdscr_el1, x10
|
|
|
|
msr sctlr_el1, x12
|
|
+alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
|
|
msr tpidr_el1, x13
|
|
+alternative_else
|
|
+ msr tpidr_el2, x13
|
|
+alternative_endif
|
|
msr sp_el0, x14
|
|
/*
|
|
* Restore oslsr_el1 by writing oslar_el1
|
|
diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h
|
|
index 386a6900e206..3bf87f92b932 100644
|
|
--- a/arch/x86/include/asm/asm.h
|
|
+++ b/arch/x86/include/asm/asm.h
|
|
@@ -46,6 +46,65 @@
|
|
#define _ASM_SI __ASM_REG(si)
|
|
#define _ASM_DI __ASM_REG(di)
|
|
|
|
+#ifndef __x86_64__
|
|
+/* 32 bit */
|
|
+
|
|
+#define _ASM_ARG1 _ASM_AX
|
|
+#define _ASM_ARG2 _ASM_DX
|
|
+#define _ASM_ARG3 _ASM_CX
|
|
+
|
|
+#define _ASM_ARG1L eax
|
|
+#define _ASM_ARG2L edx
|
|
+#define _ASM_ARG3L ecx
|
|
+
|
|
+#define _ASM_ARG1W ax
|
|
+#define _ASM_ARG2W dx
|
|
+#define _ASM_ARG3W cx
|
|
+
|
|
+#define _ASM_ARG1B al
|
|
+#define _ASM_ARG2B dl
|
|
+#define _ASM_ARG3B cl
|
|
+
|
|
+#else
|
|
+/* 64 bit */
|
|
+
|
|
+#define _ASM_ARG1 _ASM_DI
|
|
+#define _ASM_ARG2 _ASM_SI
|
|
+#define _ASM_ARG3 _ASM_DX
|
|
+#define _ASM_ARG4 _ASM_CX
|
|
+#define _ASM_ARG5 r8
|
|
+#define _ASM_ARG6 r9
|
|
+
|
|
+#define _ASM_ARG1Q rdi
|
|
+#define _ASM_ARG2Q rsi
|
|
+#define _ASM_ARG3Q rdx
|
|
+#define _ASM_ARG4Q rcx
|
|
+#define _ASM_ARG5Q r8
|
|
+#define _ASM_ARG6Q r9
|
|
+
|
|
+#define _ASM_ARG1L edi
|
|
+#define _ASM_ARG2L esi
|
|
+#define _ASM_ARG3L edx
|
|
+#define _ASM_ARG4L ecx
|
|
+#define _ASM_ARG5L r8d
|
|
+#define _ASM_ARG6L r9d
|
|
+
|
|
+#define _ASM_ARG1W di
|
|
+#define _ASM_ARG2W si
|
|
+#define _ASM_ARG3W dx
|
|
+#define _ASM_ARG4W cx
|
|
+#define _ASM_ARG5W r8w
|
|
+#define _ASM_ARG6W r9w
|
|
+
|
|
+#define _ASM_ARG1B dil
|
|
+#define _ASM_ARG2B sil
|
|
+#define _ASM_ARG3B dl
|
|
+#define _ASM_ARG4B cl
|
|
+#define _ASM_ARG5B r8b
|
|
+#define _ASM_ARG6B r9b
|
|
+
|
|
+#endif
|
|
+
|
|
/*
|
|
* Macros to generate condition code outputs from inline assembly,
|
|
* The output operand must be type "bool".
|
|
diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h
|
|
index 89f08955fff7..c4fc17220df9 100644
|
|
--- a/arch/x86/include/asm/irqflags.h
|
|
+++ b/arch/x86/include/asm/irqflags.h
|
|
@@ -13,7 +13,7 @@
|
|
* Interrupt control:
|
|
*/
|
|
|
|
-static inline unsigned long native_save_fl(void)
|
|
+extern inline unsigned long native_save_fl(void)
|
|
{
|
|
unsigned long flags;
|
|
|
|
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
|
|
index 295abaa58add..4137f7ba0f88 100644
|
|
--- a/arch/x86/kernel/Makefile
|
|
+++ b/arch/x86/kernel/Makefile
|
|
@@ -58,6 +58,7 @@ obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o
|
|
obj-y += tsc.o tsc_msr.o io_delay.o rtc.o
|
|
obj-y += pci-iommu_table.o
|
|
obj-y += resource.o
|
|
+obj-y += irqflags.o
|
|
|
|
obj-y += process.o
|
|
obj-y += fpu/
|
|
diff --git a/arch/x86/kernel/irqflags.S b/arch/x86/kernel/irqflags.S
|
|
new file mode 100644
|
|
index 000000000000..ddeeaac8adda
|
|
--- /dev/null
|
|
+++ b/arch/x86/kernel/irqflags.S
|
|
@@ -0,0 +1,26 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+
|
|
+#include <asm/asm.h>
|
|
+#include <asm/export.h>
|
|
+#include <linux/linkage.h>
|
|
+
|
|
+/*
|
|
+ * unsigned long native_save_fl(void)
|
|
+ */
|
|
+ENTRY(native_save_fl)
|
|
+ pushf
|
|
+ pop %_ASM_AX
|
|
+ ret
|
|
+ENDPROC(native_save_fl)
|
|
+EXPORT_SYMBOL(native_save_fl)
|
|
+
|
|
+/*
|
|
+ * void native_restore_fl(unsigned long flags)
|
|
+ * %eax/%rdi: flags
|
|
+ */
|
|
+ENTRY(native_restore_fl)
|
|
+ push %_ASM_ARG1
|
|
+ popf
|
|
+ ret
|
|
+ENDPROC(native_restore_fl)
|
|
+EXPORT_SYMBOL(native_restore_fl)
|
|
diff --git a/block/blk-core.c b/block/blk-core.c
|
|
index 6f6e21821d2d..68bae6338ad4 100644
|
|
--- a/block/blk-core.c
|
|
+++ b/block/blk-core.c
|
|
@@ -779,7 +779,6 @@ EXPORT_SYMBOL(blk_alloc_queue);
|
|
int blk_queue_enter(struct request_queue *q, bool nowait)
|
|
{
|
|
while (true) {
|
|
- int ret;
|
|
|
|
if (percpu_ref_tryget_live(&q->q_usage_counter))
|
|
return 0;
|
|
@@ -796,13 +795,11 @@ int blk_queue_enter(struct request_queue *q, bool nowait)
|
|
*/
|
|
smp_rmb();
|
|
|
|
- ret = wait_event_interruptible(q->mq_freeze_wq,
|
|
- !atomic_read(&q->mq_freeze_depth) ||
|
|
- blk_queue_dying(q));
|
|
+ wait_event(q->mq_freeze_wq,
|
|
+ !atomic_read(&q->mq_freeze_depth) ||
|
|
+ blk_queue_dying(q));
|
|
if (blk_queue_dying(q))
|
|
return -ENODEV;
|
|
- if (ret)
|
|
- return ret;
|
|
}
|
|
}
|
|
|
|
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
|
|
index 815ee1075574..42dfdd1fd6d8 100644
|
|
--- a/crypto/af_alg.c
|
|
+++ b/crypto/af_alg.c
|
|
@@ -1183,8 +1183,10 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags,
|
|
|
|
/* make one iovec available as scatterlist */
|
|
err = af_alg_make_sg(&rsgl->sgl, &msg->msg_iter, seglen);
|
|
- if (err < 0)
|
|
+ if (err < 0) {
|
|
+ rsgl->sg_num_bytes = 0;
|
|
return err;
|
|
+ }
|
|
|
|
/* chain the new scatterlist with previous one */
|
|
if (areq->last_rsgl)
|
|
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
|
|
index a8d2eb0ceb8d..2c288d1f42bb 100644
|
|
--- a/drivers/atm/zatm.c
|
|
+++ b/drivers/atm/zatm.c
|
|
@@ -1483,6 +1483,8 @@ static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg)
|
|
return -EFAULT;
|
|
if (pool < 0 || pool > ZATM_LAST_POOL)
|
|
return -EINVAL;
|
|
+ pool = array_index_nospec(pool,
|
|
+ ZATM_LAST_POOL + 1);
|
|
if (copy_from_user(&info,
|
|
&((struct zatm_pool_req __user *) arg)->info,
|
|
sizeof(info))) return -EFAULT;
|
|
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
|
|
index 8b432d6e846d..c9ce716247c1 100644
|
|
--- a/drivers/cpufreq/cppc_cpufreq.c
|
|
+++ b/drivers/cpufreq/cppc_cpufreq.c
|
|
@@ -126,6 +126,49 @@ static void cppc_cpufreq_stop_cpu(struct cpufreq_policy *policy)
|
|
cpu->perf_caps.lowest_perf, cpu_num, ret);
|
|
}
|
|
|
|
+/*
|
|
+ * The PCC subspace describes the rate at which platform can accept commands
|
|
+ * on the shared PCC channel (including READs which do not count towards freq
|
|
+ * trasition requests), so ideally we need to use the PCC values as a fallback
|
|
+ * if we don't have a platform specific transition_delay_us
|
|
+ */
|
|
+#ifdef CONFIG_ARM64
|
|
+#include <asm/cputype.h>
|
|
+
|
|
+static unsigned int cppc_cpufreq_get_transition_delay_us(int cpu)
|
|
+{
|
|
+ unsigned long implementor = read_cpuid_implementor();
|
|
+ unsigned long part_num = read_cpuid_part_number();
|
|
+ unsigned int delay_us = 0;
|
|
+
|
|
+ switch (implementor) {
|
|
+ case ARM_CPU_IMP_QCOM:
|
|
+ switch (part_num) {
|
|
+ case QCOM_CPU_PART_FALKOR_V1:
|
|
+ case QCOM_CPU_PART_FALKOR:
|
|
+ delay_us = 10000;
|
|
+ break;
|
|
+ default:
|
|
+ delay_us = cppc_get_transition_latency(cpu) / NSEC_PER_USEC;
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ delay_us = cppc_get_transition_latency(cpu) / NSEC_PER_USEC;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return delay_us;
|
|
+}
|
|
+
|
|
+#else
|
|
+
|
|
+static unsigned int cppc_cpufreq_get_transition_delay_us(int cpu)
|
|
+{
|
|
+ return cppc_get_transition_latency(cpu) / NSEC_PER_USEC;
|
|
+}
|
|
+#endif
|
|
+
|
|
static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
|
{
|
|
struct cppc_cpudata *cpu;
|
|
@@ -163,8 +206,7 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
|
policy->cpuinfo.max_freq = cppc_dmi_max_khz;
|
|
|
|
policy->cpuinfo.transition_latency = cppc_get_transition_latency(cpu_num);
|
|
- policy->transition_delay_us = cppc_get_transition_latency(cpu_num) /
|
|
- NSEC_PER_USEC;
|
|
+ policy->transition_delay_us = cppc_cpufreq_get_transition_delay_us(cpu_num);
|
|
policy->shared_type = cpu->shared_type;
|
|
|
|
if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
|
|
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
|
|
index 65dc78b91dea..3f9eee7e555f 100644
|
|
--- a/drivers/crypto/amcc/crypto4xx_core.c
|
|
+++ b/drivers/crypto/amcc/crypto4xx_core.c
|
|
@@ -207,7 +207,7 @@ static u32 crypto4xx_build_pdr(struct crypto4xx_device *dev)
|
|
dev->pdr_pa);
|
|
return -ENOMEM;
|
|
}
|
|
- memset(dev->pdr, 0, sizeof(struct ce_pd) * PPC4XX_NUM_PD);
|
|
+ memset(dev->pdr, 0, sizeof(struct ce_pd) * PPC4XX_NUM_PD);
|
|
dev->shadow_sa_pool = dma_alloc_coherent(dev->core_dev->device,
|
|
256 * PPC4XX_NUM_PD,
|
|
&dev->shadow_sa_pool_pa,
|
|
@@ -240,13 +240,15 @@ static u32 crypto4xx_build_pdr(struct crypto4xx_device *dev)
|
|
|
|
static void crypto4xx_destroy_pdr(struct crypto4xx_device *dev)
|
|
{
|
|
- if (dev->pdr != NULL)
|
|
+ if (dev->pdr)
|
|
dma_free_coherent(dev->core_dev->device,
|
|
sizeof(struct ce_pd) * PPC4XX_NUM_PD,
|
|
dev->pdr, dev->pdr_pa);
|
|
+
|
|
if (dev->shadow_sa_pool)
|
|
dma_free_coherent(dev->core_dev->device, 256 * PPC4XX_NUM_PD,
|
|
dev->shadow_sa_pool, dev->shadow_sa_pool_pa);
|
|
+
|
|
if (dev->shadow_sr_pool)
|
|
dma_free_coherent(dev->core_dev->device,
|
|
sizeof(struct sa_state_record) * PPC4XX_NUM_PD,
|
|
@@ -416,12 +418,12 @@ static u32 crypto4xx_build_sdr(struct crypto4xx_device *dev)
|
|
|
|
static void crypto4xx_destroy_sdr(struct crypto4xx_device *dev)
|
|
{
|
|
- if (dev->sdr != NULL)
|
|
+ if (dev->sdr)
|
|
dma_free_coherent(dev->core_dev->device,
|
|
sizeof(struct ce_sd) * PPC4XX_NUM_SD,
|
|
dev->sdr, dev->sdr_pa);
|
|
|
|
- if (dev->scatter_buffer_va != NULL)
|
|
+ if (dev->scatter_buffer_va)
|
|
dma_free_coherent(dev->core_dev->device,
|
|
dev->scatter_buffer_size * PPC4XX_NUM_SD,
|
|
dev->scatter_buffer_va,
|
|
@@ -1033,12 +1035,10 @@ int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
|
|
break;
|
|
}
|
|
|
|
- if (rc) {
|
|
- list_del(&alg->entry);
|
|
+ if (rc)
|
|
kfree(alg);
|
|
- } else {
|
|
+ else
|
|
list_add_tail(&alg->entry, &sec_dev->alg_list);
|
|
- }
|
|
}
|
|
|
|
return 0;
|
|
@@ -1193,7 +1193,7 @@ static int crypto4xx_probe(struct platform_device *ofdev)
|
|
|
|
rc = crypto4xx_build_gdr(core_dev->dev);
|
|
if (rc)
|
|
- goto err_build_gdr;
|
|
+ goto err_build_pdr;
|
|
|
|
rc = crypto4xx_build_sdr(core_dev->dev);
|
|
if (rc)
|
|
@@ -1236,12 +1236,11 @@ static int crypto4xx_probe(struct platform_device *ofdev)
|
|
err_request_irq:
|
|
irq_dispose_mapping(core_dev->irq);
|
|
tasklet_kill(&core_dev->tasklet);
|
|
- crypto4xx_destroy_sdr(core_dev->dev);
|
|
err_build_sdr:
|
|
+ crypto4xx_destroy_sdr(core_dev->dev);
|
|
crypto4xx_destroy_gdr(core_dev->dev);
|
|
-err_build_gdr:
|
|
- crypto4xx_destroy_pdr(core_dev->dev);
|
|
err_build_pdr:
|
|
+ crypto4xx_destroy_pdr(core_dev->dev);
|
|
kfree(core_dev->dev);
|
|
err_alloc_dev:
|
|
kfree(core_dev);
|
|
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
|
|
index 72f381522cb2..a22828713c1c 100644
|
|
--- a/drivers/media/rc/rc-main.c
|
|
+++ b/drivers/media/rc/rc-main.c
|
|
@@ -1824,11 +1824,11 @@ void rc_unregister_device(struct rc_dev *dev)
|
|
if (!dev)
|
|
return;
|
|
|
|
- del_timer_sync(&dev->timer_keyup);
|
|
-
|
|
if (dev->driver_type == RC_DRIVER_IR_RAW)
|
|
ir_raw_event_unregister(dev);
|
|
|
|
+ del_timer_sync(&dev->timer_keyup);
|
|
+
|
|
rc_free_rx_device(dev);
|
|
|
|
device_del(&dev->dev);
|
|
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
|
|
index 56e2e177644d..3f4f4aea0e8b 100644
|
|
--- a/drivers/mtd/nand/denali_dt.c
|
|
+++ b/drivers/mtd/nand/denali_dt.c
|
|
@@ -122,7 +122,11 @@ static int denali_dt_probe(struct platform_device *pdev)
|
|
if (ret)
|
|
return ret;
|
|
|
|
- denali->clk_x_rate = clk_get_rate(dt->clk);
|
|
+ /*
|
|
+ * Hardcode the clock rate for the backward compatibility.
|
|
+ * This works for both SOCFPGA and UniPhier.
|
|
+ */
|
|
+ denali->clk_x_rate = 200000000;
|
|
|
|
ret = denali_init(denali);
|
|
if (ret)
|
|
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
|
|
index 567ee54504bc..5e5022fa1d04 100644
|
|
--- a/drivers/net/ethernet/atheros/alx/main.c
|
|
+++ b/drivers/net/ethernet/atheros/alx/main.c
|
|
@@ -1897,13 +1897,19 @@ static int alx_resume(struct device *dev)
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
struct alx_priv *alx = pci_get_drvdata(pdev);
|
|
struct alx_hw *hw = &alx->hw;
|
|
+ int err;
|
|
|
|
alx_reset_phy(hw);
|
|
|
|
if (!netif_running(alx->dev))
|
|
return 0;
|
|
netif_device_attach(alx->dev);
|
|
- return __alx_open(alx, true);
|
|
+
|
|
+ rtnl_lock();
|
|
+ err = __alx_open(alx, true);
|
|
+ rtnl_unlock();
|
|
+
|
|
+ return err;
|
|
}
|
|
|
|
static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume);
|
|
diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
|
|
index 4f3845a58126..68470c7c630a 100644
|
|
--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c
|
|
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
|
|
@@ -1062,7 +1062,8 @@ static int bcm_enet_open(struct net_device *dev)
|
|
val = enet_readl(priv, ENET_CTL_REG);
|
|
val |= ENET_CTL_ENABLE_MASK;
|
|
enet_writel(priv, val, ENET_CTL_REG);
|
|
- enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG);
|
|
+ if (priv->dma_has_sram)
|
|
+ enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG);
|
|
enet_dmac_writel(priv, priv->dma_chan_en_mask,
|
|
ENETDMAC_CHANCFG, priv->rx_chan);
|
|
|
|
@@ -1773,7 +1774,9 @@ static int bcm_enet_probe(struct platform_device *pdev)
|
|
ret = PTR_ERR(priv->mac_clk);
|
|
goto out;
|
|
}
|
|
- clk_prepare_enable(priv->mac_clk);
|
|
+ ret = clk_prepare_enable(priv->mac_clk);
|
|
+ if (ret)
|
|
+ goto out_put_clk_mac;
|
|
|
|
/* initialize default and fetch platform data */
|
|
priv->rx_ring_size = BCMENET_DEF_RX_DESC;
|
|
@@ -1805,9 +1808,11 @@ static int bcm_enet_probe(struct platform_device *pdev)
|
|
if (IS_ERR(priv->phy_clk)) {
|
|
ret = PTR_ERR(priv->phy_clk);
|
|
priv->phy_clk = NULL;
|
|
- goto out_put_clk_mac;
|
|
+ goto out_disable_clk_mac;
|
|
}
|
|
- clk_prepare_enable(priv->phy_clk);
|
|
+ ret = clk_prepare_enable(priv->phy_clk);
|
|
+ if (ret)
|
|
+ goto out_put_clk_phy;
|
|
}
|
|
|
|
/* do minimal hardware init to be able to probe mii bus */
|
|
@@ -1901,13 +1906,16 @@ static int bcm_enet_probe(struct platform_device *pdev)
|
|
out_uninit_hw:
|
|
/* turn off mdc clock */
|
|
enet_writel(priv, 0, ENET_MIISC_REG);
|
|
- if (priv->phy_clk) {
|
|
+ if (priv->phy_clk)
|
|
clk_disable_unprepare(priv->phy_clk);
|
|
+
|
|
+out_put_clk_phy:
|
|
+ if (priv->phy_clk)
|
|
clk_put(priv->phy_clk);
|
|
- }
|
|
|
|
-out_put_clk_mac:
|
|
+out_disable_clk_mac:
|
|
clk_disable_unprepare(priv->mac_clk);
|
|
+out_put_clk_mac:
|
|
clk_put(priv->mac_clk);
|
|
out:
|
|
free_netdev(dev);
|
|
@@ -2752,7 +2760,9 @@ static int bcm_enetsw_probe(struct platform_device *pdev)
|
|
ret = PTR_ERR(priv->mac_clk);
|
|
goto out_unmap;
|
|
}
|
|
- clk_enable(priv->mac_clk);
|
|
+ ret = clk_prepare_enable(priv->mac_clk);
|
|
+ if (ret)
|
|
+ goto out_put_clk;
|
|
|
|
priv->rx_chan = 0;
|
|
priv->tx_chan = 1;
|
|
@@ -2773,7 +2783,7 @@ static int bcm_enetsw_probe(struct platform_device *pdev)
|
|
|
|
ret = register_netdev(dev);
|
|
if (ret)
|
|
- goto out_put_clk;
|
|
+ goto out_disable_clk;
|
|
|
|
netif_carrier_off(dev);
|
|
platform_set_drvdata(pdev, dev);
|
|
@@ -2782,6 +2792,9 @@ static int bcm_enetsw_probe(struct platform_device *pdev)
|
|
|
|
return 0;
|
|
|
|
+out_disable_clk:
|
|
+ clk_disable_unprepare(priv->mac_clk);
|
|
+
|
|
out_put_clk:
|
|
clk_put(priv->mac_clk);
|
|
|
|
@@ -2813,6 +2826,9 @@ static int bcm_enetsw_remove(struct platform_device *pdev)
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
release_mem_region(res->start, resource_size(res));
|
|
|
|
+ clk_disable_unprepare(priv->mac_clk);
|
|
+ clk_put(priv->mac_clk);
|
|
+
|
|
free_netdev(dev);
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c
|
|
index 2220c771092b..678835136bf8 100755
|
|
--- a/drivers/net/ethernet/cadence/macb_ptp.c
|
|
+++ b/drivers/net/ethernet/cadence/macb_ptp.c
|
|
@@ -170,10 +170,7 @@ static int gem_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
|
|
|
if (delta > TSU_NSEC_MAX_VAL) {
|
|
gem_tsu_get_time(&bp->ptp_clock_info, &now);
|
|
- if (sign)
|
|
- now = timespec64_sub(now, then);
|
|
- else
|
|
- now = timespec64_add(now, then);
|
|
+ now = timespec64_add(now, then);
|
|
|
|
gem_tsu_set_time(&bp->ptp_clock_info,
|
|
(const struct timespec64 *)&now);
|
|
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
|
|
index 6a015362c340..bf291e90cdb0 100644
|
|
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
|
|
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
|
|
@@ -51,6 +51,7 @@
|
|
#include <linux/sched.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/uaccess.h>
|
|
+#include <linux/nospec.h>
|
|
|
|
#include "common.h"
|
|
#include "cxgb3_ioctl.h"
|
|
@@ -2268,6 +2269,7 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
|
|
|
if (t.qset_idx >= nqsets)
|
|
return -EINVAL;
|
|
+ t.qset_idx = array_index_nospec(t.qset_idx, nqsets);
|
|
|
|
q = &adapter->params.sge.qset[q1 + t.qset_idx];
|
|
t.rspq_size = q->rspq_size;
|
|
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
|
|
index 20a8018d41ef..b68d94b49a8a 100644
|
|
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
|
|
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
|
|
@@ -2211,9 +2211,10 @@ static struct sk_buff *ixgbe_build_skb(struct ixgbe_ring *rx_ring,
|
|
return skb;
|
|
}
|
|
|
|
-#define IXGBE_XDP_PASS 0
|
|
-#define IXGBE_XDP_CONSUMED 1
|
|
-#define IXGBE_XDP_TX 2
|
|
+#define IXGBE_XDP_PASS 0
|
|
+#define IXGBE_XDP_CONSUMED BIT(0)
|
|
+#define IXGBE_XDP_TX BIT(1)
|
|
+#define IXGBE_XDP_REDIR BIT(2)
|
|
|
|
static int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter,
|
|
struct xdp_buff *xdp);
|
|
@@ -2242,7 +2243,7 @@ static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
|
|
case XDP_REDIRECT:
|
|
err = xdp_do_redirect(adapter->netdev, xdp, xdp_prog);
|
|
if (!err)
|
|
- result = IXGBE_XDP_TX;
|
|
+ result = IXGBE_XDP_REDIR;
|
|
else
|
|
result = IXGBE_XDP_CONSUMED;
|
|
break;
|
|
@@ -2302,7 +2303,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
|
|
unsigned int mss = 0;
|
|
#endif /* IXGBE_FCOE */
|
|
u16 cleaned_count = ixgbe_desc_unused(rx_ring);
|
|
- bool xdp_xmit = false;
|
|
+ unsigned int xdp_xmit = 0;
|
|
|
|
while (likely(total_rx_packets < budget)) {
|
|
union ixgbe_adv_rx_desc *rx_desc;
|
|
@@ -2342,8 +2343,10 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
|
|
}
|
|
|
|
if (IS_ERR(skb)) {
|
|
- if (PTR_ERR(skb) == -IXGBE_XDP_TX) {
|
|
- xdp_xmit = true;
|
|
+ unsigned int xdp_res = -PTR_ERR(skb);
|
|
+
|
|
+ if (xdp_res & (IXGBE_XDP_TX | IXGBE_XDP_REDIR)) {
|
|
+ xdp_xmit |= xdp_res;
|
|
ixgbe_rx_buffer_flip(rx_ring, rx_buffer, size);
|
|
} else {
|
|
rx_buffer->pagecnt_bias++;
|
|
@@ -2415,7 +2418,10 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
|
|
total_rx_packets++;
|
|
}
|
|
|
|
- if (xdp_xmit) {
|
|
+ if (xdp_xmit & IXGBE_XDP_REDIR)
|
|
+ xdp_do_flush_map();
|
|
+
|
|
+ if (xdp_xmit & IXGBE_XDP_TX) {
|
|
struct ixgbe_ring *ring = adapter->xdp_ring[smp_processor_id()];
|
|
|
|
/* Force memory writes to complete before letting h/w
|
|
@@ -2423,8 +2429,6 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
|
|
*/
|
|
wmb();
|
|
writel(ring->next_to_use, ring->tail);
|
|
-
|
|
- xdp_do_flush_map();
|
|
}
|
|
|
|
u64_stats_update_begin(&rx_ring->syncp);
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
|
|
index 3efe45bc2471..cf94fdf25155 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
|
|
@@ -801,6 +801,7 @@ static void cmd_work_handler(struct work_struct *work)
|
|
unsigned long flags;
|
|
bool poll_cmd = ent->polling;
|
|
int alloc_ret;
|
|
+ int cmd_mode;
|
|
|
|
sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
|
|
down(sem);
|
|
@@ -847,6 +848,7 @@ static void cmd_work_handler(struct work_struct *work)
|
|
set_signature(ent, !cmd->checksum_disabled);
|
|
dump_command(dev, ent, 1);
|
|
ent->ts1 = ktime_get_ns();
|
|
+ cmd_mode = cmd->mode;
|
|
|
|
if (ent->callback)
|
|
schedule_delayed_work(&ent->cb_timeout_work, cb_timeout);
|
|
@@ -871,7 +873,7 @@ static void cmd_work_handler(struct work_struct *work)
|
|
iowrite32be(1 << ent->idx, &dev->iseg->cmd_dbell);
|
|
mmiowb();
|
|
/* if not in polling don't use ent after this point */
|
|
- if (cmd->mode == CMD_MODE_POLLING || poll_cmd) {
|
|
+ if (cmd_mode == CMD_MODE_POLLING || poll_cmd) {
|
|
poll_timeout(ent);
|
|
/* make sure we read the descriptor after ownership is SW */
|
|
rmb();
|
|
@@ -1272,7 +1274,7 @@ static ssize_t outlen_write(struct file *filp, const char __user *buf,
|
|
{
|
|
struct mlx5_core_dev *dev = filp->private_data;
|
|
struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
|
|
- char outlen_str[8];
|
|
+ char outlen_str[8] = {0};
|
|
int outlen;
|
|
void *ptr;
|
|
int err;
|
|
@@ -1287,8 +1289,6 @@ static ssize_t outlen_write(struct file *filp, const char __user *buf,
|
|
if (copy_from_user(outlen_str, buf, count))
|
|
return -EFAULT;
|
|
|
|
- outlen_str[7] = 0;
|
|
-
|
|
err = sscanf(outlen_str, "%d", &outlen);
|
|
if (err < 0)
|
|
return err;
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
|
|
index 337ce9423794..bf34264c734b 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
|
|
@@ -2626,7 +2626,7 @@ void mlx5e_activate_priv_channels(struct mlx5e_priv *priv)
|
|
mlx5e_activate_channels(&priv->channels);
|
|
netif_tx_start_all_queues(priv->netdev);
|
|
|
|
- if (MLX5_VPORT_MANAGER(priv->mdev))
|
|
+ if (MLX5_ESWITCH_MANAGER(priv->mdev))
|
|
mlx5e_add_sqs_fwd_rules(priv);
|
|
|
|
mlx5e_wait_channels_min_rx_wqes(&priv->channels);
|
|
@@ -2637,7 +2637,7 @@ void mlx5e_deactivate_priv_channels(struct mlx5e_priv *priv)
|
|
{
|
|
mlx5e_redirect_rqts_to_drop(priv);
|
|
|
|
- if (MLX5_VPORT_MANAGER(priv->mdev))
|
|
+ if (MLX5_ESWITCH_MANAGER(priv->mdev))
|
|
mlx5e_remove_sqs_fwd_rules(priv);
|
|
|
|
/* FIXME: This is a W/A only for tx timeout watch dog false alarm when
|
|
@@ -4127,7 +4127,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
|
|
mlx5e_set_netdev_dev_addr(netdev);
|
|
|
|
#if IS_ENABLED(CONFIG_MLX5_ESWITCH)
|
|
- if (MLX5_VPORT_MANAGER(mdev))
|
|
+ if (MLX5_ESWITCH_MANAGER(mdev))
|
|
netdev->switchdev_ops = &mlx5e_switchdev_ops;
|
|
#endif
|
|
|
|
@@ -4273,7 +4273,7 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv)
|
|
|
|
mlx5e_enable_async_events(priv);
|
|
|
|
- if (MLX5_VPORT_MANAGER(priv->mdev))
|
|
+ if (MLX5_ESWITCH_MANAGER(priv->mdev))
|
|
mlx5e_register_vport_reps(priv);
|
|
|
|
if (netdev->reg_state != NETREG_REGISTERED)
|
|
@@ -4300,7 +4300,7 @@ static void mlx5e_nic_disable(struct mlx5e_priv *priv)
|
|
|
|
queue_work(priv->wq, &priv->set_rx_mode_work);
|
|
|
|
- if (MLX5_VPORT_MANAGER(priv->mdev))
|
|
+ if (MLX5_ESWITCH_MANAGER(priv->mdev))
|
|
mlx5e_unregister_vport_reps(priv);
|
|
|
|
mlx5e_disable_async_events(priv);
|
|
@@ -4483,7 +4483,7 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
|
|
return NULL;
|
|
|
|
#ifdef CONFIG_MLX5_ESWITCH
|
|
- if (MLX5_VPORT_MANAGER(mdev)) {
|
|
+ if (MLX5_ESWITCH_MANAGER(mdev)) {
|
|
rpriv = mlx5e_alloc_nic_rep_priv(mdev);
|
|
if (!rpriv) {
|
|
mlx5_core_warn(mdev, "Failed to alloc NIC rep priv data\n");
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
|
|
index 4727e7390834..281911698f72 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
|
|
@@ -710,7 +710,7 @@ bool mlx5e_is_uplink_rep(struct mlx5e_priv *priv)
|
|
struct mlx5e_rep_priv *rpriv = priv->ppriv;
|
|
struct mlx5_eswitch_rep *rep;
|
|
|
|
- if (!MLX5_CAP_GEN(priv->mdev, vport_group_manager))
|
|
+ if (!MLX5_ESWITCH_MANAGER(priv->mdev))
|
|
return false;
|
|
|
|
rep = rpriv->rep;
|
|
@@ -724,8 +724,12 @@ bool mlx5e_is_uplink_rep(struct mlx5e_priv *priv)
|
|
static bool mlx5e_is_vf_vport_rep(struct mlx5e_priv *priv)
|
|
{
|
|
struct mlx5e_rep_priv *rpriv = priv->ppriv;
|
|
- struct mlx5_eswitch_rep *rep = rpriv->rep;
|
|
+ struct mlx5_eswitch_rep *rep;
|
|
|
|
+ if (!MLX5_ESWITCH_MANAGER(priv->mdev))
|
|
+ return false;
|
|
+
|
|
+ rep = rpriv->rep;
|
|
if (rep && rep->vport != FDB_UPLINK_VPORT)
|
|
return true;
|
|
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
|
|
index 82e37250ed01..667415301066 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
|
|
@@ -1535,7 +1535,7 @@ int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
|
|
if (!ESW_ALLOWED(esw))
|
|
return 0;
|
|
|
|
- if (!MLX5_CAP_GEN(esw->dev, eswitch_flow_table) ||
|
|
+ if (!MLX5_ESWITCH_MANAGER(esw->dev) ||
|
|
!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) {
|
|
esw_warn(esw->dev, "E-Switch FDB is not supported, aborting ...\n");
|
|
return -EOPNOTSUPP;
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
|
|
index 565c8b7a399a..10bf770675f3 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
|
|
@@ -39,6 +39,8 @@
|
|
#include <linux/mlx5/device.h>
|
|
#include "lib/mpfs.h"
|
|
|
|
+#define MLX5_ESWITCH_MANAGER(mdev) MLX5_CAP_GEN(mdev, eswitch_manager)
|
|
+
|
|
enum {
|
|
SRIOV_NONE,
|
|
SRIOV_LEGACY,
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
|
|
index d9fd8570b07c..c699055c0ffd 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
|
|
@@ -912,8 +912,8 @@ static int mlx5_devlink_eswitch_check(struct devlink *devlink)
|
|
if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
|
|
return -EOPNOTSUPP;
|
|
|
|
- if (!MLX5_CAP_GEN(dev, vport_group_manager))
|
|
- return -EOPNOTSUPP;
|
|
+ if(!MLX5_ESWITCH_MANAGER(dev))
|
|
+ return -EPERM;
|
|
|
|
if (dev->priv.eswitch->mode == SRIOV_NONE)
|
|
return -EOPNOTSUPP;
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
|
|
index 33e5ff081e36..dd05cf148845 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
|
|
@@ -36,6 +36,7 @@
|
|
#include "mlx5_core.h"
|
|
#include "fs_core.h"
|
|
#include "fs_cmd.h"
|
|
+#include "eswitch.h"
|
|
#include "diag/fs_tracepoint.h"
|
|
|
|
#define INIT_TREE_NODE_ARRAY_SIZE(...) (sizeof((struct init_tree_node[]){__VA_ARGS__}) /\
|
|
@@ -2211,7 +2212,7 @@ int mlx5_init_fs(struct mlx5_core_dev *dev)
|
|
goto err;
|
|
}
|
|
|
|
- if (MLX5_CAP_GEN(dev, eswitch_flow_table)) {
|
|
+ if (MLX5_ESWITCH_MANAGER(dev)) {
|
|
if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, ft_support)) {
|
|
err = init_fdb_root_ns(steering);
|
|
if (err)
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
|
|
index 2c71557d1cee..d69897a1e2ce 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
|
|
@@ -34,6 +34,7 @@
|
|
#include <linux/mlx5/cmd.h>
|
|
#include <linux/module.h>
|
|
#include "mlx5_core.h"
|
|
+#include "eswitch.h"
|
|
#include "../../mlxfw/mlxfw.h"
|
|
|
|
static int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev, u32 *out,
|
|
@@ -152,13 +153,13 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
|
|
}
|
|
|
|
if (MLX5_CAP_GEN(dev, vport_group_manager) &&
|
|
- MLX5_CAP_GEN(dev, eswitch_flow_table)) {
|
|
+ MLX5_ESWITCH_MANAGER(dev)) {
|
|
err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH_FLOW_TABLE);
|
|
if (err)
|
|
return err;
|
|
}
|
|
|
|
- if (MLX5_CAP_GEN(dev, eswitch_flow_table)) {
|
|
+ if (MLX5_ESWITCH_MANAGER(dev)) {
|
|
err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH);
|
|
if (err)
|
|
return err;
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c
|
|
index 7cb67122e8b5..22811ecd8fcd 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c
|
|
@@ -34,6 +34,7 @@
|
|
#include <linux/mlx5/driver.h>
|
|
#include <linux/mlx5/mlx5_ifc.h>
|
|
#include "mlx5_core.h"
|
|
+#include "eswitch.h"
|
|
#include "lib/mpfs.h"
|
|
|
|
/* HW L2 Table (MPFS) management */
|
|
@@ -98,7 +99,7 @@ int mlx5_mpfs_init(struct mlx5_core_dev *dev)
|
|
int l2table_size = 1 << MLX5_CAP_GEN(dev, log_max_l2_table);
|
|
struct mlx5_mpfs *mpfs;
|
|
|
|
- if (!MLX5_VPORT_MANAGER(dev))
|
|
+ if (!MLX5_ESWITCH_MANAGER(dev))
|
|
return 0;
|
|
|
|
mpfs = kzalloc(sizeof(*mpfs), GFP_KERNEL);
|
|
@@ -122,7 +123,7 @@ void mlx5_mpfs_cleanup(struct mlx5_core_dev *dev)
|
|
{
|
|
struct mlx5_mpfs *mpfs = dev->priv.mpfs;
|
|
|
|
- if (!MLX5_VPORT_MANAGER(dev))
|
|
+ if (!MLX5_ESWITCH_MANAGER(dev))
|
|
return;
|
|
|
|
WARN_ON(!hlist_empty(mpfs->hash));
|
|
@@ -137,7 +138,7 @@ int mlx5_mpfs_add_mac(struct mlx5_core_dev *dev, u8 *mac)
|
|
u32 index;
|
|
int err;
|
|
|
|
- if (!MLX5_VPORT_MANAGER(dev))
|
|
+ if (!MLX5_ESWITCH_MANAGER(dev))
|
|
return 0;
|
|
|
|
mutex_lock(&mpfs->lock);
|
|
@@ -179,7 +180,7 @@ int mlx5_mpfs_del_mac(struct mlx5_core_dev *dev, u8 *mac)
|
|
int err = 0;
|
|
u32 index;
|
|
|
|
- if (!MLX5_VPORT_MANAGER(dev))
|
|
+ if (!MLX5_ESWITCH_MANAGER(dev))
|
|
return 0;
|
|
|
|
mutex_lock(&mpfs->lock);
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c
|
|
index e07061f565d6..ccb6287aeeb7 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/port.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c
|
|
@@ -641,7 +641,7 @@ EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc);
|
|
static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
|
|
int inlen)
|
|
{
|
|
- u32 out[MLX5_ST_SZ_DW(qtct_reg)];
|
|
+ u32 out[MLX5_ST_SZ_DW(qetc_reg)];
|
|
|
|
if (!MLX5_CAP_GEN(mdev, ets))
|
|
return -EOPNOTSUPP;
|
|
@@ -653,7 +653,7 @@ static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
|
|
static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
|
|
int outlen)
|
|
{
|
|
- u32 in[MLX5_ST_SZ_DW(qtct_reg)];
|
|
+ u32 in[MLX5_ST_SZ_DW(qetc_reg)];
|
|
|
|
if (!MLX5_CAP_GEN(mdev, ets))
|
|
return -EOPNOTSUPP;
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
|
|
index 2a8b529ce6dd..a0674962f02c 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
|
|
@@ -88,6 +88,9 @@ static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs)
|
|
return -EBUSY;
|
|
}
|
|
|
|
+ if (!MLX5_ESWITCH_MANAGER(dev))
|
|
+ goto enable_vfs_hca;
|
|
+
|
|
err = mlx5_eswitch_enable_sriov(dev->priv.eswitch, num_vfs, SRIOV_LEGACY);
|
|
if (err) {
|
|
mlx5_core_warn(dev,
|
|
@@ -95,6 +98,7 @@ static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs)
|
|
return err;
|
|
}
|
|
|
|
+enable_vfs_hca:
|
|
for (vf = 0; vf < num_vfs; vf++) {
|
|
err = mlx5_core_enable_hca(dev, vf + 1);
|
|
if (err) {
|
|
@@ -140,7 +144,8 @@ static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev)
|
|
}
|
|
|
|
out:
|
|
- mlx5_eswitch_disable_sriov(dev->priv.eswitch);
|
|
+ if (MLX5_ESWITCH_MANAGER(dev))
|
|
+ mlx5_eswitch_disable_sriov(dev->priv.eswitch);
|
|
|
|
if (mlx5_wait_for_vf_pages(dev))
|
|
mlx5_core_warn(dev, "timeout reclaiming VFs pages\n");
|
|
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
|
|
index 8f6ccc0c39e5..b306961b02fd 100644
|
|
--- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
|
|
+++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
|
|
@@ -700,9 +700,9 @@ qed_dcbx_get_local_lldp_params(struct qed_hwfn *p_hwfn,
|
|
p_local = &p_hwfn->p_dcbx_info->lldp_local[LLDP_NEAREST_BRIDGE];
|
|
|
|
memcpy(params->lldp_local.local_chassis_id, p_local->local_chassis_id,
|
|
- ARRAY_SIZE(p_local->local_chassis_id));
|
|
+ sizeof(p_local->local_chassis_id));
|
|
memcpy(params->lldp_local.local_port_id, p_local->local_port_id,
|
|
- ARRAY_SIZE(p_local->local_port_id));
|
|
+ sizeof(p_local->local_port_id));
|
|
}
|
|
|
|
static void
|
|
@@ -714,9 +714,9 @@ qed_dcbx_get_remote_lldp_params(struct qed_hwfn *p_hwfn,
|
|
p_remote = &p_hwfn->p_dcbx_info->lldp_remote[LLDP_NEAREST_BRIDGE];
|
|
|
|
memcpy(params->lldp_remote.peer_chassis_id, p_remote->peer_chassis_id,
|
|
- ARRAY_SIZE(p_remote->peer_chassis_id));
|
|
+ sizeof(p_remote->peer_chassis_id));
|
|
memcpy(params->lldp_remote.peer_port_id, p_remote->peer_port_id,
|
|
- ARRAY_SIZE(p_remote->peer_port_id));
|
|
+ sizeof(p_remote->peer_port_id));
|
|
}
|
|
|
|
static int
|
|
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
|
|
index 58a689fb04db..ef2374699726 100644
|
|
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
|
|
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
|
|
@@ -1782,7 +1782,7 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params)
|
|
DP_INFO(p_hwfn, "Failed to update driver state\n");
|
|
|
|
rc = qed_mcp_ov_update_eswitch(p_hwfn, p_hwfn->p_main_ptt,
|
|
- QED_OV_ESWITCH_VEB);
|
|
+ QED_OV_ESWITCH_NONE);
|
|
if (rc)
|
|
DP_INFO(p_hwfn, "Failed to update eswitch mode\n");
|
|
}
|
|
diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c
|
|
index 27832885a87f..2c958921dfb3 100644
|
|
--- a/drivers/net/ethernet/qlogic/qed/qed_main.c
|
|
+++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
|
|
@@ -779,6 +779,14 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev,
|
|
/* We want a minimum of one slowpath and one fastpath vector per hwfn */
|
|
cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2;
|
|
|
|
+ if (is_kdump_kernel()) {
|
|
+ DP_INFO(cdev,
|
|
+ "Kdump kernel: Limit the max number of requested MSI-X vectors to %hd\n",
|
|
+ cdev->int_params.in.min_msix_cnt);
|
|
+ cdev->int_params.in.num_vectors =
|
|
+ cdev->int_params.in.min_msix_cnt;
|
|
+ }
|
|
+
|
|
rc = qed_set_int_mode(cdev, false);
|
|
if (rc) {
|
|
DP_ERR(cdev, "qed_slowpath_setup_int ERR\n");
|
|
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c
|
|
index 3f40b1de7957..d08fe350ab6c 100644
|
|
--- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c
|
|
+++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c
|
|
@@ -4396,6 +4396,8 @@ static void qed_sriov_enable_qid_config(struct qed_hwfn *hwfn,
|
|
static int qed_sriov_enable(struct qed_dev *cdev, int num)
|
|
{
|
|
struct qed_iov_vf_init_params params;
|
|
+ struct qed_hwfn *hwfn;
|
|
+ struct qed_ptt *ptt;
|
|
int i, j, rc;
|
|
|
|
if (num >= RESC_NUM(&cdev->hwfns[0], QED_VPORT)) {
|
|
@@ -4408,8 +4410,8 @@ static int qed_sriov_enable(struct qed_dev *cdev, int num)
|
|
|
|
/* Initialize HW for VF access */
|
|
for_each_hwfn(cdev, j) {
|
|
- struct qed_hwfn *hwfn = &cdev->hwfns[j];
|
|
- struct qed_ptt *ptt = qed_ptt_acquire(hwfn);
|
|
+ hwfn = &cdev->hwfns[j];
|
|
+ ptt = qed_ptt_acquire(hwfn);
|
|
|
|
/* Make sure not to use more than 16 queues per VF */
|
|
params.num_queues = min_t(int,
|
|
@@ -4445,6 +4447,19 @@ static int qed_sriov_enable(struct qed_dev *cdev, int num)
|
|
goto err;
|
|
}
|
|
|
|
+ hwfn = QED_LEADING_HWFN(cdev);
|
|
+ ptt = qed_ptt_acquire(hwfn);
|
|
+ if (!ptt) {
|
|
+ DP_ERR(hwfn, "Failed to acquire ptt\n");
|
|
+ rc = -EBUSY;
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ rc = qed_mcp_ov_update_eswitch(hwfn, ptt, QED_OV_ESWITCH_VEB);
|
|
+ if (rc)
|
|
+ DP_INFO(cdev, "Failed to update eswitch mode\n");
|
|
+ qed_ptt_release(hwfn, ptt);
|
|
+
|
|
return num;
|
|
|
|
err:
|
|
diff --git a/drivers/net/ethernet/qlogic/qede/qede_ptp.c b/drivers/net/ethernet/qlogic/qede/qede_ptp.c
|
|
index 9b2280badaf7..475f6ae5d4b3 100644
|
|
--- a/drivers/net/ethernet/qlogic/qede/qede_ptp.c
|
|
+++ b/drivers/net/ethernet/qlogic/qede/qede_ptp.c
|
|
@@ -337,8 +337,14 @@ int qede_ptp_get_ts_info(struct qede_dev *edev, struct ethtool_ts_info *info)
|
|
{
|
|
struct qede_ptp *ptp = edev->ptp;
|
|
|
|
- if (!ptp)
|
|
- return -EIO;
|
|
+ if (!ptp) {
|
|
+ info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
|
|
+ SOF_TIMESTAMPING_RX_SOFTWARE |
|
|
+ SOF_TIMESTAMPING_SOFTWARE;
|
|
+ info->phc_index = -1;
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
|
|
info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
|
|
SOF_TIMESTAMPING_RX_SOFTWARE |
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
|
index 9866d2e34cdd..27f2e650e27b 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
|
@@ -914,6 +914,7 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
|
|
static int stmmac_init_phy(struct net_device *dev)
|
|
{
|
|
struct stmmac_priv *priv = netdev_priv(dev);
|
|
+ u32 tx_cnt = priv->plat->tx_queues_to_use;
|
|
struct phy_device *phydev;
|
|
char phy_id_fmt[MII_BUS_ID_SIZE + 3];
|
|
char bus_id[MII_BUS_ID_SIZE];
|
|
@@ -954,6 +955,15 @@ static int stmmac_init_phy(struct net_device *dev)
|
|
phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
|
|
SUPPORTED_1000baseT_Full);
|
|
|
|
+ /*
|
|
+ * Half-duplex mode not supported with multiqueue
|
|
+ * half-duplex can only works with single queue
|
|
+ */
|
|
+ if (tx_cnt > 1)
|
|
+ phydev->supported &= ~(SUPPORTED_1000baseT_Half |
|
|
+ SUPPORTED_100baseT_Half |
|
|
+ SUPPORTED_10baseT_Half);
|
|
+
|
|
/*
|
|
* Broken HW is sometimes missing the pull-up resistor on the
|
|
* MDIO line, which results in reads to non-existent devices returning
|
|
diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c
|
|
index fa607d062cb3..15cd086e3f47 100644
|
|
--- a/drivers/net/ethernet/sun/sungem.c
|
|
+++ b/drivers/net/ethernet/sun/sungem.c
|
|
@@ -59,8 +59,7 @@
|
|
#include <linux/sungem_phy.h>
|
|
#include "sungem.h"
|
|
|
|
-/* Stripping FCS is causing problems, disabled for now */
|
|
-#undef STRIP_FCS
|
|
+#define STRIP_FCS
|
|
|
|
#define DEFAULT_MSG (NETIF_MSG_DRV | \
|
|
NETIF_MSG_PROBE | \
|
|
@@ -434,7 +433,7 @@ static int gem_rxmac_reset(struct gem *gp)
|
|
writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW);
|
|
writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
|
|
val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
|
|
- ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128);
|
|
+ (ETH_HLEN << 13) | RXDMA_CFG_FTHRESH_128);
|
|
writel(val, gp->regs + RXDMA_CFG);
|
|
if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN)
|
|
writel(((5 & RXDMA_BLANK_IPKTS) |
|
|
@@ -759,7 +758,6 @@ static int gem_rx(struct gem *gp, int work_to_do)
|
|
struct net_device *dev = gp->dev;
|
|
int entry, drops, work_done = 0;
|
|
u32 done;
|
|
- __sum16 csum;
|
|
|
|
if (netif_msg_rx_status(gp))
|
|
printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n",
|
|
@@ -854,9 +852,13 @@ static int gem_rx(struct gem *gp, int work_to_do)
|
|
skb = copy_skb;
|
|
}
|
|
|
|
- csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff);
|
|
- skb->csum = csum_unfold(csum);
|
|
- skb->ip_summed = CHECKSUM_COMPLETE;
|
|
+ if (likely(dev->features & NETIF_F_RXCSUM)) {
|
|
+ __sum16 csum;
|
|
+
|
|
+ csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff);
|
|
+ skb->csum = csum_unfold(csum);
|
|
+ skb->ip_summed = CHECKSUM_COMPLETE;
|
|
+ }
|
|
skb->protocol = eth_type_trans(skb, gp->dev);
|
|
|
|
napi_gro_receive(&gp->napi, skb);
|
|
@@ -1760,7 +1762,7 @@ static void gem_init_dma(struct gem *gp)
|
|
writel(0, gp->regs + TXDMA_KICK);
|
|
|
|
val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
|
|
- ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128);
|
|
+ (ETH_HLEN << 13) | RXDMA_CFG_FTHRESH_128);
|
|
writel(val, gp->regs + RXDMA_CFG);
|
|
|
|
writel(desc_dma >> 32, gp->regs + RXDMA_DBHI);
|
|
@@ -2986,8 +2988,8 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
pci_set_drvdata(pdev, dev);
|
|
|
|
/* We can do scatter/gather and HW checksum */
|
|
- dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
|
|
- dev->features |= dev->hw_features | NETIF_F_RXCSUM;
|
|
+ dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
|
|
+ dev->features = dev->hw_features;
|
|
if (pci_using_dac)
|
|
dev->features |= NETIF_F_HIGHDMA;
|
|
|
|
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
|
|
index fbc825ac97ab..cb51448389a1 100644
|
|
--- a/drivers/net/geneve.c
|
|
+++ b/drivers/net/geneve.c
|
|
@@ -474,7 +474,7 @@ static struct sk_buff **geneve_gro_receive(struct sock *sk,
|
|
out_unlock:
|
|
rcu_read_unlock();
|
|
out:
|
|
- NAPI_GRO_CB(skb)->flush |= flush;
|
|
+ skb_gro_flush_final(skb, pp, flush);
|
|
|
|
return pp;
|
|
}
|
|
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
|
|
index 01017dd88802..cb250cacf721 100644
|
|
--- a/drivers/net/hyperv/hyperv_net.h
|
|
+++ b/drivers/net/hyperv/hyperv_net.h
|
|
@@ -207,7 +207,7 @@ int netvsc_recv_callback(struct net_device *net,
|
|
void netvsc_channel_cb(void *context);
|
|
int netvsc_poll(struct napi_struct *napi, int budget);
|
|
|
|
-void rndis_set_subchannel(struct work_struct *w);
|
|
+int rndis_set_subchannel(struct net_device *ndev, struct netvsc_device *nvdev);
|
|
int rndis_filter_open(struct netvsc_device *nvdev);
|
|
int rndis_filter_close(struct netvsc_device *nvdev);
|
|
struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
|
|
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
|
|
index 4647ecbe6f36..701be5d81062 100644
|
|
--- a/drivers/net/hyperv/netvsc.c
|
|
+++ b/drivers/net/hyperv/netvsc.c
|
|
@@ -62,6 +62,41 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf)
|
|
VM_PKT_DATA_INBAND, 0);
|
|
}
|
|
|
|
+/* Worker to setup sub channels on initial setup
|
|
+ * Initial hotplug event occurs in softirq context
|
|
+ * and can't wait for channels.
|
|
+ */
|
|
+static void netvsc_subchan_work(struct work_struct *w)
|
|
+{
|
|
+ struct netvsc_device *nvdev =
|
|
+ container_of(w, struct netvsc_device, subchan_work);
|
|
+ struct rndis_device *rdev;
|
|
+ int i, ret;
|
|
+
|
|
+ /* Avoid deadlock with device removal already under RTNL */
|
|
+ if (!rtnl_trylock()) {
|
|
+ schedule_work(w);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ rdev = nvdev->extension;
|
|
+ if (rdev) {
|
|
+ ret = rndis_set_subchannel(rdev->ndev, nvdev);
|
|
+ if (ret == 0) {
|
|
+ netif_device_attach(rdev->ndev);
|
|
+ } else {
|
|
+ /* fallback to only primary channel */
|
|
+ for (i = 1; i < nvdev->num_chn; i++)
|
|
+ netif_napi_del(&nvdev->chan_table[i].napi);
|
|
+
|
|
+ nvdev->max_chn = 1;
|
|
+ nvdev->num_chn = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ rtnl_unlock();
|
|
+}
|
|
+
|
|
static struct netvsc_device *alloc_net_device(void)
|
|
{
|
|
struct netvsc_device *net_device;
|
|
@@ -78,7 +113,7 @@ static struct netvsc_device *alloc_net_device(void)
|
|
|
|
init_completion(&net_device->channel_init_wait);
|
|
init_waitqueue_head(&net_device->subchan_open);
|
|
- INIT_WORK(&net_device->subchan_work, rndis_set_subchannel);
|
|
+ INIT_WORK(&net_device->subchan_work, netvsc_subchan_work);
|
|
|
|
return net_device;
|
|
}
|
|
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
|
|
index 6890478a0851..aeabeb107fed 100644
|
|
--- a/drivers/net/hyperv/netvsc_drv.c
|
|
+++ b/drivers/net/hyperv/netvsc_drv.c
|
|
@@ -911,8 +911,20 @@ static int netvsc_attach(struct net_device *ndev,
|
|
if (IS_ERR(nvdev))
|
|
return PTR_ERR(nvdev);
|
|
|
|
- /* Note: enable and attach happen when sub-channels setup */
|
|
+ if (nvdev->num_chn > 1) {
|
|
+ ret = rndis_set_subchannel(ndev, nvdev);
|
|
+
|
|
+ /* if unavailable, just proceed with one queue */
|
|
+ if (ret) {
|
|
+ nvdev->max_chn = 1;
|
|
+ nvdev->num_chn = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* In any case device is now ready */
|
|
+ netif_device_attach(ndev);
|
|
|
|
+ /* Note: enable and attach happen when sub-channels setup */
|
|
netif_carrier_off(ndev);
|
|
|
|
if (netif_running(ndev)) {
|
|
@@ -2035,6 +2047,9 @@ static int netvsc_probe(struct hv_device *dev,
|
|
|
|
memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
|
|
|
|
+ if (nvdev->num_chn > 1)
|
|
+ schedule_work(&nvdev->subchan_work);
|
|
+
|
|
/* hw_features computed in rndis_netdev_set_hwcaps() */
|
|
net->features = net->hw_features |
|
|
NETIF_F_HIGHDMA | NETIF_F_SG |
|
|
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
|
|
index d1ae184008b4..cb03a6ea076a 100644
|
|
--- a/drivers/net/hyperv/rndis_filter.c
|
|
+++ b/drivers/net/hyperv/rndis_filter.c
|
|
@@ -1055,29 +1055,15 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc)
|
|
* This breaks overlap of processing the host message for the
|
|
* new primary channel with the initialization of sub-channels.
|
|
*/
|
|
-void rndis_set_subchannel(struct work_struct *w)
|
|
+int rndis_set_subchannel(struct net_device *ndev, struct netvsc_device *nvdev)
|
|
{
|
|
- struct netvsc_device *nvdev
|
|
- = container_of(w, struct netvsc_device, subchan_work);
|
|
struct nvsp_message *init_packet = &nvdev->channel_init_pkt;
|
|
- struct net_device_context *ndev_ctx;
|
|
- struct rndis_device *rdev;
|
|
- struct net_device *ndev;
|
|
- struct hv_device *hv_dev;
|
|
+ struct net_device_context *ndev_ctx = netdev_priv(ndev);
|
|
+ struct hv_device *hv_dev = ndev_ctx->device_ctx;
|
|
+ struct rndis_device *rdev = nvdev->extension;
|
|
int i, ret;
|
|
|
|
- if (!rtnl_trylock()) {
|
|
- schedule_work(w);
|
|
- return;
|
|
- }
|
|
-
|
|
- rdev = nvdev->extension;
|
|
- if (!rdev)
|
|
- goto unlock; /* device was removed */
|
|
-
|
|
- ndev = rdev->ndev;
|
|
- ndev_ctx = netdev_priv(ndev);
|
|
- hv_dev = ndev_ctx->device_ctx;
|
|
+ ASSERT_RTNL();
|
|
|
|
memset(init_packet, 0, sizeof(struct nvsp_message));
|
|
init_packet->hdr.msg_type = NVSP_MSG5_TYPE_SUBCHANNEL;
|
|
@@ -1091,13 +1077,13 @@ void rndis_set_subchannel(struct work_struct *w)
|
|
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
|
|
if (ret) {
|
|
netdev_err(ndev, "sub channel allocate send failed: %d\n", ret);
|
|
- goto failed;
|
|
+ return ret;
|
|
}
|
|
|
|
wait_for_completion(&nvdev->channel_init_wait);
|
|
if (init_packet->msg.v5_msg.subchn_comp.status != NVSP_STAT_SUCCESS) {
|
|
netdev_err(ndev, "sub channel request failed\n");
|
|
- goto failed;
|
|
+ return -EIO;
|
|
}
|
|
|
|
nvdev->num_chn = 1 +
|
|
@@ -1116,21 +1102,7 @@ void rndis_set_subchannel(struct work_struct *w)
|
|
for (i = 0; i < VRSS_SEND_TAB_SIZE; i++)
|
|
ndev_ctx->tx_table[i] = i % nvdev->num_chn;
|
|
|
|
- netif_device_attach(ndev);
|
|
- rtnl_unlock();
|
|
- return;
|
|
-
|
|
-failed:
|
|
- /* fallback to only primary channel */
|
|
- for (i = 1; i < nvdev->num_chn; i++)
|
|
- netif_napi_del(&nvdev->chan_table[i].napi);
|
|
-
|
|
- nvdev->max_chn = 1;
|
|
- nvdev->num_chn = 1;
|
|
-
|
|
- netif_device_attach(ndev);
|
|
-unlock:
|
|
- rtnl_unlock();
|
|
+ return 0;
|
|
}
|
|
|
|
static int rndis_netdev_set_hwcaps(struct rndis_device *rndis_device,
|
|
@@ -1321,21 +1293,12 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
|
|
netif_napi_add(net, &net_device->chan_table[i].napi,
|
|
netvsc_poll, NAPI_POLL_WEIGHT);
|
|
|
|
- if (net_device->num_chn > 1)
|
|
- schedule_work(&net_device->subchan_work);
|
|
+ return net_device;
|
|
|
|
out:
|
|
- /* if unavailable, just proceed with one queue */
|
|
- if (ret) {
|
|
- net_device->max_chn = 1;
|
|
- net_device->num_chn = 1;
|
|
- }
|
|
-
|
|
- /* No sub channels, device is ready */
|
|
- if (net_device->num_chn == 1)
|
|
- netif_device_attach(net);
|
|
-
|
|
- return net_device;
|
|
+ /* setting up multiple channels failed */
|
|
+ net_device->max_chn = 1;
|
|
+ net_device->num_chn = 1;
|
|
|
|
err_dev_remv:
|
|
rndis_filter_device_remove(dev, net_device);
|
|
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
|
|
index c74893c1e620..e7f7a1a002ee 100644
|
|
--- a/drivers/net/ipvlan/ipvlan_main.c
|
|
+++ b/drivers/net/ipvlan/ipvlan_main.c
|
|
@@ -546,7 +546,8 @@ int ipvlan_link_new(struct net *src_net, struct net_device *dev,
|
|
ipvlan->dev = dev;
|
|
ipvlan->port = port;
|
|
ipvlan->sfeatures = IPVLAN_FEATURES;
|
|
- ipvlan_adjust_mtu(ipvlan, phy_dev);
|
|
+ if (!tb[IFLA_MTU])
|
|
+ ipvlan_adjust_mtu(ipvlan, phy_dev);
|
|
INIT_LIST_HEAD(&ipvlan->addrs);
|
|
|
|
/* If the port-id base is at the MAX value, then wrap it around and
|
|
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
|
|
index 9881edc568ba..0aa91ab9a0fb 100644
|
|
--- a/drivers/net/usb/lan78xx.c
|
|
+++ b/drivers/net/usb/lan78xx.c
|
|
@@ -3197,6 +3197,7 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev)
|
|
pkt_cnt = 0;
|
|
count = 0;
|
|
length = 0;
|
|
+ spin_lock_irqsave(&tqp->lock, flags);
|
|
for (skb = tqp->next; pkt_cnt < tqp->qlen; skb = skb->next) {
|
|
if (skb_is_gso(skb)) {
|
|
if (pkt_cnt) {
|
|
@@ -3205,7 +3206,8 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev)
|
|
}
|
|
count = 1;
|
|
length = skb->len - TX_OVERHEAD;
|
|
- skb2 = skb_dequeue(tqp);
|
|
+ __skb_unlink(skb, tqp);
|
|
+ spin_unlock_irqrestore(&tqp->lock, flags);
|
|
goto gso_skb;
|
|
}
|
|
|
|
@@ -3214,6 +3216,7 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev)
|
|
skb_totallen = skb->len + roundup(skb_totallen, sizeof(u32));
|
|
pkt_cnt++;
|
|
}
|
|
+ spin_unlock_irqrestore(&tqp->lock, flags);
|
|
|
|
/* copy to a single skb */
|
|
skb = alloc_skb(skb_totallen, GFP_ATOMIC);
|
|
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
|
|
index b23ee948e7c9..0db500bf86d9 100644
|
|
--- a/drivers/net/usb/qmi_wwan.c
|
|
+++ b/drivers/net/usb/qmi_wwan.c
|
|
@@ -1245,6 +1245,7 @@ static const struct usb_device_id products[] = {
|
|
{QMI_FIXED_INTF(0x413c, 0x81b3, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
|
|
{QMI_FIXED_INTF(0x413c, 0x81b6, 8)}, /* Dell Wireless 5811e */
|
|
{QMI_FIXED_INTF(0x413c, 0x81b6, 10)}, /* Dell Wireless 5811e */
|
|
+ {QMI_FIXED_INTF(0x413c, 0x81d7, 1)}, /* Dell Wireless 5821e */
|
|
{QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
|
|
{QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)}, /* HP lt4120 Snapdragon X5 LTE */
|
|
{QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */
|
|
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
|
|
index aa88b640cb6c..0fa64cc1a011 100644
|
|
--- a/drivers/net/usb/r8152.c
|
|
+++ b/drivers/net/usb/r8152.c
|
|
@@ -3959,7 +3959,8 @@ static int rtl8152_close(struct net_device *netdev)
|
|
#ifdef CONFIG_PM_SLEEP
|
|
unregister_pm_notifier(&tp->pm_notifier);
|
|
#endif
|
|
- napi_disable(&tp->napi);
|
|
+ if (!test_bit(RTL8152_UNPLUG, &tp->flags))
|
|
+ napi_disable(&tp->napi);
|
|
clear_bit(WORK_ENABLE, &tp->flags);
|
|
usb_kill_urb(tp->intr_urb);
|
|
cancel_delayed_work_sync(&tp->schedule);
|
|
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
|
|
index 3d9c5b35a4a7..bbdb46916dc3 100644
|
|
--- a/drivers/net/vxlan.c
|
|
+++ b/drivers/net/vxlan.c
|
|
@@ -623,9 +623,7 @@ static struct sk_buff **vxlan_gro_receive(struct sock *sk,
|
|
flush = 0;
|
|
|
|
out:
|
|
- skb_gro_remcsum_cleanup(skb, &grc);
|
|
- skb->remcsum_offload = 0;
|
|
- NAPI_GRO_CB(skb)->flush |= flush;
|
|
+ skb_gro_flush_final_remcsum(skb, pp, flush, &grc);
|
|
|
|
return pp;
|
|
}
|
|
diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c
|
|
index 93256f8bc0b5..ec82c1c3f12e 100644
|
|
--- a/drivers/net/wireless/realtek/rtlwifi/base.c
|
|
+++ b/drivers/net/wireless/realtek/rtlwifi/base.c
|
|
@@ -483,18 +483,21 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
|
|
|
|
}
|
|
|
|
-void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
|
|
+void rtl_deinit_deferred_work(struct ieee80211_hw *hw, bool ips_wq)
|
|
{
|
|
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
|
del_timer_sync(&rtlpriv->works.watchdog_timer);
|
|
|
|
- cancel_delayed_work(&rtlpriv->works.watchdog_wq);
|
|
- cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
|
|
- cancel_delayed_work(&rtlpriv->works.ps_work);
|
|
- cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
|
|
- cancel_delayed_work(&rtlpriv->works.fwevt_wq);
|
|
- cancel_delayed_work(&rtlpriv->works.c2hcmd_wq);
|
|
+ cancel_delayed_work_sync(&rtlpriv->works.watchdog_wq);
|
|
+ if (ips_wq)
|
|
+ cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
|
|
+ else
|
|
+ cancel_delayed_work_sync(&rtlpriv->works.ips_nic_off_wq);
|
|
+ cancel_delayed_work_sync(&rtlpriv->works.ps_work);
|
|
+ cancel_delayed_work_sync(&rtlpriv->works.ps_rfon_wq);
|
|
+ cancel_delayed_work_sync(&rtlpriv->works.fwevt_wq);
|
|
+ cancel_delayed_work_sync(&rtlpriv->works.c2hcmd_wq);
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtl_deinit_deferred_work);
|
|
|
|
diff --git a/drivers/net/wireless/realtek/rtlwifi/base.h b/drivers/net/wireless/realtek/rtlwifi/base.h
|
|
index b56d1b7f5567..cbbb5be36a09 100644
|
|
--- a/drivers/net/wireless/realtek/rtlwifi/base.h
|
|
+++ b/drivers/net/wireless/realtek/rtlwifi/base.h
|
|
@@ -121,7 +121,7 @@ void rtl_init_rfkill(struct ieee80211_hw *hw);
|
|
void rtl_deinit_rfkill(struct ieee80211_hw *hw);
|
|
|
|
void rtl_watch_dog_timer_callback(unsigned long data);
|
|
-void rtl_deinit_deferred_work(struct ieee80211_hw *hw);
|
|
+void rtl_deinit_deferred_work(struct ieee80211_hw *hw, bool ips_wq);
|
|
|
|
bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
|
|
int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht,
|
|
diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c
|
|
index c53cbf3d52bd..b01123138797 100644
|
|
--- a/drivers/net/wireless/realtek/rtlwifi/core.c
|
|
+++ b/drivers/net/wireless/realtek/rtlwifi/core.c
|
|
@@ -130,7 +130,6 @@ static void rtl_fw_do_work(const struct firmware *firmware, void *context,
|
|
firmware->size);
|
|
rtlpriv->rtlhal.wowlan_fwsize = firmware->size;
|
|
}
|
|
- rtlpriv->rtlhal.fwsize = firmware->size;
|
|
release_firmware(firmware);
|
|
}
|
|
|
|
@@ -196,7 +195,7 @@ static void rtl_op_stop(struct ieee80211_hw *hw)
|
|
/* reset sec info */
|
|
rtl_cam_reset_sec_info(hw);
|
|
|
|
- rtl_deinit_deferred_work(hw);
|
|
+ rtl_deinit_deferred_work(hw, false);
|
|
}
|
|
rtlpriv->intf_ops->adapter_stop(hw);
|
|
|
|
diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c
|
|
index d7331225c5f3..457a0f725c8a 100644
|
|
--- a/drivers/net/wireless/realtek/rtlwifi/pci.c
|
|
+++ b/drivers/net/wireless/realtek/rtlwifi/pci.c
|
|
@@ -2359,7 +2359,7 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
|
|
ieee80211_unregister_hw(hw);
|
|
rtlmac->mac80211_registered = 0;
|
|
} else {
|
|
- rtl_deinit_deferred_work(hw);
|
|
+ rtl_deinit_deferred_work(hw, false);
|
|
rtlpriv->intf_ops->adapter_stop(hw);
|
|
}
|
|
rtlpriv->cfg->ops->disable_interrupt(hw);
|
|
diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c
|
|
index 07ee3096f50e..f6d00613c53d 100644
|
|
--- a/drivers/net/wireless/realtek/rtlwifi/ps.c
|
|
+++ b/drivers/net/wireless/realtek/rtlwifi/ps.c
|
|
@@ -66,7 +66,7 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
|
|
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
|
/*<1> Stop all timer */
|
|
- rtl_deinit_deferred_work(hw);
|
|
+ rtl_deinit_deferred_work(hw, true);
|
|
|
|
/*<2> Disable Interrupt */
|
|
rtlpriv->cfg->ops->disable_interrupt(hw);
|
|
@@ -287,7 +287,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw)
|
|
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
|
|
enum rf_pwrstate rtstate;
|
|
|
|
- cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
|
|
+ cancel_delayed_work_sync(&rtlpriv->works.ips_nic_off_wq);
|
|
|
|
spin_lock(&rtlpriv->locks.ips_lock);
|
|
if (ppsc->inactiveps) {
|
|
diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c
|
|
index 5590d07d0918..820c42ff5384 100644
|
|
--- a/drivers/net/wireless/realtek/rtlwifi/usb.c
|
|
+++ b/drivers/net/wireless/realtek/rtlwifi/usb.c
|
|
@@ -1150,7 +1150,7 @@ void rtl_usb_disconnect(struct usb_interface *intf)
|
|
ieee80211_unregister_hw(hw);
|
|
rtlmac->mac80211_registered = 0;
|
|
} else {
|
|
- rtl_deinit_deferred_work(hw);
|
|
+ rtl_deinit_deferred_work(hw, false);
|
|
rtlpriv->intf_ops->adapter_stop(hw);
|
|
}
|
|
/*deinit rfkill */
|
|
diff --git a/drivers/pci/dwc/pci-exynos.c b/drivers/pci/dwc/pci-exynos.c
|
|
index 5596fdedbb94..ea03f1ec12a4 100644
|
|
--- a/drivers/pci/dwc/pci-exynos.c
|
|
+++ b/drivers/pci/dwc/pci-exynos.c
|
|
@@ -695,7 +695,8 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
|
|
return ret;
|
|
}
|
|
|
|
- if (ep->ops && ep->ops->get_clk_resources) {
|
|
+ if (ep->ops && ep->ops->get_clk_resources &&
|
|
+ ep->ops->init_clk_resources) {
|
|
ret = ep->ops->get_clk_resources(ep);
|
|
if (ret)
|
|
return ret;
|
|
diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c
|
|
index caea7c618207..4523d7e1bcb9 100644
|
|
--- a/drivers/pci/host/pci-hyperv.c
|
|
+++ b/drivers/pci/host/pci-hyperv.c
|
|
@@ -1091,6 +1091,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
|
struct pci_bus *pbus;
|
|
struct pci_dev *pdev;
|
|
struct cpumask *dest;
|
|
+ unsigned long flags;
|
|
struct compose_comp_ctxt comp;
|
|
struct tran_int_desc *int_desc;
|
|
struct {
|
|
@@ -1182,14 +1183,15 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
|
* the channel callback directly when channel->target_cpu is
|
|
* the current CPU. When the higher level interrupt code
|
|
* calls us with interrupt enabled, let's add the
|
|
- * local_bh_disable()/enable() to avoid race.
|
|
+ * local_irq_save()/restore() to avoid race:
|
|
+ * hv_pci_onchannelcallback() can also run in tasklet.
|
|
*/
|
|
- local_bh_disable();
|
|
+ local_irq_save(flags);
|
|
|
|
if (hbus->hdev->channel->target_cpu == smp_processor_id())
|
|
hv_pci_onchannelcallback(hbus);
|
|
|
|
- local_bh_enable();
|
|
+ local_irq_restore(flags);
|
|
|
|
if (hpdev->state == hv_pcichild_ejecting) {
|
|
dev_err_once(&hbus->hdev->device,
|
|
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
|
|
index 00b8d4cdcac3..c01d1f3a1c7d 100644
|
|
--- a/drivers/usb/host/xhci-hub.c
|
|
+++ b/drivers/usb/host/xhci-hub.c
|
|
@@ -366,7 +366,7 @@ int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
|
|
|
|
slot_id = 0;
|
|
for (i = 0; i < MAX_HC_SLOTS; i++) {
|
|
- if (!xhci->devs[i])
|
|
+ if (!xhci->devs[i] || !xhci->devs[i]->udev)
|
|
continue;
|
|
speed = xhci->devs[i]->udev->speed;
|
|
if (((speed >= USB_SPEED_SUPER) == (hcd->speed >= HCD_USB3))
|
|
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
|
|
index b0d606b2d06c..6123b4dd8638 100644
|
|
--- a/drivers/vhost/net.c
|
|
+++ b/drivers/vhost/net.c
|
|
@@ -1186,7 +1186,8 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
|
|
if (ubufs)
|
|
vhost_net_ubuf_put_wait_and_free(ubufs);
|
|
err_ubufs:
|
|
- sockfd_put(sock);
|
|
+ if (sock)
|
|
+ sockfd_put(sock);
|
|
err_vq:
|
|
mutex_unlock(&vq->mutex);
|
|
err:
|
|
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
|
|
index b7c816f39404..6dd63981787a 100644
|
|
--- a/fs/autofs4/dev-ioctl.c
|
|
+++ b/fs/autofs4/dev-ioctl.c
|
|
@@ -148,6 +148,15 @@ static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
|
|
cmd);
|
|
goto out;
|
|
}
|
|
+ } else {
|
|
+ unsigned int inr = _IOC_NR(cmd);
|
|
+
|
|
+ if (inr == AUTOFS_DEV_IOCTL_OPENMOUNT_CMD ||
|
|
+ inr == AUTOFS_DEV_IOCTL_REQUESTER_CMD ||
|
|
+ inr == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD) {
|
|
+ err = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
}
|
|
|
|
err = 0;
|
|
@@ -284,7 +293,8 @@ static int autofs_dev_ioctl_openmount(struct file *fp,
|
|
dev_t devid;
|
|
int err, fd;
|
|
|
|
- /* param->path has already been checked */
|
|
+ /* param->path has been checked in validate_dev_ioctl() */
|
|
+
|
|
if (!param->openmount.devid)
|
|
return -EINVAL;
|
|
|
|
@@ -446,10 +456,7 @@ static int autofs_dev_ioctl_requester(struct file *fp,
|
|
dev_t devid;
|
|
int err = -ENOENT;
|
|
|
|
- if (param->size <= AUTOFS_DEV_IOCTL_SIZE) {
|
|
- err = -EINVAL;
|
|
- goto out;
|
|
- }
|
|
+ /* param->path has been checked in validate_dev_ioctl() */
|
|
|
|
devid = sbi->sb->s_dev;
|
|
|
|
@@ -534,10 +541,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
|
|
unsigned int devid, magic;
|
|
int err = -ENOENT;
|
|
|
|
- if (param->size <= AUTOFS_DEV_IOCTL_SIZE) {
|
|
- err = -EINVAL;
|
|
- goto out;
|
|
- }
|
|
+ /* param->path has been checked in validate_dev_ioctl() */
|
|
|
|
name = param->path;
|
|
type = param->ismountpoint.in.type;
|
|
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
|
|
index fc4c14a72366..bf4e22df7c97 100644
|
|
--- a/fs/btrfs/tree-log.c
|
|
+++ b/fs/btrfs/tree-log.c
|
|
@@ -4214,6 +4214,110 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
|
|
return ret;
|
|
}
|
|
|
|
+/*
|
|
+ * Log all prealloc extents beyond the inode's i_size to make sure we do not
|
|
+ * lose them after doing a fast fsync and replaying the log. We scan the
|
|
+ * subvolume's root instead of iterating the inode's extent map tree because
|
|
+ * otherwise we can log incorrect extent items based on extent map conversion.
|
|
+ * That can happen due to the fact that extent maps are merged when they
|
|
+ * are not in the extent map tree's list of modified extents.
|
|
+ */
|
|
+static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans,
|
|
+ struct btrfs_inode *inode,
|
|
+ struct btrfs_path *path)
|
|
+{
|
|
+ struct btrfs_root *root = inode->root;
|
|
+ struct btrfs_key key;
|
|
+ const u64 i_size = i_size_read(&inode->vfs_inode);
|
|
+ const u64 ino = btrfs_ino(inode);
|
|
+ struct btrfs_path *dst_path = NULL;
|
|
+ u64 last_extent = (u64)-1;
|
|
+ int ins_nr = 0;
|
|
+ int start_slot;
|
|
+ int ret;
|
|
+
|
|
+ if (!(inode->flags & BTRFS_INODE_PREALLOC))
|
|
+ return 0;
|
|
+
|
|
+ key.objectid = ino;
|
|
+ key.type = BTRFS_EXTENT_DATA_KEY;
|
|
+ key.offset = i_size;
|
|
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+
|
|
+ while (true) {
|
|
+ struct extent_buffer *leaf = path->nodes[0];
|
|
+ int slot = path->slots[0];
|
|
+
|
|
+ if (slot >= btrfs_header_nritems(leaf)) {
|
|
+ if (ins_nr > 0) {
|
|
+ ret = copy_items(trans, inode, dst_path, path,
|
|
+ &last_extent, start_slot,
|
|
+ ins_nr, 1, 0);
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+ ins_nr = 0;
|
|
+ }
|
|
+ ret = btrfs_next_leaf(root, path);
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+ if (ret > 0) {
|
|
+ ret = 0;
|
|
+ break;
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ btrfs_item_key_to_cpu(leaf, &key, slot);
|
|
+ if (key.objectid > ino)
|
|
+ break;
|
|
+ if (WARN_ON_ONCE(key.objectid < ino) ||
|
|
+ key.type < BTRFS_EXTENT_DATA_KEY ||
|
|
+ key.offset < i_size) {
|
|
+ path->slots[0]++;
|
|
+ continue;
|
|
+ }
|
|
+ if (last_extent == (u64)-1) {
|
|
+ last_extent = key.offset;
|
|
+ /*
|
|
+ * Avoid logging extent items logged in past fsync calls
|
|
+ * and leading to duplicate keys in the log tree.
|
|
+ */
|
|
+ do {
|
|
+ ret = btrfs_truncate_inode_items(trans,
|
|
+ root->log_root,
|
|
+ &inode->vfs_inode,
|
|
+ i_size,
|
|
+ BTRFS_EXTENT_DATA_KEY);
|
|
+ } while (ret == -EAGAIN);
|
|
+ if (ret)
|
|
+ goto out;
|
|
+ }
|
|
+ if (ins_nr == 0)
|
|
+ start_slot = slot;
|
|
+ ins_nr++;
|
|
+ path->slots[0]++;
|
|
+ if (!dst_path) {
|
|
+ dst_path = btrfs_alloc_path();
|
|
+ if (!dst_path) {
|
|
+ ret = -ENOMEM;
|
|
+ goto out;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (ins_nr > 0) {
|
|
+ ret = copy_items(trans, inode, dst_path, path, &last_extent,
|
|
+ start_slot, ins_nr, 1, 0);
|
|
+ if (ret > 0)
|
|
+ ret = 0;
|
|
+ }
|
|
+out:
|
|
+ btrfs_release_path(path);
|
|
+ btrfs_free_path(dst_path);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
|
|
struct btrfs_root *root,
|
|
struct btrfs_inode *inode,
|
|
@@ -4256,6 +4360,11 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
|
|
if (em->generation <= test_gen)
|
|
continue;
|
|
|
|
+ /* We log prealloc extents beyond eof later. */
|
|
+ if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags) &&
|
|
+ em->start >= i_size_read(&inode->vfs_inode))
|
|
+ continue;
|
|
+
|
|
if (em->start < logged_start)
|
|
logged_start = em->start;
|
|
if ((em->start + em->len - 1) > logged_end)
|
|
@@ -4268,31 +4377,6 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
|
|
num++;
|
|
}
|
|
|
|
- /*
|
|
- * Add all prealloc extents beyond the inode's i_size to make sure we
|
|
- * don't lose them after doing a fast fsync and replaying the log.
|
|
- */
|
|
- if (inode->flags & BTRFS_INODE_PREALLOC) {
|
|
- struct rb_node *node;
|
|
-
|
|
- for (node = rb_last(&tree->map); node; node = rb_prev(node)) {
|
|
- em = rb_entry(node, struct extent_map, rb_node);
|
|
- if (em->start < i_size_read(&inode->vfs_inode))
|
|
- break;
|
|
- if (!list_empty(&em->list))
|
|
- continue;
|
|
- /* Same as above loop. */
|
|
- if (++num > 32768) {
|
|
- list_del_init(&tree->modified_extents);
|
|
- ret = -EFBIG;
|
|
- goto process;
|
|
- }
|
|
- refcount_inc(&em->refs);
|
|
- set_bit(EXTENT_FLAG_LOGGING, &em->flags);
|
|
- list_add_tail(&em->list, &extents);
|
|
- }
|
|
- }
|
|
-
|
|
list_sort(NULL, &extents, extent_cmp);
|
|
btrfs_get_logged_extents(inode, logged_list, logged_start, logged_end);
|
|
/*
|
|
@@ -4337,6 +4421,9 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
|
|
up_write(&inode->dio_sem);
|
|
|
|
btrfs_release_path(path);
|
|
+ if (!ret)
|
|
+ ret = btrfs_log_prealloc_extents(trans, inode, path);
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
|
|
index 88a31e9340a0..d1516327b787 100644
|
|
--- a/fs/ocfs2/aops.c
|
|
+++ b/fs/ocfs2/aops.c
|
|
@@ -134,6 +134,19 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
|
|
return err;
|
|
}
|
|
|
|
+static int ocfs2_lock_get_block(struct inode *inode, sector_t iblock,
|
|
+ struct buffer_head *bh_result, int create)
|
|
+{
|
|
+ int ret = 0;
|
|
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
|
|
+
|
|
+ down_read(&oi->ip_alloc_sem);
|
|
+ ret = ocfs2_get_block(inode, iblock, bh_result, create);
|
|
+ up_read(&oi->ip_alloc_sem);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
int ocfs2_get_block(struct inode *inode, sector_t iblock,
|
|
struct buffer_head *bh_result, int create)
|
|
{
|
|
@@ -2128,7 +2141,7 @@ static void ocfs2_dio_free_write_ctx(struct inode *inode,
|
|
* called like this: dio->get_blocks(dio->inode, fs_startblk,
|
|
* fs_count, map_bh, dio->rw == WRITE);
|
|
*/
|
|
-static int ocfs2_dio_get_block(struct inode *inode, sector_t iblock,
|
|
+static int ocfs2_dio_wr_get_block(struct inode *inode, sector_t iblock,
|
|
struct buffer_head *bh_result, int create)
|
|
{
|
|
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
|
@@ -2154,12 +2167,9 @@ static int ocfs2_dio_get_block(struct inode *inode, sector_t iblock,
|
|
* while file size will be changed.
|
|
*/
|
|
if (pos + total_len <= i_size_read(inode)) {
|
|
- down_read(&oi->ip_alloc_sem);
|
|
- /* This is the fast path for re-write. */
|
|
- ret = ocfs2_get_block(inode, iblock, bh_result, create);
|
|
-
|
|
- up_read(&oi->ip_alloc_sem);
|
|
|
|
+ /* This is the fast path for re-write. */
|
|
+ ret = ocfs2_lock_get_block(inode, iblock, bh_result, create);
|
|
if (buffer_mapped(bh_result) &&
|
|
!buffer_new(bh_result) &&
|
|
ret == 0)
|
|
@@ -2424,9 +2434,9 @@ static ssize_t ocfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
|
return 0;
|
|
|
|
if (iov_iter_rw(iter) == READ)
|
|
- get_block = ocfs2_get_block;
|
|
+ get_block = ocfs2_lock_get_block;
|
|
else
|
|
- get_block = ocfs2_dio_get_block;
|
|
+ get_block = ocfs2_dio_wr_get_block;
|
|
|
|
return __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev,
|
|
iter, get_block,
|
|
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
|
|
index b17d180bdc16..c204ac9b49e5 100644
|
|
--- a/fs/ocfs2/cluster/nodemanager.c
|
|
+++ b/fs/ocfs2/cluster/nodemanager.c
|
|
@@ -40,6 +40,9 @@ char *o2nm_fence_method_desc[O2NM_FENCE_METHODS] = {
|
|
"panic", /* O2NM_FENCE_PANIC */
|
|
};
|
|
|
|
+static inline void o2nm_lock_subsystem(void);
|
|
+static inline void o2nm_unlock_subsystem(void);
|
|
+
|
|
struct o2nm_node *o2nm_get_node_by_num(u8 node_num)
|
|
{
|
|
struct o2nm_node *node = NULL;
|
|
@@ -181,7 +184,10 @@ static struct o2nm_cluster *to_o2nm_cluster_from_node(struct o2nm_node *node)
|
|
{
|
|
/* through the first node_set .parent
|
|
* mycluster/nodes/mynode == o2nm_cluster->o2nm_node_group->o2nm_node */
|
|
- return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent);
|
|
+ if (node->nd_item.ci_parent)
|
|
+ return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent);
|
|
+ else
|
|
+ return NULL;
|
|
}
|
|
|
|
enum {
|
|
@@ -194,7 +200,7 @@ static ssize_t o2nm_node_num_store(struct config_item *item, const char *page,
|
|
size_t count)
|
|
{
|
|
struct o2nm_node *node = to_o2nm_node(item);
|
|
- struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
|
|
+ struct o2nm_cluster *cluster;
|
|
unsigned long tmp;
|
|
char *p = (char *)page;
|
|
int ret = 0;
|
|
@@ -214,6 +220,13 @@ static ssize_t o2nm_node_num_store(struct config_item *item, const char *page,
|
|
!test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
|
|
return -EINVAL; /* XXX */
|
|
|
|
+ o2nm_lock_subsystem();
|
|
+ cluster = to_o2nm_cluster_from_node(node);
|
|
+ if (!cluster) {
|
|
+ o2nm_unlock_subsystem();
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
write_lock(&cluster->cl_nodes_lock);
|
|
if (cluster->cl_nodes[tmp])
|
|
ret = -EEXIST;
|
|
@@ -226,6 +239,8 @@ static ssize_t o2nm_node_num_store(struct config_item *item, const char *page,
|
|
set_bit(tmp, cluster->cl_nodes_bitmap);
|
|
}
|
|
write_unlock(&cluster->cl_nodes_lock);
|
|
+ o2nm_unlock_subsystem();
|
|
+
|
|
if (ret)
|
|
return ret;
|
|
|
|
@@ -269,7 +284,7 @@ static ssize_t o2nm_node_ipv4_address_store(struct config_item *item,
|
|
size_t count)
|
|
{
|
|
struct o2nm_node *node = to_o2nm_node(item);
|
|
- struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
|
|
+ struct o2nm_cluster *cluster;
|
|
int ret, i;
|
|
struct rb_node **p, *parent;
|
|
unsigned int octets[4];
|
|
@@ -286,6 +301,13 @@ static ssize_t o2nm_node_ipv4_address_store(struct config_item *item,
|
|
be32_add_cpu(&ipv4_addr, octets[i] << (i * 8));
|
|
}
|
|
|
|
+ o2nm_lock_subsystem();
|
|
+ cluster = to_o2nm_cluster_from_node(node);
|
|
+ if (!cluster) {
|
|
+ o2nm_unlock_subsystem();
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
ret = 0;
|
|
write_lock(&cluster->cl_nodes_lock);
|
|
if (o2nm_node_ip_tree_lookup(cluster, ipv4_addr, &p, &parent))
|
|
@@ -298,6 +320,8 @@ static ssize_t o2nm_node_ipv4_address_store(struct config_item *item,
|
|
rb_insert_color(&node->nd_ip_node, &cluster->cl_node_ip_tree);
|
|
}
|
|
write_unlock(&cluster->cl_nodes_lock);
|
|
+ o2nm_unlock_subsystem();
|
|
+
|
|
if (ret)
|
|
return ret;
|
|
|
|
@@ -315,7 +339,7 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page,
|
|
size_t count)
|
|
{
|
|
struct o2nm_node *node = to_o2nm_node(item);
|
|
- struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
|
|
+ struct o2nm_cluster *cluster;
|
|
unsigned long tmp;
|
|
char *p = (char *)page;
|
|
ssize_t ret;
|
|
@@ -333,17 +357,26 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page,
|
|
!test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
|
|
return -EINVAL; /* XXX */
|
|
|
|
+ o2nm_lock_subsystem();
|
|
+ cluster = to_o2nm_cluster_from_node(node);
|
|
+ if (!cluster) {
|
|
+ ret = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
/* the only failure case is trying to set a new local node
|
|
* when a different one is already set */
|
|
if (tmp && tmp == cluster->cl_has_local &&
|
|
- cluster->cl_local_node != node->nd_num)
|
|
- return -EBUSY;
|
|
+ cluster->cl_local_node != node->nd_num) {
|
|
+ ret = -EBUSY;
|
|
+ goto out;
|
|
+ }
|
|
|
|
/* bring up the rx thread if we're setting the new local node. */
|
|
if (tmp && !cluster->cl_has_local) {
|
|
ret = o2net_start_listening(node);
|
|
if (ret)
|
|
- return ret;
|
|
+ goto out;
|
|
}
|
|
|
|
if (!tmp && cluster->cl_has_local &&
|
|
@@ -358,7 +391,11 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page,
|
|
cluster->cl_local_node = node->nd_num;
|
|
}
|
|
|
|
- return count;
|
|
+ ret = count;
|
|
+
|
|
+out:
|
|
+ o2nm_unlock_subsystem();
|
|
+ return ret;
|
|
}
|
|
|
|
CONFIGFS_ATTR(o2nm_node_, num);
|
|
@@ -738,6 +775,16 @@ static struct o2nm_cluster_group o2nm_cluster_group = {
|
|
},
|
|
};
|
|
|
|
+static inline void o2nm_lock_subsystem(void)
|
|
+{
|
|
+ mutex_lock(&o2nm_cluster_group.cs_subsys.su_mutex);
|
|
+}
|
|
+
|
|
+static inline void o2nm_unlock_subsystem(void)
|
|
+{
|
|
+ mutex_unlock(&o2nm_cluster_group.cs_subsys.su_mutex);
|
|
+}
|
|
+
|
|
int o2nm_depend_item(struct config_item *item)
|
|
{
|
|
return configfs_depend_item(&o2nm_cluster_group.cs_subsys, item);
|
|
diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
|
|
index 64f49cafbc5b..cfb0c9ac2de4 100644
|
|
--- a/fs/reiserfs/prints.c
|
|
+++ b/fs/reiserfs/prints.c
|
|
@@ -76,83 +76,99 @@ static char *le_type(struct reiserfs_key *key)
|
|
}
|
|
|
|
/* %k */
|
|
-static void sprintf_le_key(char *buf, struct reiserfs_key *key)
|
|
+static int scnprintf_le_key(char *buf, size_t size, struct reiserfs_key *key)
|
|
{
|
|
if (key)
|
|
- sprintf(buf, "[%d %d %s %s]", le32_to_cpu(key->k_dir_id),
|
|
- le32_to_cpu(key->k_objectid), le_offset(key),
|
|
- le_type(key));
|
|
+ return scnprintf(buf, size, "[%d %d %s %s]",
|
|
+ le32_to_cpu(key->k_dir_id),
|
|
+ le32_to_cpu(key->k_objectid), le_offset(key),
|
|
+ le_type(key));
|
|
else
|
|
- sprintf(buf, "[NULL]");
|
|
+ return scnprintf(buf, size, "[NULL]");
|
|
}
|
|
|
|
/* %K */
|
|
-static void sprintf_cpu_key(char *buf, struct cpu_key *key)
|
|
+static int scnprintf_cpu_key(char *buf, size_t size, struct cpu_key *key)
|
|
{
|
|
if (key)
|
|
- sprintf(buf, "[%d %d %s %s]", key->on_disk_key.k_dir_id,
|
|
- key->on_disk_key.k_objectid, reiserfs_cpu_offset(key),
|
|
- cpu_type(key));
|
|
+ return scnprintf(buf, size, "[%d %d %s %s]",
|
|
+ key->on_disk_key.k_dir_id,
|
|
+ key->on_disk_key.k_objectid,
|
|
+ reiserfs_cpu_offset(key), cpu_type(key));
|
|
else
|
|
- sprintf(buf, "[NULL]");
|
|
+ return scnprintf(buf, size, "[NULL]");
|
|
}
|
|
|
|
-static void sprintf_de_head(char *buf, struct reiserfs_de_head *deh)
|
|
+static int scnprintf_de_head(char *buf, size_t size,
|
|
+ struct reiserfs_de_head *deh)
|
|
{
|
|
if (deh)
|
|
- sprintf(buf,
|
|
- "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]",
|
|
- deh_offset(deh), deh_dir_id(deh), deh_objectid(deh),
|
|
- deh_location(deh), deh_state(deh));
|
|
+ return scnprintf(buf, size,
|
|
+ "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]",
|
|
+ deh_offset(deh), deh_dir_id(deh),
|
|
+ deh_objectid(deh), deh_location(deh),
|
|
+ deh_state(deh));
|
|
else
|
|
- sprintf(buf, "[NULL]");
|
|
+ return scnprintf(buf, size, "[NULL]");
|
|
|
|
}
|
|
|
|
-static void sprintf_item_head(char *buf, struct item_head *ih)
|
|
+static int scnprintf_item_head(char *buf, size_t size, struct item_head *ih)
|
|
{
|
|
if (ih) {
|
|
- strcpy(buf,
|
|
- (ih_version(ih) == KEY_FORMAT_3_6) ? "*3.6* " : "*3.5*");
|
|
- sprintf_le_key(buf + strlen(buf), &(ih->ih_key));
|
|
- sprintf(buf + strlen(buf), ", item_len %d, item_location %d, "
|
|
- "free_space(entry_count) %d",
|
|
- ih_item_len(ih), ih_location(ih), ih_free_space(ih));
|
|
+ char *p = buf;
|
|
+ char * const end = buf + size;
|
|
+
|
|
+ p += scnprintf(p, end - p, "%s",
|
|
+ (ih_version(ih) == KEY_FORMAT_3_6) ?
|
|
+ "*3.6* " : "*3.5*");
|
|
+
|
|
+ p += scnprintf_le_key(p, end - p, &ih->ih_key);
|
|
+
|
|
+ p += scnprintf(p, end - p,
|
|
+ ", item_len %d, item_location %d, free_space(entry_count) %d",
|
|
+ ih_item_len(ih), ih_location(ih),
|
|
+ ih_free_space(ih));
|
|
+ return p - buf;
|
|
} else
|
|
- sprintf(buf, "[NULL]");
|
|
+ return scnprintf(buf, size, "[NULL]");
|
|
}
|
|
|
|
-static void sprintf_direntry(char *buf, struct reiserfs_dir_entry *de)
|
|
+static int scnprintf_direntry(char *buf, size_t size,
|
|
+ struct reiserfs_dir_entry *de)
|
|
{
|
|
char name[20];
|
|
|
|
memcpy(name, de->de_name, de->de_namelen > 19 ? 19 : de->de_namelen);
|
|
name[de->de_namelen > 19 ? 19 : de->de_namelen] = 0;
|
|
- sprintf(buf, "\"%s\"==>[%d %d]", name, de->de_dir_id, de->de_objectid);
|
|
+ return scnprintf(buf, size, "\"%s\"==>[%d %d]",
|
|
+ name, de->de_dir_id, de->de_objectid);
|
|
}
|
|
|
|
-static void sprintf_block_head(char *buf, struct buffer_head *bh)
|
|
+static int scnprintf_block_head(char *buf, size_t size, struct buffer_head *bh)
|
|
{
|
|
- sprintf(buf, "level=%d, nr_items=%d, free_space=%d rdkey ",
|
|
- B_LEVEL(bh), B_NR_ITEMS(bh), B_FREE_SPACE(bh));
|
|
+ return scnprintf(buf, size,
|
|
+ "level=%d, nr_items=%d, free_space=%d rdkey ",
|
|
+ B_LEVEL(bh), B_NR_ITEMS(bh), B_FREE_SPACE(bh));
|
|
}
|
|
|
|
-static void sprintf_buffer_head(char *buf, struct buffer_head *bh)
|
|
+static int scnprintf_buffer_head(char *buf, size_t size, struct buffer_head *bh)
|
|
{
|
|
- sprintf(buf,
|
|
- "dev %pg, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)",
|
|
- bh->b_bdev, bh->b_size,
|
|
- (unsigned long long)bh->b_blocknr, atomic_read(&(bh->b_count)),
|
|
- bh->b_state, bh->b_page,
|
|
- buffer_uptodate(bh) ? "UPTODATE" : "!UPTODATE",
|
|
- buffer_dirty(bh) ? "DIRTY" : "CLEAN",
|
|
- buffer_locked(bh) ? "LOCKED" : "UNLOCKED");
|
|
+ return scnprintf(buf, size,
|
|
+ "dev %pg, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)",
|
|
+ bh->b_bdev, bh->b_size,
|
|
+ (unsigned long long)bh->b_blocknr,
|
|
+ atomic_read(&(bh->b_count)),
|
|
+ bh->b_state, bh->b_page,
|
|
+ buffer_uptodate(bh) ? "UPTODATE" : "!UPTODATE",
|
|
+ buffer_dirty(bh) ? "DIRTY" : "CLEAN",
|
|
+ buffer_locked(bh) ? "LOCKED" : "UNLOCKED");
|
|
}
|
|
|
|
-static void sprintf_disk_child(char *buf, struct disk_child *dc)
|
|
+static int scnprintf_disk_child(char *buf, size_t size, struct disk_child *dc)
|
|
{
|
|
- sprintf(buf, "[dc_number=%d, dc_size=%u]", dc_block_number(dc),
|
|
- dc_size(dc));
|
|
+ return scnprintf(buf, size, "[dc_number=%d, dc_size=%u]",
|
|
+ dc_block_number(dc), dc_size(dc));
|
|
}
|
|
|
|
static char *is_there_reiserfs_struct(char *fmt, int *what)
|
|
@@ -189,55 +205,60 @@ static void prepare_error_buf(const char *fmt, va_list args)
|
|
char *fmt1 = fmt_buf;
|
|
char *k;
|
|
char *p = error_buf;
|
|
+ char * const end = &error_buf[sizeof(error_buf)];
|
|
int what;
|
|
|
|
spin_lock(&error_lock);
|
|
|
|
- strcpy(fmt1, fmt);
|
|
+ if (WARN_ON(strscpy(fmt_buf, fmt, sizeof(fmt_buf)) < 0)) {
|
|
+ strscpy(error_buf, "format string too long", end - error_buf);
|
|
+ goto out_unlock;
|
|
+ }
|
|
|
|
while ((k = is_there_reiserfs_struct(fmt1, &what)) != NULL) {
|
|
*k = 0;
|
|
|
|
- p += vsprintf(p, fmt1, args);
|
|
+ p += vscnprintf(p, end - p, fmt1, args);
|
|
|
|
switch (what) {
|
|
case 'k':
|
|
- sprintf_le_key(p, va_arg(args, struct reiserfs_key *));
|
|
+ p += scnprintf_le_key(p, end - p,
|
|
+ va_arg(args, struct reiserfs_key *));
|
|
break;
|
|
case 'K':
|
|
- sprintf_cpu_key(p, va_arg(args, struct cpu_key *));
|
|
+ p += scnprintf_cpu_key(p, end - p,
|
|
+ va_arg(args, struct cpu_key *));
|
|
break;
|
|
case 'h':
|
|
- sprintf_item_head(p, va_arg(args, struct item_head *));
|
|
+ p += scnprintf_item_head(p, end - p,
|
|
+ va_arg(args, struct item_head *));
|
|
break;
|
|
case 't':
|
|
- sprintf_direntry(p,
|
|
- va_arg(args,
|
|
- struct reiserfs_dir_entry *));
|
|
+ p += scnprintf_direntry(p, end - p,
|
|
+ va_arg(args, struct reiserfs_dir_entry *));
|
|
break;
|
|
case 'y':
|
|
- sprintf_disk_child(p,
|
|
- va_arg(args, struct disk_child *));
|
|
+ p += scnprintf_disk_child(p, end - p,
|
|
+ va_arg(args, struct disk_child *));
|
|
break;
|
|
case 'z':
|
|
- sprintf_block_head(p,
|
|
- va_arg(args, struct buffer_head *));
|
|
+ p += scnprintf_block_head(p, end - p,
|
|
+ va_arg(args, struct buffer_head *));
|
|
break;
|
|
case 'b':
|
|
- sprintf_buffer_head(p,
|
|
- va_arg(args, struct buffer_head *));
|
|
+ p += scnprintf_buffer_head(p, end - p,
|
|
+ va_arg(args, struct buffer_head *));
|
|
break;
|
|
case 'a':
|
|
- sprintf_de_head(p,
|
|
- va_arg(args,
|
|
- struct reiserfs_de_head *));
|
|
+ p += scnprintf_de_head(p, end - p,
|
|
+ va_arg(args, struct reiserfs_de_head *));
|
|
break;
|
|
}
|
|
|
|
- p += strlen(p);
|
|
fmt1 = k + 2;
|
|
}
|
|
- vsprintf(p, fmt1, args);
|
|
+ p += vscnprintf(p, end - p, fmt1, args);
|
|
+out_unlock:
|
|
spin_unlock(&error_lock);
|
|
|
|
}
|
|
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
|
|
index a031897fca76..ca1d2cc2cdfa 100644
|
|
--- a/include/linux/arm-smccc.h
|
|
+++ b/include/linux/arm-smccc.h
|
|
@@ -80,6 +80,11 @@
|
|
ARM_SMCCC_SMC_32, \
|
|
0, 0x8000)
|
|
|
|
+#define ARM_SMCCC_ARCH_WORKAROUND_2 \
|
|
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
|
|
+ ARM_SMCCC_SMC_32, \
|
|
+ 0, 0x7fff)
|
|
+
|
|
#ifndef __ASSEMBLY__
|
|
|
|
#include <linux/linkage.h>
|
|
@@ -291,5 +296,10 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
|
|
*/
|
|
#define arm_smccc_1_1_hvc(...) __arm_smccc_1_1(SMCCC_HVC_INST, __VA_ARGS__)
|
|
|
|
+/* Return codes defined in ARM DEN 0070A */
|
|
+#define SMCCC_RET_SUCCESS 0
|
|
+#define SMCCC_RET_NOT_SUPPORTED -1
|
|
+#define SMCCC_RET_NOT_REQUIRED -2
|
|
+
|
|
#endif /*__ASSEMBLY__*/
|
|
#endif /*__LINUX_ARM_SMCCC_H*/
|
|
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
|
|
index 0c27515d2cf6..8124815eb121 100644
|
|
--- a/include/linux/atmdev.h
|
|
+++ b/include/linux/atmdev.h
|
|
@@ -214,6 +214,7 @@ struct atmphy_ops {
|
|
struct atm_skb_data {
|
|
struct atm_vcc *vcc; /* ATM VCC */
|
|
unsigned long atm_options; /* ATM layer options */
|
|
+ unsigned int acct_truesize; /* truesize accounted to vcc */
|
|
};
|
|
|
|
#define VCC_HTABLE_SIZE 32
|
|
@@ -241,6 +242,20 @@ void vcc_insert_socket(struct sock *sk);
|
|
|
|
void atm_dev_release_vccs(struct atm_dev *dev);
|
|
|
|
+static inline void atm_account_tx(struct atm_vcc *vcc, struct sk_buff *skb)
|
|
+{
|
|
+ /*
|
|
+ * Because ATM skbs may not belong to a sock (and we don't
|
|
+ * necessarily want to), skb->truesize may be adjusted,
|
|
+ * escaping the hack in pskb_expand_head() which avoids
|
|
+ * doing so for some cases. So stash the value of truesize
|
|
+ * at the time we accounted it, and atm_pop_raw() can use
|
|
+ * that value later, in case it changes.
|
|
+ */
|
|
+ refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
|
|
+ ATM_SKB(skb)->acct_truesize = skb->truesize;
|
|
+ ATM_SKB(skb)->atm_options = vcc->atm_options;
|
|
+}
|
|
|
|
static inline void atm_force_charge(struct atm_vcc *vcc,int truesize)
|
|
{
|
|
diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h
|
|
index eac387a3bfef..3c1beffc861a 100644
|
|
--- a/include/linux/backing-dev-defs.h
|
|
+++ b/include/linux/backing-dev-defs.h
|
|
@@ -22,7 +22,6 @@ struct dentry;
|
|
*/
|
|
enum wb_state {
|
|
WB_registered, /* bdi_register() was done */
|
|
- WB_shutting_down, /* wb_shutdown() in progress */
|
|
WB_writeback_running, /* Writeback is in progress */
|
|
WB_has_dirty_io, /* Dirty inodes on ->b_{dirty|io|more_io} */
|
|
};
|
|
@@ -165,6 +164,7 @@ struct backing_dev_info {
|
|
#ifdef CONFIG_CGROUP_WRITEBACK
|
|
struct radix_tree_root cgwb_tree; /* radix tree of active cgroup wbs */
|
|
struct rb_root cgwb_congested_tree; /* their congested states */
|
|
+ struct mutex cgwb_release_mutex; /* protect shutdown of wb structs */
|
|
#else
|
|
struct bdi_writeback_congested *wb_congested;
|
|
#endif
|
|
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
|
|
index f43113b8890b..c11032b06d68 100644
|
|
--- a/include/linux/compiler-gcc.h
|
|
+++ b/include/linux/compiler-gcc.h
|
|
@@ -65,6 +65,18 @@
|
|
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
|
|
#endif
|
|
|
|
+/*
|
|
+ * Feature detection for gnu_inline (gnu89 extern inline semantics). Either
|
|
+ * __GNUC_STDC_INLINE__ is defined (not using gnu89 extern inline semantics,
|
|
+ * and we opt in to the gnu89 semantics), or __GNUC_STDC_INLINE__ is not
|
|
+ * defined so the gnu89 semantics are the default.
|
|
+ */
|
|
+#ifdef __GNUC_STDC_INLINE__
|
|
+# define __gnu_inline __attribute__((gnu_inline))
|
|
+#else
|
|
+# define __gnu_inline
|
|
+#endif
|
|
+
|
|
/*
|
|
* Force always-inline if the user requests it so via the .config,
|
|
* or if gcc is too old.
|
|
@@ -72,19 +84,22 @@
|
|
* -Wunused-function. This turns out to avoid the need for complex #ifdef
|
|
* directives. Suppress the warning in clang as well by using "unused"
|
|
* function attribute, which is redundant but not harmful for gcc.
|
|
+ * Prefer gnu_inline, so that extern inline functions do not emit an
|
|
+ * externally visible function. This makes extern inline behave as per gnu89
|
|
+ * semantics rather than c99. This prevents multiple symbol definition errors
|
|
+ * of extern inline functions at link time.
|
|
+ * A lot of inline functions can cause havoc with function tracing.
|
|
*/
|
|
#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) || \
|
|
!defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4)
|
|
-#define inline inline __attribute__((always_inline,unused)) notrace
|
|
-#define __inline__ __inline__ __attribute__((always_inline,unused)) notrace
|
|
-#define __inline __inline __attribute__((always_inline,unused)) notrace
|
|
+#define inline \
|
|
+ inline __attribute__((always_inline, unused)) notrace __gnu_inline
|
|
#else
|
|
-/* A lot of inline functions can cause havoc with function tracing */
|
|
-#define inline inline __attribute__((unused)) notrace
|
|
-#define __inline__ __inline__ __attribute__((unused)) notrace
|
|
-#define __inline __inline __attribute__((unused)) notrace
|
|
+#define inline inline __attribute__((unused)) notrace __gnu_inline
|
|
#endif
|
|
|
|
+#define __inline__ inline
|
|
+#define __inline inline
|
|
#define __always_inline inline __attribute__((always_inline))
|
|
#define noinline __attribute__((noinline))
|
|
|
|
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
|
|
index f3765155fa4d..1d793d86d55f 100644
|
|
--- a/include/linux/mlx5/mlx5_ifc.h
|
|
+++ b/include/linux/mlx5/mlx5_ifc.h
|
|
@@ -857,7 +857,7 @@ struct mlx5_ifc_cmd_hca_cap_bits {
|
|
u8 reserved_at_1a4[0x1];
|
|
u8 ets[0x1];
|
|
u8 nic_flow_table[0x1];
|
|
- u8 eswitch_flow_table[0x1];
|
|
+ u8 eswitch_manager[0x1];
|
|
u8 early_vf_enable[0x1];
|
|
u8 mcam_reg[0x1];
|
|
u8 pcam_reg[0x1];
|
|
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
|
|
index 46bf7cc7d5d5..2ea7ee1fb495 100644
|
|
--- a/include/linux/netdevice.h
|
|
+++ b/include/linux/netdevice.h
|
|
@@ -2668,11 +2668,31 @@ static inline void skb_gro_flush_final(struct sk_buff *skb, struct sk_buff **pp,
|
|
if (PTR_ERR(pp) != -EINPROGRESS)
|
|
NAPI_GRO_CB(skb)->flush |= flush;
|
|
}
|
|
+static inline void skb_gro_flush_final_remcsum(struct sk_buff *skb,
|
|
+ struct sk_buff **pp,
|
|
+ int flush,
|
|
+ struct gro_remcsum *grc)
|
|
+{
|
|
+ if (PTR_ERR(pp) != -EINPROGRESS) {
|
|
+ NAPI_GRO_CB(skb)->flush |= flush;
|
|
+ skb_gro_remcsum_cleanup(skb, grc);
|
|
+ skb->remcsum_offload = 0;
|
|
+ }
|
|
+}
|
|
#else
|
|
static inline void skb_gro_flush_final(struct sk_buff *skb, struct sk_buff **pp, int flush)
|
|
{
|
|
NAPI_GRO_CB(skb)->flush |= flush;
|
|
}
|
|
+static inline void skb_gro_flush_final_remcsum(struct sk_buff *skb,
|
|
+ struct sk_buff **pp,
|
|
+ int flush,
|
|
+ struct gro_remcsum *grc)
|
|
+{
|
|
+ NAPI_GRO_CB(skb)->flush |= flush;
|
|
+ skb_gro_remcsum_cleanup(skb, grc);
|
|
+ skb->remcsum_offload = 0;
|
|
+}
|
|
#endif
|
|
|
|
static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,
|
|
diff --git a/include/linux/string.h b/include/linux/string.h
|
|
index cfd83eb2f926..96115bf561b4 100644
|
|
--- a/include/linux/string.h
|
|
+++ b/include/linux/string.h
|
|
@@ -28,7 +28,7 @@ extern char * strncpy(char *,const char *, __kernel_size_t);
|
|
size_t strlcpy(char *, const char *, size_t);
|
|
#endif
|
|
#ifndef __HAVE_ARCH_STRSCPY
|
|
-ssize_t __must_check strscpy(char *, const char *, size_t);
|
|
+ssize_t strscpy(char *, const char *, size_t);
|
|
#endif
|
|
#ifndef __HAVE_ARCH_STRCAT
|
|
extern char * strcat(char *, const char *);
|
|
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
|
|
index 03918a19cf2d..3b71d859ee38 100644
|
|
--- a/kernel/time/clocksource.c
|
|
+++ b/kernel/time/clocksource.c
|
|
@@ -322,6 +322,8 @@ static void clocksource_enqueue_watchdog(struct clocksource *cs)
|
|
{
|
|
unsigned long flags;
|
|
|
|
+ INIT_LIST_HEAD(&cs->wd_list);
|
|
+
|
|
spin_lock_irqsave(&watchdog_lock, flags);
|
|
if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) {
|
|
/* cs is a clocksource to be watched. */
|
|
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
|
|
index 6774e0369ebe..9386c98dac12 100644
|
|
--- a/mm/backing-dev.c
|
|
+++ b/mm/backing-dev.c
|
|
@@ -356,15 +356,8 @@ static void wb_shutdown(struct bdi_writeback *wb)
|
|
spin_lock_bh(&wb->work_lock);
|
|
if (!test_and_clear_bit(WB_registered, &wb->state)) {
|
|
spin_unlock_bh(&wb->work_lock);
|
|
- /*
|
|
- * Wait for wb shutdown to finish if someone else is just
|
|
- * running wb_shutdown(). Otherwise we could proceed to wb /
|
|
- * bdi destruction before wb_shutdown() is finished.
|
|
- */
|
|
- wait_on_bit(&wb->state, WB_shutting_down, TASK_UNINTERRUPTIBLE);
|
|
return;
|
|
}
|
|
- set_bit(WB_shutting_down, &wb->state);
|
|
spin_unlock_bh(&wb->work_lock);
|
|
|
|
cgwb_remove_from_bdi_list(wb);
|
|
@@ -376,12 +369,6 @@ static void wb_shutdown(struct bdi_writeback *wb)
|
|
mod_delayed_work(bdi_wq, &wb->dwork, 0);
|
|
flush_delayed_work(&wb->dwork);
|
|
WARN_ON(!list_empty(&wb->work_list));
|
|
- /*
|
|
- * Make sure bit gets cleared after shutdown is finished. Matches with
|
|
- * the barrier provided by test_and_clear_bit() above.
|
|
- */
|
|
- smp_wmb();
|
|
- clear_and_wake_up_bit(WB_shutting_down, &wb->state);
|
|
}
|
|
|
|
static void wb_exit(struct bdi_writeback *wb)
|
|
@@ -505,10 +492,12 @@ static void cgwb_release_workfn(struct work_struct *work)
|
|
struct bdi_writeback *wb = container_of(work, struct bdi_writeback,
|
|
release_work);
|
|
|
|
+ mutex_lock(&wb->bdi->cgwb_release_mutex);
|
|
wb_shutdown(wb);
|
|
|
|
css_put(wb->memcg_css);
|
|
css_put(wb->blkcg_css);
|
|
+ mutex_unlock(&wb->bdi->cgwb_release_mutex);
|
|
|
|
fprop_local_destroy_percpu(&wb->memcg_completions);
|
|
percpu_ref_exit(&wb->refcnt);
|
|
@@ -694,6 +683,7 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi)
|
|
|
|
INIT_RADIX_TREE(&bdi->cgwb_tree, GFP_ATOMIC);
|
|
bdi->cgwb_congested_tree = RB_ROOT;
|
|
+ mutex_init(&bdi->cgwb_release_mutex);
|
|
|
|
ret = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL);
|
|
if (!ret) {
|
|
@@ -714,7 +704,10 @@ static void cgwb_bdi_unregister(struct backing_dev_info *bdi)
|
|
spin_lock_irq(&cgwb_lock);
|
|
radix_tree_for_each_slot(slot, &bdi->cgwb_tree, &iter, 0)
|
|
cgwb_kill(*slot);
|
|
+ spin_unlock_irq(&cgwb_lock);
|
|
|
|
+ mutex_lock(&bdi->cgwb_release_mutex);
|
|
+ spin_lock_irq(&cgwb_lock);
|
|
while (!list_empty(&bdi->wb_list)) {
|
|
wb = list_first_entry(&bdi->wb_list, struct bdi_writeback,
|
|
bdi_node);
|
|
@@ -723,6 +716,7 @@ static void cgwb_bdi_unregister(struct backing_dev_info *bdi)
|
|
spin_lock_irq(&cgwb_lock);
|
|
}
|
|
spin_unlock_irq(&cgwb_lock);
|
|
+ mutex_unlock(&bdi->cgwb_release_mutex);
|
|
}
|
|
|
|
/**
|
|
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
|
|
index cf2e70003a53..cf82d970b0e4 100644
|
|
--- a/net/8021q/vlan.c
|
|
+++ b/net/8021q/vlan.c
|
|
@@ -664,7 +664,7 @@ static struct sk_buff **vlan_gro_receive(struct sk_buff **head,
|
|
out_unlock:
|
|
rcu_read_unlock();
|
|
out:
|
|
- NAPI_GRO_CB(skb)->flush |= flush;
|
|
+ skb_gro_flush_final(skb, pp, flush);
|
|
|
|
return pp;
|
|
}
|
|
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
|
|
index 4e111196f902..bc21f8e8daf2 100644
|
|
--- a/net/atm/br2684.c
|
|
+++ b/net/atm/br2684.c
|
|
@@ -252,8 +252,7 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,
|
|
|
|
ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
|
|
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);
|
|
- refcount_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
|
|
- ATM_SKB(skb)->atm_options = atmvcc->atm_options;
|
|
+ atm_account_tx(atmvcc, skb);
|
|
dev->stats.tx_packets++;
|
|
dev->stats.tx_bytes += skb->len;
|
|
|
|
diff --git a/net/atm/clip.c b/net/atm/clip.c
|
|
index 65f706e4344c..60920a42f640 100644
|
|
--- a/net/atm/clip.c
|
|
+++ b/net/atm/clip.c
|
|
@@ -381,8 +381,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
|
|
memcpy(here, llc_oui, sizeof(llc_oui));
|
|
((__be16 *) here)[3] = skb->protocol;
|
|
}
|
|
- refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
|
|
- ATM_SKB(skb)->atm_options = vcc->atm_options;
|
|
+ atm_account_tx(vcc, skb);
|
|
entry->vccs->last_use = jiffies;
|
|
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev);
|
|
old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */
|
|
diff --git a/net/atm/common.c b/net/atm/common.c
|
|
index 8a4f99114cd2..9e812c782a37 100644
|
|
--- a/net/atm/common.c
|
|
+++ b/net/atm/common.c
|
|
@@ -630,10 +630,9 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size)
|
|
goto out;
|
|
}
|
|
pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize);
|
|
- refcount_add(skb->truesize, &sk->sk_wmem_alloc);
|
|
+ atm_account_tx(vcc, skb);
|
|
|
|
skb->dev = NULL; /* for paths shared with net_device interfaces */
|
|
- ATM_SKB(skb)->atm_options = vcc->atm_options;
|
|
if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) {
|
|
kfree_skb(skb);
|
|
error = -EFAULT;
|
|
diff --git a/net/atm/lec.c b/net/atm/lec.c
|
|
index 5741b6474dd9..9f2365694ad4 100644
|
|
--- a/net/atm/lec.c
|
|
+++ b/net/atm/lec.c
|
|
@@ -182,9 +182,8 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
|
struct net_device *dev = skb->dev;
|
|
|
|
ATM_SKB(skb)->vcc = vcc;
|
|
- ATM_SKB(skb)->atm_options = vcc->atm_options;
|
|
+ atm_account_tx(vcc, skb);
|
|
|
|
- refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
|
|
if (vcc->send(vcc, skb) < 0) {
|
|
dev->stats.tx_dropped++;
|
|
return;
|
|
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
|
|
index 5677147209e8..db9a1838687c 100644
|
|
--- a/net/atm/mpc.c
|
|
+++ b/net/atm/mpc.c
|
|
@@ -555,8 +555,7 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc)
|
|
sizeof(struct llc_snap_hdr));
|
|
}
|
|
|
|
- refcount_add(skb->truesize, &sk_atm(entry->shortcut)->sk_wmem_alloc);
|
|
- ATM_SKB(skb)->atm_options = entry->shortcut->atm_options;
|
|
+ atm_account_tx(entry->shortcut, skb);
|
|
entry->shortcut->send(entry->shortcut, skb);
|
|
entry->packets_fwded++;
|
|
mpc->in_ops->put(entry);
|
|
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c
|
|
index 21d9d341a619..af8c4b38b746 100644
|
|
--- a/net/atm/pppoatm.c
|
|
+++ b/net/atm/pppoatm.c
|
|
@@ -350,8 +350,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
|
|
return 1;
|
|
}
|
|
|
|
- refcount_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc);
|
|
- ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
|
|
+ atm_account_tx(vcc, skb);
|
|
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",
|
|
skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev);
|
|
ret = ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb)
|
|
diff --git a/net/atm/raw.c b/net/atm/raw.c
|
|
index ee10e8d46185..b3ba44aab0ee 100644
|
|
--- a/net/atm/raw.c
|
|
+++ b/net/atm/raw.c
|
|
@@ -35,8 +35,8 @@ static void atm_pop_raw(struct atm_vcc *vcc, struct sk_buff *skb)
|
|
struct sock *sk = sk_atm(vcc);
|
|
|
|
pr_debug("(%d) %d -= %d\n",
|
|
- vcc->vci, sk_wmem_alloc_get(sk), skb->truesize);
|
|
- WARN_ON(refcount_sub_and_test(skb->truesize, &sk->sk_wmem_alloc));
|
|
+ vcc->vci, sk_wmem_alloc_get(sk), ATM_SKB(skb)->acct_truesize);
|
|
+ WARN_ON(refcount_sub_and_test(ATM_SKB(skb)->acct_truesize, &sk->sk_wmem_alloc));
|
|
dev_kfree_skb_any(skb);
|
|
sk->sk_write_space(sk);
|
|
}
|
|
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
|
|
index 25738b20676d..54c7fe68040f 100644
|
|
--- a/net/bridge/netfilter/ebtables.c
|
|
+++ b/net/bridge/netfilter/ebtables.c
|
|
@@ -398,6 +398,12 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
|
|
watcher = xt_request_find_target(NFPROTO_BRIDGE, w->u.name, 0);
|
|
if (IS_ERR(watcher))
|
|
return PTR_ERR(watcher);
|
|
+
|
|
+ if (watcher->family != NFPROTO_BRIDGE) {
|
|
+ module_put(watcher->me);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
w->u.watcher = watcher;
|
|
|
|
par->target = watcher;
|
|
@@ -719,6 +725,13 @@ ebt_check_entry(struct ebt_entry *e, struct net *net,
|
|
goto cleanup_watchers;
|
|
}
|
|
|
|
+ /* Reject UNSPEC, xtables verdicts/return values are incompatible */
|
|
+ if (target->family != NFPROTO_BRIDGE) {
|
|
+ module_put(target->me);
|
|
+ ret = -ENOENT;
|
|
+ goto cleanup_watchers;
|
|
+ }
|
|
+
|
|
t->u.target = target;
|
|
if (t->u.target == &ebt_standard_target) {
|
|
if (gap < sizeof(struct ebt_standard_target)) {
|
|
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
|
|
index 119c04317d48..03fcf3ee1534 100644
|
|
--- a/net/dccp/ccids/ccid3.c
|
|
+++ b/net/dccp/ccids/ccid3.c
|
|
@@ -599,7 +599,7 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk,
|
|
{
|
|
struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
|
|
struct dccp_sock *dp = dccp_sk(sk);
|
|
- ktime_t now = ktime_get_real();
|
|
+ ktime_t now = ktime_get();
|
|
s64 delta = 0;
|
|
|
|
switch (fbtype) {
|
|
@@ -624,15 +624,14 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk,
|
|
case CCID3_FBACK_PERIODIC:
|
|
delta = ktime_us_delta(now, hc->rx_tstamp_last_feedback);
|
|
if (delta <= 0)
|
|
- DCCP_BUG("delta (%ld) <= 0", (long)delta);
|
|
- else
|
|
- hc->rx_x_recv = scaled_div32(hc->rx_bytes_recv, delta);
|
|
+ delta = 1;
|
|
+ hc->rx_x_recv = scaled_div32(hc->rx_bytes_recv, delta);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
- ccid3_pr_debug("Interval %ldusec, X_recv=%u, 1/p=%u\n", (long)delta,
|
|
+ ccid3_pr_debug("Interval %lldusec, X_recv=%u, 1/p=%u\n", delta,
|
|
hc->rx_x_recv, hc->rx_pinv);
|
|
|
|
hc->rx_tstamp_last_feedback = now;
|
|
@@ -679,7 +678,8 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
|
|
static u32 ccid3_first_li(struct sock *sk)
|
|
{
|
|
struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
|
|
- u32 x_recv, p, delta;
|
|
+ u32 x_recv, p;
|
|
+ s64 delta;
|
|
u64 fval;
|
|
|
|
if (hc->rx_rtt == 0) {
|
|
@@ -687,7 +687,9 @@ static u32 ccid3_first_li(struct sock *sk)
|
|
hc->rx_rtt = DCCP_FALLBACK_RTT;
|
|
}
|
|
|
|
- delta = ktime_to_us(net_timedelta(hc->rx_tstamp_last_feedback));
|
|
+ delta = ktime_us_delta(ktime_get(), hc->rx_tstamp_last_feedback);
|
|
+ if (delta <= 0)
|
|
+ delta = 1;
|
|
x_recv = scaled_div32(hc->rx_bytes_recv, delta);
|
|
if (x_recv == 0) { /* would also trigger divide-by-zero */
|
|
DCCP_WARN("X_recv==0\n");
|
|
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
|
|
index f0252768ecf4..5f5d9eafccf5 100644
|
|
--- a/net/dns_resolver/dns_key.c
|
|
+++ b/net/dns_resolver/dns_key.c
|
|
@@ -87,35 +87,39 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
|
|
opt++;
|
|
kdebug("options: '%s'", opt);
|
|
do {
|
|
+ int opt_len, opt_nlen;
|
|
const char *eq;
|
|
- int opt_len, opt_nlen, opt_vlen, tmp;
|
|
+ char optval[128];
|
|
|
|
next_opt = memchr(opt, '#', end - opt) ?: end;
|
|
opt_len = next_opt - opt;
|
|
- if (opt_len <= 0 || opt_len > 128) {
|
|
+ if (opt_len <= 0 || opt_len > sizeof(optval)) {
|
|
pr_warn_ratelimited("Invalid option length (%d) for dns_resolver key\n",
|
|
opt_len);
|
|
return -EINVAL;
|
|
}
|
|
|
|
- eq = memchr(opt, '=', opt_len) ?: end;
|
|
- opt_nlen = eq - opt;
|
|
- eq++;
|
|
- opt_vlen = next_opt - eq; /* will be -1 if no value */
|
|
+ eq = memchr(opt, '=', opt_len);
|
|
+ if (eq) {
|
|
+ opt_nlen = eq - opt;
|
|
+ eq++;
|
|
+ memcpy(optval, eq, next_opt - eq);
|
|
+ optval[next_opt - eq] = '\0';
|
|
+ } else {
|
|
+ opt_nlen = opt_len;
|
|
+ optval[0] = '\0';
|
|
+ }
|
|
|
|
- tmp = opt_vlen >= 0 ? opt_vlen : 0;
|
|
- kdebug("option '%*.*s' val '%*.*s'",
|
|
- opt_nlen, opt_nlen, opt, tmp, tmp, eq);
|
|
+ kdebug("option '%*.*s' val '%s'",
|
|
+ opt_nlen, opt_nlen, opt, optval);
|
|
|
|
/* see if it's an error number representing a DNS error
|
|
* that's to be recorded as the result in this key */
|
|
if (opt_nlen == sizeof(DNS_ERRORNO_OPTION) - 1 &&
|
|
memcmp(opt, DNS_ERRORNO_OPTION, opt_nlen) == 0) {
|
|
kdebug("dns error number option");
|
|
- if (opt_vlen <= 0)
|
|
- goto bad_option_value;
|
|
|
|
- ret = kstrtoul(eq, 10, &derrno);
|
|
+ ret = kstrtoul(optval, 10, &derrno);
|
|
if (ret < 0)
|
|
goto bad_option_value;
|
|
|
|
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
|
|
index 1540db65241a..c9ec1603666b 100644
|
|
--- a/net/ipv4/fou.c
|
|
+++ b/net/ipv4/fou.c
|
|
@@ -448,9 +448,7 @@ static struct sk_buff **gue_gro_receive(struct sock *sk,
|
|
out_unlock:
|
|
rcu_read_unlock();
|
|
out:
|
|
- NAPI_GRO_CB(skb)->flush |= flush;
|
|
- skb_gro_remcsum_cleanup(skb, &grc);
|
|
- skb->remcsum_offload = 0;
|
|
+ skb_gro_flush_final_remcsum(skb, pp, flush, &grc);
|
|
|
|
return pp;
|
|
}
|
|
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c
|
|
index 1859c473b21a..6a7d980105f6 100644
|
|
--- a/net/ipv4/gre_offload.c
|
|
+++ b/net/ipv4/gre_offload.c
|
|
@@ -223,7 +223,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
|
|
out_unlock:
|
|
rcu_read_unlock();
|
|
out:
|
|
- NAPI_GRO_CB(skb)->flush |= flush;
|
|
+ skb_gro_flush_final(skb, pp, flush);
|
|
|
|
return pp;
|
|
}
|
|
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
|
|
index e7d15fb0d94d..24b066c32e06 100644
|
|
--- a/net/ipv4/inet_hashtables.c
|
|
+++ b/net/ipv4/inet_hashtables.c
|
|
@@ -188,9 +188,9 @@ static inline int compute_score(struct sock *sk, struct net *net,
|
|
bool dev_match = (sk->sk_bound_dev_if == dif ||
|
|
sk->sk_bound_dev_if == sdif);
|
|
|
|
- if (exact_dif && !dev_match)
|
|
+ if (!dev_match)
|
|
return -1;
|
|
- if (sk->sk_bound_dev_if && dev_match)
|
|
+ if (sk->sk_bound_dev_if)
|
|
score += 4;
|
|
}
|
|
if (sk->sk_incoming_cpu == raw_smp_processor_id())
|
|
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
|
|
index 0989e739d098..5a29dc5083a3 100644
|
|
--- a/net/ipv4/sysctl_net_ipv4.c
|
|
+++ b/net/ipv4/sysctl_net_ipv4.c
|
|
@@ -258,8 +258,9 @@ static int proc_tcp_fastopen_key(struct ctl_table *ctl, int write,
|
|
{
|
|
struct ctl_table tbl = { .maxlen = (TCP_FASTOPEN_KEY_LENGTH * 2 + 10) };
|
|
struct tcp_fastopen_context *ctxt;
|
|
- int ret;
|
|
u32 user_key[4]; /* 16 bytes, matching TCP_FASTOPEN_KEY_LENGTH */
|
|
+ __le32 key[4];
|
|
+ int ret, i;
|
|
|
|
tbl.data = kmalloc(tbl.maxlen, GFP_KERNEL);
|
|
if (!tbl.data)
|
|
@@ -268,11 +269,14 @@ static int proc_tcp_fastopen_key(struct ctl_table *ctl, int write,
|
|
rcu_read_lock();
|
|
ctxt = rcu_dereference(tcp_fastopen_ctx);
|
|
if (ctxt)
|
|
- memcpy(user_key, ctxt->key, TCP_FASTOPEN_KEY_LENGTH);
|
|
+ memcpy(key, ctxt->key, TCP_FASTOPEN_KEY_LENGTH);
|
|
else
|
|
- memset(user_key, 0, sizeof(user_key));
|
|
+ memset(key, 0, sizeof(key));
|
|
rcu_read_unlock();
|
|
|
|
+ for (i = 0; i < ARRAY_SIZE(key); i++)
|
|
+ user_key[i] = le32_to_cpu(key[i]);
|
|
+
|
|
snprintf(tbl.data, tbl.maxlen, "%08x-%08x-%08x-%08x",
|
|
user_key[0], user_key[1], user_key[2], user_key[3]);
|
|
ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
|
|
@@ -288,12 +292,16 @@ static int proc_tcp_fastopen_key(struct ctl_table *ctl, int write,
|
|
* first invocation of tcp_fastopen_cookie_gen
|
|
*/
|
|
tcp_fastopen_init_key_once(false);
|
|
- tcp_fastopen_reset_cipher(user_key, TCP_FASTOPEN_KEY_LENGTH);
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(user_key); i++)
|
|
+ key[i] = cpu_to_le32(user_key[i]);
|
|
+
|
|
+ tcp_fastopen_reset_cipher(key, TCP_FASTOPEN_KEY_LENGTH);
|
|
}
|
|
|
|
bad_key:
|
|
pr_debug("proc FO key set 0x%x-%x-%x-%x <- 0x%s: %u\n",
|
|
- user_key[0], user_key[1], user_key[2], user_key[3],
|
|
+ user_key[0], user_key[1], user_key[2], user_key[3],
|
|
(char *)tbl.data, ret);
|
|
kfree(tbl.data);
|
|
return ret;
|
|
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
|
|
index f0caff3139ed..5711b1b12d28 100644
|
|
--- a/net/ipv4/tcp_input.c
|
|
+++ b/net/ipv4/tcp_input.c
|
|
@@ -3194,6 +3194,15 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
|
|
|
|
if (tcp_is_reno(tp)) {
|
|
tcp_remove_reno_sacks(sk, pkts_acked);
|
|
+
|
|
+ /* If any of the cumulatively ACKed segments was
|
|
+ * retransmitted, non-SACK case cannot confirm that
|
|
+ * progress was due to original transmission due to
|
|
+ * lack of TCPCB_SACKED_ACKED bits even if some of
|
|
+ * the packets may have been never retransmitted.
|
|
+ */
|
|
+ if (flag & FLAG_RETRANS_DATA_ACKED)
|
|
+ flag &= ~FLAG_ORIG_SACK_ACKED;
|
|
} else {
|
|
int delta;
|
|
|
|
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
|
|
index ea6e6e7df0ee..cde2719fcb89 100644
|
|
--- a/net/ipv4/udp_offload.c
|
|
+++ b/net/ipv4/udp_offload.c
|
|
@@ -295,7 +295,7 @@ struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb,
|
|
out_unlock:
|
|
rcu_read_unlock();
|
|
out:
|
|
- NAPI_GRO_CB(skb)->flush |= flush;
|
|
+ skb_gro_flush_final(skb, pp, flush);
|
|
return pp;
|
|
}
|
|
EXPORT_SYMBOL(udp_gro_receive);
|
|
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
|
|
index b01858f5deb1..6dc93ac28261 100644
|
|
--- a/net/ipv6/inet6_hashtables.c
|
|
+++ b/net/ipv6/inet6_hashtables.c
|
|
@@ -113,9 +113,9 @@ static inline int compute_score(struct sock *sk, struct net *net,
|
|
bool dev_match = (sk->sk_bound_dev_if == dif ||
|
|
sk->sk_bound_dev_if == sdif);
|
|
|
|
- if (exact_dif && !dev_match)
|
|
+ if (!dev_match)
|
|
return -1;
|
|
- if (sk->sk_bound_dev_if && dev_match)
|
|
+ if (sk->sk_bound_dev_if)
|
|
score++;
|
|
}
|
|
if (sk->sk_incoming_cpu == raw_smp_processor_id())
|
|
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
|
|
index 64ec23388450..722a9db8c6a7 100644
|
|
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
|
|
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
|
|
@@ -618,6 +618,8 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
|
|
fq->q.meat == fq->q.len &&
|
|
nf_ct_frag6_reasm(fq, skb, dev))
|
|
ret = 0;
|
|
+ else
|
|
+ skb_dst_drop(skb);
|
|
|
|
out_unlock:
|
|
spin_unlock_bh(&fq->q.lock);
|
|
diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c
|
|
index 33fb35cbfac1..558fe8cc6d43 100644
|
|
--- a/net/ipv6/seg6_hmac.c
|
|
+++ b/net/ipv6/seg6_hmac.c
|
|
@@ -373,7 +373,7 @@ static int seg6_hmac_init_algo(void)
|
|
return -ENOMEM;
|
|
|
|
for_each_possible_cpu(cpu) {
|
|
- tfm = crypto_alloc_shash(algo->name, 0, GFP_KERNEL);
|
|
+ tfm = crypto_alloc_shash(algo->name, 0, 0);
|
|
if (IS_ERR(tfm))
|
|
return PTR_ERR(tfm);
|
|
p_tfm = per_cpu_ptr(algo->tfms, cpu);
|
|
diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c
|
|
index 2ceefa183cee..6a196e438b6c 100644
|
|
--- a/net/nfc/llcp_commands.c
|
|
+++ b/net/nfc/llcp_commands.c
|
|
@@ -752,11 +752,14 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
|
|
pr_debug("Fragment %zd bytes remaining %zd",
|
|
frag_len, remaining_len);
|
|
|
|
- pdu = nfc_alloc_send_skb(sock->dev, &sock->sk, MSG_DONTWAIT,
|
|
+ pdu = nfc_alloc_send_skb(sock->dev, &sock->sk, 0,
|
|
frag_len + LLCP_HEADER_SIZE, &err);
|
|
if (pdu == NULL) {
|
|
- pr_err("Could not allocate PDU\n");
|
|
- continue;
|
|
+ pr_err("Could not allocate PDU (error=%d)\n", err);
|
|
+ len -= remaining_len;
|
|
+ if (len == 0)
|
|
+ len = err;
|
|
+ break;
|
|
}
|
|
|
|
pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI);
|
|
diff --git a/net/nsh/nsh.c b/net/nsh/nsh.c
|
|
index 6df6f58a8103..5647905c88d6 100644
|
|
--- a/net/nsh/nsh.c
|
|
+++ b/net/nsh/nsh.c
|
|
@@ -42,7 +42,7 @@ static struct sk_buff *nsh_gso_segment(struct sk_buff *skb,
|
|
__skb_pull(skb, nsh_len);
|
|
|
|
skb_reset_mac_header(skb);
|
|
- skb_reset_mac_len(skb);
|
|
+ skb->mac_len = proto == htons(ETH_P_TEB) ? ETH_HLEN : 0;
|
|
skb->protocol = proto;
|
|
|
|
features &= NETIF_F_SG;
|
|
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
|
|
index 4fe2e34522d6..27dafe36f29c 100644
|
|
--- a/net/packet/af_packet.c
|
|
+++ b/net/packet/af_packet.c
|
|
@@ -2303,6 +2303,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
|
|
if (po->stats.stats1.tp_drops)
|
|
status |= TP_STATUS_LOSING;
|
|
}
|
|
+
|
|
+ if (do_vnet &&
|
|
+ virtio_net_hdr_from_skb(skb, h.raw + macoff -
|
|
+ sizeof(struct virtio_net_hdr),
|
|
+ vio_le(), true, 0))
|
|
+ goto drop_n_account;
|
|
+
|
|
po->stats.stats1.tp_packets++;
|
|
if (copy_skb) {
|
|
status |= TP_STATUS_COPY;
|
|
@@ -2310,15 +2317,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
|
|
}
|
|
spin_unlock(&sk->sk_receive_queue.lock);
|
|
|
|
- if (do_vnet) {
|
|
- if (virtio_net_hdr_from_skb(skb, h.raw + macoff -
|
|
- sizeof(struct virtio_net_hdr),
|
|
- vio_le(), true, 0)) {
|
|
- spin_lock(&sk->sk_receive_queue.lock);
|
|
- goto drop_n_account;
|
|
- }
|
|
- }
|
|
-
|
|
skb_copy_bits(skb, 0, h.raw + macoff, snaplen);
|
|
|
|
if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp)))
|
|
diff --git a/net/rds/loop.c b/net/rds/loop.c
|
|
index f2bf78de5688..dac6218a460e 100644
|
|
--- a/net/rds/loop.c
|
|
+++ b/net/rds/loop.c
|
|
@@ -193,4 +193,5 @@ struct rds_transport rds_loop_transport = {
|
|
.inc_copy_to_user = rds_message_inc_copy_to_user,
|
|
.inc_free = rds_loop_inc_free,
|
|
.t_name = "loopback",
|
|
+ .t_type = RDS_TRANS_LOOP,
|
|
};
|
|
diff --git a/net/rds/rds.h b/net/rds/rds.h
|
|
index d09f6c1facb4..f685d8b514e5 100644
|
|
--- a/net/rds/rds.h
|
|
+++ b/net/rds/rds.h
|
|
@@ -454,6 +454,11 @@ struct rds_notifier {
|
|
int n_status;
|
|
};
|
|
|
|
+/* Available as part of RDS core, so doesn't need to participate
|
|
+ * in get_preferred transport etc
|
|
+ */
|
|
+#define RDS_TRANS_LOOP 3
|
|
+
|
|
/**
|
|
* struct rds_transport - transport specific behavioural hooks
|
|
*
|
|
diff --git a/net/rds/recv.c b/net/rds/recv.c
|
|
index 555f07ccf0dc..c27cceae52e1 100644
|
|
--- a/net/rds/recv.c
|
|
+++ b/net/rds/recv.c
|
|
@@ -103,6 +103,11 @@ static void rds_recv_rcvbuf_delta(struct rds_sock *rs, struct sock *sk,
|
|
rds_stats_add(s_recv_bytes_added_to_socket, delta);
|
|
else
|
|
rds_stats_add(s_recv_bytes_removed_from_socket, -delta);
|
|
+
|
|
+ /* loop transport doesn't send/recv congestion updates */
|
|
+ if (rs->rs_transport->t_type == RDS_TRANS_LOOP)
|
|
+ return;
|
|
+
|
|
now_congested = rs->rs_rcv_bytes > rds_sk_rcvbuf(rs);
|
|
|
|
rdsdebug("rs %p (%pI4:%u) recv bytes %d buf %d "
|
|
diff --git a/net/sched/sch_blackhole.c b/net/sched/sch_blackhole.c
|
|
index c98a61e980ba..9c4c2bb547d7 100644
|
|
--- a/net/sched/sch_blackhole.c
|
|
+++ b/net/sched/sch_blackhole.c
|
|
@@ -21,7 +21,7 @@ static int blackhole_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|
struct sk_buff **to_free)
|
|
{
|
|
qdisc_drop(skb, sch, to_free);
|
|
- return NET_XMIT_SUCCESS;
|
|
+ return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
|
|
}
|
|
|
|
static struct sk_buff *blackhole_dequeue(struct Qdisc *sch)
|
|
diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c
|
|
index c741365f77da..a68c754e84ea 100644
|
|
--- a/net/strparser/strparser.c
|
|
+++ b/net/strparser/strparser.c
|
|
@@ -35,7 +35,6 @@ struct _strp_msg {
|
|
*/
|
|
struct strp_msg strp;
|
|
int accum_len;
|
|
- int early_eaten;
|
|
};
|
|
|
|
static inline struct _strp_msg *_strp_msg(struct sk_buff *skb)
|
|
@@ -115,20 +114,6 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
|
|
head = strp->skb_head;
|
|
if (head) {
|
|
/* Message already in progress */
|
|
-
|
|
- stm = _strp_msg(head);
|
|
- if (unlikely(stm->early_eaten)) {
|
|
- /* Already some number of bytes on the receive sock
|
|
- * data saved in skb_head, just indicate they
|
|
- * are consumed.
|
|
- */
|
|
- eaten = orig_len <= stm->early_eaten ?
|
|
- orig_len : stm->early_eaten;
|
|
- stm->early_eaten -= eaten;
|
|
-
|
|
- return eaten;
|
|
- }
|
|
-
|
|
if (unlikely(orig_offset)) {
|
|
/* Getting data with a non-zero offset when a message is
|
|
* in progress is not expected. If it does happen, we
|
|
@@ -297,9 +282,9 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
|
|
}
|
|
|
|
stm->accum_len += cand_len;
|
|
+ eaten += cand_len;
|
|
strp->need_bytes = stm->strp.full_len -
|
|
stm->accum_len;
|
|
- stm->early_eaten = cand_len;
|
|
STRP_STATS_ADD(strp->stats.bytes, cand_len);
|
|
desc->count = 0; /* Stop reading socket */
|
|
break;
|
|
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
|
|
index 97b9d4f671ac..2aaf46599126 100644
|
|
--- a/net/sunrpc/xprtrdma/verbs.c
|
|
+++ b/net/sunrpc/xprtrdma/verbs.c
|
|
@@ -270,7 +270,6 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
|
|
wait_for_completion(&ia->ri_remove_done);
|
|
|
|
ia->ri_id = NULL;
|
|
- ia->ri_pd = NULL;
|
|
ia->ri_device = NULL;
|
|
/* Return 1 to ensure the core destroys the id. */
|
|
return 1;
|
|
@@ -464,7 +463,9 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia)
|
|
ia->ri_id->qp = NULL;
|
|
}
|
|
ib_free_cq(ep->rep_attr.recv_cq);
|
|
+ ep->rep_attr.recv_cq = NULL;
|
|
ib_free_cq(ep->rep_attr.send_cq);
|
|
+ ep->rep_attr.send_cq = NULL;
|
|
|
|
/* The ULP is responsible for ensuring all DMA
|
|
* mappings and MRs are gone.
|
|
@@ -477,6 +478,8 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia)
|
|
rpcrdma_dma_unmap_regbuf(req->rl_recvbuf);
|
|
}
|
|
rpcrdma_destroy_mrs(buf);
|
|
+ ib_dealloc_pd(ia->ri_pd);
|
|
+ ia->ri_pd = NULL;
|
|
|
|
/* Allow waiters to continue */
|
|
complete(&ia->ri_remove_done);
|
|
@@ -650,14 +653,16 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
|
|
|
|
cancel_delayed_work_sync(&ep->rep_connect_worker);
|
|
|
|
- if (ia->ri_id->qp) {
|
|
+ if (ia->ri_id && ia->ri_id->qp) {
|
|
rpcrdma_ep_disconnect(ep, ia);
|
|
rdma_destroy_qp(ia->ri_id);
|
|
ia->ri_id->qp = NULL;
|
|
}
|
|
|
|
- ib_free_cq(ep->rep_attr.recv_cq);
|
|
- ib_free_cq(ep->rep_attr.send_cq);
|
|
+ if (ep->rep_attr.recv_cq)
|
|
+ ib_free_cq(ep->rep_attr.recv_cq);
|
|
+ if (ep->rep_attr.send_cq)
|
|
+ ib_free_cq(ep->rep_attr.send_cq);
|
|
}
|
|
|
|
/* Re-establish a connection after a device removal event.
|
|
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
|
|
index 3c86614462f6..8ee4e667a414 100644
|
|
--- a/net/tls/tls_sw.c
|
|
+++ b/net/tls/tls_sw.c
|
|
@@ -449,7 +449,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
|
|
ret = tls_push_record(sk, msg->msg_flags, record_type);
|
|
if (!ret)
|
|
continue;
|
|
- if (ret == -EAGAIN)
|
|
+ if (ret < 0)
|
|
goto send_end;
|
|
|
|
copied -= try_to_copy;
|
|
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
|
|
index 403d86e80162..fdb294441682 100644
|
|
--- a/net/vmw_vsock/virtio_transport.c
|
|
+++ b/net/vmw_vsock/virtio_transport.c
|
|
@@ -201,7 +201,7 @@ virtio_transport_send_pkt(struct virtio_vsock_pkt *pkt)
|
|
return -ENODEV;
|
|
}
|
|
|
|
- if (le32_to_cpu(pkt->hdr.dst_cid) == vsock->guest_cid)
|
|
+ if (le64_to_cpu(pkt->hdr.dst_cid) == vsock->guest_cid)
|
|
return virtio_transport_send_pkt_loopback(vsock, pkt);
|
|
|
|
if (pkt->reply)
|
|
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
|
|
index 9bee849db682..d5f1d8364571 100644
|
|
--- a/virt/kvm/arm/arm.c
|
|
+++ b/virt/kvm/arm/arm.c
|
|
@@ -51,8 +51,8 @@
|
|
__asm__(".arch_extension virt");
|
|
#endif
|
|
|
|
+DEFINE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
|
|
static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page);
|
|
-static kvm_cpu_context_t __percpu *kvm_host_cpu_state;
|
|
|
|
/* Per-CPU variable containing the currently running vcpu. */
|
|
static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_arm_running_vcpu);
|
|
@@ -351,7 +351,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
|
}
|
|
|
|
vcpu->cpu = cpu;
|
|
- vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state);
|
|
+ vcpu->arch.host_cpu_context = this_cpu_ptr(&kvm_host_cpu_state);
|
|
|
|
kvm_arm_set_running_vcpu(vcpu);
|
|
|
|
@@ -1259,19 +1259,8 @@ static inline void hyp_cpu_pm_exit(void)
|
|
}
|
|
#endif
|
|
|
|
-static void teardown_common_resources(void)
|
|
-{
|
|
- free_percpu(kvm_host_cpu_state);
|
|
-}
|
|
-
|
|
static int init_common_resources(void)
|
|
{
|
|
- kvm_host_cpu_state = alloc_percpu(kvm_cpu_context_t);
|
|
- if (!kvm_host_cpu_state) {
|
|
- kvm_err("Cannot allocate host CPU state\n");
|
|
- return -ENOMEM;
|
|
- }
|
|
-
|
|
/* set size of VMID supported by CPU */
|
|
kvm_vmid_bits = kvm_get_vmid_bits();
|
|
kvm_info("%d-bit VMID\n", kvm_vmid_bits);
|
|
@@ -1413,7 +1402,7 @@ static int init_hyp_mode(void)
|
|
for_each_possible_cpu(cpu) {
|
|
kvm_cpu_context_t *cpu_ctxt;
|
|
|
|
- cpu_ctxt = per_cpu_ptr(kvm_host_cpu_state, cpu);
|
|
+ cpu_ctxt = per_cpu_ptr(&kvm_host_cpu_state, cpu);
|
|
err = create_hyp_mappings(cpu_ctxt, cpu_ctxt + 1, PAGE_HYP);
|
|
|
|
if (err) {
|
|
@@ -1422,6 +1411,10 @@ static int init_hyp_mode(void)
|
|
}
|
|
}
|
|
|
|
+ err = hyp_map_aux_data();
|
|
+ if (err)
|
|
+ kvm_err("Cannot map host auxilary data: %d\n", err);
|
|
+
|
|
return 0;
|
|
|
|
out_err:
|
|
@@ -1497,7 +1490,6 @@ int kvm_arch_init(void *opaque)
|
|
if (!in_hyp_mode)
|
|
teardown_hyp_mode();
|
|
out_err:
|
|
- teardown_common_resources();
|
|
return err;
|
|
}
|
|
|
|
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
|
|
index d7fd46fe9efb..4b4221b0d4ba 100644
|
|
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
|
|
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
|
|
@@ -139,7 +139,7 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
|
|
return -1;
|
|
|
|
rd = kvm_vcpu_dabt_get_rd(vcpu);
|
|
- addr = kern_hyp_va((kern_hyp_va(&kvm_vgic_global_state))->vcpu_base_va);
|
|
+ addr = kern_hyp_va(hyp_symbol_addr(kvm_vgic_global_state)->vcpu_base_va);
|
|
addr += fault_ipa - vgic->vgic_cpu_base;
|
|
|
|
if (kvm_vcpu_dabt_iswrite(vcpu)) {
|
|
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
|
|
index c4762bef13c6..c95ab4c5a475 100644
|
|
--- a/virt/kvm/arm/psci.c
|
|
+++ b/virt/kvm/arm/psci.c
|
|
@@ -405,7 +405,7 @@ static int kvm_psci_call(struct kvm_vcpu *vcpu)
|
|
int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
|
|
{
|
|
u32 func_id = smccc_get_function(vcpu);
|
|
- u32 val = PSCI_RET_NOT_SUPPORTED;
|
|
+ u32 val = SMCCC_RET_NOT_SUPPORTED;
|
|
u32 feature;
|
|
|
|
switch (func_id) {
|
|
@@ -417,7 +417,21 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
|
|
switch(feature) {
|
|
case ARM_SMCCC_ARCH_WORKAROUND_1:
|
|
if (kvm_arm_harden_branch_predictor())
|
|
- val = 0;
|
|
+ val = SMCCC_RET_SUCCESS;
|
|
+ break;
|
|
+ case ARM_SMCCC_ARCH_WORKAROUND_2:
|
|
+ switch (kvm_arm_have_ssbd()) {
|
|
+ case KVM_SSBD_FORCE_DISABLE:
|
|
+ case KVM_SSBD_UNKNOWN:
|
|
+ break;
|
|
+ case KVM_SSBD_KERNEL:
|
|
+ val = SMCCC_RET_SUCCESS;
|
|
+ break;
|
|
+ case KVM_SSBD_FORCE_ENABLE:
|
|
+ case KVM_SSBD_MITIGATED:
|
|
+ val = SMCCC_RET_NOT_REQUIRED;
|
|
+ break;
|
|
+ }
|
|
break;
|
|
}
|
|
break;
|