Compare commits
114 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f8bc2bb0e | |||
| e64cd7a033 | |||
| 5227ac4dda | |||
| 41dc53ab98 | |||
| f98a928d6e | |||
| 88e373c047 | |||
| 69412e8ac6 | |||
| 2840e52f67 | |||
| c07fd3caad | |||
| cb2008b4de | |||
| b5c36e7734 | |||
| 7b7a6e872d | |||
| 987daa48f8 | |||
| 569cac5a50 | |||
| a58365a79a | |||
| 0e663d88f9 | |||
| 3cef7ef9c4 | |||
| 795c687eac | |||
| a85ca00279 | |||
| ab46fb3ef6 | |||
| 910d9e8839 | |||
| 0111438d7c | |||
| 97d92f0763 | |||
| d6a456237d | |||
| 8109f5b67a | |||
| dbb5cc35b9 | |||
| 63c197a192 | |||
| 40c1eee566 | |||
| 45b03799ad | |||
| 72e08c098e | |||
| 1189227da8 | |||
| 1c57e9361e | |||
| 4c1bb6bbc5 | |||
| 5148c89f99 | |||
| 570c0ee0b9 | |||
| 57916ffb5d | |||
| 5029226bb6 | |||
| 244d577e28 | |||
| 928353f4e1 | |||
| ab1908cbe2 | |||
| bb2135c6a5 | |||
| eea8956c96 | |||
| 88d945a0b0 | |||
| f3cda1dea7 | |||
| d624594445 | |||
| 78df03e4c8 | |||
| 8387e3688a | |||
| 79438f37a6 | |||
| fcddcfa746 | |||
| 79f6bca3bc | |||
| 14c274e717 | |||
| 6618825699 | |||
| 191243c650 | |||
| ef50d287de | |||
| c380833817 | |||
| 076b084d68 | |||
| 04484bed9f | |||
| 878389a536 | |||
| 0e8311ef18 | |||
| 274e0f1aee | |||
| 9b6ae97d23 | |||
| 8c22dc7584 | |||
| b730b2ceb2 | |||
| 5567384fec | |||
| eff2ccdfd2 | |||
| b96f53c165 | |||
| acfcb05fbd | |||
| fc12e3da6a | |||
| fc3b55ef2c | |||
| 56690612a9 | |||
| d3ba1e8d5c | |||
| 172b09ddc3 | |||
| 398902dbc8 | |||
| b2f4e10676 | |||
| 350a30ce84 | |||
| 1bcee23370 | |||
| 7d7e93588f | |||
| 52507cfaff | |||
| 8012f98f92 | |||
| ba386ec3d7 | |||
| 3143cd5f00 | |||
| ddac4e3401 | |||
| 5aa7ad7e99 | |||
| 92edb64da9 | |||
| 9756233a20 | |||
| 0d0dc91e84 | |||
| 82ca3ab31b | |||
| 95443fc0d7 | |||
| cd923d2b57 | |||
| 92f8c688b2 | |||
| 72e521b167 | |||
| e74c494a20 | |||
| 778226c41e | |||
| 9352a3a1ee | |||
| 81a204f1b4 | |||
| 0fbd1f06b6 | |||
| 90964a3fb5 | |||
| 987e90450a | |||
| 2867004c1d | |||
| 274ad46fb7 | |||
| 5f74e73ec3 | |||
| 4614bc9655 | |||
| abf404dfa5 | |||
| 7b77206ad5 | |||
| 75cad94d03 | |||
| c5bc6816fc | |||
| 8ac794da75 | |||
| 191355a2cf | |||
| 68c5b8cb26 | |||
| 457c529fc1 | |||
| 2a807b1b4e | |||
| 0126be1409 | |||
| 3064134f88 | |||
| 6b47a3043a |
@@ -265,8 +265,11 @@ time with the option "mds=". The valid arguments for this option are:
|
||||
|
||||
============ =============================================================
|
||||
|
||||
Not specifying this option is equivalent to "mds=full".
|
||||
|
||||
Not specifying this option is equivalent to "mds=full". For processors
|
||||
that are affected by both TAA (TSX Asynchronous Abort) and MDS,
|
||||
specifying just "mds=off" without an accompanying "tsx_async_abort=off"
|
||||
will have no effect as the same mitigation is used for both
|
||||
vulnerabilities.
|
||||
|
||||
Mitigation selection guide
|
||||
--------------------------
|
||||
|
||||
@@ -174,7 +174,10 @@ the option "tsx_async_abort=". The valid arguments for this option are:
|
||||
CPU is not vulnerable to cross-thread TAA attacks.
|
||||
============ =============================================================
|
||||
|
||||
Not specifying this option is equivalent to "tsx_async_abort=full".
|
||||
Not specifying this option is equivalent to "tsx_async_abort=full". For
|
||||
processors that are affected by both TAA and MDS, specifying just
|
||||
"tsx_async_abort=off" without an accompanying "mds=off" will have no
|
||||
effect as the same mitigation is used for both vulnerabilities.
|
||||
|
||||
The kernel command line also allows to control the TSX feature using the
|
||||
parameter "tsx=" on CPUs which support TSX control. MSR_IA32_TSX_CTRL is used
|
||||
|
||||
@@ -2473,6 +2473,12 @@
|
||||
SMT on vulnerable CPUs
|
||||
off - Unconditionally disable MDS mitigation
|
||||
|
||||
On TAA-affected machines, mds=off can be prevented by
|
||||
an active TAA mitigation as both vulnerabilities are
|
||||
mitigated with the same mechanism so in order to disable
|
||||
this mitigation, you need to specify tsx_async_abort=off
|
||||
too.
|
||||
|
||||
Not specifying this option is equivalent to
|
||||
mds=full.
|
||||
|
||||
@@ -4931,6 +4937,11 @@
|
||||
vulnerable to cross-thread TAA attacks.
|
||||
off - Unconditionally disable TAA mitigation
|
||||
|
||||
On MDS-affected machines, tsx_async_abort=off can be
|
||||
prevented by an active MDS mitigation as both vulnerabilities
|
||||
are mitigated with the same mechanism so in order to disable
|
||||
this mitigation, you need to specify mds=off too.
|
||||
|
||||
Not specifying this option is equivalent to
|
||||
tsx_async_abort=full. On CPUs which are MDS affected
|
||||
and deploy MDS mitigation, TAA mitigation is not
|
||||
|
||||
@@ -81,6 +81,12 @@ Optional properties:
|
||||
Definition: Name of external front end module used. Some valid FEM names
|
||||
for example: "microsemi-lx5586", "sky85703-11"
|
||||
and "sky85803" etc.
|
||||
- qcom,snoc-host-cap-8bit-quirk:
|
||||
Usage: Optional
|
||||
Value type: <empty>
|
||||
Definition: Quirk specifying that the firmware expects the 8bit version
|
||||
of the host capability QMI request
|
||||
|
||||
|
||||
Example (to supply PCI based wifi block details):
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 5
|
||||
PATCHLEVEL = 4
|
||||
SUBLEVEL = 0
|
||||
SUBLEVEL = 2
|
||||
EXTRAVERSION =
|
||||
NAME = Kleptomaniac Octopus
|
||||
|
||||
|
||||
@@ -152,9 +152,12 @@ void _kvmppc_save_tm_pr(struct kvm_vcpu *vcpu, u64 guest_msr);
|
||||
/* Patch sites */
|
||||
extern s32 patch__call_flush_count_cache;
|
||||
extern s32 patch__flush_count_cache_return;
|
||||
extern s32 patch__flush_link_stack_return;
|
||||
extern s32 patch__call_kvm_flush_link_stack;
|
||||
extern s32 patch__memset_nocache, patch__memcpy_nocache;
|
||||
|
||||
extern long flush_count_cache;
|
||||
extern long kvm_flush_link_stack;
|
||||
|
||||
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
|
||||
void kvmppc_save_tm_hv(struct kvm_vcpu *vcpu, u64 msr, bool preserve_nv);
|
||||
|
||||
@@ -81,6 +81,9 @@ static inline bool security_ftr_enabled(unsigned long feature)
|
||||
// Software required to flush count cache on context switch
|
||||
#define SEC_FTR_FLUSH_COUNT_CACHE 0x0000000000000400ull
|
||||
|
||||
// Software required to flush link stack on context switch
|
||||
#define SEC_FTR_FLUSH_LINK_STACK 0x0000000000001000ull
|
||||
|
||||
|
||||
// Features enabled by default
|
||||
#define SEC_FTR_DEFAULT \
|
||||
|
||||
@@ -537,6 +537,7 @@ flush_count_cache:
|
||||
/* Save LR into r9 */
|
||||
mflr r9
|
||||
|
||||
// Flush the link stack
|
||||
.rept 64
|
||||
bl .+4
|
||||
.endr
|
||||
@@ -546,6 +547,11 @@ flush_count_cache:
|
||||
.balign 32
|
||||
/* Restore LR */
|
||||
1: mtlr r9
|
||||
|
||||
// If we're just flushing the link stack, return here
|
||||
3: nop
|
||||
patch_site 3b patch__flush_link_stack_return
|
||||
|
||||
li r9,0x7fff
|
||||
mtctr r9
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ enum count_cache_flush_type {
|
||||
COUNT_CACHE_FLUSH_HW = 0x4,
|
||||
};
|
||||
static enum count_cache_flush_type count_cache_flush_type = COUNT_CACHE_FLUSH_NONE;
|
||||
static bool link_stack_flush_enabled;
|
||||
|
||||
bool barrier_nospec_enabled;
|
||||
static bool no_nospec;
|
||||
@@ -212,11 +213,19 @@ ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, c
|
||||
|
||||
if (ccd)
|
||||
seq_buf_printf(&s, "Indirect branch cache disabled");
|
||||
|
||||
if (link_stack_flush_enabled)
|
||||
seq_buf_printf(&s, ", Software link stack flush");
|
||||
|
||||
} else if (count_cache_flush_type != COUNT_CACHE_FLUSH_NONE) {
|
||||
seq_buf_printf(&s, "Mitigation: Software count cache flush");
|
||||
|
||||
if (count_cache_flush_type == COUNT_CACHE_FLUSH_HW)
|
||||
seq_buf_printf(&s, " (hardware accelerated)");
|
||||
|
||||
if (link_stack_flush_enabled)
|
||||
seq_buf_printf(&s, ", Software link stack flush");
|
||||
|
||||
} else if (btb_flush_enabled) {
|
||||
seq_buf_printf(&s, "Mitigation: Branch predictor state flush");
|
||||
} else {
|
||||
@@ -377,18 +386,49 @@ static __init int stf_barrier_debugfs_init(void)
|
||||
device_initcall(stf_barrier_debugfs_init);
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
static void no_count_cache_flush(void)
|
||||
{
|
||||
count_cache_flush_type = COUNT_CACHE_FLUSH_NONE;
|
||||
pr_info("count-cache-flush: software flush disabled.\n");
|
||||
}
|
||||
|
||||
static void toggle_count_cache_flush(bool enable)
|
||||
{
|
||||
if (!enable || !security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) {
|
||||
if (!security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE) &&
|
||||
!security_ftr_enabled(SEC_FTR_FLUSH_LINK_STACK))
|
||||
enable = false;
|
||||
|
||||
if (!enable) {
|
||||
patch_instruction_site(&patch__call_flush_count_cache, PPC_INST_NOP);
|
||||
count_cache_flush_type = COUNT_CACHE_FLUSH_NONE;
|
||||
pr_info("count-cache-flush: software flush disabled.\n");
|
||||
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
|
||||
patch_instruction_site(&patch__call_kvm_flush_link_stack, PPC_INST_NOP);
|
||||
#endif
|
||||
pr_info("link-stack-flush: software flush disabled.\n");
|
||||
link_stack_flush_enabled = false;
|
||||
no_count_cache_flush();
|
||||
return;
|
||||
}
|
||||
|
||||
// This enables the branch from _switch to flush_count_cache
|
||||
patch_branch_site(&patch__call_flush_count_cache,
|
||||
(u64)&flush_count_cache, BRANCH_SET_LINK);
|
||||
|
||||
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
|
||||
// This enables the branch from guest_exit_cont to kvm_flush_link_stack
|
||||
patch_branch_site(&patch__call_kvm_flush_link_stack,
|
||||
(u64)&kvm_flush_link_stack, BRANCH_SET_LINK);
|
||||
#endif
|
||||
|
||||
pr_info("link-stack-flush: software flush enabled.\n");
|
||||
link_stack_flush_enabled = true;
|
||||
|
||||
// If we just need to flush the link stack, patch an early return
|
||||
if (!security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) {
|
||||
patch_instruction_site(&patch__flush_link_stack_return, PPC_INST_BLR);
|
||||
no_count_cache_flush();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!security_ftr_enabled(SEC_FTR_BCCTR_FLUSH_ASSIST)) {
|
||||
count_cache_flush_type = COUNT_CACHE_FLUSH_SW;
|
||||
pr_info("count-cache-flush: full software flush sequence enabled.\n");
|
||||
@@ -407,11 +447,20 @@ void setup_count_cache_flush(void)
|
||||
if (no_spectrev2 || cpu_mitigations_off()) {
|
||||
if (security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED) ||
|
||||
security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED))
|
||||
pr_warn("Spectre v2 mitigations not under software control, can't disable\n");
|
||||
pr_warn("Spectre v2 mitigations not fully under software control, can't disable\n");
|
||||
|
||||
enable = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* There's no firmware feature flag/hypervisor bit to tell us we need to
|
||||
* flush the link stack on context switch. So we set it here if we see
|
||||
* either of the Spectre v2 mitigations that aim to protect userspace.
|
||||
*/
|
||||
if (security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED) ||
|
||||
security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE))
|
||||
security_ftr_set(SEC_FTR_FLUSH_LINK_STACK);
|
||||
|
||||
toggle_count_cache_flush(enable);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
#include <asm/ppc_asm.h>
|
||||
#include <asm/code-patching-asm.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
#include <asm/reg.h>
|
||||
#include <asm/mmu.h>
|
||||
@@ -1487,6 +1488,13 @@ guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */
|
||||
1:
|
||||
#endif /* CONFIG_KVM_XICS */
|
||||
|
||||
/*
|
||||
* Possibly flush the link stack here, before we do a blr in
|
||||
* guest_exit_short_path.
|
||||
*/
|
||||
1: nop
|
||||
patch_site 1b patch__call_kvm_flush_link_stack
|
||||
|
||||
/* If we came in through the P9 short path, go back out to C now */
|
||||
lwz r0, STACK_SLOT_SHORT_PATH(r1)
|
||||
cmpwi r0, 0
|
||||
@@ -1963,6 +1971,28 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
|
||||
mtlr r0
|
||||
blr
|
||||
|
||||
.balign 32
|
||||
.global kvm_flush_link_stack
|
||||
kvm_flush_link_stack:
|
||||
/* Save LR into r0 */
|
||||
mflr r0
|
||||
|
||||
/* Flush the link stack. On Power8 it's up to 32 entries in size. */
|
||||
.rept 32
|
||||
bl .+4
|
||||
.endr
|
||||
|
||||
/* And on Power9 it's up to 64. */
|
||||
BEGIN_FTR_SECTION
|
||||
.rept 32
|
||||
bl .+4
|
||||
.endr
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
|
||||
|
||||
/* Restore LR */
|
||||
mtlr r0
|
||||
blr
|
||||
|
||||
kvmppc_guest_external:
|
||||
/* External interrupt, first check for host_ipi. If this is
|
||||
* set, we know the host wants us out so let's do it now
|
||||
|
||||
+133
-78
@@ -172,7 +172,7 @@
|
||||
ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI
|
||||
.if \no_user_check == 0
|
||||
/* coming from usermode? */
|
||||
testl $SEGMENT_RPL_MASK, PT_CS(%esp)
|
||||
testl $USER_SEGMENT_RPL_MASK, PT_CS(%esp)
|
||||
jz .Lend_\@
|
||||
.endif
|
||||
/* On user-cr3? */
|
||||
@@ -205,64 +205,76 @@
|
||||
#define CS_FROM_ENTRY_STACK (1 << 31)
|
||||
#define CS_FROM_USER_CR3 (1 << 30)
|
||||
#define CS_FROM_KERNEL (1 << 29)
|
||||
#define CS_FROM_ESPFIX (1 << 28)
|
||||
|
||||
.macro FIXUP_FRAME
|
||||
/*
|
||||
* The high bits of the CS dword (__csh) are used for CS_FROM_*.
|
||||
* Clear them in case hardware didn't do this for us.
|
||||
*/
|
||||
andl $0x0000ffff, 3*4(%esp)
|
||||
andl $0x0000ffff, 4*4(%esp)
|
||||
|
||||
#ifdef CONFIG_VM86
|
||||
testl $X86_EFLAGS_VM, 4*4(%esp)
|
||||
testl $X86_EFLAGS_VM, 5*4(%esp)
|
||||
jnz .Lfrom_usermode_no_fixup_\@
|
||||
#endif
|
||||
testl $SEGMENT_RPL_MASK, 3*4(%esp)
|
||||
testl $USER_SEGMENT_RPL_MASK, 4*4(%esp)
|
||||
jnz .Lfrom_usermode_no_fixup_\@
|
||||
|
||||
orl $CS_FROM_KERNEL, 3*4(%esp)
|
||||
orl $CS_FROM_KERNEL, 4*4(%esp)
|
||||
|
||||
/*
|
||||
* When we're here from kernel mode; the (exception) stack looks like:
|
||||
*
|
||||
* 5*4(%esp) - <previous context>
|
||||
* 4*4(%esp) - flags
|
||||
* 3*4(%esp) - cs
|
||||
* 2*4(%esp) - ip
|
||||
* 1*4(%esp) - orig_eax
|
||||
* 0*4(%esp) - gs / function
|
||||
* 6*4(%esp) - <previous context>
|
||||
* 5*4(%esp) - flags
|
||||
* 4*4(%esp) - cs
|
||||
* 3*4(%esp) - ip
|
||||
* 2*4(%esp) - orig_eax
|
||||
* 1*4(%esp) - gs / function
|
||||
* 0*4(%esp) - fs
|
||||
*
|
||||
* Lets build a 5 entry IRET frame after that, such that struct pt_regs
|
||||
* is complete and in particular regs->sp is correct. This gives us
|
||||
* the original 5 enties as gap:
|
||||
* the original 6 enties as gap:
|
||||
*
|
||||
* 12*4(%esp) - <previous context>
|
||||
* 11*4(%esp) - gap / flags
|
||||
* 10*4(%esp) - gap / cs
|
||||
* 9*4(%esp) - gap / ip
|
||||
* 8*4(%esp) - gap / orig_eax
|
||||
* 7*4(%esp) - gap / gs / function
|
||||
* 6*4(%esp) - ss
|
||||
* 5*4(%esp) - sp
|
||||
* 4*4(%esp) - flags
|
||||
* 3*4(%esp) - cs
|
||||
* 2*4(%esp) - ip
|
||||
* 1*4(%esp) - orig_eax
|
||||
* 0*4(%esp) - gs / function
|
||||
* 14*4(%esp) - <previous context>
|
||||
* 13*4(%esp) - gap / flags
|
||||
* 12*4(%esp) - gap / cs
|
||||
* 11*4(%esp) - gap / ip
|
||||
* 10*4(%esp) - gap / orig_eax
|
||||
* 9*4(%esp) - gap / gs / function
|
||||
* 8*4(%esp) - gap / fs
|
||||
* 7*4(%esp) - ss
|
||||
* 6*4(%esp) - sp
|
||||
* 5*4(%esp) - flags
|
||||
* 4*4(%esp) - cs
|
||||
* 3*4(%esp) - ip
|
||||
* 2*4(%esp) - orig_eax
|
||||
* 1*4(%esp) - gs / function
|
||||
* 0*4(%esp) - fs
|
||||
*/
|
||||
|
||||
pushl %ss # ss
|
||||
pushl %esp # sp (points at ss)
|
||||
addl $6*4, (%esp) # point sp back at the previous context
|
||||
pushl 6*4(%esp) # flags
|
||||
pushl 6*4(%esp) # cs
|
||||
pushl 6*4(%esp) # ip
|
||||
pushl 6*4(%esp) # orig_eax
|
||||
pushl 6*4(%esp) # gs / function
|
||||
addl $7*4, (%esp) # point sp back at the previous context
|
||||
pushl 7*4(%esp) # flags
|
||||
pushl 7*4(%esp) # cs
|
||||
pushl 7*4(%esp) # ip
|
||||
pushl 7*4(%esp) # orig_eax
|
||||
pushl 7*4(%esp) # gs / function
|
||||
pushl 7*4(%esp) # fs
|
||||
.Lfrom_usermode_no_fixup_\@:
|
||||
.endm
|
||||
|
||||
.macro IRET_FRAME
|
||||
/*
|
||||
* We're called with %ds, %es, %fs, and %gs from the interrupted
|
||||
* frame, so we shouldn't use them. Also, we may be in ESPFIX
|
||||
* mode and therefore have a nonzero SS base and an offset ESP,
|
||||
* so any attempt to access the stack needs to use SS. (except for
|
||||
* accesses through %esp, which automatically use SS.)
|
||||
*/
|
||||
testl $CS_FROM_KERNEL, 1*4(%esp)
|
||||
jz .Lfinished_frame_\@
|
||||
|
||||
@@ -276,31 +288,40 @@
|
||||
movl 5*4(%esp), %eax # (modified) regs->sp
|
||||
|
||||
movl 4*4(%esp), %ecx # flags
|
||||
movl %ecx, -4(%eax)
|
||||
movl %ecx, %ss:-1*4(%eax)
|
||||
|
||||
movl 3*4(%esp), %ecx # cs
|
||||
andl $0x0000ffff, %ecx
|
||||
movl %ecx, -8(%eax)
|
||||
movl %ecx, %ss:-2*4(%eax)
|
||||
|
||||
movl 2*4(%esp), %ecx # ip
|
||||
movl %ecx, -12(%eax)
|
||||
movl %ecx, %ss:-3*4(%eax)
|
||||
|
||||
movl 1*4(%esp), %ecx # eax
|
||||
movl %ecx, -16(%eax)
|
||||
movl %ecx, %ss:-4*4(%eax)
|
||||
|
||||
popl %ecx
|
||||
lea -16(%eax), %esp
|
||||
lea -4*4(%eax), %esp
|
||||
popl %eax
|
||||
.Lfinished_frame_\@:
|
||||
.endm
|
||||
|
||||
.macro SAVE_ALL pt_regs_ax=%eax switch_stacks=0 skip_gs=0
|
||||
.macro SAVE_ALL pt_regs_ax=%eax switch_stacks=0 skip_gs=0 unwind_espfix=0
|
||||
cld
|
||||
.if \skip_gs == 0
|
||||
PUSH_GS
|
||||
.endif
|
||||
FIXUP_FRAME
|
||||
pushl %fs
|
||||
|
||||
pushl %eax
|
||||
movl $(__KERNEL_PERCPU), %eax
|
||||
movl %eax, %fs
|
||||
.if \unwind_espfix > 0
|
||||
UNWIND_ESPFIX_STACK
|
||||
.endif
|
||||
popl %eax
|
||||
|
||||
FIXUP_FRAME
|
||||
pushl %es
|
||||
pushl %ds
|
||||
pushl \pt_regs_ax
|
||||
@@ -313,8 +334,6 @@
|
||||
movl $(__USER_DS), %edx
|
||||
movl %edx, %ds
|
||||
movl %edx, %es
|
||||
movl $(__KERNEL_PERCPU), %edx
|
||||
movl %edx, %fs
|
||||
.if \skip_gs == 0
|
||||
SET_KERNEL_GS %edx
|
||||
.endif
|
||||
@@ -324,8 +343,8 @@
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro SAVE_ALL_NMI cr3_reg:req
|
||||
SAVE_ALL
|
||||
.macro SAVE_ALL_NMI cr3_reg:req unwind_espfix=0
|
||||
SAVE_ALL unwind_espfix=\unwind_espfix
|
||||
|
||||
BUG_IF_WRONG_CR3
|
||||
|
||||
@@ -357,6 +376,7 @@
|
||||
2: popl %es
|
||||
3: popl %fs
|
||||
POP_GS \pop
|
||||
IRET_FRAME
|
||||
.pushsection .fixup, "ax"
|
||||
4: movl $0, (%esp)
|
||||
jmp 1b
|
||||
@@ -395,7 +415,8 @@
|
||||
|
||||
.macro CHECK_AND_APPLY_ESPFIX
|
||||
#ifdef CONFIG_X86_ESPFIX32
|
||||
#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + (GDT_ENTRY_ESPFIX_SS * 8)
|
||||
#define GDT_ESPFIX_OFFSET (GDT_ENTRY_ESPFIX_SS * 8)
|
||||
#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + GDT_ESPFIX_OFFSET
|
||||
|
||||
ALTERNATIVE "jmp .Lend_\@", "", X86_BUG_ESPFIX
|
||||
|
||||
@@ -1075,7 +1096,6 @@ restore_all:
|
||||
/* Restore user state */
|
||||
RESTORE_REGS pop=4 # skip orig_eax/error_code
|
||||
.Lirq_return:
|
||||
IRET_FRAME
|
||||
/*
|
||||
* ARCH_HAS_MEMBARRIER_SYNC_CORE rely on IRET core serialization
|
||||
* when returning from IPI handler and when returning from
|
||||
@@ -1128,30 +1148,43 @@ ENDPROC(entry_INT80_32)
|
||||
* We can't call C functions using the ESPFIX stack. This code reads
|
||||
* the high word of the segment base from the GDT and swiches to the
|
||||
* normal stack and adjusts ESP with the matching offset.
|
||||
*
|
||||
* We might be on user CR3 here, so percpu data is not mapped and we can't
|
||||
* access the GDT through the percpu segment. Instead, use SGDT to find
|
||||
* the cpu_entry_area alias of the GDT.
|
||||
*/
|
||||
#ifdef CONFIG_X86_ESPFIX32
|
||||
/* fixup the stack */
|
||||
mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */
|
||||
mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
|
||||
pushl %ecx
|
||||
subl $2*4, %esp
|
||||
sgdt (%esp)
|
||||
movl 2(%esp), %ecx /* GDT address */
|
||||
/*
|
||||
* Careful: ECX is a linear pointer, so we need to force base
|
||||
* zero. %cs is the only known-linear segment we have right now.
|
||||
*/
|
||||
mov %cs:GDT_ESPFIX_OFFSET + 4(%ecx), %al /* bits 16..23 */
|
||||
mov %cs:GDT_ESPFIX_OFFSET + 7(%ecx), %ah /* bits 24..31 */
|
||||
shl $16, %eax
|
||||
addl $2*4, %esp
|
||||
popl %ecx
|
||||
addl %esp, %eax /* the adjusted stack pointer */
|
||||
pushl $__KERNEL_DS
|
||||
pushl %eax
|
||||
lss (%esp), %esp /* switch to the normal stack segment */
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro UNWIND_ESPFIX_STACK
|
||||
/* It's safe to clobber %eax, all other regs need to be preserved */
|
||||
#ifdef CONFIG_X86_ESPFIX32
|
||||
movl %ss, %eax
|
||||
/* see if on espfix stack */
|
||||
cmpw $__ESPFIX_SS, %ax
|
||||
jne 27f
|
||||
movl $__KERNEL_DS, %eax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
jne .Lno_fixup_\@
|
||||
/* switch to normal stack */
|
||||
FIXUP_ESPFIX_STACK
|
||||
27:
|
||||
.Lno_fixup_\@:
|
||||
#endif
|
||||
.endm
|
||||
|
||||
@@ -1341,11 +1374,6 @@ END(spurious_interrupt_bug)
|
||||
|
||||
#ifdef CONFIG_XEN_PV
|
||||
ENTRY(xen_hypervisor_callback)
|
||||
pushl $-1 /* orig_ax = -1 => not a system call */
|
||||
SAVE_ALL
|
||||
ENCODE_FRAME_POINTER
|
||||
TRACE_IRQS_OFF
|
||||
|
||||
/*
|
||||
* Check to see if we got the event in the critical
|
||||
* region in xen_iret_direct, after we've reenabled
|
||||
@@ -1353,16 +1381,17 @@ ENTRY(xen_hypervisor_callback)
|
||||
* iret instruction's behaviour where it delivers a
|
||||
* pending interrupt when enabling interrupts:
|
||||
*/
|
||||
movl PT_EIP(%esp), %eax
|
||||
cmpl $xen_iret_start_crit, %eax
|
||||
cmpl $xen_iret_start_crit, (%esp)
|
||||
jb 1f
|
||||
cmpl $xen_iret_end_crit, %eax
|
||||
cmpl $xen_iret_end_crit, (%esp)
|
||||
jae 1f
|
||||
|
||||
jmp xen_iret_crit_fixup
|
||||
|
||||
ENTRY(xen_do_upcall)
|
||||
1: mov %esp, %eax
|
||||
call xen_iret_crit_fixup
|
||||
1:
|
||||
pushl $-1 /* orig_ax = -1 => not a system call */
|
||||
SAVE_ALL
|
||||
ENCODE_FRAME_POINTER
|
||||
TRACE_IRQS_OFF
|
||||
mov %esp, %eax
|
||||
call xen_evtchn_do_upcall
|
||||
#ifndef CONFIG_PREEMPTION
|
||||
call xen_maybe_preempt_hcall
|
||||
@@ -1449,10 +1478,9 @@ END(page_fault)
|
||||
|
||||
common_exception_read_cr2:
|
||||
/* the function address is in %gs's slot on the stack */
|
||||
SAVE_ALL switch_stacks=1 skip_gs=1
|
||||
SAVE_ALL switch_stacks=1 skip_gs=1 unwind_espfix=1
|
||||
|
||||
ENCODE_FRAME_POINTER
|
||||
UNWIND_ESPFIX_STACK
|
||||
|
||||
/* fixup %gs */
|
||||
GS_TO_REG %ecx
|
||||
@@ -1474,9 +1502,8 @@ END(common_exception_read_cr2)
|
||||
|
||||
common_exception:
|
||||
/* the function address is in %gs's slot on the stack */
|
||||
SAVE_ALL switch_stacks=1 skip_gs=1
|
||||
SAVE_ALL switch_stacks=1 skip_gs=1 unwind_espfix=1
|
||||
ENCODE_FRAME_POINTER
|
||||
UNWIND_ESPFIX_STACK
|
||||
|
||||
/* fixup %gs */
|
||||
GS_TO_REG %ecx
|
||||
@@ -1515,6 +1542,10 @@ ENTRY(nmi)
|
||||
ASM_CLAC
|
||||
|
||||
#ifdef CONFIG_X86_ESPFIX32
|
||||
/*
|
||||
* ESPFIX_SS is only ever set on the return to user path
|
||||
* after we've switched to the entry stack.
|
||||
*/
|
||||
pushl %eax
|
||||
movl %ss, %eax
|
||||
cmpw $__ESPFIX_SS, %ax
|
||||
@@ -1550,6 +1581,11 @@ ENTRY(nmi)
|
||||
movl %ebx, %esp
|
||||
|
||||
.Lnmi_return:
|
||||
#ifdef CONFIG_X86_ESPFIX32
|
||||
testl $CS_FROM_ESPFIX, PT_CS(%esp)
|
||||
jnz .Lnmi_from_espfix
|
||||
#endif
|
||||
|
||||
CHECK_AND_APPLY_ESPFIX
|
||||
RESTORE_ALL_NMI cr3_reg=%edi pop=4
|
||||
jmp .Lirq_return
|
||||
@@ -1557,23 +1593,42 @@ ENTRY(nmi)
|
||||
#ifdef CONFIG_X86_ESPFIX32
|
||||
.Lnmi_espfix_stack:
|
||||
/*
|
||||
* create the pointer to lss back
|
||||
* Create the pointer to LSS back
|
||||
*/
|
||||
pushl %ss
|
||||
pushl %esp
|
||||
addl $4, (%esp)
|
||||
/* copy the iret frame of 12 bytes */
|
||||
.rept 3
|
||||
pushl 16(%esp)
|
||||
.endr
|
||||
pushl %eax
|
||||
SAVE_ALL_NMI cr3_reg=%edi
|
||||
|
||||
/* Copy the (short) IRET frame */
|
||||
pushl 4*4(%esp) # flags
|
||||
pushl 4*4(%esp) # cs
|
||||
pushl 4*4(%esp) # ip
|
||||
|
||||
pushl %eax # orig_ax
|
||||
|
||||
SAVE_ALL_NMI cr3_reg=%edi unwind_espfix=1
|
||||
ENCODE_FRAME_POINTER
|
||||
FIXUP_ESPFIX_STACK # %eax == %esp
|
||||
|
||||
/* clear CS_FROM_KERNEL, set CS_FROM_ESPFIX */
|
||||
xorl $(CS_FROM_ESPFIX | CS_FROM_KERNEL), PT_CS(%esp)
|
||||
|
||||
xorl %edx, %edx # zero error code
|
||||
call do_nmi
|
||||
movl %esp, %eax # pt_regs pointer
|
||||
jmp .Lnmi_from_sysenter_stack
|
||||
|
||||
.Lnmi_from_espfix:
|
||||
RESTORE_ALL_NMI cr3_reg=%edi
|
||||
lss 12+4(%esp), %esp # back to espfix stack
|
||||
/*
|
||||
* Because we cleared CS_FROM_KERNEL, IRET_FRAME 'forgot' to
|
||||
* fix up the gap and long frame:
|
||||
*
|
||||
* 3 - original frame (exception)
|
||||
* 2 - ESPFIX block (above)
|
||||
* 6 - gap (FIXUP_FRAME)
|
||||
* 5 - long frame (FIXUP_FRAME)
|
||||
* 1 - orig_ax
|
||||
*/
|
||||
lss (1+5+6)*4(%esp), %esp # back to espfix stack
|
||||
jmp .Lirq_return
|
||||
#endif
|
||||
END(nmi)
|
||||
|
||||
@@ -78,8 +78,12 @@ struct cpu_entry_area {
|
||||
|
||||
/*
|
||||
* The GDT is just below entry_stack and thus serves (on x86_64) as
|
||||
* a a read-only guard page.
|
||||
* a read-only guard page. On 32-bit the GDT must be writeable, so
|
||||
* it needs an extra guard page.
|
||||
*/
|
||||
#ifdef CONFIG_X86_32
|
||||
char guard_entry_stack[PAGE_SIZE];
|
||||
#endif
|
||||
struct entry_stack_page entry_stack_page;
|
||||
|
||||
/*
|
||||
@@ -94,7 +98,6 @@ struct cpu_entry_area {
|
||||
*/
|
||||
struct cea_exception_stacks estacks;
|
||||
#endif
|
||||
#ifdef CONFIG_CPU_SUP_INTEL
|
||||
/*
|
||||
* Per CPU debug store for Intel performance monitoring. Wastes a
|
||||
* full page at the moment.
|
||||
@@ -105,11 +108,13 @@ struct cpu_entry_area {
|
||||
* Reserve enough fixmap PTEs.
|
||||
*/
|
||||
struct debug_store_buffers cpu_debug_buffers;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define CPU_ENTRY_AREA_SIZE (sizeof(struct cpu_entry_area))
|
||||
#define CPU_ENTRY_AREA_TOT_SIZE (CPU_ENTRY_AREA_SIZE * NR_CPUS)
|
||||
#define CPU_ENTRY_AREA_SIZE (sizeof(struct cpu_entry_area))
|
||||
#define CPU_ENTRY_AREA_ARRAY_SIZE (CPU_ENTRY_AREA_SIZE * NR_CPUS)
|
||||
|
||||
/* Total size includes the readonly IDT mapping page as well: */
|
||||
#define CPU_ENTRY_AREA_TOTAL_SIZE (CPU_ENTRY_AREA_ARRAY_SIZE + PAGE_SIZE)
|
||||
|
||||
DECLARE_PER_CPU(struct cpu_entry_area *, cpu_entry_area);
|
||||
DECLARE_PER_CPU(struct cea_exception_stacks *, cea_exception_stacks);
|
||||
@@ -117,13 +122,14 @@ DECLARE_PER_CPU(struct cea_exception_stacks *, cea_exception_stacks);
|
||||
extern void setup_cpu_entry_areas(void);
|
||||
extern void cea_set_pte(void *cea_vaddr, phys_addr_t pa, pgprot_t flags);
|
||||
|
||||
/* Single page reserved for the readonly IDT mapping: */
|
||||
#define CPU_ENTRY_AREA_RO_IDT CPU_ENTRY_AREA_BASE
|
||||
#define CPU_ENTRY_AREA_PER_CPU (CPU_ENTRY_AREA_RO_IDT + PAGE_SIZE)
|
||||
|
||||
#define CPU_ENTRY_AREA_RO_IDT_VADDR ((void *)CPU_ENTRY_AREA_RO_IDT)
|
||||
|
||||
#define CPU_ENTRY_AREA_MAP_SIZE \
|
||||
(CPU_ENTRY_AREA_PER_CPU + CPU_ENTRY_AREA_TOT_SIZE - CPU_ENTRY_AREA_BASE)
|
||||
(CPU_ENTRY_AREA_PER_CPU + CPU_ENTRY_AREA_ARRAY_SIZE - CPU_ENTRY_AREA_BASE)
|
||||
|
||||
extern struct cpu_entry_area *get_cpu_entry_area(int cpu);
|
||||
|
||||
|
||||
@@ -509,7 +509,7 @@ static inline void __fpu_invalidate_fpregs_state(struct fpu *fpu)
|
||||
|
||||
static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu)
|
||||
{
|
||||
return fpu == this_cpu_read_stable(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu;
|
||||
return fpu == this_cpu_read(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -44,11 +44,11 @@ extern bool __vmalloc_start_set; /* set once high_memory is set */
|
||||
* Define this here and validate with BUILD_BUG_ON() in pgtable_32.c
|
||||
* to avoid include recursion hell
|
||||
*/
|
||||
#define CPU_ENTRY_AREA_PAGES (NR_CPUS * 40)
|
||||
#define CPU_ENTRY_AREA_PAGES (NR_CPUS * 39)
|
||||
|
||||
#define CPU_ENTRY_AREA_BASE \
|
||||
((FIXADDR_TOT_START - PAGE_SIZE * (CPU_ENTRY_AREA_PAGES + 1)) \
|
||||
& PMD_MASK)
|
||||
/* The +1 is for the readonly IDT page: */
|
||||
#define CPU_ENTRY_AREA_BASE \
|
||||
((FIXADDR_TOT_START - PAGE_SIZE*(CPU_ENTRY_AREA_PAGES+1)) & PMD_MASK)
|
||||
|
||||
#define LDT_BASE_ADDR \
|
||||
((CPU_ENTRY_AREA_BASE - PAGE_SIZE) & PMD_MASK)
|
||||
|
||||
@@ -31,6 +31,18 @@
|
||||
*/
|
||||
#define SEGMENT_RPL_MASK 0x3
|
||||
|
||||
/*
|
||||
* When running on Xen PV, the actual privilege level of the kernel is 1,
|
||||
* not 0. Testing the Requested Privilege Level in a segment selector to
|
||||
* determine whether the context is user mode or kernel mode with
|
||||
* SEGMENT_RPL_MASK is wrong because the PV kernel's privilege level
|
||||
* matches the 0x3 mask.
|
||||
*
|
||||
* Testing with USER_SEGMENT_RPL_MASK is valid for both native and Xen PV
|
||||
* kernels because privilege level 2 is never used.
|
||||
*/
|
||||
#define USER_SEGMENT_RPL_MASK 0x2
|
||||
|
||||
/* User mode is privilege level 3: */
|
||||
#define USER_RPL 0x3
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ static void __init spectre_v2_select_mitigation(void);
|
||||
static void __init ssb_select_mitigation(void);
|
||||
static void __init l1tf_select_mitigation(void);
|
||||
static void __init mds_select_mitigation(void);
|
||||
static void __init mds_print_mitigation(void);
|
||||
static void __init taa_select_mitigation(void);
|
||||
|
||||
/* The base value of the SPEC_CTRL MSR that always has to be preserved. */
|
||||
@@ -108,6 +109,12 @@ void __init check_bugs(void)
|
||||
mds_select_mitigation();
|
||||
taa_select_mitigation();
|
||||
|
||||
/*
|
||||
* As MDS and TAA mitigations are inter-related, print MDS
|
||||
* mitigation until after TAA mitigation selection is done.
|
||||
*/
|
||||
mds_print_mitigation();
|
||||
|
||||
arch_smt_update();
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
@@ -245,6 +252,12 @@ static void __init mds_select_mitigation(void)
|
||||
(mds_nosmt || cpu_mitigations_auto_nosmt()))
|
||||
cpu_smt_disable(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init mds_print_mitigation(void)
|
||||
{
|
||||
if (!boot_cpu_has_bug(X86_BUG_MDS) || cpu_mitigations_off())
|
||||
return;
|
||||
|
||||
pr_info("%s\n", mds_strings[mds_mitigation]);
|
||||
}
|
||||
@@ -304,8 +317,12 @@ static void __init taa_select_mitigation(void)
|
||||
return;
|
||||
}
|
||||
|
||||
/* TAA mitigation is turned off on the cmdline (tsx_async_abort=off) */
|
||||
if (taa_mitigation == TAA_MITIGATION_OFF)
|
||||
/*
|
||||
* TAA mitigation via VERW is turned off if both
|
||||
* tsx_async_abort=off and mds=off are specified.
|
||||
*/
|
||||
if (taa_mitigation == TAA_MITIGATION_OFF &&
|
||||
mds_mitigation == MDS_MITIGATION_OFF)
|
||||
goto out;
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_MD_CLEAR))
|
||||
@@ -339,6 +356,15 @@ static void __init taa_select_mitigation(void)
|
||||
if (taa_nosmt || cpu_mitigations_auto_nosmt())
|
||||
cpu_smt_disable(false);
|
||||
|
||||
/*
|
||||
* Update MDS mitigation, if necessary, as the mds_user_clear is
|
||||
* now enabled for TAA mitigation.
|
||||
*/
|
||||
if (mds_mitigation == MDS_MITIGATION_OFF &&
|
||||
boot_cpu_has_bug(X86_BUG_MDS)) {
|
||||
mds_mitigation = MDS_MITIGATION_FULL;
|
||||
mds_select_mitigation();
|
||||
}
|
||||
out:
|
||||
pr_info("%s\n", taa_strings[taa_mitigation]);
|
||||
}
|
||||
|
||||
@@ -65,6 +65,9 @@ struct x86_hw_tss doublefault_tss __cacheline_aligned = {
|
||||
.ss = __KERNEL_DS,
|
||||
.ds = __USER_DS,
|
||||
.fs = __KERNEL_PERCPU,
|
||||
#ifndef CONFIG_X86_32_LAZY_GS
|
||||
.gs = __KERNEL_STACK_CANARY,
|
||||
#endif
|
||||
|
||||
.__cr3 = __pa_nodebug(swapper_pg_dir),
|
||||
};
|
||||
|
||||
@@ -571,6 +571,16 @@ ENTRY(initial_page_table)
|
||||
# error "Kernel PMDs should be 1, 2 or 3"
|
||||
# endif
|
||||
.align PAGE_SIZE /* needs to be page-sized too */
|
||||
|
||||
#ifdef CONFIG_PAGE_TABLE_ISOLATION
|
||||
/*
|
||||
* PTI needs another page so sync_initial_pagetable() works correctly
|
||||
* and does not scribble over the data which is placed behind the
|
||||
* actual initial_page_table. See clone_pgd_range().
|
||||
*/
|
||||
.fill 1024, 4, 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
.data
|
||||
|
||||
@@ -178,7 +178,9 @@ static __init void setup_cpu_entry_area_ptes(void)
|
||||
#ifdef CONFIG_X86_32
|
||||
unsigned long start, end;
|
||||
|
||||
BUILD_BUG_ON(CPU_ENTRY_AREA_PAGES * PAGE_SIZE < CPU_ENTRY_AREA_MAP_SIZE);
|
||||
/* The +1 is for the readonly IDT: */
|
||||
BUILD_BUG_ON((CPU_ENTRY_AREA_PAGES+1)*PAGE_SIZE != CPU_ENTRY_AREA_MAP_SIZE);
|
||||
BUILD_BUG_ON(CPU_ENTRY_AREA_TOTAL_SIZE != CPU_ENTRY_AREA_MAP_SIZE);
|
||||
BUG_ON(CPU_ENTRY_AREA_BASE & ~PMD_MASK);
|
||||
|
||||
start = CPU_ENTRY_AREA_BASE;
|
||||
|
||||
@@ -69,7 +69,7 @@ BEGIN {
|
||||
|
||||
lprefix1_expr = "\\((66|!F3)\\)"
|
||||
lprefix2_expr = "\\(F3\\)"
|
||||
lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)"
|
||||
lprefix3_expr = "\\((F2|!F3|66&F2)\\)"
|
||||
lprefix_expr = "\\((66|F2|F3)\\)"
|
||||
max_lprefix = 4
|
||||
|
||||
@@ -257,7 +257,7 @@ function convert_operands(count,opnd, i,j,imm,mod)
|
||||
return add_flags(imm, mod)
|
||||
}
|
||||
|
||||
/^[0-9a-f]+\:/ {
|
||||
/^[0-9a-f]+:/ {
|
||||
if (NR == 1)
|
||||
next
|
||||
# get index
|
||||
|
||||
+25
-50
@@ -126,10 +126,9 @@ hyper_iret:
|
||||
.globl xen_iret_start_crit, xen_iret_end_crit
|
||||
|
||||
/*
|
||||
* This is called by xen_hypervisor_callback in entry.S when it sees
|
||||
* This is called by xen_hypervisor_callback in entry_32.S when it sees
|
||||
* that the EIP at the time of interrupt was between
|
||||
* xen_iret_start_crit and xen_iret_end_crit. We're passed the EIP in
|
||||
* %eax so we can do a more refined determination of what to do.
|
||||
* xen_iret_start_crit and xen_iret_end_crit.
|
||||
*
|
||||
* The stack format at this point is:
|
||||
* ----------------
|
||||
@@ -138,70 +137,46 @@ hyper_iret:
|
||||
* eflags } outer exception info
|
||||
* cs }
|
||||
* eip }
|
||||
* ---------------- <- edi (copy dest)
|
||||
* ----------------
|
||||
* eax : outer eax if it hasn't been restored
|
||||
* ----------------
|
||||
* eflags } nested exception info
|
||||
* cs } (no ss/esp because we're nested
|
||||
* eip } from the same ring)
|
||||
* orig_eax }<- esi (copy src)
|
||||
* - - - - - - - -
|
||||
* fs }
|
||||
* es }
|
||||
* ds } SAVE_ALL state
|
||||
* eax }
|
||||
* : :
|
||||
* ebx }<- esp
|
||||
* ----------------
|
||||
* eflags }
|
||||
* cs } nested exception info
|
||||
* eip }
|
||||
* return address : (into xen_hypervisor_callback)
|
||||
*
|
||||
* In order to deliver the nested exception properly, we need to shift
|
||||
* everything from the return addr up to the error code so it sits
|
||||
* just under the outer exception info. This means that when we
|
||||
* handle the exception, we do it in the context of the outer
|
||||
* exception rather than starting a new one.
|
||||
* In order to deliver the nested exception properly, we need to discard the
|
||||
* nested exception frame such that when we handle the exception, we do it
|
||||
* in the context of the outer exception rather than starting a new one.
|
||||
*
|
||||
* The only caveat is that if the outer eax hasn't been restored yet
|
||||
* (ie, it's still on stack), we need to insert its value into the
|
||||
* SAVE_ALL state before going on, since it's usermode state which we
|
||||
* eventually need to restore.
|
||||
* The only caveat is that if the outer eax hasn't been restored yet (i.e.
|
||||
* it's still on stack), we need to restore its value here.
|
||||
*/
|
||||
ENTRY(xen_iret_crit_fixup)
|
||||
/*
|
||||
* Paranoia: Make sure we're really coming from kernel space.
|
||||
* One could imagine a case where userspace jumps into the
|
||||
* critical range address, but just before the CPU delivers a
|
||||
* GP, it decides to deliver an interrupt instead. Unlikely?
|
||||
* Definitely. Easy to avoid? Yes. The Intel documents
|
||||
* explicitly say that the reported EIP for a bad jump is the
|
||||
* jump instruction itself, not the destination, but some
|
||||
* virtual environments get this wrong.
|
||||
* PF, it decides to deliver an interrupt instead. Unlikely?
|
||||
* Definitely. Easy to avoid? Yes.
|
||||
*/
|
||||
movl PT_CS(%esp), %ecx
|
||||
andl $SEGMENT_RPL_MASK, %ecx
|
||||
cmpl $USER_RPL, %ecx
|
||||
je 2f
|
||||
|
||||
lea PT_ORIG_EAX(%esp), %esi
|
||||
lea PT_EFLAGS(%esp), %edi
|
||||
testb $2, 2*4(%esp) /* nested CS */
|
||||
jnz 2f
|
||||
|
||||
/*
|
||||
* If eip is before iret_restore_end then stack
|
||||
* hasn't been restored yet.
|
||||
*/
|
||||
cmp $iret_restore_end, %eax
|
||||
cmpl $iret_restore_end, 1*4(%esp)
|
||||
jae 1f
|
||||
|
||||
movl 0+4(%edi), %eax /* copy EAX (just above top of frame) */
|
||||
movl %eax, PT_EAX(%esp)
|
||||
movl 4*4(%esp), %eax /* load outer EAX */
|
||||
ret $4*4 /* discard nested EIP, CS, and EFLAGS as
|
||||
* well as the just restored EAX */
|
||||
|
||||
lea ESP_OFFSET(%edi), %edi /* move dest up over saved regs */
|
||||
|
||||
/* set up the copy */
|
||||
1: std
|
||||
mov $PT_EIP / 4, %ecx /* saved regs up to orig_eax */
|
||||
rep movsl
|
||||
cld
|
||||
|
||||
lea 4(%edi), %esp /* point esp to new frame */
|
||||
2: jmp xen_do_upcall
|
||||
1:
|
||||
ret $3*4 /* discard nested EIP, CS, and EFLAGS */
|
||||
|
||||
2:
|
||||
ret
|
||||
END(xen_iret_crit_fixup)
|
||||
|
||||
@@ -1278,6 +1278,11 @@ struct bus_type platform_bus_type = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(platform_bus_type);
|
||||
|
||||
static inline int __platform_match(struct device *dev, const void *drv)
|
||||
{
|
||||
return platform_match(dev, (struct device_driver *)drv);
|
||||
}
|
||||
|
||||
/**
|
||||
* platform_find_device_by_driver - Find a platform device with a given
|
||||
* driver.
|
||||
@@ -1288,7 +1293,7 @@ struct device *platform_find_device_by_driver(struct device *start,
|
||||
const struct device_driver *drv)
|
||||
{
|
||||
return bus_find_device(&platform_bus_type, start, drv,
|
||||
(void *)platform_match);
|
||||
__platform_match);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(platform_find_device_by_driver);
|
||||
|
||||
|
||||
+3
-2
@@ -1032,14 +1032,15 @@ static int nbd_add_socket(struct nbd_device *nbd, unsigned long arg,
|
||||
sockfd_put(sock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
config->socks = socks;
|
||||
|
||||
nsock = kzalloc(sizeof(struct nbd_sock), GFP_KERNEL);
|
||||
if (!nsock) {
|
||||
sockfd_put(sock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
config->socks = socks;
|
||||
|
||||
nsock->fallback_index = -1;
|
||||
nsock->dead = false;
|
||||
mutex_init(&nsock->tx_lock);
|
||||
|
||||
@@ -591,6 +591,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
|
||||
if (*ptr == 0xc0) {
|
||||
BT_ERR("Short BCSP packet");
|
||||
kfree_skb(bcsp->rx_skb);
|
||||
bcsp->rx_skb = NULL;
|
||||
bcsp->rx_state = BCSP_W4_PKT_START;
|
||||
bcsp->rx_count = 0;
|
||||
} else
|
||||
@@ -606,6 +607,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
|
||||
bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) {
|
||||
BT_ERR("Error in BCSP hdr checksum");
|
||||
kfree_skb(bcsp->rx_skb);
|
||||
bcsp->rx_skb = NULL;
|
||||
bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
|
||||
bcsp->rx_count = 0;
|
||||
continue;
|
||||
@@ -630,6 +632,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
|
||||
bscp_get_crc(bcsp));
|
||||
|
||||
kfree_skb(bcsp->rx_skb);
|
||||
bcsp->rx_skb = NULL;
|
||||
bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
|
||||
bcsp->rx_count = 0;
|
||||
continue;
|
||||
|
||||
+18
-21
@@ -621,13 +621,6 @@ static int ll_setup(struct hci_uart *hu)
|
||||
|
||||
serdev_device_set_flow_control(serdev, true);
|
||||
|
||||
if (hu->oper_speed)
|
||||
speed = hu->oper_speed;
|
||||
else if (hu->proto->oper_speed)
|
||||
speed = hu->proto->oper_speed;
|
||||
else
|
||||
speed = 0;
|
||||
|
||||
do {
|
||||
/* Reset the Bluetooth device */
|
||||
gpiod_set_value_cansleep(lldev->enable_gpio, 0);
|
||||
@@ -639,20 +632,6 @@ static int ll_setup(struct hci_uart *hu)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (speed) {
|
||||
__le32 speed_le = cpu_to_le32(speed);
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = __hci_cmd_sync(hu->hdev,
|
||||
HCI_VS_UPDATE_UART_HCI_BAUDRATE,
|
||||
sizeof(speed_le), &speed_le,
|
||||
HCI_INIT_TIMEOUT);
|
||||
if (!IS_ERR(skb)) {
|
||||
kfree_skb(skb);
|
||||
serdev_device_set_baudrate(serdev, speed);
|
||||
}
|
||||
}
|
||||
|
||||
err = download_firmware(lldev);
|
||||
if (!err)
|
||||
break;
|
||||
@@ -677,7 +656,25 @@ static int ll_setup(struct hci_uart *hu)
|
||||
}
|
||||
|
||||
/* Operational speed if any */
|
||||
if (hu->oper_speed)
|
||||
speed = hu->oper_speed;
|
||||
else if (hu->proto->oper_speed)
|
||||
speed = hu->proto->oper_speed;
|
||||
else
|
||||
speed = 0;
|
||||
|
||||
if (speed) {
|
||||
__le32 speed_le = cpu_to_le32(speed);
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = __hci_cmd_sync(hu->hdev, HCI_VS_UPDATE_UART_HCI_BAUDRATE,
|
||||
sizeof(speed_le), &speed_le,
|
||||
HCI_INIT_TIMEOUT);
|
||||
if (!IS_ERR(skb)) {
|
||||
kfree_skb(skb);
|
||||
serdev_device_set_baudrate(serdev, speed);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -933,6 +933,9 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
|
||||
struct freq_attr *fattr = to_attr(attr);
|
||||
ssize_t ret;
|
||||
|
||||
if (!fattr->show)
|
||||
return -EIO;
|
||||
|
||||
down_read(&policy->rwsem);
|
||||
ret = fattr->show(policy, buf);
|
||||
up_read(&policy->rwsem);
|
||||
@@ -947,6 +950,9 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
|
||||
struct freq_attr *fattr = to_attr(attr);
|
||||
ssize_t ret = -EINVAL;
|
||||
|
||||
if (!fattr->store)
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* cpus_read_trylock() is used here to work around a circular lock
|
||||
* dependency problem with respect to the cpufreq_register_driver().
|
||||
|
||||
@@ -287,6 +287,7 @@ config CRYPTO_DEV_TALITOS
|
||||
select CRYPTO_AUTHENC
|
||||
select CRYPTO_BLKCIPHER
|
||||
select CRYPTO_HASH
|
||||
select CRYPTO_LIB_DES
|
||||
select HW_RANDOM
|
||||
depends on FSL_SOC
|
||||
help
|
||||
|
||||
@@ -221,9 +221,9 @@ static void eip197_trc_cache_init(struct safexcel_crypto_priv *priv)
|
||||
/* Step #3: Determine log2 of hash table size */
|
||||
cs_ht_sz = __fls(asize - cs_rc_max) - 2;
|
||||
/* Step #4: determine current size of hash table in dwords */
|
||||
cs_ht_wc = 16<<cs_ht_sz; /* dwords, not admin words */
|
||||
cs_ht_wc = 16 << cs_ht_sz; /* dwords, not admin words */
|
||||
/* Step #5: add back excess words and see if we can fit more records */
|
||||
cs_rc_max = min_t(uint, cs_rc_abs_max, asize - (cs_ht_wc >> 4));
|
||||
cs_rc_max = min_t(uint, cs_rc_abs_max, asize - (cs_ht_wc >> 2));
|
||||
|
||||
/* Clear the cache RAMs */
|
||||
eip197_trc_cache_clear(priv, cs_rc_max, cs_ht_wc);
|
||||
|
||||
+45
-6
@@ -211,6 +211,18 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
|
||||
return 0; /* we know nothing about this usage type */
|
||||
}
|
||||
|
||||
/*
|
||||
* Concatenate usage which defines 16 bits or less with the
|
||||
* currently defined usage page to form a 32 bit usage
|
||||
*/
|
||||
|
||||
static void complete_usage(struct hid_parser *parser, unsigned int index)
|
||||
{
|
||||
parser->local.usage[index] &= 0xFFFF;
|
||||
parser->local.usage[index] |=
|
||||
(parser->global.usage_page & 0xFFFF) << 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a usage to the temporary parser table.
|
||||
*/
|
||||
@@ -222,6 +234,14 @@ static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size)
|
||||
return -1;
|
||||
}
|
||||
parser->local.usage[parser->local.usage_index] = usage;
|
||||
|
||||
/*
|
||||
* If Usage item only includes usage id, concatenate it with
|
||||
* currently defined usage page
|
||||
*/
|
||||
if (size <= 2)
|
||||
complete_usage(parser, parser->local.usage_index);
|
||||
|
||||
parser->local.usage_size[parser->local.usage_index] = size;
|
||||
parser->local.collection_index[parser->local.usage_index] =
|
||||
parser->collection_stack_ptr ?
|
||||
@@ -543,13 +563,32 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
|
||||
* usage value."
|
||||
*/
|
||||
|
||||
static void hid_concatenate_usage_page(struct hid_parser *parser)
|
||||
static void hid_concatenate_last_usage_page(struct hid_parser *parser)
|
||||
{
|
||||
int i;
|
||||
unsigned int usage_page;
|
||||
unsigned int current_page;
|
||||
|
||||
for (i = 0; i < parser->local.usage_index; i++)
|
||||
if (parser->local.usage_size[i] <= 2)
|
||||
parser->local.usage[i] += parser->global.usage_page << 16;
|
||||
if (!parser->local.usage_index)
|
||||
return;
|
||||
|
||||
usage_page = parser->global.usage_page;
|
||||
|
||||
/*
|
||||
* Concatenate usage page again only if last declared Usage Page
|
||||
* has not been already used in previous usages concatenation
|
||||
*/
|
||||
for (i = parser->local.usage_index - 1; i >= 0; i--) {
|
||||
if (parser->local.usage_size[i] > 2)
|
||||
/* Ignore extended usages */
|
||||
continue;
|
||||
|
||||
current_page = parser->local.usage[i] >> 16;
|
||||
if (current_page == usage_page)
|
||||
break;
|
||||
|
||||
complete_usage(parser, i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -561,7 +600,7 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
|
||||
__u32 data;
|
||||
int ret;
|
||||
|
||||
hid_concatenate_usage_page(parser);
|
||||
hid_concatenate_last_usage_page(parser);
|
||||
|
||||
data = item_udata(item);
|
||||
|
||||
@@ -772,7 +811,7 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
|
||||
__u32 data;
|
||||
int i;
|
||||
|
||||
hid_concatenate_usage_page(parser);
|
||||
hid_concatenate_last_usage_page(parser);
|
||||
|
||||
data = item_udata(item);
|
||||
|
||||
|
||||
@@ -2700,21 +2700,18 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
cc->io_queue = alloc_workqueue("kcryptd_io/%s",
|
||||
WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM,
|
||||
1, devname);
|
||||
cc->io_queue = alloc_workqueue("kcryptd_io/%s", WQ_MEM_RECLAIM, 1, devname);
|
||||
if (!cc->io_queue) {
|
||||
ti->error = "Couldn't create kcryptd io queue";
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags))
|
||||
cc->crypt_queue = alloc_workqueue("kcryptd/%s",
|
||||
WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM,
|
||||
cc->crypt_queue = alloc_workqueue("kcryptd/%s", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM,
|
||||
1, devname);
|
||||
else
|
||||
cc->crypt_queue = alloc_workqueue("kcryptd/%s",
|
||||
WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND,
|
||||
WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND,
|
||||
num_online_cpus(), devname);
|
||||
if (!cc->crypt_queue) {
|
||||
ti->error = "Couldn't create kcryptd queue";
|
||||
|
||||
+1
-1
@@ -191,7 +191,7 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
|
||||
|
||||
out_free_pages:
|
||||
while (--j >= 0)
|
||||
resync_free_pages(&rps[j * 2]);
|
||||
resync_free_pages(&rps[j]);
|
||||
|
||||
j = 0;
|
||||
out_free_bio:
|
||||
|
||||
@@ -796,7 +796,11 @@ static int vivid_thread_vid_cap(void *data)
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
if (!mutex_trylock(&dev->mutex)) {
|
||||
schedule_timeout_uninterruptible(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
cur_jiffies = jiffies;
|
||||
if (dev->cap_seq_resync) {
|
||||
dev->jiffies_vid_cap = cur_jiffies;
|
||||
@@ -956,8 +960,6 @@ void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
|
||||
|
||||
/* shutdown control thread */
|
||||
vivid_grab_controls(dev, false);
|
||||
mutex_unlock(&dev->mutex);
|
||||
kthread_stop(dev->kthread_vid_cap);
|
||||
dev->kthread_vid_cap = NULL;
|
||||
mutex_lock(&dev->mutex);
|
||||
}
|
||||
|
||||
@@ -143,7 +143,11 @@ static int vivid_thread_vid_out(void *data)
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
if (!mutex_trylock(&dev->mutex)) {
|
||||
schedule_timeout_uninterruptible(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
cur_jiffies = jiffies;
|
||||
if (dev->out_seq_resync) {
|
||||
dev->jiffies_vid_out = cur_jiffies;
|
||||
@@ -301,8 +305,6 @@ void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
|
||||
|
||||
/* shutdown control thread */
|
||||
vivid_grab_controls(dev, false);
|
||||
mutex_unlock(&dev->mutex);
|
||||
kthread_stop(dev->kthread_vid_out);
|
||||
dev->kthread_vid_out = NULL;
|
||||
mutex_lock(&dev->mutex);
|
||||
}
|
||||
|
||||
@@ -141,7 +141,11 @@ static int vivid_thread_sdr_cap(void *data)
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
if (!mutex_trylock(&dev->mutex)) {
|
||||
schedule_timeout_uninterruptible(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
cur_jiffies = jiffies;
|
||||
if (dev->sdr_cap_seq_resync) {
|
||||
dev->jiffies_sdr_cap = cur_jiffies;
|
||||
@@ -303,10 +307,8 @@ static void sdr_cap_stop_streaming(struct vb2_queue *vq)
|
||||
}
|
||||
|
||||
/* shutdown control thread */
|
||||
mutex_unlock(&dev->mutex);
|
||||
kthread_stop(dev->kthread_sdr_cap);
|
||||
dev->kthread_sdr_cap = NULL;
|
||||
mutex_lock(&dev->mutex);
|
||||
}
|
||||
|
||||
static void sdr_cap_buf_request_complete(struct vb2_buffer *vb)
|
||||
|
||||
@@ -223,9 +223,6 @@ static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count)
|
||||
if (vb2_is_streaming(&dev->vb_vid_out_q))
|
||||
dev->can_loop_video = vivid_vid_can_loop(dev);
|
||||
|
||||
if (dev->kthread_vid_cap)
|
||||
return 0;
|
||||
|
||||
dev->vid_cap_seq_count = 0;
|
||||
dprintk(dev, 1, "%s\n", __func__);
|
||||
for (i = 0; i < VIDEO_MAX_FRAME; i++)
|
||||
|
||||
@@ -161,9 +161,6 @@ static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count)
|
||||
if (vb2_is_streaming(&dev->vb_vid_cap_q))
|
||||
dev->can_loop_video = vivid_vid_can_loop(dev);
|
||||
|
||||
if (dev->kthread_vid_out)
|
||||
return 0;
|
||||
|
||||
dev->vid_out_seq_count = 0;
|
||||
dprintk(dev, 1, "%s\n", __func__);
|
||||
if (dev->start_streaming_error) {
|
||||
|
||||
@@ -1598,8 +1598,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
|
||||
spin_unlock_irqrestore(&ictx->kc_lock, flags);
|
||||
|
||||
/* send touchscreen events through input subsystem if touchpad data */
|
||||
if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 &&
|
||||
buf[7] == 0x86) {
|
||||
if (ictx->touch && len == 8 && buf[7] == 0x86) {
|
||||
imon_touch_event(ictx, buf);
|
||||
return;
|
||||
|
||||
|
||||
+98
-43
@@ -564,7 +564,7 @@ static int mceusb_cmd_datasize(u8 cmd, u8 subcmd)
|
||||
datasize = 4;
|
||||
break;
|
||||
case MCE_CMD_G_REVISION:
|
||||
datasize = 2;
|
||||
datasize = 4;
|
||||
break;
|
||||
case MCE_RSP_EQWAKESUPPORT:
|
||||
case MCE_RSP_GETWAKESOURCE:
|
||||
@@ -600,14 +600,9 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len,
|
||||
char *inout;
|
||||
u8 cmd, subcmd, *data;
|
||||
struct device *dev = ir->dev;
|
||||
int start, skip = 0;
|
||||
u32 carrier, period;
|
||||
|
||||
/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
|
||||
if (ir->flags.microsoft_gen1 && !out && !offset)
|
||||
skip = 2;
|
||||
|
||||
if (len <= skip)
|
||||
if (offset < 0 || offset >= buf_len)
|
||||
return;
|
||||
|
||||
dev_dbg(dev, "%cx data[%d]: %*ph (len=%d sz=%d)",
|
||||
@@ -616,11 +611,32 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len,
|
||||
|
||||
inout = out ? "Request" : "Got";
|
||||
|
||||
start = offset + skip;
|
||||
cmd = buf[start] & 0xff;
|
||||
subcmd = buf[start + 1] & 0xff;
|
||||
data = buf + start + 2;
|
||||
cmd = buf[offset];
|
||||
subcmd = (offset + 1 < buf_len) ? buf[offset + 1] : 0;
|
||||
data = &buf[offset] + 2;
|
||||
|
||||
/* Trace meaningless 0xb1 0x60 header bytes on original receiver */
|
||||
if (ir->flags.microsoft_gen1 && !out && !offset) {
|
||||
dev_dbg(dev, "MCE gen 1 header");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Trace IR data header or trailer */
|
||||
if (cmd != MCE_CMD_PORT_IR &&
|
||||
(cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA) {
|
||||
if (cmd == MCE_IRDATA_TRAILER)
|
||||
dev_dbg(dev, "End of raw IR data");
|
||||
else
|
||||
dev_dbg(dev, "Raw IR data, %d pulse/space samples",
|
||||
cmd & MCE_PACKET_LENGTH_MASK);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unexpected end of buffer? */
|
||||
if (offset + len > buf_len)
|
||||
return;
|
||||
|
||||
/* Decode MCE command/response */
|
||||
switch (cmd) {
|
||||
case MCE_CMD_NULL:
|
||||
if (subcmd == MCE_CMD_NULL)
|
||||
@@ -644,7 +660,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len,
|
||||
dev_dbg(dev, "Get hw/sw rev?");
|
||||
else
|
||||
dev_dbg(dev, "hw/sw rev %*ph",
|
||||
4, &buf[start + 2]);
|
||||
4, &buf[offset + 2]);
|
||||
break;
|
||||
case MCE_CMD_RESUME:
|
||||
dev_dbg(dev, "Device resume requested");
|
||||
@@ -746,13 +762,6 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd == MCE_IRDATA_TRAILER)
|
||||
dev_dbg(dev, "End of raw IR data");
|
||||
else if ((cmd != MCE_CMD_PORT_IR) &&
|
||||
((cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA))
|
||||
dev_dbg(dev, "Raw IR data, %d pulse/space samples",
|
||||
cmd & MCE_PACKET_LENGTH_MASK);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1136,32 +1145,62 @@ static int mceusb_set_rx_carrier_report(struct rc_dev *dev, int enable)
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle PORT_SYS/IR command response received from the MCE device.
|
||||
*
|
||||
* Assumes single response with all its data (not truncated)
|
||||
* in buf_in[]. The response itself determines its total length
|
||||
* (mceusb_cmd_datasize() + 2) and hence the minimum size of buf_in[].
|
||||
*
|
||||
* We don't do anything but print debug spew for many of the command bits
|
||||
* we receive from the hardware, but some of them are useful information
|
||||
* we want to store so that we can use them.
|
||||
*/
|
||||
static void mceusb_handle_command(struct mceusb_dev *ir, int index)
|
||||
static void mceusb_handle_command(struct mceusb_dev *ir, u8 *buf_in)
|
||||
{
|
||||
u8 cmd = buf_in[0];
|
||||
u8 subcmd = buf_in[1];
|
||||
u8 *hi = &buf_in[2]; /* read only when required */
|
||||
u8 *lo = &buf_in[3]; /* read only when required */
|
||||
struct ir_raw_event rawir = {};
|
||||
u8 hi = ir->buf_in[index + 1] & 0xff;
|
||||
u8 lo = ir->buf_in[index + 2] & 0xff;
|
||||
u32 carrier_cycles;
|
||||
u32 cycles_fix;
|
||||
|
||||
switch (ir->buf_in[index]) {
|
||||
/* the one and only 5-byte return value command */
|
||||
case MCE_RSP_GETPORTSTATUS:
|
||||
if ((ir->buf_in[index + 4] & 0xff) == 0x00)
|
||||
ir->txports_cabled |= 1 << hi;
|
||||
break;
|
||||
if (cmd == MCE_CMD_PORT_SYS) {
|
||||
switch (subcmd) {
|
||||
/* the one and only 5-byte return value command */
|
||||
case MCE_RSP_GETPORTSTATUS:
|
||||
if (buf_in[5] == 0)
|
||||
ir->txports_cabled |= 1 << *hi;
|
||||
break;
|
||||
|
||||
/* 1-byte return value commands */
|
||||
case MCE_RSP_EQEMVER:
|
||||
ir->emver = *hi;
|
||||
break;
|
||||
|
||||
/* No return value commands */
|
||||
case MCE_RSP_CMD_ILLEGAL:
|
||||
ir->need_reset = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd != MCE_CMD_PORT_IR)
|
||||
return;
|
||||
|
||||
switch (subcmd) {
|
||||
/* 2-byte return value commands */
|
||||
case MCE_RSP_EQIRTIMEOUT:
|
||||
ir->rc->timeout = US_TO_NS((hi << 8 | lo) * MCE_TIME_UNIT);
|
||||
ir->rc->timeout = US_TO_NS((*hi << 8 | *lo) * MCE_TIME_UNIT);
|
||||
break;
|
||||
case MCE_RSP_EQIRNUMPORTS:
|
||||
ir->num_txports = hi;
|
||||
ir->num_rxports = lo;
|
||||
ir->num_txports = *hi;
|
||||
ir->num_rxports = *lo;
|
||||
break;
|
||||
case MCE_RSP_EQIRRXCFCNT:
|
||||
/*
|
||||
@@ -1174,7 +1213,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
|
||||
*/
|
||||
if (ir->carrier_report_enabled && ir->learning_active &&
|
||||
ir->pulse_tunit > 0) {
|
||||
carrier_cycles = (hi << 8 | lo);
|
||||
carrier_cycles = (*hi << 8 | *lo);
|
||||
/*
|
||||
* Adjust carrier cycle count by adding
|
||||
* 1 missed count per pulse "on"
|
||||
@@ -1192,24 +1231,24 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
|
||||
break;
|
||||
|
||||
/* 1-byte return value commands */
|
||||
case MCE_RSP_EQEMVER:
|
||||
ir->emver = hi;
|
||||
break;
|
||||
case MCE_RSP_EQIRTXPORTS:
|
||||
ir->tx_mask = hi;
|
||||
ir->tx_mask = *hi;
|
||||
break;
|
||||
case MCE_RSP_EQIRRXPORTEN:
|
||||
ir->learning_active = ((hi & 0x02) == 0x02);
|
||||
if (ir->rxports_active != hi) {
|
||||
ir->learning_active = ((*hi & 0x02) == 0x02);
|
||||
if (ir->rxports_active != *hi) {
|
||||
dev_info(ir->dev, "%s-range (0x%x) receiver active",
|
||||
ir->learning_active ? "short" : "long", hi);
|
||||
ir->rxports_active = hi;
|
||||
ir->learning_active ? "short" : "long", *hi);
|
||||
ir->rxports_active = *hi;
|
||||
}
|
||||
break;
|
||||
|
||||
/* No return value commands */
|
||||
case MCE_RSP_CMD_ILLEGAL:
|
||||
case MCE_RSP_TX_TIMEOUT:
|
||||
ir->need_reset = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1235,7 +1274,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
|
||||
ir->rem = mceusb_cmd_datasize(ir->cmd, ir->buf_in[i]);
|
||||
mceusb_dev_printdata(ir, ir->buf_in, buf_len, i - 1,
|
||||
ir->rem + 2, false);
|
||||
mceusb_handle_command(ir, i);
|
||||
if (i + ir->rem < buf_len)
|
||||
mceusb_handle_command(ir, &ir->buf_in[i - 1]);
|
||||
ir->parser_state = CMD_DATA;
|
||||
break;
|
||||
case PARSE_IRDATA:
|
||||
@@ -1264,15 +1304,22 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
|
||||
ir->rem--;
|
||||
break;
|
||||
case CMD_HEADER:
|
||||
/* decode mce packets of the form (84),AA,BB,CC,DD */
|
||||
/* IR data packets can span USB messages - rem */
|
||||
ir->cmd = ir->buf_in[i];
|
||||
if ((ir->cmd == MCE_CMD_PORT_IR) ||
|
||||
((ir->cmd & MCE_PORT_MASK) !=
|
||||
MCE_COMMAND_IRDATA)) {
|
||||
/*
|
||||
* got PORT_SYS, PORT_IR, or unknown
|
||||
* command response prefix
|
||||
*/
|
||||
ir->parser_state = SUBCMD;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* got IR data prefix (0x80 + num_bytes)
|
||||
* decode MCE packets of the form {0x83, AA, BB, CC}
|
||||
* IR data packets can span USB messages
|
||||
*/
|
||||
ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
|
||||
mceusb_dev_printdata(ir, ir->buf_in, buf_len,
|
||||
i, ir->rem + 1, false);
|
||||
@@ -1296,6 +1343,14 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
|
||||
if (ir->parser_state != CMD_HEADER && !ir->rem)
|
||||
ir->parser_state = CMD_HEADER;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accept IR data spanning multiple rx buffers.
|
||||
* Reject MCE command response spanning multiple rx buffers.
|
||||
*/
|
||||
if (ir->parser_state != PARSE_IRDATA || !ir->rem)
|
||||
ir->parser_state = CMD_HEADER;
|
||||
|
||||
if (event) {
|
||||
dev_dbg(ir->dev, "processed IR data");
|
||||
ir_raw_event_handle(ir->rc);
|
||||
|
||||
@@ -538,6 +538,9 @@ static int flexcop_usb_probe(struct usb_interface *intf,
|
||||
struct flexcop_device *fc = NULL;
|
||||
int ret;
|
||||
|
||||
if (intf->cur_altsetting->desc.bNumEndpoints < 1)
|
||||
return -ENODEV;
|
||||
|
||||
if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) {
|
||||
err("out of memory\n");
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -521,7 +521,8 @@ static int cxusb_rc_query(struct dvb_usb_device *d)
|
||||
{
|
||||
u8 ircode[4];
|
||||
|
||||
cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4);
|
||||
if (cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4) < 0)
|
||||
return 0;
|
||||
|
||||
if (ircode[2] || ircode[3])
|
||||
rc_keydown(d->rc_dev, RC_PROTO_NEC,
|
||||
|
||||
@@ -314,6 +314,10 @@ static int usbvision_v4l2_open(struct file *file)
|
||||
if (mutex_lock_interruptible(&usbvision->v4l2_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (usbvision->remove_pending) {
|
||||
err_code = -ENODEV;
|
||||
goto unlock;
|
||||
}
|
||||
if (usbvision->user) {
|
||||
err_code = -EBUSY;
|
||||
} else {
|
||||
@@ -377,6 +381,7 @@ unlock:
|
||||
static int usbvision_v4l2_close(struct file *file)
|
||||
{
|
||||
struct usb_usbvision *usbvision = video_drvdata(file);
|
||||
int r;
|
||||
|
||||
PDEBUG(DBG_IO, "close");
|
||||
|
||||
@@ -391,9 +396,10 @@ static int usbvision_v4l2_close(struct file *file)
|
||||
usbvision_scratch_free(usbvision);
|
||||
|
||||
usbvision->user--;
|
||||
r = usbvision->remove_pending;
|
||||
mutex_unlock(&usbvision->v4l2_lock);
|
||||
|
||||
if (usbvision->remove_pending) {
|
||||
if (r) {
|
||||
printk(KERN_INFO "%s: Final disconnect\n", __func__);
|
||||
usbvision_release(usbvision);
|
||||
return 0;
|
||||
@@ -453,6 +459,9 @@ static int vidioc_querycap(struct file *file, void *priv,
|
||||
{
|
||||
struct usb_usbvision *usbvision = video_drvdata(file);
|
||||
|
||||
if (!usbvision->dev)
|
||||
return -ENODEV;
|
||||
|
||||
strscpy(vc->driver, "USBVision", sizeof(vc->driver));
|
||||
strscpy(vc->card,
|
||||
usbvision_device_data[usbvision->dev_model].model_string,
|
||||
@@ -1061,6 +1070,11 @@ static int usbvision_radio_open(struct file *file)
|
||||
|
||||
if (mutex_lock_interruptible(&usbvision->v4l2_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (usbvision->remove_pending) {
|
||||
err_code = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
err_code = v4l2_fh_open(file);
|
||||
if (err_code)
|
||||
goto out;
|
||||
@@ -1093,21 +1107,24 @@ out:
|
||||
static int usbvision_radio_close(struct file *file)
|
||||
{
|
||||
struct usb_usbvision *usbvision = video_drvdata(file);
|
||||
int r;
|
||||
|
||||
PDEBUG(DBG_IO, "");
|
||||
|
||||
mutex_lock(&usbvision->v4l2_lock);
|
||||
/* Set packet size to 0 */
|
||||
usbvision->iface_alt = 0;
|
||||
usb_set_interface(usbvision->dev, usbvision->iface,
|
||||
usbvision->iface_alt);
|
||||
if (usbvision->dev)
|
||||
usb_set_interface(usbvision->dev, usbvision->iface,
|
||||
usbvision->iface_alt);
|
||||
|
||||
usbvision_audio_off(usbvision);
|
||||
usbvision->radio = 0;
|
||||
usbvision->user--;
|
||||
r = usbvision->remove_pending;
|
||||
mutex_unlock(&usbvision->v4l2_lock);
|
||||
|
||||
if (usbvision->remove_pending) {
|
||||
if (r) {
|
||||
printk(KERN_INFO "%s: Final disconnect\n", __func__);
|
||||
v4l2_fh_release(file);
|
||||
usbvision_release(usbvision);
|
||||
@@ -1539,6 +1556,7 @@ err_usb:
|
||||
static void usbvision_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct usb_usbvision *usbvision = to_usbvision(usb_get_intfdata(intf));
|
||||
int u;
|
||||
|
||||
PDEBUG(DBG_PROBE, "");
|
||||
|
||||
@@ -1555,13 +1573,14 @@ static void usbvision_disconnect(struct usb_interface *intf)
|
||||
v4l2_device_disconnect(&usbvision->v4l2_dev);
|
||||
usbvision_i2c_unregister(usbvision);
|
||||
usbvision->remove_pending = 1; /* Now all ISO data will be ignored */
|
||||
u = usbvision->user;
|
||||
|
||||
usb_put_dev(usbvision->dev);
|
||||
usbvision->dev = NULL; /* USB device is no more */
|
||||
|
||||
mutex_unlock(&usbvision->v4l2_lock);
|
||||
|
||||
if (usbvision->user) {
|
||||
if (u) {
|
||||
printk(KERN_INFO "%s: In use, disconnect pending\n",
|
||||
__func__);
|
||||
wake_up_interruptible(&usbvision->wait_frame);
|
||||
|
||||
@@ -2151,6 +2151,20 @@ static int uvc_probe(struct usb_interface *intf,
|
||||
sizeof(dev->name) - len);
|
||||
}
|
||||
|
||||
/* Initialize the media device. */
|
||||
#ifdef CONFIG_MEDIA_CONTROLLER
|
||||
dev->mdev.dev = &intf->dev;
|
||||
strscpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
|
||||
if (udev->serial)
|
||||
strscpy(dev->mdev.serial, udev->serial,
|
||||
sizeof(dev->mdev.serial));
|
||||
usb_make_path(udev, dev->mdev.bus_info, sizeof(dev->mdev.bus_info));
|
||||
dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
|
||||
media_device_init(&dev->mdev);
|
||||
|
||||
dev->vdev.mdev = &dev->mdev;
|
||||
#endif
|
||||
|
||||
/* Parse the Video Class control descriptor. */
|
||||
if (uvc_parse_control(dev) < 0) {
|
||||
uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC "
|
||||
@@ -2171,19 +2185,7 @@ static int uvc_probe(struct usb_interface *intf,
|
||||
"linux-uvc-devel mailing list.\n");
|
||||
}
|
||||
|
||||
/* Initialize the media device and register the V4L2 device. */
|
||||
#ifdef CONFIG_MEDIA_CONTROLLER
|
||||
dev->mdev.dev = &intf->dev;
|
||||
strscpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
|
||||
if (udev->serial)
|
||||
strscpy(dev->mdev.serial, udev->serial,
|
||||
sizeof(dev->mdev.serial));
|
||||
usb_make_path(udev, dev->mdev.bus_info, sizeof(dev->mdev.bus_info));
|
||||
dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
|
||||
media_device_init(&dev->mdev);
|
||||
|
||||
dev->vdev.mdev = &dev->mdev;
|
||||
#endif
|
||||
/* Register the V4L2 device. */
|
||||
if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
|
||||
goto error;
|
||||
|
||||
|
||||
@@ -873,15 +873,16 @@ static const struct device_type mei_cl_device_type = {
|
||||
|
||||
/**
|
||||
* mei_cl_bus_set_name - set device name for me client device
|
||||
* <controller>-<client device>
|
||||
* Example: 0000:00:16.0-55213584-9a29-4916-badf-0fb7ed682aeb
|
||||
*
|
||||
* @cldev: me client device
|
||||
*/
|
||||
static inline void mei_cl_bus_set_name(struct mei_cl_device *cldev)
|
||||
{
|
||||
dev_set_name(&cldev->dev, "mei:%s:%pUl:%02X",
|
||||
cldev->name,
|
||||
mei_me_cl_uuid(cldev->me_cl),
|
||||
mei_me_cl_ver(cldev->me_cl));
|
||||
dev_set_name(&cldev->dev, "%s-%pUl",
|
||||
dev_name(cldev->bus->dev),
|
||||
mei_me_cl_uuid(cldev->me_cl));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
|
||||
#define MEI_DEV_ID_CMP_LP 0x02e0 /* Comet Point LP */
|
||||
#define MEI_DEV_ID_CMP_LP_3 0x02e4 /* Comet Point LP 3 (iTouch) */
|
||||
#define MEI_DEV_ID_CMP_V 0xA3BA /* Comet Point Lake V */
|
||||
|
||||
#define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
|
||||
|
||||
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_LP, MEI_ME_PCH12_CFG)},
|
||||
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_LP_3, MEI_ME_PCH8_CFG)},
|
||||
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_V, MEI_ME_PCH12_CFG)},
|
||||
|
||||
{MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)},
|
||||
|
||||
|
||||
@@ -594,15 +594,15 @@ static int sja1105_parse_rgmii_delays(struct sja1105_private *priv,
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SJA1105_NUM_PORTS; i++) {
|
||||
if (ports->role == XMII_MAC)
|
||||
if (ports[i].role == XMII_MAC)
|
||||
continue;
|
||||
|
||||
if (ports->phy_mode == PHY_INTERFACE_MODE_RGMII_RXID ||
|
||||
ports->phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
|
||||
if (ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_RXID ||
|
||||
ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
|
||||
priv->rgmii_rx_delay[i] = true;
|
||||
|
||||
if (ports->phy_mode == PHY_INTERFACE_MODE_RGMII_TXID ||
|
||||
ports->phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
|
||||
if (ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_TXID ||
|
||||
ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
|
||||
priv->rgmii_tx_delay[i] = true;
|
||||
|
||||
if ((priv->rgmii_rx_delay[i] || priv->rgmii_tx_delay[i]) &&
|
||||
|
||||
@@ -4392,6 +4392,7 @@ static int macb_remove(struct platform_device *pdev)
|
||||
mdiobus_free(bp->mii_bus);
|
||||
|
||||
unregister_netdev(dev);
|
||||
tasklet_kill(&bp->hresp_err_tasklet);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
if (!pm_runtime_suspended(&pdev->dev)) {
|
||||
|
||||
@@ -544,7 +544,7 @@ static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id,
|
||||
}
|
||||
|
||||
qpl->id = id;
|
||||
qpl->num_entries = pages;
|
||||
qpl->num_entries = 0;
|
||||
qpl->pages = kvzalloc(pages * sizeof(*qpl->pages), GFP_KERNEL);
|
||||
/* caller handles clean up */
|
||||
if (!qpl->pages)
|
||||
@@ -562,6 +562,7 @@ static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id,
|
||||
/* caller handles clean up */
|
||||
if (err)
|
||||
return -ENOMEM;
|
||||
qpl->num_entries++;
|
||||
}
|
||||
priv->num_registered_pages += pages;
|
||||
|
||||
|
||||
@@ -1516,6 +1516,7 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
|
||||
rtl_lock_config_regs(tp);
|
||||
|
||||
device_set_wakeup_enable(tp_to_dev(tp), wolopts);
|
||||
tp->dev->wol_enabled = wolopts ? 1 : 0;
|
||||
}
|
||||
|
||||
static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
||||
@@ -4118,7 +4119,7 @@ static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
|
||||
case RTL_GIGA_MAC_VER_27 ... RTL_GIGA_MAC_VER_28:
|
||||
r8168dp_hw_jumbo_enable(tp);
|
||||
break;
|
||||
case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_34:
|
||||
case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33:
|
||||
r8168e_hw_jumbo_enable(tp);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -359,10 +359,11 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port,
|
||||
}
|
||||
spin_unlock(&port->bc_queue.lock);
|
||||
|
||||
schedule_work(&port->bc_work);
|
||||
|
||||
if (err)
|
||||
goto free_nskb;
|
||||
|
||||
schedule_work(&port->bc_work);
|
||||
return;
|
||||
|
||||
free_nskb:
|
||||
|
||||
@@ -62,8 +62,8 @@ static int mdiobus_register_reset(struct mdio_device *mdiodev)
|
||||
struct reset_control *reset = NULL;
|
||||
|
||||
if (mdiodev->dev.of_node)
|
||||
reset = devm_reset_control_get_exclusive(&mdiodev->dev,
|
||||
"phy");
|
||||
reset = of_reset_control_get_exclusive(mdiodev->dev.of_node,
|
||||
"phy");
|
||||
if (IS_ERR(reset)) {
|
||||
if (PTR_ERR(reset) == -ENOENT || PTR_ERR(reset) == -ENOTSUPP)
|
||||
reset = NULL;
|
||||
@@ -107,6 +107,8 @@ int mdiobus_unregister_device(struct mdio_device *mdiodev)
|
||||
if (mdiodev->bus->mdio_map[mdiodev->addr] != mdiodev)
|
||||
return -EINVAL;
|
||||
|
||||
reset_control_put(mdiodev->reset_ctrl);
|
||||
|
||||
mdiodev->bus->mdio_map[mdiodev->addr] = NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -855,6 +855,7 @@ err_free_chan:
|
||||
sl->tty = NULL;
|
||||
tty->disc_data = NULL;
|
||||
clear_bit(SLF_INUSE, &sl->flags);
|
||||
sl_free_netdev(sl->dev);
|
||||
free_netdev(sl->dev);
|
||||
|
||||
err_exit:
|
||||
|
||||
@@ -3490,7 +3490,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
struct ath10k_pci *ar_pci;
|
||||
enum ath10k_hw_rev hw_rev;
|
||||
struct ath10k_bus_params bus_params = {};
|
||||
bool pci_ps;
|
||||
bool pci_ps, is_qca988x = false;
|
||||
int (*pci_soft_reset)(struct ath10k *ar);
|
||||
int (*pci_hard_reset)(struct ath10k *ar);
|
||||
u32 (*targ_cpu_to_ce_addr)(struct ath10k *ar, u32 addr);
|
||||
@@ -3500,6 +3500,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
case QCA988X_2_0_DEVICE_ID:
|
||||
hw_rev = ATH10K_HW_QCA988X;
|
||||
pci_ps = false;
|
||||
is_qca988x = true;
|
||||
pci_soft_reset = ath10k_pci_warm_reset;
|
||||
pci_hard_reset = ath10k_pci_qca988x_chip_reset;
|
||||
targ_cpu_to_ce_addr = ath10k_pci_qca988x_targ_cpu_to_ce_addr;
|
||||
@@ -3619,25 +3620,34 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
goto err_deinit_irq;
|
||||
}
|
||||
|
||||
bus_params.dev_type = ATH10K_DEV_TYPE_LL;
|
||||
bus_params.link_can_suspend = true;
|
||||
/* Read CHIP_ID before reset to catch QCA9880-AR1A v1 devices that
|
||||
* fall off the bus during chip_reset. These chips have the same pci
|
||||
* device id as the QCA9880 BR4A or 2R4E. So that's why the check.
|
||||
*/
|
||||
if (is_qca988x) {
|
||||
bus_params.chip_id =
|
||||
ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
|
||||
if (bus_params.chip_id != 0xffffffff) {
|
||||
if (!ath10k_pci_chip_is_supported(pdev->device,
|
||||
bus_params.chip_id))
|
||||
goto err_unsupported;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ath10k_pci_chip_reset(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to reset chip: %d\n", ret);
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
bus_params.dev_type = ATH10K_DEV_TYPE_LL;
|
||||
bus_params.link_can_suspend = true;
|
||||
bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
|
||||
if (bus_params.chip_id == 0xffffffff) {
|
||||
ath10k_err(ar, "failed to get chip id\n");
|
||||
goto err_free_irq;
|
||||
}
|
||||
if (bus_params.chip_id == 0xffffffff)
|
||||
goto err_unsupported;
|
||||
|
||||
if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) {
|
||||
ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
|
||||
pdev->device, bus_params.chip_id);
|
||||
if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id))
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
ret = ath10k_core_register(ar, &bus_params);
|
||||
if (ret) {
|
||||
@@ -3647,6 +3657,10 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
|
||||
return 0;
|
||||
|
||||
err_unsupported:
|
||||
ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
|
||||
pdev->device, bus_params.chip_id);
|
||||
|
||||
err_free_irq:
|
||||
ath10k_pci_free_irq(ar);
|
||||
ath10k_pci_rx_retry_sync(ar);
|
||||
|
||||
@@ -581,22 +581,29 @@ static int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi)
|
||||
{
|
||||
struct wlfw_host_cap_resp_msg_v01 resp = {};
|
||||
struct wlfw_host_cap_req_msg_v01 req = {};
|
||||
struct qmi_elem_info *req_ei;
|
||||
struct ath10k *ar = qmi->ar;
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
struct qmi_txn txn;
|
||||
int ret;
|
||||
|
||||
req.daemon_support_valid = 1;
|
||||
req.daemon_support = 0;
|
||||
|
||||
ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
|
||||
wlfw_host_cap_resp_msg_v01_ei, &resp);
|
||||
ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_host_cap_resp_msg_v01_ei,
|
||||
&resp);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (test_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags))
|
||||
req_ei = wlfw_host_cap_8bit_req_msg_v01_ei;
|
||||
else
|
||||
req_ei = wlfw_host_cap_req_msg_v01_ei;
|
||||
|
||||
ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
|
||||
QMI_WLFW_HOST_CAP_REQ_V01,
|
||||
WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN,
|
||||
wlfw_host_cap_req_msg_v01_ei, &req);
|
||||
req_ei, &req);
|
||||
if (ret < 0) {
|
||||
qmi_txn_cancel(&txn);
|
||||
ath10k_err(ar, "failed to send host capability request: %d\n", ret);
|
||||
|
||||
@@ -1988,6 +1988,28 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[] = {
|
||||
{
|
||||
.data_type = QMI_OPT_FLAG,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x10,
|
||||
.offset = offsetof(struct wlfw_host_cap_req_msg_v01,
|
||||
daemon_support_valid),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_UNSIGNED_1_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x10,
|
||||
.offset = offsetof(struct wlfw_host_cap_req_msg_v01,
|
||||
daemon_support),
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[] = {
|
||||
{
|
||||
.data_type = QMI_STRUCT,
|
||||
|
||||
@@ -575,6 +575,7 @@ struct wlfw_host_cap_req_msg_v01 {
|
||||
|
||||
#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 189
|
||||
extern struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[];
|
||||
extern struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_host_cap_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
|
||||
@@ -1261,6 +1261,15 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_snoc_quirks_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
struct device *dev = &ar_snoc->dev->dev;
|
||||
|
||||
if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk"))
|
||||
set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags);
|
||||
}
|
||||
|
||||
int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)
|
||||
{
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
@@ -1678,6 +1687,8 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
|
||||
ar->ce_priv = &ar_snoc->ce;
|
||||
msa_size = drv_data->msa_size;
|
||||
|
||||
ath10k_snoc_quirks_init(ar);
|
||||
|
||||
ret = ath10k_snoc_resource_init(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to initialize resource: %d\n", ret);
|
||||
|
||||
@@ -63,6 +63,7 @@ enum ath10k_snoc_flags {
|
||||
ATH10K_SNOC_FLAG_REGISTERED,
|
||||
ATH10K_SNOC_FLAG_UNREGISTERING,
|
||||
ATH10K_SNOC_FLAG_RECOVERY,
|
||||
ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK,
|
||||
};
|
||||
|
||||
struct ath10k_snoc {
|
||||
|
||||
@@ -38,6 +38,10 @@ ath10k_usb_alloc_urb_from_pipe(struct ath10k_usb_pipe *pipe)
|
||||
struct ath10k_urb_context *urb_context = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
/* bail if this pipe is not initialized */
|
||||
if (!pipe->ar_usb)
|
||||
return NULL;
|
||||
|
||||
spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
|
||||
if (!list_empty(&pipe->urb_list_head)) {
|
||||
urb_context = list_first_entry(&pipe->urb_list_head,
|
||||
@@ -55,6 +59,10 @@ static void ath10k_usb_free_urb_to_pipe(struct ath10k_usb_pipe *pipe,
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/* bail if this pipe is not initialized */
|
||||
if (!pipe->ar_usb)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
|
||||
|
||||
pipe->urb_cnt++;
|
||||
|
||||
@@ -4183,7 +4183,7 @@ static void ar9003_hw_thermometer_apply(struct ath_hw *ah)
|
||||
|
||||
static void ar9003_hw_thermo_cal_apply(struct ath_hw *ah)
|
||||
{
|
||||
u32 data, ko, kg;
|
||||
u32 data = 0, ko, kg;
|
||||
|
||||
if (!AR_SREV_9462_20_OR_LATER(ah))
|
||||
return;
|
||||
|
||||
@@ -65,7 +65,7 @@ struct bios_args {
|
||||
u32 command;
|
||||
u32 commandtype;
|
||||
u32 datasize;
|
||||
u32 data;
|
||||
u8 data[128];
|
||||
};
|
||||
|
||||
enum hp_wmi_commandtype {
|
||||
@@ -216,7 +216,7 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
|
||||
.command = command,
|
||||
.commandtype = query,
|
||||
.datasize = insize,
|
||||
.data = 0,
|
||||
.data = { 0 },
|
||||
};
|
||||
struct acpi_buffer input = { sizeof(struct bios_args), &args };
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
@@ -228,7 +228,7 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
|
||||
|
||||
if (WARN_ON(insize > sizeof(args.data)))
|
||||
return -EINVAL;
|
||||
memcpy(&args.data, buffer, insize);
|
||||
memcpy(&args.data[0], buffer, insize);
|
||||
|
||||
wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output);
|
||||
|
||||
@@ -380,7 +380,7 @@ static int hp_wmi_rfkill2_refresh(void)
|
||||
int err, i;
|
||||
|
||||
err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,
|
||||
0, sizeof(state));
|
||||
sizeof(state), sizeof(state));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -778,7 +778,7 @@ static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
|
||||
int err, i;
|
||||
|
||||
err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,
|
||||
0, sizeof(state));
|
||||
sizeof(state), sizeof(state));
|
||||
if (err)
|
||||
return err < 0 ? err : -EINVAL;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2004-2014 Bernd Porr, mail@berndporr.me.uk
|
||||
* Copyright (C) 2004-2019 Bernd Porr, mail@berndporr.me.uk
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -8,7 +8,7 @@
|
||||
* Description: University of Stirling USB DAQ & INCITE Technology Limited
|
||||
* Devices: [ITL] USB-DUX-FAST (usbduxfast)
|
||||
* Author: Bernd Porr <mail@berndporr.me.uk>
|
||||
* Updated: 10 Oct 2014
|
||||
* Updated: 16 Nov 2019
|
||||
* Status: stable
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*
|
||||
*
|
||||
* Revision history:
|
||||
* 1.0: Fixed a rounding error in usbduxfast_ai_cmdtest
|
||||
* 0.9: Dropping the first data packet which seems to be from the last transfer.
|
||||
* Buffer overflows in the FX2 are handed over to comedi.
|
||||
* 0.92: Dropping now 4 packets. The quad buffer has to be emptied.
|
||||
@@ -350,6 +351,7 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev,
|
||||
struct comedi_cmd *cmd)
|
||||
{
|
||||
int err = 0;
|
||||
int err2 = 0;
|
||||
unsigned int steps;
|
||||
unsigned int arg;
|
||||
|
||||
@@ -399,11 +401,16 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev,
|
||||
*/
|
||||
steps = (cmd->convert_arg * 30) / 1000;
|
||||
if (cmd->chanlist_len != 1)
|
||||
err |= comedi_check_trigger_arg_min(&steps,
|
||||
MIN_SAMPLING_PERIOD);
|
||||
err |= comedi_check_trigger_arg_max(&steps, MAX_SAMPLING_PERIOD);
|
||||
arg = (steps * 1000) / 30;
|
||||
err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
|
||||
err2 |= comedi_check_trigger_arg_min(&steps,
|
||||
MIN_SAMPLING_PERIOD);
|
||||
else
|
||||
err2 |= comedi_check_trigger_arg_min(&steps, 1);
|
||||
err2 |= comedi_check_trigger_arg_max(&steps, MAX_SAMPLING_PERIOD);
|
||||
if (err2) {
|
||||
err |= err2;
|
||||
arg = (steps * 1000) / 30;
|
||||
err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
|
||||
}
|
||||
|
||||
if (cmd->stop_src == TRIG_COUNT)
|
||||
err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
|
||||
|
||||
@@ -1616,14 +1616,15 @@ static void _rtl92e_hard_data_xmit(struct sk_buff *skb, struct net_device *dev,
|
||||
memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
|
||||
skb_push(skb, priv->rtllib->tx_headroom);
|
||||
ret = _rtl92e_tx(dev, skb);
|
||||
if (ret != 0)
|
||||
kfree_skb(skb);
|
||||
|
||||
if (queue_index != MGNT_QUEUE) {
|
||||
priv->rtllib->stats.tx_bytes += (skb->len -
|
||||
priv->rtllib->tx_headroom);
|
||||
priv->rtllib->stats.tx_packets++;
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static int _rtl92e_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
|
||||
@@ -18,18 +18,13 @@
|
||||
static const struct sdio_device_id sdio_ids[] =
|
||||
{
|
||||
{ SDIO_DEVICE(0x024c, 0x0523), },
|
||||
{ SDIO_DEVICE(0x024c, 0x0525), },
|
||||
{ SDIO_DEVICE(0x024c, 0x0623), },
|
||||
{ SDIO_DEVICE(0x024c, 0x0626), },
|
||||
{ SDIO_DEVICE(0x024c, 0xb723), },
|
||||
{ /* end: all zeroes */ },
|
||||
};
|
||||
static const struct acpi_device_id acpi_ids[] = {
|
||||
{"OBDA8723", 0x0000},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(sdio, sdio_ids);
|
||||
MODULE_DEVICE_TABLE(acpi, acpi_ids);
|
||||
|
||||
static int rtw_drv_init(struct sdio_func *func, const struct sdio_device_id *id);
|
||||
static void rtw_dev_remove(struct sdio_func *func);
|
||||
|
||||
@@ -477,16 +477,21 @@ void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
|
||||
memcpy(¶m->supp_rates[1], rates_ie + 2, rates_len);
|
||||
}
|
||||
|
||||
supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies->data,
|
||||
ies->len);
|
||||
if (supp_rates_ie) {
|
||||
if (supp_rates_ie[1] > (WILC_MAX_RATES_SUPPORTED - rates_len))
|
||||
param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED;
|
||||
else
|
||||
param->supp_rates[0] += supp_rates_ie[1];
|
||||
if (rates_len < WILC_MAX_RATES_SUPPORTED) {
|
||||
supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES,
|
||||
ies->data, ies->len);
|
||||
if (supp_rates_ie) {
|
||||
u8 ext_rates = supp_rates_ie[1];
|
||||
|
||||
memcpy(¶m->supp_rates[rates_len + 1], supp_rates_ie + 2,
|
||||
(param->supp_rates[0] - rates_len));
|
||||
if (ext_rates > (WILC_MAX_RATES_SUPPORTED - rates_len))
|
||||
param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED;
|
||||
else
|
||||
param->supp_rates[0] += ext_rates;
|
||||
|
||||
memcpy(¶m->supp_rates[rates_len + 1],
|
||||
supp_rates_ie + 2,
|
||||
(param->supp_rates[0] - rates_len));
|
||||
}
|
||||
}
|
||||
|
||||
ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len);
|
||||
|
||||
@@ -168,7 +168,7 @@ static int nvm_validate_and_write(struct tb_switch *sw)
|
||||
|
||||
static int nvm_authenticate_host(struct tb_switch *sw)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Root switch NVM upgrade requires that we disconnect the
|
||||
@@ -176,6 +176,8 @@ static int nvm_authenticate_host(struct tb_switch *sw)
|
||||
* already).
|
||||
*/
|
||||
if (!sw->safe_mode) {
|
||||
u32 status;
|
||||
|
||||
ret = tb_domain_disconnect_all_paths(sw->tb);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -184,7 +186,16 @@ static int nvm_authenticate_host(struct tb_switch *sw)
|
||||
* everything goes well so getting timeout is expected.
|
||||
*/
|
||||
ret = dma_port_flash_update_auth(sw->dma_port);
|
||||
return ret == -ETIMEDOUT ? 0 : ret;
|
||||
if (!ret || ret == -ETIMEDOUT)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Any error from update auth operation requires power
|
||||
* cycling of the host router.
|
||||
*/
|
||||
tb_sw_warn(sw, "failed to authenticate NVM, power cycling\n");
|
||||
if (dma_port_flash_update_auth_status(sw->dma_port, &status) > 0)
|
||||
nvm_set_auth_status(sw, status);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -192,7 +203,7 @@ static int nvm_authenticate_host(struct tb_switch *sw)
|
||||
* switch.
|
||||
*/
|
||||
dma_port_power_cycle(sw->dma_port);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nvm_authenticate_device(struct tb_switch *sw)
|
||||
@@ -200,8 +211,16 @@ static int nvm_authenticate_device(struct tb_switch *sw)
|
||||
int ret, retries = 10;
|
||||
|
||||
ret = dma_port_flash_update_auth(sw->dma_port);
|
||||
if (ret && ret != -ETIMEDOUT)
|
||||
switch (ret) {
|
||||
case 0:
|
||||
case -ETIMEDOUT:
|
||||
case -EACCES:
|
||||
case -EINVAL:
|
||||
/* Power cycle is required */
|
||||
break;
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Poll here for the authentication status. It takes some time
|
||||
@@ -1246,8 +1265,6 @@ static ssize_t nvm_authenticate_store(struct device *dev,
|
||||
*/
|
||||
nvm_authenticate_start(sw);
|
||||
ret = nvm_authenticate_host(sw);
|
||||
if (ret)
|
||||
nvm_authenticate_complete(sw);
|
||||
} else {
|
||||
ret = nvm_authenticate_device(sw);
|
||||
}
|
||||
@@ -1690,13 +1707,16 @@ static int tb_switch_add_dma_port(struct tb_switch *sw)
|
||||
int ret;
|
||||
|
||||
switch (sw->generation) {
|
||||
case 3:
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Only root switch can be upgraded */
|
||||
if (tb_route(sw))
|
||||
return 0;
|
||||
|
||||
/* fallthrough */
|
||||
case 3:
|
||||
ret = tb_switch_set_uuid(sw);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1720,6 +1740,19 @@ static int tb_switch_add_dma_port(struct tb_switch *sw)
|
||||
if (sw->no_nvm_upgrade)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If there is status already set then authentication failed
|
||||
* when the dma_port_flash_update_auth() returned. Power cycling
|
||||
* is not needed (it was done already) so only thing we do here
|
||||
* is to unblock runtime PM of the root port.
|
||||
*/
|
||||
nvm_get_auth_status(sw, &status);
|
||||
if (status) {
|
||||
if (!tb_route(sw))
|
||||
nvm_authenticate_complete(sw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check status of the previous flash authentication. If there
|
||||
* is one we need to power cycle the switch in any case to make
|
||||
@@ -1735,9 +1768,6 @@ static int tb_switch_add_dma_port(struct tb_switch *sw)
|
||||
|
||||
if (status) {
|
||||
tb_sw_info(sw, "switch flash authentication failed\n");
|
||||
ret = tb_switch_set_uuid(sw);
|
||||
if (ret)
|
||||
return ret;
|
||||
nvm_set_auth_status(sw, status);
|
||||
}
|
||||
|
||||
|
||||
@@ -524,7 +524,7 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
|
||||
greset |= GRSTCTL_CSFTRST;
|
||||
dwc2_writel(hsotg, greset, GRSTCTL);
|
||||
|
||||
if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 50)) {
|
||||
if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 10000)) {
|
||||
dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n",
|
||||
__func__);
|
||||
return -EBUSY;
|
||||
|
||||
@@ -164,7 +164,12 @@ static int appledisplay_bl_get_brightness(struct backlight_device *bd)
|
||||
0,
|
||||
pdata->msgdata, 2,
|
||||
ACD_USB_TIMEOUT);
|
||||
brightness = pdata->msgdata[1];
|
||||
if (retval < 2) {
|
||||
if (retval >= 0)
|
||||
retval = -EMSGSIZE;
|
||||
} else {
|
||||
brightness = pdata->msgdata[1];
|
||||
}
|
||||
mutex_unlock(&pdata->sysfslock);
|
||||
|
||||
if (retval < 0)
|
||||
@@ -299,6 +304,7 @@ error:
|
||||
if (pdata) {
|
||||
if (pdata->urb) {
|
||||
usb_kill_urb(pdata->urb);
|
||||
cancel_delayed_work_sync(&pdata->work);
|
||||
if (pdata->urbdata)
|
||||
usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN,
|
||||
pdata->urbdata, pdata->urb->transfer_dma);
|
||||
|
||||
@@ -384,13 +384,17 @@ static int _chaoskey_fill(struct chaoskey *dev)
|
||||
!dev->reading,
|
||||
(started ? NAK_TIMEOUT : ALEA_FIRST_TIMEOUT) );
|
||||
|
||||
if (result < 0)
|
||||
if (result < 0) {
|
||||
usb_kill_urb(dev->urb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
if (result == 0) {
|
||||
result = -ETIMEDOUT;
|
||||
else
|
||||
usb_kill_urb(dev->urb);
|
||||
} else {
|
||||
result = dev->valid;
|
||||
}
|
||||
out:
|
||||
/* Let the device go back to sleep eventually */
|
||||
usb_autopm_put_interface(dev->interface);
|
||||
@@ -526,7 +530,21 @@ static int chaoskey_suspend(struct usb_interface *interface,
|
||||
|
||||
static int chaoskey_resume(struct usb_interface *interface)
|
||||
{
|
||||
struct chaoskey *dev;
|
||||
struct usb_device *udev = interface_to_usbdev(interface);
|
||||
|
||||
usb_dbg(interface, "resume");
|
||||
dev = usb_get_intfdata(interface);
|
||||
|
||||
/*
|
||||
* We may have lost power.
|
||||
* In that case the device that needs a long time
|
||||
* for the first requests needs an extended timeout
|
||||
* again
|
||||
*/
|
||||
if (le16_to_cpu(udev->descriptor.idVendor) == ALEA_VENDOR_ID)
|
||||
dev->reads_started = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -125,6 +125,7 @@ static const struct usb_device_id id_table[] = {
|
||||
{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
|
||||
{ USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
|
||||
{ USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
|
||||
{ USB_DEVICE(0x10C4, 0x83AA) }, /* Mark-10 Digital Force Gauge */
|
||||
{ USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */
|
||||
{ USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */
|
||||
{ USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */
|
||||
|
||||
@@ -1033,6 +1033,9 @@ static const struct usb_device_id id_table_combined[] = {
|
||||
/* Sienna devices */
|
||||
{ USB_DEVICE(FTDI_VID, FTDI_SIENNA_PID) },
|
||||
{ USB_DEVICE(ECHELON_VID, ECHELON_U20_PID) },
|
||||
/* U-Blox devices */
|
||||
{ USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ZED_PID) },
|
||||
{ USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ODIN_PID) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
|
||||
@@ -1558,3 +1558,10 @@
|
||||
*/
|
||||
#define UNJO_VID 0x22B7
|
||||
#define UNJO_ISODEBUG_V1_PID 0x150D
|
||||
|
||||
/*
|
||||
* U-Blox products (http://www.u-blox.com).
|
||||
*/
|
||||
#define UBLOX_VID 0x1546
|
||||
#define UBLOX_C099F9P_ZED_PID 0x0502
|
||||
#define UBLOX_C099F9P_ODIN_PID 0x0503
|
||||
|
||||
@@ -1833,10 +1833,6 @@ static int mos7720_startup(struct usb_serial *serial)
|
||||
product = le16_to_cpu(serial->dev->descriptor.idProduct);
|
||||
dev = serial->dev;
|
||||
|
||||
/* setting configuration feature to one */
|
||||
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
|
||||
(__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000);
|
||||
|
||||
if (product == MOSCHIP_DEVICE_ID_7715) {
|
||||
struct urb *urb = serial->port[0]->interrupt_in_urb;
|
||||
|
||||
|
||||
@@ -119,11 +119,15 @@
|
||||
/* This driver also supports
|
||||
* ATEN UC2324 device using Moschip MCS7840
|
||||
* ATEN UC2322 device using Moschip MCS7820
|
||||
* MOXA UPort 2210 device using Moschip MCS7820
|
||||
*/
|
||||
#define USB_VENDOR_ID_ATENINTL 0x0557
|
||||
#define ATENINTL_DEVICE_ID_UC2324 0x2011
|
||||
#define ATENINTL_DEVICE_ID_UC2322 0x7820
|
||||
|
||||
#define USB_VENDOR_ID_MOXA 0x110a
|
||||
#define MOXA_DEVICE_ID_2210 0x2210
|
||||
|
||||
/* Interrupt Routine Defines */
|
||||
|
||||
#define SERIAL_IIR_RLS 0x06
|
||||
@@ -195,6 +199,7 @@ static const struct usb_device_id id_table[] = {
|
||||
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)},
|
||||
{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
|
||||
{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
|
||||
{USB_DEVICE(USB_VENDOR_ID_MOXA, MOXA_DEVICE_ID_2210)},
|
||||
{} /* terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
@@ -2020,6 +2025,7 @@ static int mos7840_probe(struct usb_serial *serial,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
|
||||
u16 vid = le16_to_cpu(serial->dev->descriptor.idVendor);
|
||||
u8 *buf;
|
||||
int device_type;
|
||||
|
||||
@@ -2030,6 +2036,11 @@ static int mos7840_probe(struct usb_serial *serial,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (vid == USB_VENDOR_ID_MOXA && product == MOXA_DEVICE_ID_2210) {
|
||||
device_type = MOSCHIP_DEVICE_ID_7820;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
@@ -2279,11 +2290,6 @@ out:
|
||||
goto error;
|
||||
} else
|
||||
dev_dbg(&port->dev, "ZLP_REG5 Writing success status%d\n", status);
|
||||
|
||||
/* setting configuration feature to one */
|
||||
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
|
||||
0x03, 0x00, 0x01, 0x00, NULL, 0x00,
|
||||
MOS_WDR_TIMEOUT);
|
||||
}
|
||||
return 0;
|
||||
error:
|
||||
|
||||
@@ -197,6 +197,7 @@ static void option_instat_callback(struct urb *urb);
|
||||
#define DELL_PRODUCT_5804_MINICARD_ATT 0x819b /* Novatel E371 */
|
||||
|
||||
#define DELL_PRODUCT_5821E 0x81d7
|
||||
#define DELL_PRODUCT_5821E_ESIM 0x81e0
|
||||
|
||||
#define KYOCERA_VENDOR_ID 0x0c88
|
||||
#define KYOCERA_PRODUCT_KPC650 0x17da
|
||||
@@ -1044,6 +1045,8 @@ static const struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5804_MINICARD_ATT, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E),
|
||||
.driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
|
||||
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E_ESIM),
|
||||
.driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
|
||||
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */
|
||||
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
|
||||
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
|
||||
@@ -1990,6 +1993,10 @@ static const struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x13) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x14) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x1b) },
|
||||
{ USB_DEVICE(0x0489, 0xe0b4), /* Foxconn T77W968 */
|
||||
.driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
|
||||
{ USB_DEVICE(0x0489, 0xe0b5), /* Foxconn T77W968 ESIM */
|
||||
.driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
|
||||
{ USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 */
|
||||
.driver_info = RSVD(4) | RSVD(5) | RSVD(6) },
|
||||
{ USB_DEVICE(0x2cb7, 0x0104), /* Fibocom NL678 series */
|
||||
|
||||
@@ -4,6 +4,7 @@ config USBIP_CORE
|
||||
tristate "USB/IP support"
|
||||
depends on NET
|
||||
select USB_COMMON
|
||||
select SGL_ALLOC
|
||||
---help---
|
||||
This enables pushing USB packets over IP to allow remote
|
||||
machines direct access to USB devices. It provides the
|
||||
|
||||
+32
-18
@@ -470,18 +470,50 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,
|
||||
if (pipe == -1)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Smatch reported the error case where use_sg is true and buf_len is 0.
|
||||
* In this case, It adds SDEV_EVENT_ERROR_MALLOC and stub_priv will be
|
||||
* released by stub event handler and connection will be shut down.
|
||||
*/
|
||||
priv = stub_priv_alloc(sdev, pdu);
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
buf_len = (unsigned long long)pdu->u.cmd_submit.transfer_buffer_length;
|
||||
|
||||
if (use_sg && !buf_len) {
|
||||
dev_err(&udev->dev, "sg buffer with zero length\n");
|
||||
goto err_malloc;
|
||||
}
|
||||
|
||||
/* allocate urb transfer buffer, if needed */
|
||||
if (buf_len) {
|
||||
if (use_sg) {
|
||||
sgl = sgl_alloc(buf_len, GFP_KERNEL, &nents);
|
||||
if (!sgl)
|
||||
goto err_malloc;
|
||||
|
||||
/* Check if the server's HCD supports SG */
|
||||
if (!udev->bus->sg_tablesize) {
|
||||
/*
|
||||
* If the server's HCD doesn't support SG, break
|
||||
* a single SG request into several URBs and map
|
||||
* each SG list entry to corresponding URB
|
||||
* buffer. The previously allocated SG list is
|
||||
* stored in priv->sgl (If the server's HCD
|
||||
* support SG, SG list is stored only in
|
||||
* urb->sg) and it is used as an indicator that
|
||||
* the server split single SG request into
|
||||
* several URBs. Later, priv->sgl is used by
|
||||
* stub_complete() and stub_send_ret_submit() to
|
||||
* reassemble the divied URBs.
|
||||
*/
|
||||
support_sg = 0;
|
||||
num_urbs = nents;
|
||||
priv->completed_urbs = 0;
|
||||
pdu->u.cmd_submit.transfer_flags &=
|
||||
~URB_DMA_MAP_SG;
|
||||
}
|
||||
} else {
|
||||
buffer = kzalloc(buf_len, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
@@ -489,24 +521,6 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the server's HCD supports SG */
|
||||
if (use_sg && !udev->bus->sg_tablesize) {
|
||||
/*
|
||||
* If the server's HCD doesn't support SG, break a single SG
|
||||
* request into several URBs and map each SG list entry to
|
||||
* corresponding URB buffer. The previously allocated SG
|
||||
* list is stored in priv->sgl (If the server's HCD support SG,
|
||||
* SG list is stored only in urb->sg) and it is used as an
|
||||
* indicator that the server split single SG request into
|
||||
* several URBs. Later, priv->sgl is used by stub_complete() and
|
||||
* stub_send_ret_submit() to reassemble the divied URBs.
|
||||
*/
|
||||
support_sg = 0;
|
||||
num_urbs = nents;
|
||||
priv->completed_urbs = 0;
|
||||
pdu->u.cmd_submit.transfer_flags &= ~URB_DMA_MAP_SG;
|
||||
}
|
||||
|
||||
/* allocate urb array */
|
||||
priv->num_urbs = num_urbs;
|
||||
priv->urbs = kmalloc_array(num_urbs, sizeof(*priv->urbs), GFP_KERNEL);
|
||||
|
||||
@@ -1015,7 +1015,7 @@ static int exec_mmap(struct mm_struct *mm)
|
||||
/* Notify parent that we're no longer interested in the old VM */
|
||||
tsk = current;
|
||||
old_mm = current->mm;
|
||||
mm_release(tsk, old_mm);
|
||||
exec_mm_release(tsk, old_mm);
|
||||
|
||||
if (old_mm) {
|
||||
sync_mm_rss(old_mm);
|
||||
|
||||
@@ -5912,8 +5912,23 @@ static int __ext4_expand_extra_isize(struct inode *inode,
|
||||
{
|
||||
struct ext4_inode *raw_inode;
|
||||
struct ext4_xattr_ibody_header *header;
|
||||
unsigned int inode_size = EXT4_INODE_SIZE(inode->i_sb);
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
int error;
|
||||
|
||||
/* this was checked at iget time, but double check for good measure */
|
||||
if ((EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > inode_size) ||
|
||||
(ei->i_extra_isize & 3)) {
|
||||
EXT4_ERROR_INODE(inode, "bad extra_isize %u (inode size %u)",
|
||||
ei->i_extra_isize,
|
||||
EXT4_INODE_SIZE(inode->i_sb));
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
if ((new_extra_isize < ei->i_extra_isize) ||
|
||||
(new_extra_isize < 4) ||
|
||||
(new_extra_isize > inode_size - EXT4_GOOD_OLD_INODE_SIZE))
|
||||
return -EINVAL; /* Should never happen */
|
||||
|
||||
raw_inode = ext4_raw_inode(iloc);
|
||||
|
||||
header = IHDR(inode, raw_inode);
|
||||
|
||||
+12
-9
@@ -3555,12 +3555,15 @@ static void ext4_clamp_want_extra_isize(struct super_block *sb)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
struct ext4_super_block *es = sbi->s_es;
|
||||
unsigned def_extra_isize = sizeof(struct ext4_inode) -
|
||||
EXT4_GOOD_OLD_INODE_SIZE;
|
||||
|
||||
/* determine the minimum size of new large inodes, if present */
|
||||
if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE &&
|
||||
sbi->s_want_extra_isize == 0) {
|
||||
sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
|
||||
EXT4_GOOD_OLD_INODE_SIZE;
|
||||
if (sbi->s_inode_size == EXT4_GOOD_OLD_INODE_SIZE) {
|
||||
sbi->s_want_extra_isize = 0;
|
||||
return;
|
||||
}
|
||||
if (sbi->s_want_extra_isize < 4) {
|
||||
sbi->s_want_extra_isize = def_extra_isize;
|
||||
if (ext4_has_feature_extra_isize(sb)) {
|
||||
if (sbi->s_want_extra_isize <
|
||||
le16_to_cpu(es->s_want_extra_isize))
|
||||
@@ -3573,10 +3576,10 @@ static void ext4_clamp_want_extra_isize(struct super_block *sb)
|
||||
}
|
||||
}
|
||||
/* Check if enough inode space is available */
|
||||
if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
|
||||
sbi->s_inode_size) {
|
||||
sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
|
||||
EXT4_GOOD_OLD_INODE_SIZE;
|
||||
if ((sbi->s_want_extra_isize > sbi->s_inode_size) ||
|
||||
(EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
|
||||
sbi->s_inode_size)) {
|
||||
sbi->s_want_extra_isize = def_extra_isize;
|
||||
ext4_msg(sb, KERN_INFO,
|
||||
"required extra inode space not available");
|
||||
}
|
||||
|
||||
+22
-1
@@ -238,6 +238,8 @@ struct io_ring_ctx {
|
||||
|
||||
struct user_struct *user;
|
||||
|
||||
struct cred *creds;
|
||||
|
||||
struct completion ctx_done;
|
||||
|
||||
struct {
|
||||
@@ -1752,8 +1754,11 @@ static void io_poll_complete_work(struct work_struct *work)
|
||||
struct io_poll_iocb *poll = &req->poll;
|
||||
struct poll_table_struct pt = { ._key = poll->events };
|
||||
struct io_ring_ctx *ctx = req->ctx;
|
||||
const struct cred *old_cred;
|
||||
__poll_t mask = 0;
|
||||
|
||||
old_cred = override_creds(ctx->creds);
|
||||
|
||||
if (!READ_ONCE(poll->canceled))
|
||||
mask = vfs_poll(poll->file, &pt) & poll->events;
|
||||
|
||||
@@ -1768,7 +1773,7 @@ static void io_poll_complete_work(struct work_struct *work)
|
||||
if (!mask && !READ_ONCE(poll->canceled)) {
|
||||
add_wait_queue(poll->head, &poll->wait);
|
||||
spin_unlock_irq(&ctx->completion_lock);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
list_del_init(&req->list);
|
||||
io_poll_complete(ctx, req, mask);
|
||||
@@ -1776,6 +1781,8 @@ static void io_poll_complete_work(struct work_struct *work)
|
||||
|
||||
io_cqring_ev_posted(ctx);
|
||||
io_put_req(req);
|
||||
out:
|
||||
revert_creds(old_cred);
|
||||
}
|
||||
|
||||
static int io_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
|
||||
@@ -2147,10 +2154,12 @@ static void io_sq_wq_submit_work(struct work_struct *work)
|
||||
struct io_ring_ctx *ctx = req->ctx;
|
||||
struct mm_struct *cur_mm = NULL;
|
||||
struct async_list *async_list;
|
||||
const struct cred *old_cred;
|
||||
LIST_HEAD(req_list);
|
||||
mm_segment_t old_fs;
|
||||
int ret;
|
||||
|
||||
old_cred = override_creds(ctx->creds);
|
||||
async_list = io_async_list_from_sqe(ctx, req->submit.sqe);
|
||||
restart:
|
||||
do {
|
||||
@@ -2258,6 +2267,7 @@ out:
|
||||
unuse_mm(cur_mm);
|
||||
mmput(cur_mm);
|
||||
}
|
||||
revert_creds(old_cred);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2663,6 +2673,7 @@ static int io_sq_thread(void *data)
|
||||
{
|
||||
struct io_ring_ctx *ctx = data;
|
||||
struct mm_struct *cur_mm = NULL;
|
||||
const struct cred *old_cred;
|
||||
mm_segment_t old_fs;
|
||||
DEFINE_WAIT(wait);
|
||||
unsigned inflight;
|
||||
@@ -2672,6 +2683,7 @@ static int io_sq_thread(void *data)
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(USER_DS);
|
||||
old_cred = override_creds(ctx->creds);
|
||||
|
||||
timeout = inflight = 0;
|
||||
while (!kthread_should_park()) {
|
||||
@@ -2782,6 +2794,7 @@ static int io_sq_thread(void *data)
|
||||
unuse_mm(cur_mm);
|
||||
mmput(cur_mm);
|
||||
}
|
||||
revert_creds(old_cred);
|
||||
|
||||
kthread_parkme();
|
||||
|
||||
@@ -3567,6 +3580,8 @@ static void io_ring_ctx_free(struct io_ring_ctx *ctx)
|
||||
io_unaccount_mem(ctx->user,
|
||||
ring_pages(ctx->sq_entries, ctx->cq_entries));
|
||||
free_uid(ctx->user);
|
||||
if (ctx->creds)
|
||||
put_cred(ctx->creds);
|
||||
kfree(ctx);
|
||||
}
|
||||
|
||||
@@ -3838,6 +3853,12 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p)
|
||||
ctx->account_mem = account_mem;
|
||||
ctx->user = user;
|
||||
|
||||
ctx->creds = prepare_creds();
|
||||
if (!ctx->creds) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = io_allocate_scq_urings(ctx, p);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
+1
-1
@@ -226,7 +226,7 @@ static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *r
|
||||
lastend = this->ofs + this->size;
|
||||
} else {
|
||||
dbg_fragtree2("lookup gave no frag\n");
|
||||
return -EINVAL;
|
||||
lastend = 0;
|
||||
}
|
||||
|
||||
/* See if we ran off the end of the fragtree */
|
||||
|
||||
@@ -410,8 +410,6 @@ struct compat_kexec_segment;
|
||||
struct compat_mq_attr;
|
||||
struct compat_msgbuf;
|
||||
|
||||
extern void compat_exit_robust_list(struct task_struct *curr);
|
||||
|
||||
#define BITS_PER_COMPAT_LONG (8*sizeof(compat_long_t))
|
||||
|
||||
#define BITS_TO_COMPAT_LONGS(bits) DIV_ROUND_UP(bits, BITS_PER_COMPAT_LONG)
|
||||
|
||||
+27
-13
@@ -2,7 +2,9 @@
|
||||
#ifndef _LINUX_FUTEX_H
|
||||
#define _LINUX_FUTEX_H
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ktime.h>
|
||||
|
||||
#include <uapi/linux/futex.h>
|
||||
|
||||
struct inode;
|
||||
@@ -48,15 +50,35 @@ union futex_key {
|
||||
#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = NULL } }
|
||||
|
||||
#ifdef CONFIG_FUTEX
|
||||
extern void exit_robust_list(struct task_struct *curr);
|
||||
enum {
|
||||
FUTEX_STATE_OK,
|
||||
FUTEX_STATE_EXITING,
|
||||
FUTEX_STATE_DEAD,
|
||||
};
|
||||
|
||||
static inline void futex_init_task(struct task_struct *tsk)
|
||||
{
|
||||
tsk->robust_list = NULL;
|
||||
#ifdef CONFIG_COMPAT
|
||||
tsk->compat_robust_list = NULL;
|
||||
#endif
|
||||
INIT_LIST_HEAD(&tsk->pi_state_list);
|
||||
tsk->pi_state_cache = NULL;
|
||||
tsk->futex_state = FUTEX_STATE_OK;
|
||||
mutex_init(&tsk->futex_exit_mutex);
|
||||
}
|
||||
|
||||
void futex_exit_recursive(struct task_struct *tsk);
|
||||
void futex_exit_release(struct task_struct *tsk);
|
||||
void futex_exec_release(struct task_struct *tsk);
|
||||
|
||||
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
|
||||
u32 __user *uaddr2, u32 val2, u32 val3);
|
||||
#else
|
||||
static inline void exit_robust_list(struct task_struct *curr)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void futex_init_task(struct task_struct *tsk) { }
|
||||
static inline void futex_exit_recursive(struct task_struct *tsk) { }
|
||||
static inline void futex_exit_release(struct task_struct *tsk) { }
|
||||
static inline void futex_exec_release(struct task_struct *tsk) { }
|
||||
static inline long do_futex(u32 __user *uaddr, int op, u32 val,
|
||||
ktime_t *timeout, u32 __user *uaddr2,
|
||||
u32 val2, u32 val3)
|
||||
@@ -65,12 +87,4 @@ static inline long do_futex(u32 __user *uaddr, int op, u32 val,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FUTEX_PI
|
||||
extern void exit_pi_state_list(struct task_struct *curr);
|
||||
#else
|
||||
static inline void exit_pi_state_list(struct task_struct *curr)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1054,6 +1054,8 @@ struct task_struct {
|
||||
#endif
|
||||
struct list_head pi_state_list;
|
||||
struct futex_pi_state *pi_state_cache;
|
||||
struct mutex futex_exit_mutex;
|
||||
unsigned int futex_state;
|
||||
#endif
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
struct perf_event_context *perf_event_ctxp[perf_nr_task_contexts];
|
||||
@@ -1442,7 +1444,6 @@ extern struct pid *cad_pid;
|
||||
*/
|
||||
#define PF_IDLE 0x00000002 /* I am an IDLE thread */
|
||||
#define PF_EXITING 0x00000004 /* Getting shut down */
|
||||
#define PF_EXITPIDONE 0x00000008 /* PI exit done on shut down */
|
||||
#define PF_VCPU 0x00000010 /* I'm a virtual CPU */
|
||||
#define PF_WQ_WORKER 0x00000020 /* I'm a workqueue worker */
|
||||
#define PF_FORKNOEXEC 0x00000040 /* Forked but didn't exec */
|
||||
|
||||
@@ -117,8 +117,10 @@ extern struct mm_struct *get_task_mm(struct task_struct *task);
|
||||
* succeeds.
|
||||
*/
|
||||
extern struct mm_struct *mm_access(struct task_struct *task, unsigned int mode);
|
||||
/* Remove the current tasks stale references to the old mm_struct */
|
||||
extern void mm_release(struct task_struct *, struct mm_struct *);
|
||||
/* Remove the current tasks stale references to the old mm_struct on exit() */
|
||||
extern void exit_mm_release(struct task_struct *, struct mm_struct *);
|
||||
/* Remove the current tasks stale references to the old mm_struct on exec() */
|
||||
extern void exec_mm_release(struct task_struct *, struct mm_struct *);
|
||||
|
||||
#ifdef CONFIG_MEMCG
|
||||
extern void mm_update_next_owner(struct mm_struct *mm);
|
||||
|
||||
+13
-13
@@ -14,6 +14,7 @@
|
||||
#include <net/strparser.h>
|
||||
|
||||
#define MAX_MSG_FRAGS MAX_SKB_FRAGS
|
||||
#define NR_MSG_FRAG_IDS (MAX_MSG_FRAGS + 1)
|
||||
|
||||
enum __sk_action {
|
||||
__SK_DROP = 0,
|
||||
@@ -29,11 +30,13 @@ struct sk_msg_sg {
|
||||
u32 size;
|
||||
u32 copybreak;
|
||||
bool copy[MAX_MSG_FRAGS];
|
||||
/* The extra element is used for chaining the front and sections when
|
||||
* the list becomes partitioned (e.g. end < start). The crypto APIs
|
||||
* require the chaining.
|
||||
/* The extra two elements:
|
||||
* 1) used for chaining the front and sections when the list becomes
|
||||
* partitioned (e.g. end < start). The crypto APIs require the
|
||||
* chaining;
|
||||
* 2) to chain tailer SG entries after the message.
|
||||
*/
|
||||
struct scatterlist data[MAX_MSG_FRAGS + 1];
|
||||
struct scatterlist data[MAX_MSG_FRAGS + 2];
|
||||
};
|
||||
|
||||
/* UAPI in filter.c depends on struct sk_msg_sg being first element. */
|
||||
@@ -141,13 +144,13 @@ static inline void sk_msg_apply_bytes(struct sk_psock *psock, u32 bytes)
|
||||
|
||||
static inline u32 sk_msg_iter_dist(u32 start, u32 end)
|
||||
{
|
||||
return end >= start ? end - start : end + (MAX_MSG_FRAGS - start);
|
||||
return end >= start ? end - start : end + (NR_MSG_FRAG_IDS - start);
|
||||
}
|
||||
|
||||
#define sk_msg_iter_var_prev(var) \
|
||||
do { \
|
||||
if (var == 0) \
|
||||
var = MAX_MSG_FRAGS - 1; \
|
||||
var = NR_MSG_FRAG_IDS - 1; \
|
||||
else \
|
||||
var--; \
|
||||
} while (0)
|
||||
@@ -155,7 +158,7 @@ static inline u32 sk_msg_iter_dist(u32 start, u32 end)
|
||||
#define sk_msg_iter_var_next(var) \
|
||||
do { \
|
||||
var++; \
|
||||
if (var == MAX_MSG_FRAGS) \
|
||||
if (var == NR_MSG_FRAG_IDS) \
|
||||
var = 0; \
|
||||
} while (0)
|
||||
|
||||
@@ -172,9 +175,9 @@ static inline void sk_msg_clear_meta(struct sk_msg *msg)
|
||||
|
||||
static inline void sk_msg_init(struct sk_msg *msg)
|
||||
{
|
||||
BUILD_BUG_ON(ARRAY_SIZE(msg->sg.data) - 1 != MAX_MSG_FRAGS);
|
||||
BUILD_BUG_ON(ARRAY_SIZE(msg->sg.data) - 1 != NR_MSG_FRAG_IDS);
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
sg_init_marker(msg->sg.data, MAX_MSG_FRAGS);
|
||||
sg_init_marker(msg->sg.data, NR_MSG_FRAG_IDS);
|
||||
}
|
||||
|
||||
static inline void sk_msg_xfer(struct sk_msg *dst, struct sk_msg *src,
|
||||
@@ -195,14 +198,11 @@ static inline void sk_msg_xfer_full(struct sk_msg *dst, struct sk_msg *src)
|
||||
|
||||
static inline bool sk_msg_full(const struct sk_msg *msg)
|
||||
{
|
||||
return (msg->sg.end == msg->sg.start) && msg->sg.size;
|
||||
return sk_msg_iter_dist(msg->sg.start, msg->sg.end) == MAX_MSG_FRAGS;
|
||||
}
|
||||
|
||||
static inline u32 sk_msg_elem_used(const struct sk_msg *msg)
|
||||
{
|
||||
if (sk_msg_full(msg))
|
||||
return MAX_MSG_FRAGS;
|
||||
|
||||
return sk_msg_iter_dist(msg->sg.start, msg->sg.end);
|
||||
}
|
||||
|
||||
|
||||
@@ -1239,6 +1239,9 @@ struct sctp_ep_common {
|
||||
/* What socket does this endpoint belong to? */
|
||||
struct sock *sk;
|
||||
|
||||
/* Cache netns and it won't change once set */
|
||||
struct net *net;
|
||||
|
||||
/* This is where we receive inbound chunks. */
|
||||
struct sctp_inq inqueue;
|
||||
|
||||
|
||||
+1
-2
@@ -122,7 +122,6 @@ struct tls_rec {
|
||||
struct list_head list;
|
||||
int tx_ready;
|
||||
int tx_flags;
|
||||
int inplace_crypto;
|
||||
|
||||
struct sk_msg msg_plaintext;
|
||||
struct sk_msg msg_encrypted;
|
||||
@@ -396,7 +395,7 @@ int tls_push_sg(struct sock *sk, struct tls_context *ctx,
|
||||
int flags);
|
||||
int tls_push_partial_record(struct sock *sk, struct tls_context *ctx,
|
||||
int flags);
|
||||
bool tls_free_partial_record(struct sock *sk, struct tls_context *ctx);
|
||||
void tls_free_partial_record(struct sock *sk, struct tls_context *ctx);
|
||||
|
||||
static inline struct tls_msg *tls_msg(struct sk_buff *skb)
|
||||
{
|
||||
|
||||
+2
-28
@@ -437,7 +437,7 @@ static void exit_mm(void)
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct core_state *core_state;
|
||||
|
||||
mm_release(current, mm);
|
||||
exit_mm_release(current, mm);
|
||||
if (!mm)
|
||||
return;
|
||||
sync_mm_rss(mm);
|
||||
@@ -746,32 +746,12 @@ void __noreturn do_exit(long code)
|
||||
*/
|
||||
if (unlikely(tsk->flags & PF_EXITING)) {
|
||||
pr_alert("Fixing recursive fault but reboot is needed!\n");
|
||||
/*
|
||||
* We can do this unlocked here. The futex code uses
|
||||
* this flag just to verify whether the pi state
|
||||
* cleanup has been done or not. In the worst case it
|
||||
* loops once more. We pretend that the cleanup was
|
||||
* done as there is no way to return. Either the
|
||||
* OWNER_DIED bit is set by now or we push the blocked
|
||||
* task into the wait for ever nirwana as well.
|
||||
*/
|
||||
tsk->flags |= PF_EXITPIDONE;
|
||||
futex_exit_recursive(tsk);
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule();
|
||||
}
|
||||
|
||||
exit_signals(tsk); /* sets PF_EXITING */
|
||||
/*
|
||||
* Ensure that all new tsk->pi_lock acquisitions must observe
|
||||
* PF_EXITING. Serializes against futex.c:attach_to_pi_owner().
|
||||
*/
|
||||
smp_mb();
|
||||
/*
|
||||
* Ensure that we must observe the pi_state in exit_mm() ->
|
||||
* mm_release() -> exit_pi_state_list().
|
||||
*/
|
||||
raw_spin_lock_irq(&tsk->pi_lock);
|
||||
raw_spin_unlock_irq(&tsk->pi_lock);
|
||||
|
||||
if (unlikely(in_atomic())) {
|
||||
pr_info("note: %s[%d] exited with preempt_count %d\n",
|
||||
@@ -846,12 +826,6 @@ void __noreturn do_exit(long code)
|
||||
* Make sure we are holding no locks:
|
||||
*/
|
||||
debug_check_no_locks_held();
|
||||
/*
|
||||
* We can do this unlocked here. The futex code uses this flag
|
||||
* just to verify whether the pi state cleanup has been done
|
||||
* or not. In the worst case it loops once more.
|
||||
*/
|
||||
tsk->flags |= PF_EXITPIDONE;
|
||||
|
||||
if (tsk->io_context)
|
||||
exit_io_context(tsk);
|
||||
|
||||
+15
-25
@@ -1283,24 +1283,8 @@ static int wait_for_vfork_done(struct task_struct *child,
|
||||
* restoring the old one. . .
|
||||
* Eric Biederman 10 January 1998
|
||||
*/
|
||||
void mm_release(struct task_struct *tsk, struct mm_struct *mm)
|
||||
static void mm_release(struct task_struct *tsk, struct mm_struct *mm)
|
||||
{
|
||||
/* Get rid of any futexes when releasing the mm */
|
||||
#ifdef CONFIG_FUTEX
|
||||
if (unlikely(tsk->robust_list)) {
|
||||
exit_robust_list(tsk);
|
||||
tsk->robust_list = NULL;
|
||||
}
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (unlikely(tsk->compat_robust_list)) {
|
||||
compat_exit_robust_list(tsk);
|
||||
tsk->compat_robust_list = NULL;
|
||||
}
|
||||
#endif
|
||||
if (unlikely(!list_empty(&tsk->pi_state_list)))
|
||||
exit_pi_state_list(tsk);
|
||||
#endif
|
||||
|
||||
uprobe_free_utask(tsk);
|
||||
|
||||
/* Get rid of any cached register state */
|
||||
@@ -1333,6 +1317,18 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)
|
||||
complete_vfork_done(tsk);
|
||||
}
|
||||
|
||||
void exit_mm_release(struct task_struct *tsk, struct mm_struct *mm)
|
||||
{
|
||||
futex_exit_release(tsk);
|
||||
mm_release(tsk, mm);
|
||||
}
|
||||
|
||||
void exec_mm_release(struct task_struct *tsk, struct mm_struct *mm)
|
||||
{
|
||||
futex_exec_release(tsk);
|
||||
mm_release(tsk, mm);
|
||||
}
|
||||
|
||||
/**
|
||||
* dup_mm() - duplicates an existing mm structure
|
||||
* @tsk: the task_struct with which the new mm will be associated.
|
||||
@@ -2062,14 +2058,8 @@ static __latent_entropy struct task_struct *copy_process(
|
||||
#ifdef CONFIG_BLOCK
|
||||
p->plug = NULL;
|
||||
#endif
|
||||
#ifdef CONFIG_FUTEX
|
||||
p->robust_list = NULL;
|
||||
#ifdef CONFIG_COMPAT
|
||||
p->compat_robust_list = NULL;
|
||||
#endif
|
||||
INIT_LIST_HEAD(&p->pi_state_list);
|
||||
p->pi_state_cache = NULL;
|
||||
#endif
|
||||
futex_init_task(p);
|
||||
|
||||
/*
|
||||
* sigaltstack should be cleared when sharing the same VM
|
||||
*/
|
||||
|
||||
+281
-43
@@ -325,6 +325,12 @@ static inline bool should_fail_futex(bool fshared)
|
||||
}
|
||||
#endif /* CONFIG_FAIL_FUTEX */
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static void compat_exit_robust_list(struct task_struct *curr);
|
||||
#else
|
||||
static inline void compat_exit_robust_list(struct task_struct *curr) { }
|
||||
#endif
|
||||
|
||||
static inline void futex_get_mm(union futex_key *key)
|
||||
{
|
||||
mmgrab(key->private.mm);
|
||||
@@ -890,7 +896,7 @@ static void put_pi_state(struct futex_pi_state *pi_state)
|
||||
* Kernel cleans up PI-state, but userspace is likely hosed.
|
||||
* (Robust-futex cleanup is separate and might save the day for userspace.)
|
||||
*/
|
||||
void exit_pi_state_list(struct task_struct *curr)
|
||||
static void exit_pi_state_list(struct task_struct *curr)
|
||||
{
|
||||
struct list_head *next, *head = &curr->pi_state_list;
|
||||
struct futex_pi_state *pi_state;
|
||||
@@ -960,7 +966,8 @@ void exit_pi_state_list(struct task_struct *curr)
|
||||
}
|
||||
raw_spin_unlock_irq(&curr->pi_lock);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void exit_pi_state_list(struct task_struct *curr) { }
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -1169,16 +1176,47 @@ out_error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* wait_for_owner_exiting - Block until the owner has exited
|
||||
* @exiting: Pointer to the exiting task
|
||||
*
|
||||
* Caller must hold a refcount on @exiting.
|
||||
*/
|
||||
static void wait_for_owner_exiting(int ret, struct task_struct *exiting)
|
||||
{
|
||||
if (ret != -EBUSY) {
|
||||
WARN_ON_ONCE(exiting);
|
||||
return;
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(ret == -EBUSY && !exiting))
|
||||
return;
|
||||
|
||||
mutex_lock(&exiting->futex_exit_mutex);
|
||||
/*
|
||||
* No point in doing state checking here. If the waiter got here
|
||||
* while the task was in exec()->exec_futex_release() then it can
|
||||
* have any FUTEX_STATE_* value when the waiter has acquired the
|
||||
* mutex. OK, if running, EXITING or DEAD if it reached exit()
|
||||
* already. Highly unlikely and not a problem. Just one more round
|
||||
* through the futex maze.
|
||||
*/
|
||||
mutex_unlock(&exiting->futex_exit_mutex);
|
||||
|
||||
put_task_struct(exiting);
|
||||
}
|
||||
|
||||
static int handle_exit_race(u32 __user *uaddr, u32 uval,
|
||||
struct task_struct *tsk)
|
||||
{
|
||||
u32 uval2;
|
||||
|
||||
/*
|
||||
* If PF_EXITPIDONE is not yet set, then try again.
|
||||
* If the futex exit state is not yet FUTEX_STATE_DEAD, tell the
|
||||
* caller that the alleged owner is busy.
|
||||
*/
|
||||
if (tsk && !(tsk->flags & PF_EXITPIDONE))
|
||||
return -EAGAIN;
|
||||
if (tsk && tsk->futex_state != FUTEX_STATE_DEAD)
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* Reread the user space value to handle the following situation:
|
||||
@@ -1196,8 +1234,9 @@ static int handle_exit_race(u32 __user *uaddr, u32 uval,
|
||||
* *uaddr = 0xC0000000; tsk = get_task(PID);
|
||||
* } if (!tsk->flags & PF_EXITING) {
|
||||
* ... attach();
|
||||
* tsk->flags |= PF_EXITPIDONE; } else {
|
||||
* if (!(tsk->flags & PF_EXITPIDONE))
|
||||
* tsk->futex_state = } else {
|
||||
* FUTEX_STATE_DEAD; if (tsk->futex_state !=
|
||||
* FUTEX_STATE_DEAD)
|
||||
* return -EAGAIN;
|
||||
* return -ESRCH; <--- FAIL
|
||||
* }
|
||||
@@ -1228,7 +1267,8 @@ static int handle_exit_race(u32 __user *uaddr, u32 uval,
|
||||
* it after doing proper sanity checks.
|
||||
*/
|
||||
static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key,
|
||||
struct futex_pi_state **ps)
|
||||
struct futex_pi_state **ps,
|
||||
struct task_struct **exiting)
|
||||
{
|
||||
pid_t pid = uval & FUTEX_TID_MASK;
|
||||
struct futex_pi_state *pi_state;
|
||||
@@ -1253,22 +1293,33 @@ static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key,
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to look at the task state flags to figure out,
|
||||
* whether the task is exiting. To protect against the do_exit
|
||||
* change of the task flags, we do this protected by
|
||||
* p->pi_lock:
|
||||
* We need to look at the task state to figure out, whether the
|
||||
* task is exiting. To protect against the change of the task state
|
||||
* in futex_exit_release(), we do this protected by p->pi_lock:
|
||||
*/
|
||||
raw_spin_lock_irq(&p->pi_lock);
|
||||
if (unlikely(p->flags & PF_EXITING)) {
|
||||
if (unlikely(p->futex_state != FUTEX_STATE_OK)) {
|
||||
/*
|
||||
* The task is on the way out. When PF_EXITPIDONE is
|
||||
* set, we know that the task has finished the
|
||||
* cleanup:
|
||||
* The task is on the way out. When the futex state is
|
||||
* FUTEX_STATE_DEAD, we know that the task has finished
|
||||
* the cleanup:
|
||||
*/
|
||||
int ret = handle_exit_race(uaddr, uval, p);
|
||||
|
||||
raw_spin_unlock_irq(&p->pi_lock);
|
||||
put_task_struct(p);
|
||||
/*
|
||||
* If the owner task is between FUTEX_STATE_EXITING and
|
||||
* FUTEX_STATE_DEAD then store the task pointer and keep
|
||||
* the reference on the task struct. The calling code will
|
||||
* drop all locks, wait for the task to reach
|
||||
* FUTEX_STATE_DEAD and then drop the refcount. This is
|
||||
* required to prevent a live lock when the current task
|
||||
* preempted the exiting task between the two states.
|
||||
*/
|
||||
if (ret == -EBUSY)
|
||||
*exiting = p;
|
||||
else
|
||||
put_task_struct(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1307,7 +1358,8 @@ static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key,
|
||||
|
||||
static int lookup_pi_state(u32 __user *uaddr, u32 uval,
|
||||
struct futex_hash_bucket *hb,
|
||||
union futex_key *key, struct futex_pi_state **ps)
|
||||
union futex_key *key, struct futex_pi_state **ps,
|
||||
struct task_struct **exiting)
|
||||
{
|
||||
struct futex_q *top_waiter = futex_top_waiter(hb, key);
|
||||
|
||||
@@ -1322,7 +1374,7 @@ static int lookup_pi_state(u32 __user *uaddr, u32 uval,
|
||||
* We are the first waiter - try to look up the owner based on
|
||||
* @uval and attach to it.
|
||||
*/
|
||||
return attach_to_pi_owner(uaddr, uval, key, ps);
|
||||
return attach_to_pi_owner(uaddr, uval, key, ps, exiting);
|
||||
}
|
||||
|
||||
static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval)
|
||||
@@ -1350,6 +1402,8 @@ static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval)
|
||||
* lookup
|
||||
* @task: the task to perform the atomic lock work for. This will
|
||||
* be "current" except in the case of requeue pi.
|
||||
* @exiting: Pointer to store the task pointer of the owner task
|
||||
* which is in the middle of exiting
|
||||
* @set_waiters: force setting the FUTEX_WAITERS bit (1) or not (0)
|
||||
*
|
||||
* Return:
|
||||
@@ -1358,11 +1412,17 @@ static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval)
|
||||
* - <0 - error
|
||||
*
|
||||
* The hb->lock and futex_key refs shall be held by the caller.
|
||||
*
|
||||
* @exiting is only set when the return value is -EBUSY. If so, this holds
|
||||
* a refcount on the exiting task on return and the caller needs to drop it
|
||||
* after waiting for the exit to complete.
|
||||
*/
|
||||
static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,
|
||||
union futex_key *key,
|
||||
struct futex_pi_state **ps,
|
||||
struct task_struct *task, int set_waiters)
|
||||
struct task_struct *task,
|
||||
struct task_struct **exiting,
|
||||
int set_waiters)
|
||||
{
|
||||
u32 uval, newval, vpid = task_pid_vnr(task);
|
||||
struct futex_q *top_waiter;
|
||||
@@ -1432,7 +1492,7 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,
|
||||
* attach to the owner. If that fails, no harm done, we only
|
||||
* set the FUTEX_WAITERS bit in the user space variable.
|
||||
*/
|
||||
return attach_to_pi_owner(uaddr, newval, key, ps);
|
||||
return attach_to_pi_owner(uaddr, newval, key, ps, exiting);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1850,6 +1910,8 @@ void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key,
|
||||
* @key1: the from futex key
|
||||
* @key2: the to futex key
|
||||
* @ps: address to store the pi_state pointer
|
||||
* @exiting: Pointer to store the task pointer of the owner task
|
||||
* which is in the middle of exiting
|
||||
* @set_waiters: force setting the FUTEX_WAITERS bit (1) or not (0)
|
||||
*
|
||||
* Try and get the lock on behalf of the top waiter if we can do it atomically.
|
||||
@@ -1857,16 +1919,20 @@ void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key,
|
||||
* then direct futex_lock_pi_atomic() to force setting the FUTEX_WAITERS bit.
|
||||
* hb1 and hb2 must be held by the caller.
|
||||
*
|
||||
* @exiting is only set when the return value is -EBUSY. If so, this holds
|
||||
* a refcount on the exiting task on return and the caller needs to drop it
|
||||
* after waiting for the exit to complete.
|
||||
*
|
||||
* Return:
|
||||
* - 0 - failed to acquire the lock atomically;
|
||||
* - >0 - acquired the lock, return value is vpid of the top_waiter
|
||||
* - <0 - error
|
||||
*/
|
||||
static int futex_proxy_trylock_atomic(u32 __user *pifutex,
|
||||
struct futex_hash_bucket *hb1,
|
||||
struct futex_hash_bucket *hb2,
|
||||
union futex_key *key1, union futex_key *key2,
|
||||
struct futex_pi_state **ps, int set_waiters)
|
||||
static int
|
||||
futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1,
|
||||
struct futex_hash_bucket *hb2, union futex_key *key1,
|
||||
union futex_key *key2, struct futex_pi_state **ps,
|
||||
struct task_struct **exiting, int set_waiters)
|
||||
{
|
||||
struct futex_q *top_waiter = NULL;
|
||||
u32 curval;
|
||||
@@ -1903,7 +1969,7 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
|
||||
*/
|
||||
vpid = task_pid_vnr(top_waiter->task);
|
||||
ret = futex_lock_pi_atomic(pifutex, hb2, key2, ps, top_waiter->task,
|
||||
set_waiters);
|
||||
exiting, set_waiters);
|
||||
if (ret == 1) {
|
||||
requeue_pi_wake_futex(top_waiter, key2, hb2);
|
||||
return vpid;
|
||||
@@ -2032,6 +2098,8 @@ retry_private:
|
||||
}
|
||||
|
||||
if (requeue_pi && (task_count - nr_wake < nr_requeue)) {
|
||||
struct task_struct *exiting = NULL;
|
||||
|
||||
/*
|
||||
* Attempt to acquire uaddr2 and wake the top waiter. If we
|
||||
* intend to requeue waiters, force setting the FUTEX_WAITERS
|
||||
@@ -2039,7 +2107,8 @@ retry_private:
|
||||
* faults rather in the requeue loop below.
|
||||
*/
|
||||
ret = futex_proxy_trylock_atomic(uaddr2, hb1, hb2, &key1,
|
||||
&key2, &pi_state, nr_requeue);
|
||||
&key2, &pi_state,
|
||||
&exiting, nr_requeue);
|
||||
|
||||
/*
|
||||
* At this point the top_waiter has either taken uaddr2 or is
|
||||
@@ -2066,7 +2135,8 @@ retry_private:
|
||||
* If that call succeeds then we have pi_state and an
|
||||
* initial refcount on it.
|
||||
*/
|
||||
ret = lookup_pi_state(uaddr2, ret, hb2, &key2, &pi_state);
|
||||
ret = lookup_pi_state(uaddr2, ret, hb2, &key2,
|
||||
&pi_state, &exiting);
|
||||
}
|
||||
|
||||
switch (ret) {
|
||||
@@ -2084,17 +2154,24 @@ retry_private:
|
||||
if (!ret)
|
||||
goto retry;
|
||||
goto out;
|
||||
case -EBUSY:
|
||||
case -EAGAIN:
|
||||
/*
|
||||
* Two reasons for this:
|
||||
* - Owner is exiting and we just wait for the
|
||||
* - EBUSY: Owner is exiting and we just wait for the
|
||||
* exit to complete.
|
||||
* - The user space value changed.
|
||||
* - EAGAIN: The user space value changed.
|
||||
*/
|
||||
double_unlock_hb(hb1, hb2);
|
||||
hb_waiters_dec(hb2);
|
||||
put_futex_key(&key2);
|
||||
put_futex_key(&key1);
|
||||
/*
|
||||
* Handle the case where the owner is in the middle of
|
||||
* exiting. Wait for the exit to complete otherwise
|
||||
* this task might loop forever, aka. live lock.
|
||||
*/
|
||||
wait_for_owner_exiting(ret, exiting);
|
||||
cond_resched();
|
||||
goto retry;
|
||||
default:
|
||||
@@ -2801,6 +2878,7 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
|
||||
{
|
||||
struct hrtimer_sleeper timeout, *to;
|
||||
struct futex_pi_state *pi_state = NULL;
|
||||
struct task_struct *exiting = NULL;
|
||||
struct rt_mutex_waiter rt_waiter;
|
||||
struct futex_hash_bucket *hb;
|
||||
struct futex_q q = futex_q_init;
|
||||
@@ -2822,7 +2900,8 @@ retry:
|
||||
retry_private:
|
||||
hb = queue_lock(&q);
|
||||
|
||||
ret = futex_lock_pi_atomic(uaddr, hb, &q.key, &q.pi_state, current, 0);
|
||||
ret = futex_lock_pi_atomic(uaddr, hb, &q.key, &q.pi_state, current,
|
||||
&exiting, 0);
|
||||
if (unlikely(ret)) {
|
||||
/*
|
||||
* Atomic work succeeded and we got the lock,
|
||||
@@ -2835,15 +2914,22 @@ retry_private:
|
||||
goto out_unlock_put_key;
|
||||
case -EFAULT:
|
||||
goto uaddr_faulted;
|
||||
case -EBUSY:
|
||||
case -EAGAIN:
|
||||
/*
|
||||
* Two reasons for this:
|
||||
* - Task is exiting and we just wait for the
|
||||
* - EBUSY: Task is exiting and we just wait for the
|
||||
* exit to complete.
|
||||
* - The user space value changed.
|
||||
* - EAGAIN: The user space value changed.
|
||||
*/
|
||||
queue_unlock(hb);
|
||||
put_futex_key(&q.key);
|
||||
/*
|
||||
* Handle the case where the owner is in the middle of
|
||||
* exiting. Wait for the exit to complete otherwise
|
||||
* this task might loop forever, aka. live lock.
|
||||
*/
|
||||
wait_for_owner_exiting(ret, exiting);
|
||||
cond_resched();
|
||||
goto retry;
|
||||
default:
|
||||
@@ -3452,11 +3538,16 @@ err_unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Constants for the pending_op argument of handle_futex_death */
|
||||
#define HANDLE_DEATH_PENDING true
|
||||
#define HANDLE_DEATH_LIST false
|
||||
|
||||
/*
|
||||
* Process a futex-list entry, check whether it's owned by the
|
||||
* dying task, and do notification if so:
|
||||
*/
|
||||
static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi)
|
||||
static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr,
|
||||
bool pi, bool pending_op)
|
||||
{
|
||||
u32 uval, uninitialized_var(nval), mval;
|
||||
int err;
|
||||
@@ -3469,6 +3560,42 @@ retry:
|
||||
if (get_user(uval, uaddr))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Special case for regular (non PI) futexes. The unlock path in
|
||||
* user space has two race scenarios:
|
||||
*
|
||||
* 1. The unlock path releases the user space futex value and
|
||||
* before it can execute the futex() syscall to wake up
|
||||
* waiters it is killed.
|
||||
*
|
||||
* 2. A woken up waiter is killed before it can acquire the
|
||||
* futex in user space.
|
||||
*
|
||||
* In both cases the TID validation below prevents a wakeup of
|
||||
* potential waiters which can cause these waiters to block
|
||||
* forever.
|
||||
*
|
||||
* In both cases the following conditions are met:
|
||||
*
|
||||
* 1) task->robust_list->list_op_pending != NULL
|
||||
* @pending_op == true
|
||||
* 2) User space futex value == 0
|
||||
* 3) Regular futex: @pi == false
|
||||
*
|
||||
* If these conditions are met, it is safe to attempt waking up a
|
||||
* potential waiter without touching the user space futex value and
|
||||
* trying to set the OWNER_DIED bit. The user space futex value is
|
||||
* uncontended and the rest of the user space mutex state is
|
||||
* consistent, so a woken waiter will just take over the
|
||||
* uncontended futex. Setting the OWNER_DIED bit would create
|
||||
* inconsistent state and malfunction of the user space owner died
|
||||
* handling.
|
||||
*/
|
||||
if (pending_op && !pi && !uval) {
|
||||
futex_wake(uaddr, 1, 1, FUTEX_BITSET_MATCH_ANY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((uval & FUTEX_TID_MASK) != task_pid_vnr(curr))
|
||||
return 0;
|
||||
|
||||
@@ -3547,7 +3674,7 @@ static inline int fetch_robust_entry(struct robust_list __user **entry,
|
||||
*
|
||||
* We silently return on any sign of list-walking problem.
|
||||
*/
|
||||
void exit_robust_list(struct task_struct *curr)
|
||||
static void exit_robust_list(struct task_struct *curr)
|
||||
{
|
||||
struct robust_list_head __user *head = curr->robust_list;
|
||||
struct robust_list __user *entry, *next_entry, *pending;
|
||||
@@ -3588,10 +3715,11 @@ void exit_robust_list(struct task_struct *curr)
|
||||
* A pending lock might already be on the list, so
|
||||
* don't process it twice:
|
||||
*/
|
||||
if (entry != pending)
|
||||
if (entry != pending) {
|
||||
if (handle_futex_death((void __user *)entry + futex_offset,
|
||||
curr, pi))
|
||||
curr, pi, HANDLE_DEATH_LIST))
|
||||
return;
|
||||
}
|
||||
if (rc)
|
||||
return;
|
||||
entry = next_entry;
|
||||
@@ -3605,9 +3733,118 @@ void exit_robust_list(struct task_struct *curr)
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
if (pending)
|
||||
if (pending) {
|
||||
handle_futex_death((void __user *)pending + futex_offset,
|
||||
curr, pip);
|
||||
curr, pip, HANDLE_DEATH_PENDING);
|
||||
}
|
||||
}
|
||||
|
||||
static void futex_cleanup(struct task_struct *tsk)
|
||||
{
|
||||
if (unlikely(tsk->robust_list)) {
|
||||
exit_robust_list(tsk);
|
||||
tsk->robust_list = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (unlikely(tsk->compat_robust_list)) {
|
||||
compat_exit_robust_list(tsk);
|
||||
tsk->compat_robust_list = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (unlikely(!list_empty(&tsk->pi_state_list)))
|
||||
exit_pi_state_list(tsk);
|
||||
}
|
||||
|
||||
/**
|
||||
* futex_exit_recursive - Set the tasks futex state to FUTEX_STATE_DEAD
|
||||
* @tsk: task to set the state on
|
||||
*
|
||||
* Set the futex exit state of the task lockless. The futex waiter code
|
||||
* observes that state when a task is exiting and loops until the task has
|
||||
* actually finished the futex cleanup. The worst case for this is that the
|
||||
* waiter runs through the wait loop until the state becomes visible.
|
||||
*
|
||||
* This is called from the recursive fault handling path in do_exit().
|
||||
*
|
||||
* This is best effort. Either the futex exit code has run already or
|
||||
* not. If the OWNER_DIED bit has been set on the futex then the waiter can
|
||||
* take it over. If not, the problem is pushed back to user space. If the
|
||||
* futex exit code did not run yet, then an already queued waiter might
|
||||
* block forever, but there is nothing which can be done about that.
|
||||
*/
|
||||
void futex_exit_recursive(struct task_struct *tsk)
|
||||
{
|
||||
/* If the state is FUTEX_STATE_EXITING then futex_exit_mutex is held */
|
||||
if (tsk->futex_state == FUTEX_STATE_EXITING)
|
||||
mutex_unlock(&tsk->futex_exit_mutex);
|
||||
tsk->futex_state = FUTEX_STATE_DEAD;
|
||||
}
|
||||
|
||||
static void futex_cleanup_begin(struct task_struct *tsk)
|
||||
{
|
||||
/*
|
||||
* Prevent various race issues against a concurrent incoming waiter
|
||||
* including live locks by forcing the waiter to block on
|
||||
* tsk->futex_exit_mutex when it observes FUTEX_STATE_EXITING in
|
||||
* attach_to_pi_owner().
|
||||
*/
|
||||
mutex_lock(&tsk->futex_exit_mutex);
|
||||
|
||||
/*
|
||||
* Switch the state to FUTEX_STATE_EXITING under tsk->pi_lock.
|
||||
*
|
||||
* This ensures that all subsequent checks of tsk->futex_state in
|
||||
* attach_to_pi_owner() must observe FUTEX_STATE_EXITING with
|
||||
* tsk->pi_lock held.
|
||||
*
|
||||
* It guarantees also that a pi_state which was queued right before
|
||||
* the state change under tsk->pi_lock by a concurrent waiter must
|
||||
* be observed in exit_pi_state_list().
|
||||
*/
|
||||
raw_spin_lock_irq(&tsk->pi_lock);
|
||||
tsk->futex_state = FUTEX_STATE_EXITING;
|
||||
raw_spin_unlock_irq(&tsk->pi_lock);
|
||||
}
|
||||
|
||||
static void futex_cleanup_end(struct task_struct *tsk, int state)
|
||||
{
|
||||
/*
|
||||
* Lockless store. The only side effect is that an observer might
|
||||
* take another loop until it becomes visible.
|
||||
*/
|
||||
tsk->futex_state = state;
|
||||
/*
|
||||
* Drop the exit protection. This unblocks waiters which observed
|
||||
* FUTEX_STATE_EXITING to reevaluate the state.
|
||||
*/
|
||||
mutex_unlock(&tsk->futex_exit_mutex);
|
||||
}
|
||||
|
||||
void futex_exec_release(struct task_struct *tsk)
|
||||
{
|
||||
/*
|
||||
* The state handling is done for consistency, but in the case of
|
||||
* exec() there is no way to prevent futher damage as the PID stays
|
||||
* the same. But for the unlikely and arguably buggy case that a
|
||||
* futex is held on exec(), this provides at least as much state
|
||||
* consistency protection which is possible.
|
||||
*/
|
||||
futex_cleanup_begin(tsk);
|
||||
futex_cleanup(tsk);
|
||||
/*
|
||||
* Reset the state to FUTEX_STATE_OK. The task is alive and about
|
||||
* exec a new binary.
|
||||
*/
|
||||
futex_cleanup_end(tsk, FUTEX_STATE_OK);
|
||||
}
|
||||
|
||||
void futex_exit_release(struct task_struct *tsk)
|
||||
{
|
||||
futex_cleanup_begin(tsk);
|
||||
futex_cleanup(tsk);
|
||||
futex_cleanup_end(tsk, FUTEX_STATE_DEAD);
|
||||
}
|
||||
|
||||
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
|
||||
@@ -3737,7 +3974,7 @@ static void __user *futex_uaddr(struct robust_list __user *entry,
|
||||
*
|
||||
* We silently return on any sign of list-walking problem.
|
||||
*/
|
||||
void compat_exit_robust_list(struct task_struct *curr)
|
||||
static void compat_exit_robust_list(struct task_struct *curr)
|
||||
{
|
||||
struct compat_robust_list_head __user *head = curr->compat_robust_list;
|
||||
struct robust_list __user *entry, *next_entry, *pending;
|
||||
@@ -3784,7 +4021,8 @@ void compat_exit_robust_list(struct task_struct *curr)
|
||||
if (entry != pending) {
|
||||
void __user *uaddr = futex_uaddr(entry, futex_offset);
|
||||
|
||||
if (handle_futex_death(uaddr, curr, pi))
|
||||
if (handle_futex_death(uaddr, curr, pi,
|
||||
HANDLE_DEATH_LIST))
|
||||
return;
|
||||
}
|
||||
if (rc)
|
||||
@@ -3803,7 +4041,7 @@ void compat_exit_robust_list(struct task_struct *curr)
|
||||
if (pending) {
|
||||
void __user *uaddr = futex_uaddr(pending, futex_offset);
|
||||
|
||||
handle_futex_death(uaddr, curr, pip);
|
||||
handle_futex_death(uaddr, curr, pip, HANDLE_DEATH_PENDING);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -2299,7 +2299,7 @@ BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start,
|
||||
WARN_ON_ONCE(last_sge == first_sge);
|
||||
shift = last_sge > first_sge ?
|
||||
last_sge - first_sge - 1 :
|
||||
MAX_SKB_FRAGS - first_sge + last_sge - 1;
|
||||
NR_MSG_FRAG_IDS - first_sge + last_sge - 1;
|
||||
if (!shift)
|
||||
goto out;
|
||||
|
||||
@@ -2308,8 +2308,8 @@ BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start,
|
||||
do {
|
||||
u32 move_from;
|
||||
|
||||
if (i + shift >= MAX_MSG_FRAGS)
|
||||
move_from = i + shift - MAX_MSG_FRAGS;
|
||||
if (i + shift >= NR_MSG_FRAG_IDS)
|
||||
move_from = i + shift - NR_MSG_FRAG_IDS;
|
||||
else
|
||||
move_from = i + shift;
|
||||
if (move_from == msg->sg.end)
|
||||
@@ -2323,7 +2323,7 @@ BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start,
|
||||
} while (1);
|
||||
|
||||
msg->sg.end = msg->sg.end - shift > msg->sg.end ?
|
||||
msg->sg.end - shift + MAX_MSG_FRAGS :
|
||||
msg->sg.end - shift + NR_MSG_FRAG_IDS :
|
||||
msg->sg.end - shift;
|
||||
out:
|
||||
msg->data = sg_virt(&msg->sg.data[first_sge]) + start - offset;
|
||||
|
||||
+1
-1
@@ -421,7 +421,7 @@ static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb)
|
||||
copied = skb->len;
|
||||
msg->sg.start = 0;
|
||||
msg->sg.size = copied;
|
||||
msg->sg.end = num_sge == MAX_MSG_FRAGS ? 0 : num_sge;
|
||||
msg->sg.end = num_sge;
|
||||
msg->skb = skb;
|
||||
|
||||
sk_psock_queue_msg(psock, msg);
|
||||
|
||||
+1
-1
@@ -301,7 +301,7 @@ EXPORT_SYMBOL_GPL(tcp_bpf_sendmsg_redir);
|
||||
static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock,
|
||||
struct sk_msg *msg, int *copied, int flags)
|
||||
{
|
||||
bool cork = false, enospc = msg->sg.start == msg->sg.end;
|
||||
bool cork = false, enospc = sk_msg_full(msg);
|
||||
struct sock *sk_redir;
|
||||
u32 tosend, delta = 0;
|
||||
int ret;
|
||||
|
||||
@@ -704,9 +704,13 @@ static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts,
|
||||
{
|
||||
size_t len = NLMSG_ALIGN(sizeof(struct ovs_header));
|
||||
|
||||
/* OVS_FLOW_ATTR_UFID */
|
||||
/* OVS_FLOW_ATTR_UFID, or unmasked flow key as fallback
|
||||
* see ovs_nla_put_identifier()
|
||||
*/
|
||||
if (sfid && ovs_identifier_is_ufid(sfid))
|
||||
len += nla_total_size(sfid->ufid_len);
|
||||
else
|
||||
len += nla_total_size(ovs_key_attr_size());
|
||||
|
||||
/* OVS_FLOW_ATTR_KEY */
|
||||
if (!sfid || should_fill_key(sfid, ufid_flags))
|
||||
@@ -882,7 +886,10 @@ static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow,
|
||||
retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb,
|
||||
info->snd_portid, info->snd_seq, 0,
|
||||
cmd, ufid_flags);
|
||||
BUG_ON(retval < 0);
|
||||
if (WARN_ON_ONCE(retval < 0)) {
|
||||
kfree_skb(skb);
|
||||
skb = ERR_PTR(retval);
|
||||
}
|
||||
return skb;
|
||||
}
|
||||
|
||||
@@ -1346,7 +1353,10 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
|
||||
OVS_FLOW_CMD_DEL,
|
||||
ufid_flags);
|
||||
rcu_read_unlock();
|
||||
BUG_ON(err < 0);
|
||||
if (WARN_ON_ONCE(err < 0)) {
|
||||
kfree_skb(reply);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ovs_notify(&dp_flow_genl_family, reply, info);
|
||||
} else {
|
||||
@@ -1354,6 +1364,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
out_free:
|
||||
ovs_flow_free(flow, true);
|
||||
return 0;
|
||||
unlock:
|
||||
|
||||
@@ -229,7 +229,7 @@ void psample_sample_packet(struct psample_group *group, struct sk_buff *skb,
|
||||
data_len = PSAMPLE_MAX_PACKET_SIZE - meta_len - NLA_HDRLEN
|
||||
- NLA_ALIGNTO;
|
||||
|
||||
nl_skb = genlmsg_new(meta_len + data_len, GFP_ATOMIC);
|
||||
nl_skb = genlmsg_new(meta_len + nla_total_size(data_len), GFP_ATOMIC);
|
||||
if (unlikely(!nl_skb))
|
||||
return;
|
||||
|
||||
|
||||
+2
-1
@@ -245,7 +245,8 @@ static int mq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
|
||||
struct netdev_queue *dev_queue = mq_queue_get(sch, cl);
|
||||
|
||||
sch = dev_queue->qdisc_sleeping;
|
||||
if (gnet_stats_copy_basic(&sch->running, d, NULL, &sch->bstats) < 0 ||
|
||||
if (gnet_stats_copy_basic(&sch->running, d, sch->cpu_bstats,
|
||||
&sch->bstats) < 0 ||
|
||||
qdisc_qstats_copy(d, sch) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
@@ -557,8 +557,8 @@ static int mqprio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
|
||||
struct netdev_queue *dev_queue = mqprio_queue_get(sch, cl);
|
||||
|
||||
sch = dev_queue->qdisc_sleeping;
|
||||
if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch),
|
||||
d, NULL, &sch->bstats) < 0 ||
|
||||
if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), d,
|
||||
sch->cpu_bstats, &sch->bstats) < 0 ||
|
||||
qdisc_qstats_copy(d, sch) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ static int multiq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
|
||||
|
||||
cl_q = q->queues[cl - 1];
|
||||
if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch),
|
||||
d, NULL, &cl_q->bstats) < 0 ||
|
||||
d, cl_q->cpu_bstats, &cl_q->bstats) < 0 ||
|
||||
qdisc_qstats_copy(d, cl_q) < 0)
|
||||
return -1;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user