Merge "Merge android-4.4.131 (d5d6526
) into msm-4.4"
This commit is contained in:
commit
6e5dae3ae1
113 changed files with 1693 additions and 375 deletions
|
@ -2453,6 +2453,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
|
||||
noalign [KNL,ARM]
|
||||
|
||||
noaltinstr [S390] Disables alternative instructions patching
|
||||
(CPU alternatives feature).
|
||||
|
||||
noapic [SMP,APIC] Tells the kernel to not make use of any
|
||||
IOAPICs that may be present in the system.
|
||||
|
||||
|
|
2
Makefile
2
Makefile
|
@ -1,6 +1,6 @@
|
|||
VERSION = 4
|
||||
PATCHLEVEL = 4
|
||||
SUBLEVEL = 129
|
||||
SUBLEVEL = 131
|
||||
EXTRAVERSION =
|
||||
NAME = Blurry Fish Butt
|
||||
|
||||
|
|
|
@ -111,6 +111,7 @@ config S390
|
|||
select GENERIC_CLOCKEVENTS
|
||||
select GENERIC_CPU_AUTOPROBE
|
||||
select GENERIC_CPU_DEVICES if !SMP
|
||||
select GENERIC_CPU_VULNERABILITIES
|
||||
select GENERIC_FIND_FIRST_BIT
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select GENERIC_TIME_VSYSCALL
|
||||
|
@ -706,6 +707,51 @@ config SECCOMP
|
|||
|
||||
If unsure, say Y.
|
||||
|
||||
config KERNEL_NOBP
|
||||
def_bool n
|
||||
prompt "Enable modified branch prediction for the kernel by default"
|
||||
help
|
||||
If this option is selected the kernel will switch to a modified
|
||||
branch prediction mode if the firmware interface is available.
|
||||
The modified branch prediction mode improves the behaviour in
|
||||
regard to speculative execution.
|
||||
|
||||
With the option enabled the kernel parameter "nobp=0" or "nospec"
|
||||
can be used to run the kernel in the normal branch prediction mode.
|
||||
|
||||
With the option disabled the modified branch prediction mode is
|
||||
enabled with the "nobp=1" kernel parameter.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config EXPOLINE
|
||||
def_bool n
|
||||
prompt "Avoid speculative indirect branches in the kernel"
|
||||
help
|
||||
Compile the kernel with the expoline compiler options to guard
|
||||
against kernel-to-user data leaks by avoiding speculative indirect
|
||||
branches.
|
||||
Requires a compiler with -mindirect-branch=thunk support for full
|
||||
protection. The kernel may run slower.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
choice
|
||||
prompt "Expoline default"
|
||||
depends on EXPOLINE
|
||||
default EXPOLINE_FULL
|
||||
|
||||
config EXPOLINE_OFF
|
||||
bool "spectre_v2=off"
|
||||
|
||||
config EXPOLINE_AUTO
|
||||
bool "spectre_v2=auto"
|
||||
|
||||
config EXPOLINE_FULL
|
||||
bool "spectre_v2=on"
|
||||
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Power Management"
|
||||
|
@ -755,6 +801,7 @@ config PFAULT
|
|||
config SHARED_KERNEL
|
||||
bool "VM shared kernel support"
|
||||
depends on !JUMP_LABEL
|
||||
depends on !ALTERNATIVES
|
||||
help
|
||||
Select this option, if you want to share the text segment of the
|
||||
Linux kernel between different VM guests. This reduces memory
|
||||
|
|
|
@ -77,6 +77,16 @@ ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y)
|
|||
cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack
|
||||
endif
|
||||
|
||||
ifdef CONFIG_EXPOLINE
|
||||
ifeq ($(call cc-option-yn,$(CC_FLAGS_MARCH) -mindirect-branch=thunk),y)
|
||||
CC_FLAGS_EXPOLINE := -mindirect-branch=thunk
|
||||
CC_FLAGS_EXPOLINE += -mfunction-return=thunk
|
||||
CC_FLAGS_EXPOLINE += -mindirect-branch-table
|
||||
export CC_FLAGS_EXPOLINE
|
||||
cflags-y += $(CC_FLAGS_EXPOLINE) -DCC_USING_EXPOLINE
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_FUNCTION_TRACER
|
||||
# make use of hotpatch feature if the compiler supports it
|
||||
cc_hotpatch := -mhotpatch=0,3
|
||||
|
|
149
arch/s390/include/asm/alternative.h
Normal file
149
arch/s390/include/asm/alternative.h
Normal file
|
@ -0,0 +1,149 @@
|
|||
#ifndef _ASM_S390_ALTERNATIVE_H
|
||||
#define _ASM_S390_ALTERNATIVE_H
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/stringify.h>
|
||||
|
||||
struct alt_instr {
|
||||
s32 instr_offset; /* original instruction */
|
||||
s32 repl_offset; /* offset to replacement instruction */
|
||||
u16 facility; /* facility bit set for replacement */
|
||||
u8 instrlen; /* length of original instruction */
|
||||
u8 replacementlen; /* length of new instruction */
|
||||
} __packed;
|
||||
|
||||
void apply_alternative_instructions(void);
|
||||
void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
|
||||
|
||||
/*
|
||||
* |661: |662: |6620 |663:
|
||||
* +-----------+---------------------+
|
||||
* | oldinstr | oldinstr_padding |
|
||||
* | +----------+----------+
|
||||
* | | | |
|
||||
* | | >6 bytes |6/4/2 nops|
|
||||
* | |6 bytes jg----------->
|
||||
* +-----------+---------------------+
|
||||
* ^^ static padding ^^
|
||||
*
|
||||
* .altinstr_replacement section
|
||||
* +---------------------+-----------+
|
||||
* |6641: |6651:
|
||||
* | alternative instr 1 |
|
||||
* +-----------+---------+- - - - - -+
|
||||
* |6642: |6652: |
|
||||
* | alternative instr 2 | padding
|
||||
* +---------------------+- - - - - -+
|
||||
* ^ runtime ^
|
||||
*
|
||||
* .altinstructions section
|
||||
* +---------------------------------+
|
||||
* | alt_instr entries for each |
|
||||
* | alternative instr |
|
||||
* +---------------------------------+
|
||||
*/
|
||||
|
||||
#define b_altinstr(num) "664"#num
|
||||
#define e_altinstr(num) "665"#num
|
||||
|
||||
#define e_oldinstr_pad_end "663"
|
||||
#define oldinstr_len "662b-661b"
|
||||
#define oldinstr_total_len e_oldinstr_pad_end"b-661b"
|
||||
#define altinstr_len(num) e_altinstr(num)"b-"b_altinstr(num)"b"
|
||||
#define oldinstr_pad_len(num) \
|
||||
"-(((" altinstr_len(num) ")-(" oldinstr_len ")) > 0) * " \
|
||||
"((" altinstr_len(num) ")-(" oldinstr_len "))"
|
||||
|
||||
#define INSTR_LEN_SANITY_CHECK(len) \
|
||||
".if " len " > 254\n" \
|
||||
"\t.error \"cpu alternatives does not support instructions " \
|
||||
"blocks > 254 bytes\"\n" \
|
||||
".endif\n" \
|
||||
".if (" len ") %% 2\n" \
|
||||
"\t.error \"cpu alternatives instructions length is odd\"\n" \
|
||||
".endif\n"
|
||||
|
||||
#define OLDINSTR_PADDING(oldinstr, num) \
|
||||
".if " oldinstr_pad_len(num) " > 6\n" \
|
||||
"\tjg " e_oldinstr_pad_end "f\n" \
|
||||
"6620:\n" \
|
||||
"\t.fill (" oldinstr_pad_len(num) " - (6620b-662b)) / 2, 2, 0x0700\n" \
|
||||
".else\n" \
|
||||
"\t.fill " oldinstr_pad_len(num) " / 6, 6, 0xc0040000\n" \
|
||||
"\t.fill " oldinstr_pad_len(num) " %% 6 / 4, 4, 0x47000000\n" \
|
||||
"\t.fill " oldinstr_pad_len(num) " %% 6 %% 4 / 2, 2, 0x0700\n" \
|
||||
".endif\n"
|
||||
|
||||
#define OLDINSTR(oldinstr, num) \
|
||||
"661:\n\t" oldinstr "\n662:\n" \
|
||||
OLDINSTR_PADDING(oldinstr, num) \
|
||||
e_oldinstr_pad_end ":\n" \
|
||||
INSTR_LEN_SANITY_CHECK(oldinstr_len)
|
||||
|
||||
#define OLDINSTR_2(oldinstr, num1, num2) \
|
||||
"661:\n\t" oldinstr "\n662:\n" \
|
||||
".if " altinstr_len(num1) " < " altinstr_len(num2) "\n" \
|
||||
OLDINSTR_PADDING(oldinstr, num2) \
|
||||
".else\n" \
|
||||
OLDINSTR_PADDING(oldinstr, num1) \
|
||||
".endif\n" \
|
||||
e_oldinstr_pad_end ":\n" \
|
||||
INSTR_LEN_SANITY_CHECK(oldinstr_len)
|
||||
|
||||
#define ALTINSTR_ENTRY(facility, num) \
|
||||
"\t.long 661b - .\n" /* old instruction */ \
|
||||
"\t.long " b_altinstr(num)"b - .\n" /* alt instruction */ \
|
||||
"\t.word " __stringify(facility) "\n" /* facility bit */ \
|
||||
"\t.byte " oldinstr_total_len "\n" /* source len */ \
|
||||
"\t.byte " altinstr_len(num) "\n" /* alt instruction len */
|
||||
|
||||
#define ALTINSTR_REPLACEMENT(altinstr, num) /* replacement */ \
|
||||
b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n" \
|
||||
INSTR_LEN_SANITY_CHECK(altinstr_len(num))
|
||||
|
||||
/* alternative assembly primitive: */
|
||||
#define ALTERNATIVE(oldinstr, altinstr, facility) \
|
||||
".pushsection .altinstr_replacement, \"ax\"\n" \
|
||||
ALTINSTR_REPLACEMENT(altinstr, 1) \
|
||||
".popsection\n" \
|
||||
OLDINSTR(oldinstr, 1) \
|
||||
".pushsection .altinstructions,\"a\"\n" \
|
||||
ALTINSTR_ENTRY(facility, 1) \
|
||||
".popsection\n"
|
||||
|
||||
#define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2)\
|
||||
".pushsection .altinstr_replacement, \"ax\"\n" \
|
||||
ALTINSTR_REPLACEMENT(altinstr1, 1) \
|
||||
ALTINSTR_REPLACEMENT(altinstr2, 2) \
|
||||
".popsection\n" \
|
||||
OLDINSTR_2(oldinstr, 1, 2) \
|
||||
".pushsection .altinstructions,\"a\"\n" \
|
||||
ALTINSTR_ENTRY(facility1, 1) \
|
||||
ALTINSTR_ENTRY(facility2, 2) \
|
||||
".popsection\n"
|
||||
|
||||
/*
|
||||
* Alternative instructions for different CPU types or capabilities.
|
||||
*
|
||||
* This allows to use optimized instructions even on generic binary
|
||||
* kernels.
|
||||
*
|
||||
* oldinstr is padded with jump and nops at compile time if altinstr is
|
||||
* longer. altinstr is padded with jump and nops at run-time during patching.
|
||||
*
|
||||
* For non barrier like inlines please define new variants
|
||||
* without volatile and memory clobber.
|
||||
*/
|
||||
#define alternative(oldinstr, altinstr, facility) \
|
||||
asm volatile(ALTERNATIVE(oldinstr, altinstr, facility) : : : "memory")
|
||||
|
||||
#define alternative_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \
|
||||
asm volatile(ALTERNATIVE_2(oldinstr, altinstr1, facility1, \
|
||||
altinstr2, facility2) ::: "memory")
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* _ASM_S390_ALTERNATIVE_H */
|
|
@ -53,4 +53,28 @@ do { \
|
|||
___p1; \
|
||||
})
|
||||
|
||||
/**
|
||||
* array_index_mask_nospec - generate a mask for array_idx() that is
|
||||
* ~0UL when the bounds check succeeds and 0 otherwise
|
||||
* @index: array element index
|
||||
* @size: number of elements in array
|
||||
*/
|
||||
#define array_index_mask_nospec array_index_mask_nospec
|
||||
static inline unsigned long array_index_mask_nospec(unsigned long index,
|
||||
unsigned long size)
|
||||
{
|
||||
unsigned long mask;
|
||||
|
||||
if (__builtin_constant_p(size) && size > 0) {
|
||||
asm(" clgr %2,%1\n"
|
||||
" slbgr %0,%0\n"
|
||||
:"=d" (mask) : "d" (size-1), "d" (index) :"cc");
|
||||
return mask;
|
||||
}
|
||||
asm(" clgr %1,%2\n"
|
||||
" slbgr %0,%0\n"
|
||||
:"=d" (mask) : "d" (size), "d" (index) :"cc");
|
||||
return ~mask;
|
||||
}
|
||||
|
||||
#endif /* __ASM_BARRIER_H */
|
||||
|
|
|
@ -13,6 +13,24 @@
|
|||
|
||||
#define MAX_FACILITY_BIT (256*8) /* stfle_fac_list has 256 bytes */
|
||||
|
||||
static inline void __set_facility(unsigned long nr, void *facilities)
|
||||
{
|
||||
unsigned char *ptr = (unsigned char *) facilities;
|
||||
|
||||
if (nr >= MAX_FACILITY_BIT)
|
||||
return;
|
||||
ptr[nr >> 3] |= 0x80 >> (nr & 7);
|
||||
}
|
||||
|
||||
static inline void __clear_facility(unsigned long nr, void *facilities)
|
||||
{
|
||||
unsigned char *ptr = (unsigned char *) facilities;
|
||||
|
||||
if (nr >= MAX_FACILITY_BIT)
|
||||
return;
|
||||
ptr[nr >> 3] &= ~(0x80 >> (nr & 7));
|
||||
}
|
||||
|
||||
static inline int __test_facility(unsigned long nr, void *facilities)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
|
|
|
@ -136,7 +136,8 @@ struct kvm_s390_sie_block {
|
|||
__u16 ipa; /* 0x0056 */
|
||||
__u32 ipb; /* 0x0058 */
|
||||
__u32 scaoh; /* 0x005c */
|
||||
__u8 reserved60; /* 0x0060 */
|
||||
#define FPF_BPBC 0x20
|
||||
__u8 fpf; /* 0x0060 */
|
||||
__u8 ecb; /* 0x0061 */
|
||||
__u8 ecb2; /* 0x0062 */
|
||||
#define ECB3_AES 0x04
|
||||
|
|
|
@ -155,7 +155,9 @@ struct _lowcore {
|
|||
/* Per cpu primary space access list */
|
||||
__u32 paste[16]; /* 0x0400 */
|
||||
|
||||
__u8 pad_0x04c0[0x0e00-0x0440]; /* 0x0440 */
|
||||
/* br %r1 trampoline */
|
||||
__u16 br_r1_trampoline; /* 0x0440 */
|
||||
__u8 pad_0x0442[0x0e00-0x0442]; /* 0x0442 */
|
||||
|
||||
/*
|
||||
* 0xe00 contains the address of the IPL Parameter Information
|
||||
|
@ -170,7 +172,8 @@ struct _lowcore {
|
|||
__u8 pad_0x0e20[0x0f00-0x0e20]; /* 0x0e20 */
|
||||
|
||||
/* Extended facility list */
|
||||
__u64 stfle_fac_list[32]; /* 0x0f00 */
|
||||
__u64 stfle_fac_list[16]; /* 0x0f00 */
|
||||
__u64 alt_stfle_fac_list[16]; /* 0x0f80 */
|
||||
__u8 pad_0x1000[0x11b0-0x1000]; /* 0x1000 */
|
||||
|
||||
/* Pointer to vector register save area */
|
||||
|
|
17
arch/s390/include/asm/nospec-branch.h
Normal file
17
arch/s390/include/asm/nospec-branch.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_S390_EXPOLINE_H
|
||||
#define _ASM_S390_EXPOLINE_H
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
extern int nospec_disable;
|
||||
|
||||
void nospec_init_branches(void);
|
||||
void nospec_auto_detect(void);
|
||||
void nospec_revert(s32 *start, s32 *end);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* _ASM_S390_EXPOLINE_H */
|
|
@ -69,6 +69,7 @@ extern void s390_adjust_jiffies(void);
|
|||
extern const struct seq_operations cpuinfo_op;
|
||||
extern int sysctl_ieee_emulation_warnings;
|
||||
extern void execve_tail(void);
|
||||
extern void __bpon(void);
|
||||
|
||||
/*
|
||||
* User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit.
|
||||
|
@ -315,6 +316,9 @@ extern void memcpy_absolute(void *, void *, size_t);
|
|||
memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \
|
||||
}
|
||||
|
||||
extern int s390_isolate_bp(void);
|
||||
extern int s390_isolate_bp_guest(void);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __ASM_S390_PROCESSOR_H */
|
||||
|
|
|
@ -78,6 +78,8 @@ void arch_release_task_struct(struct task_struct *tsk);
|
|||
#define TIF_SECCOMP 5 /* secure computing */
|
||||
#define TIF_SYSCALL_TRACEPOINT 6 /* syscall tracepoint instrumentation */
|
||||
#define TIF_UPROBE 7 /* breakpointed or single-stepping */
|
||||
#define TIF_ISOLATE_BP 8 /* Run process with isolated BP */
|
||||
#define TIF_ISOLATE_BP_GUEST 9 /* Run KVM guests with isolated BP */
|
||||
#define TIF_31BIT 16 /* 32bit process */
|
||||
#define TIF_MEMDIE 17 /* is terminating due to OOM killer */
|
||||
#define TIF_RESTORE_SIGMASK 18 /* restore signal mask in do_signal() */
|
||||
|
@ -93,6 +95,8 @@ void arch_release_task_struct(struct task_struct *tsk);
|
|||
#define _TIF_SECCOMP _BITUL(TIF_SECCOMP)
|
||||
#define _TIF_SYSCALL_TRACEPOINT _BITUL(TIF_SYSCALL_TRACEPOINT)
|
||||
#define _TIF_UPROBE _BITUL(TIF_UPROBE)
|
||||
#define _TIF_ISOLATE_BP _BITUL(TIF_ISOLATE_BP)
|
||||
#define _TIF_ISOLATE_BP_GUEST _BITUL(TIF_ISOLATE_BP_GUEST)
|
||||
#define _TIF_31BIT _BITUL(TIF_31BIT)
|
||||
#define _TIF_SINGLE_STEP _BITUL(TIF_SINGLE_STEP)
|
||||
|
||||
|
|
|
@ -151,6 +151,7 @@ struct kvm_guest_debug_arch {
|
|||
#define KVM_SYNC_ARCH0 (1UL << 4)
|
||||
#define KVM_SYNC_PFAULT (1UL << 5)
|
||||
#define KVM_SYNC_VRS (1UL << 6)
|
||||
#define KVM_SYNC_BPBC (1UL << 10)
|
||||
/* definition of registers in kvm_run */
|
||||
struct kvm_sync_regs {
|
||||
__u64 prefix; /* prefix register */
|
||||
|
@ -168,6 +169,8 @@ struct kvm_sync_regs {
|
|||
__u64 vrs[32][2]; /* vector registers */
|
||||
__u8 reserved[512]; /* for future vector expansion */
|
||||
__u32 fpc; /* only valid with vector registers */
|
||||
__u8 bpbc : 1; /* bp mode */
|
||||
__u8 reserved2 : 7;
|
||||
};
|
||||
|
||||
#define KVM_REG_S390_TODPR (KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1)
|
||||
|
|
|
@ -44,10 +44,13 @@ obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
|
|||
obj-y += debug.o irq.o ipl.o dis.o diag.o sclp.o vdso.o
|
||||
obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
|
||||
obj-y += runtime_instr.o cache.o dumpstack.o
|
||||
obj-y += entry.o reipl.o relocate_kernel.o
|
||||
obj-y += entry.o reipl.o relocate_kernel.o alternative.o
|
||||
obj-y += nospec-branch.o
|
||||
|
||||
extra-y += head.o head64.o vmlinux.lds
|
||||
|
||||
CFLAGS_REMOVE_nospec-branch.o += $(CC_FLAGS_EXPOLINE)
|
||||
|
||||
obj-$(CONFIG_MODULES) += s390_ksyms.o module.o
|
||||
obj-$(CONFIG_SMP) += smp.o
|
||||
obj-$(CONFIG_SCHED_BOOK) += topology.o
|
||||
|
|
112
arch/s390/kernel/alternative.c
Normal file
112
arch/s390/kernel/alternative.c
Normal file
|
@ -0,0 +1,112 @@
|
|||
#include <linux/module.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/facility.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
|
||||
#define MAX_PATCH_LEN (255 - 1)
|
||||
|
||||
static int __initdata_or_module alt_instr_disabled;
|
||||
|
||||
static int __init disable_alternative_instructions(char *str)
|
||||
{
|
||||
alt_instr_disabled = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
early_param("noaltinstr", disable_alternative_instructions);
|
||||
|
||||
struct brcl_insn {
|
||||
u16 opc;
|
||||
s32 disp;
|
||||
} __packed;
|
||||
|
||||
static u16 __initdata_or_module nop16 = 0x0700;
|
||||
static u32 __initdata_or_module nop32 = 0x47000000;
|
||||
static struct brcl_insn __initdata_or_module nop48 = {
|
||||
0xc004, 0
|
||||
};
|
||||
|
||||
static const void *nops[] __initdata_or_module = {
|
||||
&nop16,
|
||||
&nop32,
|
||||
&nop48
|
||||
};
|
||||
|
||||
static void __init_or_module add_jump_padding(void *insns, unsigned int len)
|
||||
{
|
||||
struct brcl_insn brcl = {
|
||||
0xc0f4,
|
||||
len / 2
|
||||
};
|
||||
|
||||
memcpy(insns, &brcl, sizeof(brcl));
|
||||
insns += sizeof(brcl);
|
||||
len -= sizeof(brcl);
|
||||
|
||||
while (len > 0) {
|
||||
memcpy(insns, &nop16, 2);
|
||||
insns += 2;
|
||||
len -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void __init_or_module add_padding(void *insns, unsigned int len)
|
||||
{
|
||||
if (len > 6)
|
||||
add_jump_padding(insns, len);
|
||||
else if (len >= 2)
|
||||
memcpy(insns, nops[len / 2 - 1], len);
|
||||
}
|
||||
|
||||
static void __init_or_module __apply_alternatives(struct alt_instr *start,
|
||||
struct alt_instr *end)
|
||||
{
|
||||
struct alt_instr *a;
|
||||
u8 *instr, *replacement;
|
||||
u8 insnbuf[MAX_PATCH_LEN];
|
||||
|
||||
/*
|
||||
* The scan order should be from start to end. A later scanned
|
||||
* alternative code can overwrite previously scanned alternative code.
|
||||
*/
|
||||
for (a = start; a < end; a++) {
|
||||
int insnbuf_sz = 0;
|
||||
|
||||
instr = (u8 *)&a->instr_offset + a->instr_offset;
|
||||
replacement = (u8 *)&a->repl_offset + a->repl_offset;
|
||||
|
||||
if (!__test_facility(a->facility,
|
||||
S390_lowcore.alt_stfle_fac_list))
|
||||
continue;
|
||||
|
||||
if (unlikely(a->instrlen % 2 || a->replacementlen % 2)) {
|
||||
WARN_ONCE(1, "cpu alternatives instructions length is "
|
||||
"odd, skipping patching\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(insnbuf, replacement, a->replacementlen);
|
||||
insnbuf_sz = a->replacementlen;
|
||||
|
||||
if (a->instrlen > a->replacementlen) {
|
||||
add_padding(insnbuf + a->replacementlen,
|
||||
a->instrlen - a->replacementlen);
|
||||
insnbuf_sz += a->instrlen - a->replacementlen;
|
||||
}
|
||||
|
||||
s390_kernel_write(instr, insnbuf, insnbuf_sz);
|
||||
}
|
||||
}
|
||||
|
||||
void __init_or_module apply_alternatives(struct alt_instr *start,
|
||||
struct alt_instr *end)
|
||||
{
|
||||
if (!alt_instr_disabled)
|
||||
__apply_alternatives(start, end);
|
||||
}
|
||||
|
||||
extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
|
||||
void __init apply_alternative_instructions(void)
|
||||
{
|
||||
apply_alternatives(__alt_instructions, __alt_instructions_end);
|
||||
}
|
|
@ -279,6 +279,11 @@ static noinline __init void setup_facility_list(void)
|
|||
{
|
||||
stfle(S390_lowcore.stfle_fac_list,
|
||||
ARRAY_SIZE(S390_lowcore.stfle_fac_list));
|
||||
memcpy(S390_lowcore.alt_stfle_fac_list,
|
||||
S390_lowcore.stfle_fac_list,
|
||||
sizeof(S390_lowcore.alt_stfle_fac_list));
|
||||
if (!IS_ENABLED(CONFIG_KERNEL_NOBP))
|
||||
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
|
||||
}
|
||||
|
||||
static __init void detect_diag9c(void)
|
||||
|
|
|
@ -104,6 +104,7 @@ _PIF_WORK = (_PIF_PER_TRAP)
|
|||
j 3f
|
||||
1: LAST_BREAK %r14
|
||||
UPDATE_VTIME %r14,%r15,\timer
|
||||
BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
|
||||
2: lg %r15,__LC_ASYNC_STACK # load async stack
|
||||
3: la %r11,STACK_FRAME_OVERHEAD(%r15)
|
||||
.endm
|
||||
|
@ -162,8 +163,137 @@ _PIF_WORK = (_PIF_PER_TRAP)
|
|||
tm off+\addr, \mask
|
||||
.endm
|
||||
|
||||
.macro BPOFF
|
||||
.pushsection .altinstr_replacement, "ax"
|
||||
660: .long 0xb2e8c000
|
||||
.popsection
|
||||
661: .long 0x47000000
|
||||
.pushsection .altinstructions, "a"
|
||||
.long 661b - .
|
||||
.long 660b - .
|
||||
.word 82
|
||||
.byte 4
|
||||
.byte 4
|
||||
.popsection
|
||||
.endm
|
||||
|
||||
.macro BPON
|
||||
.pushsection .altinstr_replacement, "ax"
|
||||
662: .long 0xb2e8d000
|
||||
.popsection
|
||||
663: .long 0x47000000
|
||||
.pushsection .altinstructions, "a"
|
||||
.long 663b - .
|
||||
.long 662b - .
|
||||
.word 82
|
||||
.byte 4
|
||||
.byte 4
|
||||
.popsection
|
||||
.endm
|
||||
|
||||
.macro BPENTER tif_ptr,tif_mask
|
||||
.pushsection .altinstr_replacement, "ax"
|
||||
662: .word 0xc004, 0x0000, 0x0000 # 6 byte nop
|
||||
.word 0xc004, 0x0000, 0x0000 # 6 byte nop
|
||||
.popsection
|
||||
664: TSTMSK \tif_ptr,\tif_mask
|
||||
jz . + 8
|
||||
.long 0xb2e8d000
|
||||
.pushsection .altinstructions, "a"
|
||||
.long 664b - .
|
||||
.long 662b - .
|
||||
.word 82
|
||||
.byte 12
|
||||
.byte 12
|
||||
.popsection
|
||||
.endm
|
||||
|
||||
.macro BPEXIT tif_ptr,tif_mask
|
||||
TSTMSK \tif_ptr,\tif_mask
|
||||
.pushsection .altinstr_replacement, "ax"
|
||||
662: jnz . + 8
|
||||
.long 0xb2e8d000
|
||||
.popsection
|
||||
664: jz . + 8
|
||||
.long 0xb2e8c000
|
||||
.pushsection .altinstructions, "a"
|
||||
.long 664b - .
|
||||
.long 662b - .
|
||||
.word 82
|
||||
.byte 8
|
||||
.byte 8
|
||||
.popsection
|
||||
.endm
|
||||
|
||||
#ifdef CONFIG_EXPOLINE
|
||||
|
||||
.macro GEN_BR_THUNK name,reg,tmp
|
||||
.section .text.\name,"axG",@progbits,\name,comdat
|
||||
.globl \name
|
||||
.hidden \name
|
||||
.type \name,@function
|
||||
\name:
|
||||
.cfi_startproc
|
||||
#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
|
||||
exrl 0,0f
|
||||
#else
|
||||
larl \tmp,0f
|
||||
ex 0,0(\tmp)
|
||||
#endif
|
||||
j .
|
||||
0: br \reg
|
||||
.cfi_endproc
|
||||
.endm
|
||||
|
||||
GEN_BR_THUNK __s390x_indirect_jump_r1use_r9,%r9,%r1
|
||||
GEN_BR_THUNK __s390x_indirect_jump_r1use_r14,%r14,%r1
|
||||
GEN_BR_THUNK __s390x_indirect_jump_r11use_r14,%r14,%r11
|
||||
|
||||
.macro BASR_R14_R9
|
||||
0: brasl %r14,__s390x_indirect_jump_r1use_r9
|
||||
.pushsection .s390_indirect_branches,"a",@progbits
|
||||
.long 0b-.
|
||||
.popsection
|
||||
.endm
|
||||
|
||||
.macro BR_R1USE_R14
|
||||
0: jg __s390x_indirect_jump_r1use_r14
|
||||
.pushsection .s390_indirect_branches,"a",@progbits
|
||||
.long 0b-.
|
||||
.popsection
|
||||
.endm
|
||||
|
||||
.macro BR_R11USE_R14
|
||||
0: jg __s390x_indirect_jump_r11use_r14
|
||||
.pushsection .s390_indirect_branches,"a",@progbits
|
||||
.long 0b-.
|
||||
.popsection
|
||||
.endm
|
||||
|
||||
#else /* CONFIG_EXPOLINE */
|
||||
|
||||
.macro BASR_R14_R9
|
||||
basr %r14,%r9
|
||||
.endm
|
||||
|
||||
.macro BR_R1USE_R14
|
||||
br %r14
|
||||
.endm
|
||||
|
||||
.macro BR_R11USE_R14
|
||||
br %r14
|
||||
.endm
|
||||
|
||||
#endif /* CONFIG_EXPOLINE */
|
||||
|
||||
|
||||
.section .kprobes.text, "ax"
|
||||
|
||||
ENTRY(__bpon)
|
||||
.globl __bpon
|
||||
BPON
|
||||
BR_R1USE_R14
|
||||
|
||||
/*
|
||||
* Scheduler resume function, called by switch_to
|
||||
* gpr2 = (task_struct *) prev
|
||||
|
@ -190,9 +320,9 @@ ENTRY(__switch_to)
|
|||
mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
|
||||
lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task
|
||||
TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_LPP
|
||||
bzr %r14
|
||||
jz 0f
|
||||
.insn s,0xb2800000,__LC_LPP # set program parameter
|
||||
br %r14
|
||||
0: BR_R1USE_R14
|
||||
|
||||
.L__critical_start:
|
||||
|
||||
|
@ -204,9 +334,11 @@ ENTRY(__switch_to)
|
|||
*/
|
||||
ENTRY(sie64a)
|
||||
stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers
|
||||
lg %r12,__LC_CURRENT
|
||||
stg %r2,__SF_EMPTY(%r15) # save control block pointer
|
||||
stg %r3,__SF_EMPTY+8(%r15) # save guest register save area
|
||||
xc __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # reason code = 0
|
||||
mvc __SF_EMPTY+24(8,%r15),__TI_flags(%r12) # copy thread flags
|
||||
TSTMSK __LC_CPU_FLAGS,_CIF_FPU # load guest fp/vx registers ?
|
||||
jno .Lsie_load_guest_gprs
|
||||
brasl %r14,load_fpu_regs # load guest fp/vx regs
|
||||
|
@ -223,7 +355,11 @@ ENTRY(sie64a)
|
|||
jnz .Lsie_skip
|
||||
TSTMSK __LC_CPU_FLAGS,_CIF_FPU
|
||||
jo .Lsie_skip # exit if fp/vx regs changed
|
||||
BPEXIT __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
|
||||
sie 0(%r14)
|
||||
.Lsie_exit:
|
||||
BPOFF
|
||||
BPENTER __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
|
||||
.Lsie_skip:
|
||||
ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE
|
||||
lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
|
||||
|
@ -244,9 +380,15 @@ ENTRY(sie64a)
|
|||
sie_exit:
|
||||
lg %r14,__SF_EMPTY+8(%r15) # load guest register save area
|
||||
stmg %r0,%r13,0(%r14) # save guest gprs 0-13
|
||||
xgr %r0,%r0 # clear guest registers to
|
||||
xgr %r1,%r1 # prevent speculative use
|
||||
xgr %r2,%r2
|
||||
xgr %r3,%r3
|
||||
xgr %r4,%r4
|
||||
xgr %r5,%r5
|
||||
lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
|
||||
lg %r2,__SF_EMPTY+16(%r15) # return exit reason code
|
||||
br %r14
|
||||
BR_R1USE_R14
|
||||
.Lsie_fault:
|
||||
lghi %r14,-EFAULT
|
||||
stg %r14,__SF_EMPTY+16(%r15) # set exit reason code
|
||||
|
@ -267,6 +409,7 @@ ENTRY(system_call)
|
|||
stpt __LC_SYNC_ENTER_TIMER
|
||||
.Lsysc_stmg:
|
||||
stmg %r8,%r15,__LC_SAVE_AREA_SYNC
|
||||
BPOFF
|
||||
lg %r10,__LC_LAST_BREAK
|
||||
lg %r12,__LC_THREAD_INFO
|
||||
lghi %r14,_PIF_SYSCALL
|
||||
|
@ -276,12 +419,15 @@ ENTRY(system_call)
|
|||
LAST_BREAK %r13
|
||||
.Lsysc_vtime:
|
||||
UPDATE_VTIME %r10,%r13,__LC_SYNC_ENTER_TIMER
|
||||
BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
|
||||
stmg %r0,%r7,__PT_R0(%r11)
|
||||
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
|
||||
mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW
|
||||
mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC
|
||||
stg %r14,__PT_FLAGS(%r11)
|
||||
.Lsysc_do_svc:
|
||||
# clear user controlled register to prevent speculative use
|
||||
xgr %r0,%r0
|
||||
lg %r10,__TI_sysc_table(%r12) # address of system call table
|
||||
llgh %r8,__PT_INT_CODE+2(%r11)
|
||||
slag %r8,%r8,2 # shift and test for svc 0
|
||||
|
@ -299,7 +445,7 @@ ENTRY(system_call)
|
|||
lgf %r9,0(%r8,%r10) # get system call add.
|
||||
TSTMSK __TI_flags(%r12),_TIF_TRACE
|
||||
jnz .Lsysc_tracesys
|
||||
basr %r14,%r9 # call sys_xxxx
|
||||
BASR_R14_R9 # call sys_xxxx
|
||||
stg %r2,__PT_R2(%r11) # store return value
|
||||
|
||||
.Lsysc_return:
|
||||
|
@ -311,6 +457,7 @@ ENTRY(system_call)
|
|||
jnz .Lsysc_work # check for work
|
||||
TSTMSK __LC_CPU_FLAGS,_CIF_WORK
|
||||
jnz .Lsysc_work
|
||||
BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP
|
||||
.Lsysc_restore:
|
||||
lg %r14,__LC_VDSO_PER_CPU
|
||||
lmg %r0,%r10,__PT_R0(%r11)
|
||||
|
@ -438,7 +585,7 @@ ENTRY(system_call)
|
|||
lmg %r3,%r7,__PT_R3(%r11)
|
||||
stg %r7,STACK_FRAME_OVERHEAD(%r15)
|
||||
lg %r2,__PT_ORIG_GPR2(%r11)
|
||||
basr %r14,%r9 # call sys_xxx
|
||||
BASR_R14_R9 # call sys_xxx
|
||||
stg %r2,__PT_R2(%r11) # store return value
|
||||
.Lsysc_tracenogo:
|
||||
TSTMSK __TI_flags(%r12),_TIF_TRACE
|
||||
|
@ -462,7 +609,7 @@ ENTRY(ret_from_fork)
|
|||
lmg %r9,%r10,__PT_R9(%r11) # load gprs
|
||||
ENTRY(kernel_thread_starter)
|
||||
la %r2,0(%r10)
|
||||
basr %r14,%r9
|
||||
BASR_R14_R9
|
||||
j .Lsysc_tracenogo
|
||||
|
||||
/*
|
||||
|
@ -471,6 +618,7 @@ ENTRY(kernel_thread_starter)
|
|||
|
||||
ENTRY(pgm_check_handler)
|
||||
stpt __LC_SYNC_ENTER_TIMER
|
||||
BPOFF
|
||||
stmg %r8,%r15,__LC_SAVE_AREA_SYNC
|
||||
lg %r10,__LC_LAST_BREAK
|
||||
lg %r12,__LC_THREAD_INFO
|
||||
|
@ -495,6 +643,7 @@ ENTRY(pgm_check_handler)
|
|||
j 3f
|
||||
2: LAST_BREAK %r14
|
||||
UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER
|
||||
BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
|
||||
lg %r15,__LC_KERNEL_STACK
|
||||
lg %r14,__TI_task(%r12)
|
||||
aghi %r14,__TASK_thread # pointer to thread_struct
|
||||
|
@ -504,6 +653,15 @@ ENTRY(pgm_check_handler)
|
|||
mvc __THREAD_trap_tdb(256,%r14),0(%r13)
|
||||
3: la %r11,STACK_FRAME_OVERHEAD(%r15)
|
||||
stmg %r0,%r7,__PT_R0(%r11)
|
||||
# clear user controlled registers to prevent speculative use
|
||||
xgr %r0,%r0
|
||||
xgr %r1,%r1
|
||||
xgr %r2,%r2
|
||||
xgr %r3,%r3
|
||||
xgr %r4,%r4
|
||||
xgr %r5,%r5
|
||||
xgr %r6,%r6
|
||||
xgr %r7,%r7
|
||||
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
|
||||
stmg %r8,%r9,__PT_PSW(%r11)
|
||||
mvc __PT_INT_CODE(4,%r11),__LC_PGM_ILC
|
||||
|
@ -525,9 +683,9 @@ ENTRY(pgm_check_handler)
|
|||
nill %r10,0x007f
|
||||
sll %r10,2
|
||||
je .Lpgm_return
|
||||
lgf %r1,0(%r10,%r1) # load address of handler routine
|
||||
lgf %r9,0(%r10,%r1) # load address of handler routine
|
||||
lgr %r2,%r11 # pass pointer to pt_regs
|
||||
basr %r14,%r1 # branch to interrupt-handler
|
||||
BASR_R14_R9 # branch to interrupt-handler
|
||||
.Lpgm_return:
|
||||
LOCKDEP_SYS_EXIT
|
||||
tm __PT_PSW+1(%r11),0x01 # returning to user ?
|
||||
|
@ -560,6 +718,7 @@ ENTRY(pgm_check_handler)
|
|||
ENTRY(io_int_handler)
|
||||
STCK __LC_INT_CLOCK
|
||||
stpt __LC_ASYNC_ENTER_TIMER
|
||||
BPOFF
|
||||
stmg %r8,%r15,__LC_SAVE_AREA_ASYNC
|
||||
lg %r10,__LC_LAST_BREAK
|
||||
lg %r12,__LC_THREAD_INFO
|
||||
|
@ -567,6 +726,16 @@ ENTRY(io_int_handler)
|
|||
lmg %r8,%r9,__LC_IO_OLD_PSW
|
||||
SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER
|
||||
stmg %r0,%r7,__PT_R0(%r11)
|
||||
# clear user controlled registers to prevent speculative use
|
||||
xgr %r0,%r0
|
||||
xgr %r1,%r1
|
||||
xgr %r2,%r2
|
||||
xgr %r3,%r3
|
||||
xgr %r4,%r4
|
||||
xgr %r5,%r5
|
||||
xgr %r6,%r6
|
||||
xgr %r7,%r7
|
||||
xgr %r10,%r10
|
||||
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
|
||||
stmg %r8,%r9,__PT_PSW(%r11)
|
||||
mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
|
||||
|
@ -601,9 +770,13 @@ ENTRY(io_int_handler)
|
|||
lg %r14,__LC_VDSO_PER_CPU
|
||||
lmg %r0,%r10,__PT_R0(%r11)
|
||||
mvc __LC_RETURN_PSW(16),__PT_PSW(%r11)
|
||||
tm __PT_PSW+1(%r11),0x01 # returning to user ?
|
||||
jno .Lio_exit_kernel
|
||||
BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP
|
||||
.Lio_exit_timer:
|
||||
stpt __LC_EXIT_TIMER
|
||||
mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
|
||||
.Lio_exit_kernel:
|
||||
lmg %r11,%r15,__PT_R11(%r11)
|
||||
lpswe __LC_RETURN_PSW
|
||||
.Lio_done:
|
||||
|
@ -735,6 +908,7 @@ ENTRY(io_int_handler)
|
|||
ENTRY(ext_int_handler)
|
||||
STCK __LC_INT_CLOCK
|
||||
stpt __LC_ASYNC_ENTER_TIMER
|
||||
BPOFF
|
||||
stmg %r8,%r15,__LC_SAVE_AREA_ASYNC
|
||||
lg %r10,__LC_LAST_BREAK
|
||||
lg %r12,__LC_THREAD_INFO
|
||||
|
@ -742,6 +916,16 @@ ENTRY(ext_int_handler)
|
|||
lmg %r8,%r9,__LC_EXT_OLD_PSW
|
||||
SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER
|
||||
stmg %r0,%r7,__PT_R0(%r11)
|
||||
# clear user controlled registers to prevent speculative use
|
||||
xgr %r0,%r0
|
||||
xgr %r1,%r1
|
||||
xgr %r2,%r2
|
||||
xgr %r3,%r3
|
||||
xgr %r4,%r4
|
||||
xgr %r5,%r5
|
||||
xgr %r6,%r6
|
||||
xgr %r7,%r7
|
||||
xgr %r10,%r10
|
||||
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
|
||||
stmg %r8,%r9,__PT_PSW(%r11)
|
||||
lghi %r1,__LC_EXT_PARAMS2
|
||||
|
@ -773,11 +957,12 @@ ENTRY(psw_idle)
|
|||
.insn rsy,0xeb0000000017,%r1,5,__SF_EMPTY+16(%r15)
|
||||
.Lpsw_idle_stcctm:
|
||||
#endif
|
||||
BPON
|
||||
STCK __CLOCK_IDLE_ENTER(%r2)
|
||||
stpt __TIMER_IDLE_ENTER(%r2)
|
||||
.Lpsw_idle_lpsw:
|
||||
lpswe __SF_EMPTY(%r15)
|
||||
br %r14
|
||||
BR_R1USE_R14
|
||||
.Lpsw_idle_end:
|
||||
|
||||
/*
|
||||
|
@ -791,7 +976,7 @@ ENTRY(save_fpu_regs)
|
|||
lg %r2,__LC_CURRENT
|
||||
aghi %r2,__TASK_thread
|
||||
TSTMSK __LC_CPU_FLAGS,_CIF_FPU
|
||||
bor %r14
|
||||
jo .Lsave_fpu_regs_exit
|
||||
stfpc __THREAD_FPU_fpc(%r2)
|
||||
.Lsave_fpu_regs_fpc_end:
|
||||
lg %r3,__THREAD_FPU_regs(%r2)
|
||||
|
@ -821,7 +1006,8 @@ ENTRY(save_fpu_regs)
|
|||
std 15,120(%r3)
|
||||
.Lsave_fpu_regs_done:
|
||||
oi __LC_CPU_FLAGS+7,_CIF_FPU
|
||||
br %r14
|
||||
.Lsave_fpu_regs_exit:
|
||||
BR_R1USE_R14
|
||||
.Lsave_fpu_regs_end:
|
||||
|
||||
/*
|
||||
|
@ -838,7 +1024,7 @@ load_fpu_regs:
|
|||
lg %r4,__LC_CURRENT
|
||||
aghi %r4,__TASK_thread
|
||||
TSTMSK __LC_CPU_FLAGS,_CIF_FPU
|
||||
bnor %r14
|
||||
jno .Lload_fpu_regs_exit
|
||||
lfpc __THREAD_FPU_fpc(%r4)
|
||||
TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
|
||||
lg %r4,__THREAD_FPU_regs(%r4) # %r4 <- reg save area
|
||||
|
@ -867,7 +1053,8 @@ load_fpu_regs:
|
|||
ld 15,120(%r4)
|
||||
.Lload_fpu_regs_done:
|
||||
ni __LC_CPU_FLAGS+7,255-_CIF_FPU
|
||||
br %r14
|
||||
.Lload_fpu_regs_exit:
|
||||
BR_R1USE_R14
|
||||
.Lload_fpu_regs_end:
|
||||
|
||||
.L__critical_end:
|
||||
|
@ -877,6 +1064,7 @@ load_fpu_regs:
|
|||
*/
|
||||
ENTRY(mcck_int_handler)
|
||||
STCK __LC_MCCK_CLOCK
|
||||
BPOFF
|
||||
la %r1,4095 # revalidate r1
|
||||
spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer
|
||||
lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
|
||||
|
@ -908,6 +1096,16 @@ ENTRY(mcck_int_handler)
|
|||
.Lmcck_skip:
|
||||
lghi %r14,__LC_GPREGS_SAVE_AREA+64
|
||||
stmg %r0,%r7,__PT_R0(%r11)
|
||||
# clear user controlled registers to prevent speculative use
|
||||
xgr %r0,%r0
|
||||
xgr %r1,%r1
|
||||
xgr %r2,%r2
|
||||
xgr %r3,%r3
|
||||
xgr %r4,%r4
|
||||
xgr %r5,%r5
|
||||
xgr %r6,%r6
|
||||
xgr %r7,%r7
|
||||
xgr %r10,%r10
|
||||
mvc __PT_R8(64,%r11),0(%r14)
|
||||
stmg %r8,%r9,__PT_PSW(%r11)
|
||||
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
|
||||
|
@ -933,6 +1131,7 @@ ENTRY(mcck_int_handler)
|
|||
mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW
|
||||
tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
|
||||
jno 0f
|
||||
BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP
|
||||
stpt __LC_EXIT_TIMER
|
||||
mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
|
||||
0: lmg %r11,%r15,__PT_R11(%r11)
|
||||
|
@ -1028,7 +1227,7 @@ cleanup_critical:
|
|||
jl 0f
|
||||
clg %r9,BASED(.Lcleanup_table+104) # .Lload_fpu_regs_end
|
||||
jl .Lcleanup_load_fpu_regs
|
||||
0: br %r14
|
||||
0: BR_R11USE_R14
|
||||
|
||||
.align 8
|
||||
.Lcleanup_table:
|
||||
|
@ -1053,11 +1252,12 @@ cleanup_critical:
|
|||
.quad .Lsie_done
|
||||
|
||||
.Lcleanup_sie:
|
||||
BPENTER __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
|
||||
lg %r9,__SF_EMPTY(%r15) # get control block pointer
|
||||
ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE
|
||||
lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
|
||||
larl %r9,sie_exit # skip forward to sie_exit
|
||||
br %r14
|
||||
BR_R11USE_R14
|
||||
#endif
|
||||
|
||||
.Lcleanup_system_call:
|
||||
|
@ -1099,7 +1299,8 @@ cleanup_critical:
|
|||
srag %r9,%r9,23
|
||||
jz 0f
|
||||
mvc __TI_last_break(8,%r12),16(%r11)
|
||||
0: # set up saved register r11
|
||||
0: BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
|
||||
# set up saved register r11
|
||||
lg %r15,__LC_KERNEL_STACK
|
||||
la %r9,STACK_FRAME_OVERHEAD(%r15)
|
||||
stg %r9,24(%r11) # r11 pt_regs pointer
|
||||
|
@ -1114,7 +1315,7 @@ cleanup_critical:
|
|||
stg %r15,56(%r11) # r15 stack pointer
|
||||
# set new psw address and exit
|
||||
larl %r9,.Lsysc_do_svc
|
||||
br %r14
|
||||
BR_R11USE_R14
|
||||
.Lcleanup_system_call_insn:
|
||||
.quad system_call
|
||||
.quad .Lsysc_stmg
|
||||
|
@ -1124,7 +1325,7 @@ cleanup_critical:
|
|||
|
||||
.Lcleanup_sysc_tif:
|
||||
larl %r9,.Lsysc_tif
|
||||
br %r14
|
||||
BR_R11USE_R14
|
||||
|
||||
.Lcleanup_sysc_restore:
|
||||
# check if stpt has been executed
|
||||
|
@ -1141,14 +1342,14 @@ cleanup_critical:
|
|||
mvc 0(64,%r11),__PT_R8(%r9)
|
||||
lmg %r0,%r7,__PT_R0(%r9)
|
||||
1: lmg %r8,%r9,__LC_RETURN_PSW
|
||||
br %r14
|
||||
BR_R11USE_R14
|
||||
.Lcleanup_sysc_restore_insn:
|
||||
.quad .Lsysc_exit_timer
|
||||
.quad .Lsysc_done - 4
|
||||
|
||||
.Lcleanup_io_tif:
|
||||
larl %r9,.Lio_tif
|
||||
br %r14
|
||||
BR_R11USE_R14
|
||||
|
||||
.Lcleanup_io_restore:
|
||||
# check if stpt has been executed
|
||||
|
@ -1162,7 +1363,7 @@ cleanup_critical:
|
|||
mvc 0(64,%r11),__PT_R8(%r9)
|
||||
lmg %r0,%r7,__PT_R0(%r9)
|
||||
1: lmg %r8,%r9,__LC_RETURN_PSW
|
||||
br %r14
|
||||
BR_R11USE_R14
|
||||
.Lcleanup_io_restore_insn:
|
||||
.quad .Lio_exit_timer
|
||||
.quad .Lio_done - 4
|
||||
|
@ -1214,17 +1415,17 @@ cleanup_critical:
|
|||
# prepare return psw
|
||||
nihh %r8,0xfcfd # clear irq & wait state bits
|
||||
lg %r9,48(%r11) # return from psw_idle
|
||||
br %r14
|
||||
BR_R11USE_R14
|
||||
.Lcleanup_idle_insn:
|
||||
.quad .Lpsw_idle_lpsw
|
||||
|
||||
.Lcleanup_save_fpu_regs:
|
||||
larl %r9,save_fpu_regs
|
||||
br %r14
|
||||
BR_R11USE_R14
|
||||
|
||||
.Lcleanup_load_fpu_regs:
|
||||
larl %r9,load_fpu_regs
|
||||
br %r14
|
||||
BR_R11USE_R14
|
||||
|
||||
/*
|
||||
* Integer constants
|
||||
|
@ -1240,7 +1441,6 @@ cleanup_critical:
|
|||
.Lsie_critical_length:
|
||||
.quad .Lsie_done - .Lsie_gmap
|
||||
#endif
|
||||
|
||||
.section .rodata, "a"
|
||||
#define SYSCALL(esame,emu) .long esame
|
||||
.globl sys_call_table
|
||||
|
|
|
@ -563,6 +563,7 @@ static struct kset *ipl_kset;
|
|||
|
||||
static void __ipl_run(void *unused)
|
||||
{
|
||||
__bpon();
|
||||
diag308(DIAG308_IPL, NULL);
|
||||
if (MACHINE_IS_VM)
|
||||
__cpcmd("IPL", NULL, 0, NULL);
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/moduleloader.h>
|
||||
#include <linux/bug.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/facility.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
|
@ -163,7 +166,11 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
|||
me->arch.got_offset = me->core_size;
|
||||
me->core_size += me->arch.got_size;
|
||||
me->arch.plt_offset = me->core_size;
|
||||
me->core_size += me->arch.plt_size;
|
||||
if (me->arch.plt_size) {
|
||||
if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable)
|
||||
me->arch.plt_size += PLT_ENTRY_SIZE;
|
||||
me->core_size += me->arch.plt_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -317,9 +324,20 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
|
|||
unsigned int *ip;
|
||||
ip = me->module_core + me->arch.plt_offset +
|
||||
info->plt_offset;
|
||||
ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
|
||||
ip[1] = 0x100a0004;
|
||||
ip[2] = 0x07f10000;
|
||||
ip[0] = 0x0d10e310; /* basr 1,0 */
|
||||
ip[1] = 0x100a0004; /* lg 1,10(1) */
|
||||
if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) {
|
||||
unsigned int *ij;
|
||||
ij = me->module_core +
|
||||
me->arch.plt_offset +
|
||||
me->arch.plt_size - PLT_ENTRY_SIZE;
|
||||
ip[2] = 0xa7f40000 + /* j __jump_r1 */
|
||||
(unsigned int)(u16)
|
||||
(((unsigned long) ij - 8 -
|
||||
(unsigned long) ip) / 2);
|
||||
} else {
|
||||
ip[2] = 0x07f10000; /* br %r1 */
|
||||
}
|
||||
ip[3] = (unsigned int) (val >> 32);
|
||||
ip[4] = (unsigned int) val;
|
||||
info->plt_initialized = 1;
|
||||
|
@ -424,6 +442,45 @@ int module_finalize(const Elf_Ehdr *hdr,
|
|||
const Elf_Shdr *sechdrs,
|
||||
struct module *me)
|
||||
{
|
||||
const Elf_Shdr *s;
|
||||
char *secstrings, *secname;
|
||||
void *aseg;
|
||||
|
||||
if (IS_ENABLED(CONFIG_EXPOLINE) &&
|
||||
!nospec_disable && me->arch.plt_size) {
|
||||
unsigned int *ij;
|
||||
|
||||
ij = me->module_core + me->arch.plt_offset +
|
||||
me->arch.plt_size - PLT_ENTRY_SIZE;
|
||||
if (test_facility(35)) {
|
||||
ij[0] = 0xc6000000; /* exrl %r0,.+10 */
|
||||
ij[1] = 0x0005a7f4; /* j . */
|
||||
ij[2] = 0x000007f1; /* br %r1 */
|
||||
} else {
|
||||
ij[0] = 0x44000000 | (unsigned int)
|
||||
offsetof(struct _lowcore, br_r1_trampoline);
|
||||
ij[1] = 0xa7f40000; /* j . */
|
||||
}
|
||||
}
|
||||
|
||||
secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
|
||||
for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
|
||||
aseg = (void *) s->sh_addr;
|
||||
secname = secstrings + s->sh_name;
|
||||
|
||||
if (!strcmp(".altinstructions", secname))
|
||||
/* patch .altinstructions */
|
||||
apply_alternatives(aseg, aseg + s->sh_size);
|
||||
|
||||
if (IS_ENABLED(CONFIG_EXPOLINE) &&
|
||||
(!strncmp(".s390_indirect", secname, 14)))
|
||||
nospec_revert(aseg, aseg + s->sh_size);
|
||||
|
||||
if (IS_ENABLED(CONFIG_EXPOLINE) &&
|
||||
(!strncmp(".s390_return", secname, 12)))
|
||||
nospec_revert(aseg, aseg + s->sh_size);
|
||||
}
|
||||
|
||||
jump_label_apply_nops(me);
|
||||
vfree(me->arch.syminfo);
|
||||
me->arch.syminfo = NULL;
|
||||
|
|
169
arch/s390/kernel/nospec-branch.c
Normal file
169
arch/s390/kernel/nospec-branch.c
Normal file
|
@ -0,0 +1,169 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <asm/facility.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
|
||||
static int __init nobp_setup_early(char *str)
|
||||
{
|
||||
bool enabled;
|
||||
int rc;
|
||||
|
||||
rc = kstrtobool(str, &enabled);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (enabled && test_facility(82)) {
|
||||
/*
|
||||
* The user explicitely requested nobp=1, enable it and
|
||||
* disable the expoline support.
|
||||
*/
|
||||
__set_facility(82, S390_lowcore.alt_stfle_fac_list);
|
||||
if (IS_ENABLED(CONFIG_EXPOLINE))
|
||||
nospec_disable = 1;
|
||||
} else {
|
||||
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
early_param("nobp", nobp_setup_early);
|
||||
|
||||
static int __init nospec_setup_early(char *str)
|
||||
{
|
||||
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
|
||||
return 0;
|
||||
}
|
||||
early_param("nospec", nospec_setup_early);
|
||||
|
||||
static int __init nospec_report(void)
|
||||
{
|
||||
if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable)
|
||||
pr_info("Spectre V2 mitigation: execute trampolines.\n");
|
||||
if (__test_facility(82, S390_lowcore.alt_stfle_fac_list))
|
||||
pr_info("Spectre V2 mitigation: limited branch prediction.\n");
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(nospec_report);
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
ssize_t cpu_show_spectre_v1(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "Mitigation: __user pointer sanitization\n");
|
||||
}
|
||||
|
||||
ssize_t cpu_show_spectre_v2(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable)
|
||||
return sprintf(buf, "Mitigation: execute trampolines\n");
|
||||
if (__test_facility(82, S390_lowcore.alt_stfle_fac_list))
|
||||
return sprintf(buf, "Mitigation: limited branch prediction.\n");
|
||||
return sprintf(buf, "Vulnerable\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EXPOLINE
|
||||
|
||||
int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF);
|
||||
|
||||
static int __init nospectre_v2_setup_early(char *str)
|
||||
{
|
||||
nospec_disable = 1;
|
||||
return 0;
|
||||
}
|
||||
early_param("nospectre_v2", nospectre_v2_setup_early);
|
||||
|
||||
void __init nospec_auto_detect(void)
|
||||
{
|
||||
if (IS_ENABLED(CC_USING_EXPOLINE)) {
|
||||
/*
|
||||
* The kernel has been compiled with expolines.
|
||||
* Keep expolines enabled and disable nobp.
|
||||
*/
|
||||
nospec_disable = 0;
|
||||
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
|
||||
}
|
||||
/*
|
||||
* If the kernel has not been compiled with expolines the
|
||||
* nobp setting decides what is done, this depends on the
|
||||
* CONFIG_KERNEL_NP option and the nobp/nospec parameters.
|
||||
*/
|
||||
}
|
||||
|
||||
static int __init spectre_v2_setup_early(char *str)
|
||||
{
|
||||
if (str && !strncmp(str, "on", 2)) {
|
||||
nospec_disable = 0;
|
||||
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
|
||||
}
|
||||
if (str && !strncmp(str, "off", 3))
|
||||
nospec_disable = 1;
|
||||
if (str && !strncmp(str, "auto", 4))
|
||||
nospec_auto_detect();
|
||||
return 0;
|
||||
}
|
||||
early_param("spectre_v2", spectre_v2_setup_early);
|
||||
|
||||
static void __init_or_module __nospec_revert(s32 *start, s32 *end)
|
||||
{
|
||||
enum { BRCL_EXPOLINE, BRASL_EXPOLINE } type;
|
||||
u8 *instr, *thunk, *br;
|
||||
u8 insnbuf[6];
|
||||
s32 *epo;
|
||||
|
||||
/* Second part of the instruction replace is always a nop */
|
||||
memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x00, 0x00 }, 4);
|
||||
for (epo = start; epo < end; epo++) {
|
||||
instr = (u8 *) epo + *epo;
|
||||
if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x04)
|
||||
type = BRCL_EXPOLINE; /* brcl instruction */
|
||||
else if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x05)
|
||||
type = BRASL_EXPOLINE; /* brasl instruction */
|
||||
else
|
||||
continue;
|
||||
thunk = instr + (*(int *)(instr + 2)) * 2;
|
||||
if (thunk[0] == 0xc6 && thunk[1] == 0x00)
|
||||
/* exrl %r0,<target-br> */
|
||||
br = thunk + (*(int *)(thunk + 2)) * 2;
|
||||
else if (thunk[0] == 0xc0 && (thunk[1] & 0x0f) == 0x00 &&
|
||||
thunk[6] == 0x44 && thunk[7] == 0x00 &&
|
||||
(thunk[8] & 0x0f) == 0x00 && thunk[9] == 0x00 &&
|
||||
(thunk[1] & 0xf0) == (thunk[8] & 0xf0))
|
||||
/* larl %rx,<target br> + ex %r0,0(%rx) */
|
||||
br = thunk + (*(int *)(thunk + 2)) * 2;
|
||||
else
|
||||
continue;
|
||||
if (br[0] != 0x07 || (br[1] & 0xf0) != 0xf0)
|
||||
continue;
|
||||
switch (type) {
|
||||
case BRCL_EXPOLINE:
|
||||
/* brcl to thunk, replace with br + nop */
|
||||
insnbuf[0] = br[0];
|
||||
insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
|
||||
break;
|
||||
case BRASL_EXPOLINE:
|
||||
/* brasl to thunk, replace with basr + nop */
|
||||
insnbuf[0] = 0x0d;
|
||||
insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
|
||||
break;
|
||||
}
|
||||
|
||||
s390_kernel_write(instr, insnbuf, 6);
|
||||
}
|
||||
}
|
||||
|
||||
void __init_or_module nospec_revert(s32 *start, s32 *end)
|
||||
{
|
||||
if (nospec_disable)
|
||||
__nospec_revert(start, end);
|
||||
}
|
||||
|
||||
extern s32 __nospec_call_start[], __nospec_call_end[];
|
||||
extern s32 __nospec_return_start[], __nospec_return_end[];
|
||||
void __init nospec_init_branches(void)
|
||||
{
|
||||
nospec_revert(__nospec_call_start, __nospec_call_end);
|
||||
nospec_revert(__nospec_return_start, __nospec_return_end);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_EXPOLINE */
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/cpu.h>
|
||||
#include <asm/diag.h>
|
||||
#include <asm/elf.h>
|
||||
#include <asm/facility.h>
|
||||
#include <asm/lowcore.h>
|
||||
#include <asm/param.h>
|
||||
#include <asm/smp.h>
|
||||
|
@ -113,3 +114,20 @@ const struct seq_operations cpuinfo_op = {
|
|||
.show = show_cpuinfo,
|
||||
};
|
||||
|
||||
int s390_isolate_bp(void)
|
||||
{
|
||||
if (!test_facility(82))
|
||||
return -EOPNOTSUPP;
|
||||
set_thread_flag(TIF_ISOLATE_BP);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(s390_isolate_bp);
|
||||
|
||||
int s390_isolate_bp_guest(void)
|
||||
{
|
||||
if (!test_facility(82))
|
||||
return -EOPNOTSUPP;
|
||||
set_thread_flag(TIF_ISOLATE_BP_GUEST);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(s390_isolate_bp_guest);
|
||||
|
|
|
@ -63,6 +63,8 @@
|
|||
#include <asm/sclp.h>
|
||||
#include <asm/sysinfo.h>
|
||||
#include <asm/numa.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include "entry.h"
|
||||
|
||||
/*
|
||||
|
@ -333,7 +335,9 @@ static void __init setup_lowcore(void)
|
|||
lc->machine_flags = S390_lowcore.machine_flags;
|
||||
lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
|
||||
memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
|
||||
MAX_FACILITY_BIT/8);
|
||||
sizeof(lc->stfle_fac_list));
|
||||
memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list,
|
||||
sizeof(lc->alt_stfle_fac_list));
|
||||
if (MACHINE_HAS_VX)
|
||||
lc->vector_save_area_addr =
|
||||
(unsigned long) &lc->vector_save_area;
|
||||
|
@ -370,6 +374,7 @@ static void __init setup_lowcore(void)
|
|||
#ifdef CONFIG_SMP
|
||||
lc->spinlock_lockval = arch_spin_lockval(0);
|
||||
#endif
|
||||
lc->br_r1_trampoline = 0x07f1; /* br %r1 */
|
||||
|
||||
set_prefix((u32)(unsigned long) lc);
|
||||
lowcore_ptr[0] = lc;
|
||||
|
@ -841,6 +846,9 @@ void __init setup_arch(char **cmdline_p)
|
|||
init_mm.end_data = (unsigned long) &_edata;
|
||||
init_mm.brk = (unsigned long) &_end;
|
||||
|
||||
if (IS_ENABLED(CONFIG_EXPOLINE_AUTO))
|
||||
nospec_auto_detect();
|
||||
|
||||
parse_early_param();
|
||||
os_info_init();
|
||||
setup_ipl();
|
||||
|
@ -893,6 +901,10 @@ void __init setup_arch(char **cmdline_p)
|
|||
conmode_default();
|
||||
set_preferred_console();
|
||||
|
||||
apply_alternative_instructions();
|
||||
if (IS_ENABLED(CONFIG_EXPOLINE))
|
||||
nospec_init_branches();
|
||||
|
||||
/* Setup zfcpdump support */
|
||||
setup_zfcpdump();
|
||||
|
||||
|
|
|
@ -200,6 +200,7 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
|
|||
lc->panic_stack = panic_stack + PANIC_FRAME_OFFSET;
|
||||
lc->cpu_nr = cpu;
|
||||
lc->spinlock_lockval = arch_spin_lockval(cpu);
|
||||
lc->br_r1_trampoline = 0x07f1; /* br %r1 */
|
||||
if (MACHINE_HAS_VX)
|
||||
lc->vector_save_area_addr =
|
||||
(unsigned long) &lc->vector_save_area;
|
||||
|
@ -250,7 +251,9 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
|
|||
__ctl_store(lc->cregs_save_area, 0, 15);
|
||||
save_access_regs((unsigned int *) lc->access_regs_save_area);
|
||||
memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
|
||||
MAX_FACILITY_BIT/8);
|
||||
sizeof(lc->stfle_fac_list));
|
||||
memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list,
|
||||
sizeof(lc->alt_stfle_fac_list));
|
||||
}
|
||||
|
||||
static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)
|
||||
|
@ -299,6 +302,7 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *),
|
|||
mem_assign_absolute(lc->restart_fn, (unsigned long) func);
|
||||
mem_assign_absolute(lc->restart_data, (unsigned long) data);
|
||||
mem_assign_absolute(lc->restart_source, source_cpu);
|
||||
__bpon();
|
||||
asm volatile(
|
||||
"0: sigp 0,%0,%2 # sigp restart to target cpu\n"
|
||||
" brc 2,0b # busy, try again\n"
|
||||
|
@ -888,6 +892,7 @@ void __cpu_die(unsigned int cpu)
|
|||
void __noreturn cpu_die(void)
|
||||
{
|
||||
idle_task_exit();
|
||||
__bpon();
|
||||
pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0);
|
||||
for (;;) ;
|
||||
}
|
||||
|
|
|
@ -147,6 +147,15 @@ unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline,
|
|||
return orig;
|
||||
}
|
||||
|
||||
bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
if (ctx == RP_CHECK_CHAIN_CALL)
|
||||
return user_stack_pointer(regs) <= ret->stack;
|
||||
else
|
||||
return user_stack_pointer(regs) < ret->stack;
|
||||
}
|
||||
|
||||
/* Instruction Emulation */
|
||||
|
||||
static void adjust_psw_addr(psw_t *psw, unsigned long len)
|
||||
|
|
|
@ -79,6 +79,43 @@ SECTIONS
|
|||
EXIT_DATA
|
||||
}
|
||||
|
||||
/*
|
||||
* struct alt_inst entries. From the header (alternative.h):
|
||||
* "Alternative instructions for different CPU types or capabilities"
|
||||
* Think locking instructions on spinlocks.
|
||||
* Note, that it is a part of __init region.
|
||||
*/
|
||||
. = ALIGN(8);
|
||||
.altinstructions : {
|
||||
__alt_instructions = .;
|
||||
*(.altinstructions)
|
||||
__alt_instructions_end = .;
|
||||
}
|
||||
|
||||
/*
|
||||
* And here are the replacement instructions. The linker sticks
|
||||
* them as binary blobs. The .altinstructions has enough data to
|
||||
* get the address and the length of them to patch the kernel safely.
|
||||
* Note, that it is a part of __init region.
|
||||
*/
|
||||
.altinstr_replacement : {
|
||||
*(.altinstr_replacement)
|
||||
}
|
||||
|
||||
/*
|
||||
* Table with the patch locations to undo expolines
|
||||
*/
|
||||
.nospec_call_table : {
|
||||
__nospec_call_start = . ;
|
||||
*(.s390_indirect*)
|
||||
__nospec_call_end = . ;
|
||||
}
|
||||
.nospec_return_table : {
|
||||
__nospec_return_start = . ;
|
||||
*(.s390_return*)
|
||||
__nospec_return_end = . ;
|
||||
}
|
||||
|
||||
/* early.c uses stsi, which requires page aligned data. */
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
INIT_DATA_SECTION(0x100)
|
||||
|
|
|
@ -257,6 +257,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||
case KVM_CAP_S390_VECTOR_REGISTERS:
|
||||
r = MACHINE_HAS_VX;
|
||||
break;
|
||||
case KVM_CAP_S390_BPB:
|
||||
r = test_facility(82);
|
||||
break;
|
||||
default:
|
||||
r = 0;
|
||||
}
|
||||
|
@ -1264,6 +1267,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
|
|||
KVM_SYNC_PFAULT;
|
||||
if (test_kvm_facility(vcpu->kvm, 129))
|
||||
vcpu->run->kvm_valid_regs |= KVM_SYNC_VRS;
|
||||
if (test_kvm_facility(vcpu->kvm, 82))
|
||||
vcpu->run->kvm_valid_regs |= KVM_SYNC_BPBC;
|
||||
|
||||
if (kvm_is_ucontrol(vcpu->kvm))
|
||||
return __kvm_ucontrol_vcpu_init(vcpu);
|
||||
|
@ -1327,6 +1332,7 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
|
|||
current->thread.fpu.fpc = 0;
|
||||
vcpu->arch.sie_block->gbea = 1;
|
||||
vcpu->arch.sie_block->pp = 0;
|
||||
vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
|
||||
vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
|
||||
kvm_clear_async_pf_completion_queue(vcpu);
|
||||
if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
|
||||
|
@ -2145,6 +2151,11 @@ static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
|||
if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID)
|
||||
kvm_clear_async_pf_completion_queue(vcpu);
|
||||
}
|
||||
if ((kvm_run->kvm_dirty_regs & KVM_SYNC_BPBC) &&
|
||||
test_kvm_facility(vcpu->kvm, 82)) {
|
||||
vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
|
||||
vcpu->arch.sie_block->fpf |= kvm_run->s.regs.bpbc ? FPF_BPBC : 0;
|
||||
}
|
||||
kvm_run->kvm_dirty_regs = 0;
|
||||
}
|
||||
|
||||
|
@ -2162,6 +2173,7 @@ static void store_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
|||
kvm_run->s.regs.pft = vcpu->arch.pfault_token;
|
||||
kvm_run->s.regs.pfs = vcpu->arch.pfault_select;
|
||||
kvm_run->s.regs.pfc = vcpu->arch.pfault_compare;
|
||||
kvm_run->s.regs.bpbc = (vcpu->arch.sie_block->fpf & FPF_BPBC) == FPF_BPBC;
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||
|
|
|
@ -1 +1,32 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef __ASM_X64_MSGBUF_H
|
||||
#define __ASM_X64_MSGBUF_H
|
||||
|
||||
#if !defined(__x86_64__) || !defined(__ILP32__)
|
||||
#include <asm-generic/msgbuf.h>
|
||||
#else
|
||||
/*
|
||||
* The msqid64_ds structure for x86 architecture with x32 ABI.
|
||||
*
|
||||
* On x86-32 and x86-64 we can just use the generic definition, but
|
||||
* x32 uses the same binary layout as x86_64, which is differnet
|
||||
* from other 32-bit architectures.
|
||||
*/
|
||||
|
||||
struct msqid64_ds {
|
||||
struct ipc64_perm msg_perm;
|
||||
__kernel_time_t msg_stime; /* last msgsnd time */
|
||||
__kernel_time_t msg_rtime; /* last msgrcv time */
|
||||
__kernel_time_t msg_ctime; /* last change time */
|
||||
__kernel_ulong_t msg_cbytes; /* current number of bytes on queue */
|
||||
__kernel_ulong_t msg_qnum; /* number of messages in queue */
|
||||
__kernel_ulong_t msg_qbytes; /* max number of bytes on queue */
|
||||
__kernel_pid_t msg_lspid; /* pid of last msgsnd */
|
||||
__kernel_pid_t msg_lrpid; /* last receive pid */
|
||||
__kernel_ulong_t __unused4;
|
||||
__kernel_ulong_t __unused5;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __ASM_GENERIC_MSGBUF_H */
|
||||
|
|
|
@ -1 +1,43 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef __ASM_X86_SHMBUF_H
|
||||
#define __ASM_X86_SHMBUF_H
|
||||
|
||||
#if !defined(__x86_64__) || !defined(__ILP32__)
|
||||
#include <asm-generic/shmbuf.h>
|
||||
#else
|
||||
/*
|
||||
* The shmid64_ds structure for x86 architecture with x32 ABI.
|
||||
*
|
||||
* On x86-32 and x86-64 we can just use the generic definition, but
|
||||
* x32 uses the same binary layout as x86_64, which is differnet
|
||||
* from other 32-bit architectures.
|
||||
*/
|
||||
|
||||
struct shmid64_ds {
|
||||
struct ipc64_perm shm_perm; /* operation perms */
|
||||
size_t shm_segsz; /* size of segment (bytes) */
|
||||
__kernel_time_t shm_atime; /* last attach time */
|
||||
__kernel_time_t shm_dtime; /* last detach time */
|
||||
__kernel_time_t shm_ctime; /* last change time */
|
||||
__kernel_pid_t shm_cpid; /* pid of creator */
|
||||
__kernel_pid_t shm_lpid; /* pid of last operator */
|
||||
__kernel_ulong_t shm_nattch; /* no. of current attaches */
|
||||
__kernel_ulong_t __unused4;
|
||||
__kernel_ulong_t __unused5;
|
||||
};
|
||||
|
||||
struct shminfo64 {
|
||||
__kernel_ulong_t shmmax;
|
||||
__kernel_ulong_t shmmin;
|
||||
__kernel_ulong_t shmmni;
|
||||
__kernel_ulong_t shmseg;
|
||||
__kernel_ulong_t shmall;
|
||||
__kernel_ulong_t __unused1;
|
||||
__kernel_ulong_t __unused2;
|
||||
__kernel_ulong_t __unused3;
|
||||
__kernel_ulong_t __unused4;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __ASM_X86_SHMBUF_H */
|
||||
|
|
|
@ -1442,6 +1442,8 @@ static inline void mwait_play_dead(void)
|
|||
void *mwait_ptr;
|
||||
int i;
|
||||
|
||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
|
||||
return;
|
||||
if (!this_cpu_has(X86_FEATURE_MWAIT))
|
||||
return;
|
||||
if (!this_cpu_has(X86_FEATURE_CLFLUSH))
|
||||
|
|
|
@ -408,7 +408,7 @@ static unsigned long calc_hpet_ref(u64 deltatsc, u64 hpet1, u64 hpet2)
|
|||
hpet2 -= hpet1;
|
||||
tmp = ((u64)hpet2 * hpet_readl(HPET_PERIOD));
|
||||
do_div(tmp, 1000000);
|
||||
do_div(deltatsc, tmp);
|
||||
deltatsc = div64_u64(deltatsc, tmp);
|
||||
|
||||
return (unsigned long) deltatsc;
|
||||
}
|
||||
|
|
|
@ -68,11 +68,12 @@ static ssize_t driver_override_show(struct device *_dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct amba_device *dev = to_amba_device(_dev);
|
||||
ssize_t len;
|
||||
|
||||
if (!dev->driver_override)
|
||||
return 0;
|
||||
|
||||
return sprintf(buf, "%s\n", dev->driver_override);
|
||||
device_lock(_dev);
|
||||
len = sprintf(buf, "%s\n", dev->driver_override);
|
||||
device_unlock(_dev);
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t driver_override_store(struct device *_dev,
|
||||
|
@ -80,7 +81,7 @@ static ssize_t driver_override_store(struct device *_dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct amba_device *dev = to_amba_device(_dev);
|
||||
char *driver_override, *old = dev->driver_override, *cp;
|
||||
char *driver_override, *old, *cp;
|
||||
|
||||
/* We need to keep extra room for a newline */
|
||||
if (count >= (PAGE_SIZE - 1))
|
||||
|
@ -94,12 +95,15 @@ static ssize_t driver_override_store(struct device *_dev,
|
|||
if (cp)
|
||||
*cp = '\0';
|
||||
|
||||
device_lock(_dev);
|
||||
old = dev->driver_override;
|
||||
if (strlen(driver_override)) {
|
||||
dev->driver_override = driver_override;
|
||||
} else {
|
||||
kfree(driver_override);
|
||||
dev->driver_override = NULL;
|
||||
}
|
||||
device_unlock(_dev);
|
||||
|
||||
kfree(old);
|
||||
|
||||
|
|
|
@ -2358,7 +2358,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
|
|||
if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)
|
||||
return media_changed(cdi, 1);
|
||||
|
||||
if ((unsigned int)arg >= cdi->capacity)
|
||||
if (arg >= cdi->capacity)
|
||||
return -EINVAL;
|
||||
|
||||
info = kmalloc(sizeof(*info), GFP_KERNEL);
|
||||
|
|
|
@ -1399,7 +1399,6 @@ static int add_port(struct ports_device *portdev, u32 id)
|
|||
{
|
||||
char debugfs_name[16];
|
||||
struct port *port;
|
||||
struct port_buffer *buf;
|
||||
dev_t devt;
|
||||
unsigned int nr_added_bufs;
|
||||
int err;
|
||||
|
@ -1510,8 +1509,6 @@ static int add_port(struct ports_device *portdev, u32 id)
|
|||
return 0;
|
||||
|
||||
free_inbufs:
|
||||
while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
|
||||
free_buf(buf, true);
|
||||
free_device:
|
||||
device_destroy(pdrvdata.class, port->dev->devt);
|
||||
free_cdev:
|
||||
|
@ -1536,34 +1533,14 @@ static void remove_port(struct kref *kref)
|
|||
|
||||
static void remove_port_data(struct port *port)
|
||||
{
|
||||
struct port_buffer *buf;
|
||||
|
||||
spin_lock_irq(&port->inbuf_lock);
|
||||
/* Remove unused data this port might have received. */
|
||||
discard_port_data(port);
|
||||
spin_unlock_irq(&port->inbuf_lock);
|
||||
|
||||
/* Remove buffers we queued up for the Host to send us data in. */
|
||||
do {
|
||||
spin_lock_irq(&port->inbuf_lock);
|
||||
buf = virtqueue_detach_unused_buf(port->in_vq);
|
||||
spin_unlock_irq(&port->inbuf_lock);
|
||||
if (buf)
|
||||
free_buf(buf, true);
|
||||
} while (buf);
|
||||
|
||||
spin_lock_irq(&port->outvq_lock);
|
||||
reclaim_consumed_buffers(port);
|
||||
spin_unlock_irq(&port->outvq_lock);
|
||||
|
||||
/* Free pending buffers from the out-queue. */
|
||||
do {
|
||||
spin_lock_irq(&port->outvq_lock);
|
||||
buf = virtqueue_detach_unused_buf(port->out_vq);
|
||||
spin_unlock_irq(&port->outvq_lock);
|
||||
if (buf)
|
||||
free_buf(buf, true);
|
||||
} while (buf);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1788,13 +1765,24 @@ static void control_work_handler(struct work_struct *work)
|
|||
spin_unlock(&portdev->c_ivq_lock);
|
||||
}
|
||||
|
||||
static void flush_bufs(struct virtqueue *vq, bool can_sleep)
|
||||
{
|
||||
struct port_buffer *buf;
|
||||
unsigned int len;
|
||||
|
||||
while ((buf = virtqueue_get_buf(vq, &len)))
|
||||
free_buf(buf, can_sleep);
|
||||
}
|
||||
|
||||
static void out_intr(struct virtqueue *vq)
|
||||
{
|
||||
struct port *port;
|
||||
|
||||
port = find_port_by_vq(vq->vdev->priv, vq);
|
||||
if (!port)
|
||||
if (!port) {
|
||||
flush_bufs(vq, false);
|
||||
return;
|
||||
}
|
||||
|
||||
wake_up_interruptible(&port->waitqueue);
|
||||
}
|
||||
|
@ -1805,8 +1793,10 @@ static void in_intr(struct virtqueue *vq)
|
|||
unsigned long flags;
|
||||
|
||||
port = find_port_by_vq(vq->vdev->priv, vq);
|
||||
if (!port)
|
||||
if (!port) {
|
||||
flush_bufs(vq, false);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&port->inbuf_lock, flags);
|
||||
port->inbuf = get_inbuf(port);
|
||||
|
@ -1981,6 +1971,15 @@ static const struct file_operations portdev_fops = {
|
|||
|
||||
static void remove_vqs(struct ports_device *portdev)
|
||||
{
|
||||
struct virtqueue *vq;
|
||||
|
||||
virtio_device_for_each_vq(portdev->vdev, vq) {
|
||||
struct port_buffer *buf;
|
||||
|
||||
flush_bufs(vq, true);
|
||||
while ((buf = virtqueue_detach_unused_buf(vq)))
|
||||
free_buf(buf, true);
|
||||
}
|
||||
portdev->vdev->config->del_vqs(portdev->vdev);
|
||||
kfree(portdev->in_vqs);
|
||||
kfree(portdev->out_vqs);
|
||||
|
|
|
@ -324,7 +324,7 @@ retry:
|
|||
ret = virtqueue_add_sgs(vq, sgs, outcnt, incnt, vbuf, GFP_ATOMIC);
|
||||
if (ret == -ENOSPC) {
|
||||
spin_unlock(&vgdev->ctrlq.qlock);
|
||||
wait_event(vgdev->ctrlq.ack_queue, vq->num_free);
|
||||
wait_event(vgdev->ctrlq.ack_queue, vq->num_free >= outcnt + incnt);
|
||||
spin_lock(&vgdev->ctrlq.qlock);
|
||||
goto retry;
|
||||
} else {
|
||||
|
@ -399,7 +399,7 @@ retry:
|
|||
ret = virtqueue_add_sgs(vq, sgs, outcnt, 0, vbuf, GFP_ATOMIC);
|
||||
if (ret == -ENOSPC) {
|
||||
spin_unlock(&vgdev->cursorq.qlock);
|
||||
wait_event(vgdev->cursorq.ack_queue, vq->num_free);
|
||||
wait_event(vgdev->cursorq.ack_queue, vq->num_free >= outcnt);
|
||||
spin_lock(&vgdev->cursorq.qlock);
|
||||
goto retry;
|
||||
} else {
|
||||
|
|
|
@ -521,7 +521,7 @@ static int drv260x_probe(struct i2c_client *client,
|
|||
if (!haptics)
|
||||
return -ENOMEM;
|
||||
|
||||
haptics->rated_voltage = DRV260X_DEF_OD_CLAMP_VOLT;
|
||||
haptics->overdrive_voltage = DRV260X_DEF_OD_CLAMP_VOLT;
|
||||
haptics->rated_voltage = DRV260X_DEF_RATED_VOLT;
|
||||
|
||||
if (pdata) {
|
||||
|
|
|
@ -1994,6 +1994,7 @@ static struct scsi_host_template mptsas_driver_template = {
|
|||
.cmd_per_lun = 7,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.shost_attrs = mptscsih_host_attrs,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
static int mptsas_get_linkerrors(struct sas_phy *phy)
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#define I82802AB 0x00ad
|
||||
#define I82802AC 0x00ac
|
||||
#define PF38F4476 0x881c
|
||||
#define M28F00AP30 0x8963
|
||||
/* STMicroelectronics chips */
|
||||
#define M50LPW080 0x002F
|
||||
#define M50FLW080A 0x0080
|
||||
|
@ -375,6 +376,17 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi,
|
|||
extp->MinorVersion = '1';
|
||||
}
|
||||
|
||||
static int cfi_is_micron_28F00AP30(struct cfi_private *cfi, struct flchip *chip)
|
||||
{
|
||||
/*
|
||||
* Micron(was Numonyx) 1Gbit bottom boot are buggy w.r.t
|
||||
* Erase Supend for their small Erase Blocks(0x8000)
|
||||
*/
|
||||
if (cfi->mfr == CFI_MFR_INTEL && cfi->id == M28F00AP30)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct cfi_pri_intelext *
|
||||
read_pri_intelext(struct map_info *map, __u16 adr)
|
||||
{
|
||||
|
@ -825,21 +837,30 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
|
|||
(mode == FL_WRITING && (cfip->SuspendCmdSupport & 1))))
|
||||
goto sleep;
|
||||
|
||||
/* Do not allow suspend iff read/write to EB address */
|
||||
if ((adr & chip->in_progress_block_mask) ==
|
||||
chip->in_progress_block_addr)
|
||||
goto sleep;
|
||||
|
||||
/* do not suspend small EBs, buggy Micron Chips */
|
||||
if (cfi_is_micron_28F00AP30(cfi, chip) &&
|
||||
(chip->in_progress_block_mask == ~(0x8000-1)))
|
||||
goto sleep;
|
||||
|
||||
/* Erase suspend */
|
||||
map_write(map, CMD(0xB0), adr);
|
||||
map_write(map, CMD(0xB0), chip->in_progress_block_addr);
|
||||
|
||||
/* If the flash has finished erasing, then 'erase suspend'
|
||||
* appears to make some (28F320) flash devices switch to
|
||||
* 'read' mode. Make sure that we switch to 'read status'
|
||||
* mode so we get the right data. --rmk
|
||||
*/
|
||||
map_write(map, CMD(0x70), adr);
|
||||
map_write(map, CMD(0x70), chip->in_progress_block_addr);
|
||||
chip->oldstate = FL_ERASING;
|
||||
chip->state = FL_ERASE_SUSPENDING;
|
||||
chip->erase_suspended = 1;
|
||||
for (;;) {
|
||||
status = map_read(map, adr);
|
||||
status = map_read(map, chip->in_progress_block_addr);
|
||||
if (map_word_andequal(map, status, status_OK, status_OK))
|
||||
break;
|
||||
|
||||
|
@ -1035,8 +1056,8 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
|
|||
sending the 0x70 (Read Status) command to an erasing
|
||||
chip and expecting it to be ignored, that's what we
|
||||
do. */
|
||||
map_write(map, CMD(0xd0), adr);
|
||||
map_write(map, CMD(0x70), adr);
|
||||
map_write(map, CMD(0xd0), chip->in_progress_block_addr);
|
||||
map_write(map, CMD(0x70), chip->in_progress_block_addr);
|
||||
chip->oldstate = FL_READY;
|
||||
chip->state = FL_ERASING;
|
||||
break;
|
||||
|
@ -1927,6 +1948,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
|
|||
map_write(map, CMD(0xD0), adr);
|
||||
chip->state = FL_ERASING;
|
||||
chip->erase_suspended = 0;
|
||||
chip->in_progress_block_addr = adr;
|
||||
chip->in_progress_block_mask = ~(len - 1);
|
||||
|
||||
ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
|
||||
adr, len,
|
||||
|
|
|
@ -814,9 +814,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
|
|||
(mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
|
||||
goto sleep;
|
||||
|
||||
/* We could check to see if we're trying to access the sector
|
||||
* that is currently being erased. However, no user will try
|
||||
* anything like that so we just wait for the timeout. */
|
||||
/* Do not allow suspend iff read/write to EB address */
|
||||
if ((adr & chip->in_progress_block_mask) ==
|
||||
chip->in_progress_block_addr)
|
||||
goto sleep;
|
||||
|
||||
/* Erase suspend */
|
||||
/* It's harmless to issue the Erase-Suspend and Erase-Resume
|
||||
|
@ -2265,6 +2266,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
|
|||
chip->state = FL_ERASING;
|
||||
chip->erase_suspended = 0;
|
||||
chip->in_progress_block_addr = adr;
|
||||
chip->in_progress_block_mask = ~(map->size - 1);
|
||||
|
||||
INVALIDATE_CACHE_UDELAY(map, chip,
|
||||
adr, map->size,
|
||||
|
@ -2354,6 +2356,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
|
|||
chip->state = FL_ERASING;
|
||||
chip->erase_suspended = 0;
|
||||
chip->in_progress_block_addr = adr;
|
||||
chip->in_progress_block_mask = ~(len - 1);
|
||||
|
||||
INVALIDATE_CACHE_UDELAY(map, chip,
|
||||
adr, len,
|
||||
|
|
|
@ -1614,8 +1614,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
|||
} /* switch(bond_mode) */
|
||||
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
slave_dev->npinfo = bond->dev->npinfo;
|
||||
if (slave_dev->npinfo) {
|
||||
if (bond->dev->npinfo) {
|
||||
if (slave_enable_netpoll(new_slave)) {
|
||||
netdev_info(bond_dev, "master_dev is using netpoll, but new slave device does not support netpoll\n");
|
||||
res = -EBUSY;
|
||||
|
|
|
@ -638,6 +638,10 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
|
|||
lock_sock(sk);
|
||||
|
||||
error = -EINVAL;
|
||||
|
||||
if (sockaddr_len != sizeof(struct sockaddr_pppox))
|
||||
goto end;
|
||||
|
||||
if (sp->sa_protocol != PX_PROTO_OE)
|
||||
goto end;
|
||||
|
||||
|
|
|
@ -247,6 +247,17 @@ static void __team_option_inst_mark_removed_port(struct team *team,
|
|||
}
|
||||
}
|
||||
|
||||
static bool __team_option_inst_tmp_find(const struct list_head *opts,
|
||||
const struct team_option_inst *needle)
|
||||
{
|
||||
struct team_option_inst *opt_inst;
|
||||
|
||||
list_for_each_entry(opt_inst, opts, tmp_list)
|
||||
if (opt_inst == needle)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __team_options_register(struct team *team,
|
||||
const struct team_option *option,
|
||||
size_t option_count)
|
||||
|
@ -1039,14 +1050,11 @@ static void team_port_leave(struct team *team, struct team_port *port)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
static int team_port_enable_netpoll(struct team *team, struct team_port *port)
|
||||
static int __team_port_enable_netpoll(struct team_port *port)
|
||||
{
|
||||
struct netpoll *np;
|
||||
int err;
|
||||
|
||||
if (!team->dev->npinfo)
|
||||
return 0;
|
||||
|
||||
np = kzalloc(sizeof(*np), GFP_KERNEL);
|
||||
if (!np)
|
||||
return -ENOMEM;
|
||||
|
@ -1060,6 +1068,14 @@ static int team_port_enable_netpoll(struct team *team, struct team_port *port)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int team_port_enable_netpoll(struct team_port *port)
|
||||
{
|
||||
if (!port->team->dev->npinfo)
|
||||
return 0;
|
||||
|
||||
return __team_port_enable_netpoll(port);
|
||||
}
|
||||
|
||||
static void team_port_disable_netpoll(struct team_port *port)
|
||||
{
|
||||
struct netpoll *np = port->np;
|
||||
|
@ -1074,7 +1090,7 @@ static void team_port_disable_netpoll(struct team_port *port)
|
|||
kfree(np);
|
||||
}
|
||||
#else
|
||||
static int team_port_enable_netpoll(struct team *team, struct team_port *port)
|
||||
static int team_port_enable_netpoll(struct team_port *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -1181,7 +1197,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
|
|||
goto err_vids_add;
|
||||
}
|
||||
|
||||
err = team_port_enable_netpoll(team, port);
|
||||
err = team_port_enable_netpoll(port);
|
||||
if (err) {
|
||||
netdev_err(dev, "Failed to enable netpoll on device %s\n",
|
||||
portname);
|
||||
|
@ -1889,7 +1905,7 @@ static int team_netpoll_setup(struct net_device *dev,
|
|||
|
||||
mutex_lock(&team->lock);
|
||||
list_for_each_entry(port, &team->port_list, list) {
|
||||
err = team_port_enable_netpoll(team, port);
|
||||
err = __team_port_enable_netpoll(port);
|
||||
if (err) {
|
||||
__team_netpoll_cleanup(team);
|
||||
break;
|
||||
|
@ -2544,6 +2560,14 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
|
|||
if (err)
|
||||
goto team_put;
|
||||
opt_inst->changed = true;
|
||||
|
||||
/* dumb/evil user-space can send us duplicate opt,
|
||||
* keep only the last one
|
||||
*/
|
||||
if (__team_option_inst_tmp_find(&opt_inst_list,
|
||||
opt_inst))
|
||||
continue;
|
||||
|
||||
list_add(&opt_inst->tmp_list, &opt_inst_list);
|
||||
}
|
||||
if (!opt_found) {
|
||||
|
|
|
@ -461,6 +461,7 @@ static const struct driver_info wwan_info = {
|
|||
#define REALTEK_VENDOR_ID 0x0bda
|
||||
#define SAMSUNG_VENDOR_ID 0x04e8
|
||||
#define LENOVO_VENDOR_ID 0x17ef
|
||||
#define LINKSYS_VENDOR_ID 0x13b1
|
||||
#define NVIDIA_VENDOR_ID 0x0955
|
||||
#define HP_VENDOR_ID 0x03f0
|
||||
|
||||
|
@ -650,6 +651,15 @@ static const struct usb_device_id products[] = {
|
|||
.driver_info = 0,
|
||||
},
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_RTL8152)
|
||||
/* Linksys USB3GIGV1 Ethernet Adapter */
|
||||
{
|
||||
USB_DEVICE_AND_INTERFACE_INFO(LINKSYS_VENDOR_ID, 0x0041, USB_CLASS_COMM,
|
||||
USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
||||
.driver_info = 0,
|
||||
},
|
||||
#endif
|
||||
|
||||
/* Lenovo Thinkpad USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */
|
||||
{
|
||||
USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x7205, USB_CLASS_COMM,
|
||||
|
|
|
@ -506,6 +506,7 @@ enum rtl8152_flags {
|
|||
#define VENDOR_ID_REALTEK 0x0bda
|
||||
#define VENDOR_ID_SAMSUNG 0x04e8
|
||||
#define VENDOR_ID_LENOVO 0x17ef
|
||||
#define VENDOR_ID_LINKSYS 0x13b1
|
||||
#define VENDOR_ID_NVIDIA 0x0955
|
||||
|
||||
#define MCU_TYPE_PLA 0x0100
|
||||
|
@ -4376,6 +4377,7 @@ static struct usb_device_id rtl8152_table[] = {
|
|||
{REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)},
|
||||
{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7205)},
|
||||
{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f)},
|
||||
{REALTEK_USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041)},
|
||||
{REALTEK_USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff)},
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -5929,9 +5929,8 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
|
|||
sta->addr, smps, err);
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_RC_SUPP_RATES_CHANGED ||
|
||||
changed & IEEE80211_RC_NSS_CHANGED) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n",
|
||||
if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
|
||||
sta->addr);
|
||||
|
||||
err = ath10k_station_assoc(ar, arvif->vif, sta, true);
|
||||
|
|
|
@ -1595,6 +1595,10 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
|
|||
int count = 50;
|
||||
u32 reg, last_val;
|
||||
|
||||
/* Check if chip failed to wake up */
|
||||
if (REG_READ(ah, AR_CFG) == 0xdeadbeef)
|
||||
return false;
|
||||
|
||||
if (AR_SREV_9300(ah))
|
||||
return !ath9k_hw_detect_mac_hang(ah);
|
||||
|
||||
|
|
|
@ -2,5 +2,4 @@
|
|||
# Makefile for Goldfish platform specific drivers
|
||||
#
|
||||
obj-$(CONFIG_GOLDFISH_BUS) += pdev_bus.o
|
||||
obj-$(CONFIG_GOLDFISH_PIPE) += goldfish_pipe_all.o
|
||||
goldfish_pipe_all-objs := goldfish_pipe.o goldfish_pipe_v2.o
|
||||
obj-$(CONFIG_GOLDFISH_PIPE) += goldfish_pipe.o goldfish_pipe_v2.o
|
||||
|
|
|
@ -506,7 +506,7 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
|
|||
static int goldfish_pipe_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct goldfish_pipe *pipe;
|
||||
struct goldfish_pipe_dev *dev = pipe_dev;
|
||||
struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
|
||||
int32_t status;
|
||||
|
||||
/* Allocate new pipe kernel object */
|
||||
|
@ -558,7 +558,7 @@ static const struct file_operations goldfish_pipe_fops = {
|
|||
.release = goldfish_pipe_release,
|
||||
};
|
||||
|
||||
static struct miscdevice goldfish_pipe_dev = {
|
||||
static struct miscdevice goldfish_pipe_miscdev = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "goldfish_pipe",
|
||||
.fops = &goldfish_pipe_fops,
|
||||
|
@ -566,15 +566,16 @@ static struct miscdevice goldfish_pipe_dev = {
|
|||
|
||||
int goldfish_pipe_device_init_v1(struct platform_device *pdev)
|
||||
{
|
||||
struct goldfish_pipe_dev *dev = pipe_dev;
|
||||
struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
|
||||
int err = devm_request_irq(&pdev->dev, dev->irq,
|
||||
goldfish_pipe_interrupt, IRQF_SHARED, "goldfish_pipe", dev);
|
||||
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "unable to allocate IRQ for v1\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = misc_register(&goldfish_pipe_dev);
|
||||
err = misc_register(&goldfish_pipe_miscdev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "unable to register v1 device\n");
|
||||
return err;
|
||||
|
@ -586,5 +587,5 @@ int goldfish_pipe_device_init_v1(struct platform_device *pdev)
|
|||
|
||||
void goldfish_pipe_device_deinit_v1(struct platform_device *pdev)
|
||||
{
|
||||
misc_deregister(&goldfish_pipe_dev);
|
||||
misc_deregister(&goldfish_pipe_miscdev);
|
||||
}
|
||||
|
|
|
@ -86,6 +86,6 @@ struct goldfish_pipe_dev {
|
|||
struct access_params *aps;
|
||||
};
|
||||
|
||||
extern struct goldfish_pipe_dev pipe_dev[1];
|
||||
extern struct goldfish_pipe_dev goldfish_pipe_dev;
|
||||
|
||||
#endif /* GOLDFISH_PIPE_H */
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
#include <linux/printk.h>
|
||||
#include "goldfish_pipe.h"
|
||||
|
||||
|
||||
/*
|
||||
* Update this when something changes in the driver's behavior so the host
|
||||
* can benefit from knowing it
|
||||
|
@ -83,9 +82,9 @@ enum PipeErrors {
|
|||
|
||||
/* Bit-flags used to signal events from the emulator */
|
||||
enum PipeWakeFlags {
|
||||
PIPE_WAKE_CLOSED = 1 << 0, /* emulator closed pipe */
|
||||
PIPE_WAKE_READ = 1 << 1, /* pipe can now be read from */
|
||||
PIPE_WAKE_WRITE = 1 << 2 /* pipe can now be written to */
|
||||
PIPE_WAKE_CLOSED = BIT(0), /* emulator closed pipe */
|
||||
PIPE_WAKE_READ = BIT(1), /* pipe can now be read from */
|
||||
PIPE_WAKE_WRITE = BIT(2), /* pipe can now be written to */
|
||||
};
|
||||
|
||||
/* Bit flags for the 'flags' field */
|
||||
|
@ -214,9 +213,10 @@ struct goldfish_pipe {
|
|||
struct goldfish_pipe_dev *dev;
|
||||
};
|
||||
|
||||
struct goldfish_pipe_dev pipe_dev[1] = {};
|
||||
struct goldfish_pipe_dev goldfish_pipe_dev;
|
||||
|
||||
static int goldfish_cmd_locked(struct goldfish_pipe *pipe, enum PipeCmdCode cmd)
|
||||
static int goldfish_pipe_cmd_locked(
|
||||
struct goldfish_pipe *pipe, enum PipeCmdCode cmd)
|
||||
{
|
||||
pipe->command_buffer->cmd = cmd;
|
||||
/* failure by default */
|
||||
|
@ -225,12 +225,15 @@ static int goldfish_cmd_locked(struct goldfish_pipe *pipe, enum PipeCmdCode cmd)
|
|||
return pipe->command_buffer->status;
|
||||
}
|
||||
|
||||
static int goldfish_cmd(struct goldfish_pipe *pipe, enum PipeCmdCode cmd)
|
||||
static int goldfish_pipe_cmd(struct goldfish_pipe *pipe, enum PipeCmdCode cmd)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (mutex_lock_interruptible(&pipe->lock))
|
||||
return PIPE_ERROR_IO;
|
||||
status = goldfish_cmd_locked(pipe, cmd);
|
||||
|
||||
status = goldfish_pipe_cmd_locked(pipe, cmd);
|
||||
|
||||
mutex_unlock(&pipe->lock);
|
||||
return status;
|
||||
}
|
||||
|
@ -329,7 +332,7 @@ static void populate_rw_params(
|
|||
command->rw_params.buffers_count = buffer_idx + 1;
|
||||
}
|
||||
|
||||
static int transfer_max_buffers(struct goldfish_pipe* pipe,
|
||||
static int transfer_max_buffers(struct goldfish_pipe *pipe,
|
||||
unsigned long address, unsigned long address_end, int is_write,
|
||||
unsigned long last_page, unsigned int last_page_size,
|
||||
s32 *consumed_size, int *status)
|
||||
|
@ -352,7 +355,7 @@ static int transfer_max_buffers(struct goldfish_pipe* pipe,
|
|||
pipe->command_buffer);
|
||||
|
||||
/* Transfer the data */
|
||||
*status = goldfish_cmd_locked(
|
||||
*status = goldfish_pipe_cmd_locked(
|
||||
pipe,
|
||||
is_write ? PIPE_CMD_WRITE : PIPE_CMD_READ);
|
||||
|
||||
|
@ -361,7 +364,6 @@ static int transfer_max_buffers(struct goldfish_pipe* pipe,
|
|||
mutex_unlock(&pipe->lock);
|
||||
|
||||
release_user_pages(pages, pages_count, is_write, *consumed_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -371,7 +373,7 @@ static int wait_for_host_signal(struct goldfish_pipe *pipe, int is_write)
|
|||
set_bit(wakeBit, &pipe->flags);
|
||||
|
||||
/* Tell the emulator we're going to wait for a wake event */
|
||||
(void)goldfish_cmd(pipe,
|
||||
goldfish_pipe_cmd(pipe,
|
||||
is_write ? PIPE_CMD_WAKE_ON_WRITE : PIPE_CMD_WAKE_ON_READ);
|
||||
|
||||
while (test_bit(wakeBit, &pipe->flags)) {
|
||||
|
@ -414,6 +416,7 @@ static ssize_t goldfish_pipe_read_write(struct file *filp,
|
|||
while (address < address_end) {
|
||||
s32 consumed_size;
|
||||
int status;
|
||||
|
||||
ret = transfer_max_buffers(pipe, address, address_end, is_write,
|
||||
last_page, last_page_size, &consumed_size, &status);
|
||||
if (ret < 0)
|
||||
|
@ -491,7 +494,7 @@ static unsigned int goldfish_pipe_poll(struct file *filp, poll_table *wait)
|
|||
|
||||
poll_wait(filp, &pipe->wake_queue, wait);
|
||||
|
||||
status = goldfish_cmd(pipe, PIPE_CMD_POLL);
|
||||
status = goldfish_pipe_cmd(pipe, PIPE_CMD_POLL);
|
||||
if (status < 0)
|
||||
return -ERESTARTSYS;
|
||||
|
||||
|
@ -507,26 +510,30 @@ static unsigned int goldfish_pipe_poll(struct file *filp, poll_table *wait)
|
|||
return mask;
|
||||
}
|
||||
|
||||
static void signalled_pipes_add_locked(struct goldfish_pipe_dev *dev,
|
||||
static int signalled_pipes_add_locked(struct goldfish_pipe_dev *dev,
|
||||
u32 id, u32 flags)
|
||||
{
|
||||
struct goldfish_pipe *pipe;
|
||||
|
||||
BUG_ON(id >= dev->pipes_capacity);
|
||||
if (id >= dev->pipes_capacity)
|
||||
return -EINVAL;
|
||||
|
||||
pipe = dev->pipes[id];
|
||||
if (!pipe)
|
||||
return;
|
||||
return -ENXIO;
|
||||
|
||||
pipe->signalled_flags |= flags;
|
||||
|
||||
if (pipe->prev_signalled || pipe->next_signalled
|
||||
|| dev->first_signalled_pipe == pipe)
|
||||
return; /* already in the list */
|
||||
return 0; /* already in the list */
|
||||
|
||||
pipe->next_signalled = dev->first_signalled_pipe;
|
||||
if (dev->first_signalled_pipe)
|
||||
dev->first_signalled_pipe->prev_signalled = pipe;
|
||||
|
||||
dev->first_signalled_pipe = pipe;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void signalled_pipes_remove_locked(struct goldfish_pipe_dev *dev,
|
||||
|
@ -570,11 +577,12 @@ static struct goldfish_pipe *signalled_pipes_pop_front(
|
|||
|
||||
static void goldfish_interrupt_task(unsigned long unused)
|
||||
{
|
||||
struct goldfish_pipe_dev *dev = pipe_dev;
|
||||
/* Iterate over the signalled pipes and wake them one by one */
|
||||
struct goldfish_pipe *pipe;
|
||||
int wakes;
|
||||
while ((pipe = signalled_pipes_pop_front(dev, &wakes)) != NULL) {
|
||||
|
||||
while ((pipe = signalled_pipes_pop_front(&goldfish_pipe_dev, &wakes)) !=
|
||||
NULL) {
|
||||
if (wakes & PIPE_WAKE_CLOSED) {
|
||||
pipe->flags = 1 << BIT_CLOSED_ON_HOST;
|
||||
} else {
|
||||
|
@ -611,7 +619,8 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
|
|||
u32 i;
|
||||
unsigned long flags;
|
||||
struct goldfish_pipe_dev *dev = dev_id;
|
||||
if (dev != pipe_dev)
|
||||
|
||||
if (dev != &goldfish_pipe_dev)
|
||||
return IRQ_NONE;
|
||||
|
||||
/* Request the signalled pipes from the device */
|
||||
|
@ -649,7 +658,7 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev)
|
|||
u32 new_capacity = 2 * dev->pipes_capacity;
|
||||
struct goldfish_pipe **pipes =
|
||||
kcalloc(new_capacity, sizeof(*pipes),
|
||||
GFP_ATOMIC);
|
||||
GFP_KERNEL);
|
||||
if (!pipes)
|
||||
return -ENOMEM;
|
||||
memcpy(pipes, dev->pipes, sizeof(*pipes) * dev->pipes_capacity);
|
||||
|
@ -674,13 +683,14 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev)
|
|||
*/
|
||||
static int goldfish_pipe_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct goldfish_pipe_dev *dev = pipe_dev;
|
||||
struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
|
||||
unsigned long flags;
|
||||
int id;
|
||||
int status;
|
||||
|
||||
/* Allocate new pipe kernel object */
|
||||
struct goldfish_pipe *pipe = kzalloc(sizeof(*pipe), GFP_KERNEL);
|
||||
|
||||
if (pipe == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -717,16 +727,16 @@ static int goldfish_pipe_open(struct inode *inode, struct file *file)
|
|||
dev->buffers->open_command_params.rw_params_max_count =
|
||||
MAX_BUFFERS_PER_COMMAND;
|
||||
dev->buffers->open_command_params.command_buffer_ptr =
|
||||
(u64)(unsigned long)__pa(pipe->command_buffer);
|
||||
status = goldfish_cmd_locked(pipe, PIPE_CMD_OPEN);
|
||||
(u64)__pa(pipe->command_buffer);
|
||||
status = goldfish_pipe_cmd_locked(pipe, PIPE_CMD_OPEN);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
if (status < 0) {
|
||||
pr_err("Could not tell host of new pipe! status=%d", status);
|
||||
pr_err("Could not tell host of new pipe! status=%d\n", status);
|
||||
goto err_cmd;
|
||||
}
|
||||
|
||||
/* All is done, save the pipe into the file's private data field */
|
||||
file->private_data = pipe;
|
||||
pr_debug("%s on 0x%p\n", __func__, pipe);
|
||||
return 0;
|
||||
|
||||
err_cmd:
|
||||
|
@ -746,10 +756,8 @@ static int goldfish_pipe_release(struct inode *inode, struct file *filp)
|
|||
struct goldfish_pipe *pipe = filp->private_data;
|
||||
struct goldfish_pipe_dev *dev = pipe->dev;
|
||||
|
||||
pr_debug("%s on 0x%p\n", __func__, pipe);
|
||||
|
||||
/* The guest is closing the channel, so tell the emulator right now */
|
||||
(void)goldfish_cmd(pipe, PIPE_CMD_CLOSE);
|
||||
goldfish_pipe_cmd(pipe, PIPE_CMD_CLOSE);
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
dev->pipes[pipe->id] = NULL;
|
||||
|
@ -757,8 +765,10 @@ static int goldfish_pipe_release(struct inode *inode, struct file *filp)
|
|||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
filp->private_data = NULL;
|
||||
|
||||
free_page((unsigned long)pipe->command_buffer);
|
||||
kfree(pipe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -771,7 +781,7 @@ static const struct file_operations goldfish_pipe_fops = {
|
|||
.release = goldfish_pipe_release,
|
||||
};
|
||||
|
||||
static struct miscdevice goldfish_pipe_dev = {
|
||||
static struct miscdevice goldfish_pipe_miscdev = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "goldfish_pipe",
|
||||
.fops = &goldfish_pipe_fops,
|
||||
|
@ -780,7 +790,7 @@ static struct miscdevice goldfish_pipe_dev = {
|
|||
static int goldfish_pipe_device_init_v2(struct platform_device *pdev)
|
||||
{
|
||||
char *page;
|
||||
struct goldfish_pipe_dev *dev = pipe_dev;
|
||||
struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
|
||||
int err = devm_request_irq(&pdev->dev, dev->irq, goldfish_pipe_interrupt,
|
||||
IRQF_SHARED, "goldfish_pipe", dev);
|
||||
if (err) {
|
||||
|
@ -788,7 +798,7 @@ static int goldfish_pipe_device_init_v2(struct platform_device *pdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
err = misc_register(&goldfish_pipe_dev);
|
||||
err = misc_register(&goldfish_pipe_miscdev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "unable to register v2 device\n");
|
||||
return err;
|
||||
|
@ -807,13 +817,13 @@ static int goldfish_pipe_device_init_v2(struct platform_device *pdev)
|
|||
* needs to be contained in a single physical page. The easiest choice
|
||||
* is to just allocate a page and place the buffers in it.
|
||||
*/
|
||||
BUG_ON(sizeof(*dev->buffers) > PAGE_SIZE);
|
||||
page = (char*)__get_free_page(GFP_KERNEL);
|
||||
BUILD_BUG_ON(sizeof(*dev->buffers) > PAGE_SIZE);
|
||||
page = (char *)__get_free_page(GFP_KERNEL);
|
||||
if (!page) {
|
||||
kfree(dev->pipes);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dev->buffers = (struct goldfish_pipe_dev_buffers*)page;
|
||||
dev->buffers = (struct goldfish_pipe_dev_buffers *)page;
|
||||
|
||||
/* Send the buffer addresses to the host */
|
||||
{
|
||||
|
@ -832,23 +842,24 @@ static int goldfish_pipe_device_init_v2(struct platform_device *pdev)
|
|||
writel((u32)(unsigned long)paddr,
|
||||
dev->base + PIPE_REG_OPEN_BUFFER);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void goldfish_pipe_device_deinit_v2(struct platform_device *pdev) {
|
||||
struct goldfish_pipe_dev *dev = pipe_dev;
|
||||
misc_deregister(&goldfish_pipe_dev);
|
||||
kfree(dev->pipes);
|
||||
free_page((unsigned long)dev->buffers);
|
||||
static void goldfish_pipe_device_deinit_v2(struct platform_device *pdev)
|
||||
{
|
||||
misc_deregister(&goldfish_pipe_miscdev);
|
||||
kfree(goldfish_pipe_dev.pipes);
|
||||
free_page((unsigned long)goldfish_pipe_dev.buffers);
|
||||
}
|
||||
|
||||
static int goldfish_pipe_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
struct resource *r;
|
||||
struct goldfish_pipe_dev *dev = pipe_dev;
|
||||
struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
|
||||
|
||||
BUG_ON(sizeof(struct goldfish_pipe_command) > PAGE_SIZE);
|
||||
BUILD_BUG_ON(sizeof(struct goldfish_pipe_command) > PAGE_SIZE);
|
||||
|
||||
/* not thread safe, but this should not happen */
|
||||
WARN_ON(dev->base != NULL);
|
||||
|
@ -899,7 +910,8 @@ error:
|
|||
|
||||
static int goldfish_pipe_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct goldfish_pipe_dev *dev = pipe_dev;
|
||||
struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
|
||||
|
||||
if (dev->version < PIPE_CURRENT_DEVICE_VERSION)
|
||||
goldfish_pipe_device_deinit_v1(pdev);
|
||||
else
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
# S/390 character devices
|
||||
#
|
||||
|
||||
CFLAGS_REMOVE_sclp_early_core.o += $(CC_FLAGS_EXPOLINE)
|
||||
|
||||
obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
|
||||
sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \
|
||||
sclp_early.o
|
||||
|
|
|
@ -451,6 +451,7 @@ static void chsc_process_sei_link_incident(struct chsc_sei_nt0_area *sei_area)
|
|||
|
||||
static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area)
|
||||
{
|
||||
struct channel_path *chp;
|
||||
struct chp_link link;
|
||||
struct chp_id chpid;
|
||||
int status;
|
||||
|
@ -463,10 +464,17 @@ static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area)
|
|||
chpid.id = sei_area->rsid;
|
||||
/* allocate a new channel path structure, if needed */
|
||||
status = chp_get_status(chpid);
|
||||
if (status < 0)
|
||||
chp_new(chpid);
|
||||
else if (!status)
|
||||
if (!status)
|
||||
return;
|
||||
|
||||
if (status < 0) {
|
||||
chp_new(chpid);
|
||||
} else {
|
||||
chp = chpid_to_chp(chpid);
|
||||
mutex_lock(&chp->lock);
|
||||
chp_update_desc(chp);
|
||||
mutex_unlock(&chp->lock);
|
||||
}
|
||||
memset(&link, 0, sizeof(struct chp_link));
|
||||
link.chpid = chpid;
|
||||
if ((sei_area->vf & 0xc0) != 0) {
|
||||
|
|
|
@ -1873,6 +1873,8 @@ sd_spinup_disk(struct scsi_disk *sdkp)
|
|||
break; /* standby */
|
||||
if (sshdr.asc == 4 && sshdr.ascq == 0xc)
|
||||
break; /* unavailable */
|
||||
if (sshdr.asc == 4 && sshdr.ascq == 0x1b)
|
||||
break; /* sanitize in progress */
|
||||
/*
|
||||
* Issue command to spin up drive when not ready
|
||||
*/
|
||||
|
|
|
@ -1031,7 +1031,6 @@ void ion_client_destroy(struct ion_client *client)
|
|||
struct ion_device *dev = client->dev;
|
||||
struct rb_node *n;
|
||||
|
||||
pr_debug("%s: %d\n", __func__, __LINE__);
|
||||
mutex_lock(&debugfs_mutex);
|
||||
while ((n = rb_first(&client->handles))) {
|
||||
struct ion_handle *handle = rb_entry(n, struct ion_handle,
|
||||
|
@ -1239,9 +1238,6 @@ static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
|
|||
int pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
|
||||
int i;
|
||||
|
||||
pr_debug("%s: syncing for device %s\n", __func__,
|
||||
dev ? dev_name(dev) : "null");
|
||||
|
||||
if (!ion_buffer_fault_user_mappings(buffer))
|
||||
return;
|
||||
|
||||
|
@ -1295,7 +1291,6 @@ static void ion_vm_open(struct vm_area_struct *vma)
|
|||
mutex_lock(&buffer->lock);
|
||||
list_add(&vma_list->list, &buffer->vmas);
|
||||
mutex_unlock(&buffer->lock);
|
||||
pr_debug("%s: adding %pK\n", __func__, vma);
|
||||
}
|
||||
|
||||
static void ion_vm_close(struct vm_area_struct *vma)
|
||||
|
@ -1303,14 +1298,12 @@ static void ion_vm_close(struct vm_area_struct *vma)
|
|||
struct ion_buffer *buffer = vma->vm_private_data;
|
||||
struct ion_vma_list *vma_list, *tmp;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
mutex_lock(&buffer->lock);
|
||||
list_for_each_entry_safe(vma_list, tmp, &buffer->vmas, list) {
|
||||
if (vma_list->vma != vma)
|
||||
continue;
|
||||
list_del(&vma_list->list);
|
||||
kfree(vma_list);
|
||||
pr_debug("%s: deleting %pK\n", __func__, vma);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&buffer->lock);
|
||||
|
@ -1717,7 +1710,6 @@ static int ion_release(struct inode *inode, struct file *file)
|
|||
{
|
||||
struct ion_client *client = file->private_data;
|
||||
|
||||
pr_debug("%s: %d\n", __func__, __LINE__);
|
||||
ion_client_destroy(client);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1729,7 +1721,6 @@ static int ion_open(struct inode *inode, struct file *file)
|
|||
struct ion_client *client;
|
||||
char debug_name[64];
|
||||
|
||||
pr_debug("%s: %d\n", __func__, __LINE__);
|
||||
snprintf(debug_name, 64, "%u", task_pid_nr(current->group_leader));
|
||||
client = ion_client_create(dev, debug_name);
|
||||
if (IS_ERR(client))
|
||||
|
|
|
@ -65,8 +65,6 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
|
|||
struct device *dev = heap->priv;
|
||||
struct ion_cma_buffer_info *info;
|
||||
|
||||
dev_dbg(dev, "Request buffer allocation len %ld\n", len);
|
||||
|
||||
info = kzalloc(sizeof(struct ion_cma_buffer_info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return ION_CMA_ALLOCATE_FAILED;
|
||||
|
@ -94,7 +92,6 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
|
|||
|
||||
/* keep this for memory release */
|
||||
buffer->priv_virt = info;
|
||||
dev_dbg(dev, "Allocate buffer %pK\n", buffer);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
@ -107,7 +104,6 @@ static void ion_cma_free(struct ion_buffer *buffer)
|
|||
struct device *dev = buffer->heap->priv;
|
||||
struct ion_cma_buffer_info *info = buffer->priv_virt;
|
||||
|
||||
dev_dbg(dev, "Release buffer %pK\n", buffer);
|
||||
/* release memory */
|
||||
dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
|
||||
sg_free_table(info->table);
|
||||
|
|
|
@ -137,6 +137,9 @@ struct gsm_dlci {
|
|||
struct mutex mutex;
|
||||
|
||||
/* Link layer */
|
||||
int mode;
|
||||
#define DLCI_MODE_ABM 0 /* Normal Asynchronous Balanced Mode */
|
||||
#define DLCI_MODE_ADM 1 /* Asynchronous Disconnected Mode */
|
||||
spinlock_t lock; /* Protects the internal state */
|
||||
struct timer_list t1; /* Retransmit timer for SABM and UA */
|
||||
int retries;
|
||||
|
@ -1380,7 +1383,13 @@ retry:
|
|||
ctrl->data = data;
|
||||
ctrl->len = clen;
|
||||
gsm->pending_cmd = ctrl;
|
||||
gsm->cretries = gsm->n2;
|
||||
|
||||
/* If DLCI0 is in ADM mode skip retries, it won't respond */
|
||||
if (gsm->dlci[0]->mode == DLCI_MODE_ADM)
|
||||
gsm->cretries = 1;
|
||||
else
|
||||
gsm->cretries = gsm->n2;
|
||||
|
||||
mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
|
||||
gsm_control_transmit(gsm, ctrl);
|
||||
spin_unlock_irqrestore(&gsm->control_lock, flags);
|
||||
|
@ -1488,6 +1497,7 @@ static void gsm_dlci_t1(unsigned long data)
|
|||
if (debug & 8)
|
||||
pr_info("DLCI %d opening in ADM mode.\n",
|
||||
dlci->addr);
|
||||
dlci->mode = DLCI_MODE_ADM;
|
||||
gsm_dlci_open(dlci);
|
||||
} else {
|
||||
gsm_dlci_close(dlci);
|
||||
|
@ -2881,11 +2891,22 @@ static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
|
|||
static int gsm_carrier_raised(struct tty_port *port)
|
||||
{
|
||||
struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
|
||||
struct gsm_mux *gsm = dlci->gsm;
|
||||
|
||||
/* Not yet open so no carrier info */
|
||||
if (dlci->state != DLCI_OPEN)
|
||||
return 0;
|
||||
if (debug & 2)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Basic mode with control channel in ADM mode may not respond
|
||||
* to CMD_MSC at all and modem_rx is empty.
|
||||
*/
|
||||
if (gsm->encoding == 0 && gsm->dlci[0]->mode == DLCI_MODE_ADM &&
|
||||
!dlci->modem_rx)
|
||||
return 1;
|
||||
|
||||
return dlci->modem_rx & TIOCM_CD;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/termios.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "serial_mctrl_gpio.h"
|
||||
|
||||
|
@ -193,6 +194,7 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
|
|||
|
||||
return gpios;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_init);
|
||||
|
||||
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
|
||||
{
|
||||
|
@ -247,3 +249,6 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
|
|||
disable_irq(gpios->irq[i]);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -3154,7 +3154,10 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)
|
|||
|
||||
kref_init(&tty->kref);
|
||||
tty->magic = TTY_MAGIC;
|
||||
tty_ldisc_init(tty);
|
||||
if (tty_ldisc_init(tty)) {
|
||||
kfree(tty);
|
||||
return NULL;
|
||||
}
|
||||
tty->session = NULL;
|
||||
tty->pgrp = NULL;
|
||||
mutex_init(&tty->legacy_mutex);
|
||||
|
|
|
@ -168,12 +168,11 @@ static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
|
|||
return ERR_CAST(ldops);
|
||||
}
|
||||
|
||||
ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
|
||||
if (ld == NULL) {
|
||||
put_ldops(ldops);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/*
|
||||
* There is no way to handle allocation failure of only 16 bytes.
|
||||
* Let's simplify error handling and save more memory.
|
||||
*/
|
||||
ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL | __GFP_NOFAIL);
|
||||
ld->ops = ldops;
|
||||
ld->tty = tty;
|
||||
|
||||
|
@ -804,12 +803,13 @@ void tty_ldisc_release(struct tty_struct *tty)
|
|||
* the tty structure is not completely set up when this call is made.
|
||||
*/
|
||||
|
||||
void tty_ldisc_init(struct tty_struct *tty)
|
||||
int tty_ldisc_init(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY);
|
||||
if (IS_ERR(ld))
|
||||
panic("n_tty: init_tty");
|
||||
return PTR_ERR(ld);
|
||||
tty->ldisc = ld;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2395,6 +2395,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
|
|||
|
||||
spin_lock_irqsave (&hcd_root_hub_lock, flags);
|
||||
if (hcd->rh_registered) {
|
||||
pm_wakeup_event(&hcd->self.root_hub->dev, 0);
|
||||
set_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
|
||||
queue_work(pm_wq, &hcd->wakeup_work);
|
||||
}
|
||||
|
|
|
@ -643,12 +643,17 @@ void usb_wakeup_notification(struct usb_device *hdev,
|
|||
unsigned int portnum)
|
||||
{
|
||||
struct usb_hub *hub;
|
||||
struct usb_port *port_dev;
|
||||
|
||||
if (!hdev)
|
||||
return;
|
||||
|
||||
hub = usb_hub_to_struct_hub(hdev);
|
||||
if (hub) {
|
||||
port_dev = hub->ports[portnum - 1];
|
||||
if (port_dev && port_dev->child)
|
||||
pm_wakeup_event(&port_dev->child->dev, 0);
|
||||
|
||||
set_bit(portnum, hub->wakeup_bits);
|
||||
kick_hub_wq(hub);
|
||||
}
|
||||
|
@ -3372,8 +3377,11 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
|||
|
||||
/* Skip the initial Clear-Suspend step for a remote wakeup */
|
||||
status = hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
if (status == 0 && !port_is_suspended(hub, portstatus))
|
||||
if (status == 0 && !port_is_suspended(hub, portstatus)) {
|
||||
if (portchange & USB_PORT_STAT_C_SUSPEND)
|
||||
pm_wakeup_event(&udev->dev, 0);
|
||||
goto SuspendCleared;
|
||||
}
|
||||
|
||||
/* see 7.1.7.7; affects power usage, but not budgeting */
|
||||
if (hub_is_superspeed(hub->hdev))
|
||||
|
|
|
@ -45,6 +45,9 @@ static const struct usb_device_id usb_quirk_list[] = {
|
|||
{ USB_DEVICE(0x03f0, 0x0701), .driver_info =
|
||||
USB_QUIRK_STRING_FETCH_255 },
|
||||
|
||||
/* HP v222w 16GB Mini USB Drive */
|
||||
{ USB_DEVICE(0x03f0, 0x3f40), .driver_info = USB_QUIRK_DELAY_INIT },
|
||||
|
||||
/* Creative SB Audigy 2 NX */
|
||||
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ config USB_SERIAL_SIMPLE
|
|||
- Fundamental Software dongle.
|
||||
- Google USB serial devices
|
||||
- HP4x calculators
|
||||
- Libtransistor USB console
|
||||
- a number of Motorola phones
|
||||
- Motorola Tetra devices
|
||||
- Novatel Wireless GPS receivers
|
||||
|
|
|
@ -210,6 +210,7 @@ static const struct usb_device_id id_table[] = {
|
|||
{ USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
|
||||
{ USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */
|
||||
{ USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */
|
||||
{ USB_DEVICE(0x3923, 0x7A0B) }, /* National Instruments USB Serial Console */
|
||||
{ USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
|
||||
{ } /* Terminating Entry */
|
||||
};
|
||||
|
|
|
@ -1911,7 +1911,8 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial)
|
|||
return ftdi_jtag_probe(serial);
|
||||
|
||||
if (udev->product &&
|
||||
(!strcmp(udev->product, "BeagleBone/XDS100V2") ||
|
||||
(!strcmp(udev->product, "Arrow USB Blaster") ||
|
||||
!strcmp(udev->product, "BeagleBone/XDS100V2") ||
|
||||
!strcmp(udev->product, "SNAP Connect E10")))
|
||||
return ftdi_jtag_probe(serial);
|
||||
|
||||
|
|
|
@ -66,6 +66,11 @@ DEVICE(flashloader, FLASHLOADER_IDS);
|
|||
0x01) }
|
||||
DEVICE(google, GOOGLE_IDS);
|
||||
|
||||
/* Libtransistor USB console */
|
||||
#define LIBTRANSISTOR_IDS() \
|
||||
{ USB_DEVICE(0x1209, 0x8b00) }
|
||||
DEVICE(libtransistor, LIBTRANSISTOR_IDS);
|
||||
|
||||
/* ViVOpay USB Serial Driver */
|
||||
#define VIVOPAY_IDS() \
|
||||
{ USB_DEVICE(0x1d5f, 0x1004) } /* ViVOpay 8800 */
|
||||
|
@ -113,6 +118,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
|
|||
&funsoft_device,
|
||||
&flashloader_device,
|
||||
&google_device,
|
||||
&libtransistor_device,
|
||||
&vivopay_device,
|
||||
&moto_modem_device,
|
||||
&motorola_tetra_device,
|
||||
|
@ -129,6 +135,7 @@ static const struct usb_device_id id_table[] = {
|
|||
FUNSOFT_IDS(),
|
||||
FLASHLOADER_IDS(),
|
||||
GOOGLE_IDS(),
|
||||
LIBTRANSISTOR_IDS(),
|
||||
VIVOPAY_IDS(),
|
||||
MOTO_IDS(),
|
||||
MOTOROLA_TETRA_IDS(),
|
||||
|
|
|
@ -201,7 +201,12 @@ static ssize_t rebind_store(struct device_driver *dev, const char *buf,
|
|||
if (!bid)
|
||||
return -ENODEV;
|
||||
|
||||
/* device_attach() callers should hold parent lock for USB */
|
||||
if (bid->udev->dev.parent)
|
||||
device_lock(bid->udev->dev.parent);
|
||||
ret = device_attach(&bid->udev->dev);
|
||||
if (bid->udev->dev.parent)
|
||||
device_unlock(bid->udev->dev.parent);
|
||||
if (ret < 0) {
|
||||
dev_err(&bid->udev->dev, "rebind failed\n");
|
||||
return ret;
|
||||
|
|
|
@ -248,7 +248,7 @@ enum usbip_side {
|
|||
#define SDEV_EVENT_ERROR_SUBMIT (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
|
||||
#define SDEV_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE)
|
||||
|
||||
#define VDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_BYE)
|
||||
#define VDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_RESET | USBIP_EH_BYE)
|
||||
#define VDEV_EVENT_DOWN (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
|
||||
#define VDEV_EVENT_ERROR_TCP (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
|
||||
#define VDEV_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE)
|
||||
|
|
|
@ -673,6 +673,9 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
|
|||
goto mknod_out;
|
||||
}
|
||||
|
||||
if (!S_ISCHR(mode) && !S_ISBLK(mode))
|
||||
goto mknod_out;
|
||||
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
|
||||
goto mknod_out;
|
||||
|
||||
|
@ -681,10 +684,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
|
|||
|
||||
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
|
||||
if (buf == NULL) {
|
||||
kfree(full_path);
|
||||
rc = -ENOMEM;
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
goto mknod_out;
|
||||
}
|
||||
|
||||
if (backup_cred(cifs_sb))
|
||||
|
@ -731,7 +732,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
|
|||
pdev->minor = cpu_to_le64(MINOR(device_number));
|
||||
rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
|
||||
&bytes_written, iov, 1);
|
||||
} /* else if (S_ISFIFO) */
|
||||
}
|
||||
tcon->ses->server->ops->close(xid, tcon, &fid);
|
||||
d_drop(direntry);
|
||||
|
||||
|
|
|
@ -320,6 +320,7 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb,
|
|||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
ext4_grpblk_t offset;
|
||||
ext4_grpblk_t next_zero_bit;
|
||||
ext4_grpblk_t max_bit = EXT4_CLUSTERS_PER_GROUP(sb);
|
||||
ext4_fsblk_t blk;
|
||||
ext4_fsblk_t group_first_block;
|
||||
|
||||
|
@ -337,20 +338,25 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb,
|
|||
/* check whether block bitmap block number is set */
|
||||
blk = ext4_block_bitmap(sb, desc);
|
||||
offset = blk - group_first_block;
|
||||
if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
|
||||
if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit ||
|
||||
!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
|
||||
/* bad block bitmap */
|
||||
return blk;
|
||||
|
||||
/* check whether the inode bitmap block number is set */
|
||||
blk = ext4_inode_bitmap(sb, desc);
|
||||
offset = blk - group_first_block;
|
||||
if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
|
||||
if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit ||
|
||||
!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
|
||||
/* bad block bitmap */
|
||||
return blk;
|
||||
|
||||
/* check whether the inode table block number is set */
|
||||
blk = ext4_inode_table(sb, desc);
|
||||
offset = blk - group_first_block;
|
||||
if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit ||
|
||||
EXT4_B2C(sbi, offset + sbi->s_itb_per_group) >= max_bit)
|
||||
return blk;
|
||||
next_zero_bit = ext4_find_next_zero_bit(bh->b_data,
|
||||
EXT4_B2C(sbi, offset + EXT4_SB(sb)->s_itb_per_group),
|
||||
EXT4_B2C(sbi, offset));
|
||||
|
@ -416,6 +422,7 @@ struct buffer_head *
|
|||
ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
|
||||
{
|
||||
struct ext4_group_desc *desc;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
struct buffer_head *bh;
|
||||
ext4_fsblk_t bitmap_blk;
|
||||
int err;
|
||||
|
@ -424,6 +431,12 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
|
|||
if (!desc)
|
||||
return ERR_PTR(-EFSCORRUPTED);
|
||||
bitmap_blk = ext4_block_bitmap(sb, desc);
|
||||
if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
|
||||
(bitmap_blk >= ext4_blocks_count(sbi->s_es))) {
|
||||
ext4_error(sb, "Invalid block bitmap block %llu in "
|
||||
"block_group %u", bitmap_blk, block_group);
|
||||
return ERR_PTR(-EFSCORRUPTED);
|
||||
}
|
||||
bh = sb_getblk(sb, bitmap_blk);
|
||||
if (unlikely(!bh)) {
|
||||
ext4_error(sb, "Cannot get buffer for block bitmap - "
|
||||
|
|
|
@ -5372,8 +5372,9 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
|
|||
stop = le32_to_cpu(extent->ee_block);
|
||||
|
||||
/*
|
||||
* In case of left shift, Don't start shifting extents until we make
|
||||
* sure the hole is big enough to accommodate the shift.
|
||||
* For left shifts, make sure the hole on the left is big enough to
|
||||
* accommodate the shift. For right shifts, make sure the last extent
|
||||
* won't be shifted beyond EXT_MAX_BLOCKS.
|
||||
*/
|
||||
if (SHIFT == SHIFT_LEFT) {
|
||||
path = ext4_find_extent(inode, start - 1, &path,
|
||||
|
@ -5393,9 +5394,14 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
|
|||
|
||||
if ((start == ex_start && shift > ex_start) ||
|
||||
(shift > start - ex_end)) {
|
||||
ext4_ext_drop_refs(path);
|
||||
kfree(path);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if (shift > EXT_MAX_BLOCKS -
|
||||
(stop + ext4_ext_get_actual_len(extent))) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@ static struct buffer_head *
|
|||
ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
|
||||
{
|
||||
struct ext4_group_desc *desc;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
struct buffer_head *bh = NULL;
|
||||
ext4_fsblk_t bitmap_blk;
|
||||
int err;
|
||||
|
@ -128,6 +129,12 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
|
|||
return ERR_PTR(-EFSCORRUPTED);
|
||||
|
||||
bitmap_blk = ext4_inode_bitmap(sb, desc);
|
||||
if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
|
||||
(bitmap_blk >= ext4_blocks_count(sbi->s_es))) {
|
||||
ext4_error(sb, "Invalid inode bitmap blk %llu in "
|
||||
"block_group %u", bitmap_blk, block_group);
|
||||
return ERR_PTR(-EFSCORRUPTED);
|
||||
}
|
||||
bh = sb_getblk(sb, bitmap_blk);
|
||||
if (unlikely(!bh)) {
|
||||
ext4_error(sb, "Cannot read inode bitmap - "
|
||||
|
|
|
@ -527,6 +527,7 @@ int jbd2_journal_start_reserved(handle_t *handle, unsigned int type,
|
|||
*/
|
||||
ret = start_this_handle(journal, handle, GFP_NOFS);
|
||||
if (ret < 0) {
|
||||
handle->h_journal = journal;
|
||||
jbd2_journal_free_reserved(handle);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -131,6 +131,8 @@ out:
|
|||
|
||||
static void sdcardfs_d_release(struct dentry *dentry)
|
||||
{
|
||||
if (!dentry || !dentry->d_fsdata)
|
||||
return;
|
||||
/* release and reset the lower paths */
|
||||
if (has_graft_path(dentry))
|
||||
sdcardfs_put_reset_orig_path(dentry);
|
||||
|
|
|
@ -41,8 +41,6 @@ void sdcardfs_destroy_dentry_cache(void)
|
|||
|
||||
void free_dentry_private_data(struct dentry *dentry)
|
||||
{
|
||||
if (!dentry || !dentry->d_fsdata)
|
||||
return;
|
||||
kmem_cache_free(sdcardfs_dentry_cachep, dentry->d_fsdata);
|
||||
dentry->d_fsdata = NULL;
|
||||
}
|
||||
|
|
|
@ -316,7 +316,7 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb,
|
|||
sb->s_root = d_make_root(inode);
|
||||
if (!sb->s_root) {
|
||||
err = -ENOMEM;
|
||||
goto out_iput;
|
||||
goto out_sput;
|
||||
}
|
||||
d_set_d_op(sb->s_root, &sdcardfs_ci_dops);
|
||||
|
||||
|
@ -361,8 +361,7 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb,
|
|||
/* no longer needed: free_dentry_private_data(sb->s_root); */
|
||||
out_freeroot:
|
||||
dput(sb->s_root);
|
||||
out_iput:
|
||||
iput(inode);
|
||||
sb->s_root = NULL;
|
||||
out_sput:
|
||||
/* drop refs we took earlier */
|
||||
atomic_dec(&lower_sb->s_active);
|
||||
|
@ -422,7 +421,7 @@ void sdcardfs_kill_sb(struct super_block *sb)
|
|||
{
|
||||
struct sdcardfs_sb_info *sbi;
|
||||
|
||||
if (sb->s_magic == SDCARDFS_SUPER_MAGIC) {
|
||||
if (sb->s_magic == SDCARDFS_SUPER_MAGIC && sb->s_fs_info) {
|
||||
sbi = SDCARDFS_SB(sb);
|
||||
mutex_lock(&sdcardfs_super_list_lock);
|
||||
list_del(&sbi->list);
|
||||
|
|
|
@ -585,7 +585,7 @@ static inline bool skb_vlan_tagged(const struct sk_buff *skb)
|
|||
* Returns true if the skb is tagged with multiple vlan headers, regardless
|
||||
* of whether it is hardware accelerated or not.
|
||||
*/
|
||||
static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb)
|
||||
static inline bool skb_vlan_tagged_multi(struct sk_buff *skb)
|
||||
{
|
||||
__be16 protocol = skb->protocol;
|
||||
|
||||
|
@ -596,6 +596,9 @@ static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb)
|
|||
protocol != htons(ETH_P_8021AD)))
|
||||
return false;
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN)))
|
||||
return false;
|
||||
|
||||
veh = (struct vlan_ethhdr *)skb->data;
|
||||
protocol = veh->h_vlan_encapsulated_proto;
|
||||
}
|
||||
|
@ -613,7 +616,7 @@ static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb)
|
|||
*
|
||||
* Returns features without unsafe ones if the skb has multiple tags.
|
||||
*/
|
||||
static inline netdev_features_t vlan_features_check(const struct sk_buff *skb,
|
||||
static inline netdev_features_t vlan_features_check(struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
if (skb_vlan_tagged_multi(skb)) {
|
||||
|
|
|
@ -85,6 +85,7 @@ struct flchip {
|
|||
unsigned int write_suspended:1;
|
||||
unsigned int erase_suspended:1;
|
||||
unsigned long in_progress_block_addr;
|
||||
unsigned long in_progress_block_mask;
|
||||
|
||||
struct mutex mutex;
|
||||
wait_queue_head_t wq; /* Wait on here when we're waiting for the chip
|
||||
|
|
|
@ -586,7 +586,7 @@ extern int tty_unregister_ldisc(int disc);
|
|||
extern int tty_set_ldisc(struct tty_struct *tty, int ldisc);
|
||||
extern int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty);
|
||||
extern void tty_ldisc_release(struct tty_struct *tty);
|
||||
extern void tty_ldisc_init(struct tty_struct *tty);
|
||||
extern int __must_check tty_ldisc_init(struct tty_struct *tty);
|
||||
extern void tty_ldisc_deinit(struct tty_struct *tty);
|
||||
extern void tty_ldisc_begin(void);
|
||||
|
||||
|
|
|
@ -124,6 +124,9 @@ int virtio_device_freeze(struct virtio_device *dev);
|
|||
int virtio_device_restore(struct virtio_device *dev);
|
||||
#endif
|
||||
|
||||
#define virtio_device_for_each_vq(vdev, vq) \
|
||||
list_for_each_entry(vq, &vdev->vqs, list)
|
||||
|
||||
/**
|
||||
* virtio_driver - operations for a virtio I/O driver
|
||||
* @driver: underlying device driver (populate name and owner).
|
||||
|
|
|
@ -97,6 +97,7 @@ static __inline__ char llc_backlog_type(struct sk_buff *skb)
|
|||
|
||||
struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority,
|
||||
struct proto *prot, int kern);
|
||||
void llc_sk_stop_all_timers(struct sock *sk, bool sync);
|
||||
void llc_sk_free(struct sock *sk);
|
||||
|
||||
void llc_sk_reset(struct sock *sk);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/nospec.h>
|
||||
#include <sound/asound.h>
|
||||
|
||||
#define snd_kcontrol_chip(kcontrol) ((kcontrol)->private_data)
|
||||
|
@ -147,12 +148,14 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type);
|
|||
|
||||
static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
|
||||
{
|
||||
return id->numid - kctl->id.numid;
|
||||
unsigned int ioff = id->numid - kctl->id.numid;
|
||||
return array_index_nospec(ioff, kctl->count);
|
||||
}
|
||||
|
||||
static inline unsigned int snd_ctl_get_ioffidx(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
|
||||
{
|
||||
return id->index - kctl->id.index;
|
||||
unsigned int ioff = id->index - kctl->id.index;
|
||||
return array_index_nospec(ioff, kctl->count);
|
||||
}
|
||||
|
||||
static inline unsigned int snd_ctl_get_ioff(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
|
||||
|
|
|
@ -831,6 +831,7 @@ struct kvm_ppc_smmu_info {
|
|||
#define KVM_CAP_GUEST_DEBUG_HW_WPS 120
|
||||
#define KVM_CAP_SPLIT_IRQCHIP 121
|
||||
#define KVM_CAP_IOEVENTFD_ANY_LENGTH 122
|
||||
#define KVM_CAP_S390_BPB 152
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
|
|
|
@ -8342,9 +8342,9 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
|
|||
* __u16 sample size limit.
|
||||
*/
|
||||
if (attr->sample_stack_user >= USHRT_MAX)
|
||||
ret = -EINVAL;
|
||||
return -EINVAL;
|
||||
else if (!IS_ALIGNED(attr->sample_stack_user, sizeof(u64)))
|
||||
ret = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (attr->sample_type & PERF_SAMPLE_REGS_INTR)
|
||||
|
|
|
@ -234,14 +234,12 @@ static int kobject_add_internal(struct kobject *kobj)
|
|||
|
||||
/* be noisy on error issues */
|
||||
if (error == -EEXIST)
|
||||
WARN(1, "%s failed for %s with "
|
||||
"-EEXIST, don't try to register things with "
|
||||
"the same name in the same directory.\n",
|
||||
__func__, kobject_name(kobj));
|
||||
pr_err("%s failed for %s with -EEXIST, don't try to register things with the same name in the same directory.\n",
|
||||
__func__, kobject_name(kobj));
|
||||
else
|
||||
WARN(1, "%s failed for %s (error: %d parent: %s)\n",
|
||||
__func__, kobject_name(kobj), error,
|
||||
parent ? kobject_name(parent) : "'none'");
|
||||
pr_err("%s failed for %s (error: %d parent: %s)\n",
|
||||
__func__, kobject_name(kobj), error,
|
||||
parent ? kobject_name(parent) : "'none'");
|
||||
} else
|
||||
kobj->state_in_sysfs = 1;
|
||||
|
||||
|
|
|
@ -2531,6 +2531,11 @@ static int try_write(struct ceph_connection *con)
|
|||
int ret = 1;
|
||||
|
||||
dout("try_write start %p state %lu\n", con, con->state);
|
||||
if (con->state != CON_STATE_PREOPEN &&
|
||||
con->state != CON_STATE_CONNECTING &&
|
||||
con->state != CON_STATE_NEGOTIATING &&
|
||||
con->state != CON_STATE_OPEN)
|
||||
return 0;
|
||||
|
||||
more:
|
||||
dout("try_write out_kvec_bytes %d\n", con->out_kvec_bytes);
|
||||
|
@ -2556,6 +2561,8 @@ more:
|
|||
}
|
||||
|
||||
more_kvec:
|
||||
BUG_ON(!con->sock);
|
||||
|
||||
/* kvec data queued? */
|
||||
if (con->out_kvec_left) {
|
||||
ret = write_partial_kvec(con);
|
||||
|
|
|
@ -2708,7 +2708,7 @@ netdev_features_t passthru_features_check(struct sk_buff *skb,
|
|||
}
|
||||
EXPORT_SYMBOL(passthru_features_check);
|
||||
|
||||
static netdev_features_t dflt_features_check(const struct sk_buff *skb,
|
||||
static netdev_features_t dflt_features_check(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
netdev_features_t features)
|
||||
{
|
||||
|
|
|
@ -54,7 +54,8 @@ do { \
|
|||
static void neigh_timer_handler(unsigned long arg);
|
||||
static void __neigh_notify(struct neighbour *n, int type, int flags);
|
||||
static void neigh_update_notify(struct neighbour *neigh);
|
||||
static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
|
||||
static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
|
||||
struct net_device *dev);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static const struct file_operations neigh_stat_seq_fops;
|
||||
|
@ -254,8 +255,7 @@ int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
|
|||
{
|
||||
write_lock_bh(&tbl->lock);
|
||||
neigh_flush_dev(tbl, dev);
|
||||
pneigh_ifdown(tbl, dev);
|
||||
write_unlock_bh(&tbl->lock);
|
||||
pneigh_ifdown_and_unlock(tbl, dev);
|
||||
|
||||
del_timer_sync(&tbl->proxy_timer);
|
||||
pneigh_queue_purge(&tbl->proxy_queue);
|
||||
|
@ -645,9 +645,10 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
|
||||
static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct pneigh_entry *n, **np;
|
||||
struct pneigh_entry *n, **np, *freelist = NULL;
|
||||
u32 h;
|
||||
|
||||
for (h = 0; h <= PNEIGH_HASHMASK; h++) {
|
||||
|
@ -655,16 +656,23 @@ static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
|
|||
while ((n = *np) != NULL) {
|
||||
if (!dev || n->dev == dev) {
|
||||
*np = n->next;
|
||||
if (tbl->pdestructor)
|
||||
tbl->pdestructor(n);
|
||||
if (n->dev)
|
||||
dev_put(n->dev);
|
||||
kfree(n);
|
||||
n->next = freelist;
|
||||
freelist = n;
|
||||
continue;
|
||||
}
|
||||
np = &n->next;
|
||||
}
|
||||
}
|
||||
write_unlock_bh(&tbl->lock);
|
||||
while ((n = freelist)) {
|
||||
freelist = n->next;
|
||||
n->next = NULL;
|
||||
if (tbl->pdestructor)
|
||||
tbl->pdestructor(n);
|
||||
if (n->dev)
|
||||
dev_put(n->dev);
|
||||
kfree(n);
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
@ -2280,12 +2288,16 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
|
|||
|
||||
err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL);
|
||||
if (!err) {
|
||||
if (tb[NDA_IFINDEX])
|
||||
if (tb[NDA_IFINDEX]) {
|
||||
if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32))
|
||||
return -EINVAL;
|
||||
filter_idx = nla_get_u32(tb[NDA_IFINDEX]);
|
||||
|
||||
if (tb[NDA_MASTER])
|
||||
}
|
||||
if (tb[NDA_MASTER]) {
|
||||
if (nla_len(tb[NDA_MASTER]) != sizeof(u32))
|
||||
return -EINVAL;
|
||||
filter_master_idx = nla_get_u32(tb[NDA_MASTER]);
|
||||
|
||||
}
|
||||
if (filter_idx || filter_master_idx)
|
||||
flags |= NLM_F_DUMP_FILTERED;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/moduleparam.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/keyctl.h>
|
||||
#include <linux/err.h>
|
||||
|
@ -91,9 +92,9 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
|
|||
|
||||
next_opt = memchr(opt, '#', end - opt) ?: end;
|
||||
opt_len = next_opt - opt;
|
||||
if (!opt_len) {
|
||||
printk(KERN_WARNING
|
||||
"Empty option to dns_resolver key\n");
|
||||
if (opt_len <= 0 || opt_len > 128) {
|
||||
pr_warn_ratelimited("Invalid option length (%d) for dns_resolver key\n",
|
||||
opt_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -127,10 +128,8 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
|
|||
}
|
||||
|
||||
bad_option_value:
|
||||
printk(KERN_WARNING
|
||||
"Option '%*.*s' to dns_resolver key:"
|
||||
" bad/missing value\n",
|
||||
opt_nlen, opt_nlen, opt);
|
||||
pr_warn_ratelimited("Option '%*.*s' to dns_resolver key: bad/missing value\n",
|
||||
opt_nlen, opt_nlen, opt);
|
||||
return -EINVAL;
|
||||
} while (opt = next_opt + 1, opt < end);
|
||||
}
|
||||
|
|
|
@ -2598,8 +2598,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
|
|||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
case TCP_MD5SIG:
|
||||
/* Read the IP->Key mappings from userspace */
|
||||
err = tp->af_specific->md5_parse(sk, optval, optlen);
|
||||
if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))
|
||||
err = tp->af_specific->md5_parse(sk, optval, optlen);
|
||||
else
|
||||
err = -EINVAL;
|
||||
break;
|
||||
#endif
|
||||
case TCP_USER_TIMEOUT:
|
||||
|
|
|
@ -3870,11 +3870,8 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th)
|
|||
int length = (th->doff << 2) - sizeof(*th);
|
||||
const u8 *ptr = (const u8 *)(th + 1);
|
||||
|
||||
/* If the TCP option is too short, we can short cut */
|
||||
if (length < TCPOLEN_MD5SIG)
|
||||
return NULL;
|
||||
|
||||
while (length > 0) {
|
||||
/* If not enough data remaining, we can short cut */
|
||||
while (length >= TCPOLEN_MD5SIG) {
|
||||
int opcode = *ptr++;
|
||||
int opsize;
|
||||
|
||||
|
|
|
@ -2699,6 +2699,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
|
|||
|
||||
static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
|
||||
[RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
|
||||
[RTA_PREFSRC] = { .len = sizeof(struct in6_addr) },
|
||||
[RTA_OIF] = { .type = NLA_U32 },
|
||||
[RTA_IIF] = { .type = NLA_U32 },
|
||||
[RTA_PRIORITY] = { .type = NLA_U32 },
|
||||
|
@ -2708,6 +2709,7 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
|
|||
[RTA_ENCAP_TYPE] = { .type = NLA_U16 },
|
||||
[RTA_ENCAP] = { .type = NLA_NESTED },
|
||||
[RTA_UID] = { .type = NLA_U32 },
|
||||
[RTA_TABLE] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
|
|
|
@ -606,6 +606,13 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
|
|||
lock_sock(sk);
|
||||
|
||||
error = -EINVAL;
|
||||
|
||||
if (sockaddr_len != sizeof(struct sockaddr_pppol2tp) &&
|
||||
sockaddr_len != sizeof(struct sockaddr_pppol2tpv3) &&
|
||||
sockaddr_len != sizeof(struct sockaddr_pppol2tpin6) &&
|
||||
sockaddr_len != sizeof(struct sockaddr_pppol2tpv3in6))
|
||||
goto end;
|
||||
|
||||
if (sp->sa_protocol != PX_PROTO_OL2TP)
|
||||
goto end;
|
||||
|
||||
|
|
|
@ -197,9 +197,19 @@ static int llc_ui_release(struct socket *sock)
|
|||
llc->laddr.lsap, llc->daddr.lsap);
|
||||
if (!llc_send_disc(sk))
|
||||
llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo);
|
||||
if (!sock_flag(sk, SOCK_ZAPPED))
|
||||
if (!sock_flag(sk, SOCK_ZAPPED)) {
|
||||
struct llc_sap *sap = llc->sap;
|
||||
|
||||
/* Hold this for release_sock(), so that llc_backlog_rcv()
|
||||
* could still use it.
|
||||
*/
|
||||
llc_sap_hold(sap);
|
||||
llc_sap_remove_socket(llc->sap, sk);
|
||||
release_sock(sk);
|
||||
release_sock(sk);
|
||||
llc_sap_put(sap);
|
||||
} else {
|
||||
release_sock(sk);
|
||||
}
|
||||
if (llc->dev)
|
||||
dev_put(llc->dev);
|
||||
sock_put(sk);
|
||||
|
|
|
@ -1096,14 +1096,7 @@ int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct sk_buff *skb)
|
|||
|
||||
int llc_conn_ac_stop_all_timers(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct llc_sock *llc = llc_sk(sk);
|
||||
|
||||
del_timer(&llc->pf_cycle_timer.timer);
|
||||
del_timer(&llc->ack_timer.timer);
|
||||
del_timer(&llc->rej_sent_timer.timer);
|
||||
del_timer(&llc->busy_state_timer.timer);
|
||||
llc->ack_must_be_send = 0;
|
||||
llc->ack_pf = 0;
|
||||
llc_sk_stop_all_timers(sk, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -951,6 +951,26 @@ out:
|
|||
return sk;
|
||||
}
|
||||
|
||||
void llc_sk_stop_all_timers(struct sock *sk, bool sync)
|
||||
{
|
||||
struct llc_sock *llc = llc_sk(sk);
|
||||
|
||||
if (sync) {
|
||||
del_timer_sync(&llc->pf_cycle_timer.timer);
|
||||
del_timer_sync(&llc->ack_timer.timer);
|
||||
del_timer_sync(&llc->rej_sent_timer.timer);
|
||||
del_timer_sync(&llc->busy_state_timer.timer);
|
||||
} else {
|
||||
del_timer(&llc->pf_cycle_timer.timer);
|
||||
del_timer(&llc->ack_timer.timer);
|
||||
del_timer(&llc->rej_sent_timer.timer);
|
||||
del_timer(&llc->busy_state_timer.timer);
|
||||
}
|
||||
|
||||
llc->ack_must_be_send = 0;
|
||||
llc->ack_pf = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* llc_sk_free - Frees a LLC socket
|
||||
* @sk - socket to free
|
||||
|
@ -963,7 +983,7 @@ void llc_sk_free(struct sock *sk)
|
|||
|
||||
llc->state = LLC_CONN_OUT_OF_SVC;
|
||||
/* Stop all (possibly) running timers */
|
||||
llc_conn_ac_stop_all_timers(sk, NULL);
|
||||
llc_sk_stop_all_timers(sk, true);
|
||||
#ifdef DEBUG_LLC_CONN_ALLOC
|
||||
printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __func__,
|
||||
skb_queue_len(&llc->pdu_unack_q),
|
||||
|
|
|
@ -332,11 +332,11 @@ static void packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb)
|
|||
skb_set_queue_mapping(skb, queue_index);
|
||||
}
|
||||
|
||||
/* register_prot_hook must be invoked with the po->bind_lock held,
|
||||
/* __register_prot_hook must be invoked through register_prot_hook
|
||||
* or from a context in which asynchronous accesses to the packet
|
||||
* socket is not possible (packet_create()).
|
||||
*/
|
||||
static void register_prot_hook(struct sock *sk)
|
||||
static void __register_prot_hook(struct sock *sk)
|
||||
{
|
||||
struct packet_sock *po = pkt_sk(sk);
|
||||
|
||||
|
@ -351,8 +351,13 @@ static void register_prot_hook(struct sock *sk)
|
|||
}
|
||||
}
|
||||
|
||||
/* {,__}unregister_prot_hook() must be invoked with the po->bind_lock
|
||||
* held. If the sync parameter is true, we will temporarily drop
|
||||
static void register_prot_hook(struct sock *sk)
|
||||
{
|
||||
lockdep_assert_held_once(&pkt_sk(sk)->bind_lock);
|
||||
__register_prot_hook(sk);
|
||||
}
|
||||
|
||||
/* If the sync parameter is true, we will temporarily drop
|
||||
* the po->bind_lock and do a synchronize_net to make sure no
|
||||
* asynchronous packet processing paths still refer to the elements
|
||||
* of po->prot_hook. If the sync parameter is false, it is the
|
||||
|
@ -362,6 +367,8 @@ static void __unregister_prot_hook(struct sock *sk, bool sync)
|
|||
{
|
||||
struct packet_sock *po = pkt_sk(sk);
|
||||
|
||||
lockdep_assert_held_once(&po->bind_lock);
|
||||
|
||||
po->running = 0;
|
||||
|
||||
if (po->fanout)
|
||||
|
@ -2892,6 +2899,7 @@ static int packet_release(struct socket *sock)
|
|||
|
||||
packet_flush_mclist(sk);
|
||||
|
||||
lock_sock(sk);
|
||||
if (po->rx_ring.pg_vec) {
|
||||
memset(&req_u, 0, sizeof(req_u));
|
||||
packet_set_ring(sk, &req_u, 1, 0);
|
||||
|
@ -2901,6 +2909,7 @@ static int packet_release(struct socket *sock)
|
|||
memset(&req_u, 0, sizeof(req_u));
|
||||
packet_set_ring(sk, &req_u, 1, 1);
|
||||
}
|
||||
release_sock(sk);
|
||||
|
||||
f = fanout_release(sk);
|
||||
|
||||
|
@ -3134,7 +3143,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
|
|||
|
||||
if (proto) {
|
||||
po->prot_hook.type = proto;
|
||||
register_prot_hook(sk);
|
||||
__register_prot_hook(sk);
|
||||
}
|
||||
|
||||
mutex_lock(&net->packet.sklist_lock);
|
||||
|
@ -3570,6 +3579,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|||
union tpacket_req_u req_u;
|
||||
int len;
|
||||
|
||||
lock_sock(sk);
|
||||
switch (po->tp_version) {
|
||||
case TPACKET_V1:
|
||||
case TPACKET_V2:
|
||||
|
@ -3580,14 +3590,21 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|||
len = sizeof(req_u.req3);
|
||||
break;
|
||||
}
|
||||
if (optlen < len)
|
||||
return -EINVAL;
|
||||
if (pkt_sk(sk)->has_vnet_hdr)
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&req_u.req, optval, len))
|
||||
return -EFAULT;
|
||||
return packet_set_ring(sk, &req_u, 0,
|
||||
optname == PACKET_TX_RING);
|
||||
if (optlen < len) {
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
if (pkt_sk(sk)->has_vnet_hdr) {
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
if (copy_from_user(&req_u.req, optval, len))
|
||||
ret = -EFAULT;
|
||||
else
|
||||
ret = packet_set_ring(sk, &req_u, 0,
|
||||
optname == PACKET_TX_RING);
|
||||
}
|
||||
}
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
case PACKET_COPY_THRESH:
|
||||
{
|
||||
|
@ -3653,12 +3670,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|||
|
||||
if (optlen != sizeof(val))
|
||||
return -EINVAL;
|
||||
if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
|
||||
return -EBUSY;
|
||||
if (copy_from_user(&val, optval, sizeof(val)))
|
||||
return -EFAULT;
|
||||
po->tp_loss = !!val;
|
||||
return 0;
|
||||
|
||||
lock_sock(sk);
|
||||
if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
|
||||
ret = -EBUSY;
|
||||
} else {
|
||||
po->tp_loss = !!val;
|
||||
ret = 0;
|
||||
}
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
case PACKET_AUXDATA:
|
||||
{
|
||||
|
@ -3669,7 +3692,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|||
if (copy_from_user(&val, optval, sizeof(val)))
|
||||
return -EFAULT;
|
||||
|
||||
lock_sock(sk);
|
||||
po->auxdata = !!val;
|
||||
release_sock(sk);
|
||||
return 0;
|
||||
}
|
||||
case PACKET_ORIGDEV:
|
||||
|
@ -3681,7 +3706,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|||
if (copy_from_user(&val, optval, sizeof(val)))
|
||||
return -EFAULT;
|
||||
|
||||
lock_sock(sk);
|
||||
po->origdev = !!val;
|
||||
release_sock(sk);
|
||||
return 0;
|
||||
}
|
||||
case PACKET_VNET_HDR:
|
||||
|
@ -3690,15 +3717,20 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|||
|
||||
if (sock->type != SOCK_RAW)
|
||||
return -EINVAL;
|
||||
if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
|
||||
return -EBUSY;
|
||||
if (optlen < sizeof(val))
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&val, optval, sizeof(val)))
|
||||
return -EFAULT;
|
||||
|
||||
po->has_vnet_hdr = !!val;
|
||||
return 0;
|
||||
lock_sock(sk);
|
||||
if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
|
||||
ret = -EBUSY;
|
||||
} else {
|
||||
po->has_vnet_hdr = !!val;
|
||||
ret = 0;
|
||||
}
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
case PACKET_TIMESTAMP:
|
||||
{
|
||||
|
@ -3736,11 +3768,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|||
|
||||
if (optlen != sizeof(val))
|
||||
return -EINVAL;
|
||||
if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
|
||||
return -EBUSY;
|
||||
if (copy_from_user(&val, optval, sizeof(val)))
|
||||
return -EFAULT;
|
||||
po->tp_tx_has_off = !!val;
|
||||
|
||||
lock_sock(sk);
|
||||
if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
|
||||
ret = -EBUSY;
|
||||
} else {
|
||||
po->tp_tx_has_off = !!val;
|
||||
ret = 0;
|
||||
}
|
||||
release_sock(sk);
|
||||
return 0;
|
||||
}
|
||||
case PACKET_QDISC_BYPASS:
|
||||
|
@ -4116,7 +4154,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
|
|||
/* Added to avoid minimal code churn */
|
||||
struct tpacket_req *req = &req_u->req;
|
||||
|
||||
lock_sock(sk);
|
||||
/* Opening a Tx-ring is NOT supported in TPACKET_V3 */
|
||||
if (!closing && tx_ring && (po->tp_version > TPACKET_V2)) {
|
||||
WARN(1, "Tx-ring is not supported.\n");
|
||||
|
@ -4252,7 +4289,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
|
|||
if (pg_vec)
|
||||
free_pg_vec(pg_vec, order, req->tp_block_nr);
|
||||
out:
|
||||
release_sock(sk);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,10 +109,12 @@ struct packet_sock {
|
|||
int copy_thresh;
|
||||
spinlock_t bind_lock;
|
||||
struct mutex pg_vec_lock;
|
||||
unsigned int running:1, /* prot_hook is attached*/
|
||||
auxdata:1,
|
||||
unsigned int running; /* bind_lock must be held */
|
||||
unsigned int auxdata:1, /* writer must hold sock lock */
|
||||
origdev:1,
|
||||
has_vnet_hdr:1;
|
||||
has_vnet_hdr:1,
|
||||
tp_loss:1,
|
||||
tp_tx_has_off:1;
|
||||
int pressure;
|
||||
int ifindex; /* bound device */
|
||||
__be16 num;
|
||||
|
@ -122,8 +124,6 @@ struct packet_sock {
|
|||
enum tpacket_versions tp_version;
|
||||
unsigned int tp_hdrlen;
|
||||
unsigned int tp_reserve;
|
||||
unsigned int tp_loss:1;
|
||||
unsigned int tp_tx_has_off:1;
|
||||
unsigned int tp_tstamp;
|
||||
struct net_device __rcu *cached_dev;
|
||||
int (*xmit)(struct sk_buff *skb);
|
||||
|
|
|
@ -519,44 +519,47 @@ static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
|
|||
addr->v6.sin6_scope_id = 0;
|
||||
}
|
||||
|
||||
static int __sctp_v6_cmp_addr(const union sctp_addr *addr1,
|
||||
const union sctp_addr *addr2)
|
||||
{
|
||||
if (addr1->sa.sa_family != addr2->sa.sa_family) {
|
||||
if (addr1->sa.sa_family == AF_INET &&
|
||||
addr2->sa.sa_family == AF_INET6 &&
|
||||
ipv6_addr_v4mapped(&addr2->v6.sin6_addr) &&
|
||||
addr2->v6.sin6_addr.s6_addr32[3] ==
|
||||
addr1->v4.sin_addr.s_addr)
|
||||
return 1;
|
||||
|
||||
if (addr2->sa.sa_family == AF_INET &&
|
||||
addr1->sa.sa_family == AF_INET6 &&
|
||||
ipv6_addr_v4mapped(&addr1->v6.sin6_addr) &&
|
||||
addr1->v6.sin6_addr.s6_addr32[3] ==
|
||||
addr2->v4.sin_addr.s_addr)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ipv6_addr_equal(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr))
|
||||
return 0;
|
||||
|
||||
/* If this is a linklocal address, compare the scope_id. */
|
||||
if ((ipv6_addr_type(&addr1->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) &&
|
||||
addr1->v6.sin6_scope_id && addr2->v6.sin6_scope_id &&
|
||||
addr1->v6.sin6_scope_id != addr2->v6.sin6_scope_id)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compare addresses exactly.
|
||||
* v4-mapped-v6 is also in consideration.
|
||||
*/
|
||||
static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
|
||||
const union sctp_addr *addr2)
|
||||
{
|
||||
if (addr1->sa.sa_family != addr2->sa.sa_family) {
|
||||
if (addr1->sa.sa_family == AF_INET &&
|
||||
addr2->sa.sa_family == AF_INET6 &&
|
||||
ipv6_addr_v4mapped(&addr2->v6.sin6_addr)) {
|
||||
if (addr2->v6.sin6_port == addr1->v4.sin_port &&
|
||||
addr2->v6.sin6_addr.s6_addr32[3] ==
|
||||
addr1->v4.sin_addr.s_addr)
|
||||
return 1;
|
||||
}
|
||||
if (addr2->sa.sa_family == AF_INET &&
|
||||
addr1->sa.sa_family == AF_INET6 &&
|
||||
ipv6_addr_v4mapped(&addr1->v6.sin6_addr)) {
|
||||
if (addr1->v6.sin6_port == addr2->v4.sin_port &&
|
||||
addr1->v6.sin6_addr.s6_addr32[3] ==
|
||||
addr2->v4.sin_addr.s_addr)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (addr1->v6.sin6_port != addr2->v6.sin6_port)
|
||||
return 0;
|
||||
if (!ipv6_addr_equal(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr))
|
||||
return 0;
|
||||
/* If this is a linklocal address, compare the scope_id. */
|
||||
if (ipv6_addr_type(&addr1->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) {
|
||||
if (addr1->v6.sin6_scope_id && addr2->v6.sin6_scope_id &&
|
||||
(addr1->v6.sin6_scope_id != addr2->v6.sin6_scope_id)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return __sctp_v6_cmp_addr(addr1, addr2) &&
|
||||
addr1->v6.sin6_port == addr2->v6.sin6_port;
|
||||
}
|
||||
|
||||
/* Initialize addr struct to INADDR_ANY. */
|
||||
|
@ -843,8 +846,8 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1,
|
|||
const union sctp_addr *addr2,
|
||||
struct sctp_sock *opt)
|
||||
{
|
||||
struct sctp_af *af1, *af2;
|
||||
struct sock *sk = sctp_opt2sk(opt);
|
||||
struct sctp_af *af1, *af2;
|
||||
|
||||
af1 = sctp_get_af_specific(addr1->sa.sa_family);
|
||||
af2 = sctp_get_af_specific(addr2->sa.sa_family);
|
||||
|
@ -860,10 +863,7 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1,
|
|||
if (sctp_is_any(sk, addr1) || sctp_is_any(sk, addr2))
|
||||
return 1;
|
||||
|
||||
if (addr1->sa.sa_family != addr2->sa.sa_family)
|
||||
return 0;
|
||||
|
||||
return af1->cmp_addr(addr1, addr2);
|
||||
return __sctp_v6_cmp_addr(addr1, addr2);
|
||||
}
|
||||
|
||||
/* Verify that the provided sockaddr looks bindable. Common verification,
|
||||
|
|
|
@ -44,7 +44,8 @@
|
|||
|
||||
static const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = {
|
||||
[TIPC_NLA_NET_UNSPEC] = { .type = NLA_UNSPEC },
|
||||
[TIPC_NLA_NET_ID] = { .type = NLA_U32 }
|
||||
[TIPC_NLA_NET_ID] = { .type = NLA_U32 },
|
||||
[TIPC_NLA_NET_ADDR] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -2765,6 +2765,7 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
|
|||
sync_ptr.s.status.hw_ptr = status->hw_ptr;
|
||||
sync_ptr.s.status.tstamp = status->tstamp;
|
||||
sync_ptr.s.status.suspended_state = status->suspended_state;
|
||||
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
|
||||
return -EFAULT;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue