Linux 4.14-rc3

-----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJZ0WQ6AAoJEHm+PkMAQRiGuloH/3sF4qfBhPuJo8OTf0uCtQ18
 4Ux9zZbm81df/Jjz0exAp1Jqk+TvdIS3OXPWcKilvbUBP16hQcsxFTnI/5QF+YcN
 87aNr+OCMJzOBK4suN1yhzO46NYHeIizdB0PTZVL1Zsto69Tt31D8VJmgH6oBxAw
 Isb/nAkOr31dZ9PI5UEExTIanUt6EywVb0UswA+2rNl3h1UkeasQCpMpK2n6HBhU
 kVD7sxEd/CN0MmfhB0HrySSam/BeSpOtzoU9bemOwrU2uu9+5+2rqMe7Gsdj4nX6
 3Kk+7FQNktlrhxCZIFN/+CdusOUuDd8r/75d7DnsRK5YvSb0sZzJkfD3Nba68Ms=
 =7J2+
 -----END PGP SIGNATURE-----

BackMerge tag 'v4.14-rc3' into drm-next

Linux 4.14-rc3

Requested by Daniel for the tracing build fix in fixes.
This commit is contained in:
Dave Airlie 2017-10-03 09:35:04 +10:00
commit ebec44a245
236 changed files with 2900 additions and 1807 deletions

View File

@ -32,8 +32,6 @@ cpufreq-stats.txt - General description of sysfs cpufreq stats.
index.txt - File index, Mailing list and Links (this document) index.txt - File index, Mailing list and Links (this document)
intel-pstate.txt - Intel pstate cpufreq driver specific file.
pcc-cpufreq.txt - PCC cpufreq driver specific file. pcc-cpufreq.txt - PCC cpufreq driver specific file.

View File

@ -15,11 +15,14 @@ Required properties
compatible : Must be "ams,as3645a". compatible : Must be "ams,as3645a".
reg : The I2C address of the device. Typically 0x30. reg : The I2C address of the device. Typically 0x30.
#address-cells : 1
#size-cells : 0
Required properties of the "flash" child node Required properties of the flash child node (0)
============================================= ===============================================
reg: 0
flash-timeout-us: Flash timeout in microseconds. The value must be in flash-timeout-us: Flash timeout in microseconds. The value must be in
the range [100000, 850000] and divisible by 50000. the range [100000, 850000] and divisible by 50000.
flash-max-microamp: Maximum flash current in microamperes. Has to be flash-max-microamp: Maximum flash current in microamperes. Has to be
@ -33,20 +36,21 @@ ams,input-max-microamp: Maximum flash controller input current. The
and divisible by 50000. and divisible by 50000.
Optional properties of the "flash" child node Optional properties of the flash child node
============================================= ===========================================
label : The label of the flash LED. label : The label of the flash LED.
Required properties of the "indicator" child node Required properties of the indicator child node (1)
================================================= ===================================================
reg: 1
led-max-microamp: Maximum indicator current. The allowed values are led-max-microamp: Maximum indicator current. The allowed values are
2500, 5000, 7500 and 10000. 2500, 5000, 7500 and 10000.
Optional properties of the "indicator" child node Optional properties of the indicator child node
================================================= ===============================================
label : The label of the indicator LED. label : The label of the indicator LED.
@ -55,16 +59,20 @@ Example
======= =======
as3645a@30 { as3645a@30 {
#address-cells: 1
#size-cells: 0
reg = <0x30>; reg = <0x30>;
compatible = "ams,as3645a"; compatible = "ams,as3645a";
flash { flash@0 {
reg = <0x0>;
flash-timeout-us = <150000>; flash-timeout-us = <150000>;
flash-max-microamp = <320000>; flash-max-microamp = <320000>;
led-max-microamp = <60000>; led-max-microamp = <60000>;
ams,input-max-microamp = <1750000>; ams,input-max-microamp = <1750000>;
label = "as3645a:flash"; label = "as3645a:flash";
}; };
indicator { indicator@1 {
reg = <0x1>;
led-max-microamp = <10000>; led-max-microamp = <10000>;
label = "as3645a:indicator"; label = "as3645a:indicator";
}; };

View File

@ -8603,6 +8603,12 @@ M: Sean Wang <sean.wang@mediatek.com>
S: Maintained S: Maintained
F: drivers/media/rc/mtk-cir.c F: drivers/media/rc/mtk-cir.c
MEDIATEK PMIC LED DRIVER
M: Sean Wang <sean.wang@mediatek.com>
S: Maintained
F: drivers/leds/leds-mt6323.c
F: Documentation/devicetree/bindings/leds/leds-mt6323.txt
MEDIATEK ETHERNET DRIVER MEDIATEK ETHERNET DRIVER
M: Felix Fietkau <nbd@openwrt.org> M: Felix Fietkau <nbd@openwrt.org>
M: John Crispin <john@phrozen.org> M: John Crispin <john@phrozen.org>

View File

@ -1,7 +1,7 @@
VERSION = 4 VERSION = 4
PATCHLEVEL = 14 PATCHLEVEL = 14
SUBLEVEL = 0 SUBLEVEL = 0
EXTRAVERSION = -rc2 EXTRAVERSION = -rc3
NAME = Fearless Coyote NAME = Fearless Coyote
# *DOCUMENTATION* # *DOCUMENTATION*
@ -1172,11 +1172,11 @@ headers_check: headers_install
PHONY += kselftest PHONY += kselftest
kselftest: kselftest:
$(Q)$(MAKE) -C tools/testing/selftests run_tests $(Q)$(MAKE) -C $(srctree)/tools/testing/selftests run_tests
PHONY += kselftest-clean PHONY += kselftest-clean
kselftest-clean: kselftest-clean:
$(Q)$(MAKE) -C tools/testing/selftests clean $(Q)$(MAKE) -C $(srctree)/tools/testing/selftests clean
PHONY += kselftest-merge PHONY += kselftest-merge
kselftest-merge: kselftest-merge:

View File

@ -267,15 +267,19 @@ &i2c2 {
clock-frequency = <400000>; clock-frequency = <400000>;
as3645a@30 { as3645a@30 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0x30>; reg = <0x30>;
compatible = "ams,as3645a"; compatible = "ams,as3645a";
flash { flash@0 {
reg = <0x0>;
flash-timeout-us = <150000>; flash-timeout-us = <150000>;
flash-max-microamp = <320000>; flash-max-microamp = <320000>;
led-max-microamp = <60000>; led-max-microamp = <60000>;
peak-current-limit = <1750000>; ams,input-max-microamp = <1750000>;
}; };
indicator { indicator@1 {
reg = <0x1>;
led-max-microamp = <10000>; led-max-microamp = <10000>;
}; };
}; };

View File

@ -401,7 +401,7 @@ static inline phys_addr_t pmd_page_paddr(pmd_t pmd)
/* Find an entry in the third-level page table. */ /* Find an entry in the third-level page table. */
#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) #define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define pte_offset_phys(dir,addr) (pmd_page_paddr(*(dir)) + pte_index(addr) * sizeof(pte_t)) #define pte_offset_phys(dir,addr) (pmd_page_paddr(READ_ONCE(*(dir))) + pte_index(addr) * sizeof(pte_t))
#define pte_offset_kernel(dir,addr) ((pte_t *)__va(pte_offset_phys((dir), (addr)))) #define pte_offset_kernel(dir,addr) ((pte_t *)__va(pte_offset_phys((dir), (addr))))
#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr)) #define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))

View File

@ -384,6 +384,7 @@ ENTRY(kimage_vaddr)
* booted in EL1 or EL2 respectively. * booted in EL1 or EL2 respectively.
*/ */
ENTRY(el2_setup) ENTRY(el2_setup)
msr SPsel, #1 // We want to use SP_EL{1,2}
mrs x0, CurrentEL mrs x0, CurrentEL
cmp x0, #CurrentEL_EL2 cmp x0, #CurrentEL_EL2
b.eq 1f b.eq 1f

View File

@ -651,7 +651,7 @@ static const struct fault_info fault_info[] = {
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 0 translation fault" }, { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 0 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" }, { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" }, { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
{ do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" }, { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
{ do_bad, SIGBUS, 0, "unknown 8" }, { do_bad, SIGBUS, 0, "unknown 8" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" }, { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" }, { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },

View File

@ -39,7 +39,7 @@ config MICROBLAZE
# Endianness selection # Endianness selection
choice choice
prompt "Endianness selection" prompt "Endianness selection"
default CPU_BIG_ENDIAN default CPU_LITTLE_ENDIAN
help help
microblaze architectures can be configured for either little or microblaze architectures can be configured for either little or
big endian formats. Be sure to select the appropriate mode. big endian formats. Be sure to select the appropriate mode.

View File

@ -7,6 +7,7 @@ generic-y += fcntl.h
generic-y += ioctl.h generic-y += ioctl.h
generic-y += ioctls.h generic-y += ioctls.h
generic-y += ipcbuf.h generic-y += ipcbuf.h
generic-y += kvm_para.h
generic-y += mman.h generic-y += mman.h
generic-y += msgbuf.h generic-y += msgbuf.h
generic-y += param.h generic-y += param.h

View File

@ -165,7 +165,7 @@ int dma_direct_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
unsigned long attrs) unsigned long attrs)
{ {
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; unsigned long user_count = vma_pages(vma);
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
unsigned long off = vma->vm_pgoff; unsigned long off = vma->vm_pgoff;
unsigned long pfn; unsigned long pfn;

View File

@ -1121,6 +1121,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
mtspr SPRN_PPR, r0 mtspr SPRN_PPR, r0
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
/* Move canary into DSISR to check for later */
BEGIN_FTR_SECTION
li r0, 0x7fff
mtspr SPRN_HDSISR, r0
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
ld r0, VCPU_GPR(R0)(r4) ld r0, VCPU_GPR(R0)(r4)
ld r4, VCPU_GPR(R4)(r4) ld r4, VCPU_GPR(R4)(r4)
@ -1956,9 +1963,14 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX)
kvmppc_hdsi: kvmppc_hdsi:
ld r3, VCPU_KVM(r9) ld r3, VCPU_KVM(r9)
lbz r0, KVM_RADIX(r3) lbz r0, KVM_RADIX(r3)
cmpwi r0, 0
mfspr r4, SPRN_HDAR mfspr r4, SPRN_HDAR
mfspr r6, SPRN_HDSISR mfspr r6, SPRN_HDSISR
BEGIN_FTR_SECTION
/* Look for DSISR canary. If we find it, retry instruction */
cmpdi r6, 0x7fff
beq 6f
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
cmpwi r0, 0
bne .Lradix_hdsi /* on radix, just save DAR/DSISR/ASDR */ bne .Lradix_hdsi /* on radix, just save DAR/DSISR/ASDR */
/* HPTE not found fault or protection fault? */ /* HPTE not found fault or protection fault? */
andis. r0, r6, (DSISR_NOHPTE | DSISR_PROTFAULT)@h andis. r0, r6, (DSISR_NOHPTE | DSISR_PROTFAULT)@h

View File

@ -98,7 +98,7 @@ static struct clocksource timer_clocksource = {
.flags = CLOCK_SOURCE_IS_CONTINUOUS, .flags = CLOCK_SOURCE_IS_CONTINUOUS,
}; };
static void __init timer_setup(void) static void __init um_timer_setup(void)
{ {
int err; int err;
@ -132,5 +132,5 @@ void read_persistent_clock(struct timespec *ts)
void __init time_init(void) void __init time_init(void)
{ {
timer_set_signal_handler(); timer_set_signal_handler();
late_time_init = timer_setup; late_time_init = um_timer_setup;
} }

View File

@ -552,6 +552,7 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = {
X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_MOBILE, snb_cstates), X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_MOBILE, snb_cstates),
X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_DESKTOP, snb_cstates), X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_DESKTOP, snb_cstates),
X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_X, snb_cstates),
X86_CSTATES_MODEL(INTEL_FAM6_KABYLAKE_MOBILE, snb_cstates), X86_CSTATES_MODEL(INTEL_FAM6_KABYLAKE_MOBILE, snb_cstates),
X86_CSTATES_MODEL(INTEL_FAM6_KABYLAKE_DESKTOP, snb_cstates), X86_CSTATES_MODEL(INTEL_FAM6_KABYLAKE_DESKTOP, snb_cstates),
@ -560,6 +561,9 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = {
X86_CSTATES_MODEL(INTEL_FAM6_XEON_PHI_KNM, knl_cstates), X86_CSTATES_MODEL(INTEL_FAM6_XEON_PHI_KNM, knl_cstates),
X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT, glm_cstates), X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT, glm_cstates),
X86_CSTATES_MODEL(INTEL_FAM6_ATOM_DENVERTON, glm_cstates),
X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GEMINI_LAKE, glm_cstates),
{ }, { },
}; };
MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match); MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);

View File

@ -775,6 +775,9 @@ static const struct x86_cpu_id rapl_cpu_match[] __initconst = {
X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE_DESKTOP, skl_rapl_init), X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE_DESKTOP, skl_rapl_init),
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT, hsw_rapl_init), X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT, hsw_rapl_init),
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_DENVERTON, hsw_rapl_init),
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GEMINI_LAKE, hsw_rapl_init),
{}, {},
}; };

View File

@ -3462,7 +3462,7 @@ static struct intel_uncore_ops skx_uncore_iio_ops = {
static struct intel_uncore_type skx_uncore_iio = { static struct intel_uncore_type skx_uncore_iio = {
.name = "iio", .name = "iio",
.num_counters = 4, .num_counters = 4,
.num_boxes = 5, .num_boxes = 6,
.perf_ctr_bits = 48, .perf_ctr_bits = 48,
.event_ctl = SKX_IIO0_MSR_PMON_CTL0, .event_ctl = SKX_IIO0_MSR_PMON_CTL0,
.perf_ctr = SKX_IIO0_MSR_PMON_CTR0, .perf_ctr = SKX_IIO0_MSR_PMON_CTR0,
@ -3492,7 +3492,7 @@ static const struct attribute_group skx_uncore_format_group = {
static struct intel_uncore_type skx_uncore_irp = { static struct intel_uncore_type skx_uncore_irp = {
.name = "irp", .name = "irp",
.num_counters = 2, .num_counters = 2,
.num_boxes = 5, .num_boxes = 6,
.perf_ctr_bits = 48, .perf_ctr_bits = 48,
.event_ctl = SKX_IRP0_MSR_PMON_CTL0, .event_ctl = SKX_IRP0_MSR_PMON_CTL0,
.perf_ctr = SKX_IRP0_MSR_PMON_CTR0, .perf_ctr = SKX_IRP0_MSR_PMON_CTR0,

View File

@ -63,6 +63,14 @@ static bool test_intel(int idx)
case INTEL_FAM6_ATOM_SILVERMONT1: case INTEL_FAM6_ATOM_SILVERMONT1:
case INTEL_FAM6_ATOM_SILVERMONT2: case INTEL_FAM6_ATOM_SILVERMONT2:
case INTEL_FAM6_ATOM_AIRMONT: case INTEL_FAM6_ATOM_AIRMONT:
case INTEL_FAM6_ATOM_GOLDMONT:
case INTEL_FAM6_ATOM_DENVERTON:
case INTEL_FAM6_ATOM_GEMINI_LAKE:
case INTEL_FAM6_XEON_PHI_KNL:
case INTEL_FAM6_XEON_PHI_KNM:
if (idx == PERF_MSR_SMI) if (idx == PERF_MSR_SMI)
return true; return true;
break; break;

View File

@ -231,7 +231,7 @@ static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
ksig->ka.sa.sa_restorer) ksig->ka.sa.sa_restorer)
sp = (unsigned long) ksig->ka.sa.sa_restorer; sp = (unsigned long) ksig->ka.sa.sa_restorer;
if (fpu->fpstate_active) { if (fpu->initialized) {
unsigned long fx_aligned, math_size; unsigned long fx_aligned, math_size;
sp = fpu__alloc_mathframe(sp, 1, &fx_aligned, &math_size); sp = fpu__alloc_mathframe(sp, 1, &fx_aligned, &math_size);

View File

@ -11,10 +11,12 @@
# define __ASM_FORM_COMMA(x) " " #x "," # define __ASM_FORM_COMMA(x) " " #x ","
#endif #endif
#ifdef CONFIG_X86_32 #ifndef __x86_64__
/* 32 bit */
# define __ASM_SEL(a,b) __ASM_FORM(a) # define __ASM_SEL(a,b) __ASM_FORM(a)
# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a) # define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a)
#else #else
/* 64 bit */
# define __ASM_SEL(a,b) __ASM_FORM(b) # define __ASM_SEL(a,b) __ASM_FORM(b)
# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b) # define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b)
#endif #endif
@ -139,8 +141,8 @@
* gets set up by the containing function. If you forget to do this, objtool * gets set up by the containing function. If you forget to do this, objtool
* may print a "call without frame pointer save/setup" warning. * may print a "call without frame pointer save/setup" warning.
*/ */
register unsigned int __asm_call_sp asm("esp"); register unsigned long current_stack_pointer asm(_ASM_SP);
#define ASM_CALL_CONSTRAINT "+r" (__asm_call_sp) #define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer)
#endif #endif
#endif /* _ASM_X86_ASM_H */ #endif /* _ASM_X86_ASM_H */

View File

@ -23,11 +23,9 @@
/* /*
* High level FPU state handling functions: * High level FPU state handling functions:
*/ */
extern void fpu__activate_curr(struct fpu *fpu); extern void fpu__initialize(struct fpu *fpu);
extern void fpu__activate_fpstate_read(struct fpu *fpu); extern void fpu__prepare_read(struct fpu *fpu);
extern void fpu__activate_fpstate_write(struct fpu *fpu); extern void fpu__prepare_write(struct fpu *fpu);
extern void fpu__current_fpstate_write_begin(void);
extern void fpu__current_fpstate_write_end(void);
extern void fpu__save(struct fpu *fpu); extern void fpu__save(struct fpu *fpu);
extern void fpu__restore(struct fpu *fpu); extern void fpu__restore(struct fpu *fpu);
extern int fpu__restore_sig(void __user *buf, int ia32_frame); extern int fpu__restore_sig(void __user *buf, int ia32_frame);
@ -120,20 +118,11 @@ extern void fpstate_sanitize_xstate(struct fpu *fpu);
err; \ err; \
}) })
#define check_insn(insn, output, input...) \ #define kernel_insn(insn, output, input...) \
({ \
int err; \
asm volatile("1:" #insn "\n\t" \ asm volatile("1:" #insn "\n\t" \
"2:\n" \ "2:\n" \
".section .fixup,\"ax\"\n" \ _ASM_EXTABLE_HANDLE(1b, 2b, ex_handler_fprestore) \
"3: movl $-1,%[err]\n" \ : output : input)
" jmp 2b\n" \
".previous\n" \
_ASM_EXTABLE(1b, 3b) \
: [err] "=r" (err), output \
: "0"(0), input); \
err; \
})
static inline int copy_fregs_to_user(struct fregs_state __user *fx) static inline int copy_fregs_to_user(struct fregs_state __user *fx)
{ {
@ -153,20 +142,16 @@ static inline int copy_fxregs_to_user(struct fxregs_state __user *fx)
static inline void copy_kernel_to_fxregs(struct fxregs_state *fx) static inline void copy_kernel_to_fxregs(struct fxregs_state *fx)
{ {
int err;
if (IS_ENABLED(CONFIG_X86_32)) { if (IS_ENABLED(CONFIG_X86_32)) {
err = check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); kernel_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
} else { } else {
if (IS_ENABLED(CONFIG_AS_FXSAVEQ)) { if (IS_ENABLED(CONFIG_AS_FXSAVEQ)) {
err = check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); kernel_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
} else { } else {
/* See comment in copy_fxregs_to_kernel() below. */ /* See comment in copy_fxregs_to_kernel() below. */
err = check_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx), "m" (*fx)); kernel_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx), "m" (*fx));
} }
} }
/* Copying from a kernel buffer to FPU registers should never fail: */
WARN_ON_FPU(err);
} }
static inline int copy_user_to_fxregs(struct fxregs_state __user *fx) static inline int copy_user_to_fxregs(struct fxregs_state __user *fx)
@ -183,9 +168,7 @@ static inline int copy_user_to_fxregs(struct fxregs_state __user *fx)
static inline void copy_kernel_to_fregs(struct fregs_state *fx) static inline void copy_kernel_to_fregs(struct fregs_state *fx)
{ {
int err = check_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); kernel_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
WARN_ON_FPU(err);
} }
static inline int copy_user_to_fregs(struct fregs_state __user *fx) static inline int copy_user_to_fregs(struct fregs_state __user *fx)
@ -281,18 +264,13 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)
* Use XRSTORS to restore context if it is enabled. XRSTORS supports compact * Use XRSTORS to restore context if it is enabled. XRSTORS supports compact
* XSAVE area format. * XSAVE area format.
*/ */
#define XSTATE_XRESTORE(st, lmask, hmask, err) \ #define XSTATE_XRESTORE(st, lmask, hmask) \
asm volatile(ALTERNATIVE(XRSTOR, \ asm volatile(ALTERNATIVE(XRSTOR, \
XRSTORS, X86_FEATURE_XSAVES) \ XRSTORS, X86_FEATURE_XSAVES) \
"\n" \ "\n" \
"xor %[err], %[err]\n" \
"3:\n" \ "3:\n" \
".pushsection .fixup,\"ax\"\n" \ _ASM_EXTABLE_HANDLE(661b, 3b, ex_handler_fprestore)\
"4: movl $-2, %[err]\n" \ : \
"jmp 3b\n" \
".popsection\n" \
_ASM_EXTABLE(661b, 4b) \
: [err] "=r" (err) \
: "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \ : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \
: "memory") : "memory")
@ -336,7 +314,10 @@ static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate)
else else
XSTATE_OP(XRSTOR, xstate, lmask, hmask, err); XSTATE_OP(XRSTOR, xstate, lmask, hmask, err);
/* We should never fault when copying from a kernel buffer: */ /*
* We should never fault when copying from a kernel buffer, and the FPU
* state we set at boot time should be valid.
*/
WARN_ON_FPU(err); WARN_ON_FPU(err);
} }
@ -350,7 +331,7 @@ static inline void copy_xregs_to_kernel(struct xregs_state *xstate)
u32 hmask = mask >> 32; u32 hmask = mask >> 32;
int err; int err;
WARN_ON(!alternatives_patched); WARN_ON_FPU(!alternatives_patched);
XSTATE_XSAVE(xstate, lmask, hmask, err); XSTATE_XSAVE(xstate, lmask, hmask, err);
@ -365,12 +346,8 @@ static inline void copy_kernel_to_xregs(struct xregs_state *xstate, u64 mask)
{ {
u32 lmask = mask; u32 lmask = mask;
u32 hmask = mask >> 32; u32 hmask = mask >> 32;
int err;
XSTATE_XRESTORE(xstate, lmask, hmask, err); XSTATE_XRESTORE(xstate, lmask, hmask);
/* We should never fault when copying from a kernel buffer: */
WARN_ON_FPU(err);
} }
/* /*
@ -526,37 +503,16 @@ static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu)
*/ */
static inline void fpregs_deactivate(struct fpu *fpu) static inline void fpregs_deactivate(struct fpu *fpu)
{ {
WARN_ON_FPU(!fpu->fpregs_active);
fpu->fpregs_active = 0;
this_cpu_write(fpu_fpregs_owner_ctx, NULL); this_cpu_write(fpu_fpregs_owner_ctx, NULL);
trace_x86_fpu_regs_deactivated(fpu); trace_x86_fpu_regs_deactivated(fpu);
} }
static inline void fpregs_activate(struct fpu *fpu) static inline void fpregs_activate(struct fpu *fpu)
{ {
WARN_ON_FPU(fpu->fpregs_active);
fpu->fpregs_active = 1;
this_cpu_write(fpu_fpregs_owner_ctx, fpu); this_cpu_write(fpu_fpregs_owner_ctx, fpu);
trace_x86_fpu_regs_activated(fpu); trace_x86_fpu_regs_activated(fpu);
} }
/*
* The question "does this thread have fpu access?"
* is slightly racy, since preemption could come in
* and revoke it immediately after the test.
*
* However, even in that very unlikely scenario,
* we can just assume we have FPU access - typically
* to save the FP state - we'll just take a #NM
* fault and get the FPU access back.
*/
static inline int fpregs_active(void)
{
return current->thread.fpu.fpregs_active;
}
/* /*
* FPU state switching for scheduling. * FPU state switching for scheduling.
* *
@ -571,14 +527,13 @@ static inline int fpregs_active(void)
static inline void static inline void
switch_fpu_prepare(struct fpu *old_fpu, int cpu) switch_fpu_prepare(struct fpu *old_fpu, int cpu)
{ {
if (old_fpu->fpregs_active) { if (old_fpu->initialized) {
if (!copy_fpregs_to_fpstate(old_fpu)) if (!copy_fpregs_to_fpstate(old_fpu))
old_fpu->last_cpu = -1; old_fpu->last_cpu = -1;
else else
old_fpu->last_cpu = cpu; old_fpu->last_cpu = cpu;
/* But leave fpu_fpregs_owner_ctx! */ /* But leave fpu_fpregs_owner_ctx! */
old_fpu->fpregs_active = 0;
trace_x86_fpu_regs_deactivated(old_fpu); trace_x86_fpu_regs_deactivated(old_fpu);
} else } else
old_fpu->last_cpu = -1; old_fpu->last_cpu = -1;
@ -595,7 +550,7 @@ switch_fpu_prepare(struct fpu *old_fpu, int cpu)
static inline void switch_fpu_finish(struct fpu *new_fpu, int cpu) static inline void switch_fpu_finish(struct fpu *new_fpu, int cpu)
{ {
bool preload = static_cpu_has(X86_FEATURE_FPU) && bool preload = static_cpu_has(X86_FEATURE_FPU) &&
new_fpu->fpstate_active; new_fpu->initialized;
if (preload) { if (preload) {
if (!fpregs_state_valid(new_fpu, cpu)) if (!fpregs_state_valid(new_fpu, cpu))
@ -617,8 +572,7 @@ static inline void user_fpu_begin(void)
struct fpu *fpu = &current->thread.fpu; struct fpu *fpu = &current->thread.fpu;
preempt_disable(); preempt_disable();
if (!fpregs_active()) fpregs_activate(fpu);
fpregs_activate(fpu);
preempt_enable(); preempt_enable();
} }

View File

@ -68,6 +68,9 @@ struct fxregs_state {
/* Default value for fxregs_state.mxcsr: */ /* Default value for fxregs_state.mxcsr: */
#define MXCSR_DEFAULT 0x1f80 #define MXCSR_DEFAULT 0x1f80
/* Copy both mxcsr & mxcsr_flags with a single u64 memcpy: */
#define MXCSR_AND_FLAGS_SIZE sizeof(u64)
/* /*
* Software based FPU emulation state. This is arbitrary really, * Software based FPU emulation state. This is arbitrary really,
* it matches the x87 format to make it easier to understand: * it matches the x87 format to make it easier to understand:
@ -290,36 +293,13 @@ struct fpu {
unsigned int last_cpu; unsigned int last_cpu;
/* /*
* @fpstate_active: * @initialized:
* *
* This flag indicates whether this context is active: if the task * This flag indicates whether this context is initialized: if the task
* is not running then we can restore from this context, if the task * is not running then we can restore from this context, if the task
* is running then we should save into this context. * is running then we should save into this context.
*/ */
unsigned char fpstate_active; unsigned char initialized;
/*
* @fpregs_active:
*
* This flag determines whether a given context is actively
* loaded into the FPU's registers and that those registers
* represent the task's current FPU state.
*
* Note the interaction with fpstate_active:
*
* # task does not use the FPU:
* fpstate_active == 0
*
* # task uses the FPU and regs are active:
* fpstate_active == 1 && fpregs_active == 1
*
* # the regs are inactive but still match fpstate:
* fpstate_active == 1 && fpregs_active == 0 && fpregs_owner == fpu
*
* The third state is what we use for the lazy restore optimization
* on lazy-switching CPUs.
*/
unsigned char fpregs_active;
/* /*
* @state: * @state:

View File

@ -48,8 +48,12 @@ void fpu__xstate_clear_all_cpu_caps(void);
void *get_xsave_addr(struct xregs_state *xsave, int xstate); void *get_xsave_addr(struct xregs_state *xsave, int xstate);
const void *get_xsave_field_ptr(int xstate_field); const void *get_xsave_field_ptr(int xstate_field);
int using_compacted_format(void); int using_compacted_format(void);
int copyout_from_xsaves(unsigned int pos, unsigned int count, void *kbuf, int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset, unsigned int size);
void __user *ubuf, struct xregs_state *xsave); int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned int offset, unsigned int size);
int copyin_to_xsaves(const void *kbuf, const void __user *ubuf, int copy_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf);
struct xregs_state *xsave); int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf);
/* Validate an xstate header supplied by userspace (ptrace or sigreturn) */
extern int validate_xstate_header(const struct xstate_header *hdr);
#endif #endif

View File

@ -158,17 +158,6 @@ struct thread_info {
*/ */
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
static inline unsigned long current_stack_pointer(void)
{
unsigned long sp;
#ifdef CONFIG_X86_64
asm("mov %%rsp,%0" : "=g" (sp));
#else
asm("mov %%esp,%0" : "=g" (sp));
#endif
return sp;
}
/* /*
* Walks up the stack frames to make sure that the specified object is * Walks up the stack frames to make sure that the specified object is
* entirely contained by a single stack frame. * entirely contained by a single stack frame.

View File

@ -12,25 +12,22 @@ DECLARE_EVENT_CLASS(x86_fpu,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(struct fpu *, fpu) __field(struct fpu *, fpu)
__field(bool, fpregs_active) __field(bool, initialized)
__field(bool, fpstate_active)
__field(u64, xfeatures) __field(u64, xfeatures)
__field(u64, xcomp_bv) __field(u64, xcomp_bv)
), ),
TP_fast_assign( TP_fast_assign(
__entry->fpu = fpu; __entry->fpu = fpu;
__entry->fpregs_active = fpu->fpregs_active; __entry->initialized = fpu->initialized;
__entry->fpstate_active = fpu->fpstate_active;
if (boot_cpu_has(X86_FEATURE_OSXSAVE)) { if (boot_cpu_has(X86_FEATURE_OSXSAVE)) {
__entry->xfeatures = fpu->state.xsave.header.xfeatures; __entry->xfeatures = fpu->state.xsave.header.xfeatures;
__entry->xcomp_bv = fpu->state.xsave.header.xcomp_bv; __entry->xcomp_bv = fpu->state.xsave.header.xcomp_bv;
} }
), ),
TP_printk("x86/fpu: %p fpregs_active: %d fpstate_active: %d xfeatures: %llx xcomp_bv: %llx", TP_printk("x86/fpu: %p initialized: %d xfeatures: %llx xcomp_bv: %llx",
__entry->fpu, __entry->fpu,
__entry->fpregs_active, __entry->initialized,
__entry->fpstate_active,
__entry->xfeatures, __entry->xfeatures,
__entry->xcomp_bv __entry->xcomp_bv
) )

View File

@ -337,7 +337,7 @@ do { \
_ASM_EXTABLE(1b, 4b) \ _ASM_EXTABLE(1b, 4b) \
_ASM_EXTABLE(2b, 4b) \ _ASM_EXTABLE(2b, 4b) \
: "=r" (retval), "=&A"(x) \ : "=r" (retval), "=&A"(x) \
: "m" (__m(__ptr)), "m" __m(((u32 *)(__ptr)) + 1), \ : "m" (__m(__ptr)), "m" __m(((u32 __user *)(__ptr)) + 1), \
"i" (errret), "0" (retval)); \ "i" (errret), "0" (retval)); \
}) })

View File

@ -551,13 +551,13 @@ static inline void
MULTI_update_descriptor(struct multicall_entry *mcl, u64 maddr, MULTI_update_descriptor(struct multicall_entry *mcl, u64 maddr,
struct desc_struct desc) struct desc_struct desc)
{ {
u32 *p = (u32 *) &desc;
mcl->op = __HYPERVISOR_update_descriptor; mcl->op = __HYPERVISOR_update_descriptor;
if (sizeof(maddr) == sizeof(long)) { if (sizeof(maddr) == sizeof(long)) {
mcl->args[0] = maddr; mcl->args[0] = maddr;
mcl->args[1] = *(unsigned long *)&desc; mcl->args[1] = *(unsigned long *)&desc;
} else { } else {
u32 *p = (u32 *)&desc;
mcl->args[0] = maddr; mcl->args[0] = maddr;
mcl->args[1] = maddr >> 32; mcl->args[1] = maddr >> 32;
mcl->args[2] = *p++; mcl->args[2] = *p++;

View File

@ -100,7 +100,7 @@ void __kernel_fpu_begin(void)
kernel_fpu_disable(); kernel_fpu_disable();
if (fpu->fpregs_active) { if (fpu->initialized) {
/* /*
* Ignore return value -- we don't care if reg state * Ignore return value -- we don't care if reg state
* is clobbered. * is clobbered.
@ -116,7 +116,7 @@ void __kernel_fpu_end(void)
{ {
struct fpu *fpu = &current->thread.fpu; struct fpu *fpu = &current->thread.fpu;
if (fpu->fpregs_active) if (fpu->initialized)
copy_kernel_to_fpregs(&fpu->state); copy_kernel_to_fpregs(&fpu->state);
kernel_fpu_enable(); kernel_fpu_enable();
@ -148,7 +148,7 @@ void fpu__save(struct fpu *fpu)
preempt_disable(); preempt_disable();
trace_x86_fpu_before_save(fpu); trace_x86_fpu_before_save(fpu);
if (fpu->fpregs_active) { if (fpu->initialized) {
if (!copy_fpregs_to_fpstate(fpu)) { if (!copy_fpregs_to_fpstate(fpu)) {
copy_kernel_to_fpregs(&fpu->state); copy_kernel_to_fpregs(&fpu->state);
} }
@ -189,10 +189,9 @@ EXPORT_SYMBOL_GPL(fpstate_init);
int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)
{ {
dst_fpu->fpregs_active = 0;
dst_fpu->last_cpu = -1; dst_fpu->last_cpu = -1;
if (!src_fpu->fpstate_active || !static_cpu_has(X86_FEATURE_FPU)) if (!src_fpu->initialized || !static_cpu_has(X86_FEATURE_FPU))
return 0; return 0;
WARN_ON_FPU(src_fpu != &current->thread.fpu); WARN_ON_FPU(src_fpu != &current->thread.fpu);
@ -206,26 +205,14 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)
/* /*
* Save current FPU registers directly into the child * Save current FPU registers directly into the child
* FPU context, without any memory-to-memory copying. * FPU context, without any memory-to-memory copying.
* In lazy mode, if the FPU context isn't loaded into
* fpregs, CR0.TS will be set and do_device_not_available
* will load the FPU context.
* *
* We have to do all this with preemption disabled, * ( The function 'fails' in the FNSAVE case, which destroys
* mostly because of the FNSAVE case, because in that * register contents so we have to copy them back. )
* case we must not allow preemption in the window
* between the FNSAVE and us marking the context lazy.
*
* It shouldn't be an issue as even FNSAVE is plenty
* fast in terms of critical section length.
*/ */
preempt_disable();
if (!copy_fpregs_to_fpstate(dst_fpu)) { if (!copy_fpregs_to_fpstate(dst_fpu)) {
memcpy(&src_fpu->state, &dst_fpu->state, memcpy(&src_fpu->state, &dst_fpu->state, fpu_kernel_xstate_size);
fpu_kernel_xstate_size);
copy_kernel_to_fpregs(&src_fpu->state); copy_kernel_to_fpregs(&src_fpu->state);
} }
preempt_enable();
trace_x86_fpu_copy_src(src_fpu); trace_x86_fpu_copy_src(src_fpu);
trace_x86_fpu_copy_dst(dst_fpu); trace_x86_fpu_copy_dst(dst_fpu);
@ -237,45 +224,48 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)
* Activate the current task's in-memory FPU context, * Activate the current task's in-memory FPU context,
* if it has not been used before: * if it has not been used before:
*/ */
void fpu__activate_curr(struct fpu *fpu) void fpu__initialize(struct fpu *fpu)
{ {
WARN_ON_FPU(fpu != &current->thread.fpu); WARN_ON_FPU(fpu != &current->thread.fpu);
if (!fpu->fpstate_active) { if (!fpu->initialized) {
fpstate_init(&fpu->state); fpstate_init(&fpu->state);
trace_x86_fpu_init_state(fpu); trace_x86_fpu_init_state(fpu);
trace_x86_fpu_activate_state(fpu); trace_x86_fpu_activate_state(fpu);
/* Safe to do for the current task: */ /* Safe to do for the current task: */
fpu->fpstate_active = 1; fpu->initialized = 1;
} }
} }
EXPORT_SYMBOL_GPL(fpu__activate_curr); EXPORT_SYMBOL_GPL(fpu__initialize);
/* /*
* This function must be called before we read a task's fpstate. * This function must be called before we read a task's fpstate.
* *
* If the task has not used the FPU before then initialize its * There's two cases where this gets called:
* fpstate. *
* - for the current task (when coredumping), in which case we have
* to save the latest FPU registers into the fpstate,
*
* - or it's called for stopped tasks (ptrace), in which case the
* registers were already saved by the context-switch code when
* the task scheduled out - we only have to initialize the registers
* if they've never been initialized.
* *
* If the task has used the FPU before then save it. * If the task has used the FPU before then save it.
*/ */
void fpu__activate_fpstate_read(struct fpu *fpu) void fpu__prepare_read(struct fpu *fpu)
{ {
/* if (fpu == &current->thread.fpu) {
* If fpregs are active (in the current CPU), then
* copy them to the fpstate:
*/
if (fpu->fpregs_active) {
fpu__save(fpu); fpu__save(fpu);
} else { } else {
if (!fpu->fpstate_active) { if (!fpu->initialized) {
fpstate_init(&fpu->state); fpstate_init(&fpu->state);
trace_x86_fpu_init_state(fpu); trace_x86_fpu_init_state(fpu);
trace_x86_fpu_activate_state(fpu); trace_x86_fpu_activate_state(fpu);
/* Safe to do for current and for stopped child tasks: */ /* Safe to do for current and for stopped child tasks: */
fpu->fpstate_active = 1; fpu->initialized = 1;
} }
} }
} }
@ -283,17 +273,17 @@ void fpu__activate_fpstate_read(struct fpu *fpu)
/* /*
* This function must be called before we write a task's fpstate. * This function must be called before we write a task's fpstate.
* *
* If the task has used the FPU before then unlazy it. * If the task has used the FPU before then invalidate any cached FPU registers.
* If the task has not used the FPU before then initialize its fpstate. * If the task has not used the FPU before then initialize its fpstate.
* *
* After this function call, after registers in the fpstate are * After this function call, after registers in the fpstate are
* modified and the child task has woken up, the child task will * modified and the child task has woken up, the child task will
* restore the modified FPU state from the modified context. If we * restore the modified FPU state from the modified context. If we
* didn't clear its lazy status here then the lazy in-registers * didn't clear its cached status here then the cached in-registers
* state pending on its former CPU could be restored, corrupting * state pending on its former CPU could be restored, corrupting
* the modifications. * the modifications.
*/ */
void fpu__activate_fpstate_write(struct fpu *fpu) void fpu__prepare_write(struct fpu *fpu)
{ {
/* /*
* Only stopped child tasks can be used to modify the FPU * Only stopped child tasks can be used to modify the FPU
@ -301,8 +291,8 @@ void fpu__activate_fpstate_write(struct fpu *fpu)
*/ */
WARN_ON_FPU(fpu == &current->thread.fpu); WARN_ON_FPU(fpu == &current->thread.fpu);
if (fpu->fpstate_active) { if (fpu->initialized) {
/* Invalidate any lazy state: */ /* Invalidate any cached state: */
__fpu_invalidate_fpregs_state(fpu); __fpu_invalidate_fpregs_state(fpu);
} else { } else {
fpstate_init(&fpu->state); fpstate_init(&fpu->state);
@ -310,73 +300,10 @@ void fpu__activate_fpstate_write(struct fpu *fpu)
trace_x86_fpu_activate_state(fpu); trace_x86_fpu_activate_state(fpu);
/* Safe to do for stopped child tasks: */ /* Safe to do for stopped child tasks: */
fpu->fpstate_active = 1; fpu->initialized = 1;
} }
} }
/*
* This function must be called before we write the current
* task's fpstate.
*
* This call gets the current FPU register state and moves
* it in to the 'fpstate'. Preemption is disabled so that
* no writes to the 'fpstate' can occur from context
* swiches.
*
* Must be followed by a fpu__current_fpstate_write_end().
*/
void fpu__current_fpstate_write_begin(void)
{
struct fpu *fpu = &current->thread.fpu;
/*
* Ensure that the context-switching code does not write
* over the fpstate while we are doing our update.
*/
preempt_disable();
/*
* Move the fpregs in to the fpu's 'fpstate'.
*/
fpu__activate_fpstate_read(fpu);
/*
* The caller is about to write to 'fpu'. Ensure that no
* CPU thinks that its fpregs match the fpstate. This
* ensures we will not be lazy and skip a XRSTOR in the
* future.
*/
__fpu_invalidate_fpregs_state(fpu);
}
/*
* This function must be paired with fpu__current_fpstate_write_begin()
*
* This will ensure that the modified fpstate gets placed back in
* the fpregs if necessary.
*
* Note: This function may be called whether or not an _actual_
* write to the fpstate occurred.
*/
void fpu__current_fpstate_write_end(void)
{
struct fpu *fpu = &current->thread.fpu;
/*
* 'fpu' now has an updated copy of the state, but the
* registers may still be out of date. Update them with
* an XRSTOR if they are active.
*/
if (fpregs_active())
copy_kernel_to_fpregs(&fpu->state);
/*
* Our update is done and the fpregs/fpstate are in sync
* if necessary. Context switches can happen again.
*/
preempt_enable();
}
/* /*
* 'fpu__restore()' is called to copy FPU registers from * 'fpu__restore()' is called to copy FPU registers from
* the FPU fpstate to the live hw registers and to activate * the FPU fpstate to the live hw registers and to activate
@ -389,7 +316,7 @@ void fpu__current_fpstate_write_end(void)
*/ */
void fpu__restore(struct fpu *fpu) void fpu__restore(struct fpu *fpu)
{ {
fpu__activate_curr(fpu); fpu__initialize(fpu);
/* Avoid __kernel_fpu_begin() right after fpregs_activate() */ /* Avoid __kernel_fpu_begin() right after fpregs_activate() */
kernel_fpu_disable(); kernel_fpu_disable();
@ -414,15 +341,17 @@ void fpu__drop(struct fpu *fpu)
{ {
preempt_disable(); preempt_disable();
if (fpu->fpregs_active) { if (fpu == &current->thread.fpu) {
/* Ignore delayed exceptions from user space */ if (fpu->initialized) {
asm volatile("1: fwait\n" /* Ignore delayed exceptions from user space */
"2:\n" asm volatile("1: fwait\n"
_ASM_EXTABLE(1b, 2b)); "2:\n"
fpregs_deactivate(fpu); _ASM_EXTABLE(1b, 2b));
fpregs_deactivate(fpu);
}
} }
fpu->fpstate_active = 0; fpu->initialized = 0;
trace_x86_fpu_dropped(fpu); trace_x86_fpu_dropped(fpu);
@ -462,9 +391,11 @@ void fpu__clear(struct fpu *fpu)
* Make sure fpstate is cleared and initialized. * Make sure fpstate is cleared and initialized.
*/ */
if (static_cpu_has(X86_FEATURE_FPU)) { if (static_cpu_has(X86_FEATURE_FPU)) {
fpu__activate_curr(fpu); preempt_disable();
fpu__initialize(fpu);
user_fpu_begin(); user_fpu_begin();
copy_init_fpstate_to_fpregs(); copy_init_fpstate_to_fpregs();
preempt_enable();
} }
} }

View File

@ -240,7 +240,7 @@ static void __init fpu__init_system_ctx_switch(void)
WARN_ON_FPU(!on_boot_cpu); WARN_ON_FPU(!on_boot_cpu);
on_boot_cpu = 0; on_boot_cpu = 0;
WARN_ON_FPU(current->thread.fpu.fpstate_active); WARN_ON_FPU(current->thread.fpu.initialized);
} }
/* /*

View File

@ -16,14 +16,14 @@ int regset_fpregs_active(struct task_struct *target, const struct user_regset *r
{ {
struct fpu *target_fpu = &target->thread.fpu; struct fpu *target_fpu = &target->thread.fpu;
return target_fpu->fpstate_active ? regset->n : 0; return target_fpu->initialized ? regset->n : 0;
} }
int regset_xregset_fpregs_active(struct task_struct *target, const struct user_regset *regset) int regset_xregset_fpregs_active(struct task_struct *target, const struct user_regset *regset)
{ {
struct fpu *target_fpu = &target->thread.fpu; struct fpu *target_fpu = &target->thread.fpu;
if (boot_cpu_has(X86_FEATURE_FXSR) && target_fpu->fpstate_active) if (boot_cpu_has(X86_FEATURE_FXSR) && target_fpu->initialized)
return regset->n; return regset->n;
else else
return 0; return 0;
@ -38,7 +38,7 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
if (!boot_cpu_has(X86_FEATURE_FXSR)) if (!boot_cpu_has(X86_FEATURE_FXSR))
return -ENODEV; return -ENODEV;
fpu__activate_fpstate_read(fpu); fpu__prepare_read(fpu);
fpstate_sanitize_xstate(fpu); fpstate_sanitize_xstate(fpu);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
@ -55,7 +55,7 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
if (!boot_cpu_has(X86_FEATURE_FXSR)) if (!boot_cpu_has(X86_FEATURE_FXSR))
return -ENODEV; return -ENODEV;
fpu__activate_fpstate_write(fpu); fpu__prepare_write(fpu);
fpstate_sanitize_xstate(fpu); fpstate_sanitize_xstate(fpu);
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
@ -89,10 +89,13 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
xsave = &fpu->state.xsave; xsave = &fpu->state.xsave;
fpu__activate_fpstate_read(fpu); fpu__prepare_read(fpu);
if (using_compacted_format()) { if (using_compacted_format()) {
ret = copyout_from_xsaves(pos, count, kbuf, ubuf, xsave); if (kbuf)
ret = copy_xstate_to_kernel(kbuf, xsave, pos, count);
else
ret = copy_xstate_to_user(ubuf, xsave, pos, count);
} else { } else {
fpstate_sanitize_xstate(fpu); fpstate_sanitize_xstate(fpu);
/* /*
@ -129,12 +132,23 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
xsave = &fpu->state.xsave; xsave = &fpu->state.xsave;
fpu__activate_fpstate_write(fpu); fpu__prepare_write(fpu);
if (boot_cpu_has(X86_FEATURE_XSAVES)) if (using_compacted_format()) {
ret = copyin_to_xsaves(kbuf, ubuf, xsave); if (kbuf)
else ret = copy_kernel_to_xstate(xsave, kbuf);
else
ret = copy_user_to_xstate(xsave, ubuf);
} else {
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1);
if (!ret)
ret = validate_xstate_header(&xsave->header);
}
/*
* mxcsr reserved bits must be masked to zero for security reasons.
*/
xsave->i387.mxcsr &= mxcsr_feature_mask;
/* /*
* In case of failure, mark all states as init: * In case of failure, mark all states as init:
@ -142,16 +156,6 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
if (ret) if (ret)
fpstate_init(&fpu->state); fpstate_init(&fpu->state);
/*
* mxcsr reserved bits must be masked to zero for security reasons.
*/
xsave->i387.mxcsr &= mxcsr_feature_mask;
xsave->header.xfeatures &= xfeatures_mask;
/*
* These bits must be zero.
*/
memset(&xsave->header.reserved, 0, 48);
return ret; return ret;
} }
@ -299,7 +303,7 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset,
struct fpu *fpu = &target->thread.fpu; struct fpu *fpu = &target->thread.fpu;
struct user_i387_ia32_struct env; struct user_i387_ia32_struct env;
fpu__activate_fpstate_read(fpu); fpu__prepare_read(fpu);
if (!boot_cpu_has(X86_FEATURE_FPU)) if (!boot_cpu_has(X86_FEATURE_FPU))
return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf); return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf);
@ -329,7 +333,7 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
struct user_i387_ia32_struct env; struct user_i387_ia32_struct env;
int ret; int ret;
fpu__activate_fpstate_write(fpu); fpu__prepare_write(fpu);
fpstate_sanitize_xstate(fpu); fpstate_sanitize_xstate(fpu);
if (!boot_cpu_has(X86_FEATURE_FPU)) if (!boot_cpu_has(X86_FEATURE_FPU))
@ -369,7 +373,7 @@ int dump_fpu(struct pt_regs *regs, struct user_i387_struct *ufpu)
struct fpu *fpu = &tsk->thread.fpu; struct fpu *fpu = &tsk->thread.fpu;
int fpvalid; int fpvalid;
fpvalid = fpu->fpstate_active; fpvalid = fpu->initialized;
if (fpvalid) if (fpvalid)
fpvalid = !fpregs_get(tsk, NULL, fpvalid = !fpregs_get(tsk, NULL,
0, sizeof(struct user_i387_ia32_struct), 0, sizeof(struct user_i387_ia32_struct),

View File

@ -155,7 +155,8 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf)
*/ */
int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
{ {
struct xregs_state *xsave = &current->thread.fpu.state.xsave; struct fpu *fpu = &current->thread.fpu;
struct xregs_state *xsave = &fpu->state.xsave;
struct task_struct *tsk = current; struct task_struct *tsk = current;
int ia32_fxstate = (buf != buf_fx); int ia32_fxstate = (buf != buf_fx);
@ -170,13 +171,13 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
sizeof(struct user_i387_ia32_struct), NULL, sizeof(struct user_i387_ia32_struct), NULL,
(struct _fpstate_32 __user *) buf) ? -1 : 1; (struct _fpstate_32 __user *) buf) ? -1 : 1;
if (fpregs_active() || using_compacted_format()) { if (fpu->initialized || using_compacted_format()) {
/* Save the live register state to the user directly. */ /* Save the live register state to the user directly. */
if (copy_fpregs_to_sigframe(buf_fx)) if (copy_fpregs_to_sigframe(buf_fx))
return -1; return -1;
/* Update the thread's fxstate to save the fsave header. */ /* Update the thread's fxstate to save the fsave header. */
if (ia32_fxstate) if (ia32_fxstate)
copy_fxregs_to_kernel(&tsk->thread.fpu); copy_fxregs_to_kernel(fpu);
} else { } else {
/* /*
* It is a *bug* if kernel uses compacted-format for xsave * It is a *bug* if kernel uses compacted-format for xsave
@ -189,7 +190,7 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
return -1; return -1;
} }
fpstate_sanitize_xstate(&tsk->thread.fpu); fpstate_sanitize_xstate(fpu);
if (__copy_to_user(buf_fx, xsave, fpu_user_xstate_size)) if (__copy_to_user(buf_fx, xsave, fpu_user_xstate_size))
return -1; return -1;
} }
@ -213,8 +214,11 @@ sanitize_restored_xstate(struct task_struct *tsk,
struct xstate_header *header = &xsave->header; struct xstate_header *header = &xsave->header;
if (use_xsave()) { if (use_xsave()) {
/* These bits must be zero. */ /*
memset(header->reserved, 0, 48); * Note: we don't need to zero the reserved bits in the
* xstate_header here because we either didn't copy them at all,
* or we checked earlier that they aren't set.
*/
/* /*
* Init the state that is not present in the memory * Init the state that is not present in the memory
@ -223,7 +227,7 @@ sanitize_restored_xstate(struct task_struct *tsk,
if (fx_only) if (fx_only)
header->xfeatures = XFEATURE_MASK_FPSSE; header->xfeatures = XFEATURE_MASK_FPSSE;
else else
header->xfeatures &= (xfeatures_mask & xfeatures); header->xfeatures &= xfeatures;
} }
if (use_fxsr()) { if (use_fxsr()) {
@ -279,7 +283,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
if (!access_ok(VERIFY_READ, buf, size)) if (!access_ok(VERIFY_READ, buf, size))
return -EACCES; return -EACCES;
fpu__activate_curr(fpu); fpu__initialize(fpu);
if (!static_cpu_has(X86_FEATURE_FPU)) if (!static_cpu_has(X86_FEATURE_FPU))
return fpregs_soft_set(current, NULL, return fpregs_soft_set(current, NULL,
@ -307,28 +311,29 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
/* /*
* For 32-bit frames with fxstate, copy the user state to the * For 32-bit frames with fxstate, copy the user state to the
* thread's fpu state, reconstruct fxstate from the fsave * thread's fpu state, reconstruct fxstate from the fsave
* header. Sanitize the copied state etc. * header. Validate and sanitize the copied state.
*/ */
struct fpu *fpu = &tsk->thread.fpu; struct fpu *fpu = &tsk->thread.fpu;
struct user_i387_ia32_struct env; struct user_i387_ia32_struct env;
int err = 0; int err = 0;
/* /*
* Drop the current fpu which clears fpu->fpstate_active. This ensures * Drop the current fpu which clears fpu->initialized. This ensures
* that any context-switch during the copy of the new state, * that any context-switch during the copy of the new state,
* avoids the intermediate state from getting restored/saved. * avoids the intermediate state from getting restored/saved.
* Thus avoiding the new restored state from getting corrupted. * Thus avoiding the new restored state from getting corrupted.
* We will be ready to restore/save the state only after * We will be ready to restore/save the state only after
* fpu->fpstate_active is again set. * fpu->initialized is again set.
*/ */
fpu__drop(fpu); fpu__drop(fpu);
if (using_compacted_format()) { if (using_compacted_format()) {
err = copyin_to_xsaves(NULL, buf_fx, err = copy_user_to_xstate(&fpu->state.xsave, buf_fx);
&fpu->state.xsave);
} else { } else {
err = __copy_from_user(&fpu->state.xsave, err = __copy_from_user(&fpu->state.xsave, buf_fx, state_size);
buf_fx, state_size);
if (!err && state_size > offsetof(struct xregs_state, header))
err = validate_xstate_header(&fpu->state.xsave.header);
} }
if (err || __copy_from_user(&env, buf, sizeof(env))) { if (err || __copy_from_user(&env, buf, sizeof(env))) {
@ -339,7 +344,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
sanitize_restored_xstate(tsk, &env, xfeatures, fx_only); sanitize_restored_xstate(tsk, &env, xfeatures, fx_only);
} }
fpu->fpstate_active = 1; fpu->initialized = 1;
preempt_disable(); preempt_disable();
fpu__restore(fpu); fpu__restore(fpu);
preempt_enable(); preempt_enable();

View File

@ -483,6 +483,30 @@ int using_compacted_format(void)
return boot_cpu_has(X86_FEATURE_XSAVES); return boot_cpu_has(X86_FEATURE_XSAVES);
} }
/* Validate an xstate header supplied by userspace (ptrace or sigreturn) */
int validate_xstate_header(const struct xstate_header *hdr)
{
/* No unknown or supervisor features may be set */
if (hdr->xfeatures & (~xfeatures_mask | XFEATURE_MASK_SUPERVISOR))
return -EINVAL;
/* Userspace must use the uncompacted format */
if (hdr->xcomp_bv)
return -EINVAL;
/*
* If 'reserved' is shrunken to add a new field, make sure to validate
* that new field here!
*/
BUILD_BUG_ON(sizeof(hdr->reserved) != 48);
/* No reserved bits may be set */
if (memchr_inv(hdr->reserved, 0, sizeof(hdr->reserved)))
return -EINVAL;
return 0;
}
static void __xstate_dump_leaves(void) static void __xstate_dump_leaves(void)
{ {
int i; int i;
@ -867,7 +891,7 @@ const void *get_xsave_field_ptr(int xsave_state)
{ {
struct fpu *fpu = &current->thread.fpu; struct fpu *fpu = &current->thread.fpu;
if (!fpu->fpstate_active) if (!fpu->initialized)
return NULL; return NULL;
/* /*
* fpu__save() takes the CPU's xstate registers * fpu__save() takes the CPU's xstate registers
@ -920,48 +944,55 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
} }
#endif /* ! CONFIG_ARCH_HAS_PKEYS */ #endif /* ! CONFIG_ARCH_HAS_PKEYS */
/*
* Weird legacy quirk: SSE and YMM states store information in the
* MXCSR and MXCSR_FLAGS fields of the FP area. That means if the FP
* area is marked as unused in the xfeatures header, we need to copy
* MXCSR and MXCSR_FLAGS if either SSE or YMM are in use.
*/
static inline bool xfeatures_mxcsr_quirk(u64 xfeatures)
{
if (!(xfeatures & (XFEATURE_MASK_SSE|XFEATURE_MASK_YMM)))
return false;
if (xfeatures & XFEATURE_MASK_FP)
return false;
return true;
}
/* /*
* This is similar to user_regset_copyout(), but will not add offset to * This is similar to user_regset_copyout(), but will not add offset to
* the source data pointer or increment pos, count, kbuf, and ubuf. * the source data pointer or increment pos, count, kbuf, and ubuf.
*/ */
static inline int xstate_copyout(unsigned int pos, unsigned int count, static inline void
void *kbuf, void __user *ubuf, __copy_xstate_to_kernel(void *kbuf, const void *data,
const void *data, const int start_pos, unsigned int offset, unsigned int size, unsigned int size_total)
const int end_pos)
{ {
if ((count == 0) || (pos < start_pos)) if (offset < size_total) {
return 0; unsigned int copy = min(size, size_total - offset);
if (end_pos < 0 || pos < end_pos) { memcpy(kbuf + offset, data, copy);
unsigned int copy = (end_pos < 0 ? count : min(count, end_pos - pos));
if (kbuf) {
memcpy(kbuf + pos, data, copy);
} else {
if (__copy_to_user(ubuf + pos, data, copy))
return -EFAULT;
}
} }
return 0;
} }
/* /*
* Convert from kernel XSAVES compacted format to standard format and copy * Convert from kernel XSAVES compacted format to standard format and copy
* to a ptrace buffer. It supports partial copy but pos always starts from * to a kernel-space ptrace buffer.
* zero. This is called from xstateregs_get() and there we check the CPU *
* has XSAVES. * It supports partial copy but pos always starts from zero. This is called
* from xstateregs_get() and there we check the CPU has XSAVES.
*/ */
int copyout_from_xsaves(unsigned int pos, unsigned int count, void *kbuf, int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset_start, unsigned int size_total)
void __user *ubuf, struct xregs_state *xsave)
{ {
unsigned int offset, size; unsigned int offset, size;
int ret, i;
struct xstate_header header; struct xstate_header header;
int i;
/* /*
* Currently copy_regset_to_user() starts from pos 0: * Currently copy_regset_to_user() starts from pos 0:
*/ */
if (unlikely(pos != 0)) if (unlikely(offset_start != 0))
return -EFAULT; return -EFAULT;
/* /*
@ -977,8 +1008,91 @@ int copyout_from_xsaves(unsigned int pos, unsigned int count, void *kbuf,
offset = offsetof(struct xregs_state, header); offset = offsetof(struct xregs_state, header);
size = sizeof(header); size = sizeof(header);
ret = xstate_copyout(offset, size, kbuf, ubuf, &header, 0, count); __copy_xstate_to_kernel(kbuf, &header, offset, size, size_total);
for (i = 0; i < XFEATURE_MAX; i++) {
/*
* Copy only in-use xstates:
*/
if ((header.xfeatures >> i) & 1) {
void *src = __raw_xsave_addr(xsave, 1 << i);
offset = xstate_offsets[i];
size = xstate_sizes[i];
/* The next component has to fit fully into the output buffer: */
if (offset + size > size_total)
break;
__copy_xstate_to_kernel(kbuf, src, offset, size, size_total);
}
}
if (xfeatures_mxcsr_quirk(header.xfeatures)) {
offset = offsetof(struct fxregs_state, mxcsr);
size = MXCSR_AND_FLAGS_SIZE;
__copy_xstate_to_kernel(kbuf, &xsave->i387.mxcsr, offset, size, size_total);
}
/*
* Fill xsave->i387.sw_reserved value for ptrace frame:
*/
offset = offsetof(struct fxregs_state, sw_reserved);
size = sizeof(xstate_fx_sw_bytes);
__copy_xstate_to_kernel(kbuf, xstate_fx_sw_bytes, offset, size, size_total);
return 0;
}
static inline int
__copy_xstate_to_user(void __user *ubuf, const void *data, unsigned int offset, unsigned int size, unsigned int size_total)
{
if (!size)
return 0;
if (offset < size_total) {
unsigned int copy = min(size, size_total - offset);
if (__copy_to_user(ubuf + offset, data, copy))
return -EFAULT;
}
return 0;
}
/*
* Convert from kernel XSAVES compacted format to standard format and copy
* to a user-space buffer. It supports partial copy but pos always starts from
* zero. This is called from xstateregs_get() and there we check the CPU
* has XSAVES.
*/
int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned int offset_start, unsigned int size_total)
{
unsigned int offset, size;
int ret, i;
struct xstate_header header;
/*
* Currently copy_regset_to_user() starts from pos 0:
*/
if (unlikely(offset_start != 0))
return -EFAULT;
/*
* The destination is a ptrace buffer; we put in only user xstates:
*/
memset(&header, 0, sizeof(header));
header.xfeatures = xsave->header.xfeatures;
header.xfeatures &= ~XFEATURE_MASK_SUPERVISOR;
/*
* Copy xregs_state->header:
*/
offset = offsetof(struct xregs_state, header);
size = sizeof(header);
ret = __copy_xstate_to_user(ubuf, &header, offset, size, size_total);
if (ret) if (ret)
return ret; return ret;
@ -992,25 +1106,30 @@ int copyout_from_xsaves(unsigned int pos, unsigned int count, void *kbuf,
offset = xstate_offsets[i]; offset = xstate_offsets[i];
size = xstate_sizes[i]; size = xstate_sizes[i];
ret = xstate_copyout(offset, size, kbuf, ubuf, src, 0, count); /* The next component has to fit fully into the output buffer: */
if (offset + size > size_total)
break;
ret = __copy_xstate_to_user(ubuf, src, offset, size, size_total);
if (ret) if (ret)
return ret; return ret;
if (offset + size >= count)
break;
} }
} }
if (xfeatures_mxcsr_quirk(header.xfeatures)) {
offset = offsetof(struct fxregs_state, mxcsr);
size = MXCSR_AND_FLAGS_SIZE;
__copy_xstate_to_user(ubuf, &xsave->i387.mxcsr, offset, size, size_total);
}
/* /*
* Fill xsave->i387.sw_reserved value for ptrace frame: * Fill xsave->i387.sw_reserved value for ptrace frame:
*/ */
offset = offsetof(struct fxregs_state, sw_reserved); offset = offsetof(struct fxregs_state, sw_reserved);
size = sizeof(xstate_fx_sw_bytes); size = sizeof(xstate_fx_sw_bytes);
ret = xstate_copyout(offset, size, kbuf, ubuf, xstate_fx_sw_bytes, 0, count); ret = __copy_xstate_to_user(ubuf, xstate_fx_sw_bytes, offset, size, size_total);
if (ret) if (ret)
return ret; return ret;
@ -1018,55 +1137,42 @@ int copyout_from_xsaves(unsigned int pos, unsigned int count, void *kbuf,
} }
/* /*
* Convert from a ptrace standard-format buffer to kernel XSAVES format * Convert from a ptrace standard-format kernel buffer to kernel XSAVES format
* and copy to the target thread. This is called from xstateregs_set() and * and copy to the target thread. This is called from xstateregs_set().
* there we check the CPU has XSAVES and a whole standard-sized buffer
* exists.
*/ */
int copyin_to_xsaves(const void *kbuf, const void __user *ubuf, int copy_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf)
struct xregs_state *xsave)
{ {
unsigned int offset, size; unsigned int offset, size;
int i; int i;
u64 xfeatures; struct xstate_header hdr;
u64 allowed_features;
offset = offsetof(struct xregs_state, header); offset = offsetof(struct xregs_state, header);
size = sizeof(xfeatures); size = sizeof(hdr);
if (kbuf) { memcpy(&hdr, kbuf + offset, size);
memcpy(&xfeatures, kbuf + offset, size);
} else {
if (__copy_from_user(&xfeatures, ubuf + offset, size))
return -EFAULT;
}
/* if (validate_xstate_header(&hdr))
* Reject if the user sets any disabled or supervisor features:
*/
allowed_features = xfeatures_mask & ~XFEATURE_MASK_SUPERVISOR;
if (xfeatures & ~allowed_features)
return -EINVAL; return -EINVAL;
for (i = 0; i < XFEATURE_MAX; i++) { for (i = 0; i < XFEATURE_MAX; i++) {
u64 mask = ((u64)1 << i); u64 mask = ((u64)1 << i);
if (xfeatures & mask) { if (hdr.xfeatures & mask) {
void *dst = __raw_xsave_addr(xsave, 1 << i); void *dst = __raw_xsave_addr(xsave, 1 << i);
offset = xstate_offsets[i]; offset = xstate_offsets[i];
size = xstate_sizes[i]; size = xstate_sizes[i];
if (kbuf) { memcpy(dst, kbuf + offset, size);
memcpy(dst, kbuf + offset, size);
} else {
if (__copy_from_user(dst, ubuf + offset, size))
return -EFAULT;
}
} }
} }
if (xfeatures_mxcsr_quirk(hdr.xfeatures)) {
offset = offsetof(struct fxregs_state, mxcsr);
size = MXCSR_AND_FLAGS_SIZE;
memcpy(&xsave->i387.mxcsr, kbuf + offset, size);
}
/* /*
* The state that came in from userspace was user-state only. * The state that came in from userspace was user-state only.
* Mask all the user states out of 'xfeatures': * Mask all the user states out of 'xfeatures':
@ -1076,7 +1182,63 @@ int copyin_to_xsaves(const void *kbuf, const void __user *ubuf,
/* /*
* Add back in the features that came in from userspace: * Add back in the features that came in from userspace:
*/ */
xsave->header.xfeatures |= xfeatures; xsave->header.xfeatures |= hdr.xfeatures;
return 0;
}
/*
* Convert from a ptrace or sigreturn standard-format user-space buffer to
* kernel XSAVES format and copy to the target thread. This is called from
* xstateregs_set(), as well as potentially from the sigreturn() and
* rt_sigreturn() system calls.
*/
int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf)
{
unsigned int offset, size;
int i;
struct xstate_header hdr;
offset = offsetof(struct xregs_state, header);
size = sizeof(hdr);
if (__copy_from_user(&hdr, ubuf + offset, size))
return -EFAULT;
if (validate_xstate_header(&hdr))
return -EINVAL;
for (i = 0; i < XFEATURE_MAX; i++) {
u64 mask = ((u64)1 << i);
if (hdr.xfeatures & mask) {
void *dst = __raw_xsave_addr(xsave, 1 << i);
offset = xstate_offsets[i];
size = xstate_sizes[i];
if (__copy_from_user(dst, ubuf + offset, size))
return -EFAULT;
}
}
if (xfeatures_mxcsr_quirk(hdr.xfeatures)) {
offset = offsetof(struct fxregs_state, mxcsr);
size = MXCSR_AND_FLAGS_SIZE;
if (__copy_from_user(&xsave->i387.mxcsr, ubuf + offset, size))
return -EFAULT;
}
/*
* The state that came in from userspace was user-state only.
* Mask all the user states out of 'xfeatures':
*/
xsave->header.xfeatures &= XFEATURE_MASK_SUPERVISOR;
/*
* Add back in the features that came in from userspace:
*/
xsave->header.xfeatures |= hdr.xfeatures;
return 0; return 0;
} }

View File

@ -64,7 +64,7 @@ static void call_on_stack(void *func, void *stack)
static inline void *current_stack(void) static inline void *current_stack(void)
{ {
return (void *)(current_stack_pointer() & ~(THREAD_SIZE - 1)); return (void *)(current_stack_pointer & ~(THREAD_SIZE - 1));
} }
static inline int execute_on_irq_stack(int overflow, struct irq_desc *desc) static inline int execute_on_irq_stack(int overflow, struct irq_desc *desc)
@ -88,7 +88,7 @@ static inline int execute_on_irq_stack(int overflow, struct irq_desc *desc)
/* Save the next esp at the bottom of the stack */ /* Save the next esp at the bottom of the stack */
prev_esp = (u32 *)irqstk; prev_esp = (u32 *)irqstk;
*prev_esp = current_stack_pointer(); *prev_esp = current_stack_pointer;
if (unlikely(overflow)) if (unlikely(overflow))
call_on_stack(print_stack_overflow, isp); call_on_stack(print_stack_overflow, isp);
@ -139,7 +139,7 @@ void do_softirq_own_stack(void)
/* Push the previous esp onto the stack */ /* Push the previous esp onto the stack */
prev_esp = (u32 *)irqstk; prev_esp = (u32 *)irqstk;
*prev_esp = current_stack_pointer(); *prev_esp = current_stack_pointer;
call_on_stack(__do_softirq, isp); call_on_stack(__do_softirq, isp);
} }

View File

@ -299,7 +299,7 @@ static int __init create_setup_data_nodes(struct kobject *parent)
return 0; return 0;
out_clean_nodes: out_clean_nodes:
for (j = i - 1; j > 0; j--) for (j = i - 1; j >= 0; j--)
cleanup_setup_data_node(*(kobjp + j)); cleanup_setup_data_node(*(kobjp + j));
kfree(kobjp); kfree(kobjp);
out_setup_data_kobj: out_setup_data_kobj:

View File

@ -140,7 +140,8 @@ void kvm_async_pf_task_wait(u32 token)
n.token = token; n.token = token;
n.cpu = smp_processor_id(); n.cpu = smp_processor_id();
n.halted = is_idle_task(current) || preempt_count() > 1; n.halted = is_idle_task(current) || preempt_count() > 1 ||
rcu_preempt_depth();
init_swait_queue_head(&n.wq); init_swait_queue_head(&n.wq);
hlist_add_head(&n.link, &b->list); hlist_add_head(&n.link, &b->list);
raw_spin_unlock(&b->lock); raw_spin_unlock(&b->lock);

View File

@ -263,7 +263,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
sp = (unsigned long) ka->sa.sa_restorer; sp = (unsigned long) ka->sa.sa_restorer;
} }
if (fpu->fpstate_active) { if (fpu->initialized) {
sp = fpu__alloc_mathframe(sp, IS_ENABLED(CONFIG_X86_32), sp = fpu__alloc_mathframe(sp, IS_ENABLED(CONFIG_X86_32),
&buf_fx, &math_size); &buf_fx, &math_size);
*fpstate = (void __user *)sp; *fpstate = (void __user *)sp;
@ -279,7 +279,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
return (void __user *)-1L; return (void __user *)-1L;
/* save i387 and extended state */ /* save i387 and extended state */
if (fpu->fpstate_active && if (fpu->initialized &&
copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size) < 0) copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size) < 0)
return (void __user *)-1L; return (void __user *)-1L;
@ -755,7 +755,7 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
/* /*
* Ensure the signal handler starts with the new fpu state. * Ensure the signal handler starts with the new fpu state.
*/ */
if (fpu->fpstate_active) if (fpu->initialized)
fpu__clear(fpu); fpu__clear(fpu);
} }
signal_setup_done(failed, ksig, stepping); signal_setup_done(failed, ksig, stepping);

View File

@ -142,7 +142,7 @@ void ist_begin_non_atomic(struct pt_regs *regs)
* from double_fault. * from double_fault.
*/ */
BUG_ON((unsigned long)(current_top_of_stack() - BUG_ON((unsigned long)(current_top_of_stack() -
current_stack_pointer()) >= THREAD_SIZE); current_stack_pointer) >= THREAD_SIZE);
preempt_enable_no_resched(); preempt_enable_no_resched();
} }

View File

@ -200,6 +200,8 @@ struct loaded_vmcs {
int cpu; int cpu;
bool launched; bool launched;
bool nmi_known_unmasked; bool nmi_known_unmasked;
unsigned long vmcs_host_cr3; /* May not match real cr3 */
unsigned long vmcs_host_cr4; /* May not match real cr4 */
struct list_head loaded_vmcss_on_cpu_link; struct list_head loaded_vmcss_on_cpu_link;
}; };
@ -600,8 +602,6 @@ struct vcpu_vmx {
int gs_ldt_reload_needed; int gs_ldt_reload_needed;
int fs_reload_needed; int fs_reload_needed;
u64 msr_host_bndcfgs; u64 msr_host_bndcfgs;
unsigned long vmcs_host_cr3; /* May not match real cr3 */
unsigned long vmcs_host_cr4; /* May not match real cr4 */
} host_state; } host_state;
struct { struct {
int vm86_active; int vm86_active;
@ -2202,46 +2202,44 @@ static void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu)
struct pi_desc old, new; struct pi_desc old, new;
unsigned int dest; unsigned int dest;
if (!kvm_arch_has_assigned_device(vcpu->kvm) || /*
!irq_remapping_cap(IRQ_POSTING_CAP) || * In case of hot-plug or hot-unplug, we may have to undo
!kvm_vcpu_apicv_active(vcpu)) * vmx_vcpu_pi_put even if there is no assigned device. And we
* always keep PI.NDST up to date for simplicity: it makes the
* code easier, and CPU migration is not a fast path.
*/
if (!pi_test_sn(pi_desc) && vcpu->cpu == cpu)
return; return;
/*
* First handle the simple case where no cmpxchg is necessary; just
* allow posting non-urgent interrupts.
*
* If the 'nv' field is POSTED_INTR_WAKEUP_VECTOR, do not change
* PI.NDST: pi_post_block will do it for us and the wakeup_handler
* expects the VCPU to be on the blocked_vcpu_list that matches
* PI.NDST.
*/
if (pi_desc->nv == POSTED_INTR_WAKEUP_VECTOR ||
vcpu->cpu == cpu) {
pi_clear_sn(pi_desc);
return;
}
/* The full case. */
do { do {
old.control = new.control = pi_desc->control; old.control = new.control = pi_desc->control;
/* dest = cpu_physical_id(cpu);
* If 'nv' field is POSTED_INTR_WAKEUP_VECTOR, there
* are two possible cases:
* 1. After running 'pre_block', context switch
* happened. For this case, 'sn' was set in
* vmx_vcpu_put(), so we need to clear it here.
* 2. After running 'pre_block', we were blocked,
* and woken up by some other guy. For this case,
* we don't need to do anything, 'pi_post_block'
* will do everything for us. However, we cannot
* check whether it is case #1 or case #2 here
* (maybe, not needed), so we also clear sn here,
* I think it is not a big deal.
*/
if (pi_desc->nv != POSTED_INTR_WAKEUP_VECTOR) {
if (vcpu->cpu != cpu) {
dest = cpu_physical_id(cpu);
if (x2apic_enabled()) if (x2apic_enabled())
new.ndst = dest; new.ndst = dest;
else else
new.ndst = (dest << 8) & 0xFF00; new.ndst = (dest << 8) & 0xFF00;
}
/* set 'NV' to 'notification vector' */
new.nv = POSTED_INTR_VECTOR;
}
/* Allow posting non-urgent interrupts */
new.sn = 0; new.sn = 0;
} while (cmpxchg(&pi_desc->control, old.control, } while (cmpxchg64(&pi_desc->control, old.control,
new.control) != old.control); new.control) != old.control);
} }
static void decache_tsc_multiplier(struct vcpu_vmx *vmx) static void decache_tsc_multiplier(struct vcpu_vmx *vmx)
@ -5178,12 +5176,12 @@ static void vmx_set_constant_host_state(struct vcpu_vmx *vmx)
*/ */
cr3 = __read_cr3(); cr3 = __read_cr3();
vmcs_writel(HOST_CR3, cr3); /* 22.2.3 FIXME: shadow tables */ vmcs_writel(HOST_CR3, cr3); /* 22.2.3 FIXME: shadow tables */
vmx->host_state.vmcs_host_cr3 = cr3; vmx->loaded_vmcs->vmcs_host_cr3 = cr3;
/* Save the most likely value for this task's CR4 in the VMCS. */ /* Save the most likely value for this task's CR4 in the VMCS. */
cr4 = cr4_read_shadow(); cr4 = cr4_read_shadow();
vmcs_writel(HOST_CR4, cr4); /* 22.2.3, 22.2.5 */ vmcs_writel(HOST_CR4, cr4); /* 22.2.3, 22.2.5 */
vmx->host_state.vmcs_host_cr4 = cr4; vmx->loaded_vmcs->vmcs_host_cr4 = cr4;
vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */ vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
@ -9273,15 +9271,15 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
vmcs_writel(GUEST_RIP, vcpu->arch.regs[VCPU_REGS_RIP]); vmcs_writel(GUEST_RIP, vcpu->arch.regs[VCPU_REGS_RIP]);
cr3 = __get_current_cr3_fast(); cr3 = __get_current_cr3_fast();
if (unlikely(cr3 != vmx->host_state.vmcs_host_cr3)) { if (unlikely(cr3 != vmx->loaded_vmcs->vmcs_host_cr3)) {
vmcs_writel(HOST_CR3, cr3); vmcs_writel(HOST_CR3, cr3);
vmx->host_state.vmcs_host_cr3 = cr3; vmx->loaded_vmcs->vmcs_host_cr3 = cr3;
} }
cr4 = cr4_read_shadow(); cr4 = cr4_read_shadow();
if (unlikely(cr4 != vmx->host_state.vmcs_host_cr4)) { if (unlikely(cr4 != vmx->loaded_vmcs->vmcs_host_cr4)) {
vmcs_writel(HOST_CR4, cr4); vmcs_writel(HOST_CR4, cr4);
vmx->host_state.vmcs_host_cr4 = cr4; vmx->loaded_vmcs->vmcs_host_cr4 = cr4;
} }
/* When single-stepping over STI and MOV SS, we must clear the /* When single-stepping over STI and MOV SS, we must clear the
@ -9591,6 +9589,13 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
vmx->msr_ia32_feature_control_valid_bits = FEATURE_CONTROL_LOCKED; vmx->msr_ia32_feature_control_valid_bits = FEATURE_CONTROL_LOCKED;
/*
* Enforce invariant: pi_desc.nv is always either POSTED_INTR_VECTOR
* or POSTED_INTR_WAKEUP_VECTOR.
*/
vmx->pi_desc.nv = POSTED_INTR_VECTOR;
vmx->pi_desc.sn = 1;
return &vmx->vcpu; return &vmx->vcpu;
free_vmcs: free_vmcs:
@ -9839,7 +9844,8 @@ static void vmx_inject_page_fault_nested(struct kvm_vcpu *vcpu,
WARN_ON(!is_guest_mode(vcpu)); WARN_ON(!is_guest_mode(vcpu));
if (nested_vmx_is_page_fault_vmexit(vmcs12, fault->error_code)) { if (nested_vmx_is_page_fault_vmexit(vmcs12, fault->error_code) &&
!to_vmx(vcpu)->nested.nested_run_pending) {
vmcs12->vm_exit_intr_error_code = fault->error_code; vmcs12->vm_exit_intr_error_code = fault->error_code;
nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI, nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI,
PF_VECTOR | INTR_TYPE_HARD_EXCEPTION | PF_VECTOR | INTR_TYPE_HARD_EXCEPTION |
@ -11704,6 +11710,37 @@ static void vmx_enable_log_dirty_pt_masked(struct kvm *kvm,
kvm_mmu_clear_dirty_pt_masked(kvm, memslot, offset, mask); kvm_mmu_clear_dirty_pt_masked(kvm, memslot, offset, mask);
} }
static void __pi_post_block(struct kvm_vcpu *vcpu)
{
struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
struct pi_desc old, new;
unsigned int dest;
do {
old.control = new.control = pi_desc->control;
WARN(old.nv != POSTED_INTR_WAKEUP_VECTOR,
"Wakeup handler not enabled while the VCPU is blocked\n");
dest = cpu_physical_id(vcpu->cpu);
if (x2apic_enabled())
new.ndst = dest;
else
new.ndst = (dest << 8) & 0xFF00;
/* set 'NV' to 'notification vector' */
new.nv = POSTED_INTR_VECTOR;
} while (cmpxchg64(&pi_desc->control, old.control,
new.control) != old.control);
if (!WARN_ON_ONCE(vcpu->pre_pcpu == -1)) {
spin_lock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu));
list_del(&vcpu->blocked_vcpu_list);
spin_unlock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu));
vcpu->pre_pcpu = -1;
}
}
/* /*
* This routine does the following things for vCPU which is going * This routine does the following things for vCPU which is going
* to be blocked if VT-d PI is enabled. * to be blocked if VT-d PI is enabled.
@ -11719,7 +11756,6 @@ static void vmx_enable_log_dirty_pt_masked(struct kvm *kvm,
*/ */
static int pi_pre_block(struct kvm_vcpu *vcpu) static int pi_pre_block(struct kvm_vcpu *vcpu)
{ {
unsigned long flags;
unsigned int dest; unsigned int dest;
struct pi_desc old, new; struct pi_desc old, new;
struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
@ -11729,34 +11765,20 @@ static int pi_pre_block(struct kvm_vcpu *vcpu)
!kvm_vcpu_apicv_active(vcpu)) !kvm_vcpu_apicv_active(vcpu))
return 0; return 0;
vcpu->pre_pcpu = vcpu->cpu; WARN_ON(irqs_disabled());
spin_lock_irqsave(&per_cpu(blocked_vcpu_on_cpu_lock, local_irq_disable();
vcpu->pre_pcpu), flags); if (!WARN_ON_ONCE(vcpu->pre_pcpu != -1)) {
list_add_tail(&vcpu->blocked_vcpu_list, vcpu->pre_pcpu = vcpu->cpu;
&per_cpu(blocked_vcpu_on_cpu, spin_lock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu));
vcpu->pre_pcpu)); list_add_tail(&vcpu->blocked_vcpu_list,
spin_unlock_irqrestore(&per_cpu(blocked_vcpu_on_cpu_lock, &per_cpu(blocked_vcpu_on_cpu,
vcpu->pre_pcpu), flags); vcpu->pre_pcpu));
spin_unlock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu));
}
do { do {
old.control = new.control = pi_desc->control; old.control = new.control = pi_desc->control;
/*
* We should not block the vCPU if
* an interrupt is posted for it.
*/
if (pi_test_on(pi_desc) == 1) {
spin_lock_irqsave(&per_cpu(blocked_vcpu_on_cpu_lock,
vcpu->pre_pcpu), flags);
list_del(&vcpu->blocked_vcpu_list);
spin_unlock_irqrestore(
&per_cpu(blocked_vcpu_on_cpu_lock,
vcpu->pre_pcpu), flags);
vcpu->pre_pcpu = -1;
return 1;
}
WARN((pi_desc->sn == 1), WARN((pi_desc->sn == 1),
"Warning: SN field of posted-interrupts " "Warning: SN field of posted-interrupts "
"is set before blocking\n"); "is set before blocking\n");
@ -11778,10 +11800,15 @@ static int pi_pre_block(struct kvm_vcpu *vcpu)
/* set 'NV' to 'wakeup vector' */ /* set 'NV' to 'wakeup vector' */
new.nv = POSTED_INTR_WAKEUP_VECTOR; new.nv = POSTED_INTR_WAKEUP_VECTOR;
} while (cmpxchg(&pi_desc->control, old.control, } while (cmpxchg64(&pi_desc->control, old.control,
new.control) != old.control); new.control) != old.control);
return 0; /* We should not block the vCPU if an interrupt is posted for it. */
if (pi_test_on(pi_desc) == 1)
__pi_post_block(vcpu);
local_irq_enable();
return (vcpu->pre_pcpu == -1);
} }
static int vmx_pre_block(struct kvm_vcpu *vcpu) static int vmx_pre_block(struct kvm_vcpu *vcpu)
@ -11797,44 +11824,13 @@ static int vmx_pre_block(struct kvm_vcpu *vcpu)
static void pi_post_block(struct kvm_vcpu *vcpu) static void pi_post_block(struct kvm_vcpu *vcpu)
{ {
struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); if (vcpu->pre_pcpu == -1)
struct pi_desc old, new;
unsigned int dest;
unsigned long flags;
if (!kvm_arch_has_assigned_device(vcpu->kvm) ||
!irq_remapping_cap(IRQ_POSTING_CAP) ||
!kvm_vcpu_apicv_active(vcpu))
return; return;
do { WARN_ON(irqs_disabled());
old.control = new.control = pi_desc->control; local_irq_disable();
__pi_post_block(vcpu);
dest = cpu_physical_id(vcpu->cpu); local_irq_enable();
if (x2apic_enabled())
new.ndst = dest;
else
new.ndst = (dest << 8) & 0xFF00;
/* Allow posting non-urgent interrupts */
new.sn = 0;
/* set 'NV' to 'notification vector' */
new.nv = POSTED_INTR_VECTOR;
} while (cmpxchg(&pi_desc->control, old.control,
new.control) != old.control);
if(vcpu->pre_pcpu != -1) {
spin_lock_irqsave(
&per_cpu(blocked_vcpu_on_cpu_lock,
vcpu->pre_pcpu), flags);
list_del(&vcpu->blocked_vcpu_list);
spin_unlock_irqrestore(
&per_cpu(blocked_vcpu_on_cpu_lock,
vcpu->pre_pcpu), flags);
vcpu->pre_pcpu = -1;
}
} }
static void vmx_post_block(struct kvm_vcpu *vcpu) static void vmx_post_block(struct kvm_vcpu *vcpu)

View File

@ -7225,7 +7225,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
int r; int r;
sigset_t sigsaved; sigset_t sigsaved;
fpu__activate_curr(fpu); fpu__initialize(fpu);
if (vcpu->sigset_active) if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);

View File

@ -114,7 +114,7 @@ void math_emulate(struct math_emu_info *info)
struct desc_struct code_descriptor; struct desc_struct code_descriptor;
struct fpu *fpu = &current->thread.fpu; struct fpu *fpu = &current->thread.fpu;
fpu__activate_curr(fpu); fpu__initialize(fpu);
#ifdef RE_ENTRANT_CHECKING #ifdef RE_ENTRANT_CHECKING
if (emulating) { if (emulating) {

View File

@ -2,6 +2,7 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/sched/debug.h> #include <linux/sched/debug.h>
#include <asm/fpu/internal.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/kdebug.h> #include <asm/kdebug.h>
@ -78,6 +79,29 @@ bool ex_handler_refcount(const struct exception_table_entry *fixup,
} }
EXPORT_SYMBOL_GPL(ex_handler_refcount); EXPORT_SYMBOL_GPL(ex_handler_refcount);
/*
* Handler for when we fail to restore a task's FPU state. We should never get
* here because the FPU state of a task using the FPU (task->thread.fpu.state)
* should always be valid. However, past bugs have allowed userspace to set
* reserved bits in the XSAVE area using PTRACE_SETREGSET or sys_rt_sigreturn().
* These caused XRSTOR to fail when switching to the task, leaking the FPU
* registers of the task previously executing on the CPU. Mitigate this class
* of vulnerability by restoring from the initial state (essentially, zeroing
* out all the FPU registers) if we can't restore from the task's FPU state.
*/
bool ex_handler_fprestore(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr)
{
regs->ip = ex_fixup_addr(fixup);
WARN_ONCE(1, "Bad FPU state detected at %pB, reinitializing FPU registers.",
(void *)instruction_pointer(regs));
__copy_kernel_to_fpregs(&init_fpstate, -1);
return true;
}
EXPORT_SYMBOL_GPL(ex_handler_fprestore);
bool ex_handler_ext(const struct exception_table_entry *fixup, bool ex_handler_ext(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr) struct pt_regs *regs, int trapnr)
{ {

View File

@ -192,8 +192,7 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)
* 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really * 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really
* faulted on a pte with its pkey=4. * faulted on a pte with its pkey=4.
*/ */
static void fill_sig_info_pkey(int si_code, siginfo_t *info, static void fill_sig_info_pkey(int si_code, siginfo_t *info, u32 *pkey)
struct vm_area_struct *vma)
{ {
/* This is effectively an #ifdef */ /* This is effectively an #ifdef */
if (!boot_cpu_has(X86_FEATURE_OSPKE)) if (!boot_cpu_has(X86_FEATURE_OSPKE))
@ -209,7 +208,7 @@ static void fill_sig_info_pkey(int si_code, siginfo_t *info,
* valid VMA, so we should never reach this without a * valid VMA, so we should never reach this without a
* valid VMA. * valid VMA.
*/ */
if (!vma) { if (!pkey) {
WARN_ONCE(1, "PKU fault with no VMA passed in"); WARN_ONCE(1, "PKU fault with no VMA passed in");
info->si_pkey = 0; info->si_pkey = 0;
return; return;
@ -219,13 +218,12 @@ static void fill_sig_info_pkey(int si_code, siginfo_t *info,
* absolutely guranteed to be 100% accurate because of * absolutely guranteed to be 100% accurate because of
* the race explained above. * the race explained above.
*/ */
info->si_pkey = vma_pkey(vma); info->si_pkey = *pkey;
} }
static void static void
force_sig_info_fault(int si_signo, int si_code, unsigned long address, force_sig_info_fault(int si_signo, int si_code, unsigned long address,
struct task_struct *tsk, struct vm_area_struct *vma, struct task_struct *tsk, u32 *pkey, int fault)
int fault)
{ {
unsigned lsb = 0; unsigned lsb = 0;
siginfo_t info; siginfo_t info;
@ -240,7 +238,7 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address,
lsb = PAGE_SHIFT; lsb = PAGE_SHIFT;
info.si_addr_lsb = lsb; info.si_addr_lsb = lsb;
fill_sig_info_pkey(si_code, &info, vma); fill_sig_info_pkey(si_code, &info, pkey);
force_sig_info(si_signo, &info, tsk); force_sig_info(si_signo, &info, tsk);
} }
@ -762,8 +760,6 @@ no_context(struct pt_regs *regs, unsigned long error_code,
struct task_struct *tsk = current; struct task_struct *tsk = current;
unsigned long flags; unsigned long flags;
int sig; int sig;
/* No context means no VMA to pass down */
struct vm_area_struct *vma = NULL;
/* Are we prepared to handle this kernel fault? */ /* Are we prepared to handle this kernel fault? */
if (fixup_exception(regs, X86_TRAP_PF)) { if (fixup_exception(regs, X86_TRAP_PF)) {
@ -788,7 +784,7 @@ no_context(struct pt_regs *regs, unsigned long error_code,
/* XXX: hwpoison faults will set the wrong code. */ /* XXX: hwpoison faults will set the wrong code. */
force_sig_info_fault(signal, si_code, address, force_sig_info_fault(signal, si_code, address,
tsk, vma, 0); tsk, NULL, 0);
} }
/* /*
@ -896,8 +892,7 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code,
static void static void
__bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
unsigned long address, struct vm_area_struct *vma, unsigned long address, u32 *pkey, int si_code)
int si_code)
{ {
struct task_struct *tsk = current; struct task_struct *tsk = current;
@ -945,7 +940,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
tsk->thread.error_code = error_code; tsk->thread.error_code = error_code;
tsk->thread.trap_nr = X86_TRAP_PF; tsk->thread.trap_nr = X86_TRAP_PF;
force_sig_info_fault(SIGSEGV, si_code, address, tsk, vma, 0); force_sig_info_fault(SIGSEGV, si_code, address, tsk, pkey, 0);
return; return;
} }
@ -958,9 +953,9 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
static noinline void static noinline void
bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
unsigned long address, struct vm_area_struct *vma) unsigned long address, u32 *pkey)
{ {
__bad_area_nosemaphore(regs, error_code, address, vma, SEGV_MAPERR); __bad_area_nosemaphore(regs, error_code, address, pkey, SEGV_MAPERR);
} }
static void static void
@ -968,6 +963,10 @@ __bad_area(struct pt_regs *regs, unsigned long error_code,
unsigned long address, struct vm_area_struct *vma, int si_code) unsigned long address, struct vm_area_struct *vma, int si_code)
{ {
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
u32 pkey;
if (vma)
pkey = vma_pkey(vma);
/* /*
* Something tried to access memory that isn't in our memory map.. * Something tried to access memory that isn't in our memory map..
@ -975,7 +974,8 @@ __bad_area(struct pt_regs *regs, unsigned long error_code,
*/ */
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
__bad_area_nosemaphore(regs, error_code, address, vma, si_code); __bad_area_nosemaphore(regs, error_code, address,
(vma) ? &pkey : NULL, si_code);
} }
static noinline void static noinline void
@ -1018,7 +1018,7 @@ bad_area_access_error(struct pt_regs *regs, unsigned long error_code,
static void static void
do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
struct vm_area_struct *vma, unsigned int fault) u32 *pkey, unsigned int fault)
{ {
struct task_struct *tsk = current; struct task_struct *tsk = current;
int code = BUS_ADRERR; int code = BUS_ADRERR;
@ -1045,13 +1045,12 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
code = BUS_MCEERR_AR; code = BUS_MCEERR_AR;
} }
#endif #endif
force_sig_info_fault(SIGBUS, code, address, tsk, vma, fault); force_sig_info_fault(SIGBUS, code, address, tsk, pkey, fault);
} }
static noinline void static noinline void
mm_fault_error(struct pt_regs *regs, unsigned long error_code, mm_fault_error(struct pt_regs *regs, unsigned long error_code,
unsigned long address, struct vm_area_struct *vma, unsigned long address, u32 *pkey, unsigned int fault)
unsigned int fault)
{ {
if (fatal_signal_pending(current) && !(error_code & PF_USER)) { if (fatal_signal_pending(current) && !(error_code & PF_USER)) {
no_context(regs, error_code, address, 0, 0); no_context(regs, error_code, address, 0, 0);
@ -1075,9 +1074,9 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
} else { } else {
if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON| if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
VM_FAULT_HWPOISON_LARGE)) VM_FAULT_HWPOISON_LARGE))
do_sigbus(regs, error_code, address, vma, fault); do_sigbus(regs, error_code, address, pkey, fault);
else if (fault & VM_FAULT_SIGSEGV) else if (fault & VM_FAULT_SIGSEGV)
bad_area_nosemaphore(regs, error_code, address, vma); bad_area_nosemaphore(regs, error_code, address, pkey);
else else
BUG(); BUG();
} }
@ -1267,6 +1266,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,
struct mm_struct *mm; struct mm_struct *mm;
int fault, major = 0; int fault, major = 0;
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
u32 pkey;
tsk = current; tsk = current;
mm = tsk->mm; mm = tsk->mm;
@ -1467,9 +1467,10 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,
return; return;
} }
pkey = vma_pkey(vma);
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
if (unlikely(fault & VM_FAULT_ERROR)) { if (unlikely(fault & VM_FAULT_ERROR)) {
mm_fault_error(regs, error_code, address, vma, fault); mm_fault_error(regs, error_code, address, &pkey, fault);
return; return;
} }

View File

@ -10,6 +10,8 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define DISABLE_BRANCH_PROFILING
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/mm.h> #include <linux/mm.h>

View File

@ -18,7 +18,6 @@
#include <asm/cpufeature.h> /* boot_cpu_has, ... */ #include <asm/cpufeature.h> /* boot_cpu_has, ... */
#include <asm/mmu_context.h> /* vma_pkey() */ #include <asm/mmu_context.h> /* vma_pkey() */
#include <asm/fpu/internal.h> /* fpregs_active() */
int __execute_only_pkey(struct mm_struct *mm) int __execute_only_pkey(struct mm_struct *mm)
{ {
@ -45,7 +44,7 @@ int __execute_only_pkey(struct mm_struct *mm)
*/ */
preempt_disable(); preempt_disable();
if (!need_to_set_mm_pkey && if (!need_to_set_mm_pkey &&
fpregs_active() && current->thread.fpu.initialized &&
!__pkru_allows_read(read_pkru(), execute_only_pkey)) { !__pkru_allows_read(read_pkru(), execute_only_pkey)) {
preempt_enable(); preempt_enable();
return execute_only_pkey; return execute_only_pkey;

View File

@ -191,7 +191,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
* mapped in the new pgd, we'll double-fault. Forcibly * mapped in the new pgd, we'll double-fault. Forcibly
* map it. * map it.
*/ */
unsigned int index = pgd_index(current_stack_pointer()); unsigned int index = pgd_index(current_stack_pointer);
pgd_t *pgd = next->pgd + index; pgd_t *pgd = next->pgd + index;
if (unlikely(pgd_none(*pgd))) if (unlikely(pgd_none(*pgd)))

View File

@ -1238,21 +1238,16 @@ static void __init xen_pagetable_cleanhighmap(void)
* from _brk_limit way up to the max_pfn_mapped (which is the end of * from _brk_limit way up to the max_pfn_mapped (which is the end of
* the ramdisk). We continue on, erasing PMD entries that point to page * the ramdisk). We continue on, erasing PMD entries that point to page
* tables - do note that they are accessible at this stage via __va. * tables - do note that they are accessible at this stage via __va.
* For good measure we also round up to the PMD - which means that if * As Xen is aligning the memory end to a 4MB boundary, for good
* measure we also round up to PMD_SIZE * 2 - which means that if
* anybody is using __ka address to the initial boot-stack - and try * anybody is using __ka address to the initial boot-stack - and try
* to use it - they are going to crash. The xen_start_info has been * to use it - they are going to crash. The xen_start_info has been
* taken care of already in xen_setup_kernel_pagetable. */ * taken care of already in xen_setup_kernel_pagetable. */
addr = xen_start_info->pt_base; addr = xen_start_info->pt_base;
size = roundup(xen_start_info->nr_pt_frames * PAGE_SIZE, PMD_SIZE); size = xen_start_info->nr_pt_frames * PAGE_SIZE;
xen_cleanhighmap(addr, addr + size); xen_cleanhighmap(addr, roundup(addr + size, PMD_SIZE * 2));
xen_start_info->pt_base = (unsigned long)__va(__pa(xen_start_info->pt_base)); xen_start_info->pt_base = (unsigned long)__va(__pa(xen_start_info->pt_base));
#ifdef DEBUG
/* This is superfluous and is not necessary, but you know what
* lets do it. The MODULES_VADDR -> MODULES_END should be clear of
* anything at this stage. */
xen_cleanhighmap(MODULES_VADDR, roundup(MODULES_VADDR, PUD_SIZE) - 1);
#endif
} }
#endif #endif

View File

@ -854,6 +854,9 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
kobject_init(&q->kobj, &blk_queue_ktype); kobject_init(&q->kobj, &blk_queue_ktype);
#ifdef CONFIG_BLK_DEV_IO_TRACE
mutex_init(&q->blk_trace_mutex);
#endif
mutex_init(&q->sysfs_lock); mutex_init(&q->sysfs_lock);
spin_lock_init(&q->__queue_lock); spin_lock_init(&q->__queue_lock);

View File

@ -154,7 +154,6 @@ static int bsg_prepare_job(struct device *dev, struct request *req)
failjob_rls_rqst_payload: failjob_rls_rqst_payload:
kfree(job->request_payload.sg_list); kfree(job->request_payload.sg_list);
failjob_rls_job: failjob_rls_job:
kfree(job);
return -ENOMEM; return -ENOMEM;
} }

View File

@ -112,7 +112,7 @@ ssize_t part_stat_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct hd_struct *p = dev_to_part(dev); struct hd_struct *p = dev_to_part(dev);
struct request_queue *q = dev_to_disk(dev)->queue; struct request_queue *q = part_to_disk(p)->queue;
unsigned int inflight[2]; unsigned int inflight[2];
int cpu; int cpu;

View File

@ -743,17 +743,19 @@ static int ghes_proc(struct ghes *ghes)
} }
ghes_do_proc(ghes, ghes->estatus); ghes_do_proc(ghes, ghes->estatus);
out:
ghes_clear_estatus(ghes);
if (rc == -ENOENT)
return rc;
/* /*
* GHESv2 type HEST entries introduce support for error acknowledgment, * GHESv2 type HEST entries introduce support for error acknowledgment,
* so only acknowledge the error if this support is present. * so only acknowledge the error if this support is present.
*/ */
if (is_hest_type_generic_v2(ghes)) { if (is_hest_type_generic_v2(ghes))
rc = ghes_ack_error(ghes->generic_v2); return ghes_ack_error(ghes->generic_v2);
if (rc)
return rc;
}
out:
ghes_clear_estatus(ghes);
return rc; return rc;
} }

View File

@ -1581,6 +1581,9 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
opp->available = availability_req; opp->available = availability_req;
dev_pm_opp_get(opp);
mutex_unlock(&opp_table->lock);
/* Notify the change of the OPP availability */ /* Notify the change of the OPP availability */
if (availability_req) if (availability_req)
blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ENABLE, blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ENABLE,
@ -1589,8 +1592,12 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
blocking_notifier_call_chain(&opp_table->head, blocking_notifier_call_chain(&opp_table->head,
OPP_EVENT_DISABLE, opp); OPP_EVENT_DISABLE, opp);
dev_pm_opp_put(opp);
goto put_table;
unlock: unlock:
mutex_unlock(&opp_table->lock); mutex_unlock(&opp_table->lock);
put_table:
dev_pm_opp_put_opp_table(opp_table); dev_pm_opp_put_opp_table(opp_table);
return r; return r;
} }

View File

@ -342,7 +342,7 @@ static long __brd_direct_access(struct brd_device *brd, pgoff_t pgoff,
if (!brd) if (!brd)
return -ENODEV; return -ENODEV;
page = brd_insert_page(brd, PFN_PHYS(pgoff) / 512); page = brd_insert_page(brd, (sector_t)pgoff << PAGE_SECTORS_SHIFT);
if (!page) if (!page)
return -ENOSPC; return -ENOSPC;
*kaddr = page_address(page); *kaddr = page_address(page);

View File

@ -67,10 +67,8 @@ struct loop_device {
struct loop_cmd { struct loop_cmd {
struct kthread_work work; struct kthread_work work;
struct request *rq; struct request *rq;
union { bool use_aio; /* use AIO interface to handle I/O */
bool use_aio; /* use AIO interface to handle I/O */ atomic_t ref; /* only for aio */
atomic_t ref; /* only for aio */
};
long ret; long ret;
struct kiocb iocb; struct kiocb iocb;
struct bio_vec *bvec; struct bio_vec *bvec;

View File

@ -1194,6 +1194,12 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
/* The block layer will pass back some non-nbd ioctls in case we have
* special handling for them, but we don't so just return an error.
*/
if (_IOC_TYPE(cmd) != 0xab)
return -EINVAL;
mutex_lock(&nbd->config_lock); mutex_lock(&nbd->config_lock);
/* Don't allow ioctl operations on a nbd device that was created with /* Don't allow ioctl operations on a nbd device that was created with

View File

@ -43,7 +43,7 @@ static int numachip2_set_next_event(unsigned long delta, struct clock_event_devi
return 0; return 0;
} }
static struct clock_event_device numachip2_clockevent = { static const struct clock_event_device numachip2_clockevent __initconst = {
.name = "numachip2", .name = "numachip2",
.rating = 400, .rating = 400,
.set_next_event = numachip2_set_next_event, .set_next_event = numachip2_set_next_event,

View File

@ -118,6 +118,10 @@ static const struct of_device_id blacklist[] __initconst = {
{ .compatible = "sigma,tango4", }, { .compatible = "sigma,tango4", },
{ .compatible = "ti,am33xx", },
{ .compatible = "ti,am43", },
{ .compatible = "ti,dra7", },
{ } { }
}; };

View File

@ -636,7 +636,194 @@ static void gfx_v6_0_tiling_mode_table_init(struct amdgpu_device *adev)
NUM_BANKS(ADDR_SURF_2_BANK); NUM_BANKS(ADDR_SURF_2_BANK);
for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++)
WREG32(mmGB_TILE_MODE0 + reg_offset, tilemode[reg_offset]); WREG32(mmGB_TILE_MODE0 + reg_offset, tilemode[reg_offset]);
} else if (adev->asic_type == CHIP_OLAND || adev->asic_type == CHIP_HAINAN) { } else if (adev->asic_type == CHIP_OLAND) {
tilemode[0] = MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4);
tilemode[1] = MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4);
tilemode[2] = MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4);
tilemode[3] = MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4);
tilemode[4] = MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[5] = MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(split_equal_to_row_size) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[6] = MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(split_equal_to_row_size) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[7] = MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(split_equal_to_row_size) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4);
tilemode[8] = MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[9] = MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[10] = MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4);
tilemode[11] = MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[12] = MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[13] = MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[14] = MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[15] = MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[16] = MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[17] = MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_8x16) |
TILE_SPLIT(split_equal_to_row_size) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[21] = MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[22] = MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4);
tilemode[23] = MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[24] = MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
NUM_BANKS(ADDR_SURF_16_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2);
tilemode[25] = MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) |
NUM_BANKS(ADDR_SURF_8_BANK) |
BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1);
for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++)
WREG32(mmGB_TILE_MODE0 + reg_offset, tilemode[reg_offset]);
} else if (adev->asic_type == CHIP_HAINAN) {
tilemode[0] = MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | tilemode[0] = MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
ARRAY_MODE(ARRAY_2D_TILED_THIN1) | ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P2) | PIPE_CONFIG(ADDR_SURF_P2) |

View File

@ -892,6 +892,8 @@ static int kfd_ioctl_get_tile_config(struct file *filep,
int err = 0; int err = 0;
dev = kfd_device_by_id(args->gpu_id); dev = kfd_device_by_id(args->gpu_id);
if (!dev)
return -EINVAL;
dev->kfd2kgd->get_tile_config(dev->kgd, &config); dev->kfd2kgd->get_tile_config(dev->kgd, &config);

View File

@ -292,7 +292,10 @@ static int create_signal_event(struct file *devkfd,
struct kfd_event *ev) struct kfd_event *ev)
{ {
if (p->signal_event_count == KFD_SIGNAL_EVENT_LIMIT) { if (p->signal_event_count == KFD_SIGNAL_EVENT_LIMIT) {
pr_warn("Signal event wasn't created because limit was reached\n"); if (!p->signal_event_limit_reached) {
pr_warn("Signal event wasn't created because limit was reached\n");
p->signal_event_limit_reached = true;
}
return -ENOMEM; return -ENOMEM;
} }

View File

@ -184,7 +184,7 @@ static void uninitialize(struct kernel_queue *kq)
if (kq->queue->properties.type == KFD_QUEUE_TYPE_HIQ) if (kq->queue->properties.type == KFD_QUEUE_TYPE_HIQ)
kq->mqd->destroy_mqd(kq->mqd, kq->mqd->destroy_mqd(kq->mqd,
kq->queue->mqd, kq->queue->mqd,
false, KFD_PREEMPT_TYPE_WAVEFRONT_RESET,
QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS, QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS,
kq->queue->pipe, kq->queue->pipe,
kq->queue->queue); kq->queue->queue);
@ -210,6 +210,11 @@ static int acquire_packet_buffer(struct kernel_queue *kq,
uint32_t wptr, rptr; uint32_t wptr, rptr;
unsigned int *queue_address; unsigned int *queue_address;
/* When rptr == wptr, the buffer is empty.
* When rptr == wptr + 1, the buffer is full.
* It is always rptr that advances to the position of wptr, rather than
* the opposite. So we can only use up to queue_size_dwords - 1 dwords.
*/
rptr = *kq->rptr_kernel; rptr = *kq->rptr_kernel;
wptr = *kq->wptr_kernel; wptr = *kq->wptr_kernel;
queue_address = (unsigned int *)kq->pq_kernel_addr; queue_address = (unsigned int *)kq->pq_kernel_addr;
@ -219,11 +224,10 @@ static int acquire_packet_buffer(struct kernel_queue *kq,
pr_debug("wptr: %d\n", wptr); pr_debug("wptr: %d\n", wptr);
pr_debug("queue_address 0x%p\n", queue_address); pr_debug("queue_address 0x%p\n", queue_address);
available_size = (rptr - 1 - wptr + queue_size_dwords) % available_size = (rptr + queue_size_dwords - 1 - wptr) %
queue_size_dwords; queue_size_dwords;
if (packet_size_in_dwords >= queue_size_dwords || if (packet_size_in_dwords > available_size) {
packet_size_in_dwords >= available_size) {
/* /*
* make sure calling functions know * make sure calling functions know
* acquire_packet_buffer() failed * acquire_packet_buffer() failed
@ -233,6 +237,14 @@ static int acquire_packet_buffer(struct kernel_queue *kq,
} }
if (wptr + packet_size_in_dwords >= queue_size_dwords) { if (wptr + packet_size_in_dwords >= queue_size_dwords) {
/* make sure after rolling back to position 0, there is
* still enough space.
*/
if (packet_size_in_dwords >= rptr) {
*buffer_ptr = NULL;
return -ENOMEM;
}
/* fill nops, roll back and start at position 0 */
while (wptr > 0) { while (wptr > 0) {
queue_address[wptr] = kq->nop_packet; queue_address[wptr] = kq->nop_packet;
wptr = (wptr + 1) % queue_size_dwords; wptr = (wptr + 1) % queue_size_dwords;

View File

@ -519,6 +519,7 @@ struct kfd_process {
struct list_head signal_event_pages; struct list_head signal_event_pages;
u32 next_nonsignal_event_id; u32 next_nonsignal_event_id;
size_t signal_event_count; size_t signal_event_count;
bool signal_event_limit_reached;
}; };
/** /**

View File

@ -551,12 +551,15 @@ static const struct etnaviv_gem_ops etnaviv_gem_shmem_ops = {
void etnaviv_gem_free_object(struct drm_gem_object *obj) void etnaviv_gem_free_object(struct drm_gem_object *obj)
{ {
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
struct etnaviv_drm_private *priv = obj->dev->dev_private;
struct etnaviv_vram_mapping *mapping, *tmp; struct etnaviv_vram_mapping *mapping, *tmp;
/* object should not be active */ /* object should not be active */
WARN_ON(is_active(etnaviv_obj)); WARN_ON(is_active(etnaviv_obj));
mutex_lock(&priv->gem_lock);
list_del(&etnaviv_obj->gem_node); list_del(&etnaviv_obj->gem_node);
mutex_unlock(&priv->gem_lock);
list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list, list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list,
obj_node) { obj_node) {

View File

@ -445,8 +445,10 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
cmdbuf->user_size = ALIGN(args->stream_size, 8); cmdbuf->user_size = ALIGN(args->stream_size, 8);
ret = etnaviv_gpu_submit(gpu, submit, cmdbuf); ret = etnaviv_gpu_submit(gpu, submit, cmdbuf);
if (ret == 0) if (ret)
cmdbuf = NULL; goto out;
cmdbuf = NULL;
if (args->flags & ETNA_SUBMIT_FENCE_FD_OUT) { if (args->flags & ETNA_SUBMIT_FENCE_FD_OUT) {
/* /*

View File

@ -509,23 +509,25 @@ static void qxl_primary_atomic_update(struct drm_plane *plane,
.y2 = qfb->base.height .y2 = qfb->base.height
}; };
if (!old_state->fb) { if (old_state->fb) {
qxl_io_log(qdev,
"create primary fb: %dx%d,%d,%d\n",
bo->surf.width, bo->surf.height,
bo->surf.stride, bo->surf.format);
qxl_io_create_primary(qdev, 0, bo);
bo->is_primary = true;
return;
} else {
qfb_old = to_qxl_framebuffer(old_state->fb); qfb_old = to_qxl_framebuffer(old_state->fb);
bo_old = gem_to_qxl_bo(qfb_old->obj); bo_old = gem_to_qxl_bo(qfb_old->obj);
} else {
bo_old = NULL;
}
if (bo == bo_old)
return;
if (bo_old && bo_old->is_primary) {
qxl_io_destroy_primary(qdev);
bo_old->is_primary = false; bo_old->is_primary = false;
} }
bo->is_primary = true; if (!bo->is_primary) {
qxl_io_create_primary(qdev, 0, bo);
bo->is_primary = true;
}
qxl_draw_dirty_fb(qdev, qfb, bo, 0, 0, &norect, 1, 1); qxl_draw_dirty_fb(qdev, qfb, bo, 0, 0, &norect, 1, 1);
} }
@ -534,13 +536,15 @@ static void qxl_primary_atomic_disable(struct drm_plane *plane,
{ {
struct qxl_device *qdev = plane->dev->dev_private; struct qxl_device *qdev = plane->dev->dev_private;
if (old_state->fb) if (old_state->fb) {
{ struct qxl_framebuffer *qfb = struct qxl_framebuffer *qfb =
to_qxl_framebuffer(old_state->fb); to_qxl_framebuffer(old_state->fb);
struct qxl_bo *bo = gem_to_qxl_bo(qfb->obj); struct qxl_bo *bo = gem_to_qxl_bo(qfb->obj);
qxl_io_destroy_primary(qdev); if (bo->is_primary) {
bo->is_primary = false; qxl_io_destroy_primary(qdev);
bo->is_primary = false;
}
} }
} }
@ -698,14 +702,15 @@ static void qxl_plane_cleanup_fb(struct drm_plane *plane,
struct drm_gem_object *obj; struct drm_gem_object *obj;
struct qxl_bo *user_bo; struct qxl_bo *user_bo;
if (!plane->state->fb) { if (!old_state->fb) {
/* we never executed prepare_fb, so there's nothing to /*
* we never executed prepare_fb, so there's nothing to
* unpin. * unpin.
*/ */
return; return;
} }
obj = to_qxl_framebuffer(plane->state->fb)->obj; obj = to_qxl_framebuffer(old_state->fb)->obj;
user_bo = gem_to_qxl_bo(obj); user_bo = gem_to_qxl_bo(obj);
qxl_bo_unpin(user_bo); qxl_bo_unpin(user_bo);
} }

View File

@ -1663,7 +1663,7 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend,
radeon_agp_suspend(rdev); radeon_agp_suspend(rdev);
pci_save_state(dev->pdev); pci_save_state(dev->pdev);
if (freeze && rdev->family >= CHIP_CEDAR) { if (freeze && rdev->family >= CHIP_CEDAR && !(rdev->flags & RADEON_IS_IGP)) {
rdev->asic->asic_reset(rdev, true); rdev->asic->asic_reset(rdev, true);
pci_restore_state(dev->pdev); pci_restore_state(dev->pdev);
} else if (suspend) { } else if (suspend) {

View File

@ -26,7 +26,7 @@ config DRM_SUN4I_HDMI_CEC
bool "Allwinner A10 HDMI CEC Support" bool "Allwinner A10 HDMI CEC Support"
depends on DRM_SUN4I_HDMI depends on DRM_SUN4I_HDMI
select CEC_CORE select CEC_CORE
depends on CEC_PIN select CEC_PIN
help help
Choose this option if you have an Allwinner SoC with an HDMI Choose this option if you have an Allwinner SoC with an HDMI
controller and want to use CEC. controller and want to use CEC.

View File

@ -15,7 +15,7 @@
#include <drm/drm_connector.h> #include <drm/drm_connector.h>
#include <drm/drm_encoder.h> #include <drm/drm_encoder.h>
#include <media/cec.h> #include <media/cec-pin.h>
#define SUN4I_HDMI_CTRL_REG 0x004 #define SUN4I_HDMI_CTRL_REG 0x004
#define SUN4I_HDMI_CTRL_ENABLE BIT(31) #define SUN4I_HDMI_CTRL_ENABLE BIT(31)

View File

@ -63,6 +63,6 @@ DEFINE_EVENT(register_access, sor_readl,
/* This part must be outside protection */ /* This part must be outside protection */
#undef TRACE_INCLUDE_PATH #undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH . #define TRACE_INCLUDE_PATH ../../drivers/gpu/drm/tegra
#define TRACE_INCLUDE_FILE trace #define TRACE_INCLUDE_FILE trace
#include <trace/define_trace.h> #include <trace/define_trace.h>

View File

@ -432,8 +432,10 @@ int ib_create_qp_security(struct ib_qp *qp, struct ib_device *dev)
atomic_set(&qp->qp_sec->error_list_count, 0); atomic_set(&qp->qp_sec->error_list_count, 0);
init_completion(&qp->qp_sec->error_complete); init_completion(&qp->qp_sec->error_complete);
ret = security_ib_alloc_security(&qp->qp_sec->security); ret = security_ib_alloc_security(&qp->qp_sec->security);
if (ret) if (ret) {
kfree(qp->qp_sec); kfree(qp->qp_sec);
qp->qp_sec = NULL;
}
return ret; return ret;
} }

View File

@ -3869,15 +3869,15 @@ int ib_uverbs_ex_query_device(struct ib_uverbs_file *file,
resp.raw_packet_caps = attr.raw_packet_caps; resp.raw_packet_caps = attr.raw_packet_caps;
resp.response_length += sizeof(resp.raw_packet_caps); resp.response_length += sizeof(resp.raw_packet_caps);
if (ucore->outlen < resp.response_length + sizeof(resp.xrq_caps)) if (ucore->outlen < resp.response_length + sizeof(resp.tm_caps))
goto end; goto end;
resp.xrq_caps.max_rndv_hdr_size = attr.xrq_caps.max_rndv_hdr_size; resp.tm_caps.max_rndv_hdr_size = attr.tm_caps.max_rndv_hdr_size;
resp.xrq_caps.max_num_tags = attr.xrq_caps.max_num_tags; resp.tm_caps.max_num_tags = attr.tm_caps.max_num_tags;
resp.xrq_caps.max_ops = attr.xrq_caps.max_ops; resp.tm_caps.max_ops = attr.tm_caps.max_ops;
resp.xrq_caps.max_sge = attr.xrq_caps.max_sge; resp.tm_caps.max_sge = attr.tm_caps.max_sge;
resp.xrq_caps.flags = attr.xrq_caps.flags; resp.tm_caps.flags = attr.tm_caps.flags;
resp.response_length += sizeof(resp.xrq_caps); resp.response_length += sizeof(resp.tm_caps);
end: end:
err = ib_copy_to_udata(ucore, &resp, resp.response_length); err = ib_copy_to_udata(ucore, &resp, resp.response_length);
return err; return err;

View File

@ -1066,6 +1066,8 @@ static int read_idle_sma(struct hfi1_devdata *dd, u64 *data);
static int thermal_init(struct hfi1_devdata *dd); static int thermal_init(struct hfi1_devdata *dd);
static void update_statusp(struct hfi1_pportdata *ppd, u32 state); static void update_statusp(struct hfi1_pportdata *ppd, u32 state);
static int wait_phys_link_offline_substates(struct hfi1_pportdata *ppd,
int msecs);
static int wait_logical_linkstate(struct hfi1_pportdata *ppd, u32 state, static int wait_logical_linkstate(struct hfi1_pportdata *ppd, u32 state,
int msecs); int msecs);
static void log_state_transition(struct hfi1_pportdata *ppd, u32 state); static void log_state_transition(struct hfi1_pportdata *ppd, u32 state);
@ -8238,6 +8240,7 @@ static irqreturn_t general_interrupt(int irq, void *data)
u64 regs[CCE_NUM_INT_CSRS]; u64 regs[CCE_NUM_INT_CSRS];
u32 bit; u32 bit;
int i; int i;
irqreturn_t handled = IRQ_NONE;
this_cpu_inc(*dd->int_counter); this_cpu_inc(*dd->int_counter);
@ -8258,9 +8261,10 @@ static irqreturn_t general_interrupt(int irq, void *data)
for_each_set_bit(bit, (unsigned long *)&regs[0], for_each_set_bit(bit, (unsigned long *)&regs[0],
CCE_NUM_INT_CSRS * 64) { CCE_NUM_INT_CSRS * 64) {
is_interrupt(dd, bit); is_interrupt(dd, bit);
handled = IRQ_HANDLED;
} }
return IRQ_HANDLED; return handled;
} }
static irqreturn_t sdma_interrupt(int irq, void *data) static irqreturn_t sdma_interrupt(int irq, void *data)
@ -9413,7 +9417,7 @@ static void set_qsfp_int_n(struct hfi1_pportdata *ppd, u8 enable)
write_csr(dd, dd->hfi1_id ? ASIC_QSFP2_MASK : ASIC_QSFP1_MASK, mask); write_csr(dd, dd->hfi1_id ? ASIC_QSFP2_MASK : ASIC_QSFP1_MASK, mask);
} }
void reset_qsfp(struct hfi1_pportdata *ppd) int reset_qsfp(struct hfi1_pportdata *ppd)
{ {
struct hfi1_devdata *dd = ppd->dd; struct hfi1_devdata *dd = ppd->dd;
u64 mask, qsfp_mask; u64 mask, qsfp_mask;
@ -9443,6 +9447,13 @@ void reset_qsfp(struct hfi1_pportdata *ppd)
* for alarms and warnings * for alarms and warnings
*/ */
set_qsfp_int_n(ppd, 1); set_qsfp_int_n(ppd, 1);
/*
* After the reset, AOC transmitters are enabled by default. They need
* to be turned off to complete the QSFP setup before they can be
* enabled again.
*/
return set_qsfp_tx(ppd, 0);
} }
static int handle_qsfp_error_conditions(struct hfi1_pportdata *ppd, static int handle_qsfp_error_conditions(struct hfi1_pportdata *ppd,
@ -10305,6 +10316,7 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason)
{ {
struct hfi1_devdata *dd = ppd->dd; struct hfi1_devdata *dd = ppd->dd;
u32 previous_state; u32 previous_state;
int offline_state_ret;
int ret; int ret;
update_lcb_cache(dd); update_lcb_cache(dd);
@ -10326,28 +10338,11 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason)
ppd->offline_disabled_reason = ppd->offline_disabled_reason =
HFI1_ODR_MASK(OPA_LINKDOWN_REASON_TRANSIENT); HFI1_ODR_MASK(OPA_LINKDOWN_REASON_TRANSIENT);
/* offline_state_ret = wait_phys_link_offline_substates(ppd, 10000);
* Wait for offline transition. It can take a while for if (offline_state_ret < 0)
* the link to go down. return offline_state_ret;
*/
ret = wait_physical_linkstate(ppd, PLS_OFFLINE, 10000);
if (ret < 0)
return ret;
/*
* Now in charge of LCB - must be after the physical state is
* offline.quiet and before host_link_state is changed.
*/
set_host_lcb_access(dd);
write_csr(dd, DC_LCB_ERR_EN, ~0ull); /* watch LCB errors */
/* make sure the logical state is also down */
ret = wait_logical_linkstate(ppd, IB_PORT_DOWN, 1000);
if (ret)
force_logical_link_state_down(ppd);
ppd->host_link_state = HLS_LINK_COOLDOWN; /* LCB access allowed */
/* Disabling AOC transmitters */
if (ppd->port_type == PORT_TYPE_QSFP && if (ppd->port_type == PORT_TYPE_QSFP &&
ppd->qsfp_info.limiting_active && ppd->qsfp_info.limiting_active &&
qsfp_mod_present(ppd)) { qsfp_mod_present(ppd)) {
@ -10364,6 +10359,30 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason)
} }
} }
/*
* Wait for the offline.Quiet transition if it hasn't happened yet. It
* can take a while for the link to go down.
*/
if (offline_state_ret != PLS_OFFLINE_QUIET) {
ret = wait_physical_linkstate(ppd, PLS_OFFLINE, 30000);
if (ret < 0)
return ret;
}
/*
* Now in charge of LCB - must be after the physical state is
* offline.quiet and before host_link_state is changed.
*/
set_host_lcb_access(dd);
write_csr(dd, DC_LCB_ERR_EN, ~0ull); /* watch LCB errors */
/* make sure the logical state is also down */
ret = wait_logical_linkstate(ppd, IB_PORT_DOWN, 1000);
if (ret)
force_logical_link_state_down(ppd);
ppd->host_link_state = HLS_LINK_COOLDOWN; /* LCB access allowed */
/* /*
* The LNI has a mandatory wait time after the physical state * The LNI has a mandatory wait time after the physical state
* moves to Offline.Quiet. The wait time may be different * moves to Offline.Quiet. The wait time may be different
@ -10396,6 +10415,9 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason)
& (HLS_DN_POLL | HLS_VERIFY_CAP | HLS_GOING_UP)) { & (HLS_DN_POLL | HLS_VERIFY_CAP | HLS_GOING_UP)) {
/* went down while attempting link up */ /* went down while attempting link up */
check_lni_states(ppd); check_lni_states(ppd);
/* The QSFP doesn't need to be reset on LNI failure */
ppd->qsfp_info.reset_needed = 0;
} }
/* the active link width (downgrade) is 0 on link down */ /* the active link width (downgrade) is 0 on link down */
@ -12804,6 +12826,39 @@ static int wait_physical_linkstate(struct hfi1_pportdata *ppd, u32 state,
return 0; return 0;
} }
/*
* wait_phys_link_offline_quiet_substates - wait for any offline substate
* @ppd: port device
* @msecs: the number of milliseconds to wait
*
* Wait up to msecs milliseconds for any offline physical link
* state change to occur.
* Returns 0 if at least one state is reached, otherwise -ETIMEDOUT.
*/
static int wait_phys_link_offline_substates(struct hfi1_pportdata *ppd,
int msecs)
{
u32 read_state;
unsigned long timeout;
timeout = jiffies + msecs_to_jiffies(msecs);
while (1) {
read_state = read_physical_state(ppd->dd);
if ((read_state & 0xF0) == PLS_OFFLINE)
break;
if (time_after(jiffies, timeout)) {
dd_dev_err(ppd->dd,
"timeout waiting for phy link offline.quiet substates. Read state 0x%x, %dms\n",
read_state, msecs);
return -ETIMEDOUT;
}
usleep_range(1950, 2050); /* sleep 2ms-ish */
}
log_state_transition(ppd, read_state);
return read_state;
}
#define CLEAR_STATIC_RATE_CONTROL_SMASK(r) \ #define CLEAR_STATIC_RATE_CONTROL_SMASK(r) \
(r &= ~SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK) (r &= ~SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK)

View File

@ -204,6 +204,7 @@
#define PLS_OFFLINE_READY_TO_QUIET_LT 0x92 #define PLS_OFFLINE_READY_TO_QUIET_LT 0x92
#define PLS_OFFLINE_REPORT_FAILURE 0x93 #define PLS_OFFLINE_REPORT_FAILURE 0x93
#define PLS_OFFLINE_READY_TO_QUIET_BCC 0x94 #define PLS_OFFLINE_READY_TO_QUIET_BCC 0x94
#define PLS_OFFLINE_QUIET_DURATION 0x95
#define PLS_POLLING 0x20 #define PLS_POLLING 0x20
#define PLS_POLLING_QUIET 0x20 #define PLS_POLLING_QUIET 0x20
#define PLS_POLLING_ACTIVE 0x21 #define PLS_POLLING_ACTIVE 0x21
@ -722,7 +723,7 @@ void handle_link_downgrade(struct work_struct *work);
void handle_link_bounce(struct work_struct *work); void handle_link_bounce(struct work_struct *work);
void handle_start_link(struct work_struct *work); void handle_start_link(struct work_struct *work);
void handle_sma_message(struct work_struct *work); void handle_sma_message(struct work_struct *work);
void reset_qsfp(struct hfi1_pportdata *ppd); int reset_qsfp(struct hfi1_pportdata *ppd);
void qsfp_event(struct work_struct *work); void qsfp_event(struct work_struct *work);
void start_freeze_handling(struct hfi1_pportdata *ppd, int flags); void start_freeze_handling(struct hfi1_pportdata *ppd, int flags);
int send_idle_sma(struct hfi1_devdata *dd, u64 message); int send_idle_sma(struct hfi1_devdata *dd, u64 message);

View File

@ -204,7 +204,10 @@ int eprom_init(struct hfi1_devdata *dd)
return ret; return ret;
} }
/* magic character sequence that trails an image */ /* magic character sequence that begins an image */
#define IMAGE_START_MAGIC "APO="
/* magic character sequence that might trail an image */
#define IMAGE_TRAIL_MAGIC "egamiAPO" #define IMAGE_TRAIL_MAGIC "egamiAPO"
/* EPROM file types */ /* EPROM file types */
@ -250,6 +253,7 @@ static int read_partition_platform_config(struct hfi1_devdata *dd, void **data,
{ {
void *buffer; void *buffer;
void *p; void *p;
u32 length;
int ret; int ret;
buffer = kmalloc(P1_SIZE, GFP_KERNEL); buffer = kmalloc(P1_SIZE, GFP_KERNEL);
@ -262,15 +266,21 @@ static int read_partition_platform_config(struct hfi1_devdata *dd, void **data,
return ret; return ret;
} }
/* scan for image magic that may trail the actual data */ /* config partition is valid only if it starts with IMAGE_START_MAGIC */
p = strnstr(buffer, IMAGE_TRAIL_MAGIC, P1_SIZE); if (memcmp(buffer, IMAGE_START_MAGIC, strlen(IMAGE_START_MAGIC))) {
if (!p) {
kfree(buffer); kfree(buffer);
return -ENOENT; return -ENOENT;
} }
/* scan for image magic that may trail the actual data */
p = strnstr(buffer, IMAGE_TRAIL_MAGIC, P1_SIZE);
if (p)
length = p - buffer;
else
length = P1_SIZE;
*data = buffer; *data = buffer;
*size = p - buffer; *size = length;
return 0; return 0;
} }

View File

@ -930,15 +930,8 @@ static int assign_ctxt(struct hfi1_filedata *fd, struct hfi1_user_info *uinfo)
switch (ret) { switch (ret) {
case 0: case 0:
ret = setup_base_ctxt(fd, uctxt); ret = setup_base_ctxt(fd, uctxt);
if (uctxt->subctxt_cnt) { if (ret)
/* deallocate_ctxt(uctxt);
* Base context is done (successfully or not), notify
* anybody using a sub-context that is waiting for
* this completion.
*/
clear_bit(HFI1_CTXT_BASE_UNINIT, &uctxt->event_flags);
wake_up(&uctxt->wait);
}
break; break;
case 1: case 1:
ret = complete_subctxt(fd); ret = complete_subctxt(fd);
@ -1305,25 +1298,25 @@ static int setup_base_ctxt(struct hfi1_filedata *fd,
/* Now allocate the RcvHdr queue and eager buffers. */ /* Now allocate the RcvHdr queue and eager buffers. */
ret = hfi1_create_rcvhdrq(dd, uctxt); ret = hfi1_create_rcvhdrq(dd, uctxt);
if (ret) if (ret)
return ret; goto done;
ret = hfi1_setup_eagerbufs(uctxt); ret = hfi1_setup_eagerbufs(uctxt);
if (ret) if (ret)
goto setup_failed; goto done;
/* If sub-contexts are enabled, do the appropriate setup */ /* If sub-contexts are enabled, do the appropriate setup */
if (uctxt->subctxt_cnt) if (uctxt->subctxt_cnt)
ret = setup_subctxt(uctxt); ret = setup_subctxt(uctxt);
if (ret) if (ret)
goto setup_failed; goto done;
ret = hfi1_alloc_ctxt_rcv_groups(uctxt); ret = hfi1_alloc_ctxt_rcv_groups(uctxt);
if (ret) if (ret)
goto setup_failed; goto done;
ret = init_user_ctxt(fd, uctxt); ret = init_user_ctxt(fd, uctxt);
if (ret) if (ret)
goto setup_failed; goto done;
user_init(uctxt); user_init(uctxt);
@ -1331,12 +1324,22 @@ static int setup_base_ctxt(struct hfi1_filedata *fd,
fd->uctxt = uctxt; fd->uctxt = uctxt;
hfi1_rcd_get(uctxt); hfi1_rcd_get(uctxt);
return 0; done:
if (uctxt->subctxt_cnt) {
/*
* On error, set the failed bit so sub-contexts will clean up
* correctly.
*/
if (ret)
set_bit(HFI1_CTXT_BASE_FAILED, &uctxt->event_flags);
setup_failed: /*
/* Set the failed bit so sub-context init can do the right thing */ * Base context is done (successfully or not), notify anybody
set_bit(HFI1_CTXT_BASE_FAILED, &uctxt->event_flags); * using a sub-context that is waiting for this completion.
deallocate_ctxt(uctxt); */
clear_bit(HFI1_CTXT_BASE_UNINIT, &uctxt->event_flags);
wake_up(&uctxt->wait);
}
return ret; return ret;
} }

View File

@ -68,7 +68,7 @@
/* /*
* Code to adjust PCIe capabilities. * Code to adjust PCIe capabilities.
*/ */
static int tune_pcie_caps(struct hfi1_devdata *); static void tune_pcie_caps(struct hfi1_devdata *);
/* /*
* Do all the common PCIe setup and initialization. * Do all the common PCIe setup and initialization.
@ -351,7 +351,7 @@ int pcie_speeds(struct hfi1_devdata *dd)
*/ */
int request_msix(struct hfi1_devdata *dd, u32 msireq) int request_msix(struct hfi1_devdata *dd, u32 msireq)
{ {
int nvec, ret; int nvec;
nvec = pci_alloc_irq_vectors(dd->pcidev, 1, msireq, nvec = pci_alloc_irq_vectors(dd->pcidev, 1, msireq,
PCI_IRQ_MSIX | PCI_IRQ_LEGACY); PCI_IRQ_MSIX | PCI_IRQ_LEGACY);
@ -360,12 +360,7 @@ int request_msix(struct hfi1_devdata *dd, u32 msireq)
return nvec; return nvec;
} }
ret = tune_pcie_caps(dd); tune_pcie_caps(dd);
if (ret) {
dd_dev_err(dd, "tune_pcie_caps() failed: %d\n", ret);
pci_free_irq_vectors(dd->pcidev);
return ret;
}
/* check for legacy IRQ */ /* check for legacy IRQ */
if (nvec == 1 && !dd->pcidev->msix_enabled) if (nvec == 1 && !dd->pcidev->msix_enabled)
@ -502,7 +497,7 @@ uint aspm_mode = ASPM_MODE_DISABLED;
module_param_named(aspm, aspm_mode, uint, S_IRUGO); module_param_named(aspm, aspm_mode, uint, S_IRUGO);
MODULE_PARM_DESC(aspm, "PCIe ASPM: 0: disable, 1: enable, 2: dynamic"); MODULE_PARM_DESC(aspm, "PCIe ASPM: 0: disable, 1: enable, 2: dynamic");
static int tune_pcie_caps(struct hfi1_devdata *dd) static void tune_pcie_caps(struct hfi1_devdata *dd)
{ {
struct pci_dev *parent; struct pci_dev *parent;
u16 rc_mpss, rc_mps, ep_mpss, ep_mps; u16 rc_mpss, rc_mps, ep_mpss, ep_mps;
@ -513,22 +508,14 @@ static int tune_pcie_caps(struct hfi1_devdata *dd)
* Turn on extended tags in DevCtl in case the BIOS has turned it off * Turn on extended tags in DevCtl in case the BIOS has turned it off
* to improve WFR SDMA bandwidth * to improve WFR SDMA bandwidth
*/ */
ret = pcie_capability_read_word(dd->pcidev, ret = pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVCTL, &ectl);
PCI_EXP_DEVCTL, &ectl); if ((!ret) && !(ectl & PCI_EXP_DEVCTL_EXT_TAG)) {
if (ret) {
dd_dev_err(dd, "Unable to read from PCI config\n");
return ret;
}
if (!(ectl & PCI_EXP_DEVCTL_EXT_TAG)) {
dd_dev_info(dd, "Enabling PCIe extended tags\n"); dd_dev_info(dd, "Enabling PCIe extended tags\n");
ectl |= PCI_EXP_DEVCTL_EXT_TAG; ectl |= PCI_EXP_DEVCTL_EXT_TAG;
ret = pcie_capability_write_word(dd->pcidev, ret = pcie_capability_write_word(dd->pcidev,
PCI_EXP_DEVCTL, ectl); PCI_EXP_DEVCTL, ectl);
if (ret) { if (ret)
dd_dev_err(dd, "Unable to write to PCI config\n"); dd_dev_info(dd, "Unable to write to PCI config\n");
return ret;
}
} }
/* Find out supported and configured values for parent (root) */ /* Find out supported and configured values for parent (root) */
parent = dd->pcidev->bus->self; parent = dd->pcidev->bus->self;
@ -536,15 +523,22 @@ static int tune_pcie_caps(struct hfi1_devdata *dd)
* The driver cannot perform the tuning if it does not have * The driver cannot perform the tuning if it does not have
* access to the upstream component. * access to the upstream component.
*/ */
if (!parent) if (!parent) {
return -EINVAL; dd_dev_info(dd, "Parent not found\n");
return;
}
if (!pci_is_root_bus(parent->bus)) { if (!pci_is_root_bus(parent->bus)) {
dd_dev_info(dd, "Parent not root\n"); dd_dev_info(dd, "Parent not root\n");
return -EINVAL; return;
}
if (!pci_is_pcie(parent)) {
dd_dev_info(dd, "Parent is not PCI Express capable\n");
return;
}
if (!pci_is_pcie(dd->pcidev)) {
dd_dev_info(dd, "PCI device is not PCI Express capable\n");
return;
} }
if (!pci_is_pcie(parent) || !pci_is_pcie(dd->pcidev))
return -EINVAL;
rc_mpss = parent->pcie_mpss; rc_mpss = parent->pcie_mpss;
rc_mps = ffs(pcie_get_mps(parent)) - 8; rc_mps = ffs(pcie_get_mps(parent)) - 8;
/* Find out supported and configured values for endpoint (us) */ /* Find out supported and configured values for endpoint (us) */
@ -590,8 +584,6 @@ static int tune_pcie_caps(struct hfi1_devdata *dd)
ep_mrrs = max_mrrs; ep_mrrs = max_mrrs;
pcie_set_readrq(dd->pcidev, ep_mrrs); pcie_set_readrq(dd->pcidev, ep_mrrs);
} }
return 0;
} }
/* End of PCIe capability tuning */ /* End of PCIe capability tuning */

View File

@ -790,7 +790,9 @@ static int tune_active_qsfp(struct hfi1_pportdata *ppd, u32 *ptr_tx_preset,
* reuse of stale settings established in our previous pass through. * reuse of stale settings established in our previous pass through.
*/ */
if (ppd->qsfp_info.reset_needed) { if (ppd->qsfp_info.reset_needed) {
reset_qsfp(ppd); ret = reset_qsfp(ppd);
if (ret)
return ret;
refresh_qsfp_cache(ppd, &ppd->qsfp_info); refresh_qsfp_cache(ppd, &ppd->qsfp_info);
} else { } else {
ppd->qsfp_info.reset_needed = 1; ppd->qsfp_info.reset_needed = 1;

View File

@ -778,13 +778,13 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
} }
if (MLX5_CAP_GEN(mdev, tag_matching)) { if (MLX5_CAP_GEN(mdev, tag_matching)) {
props->xrq_caps.max_rndv_hdr_size = MLX5_TM_MAX_RNDV_MSG_SIZE; props->tm_caps.max_rndv_hdr_size = MLX5_TM_MAX_RNDV_MSG_SIZE;
props->xrq_caps.max_num_tags = props->tm_caps.max_num_tags =
(1 << MLX5_CAP_GEN(mdev, log_tag_matching_list_sz)) - 1; (1 << MLX5_CAP_GEN(mdev, log_tag_matching_list_sz)) - 1;
props->xrq_caps.flags = IB_TM_CAP_RC; props->tm_caps.flags = IB_TM_CAP_RC;
props->xrq_caps.max_ops = props->tm_caps.max_ops =
1 << MLX5_CAP_GEN(mdev, log_max_qp_sz); 1 << MLX5_CAP_GEN(mdev, log_max_qp_sz);
props->xrq_caps.max_sge = MLX5_TM_MAX_SGE; props->tm_caps.max_sge = MLX5_TM_MAX_SGE;
} }
if (field_avail(typeof(resp), cqe_comp_caps, uhw->outlen)) { if (field_avail(typeof(resp), cqe_comp_caps, uhw->outlen)) {

View File

@ -50,13 +50,9 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr,
{ {
unsigned long tmp; unsigned long tmp;
unsigned long m; unsigned long m;
int i, k; u64 base = ~0, p = 0;
u64 base = 0; u64 len, pfn;
int p = 0; int i = 0;
int skip;
int mask;
u64 len;
u64 pfn;
struct scatterlist *sg; struct scatterlist *sg;
int entry; int entry;
unsigned long page_shift = umem->page_shift; unsigned long page_shift = umem->page_shift;
@ -76,33 +72,24 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr,
m = find_first_bit(&tmp, BITS_PER_LONG); m = find_first_bit(&tmp, BITS_PER_LONG);
if (max_page_shift) if (max_page_shift)
m = min_t(unsigned long, max_page_shift - page_shift, m); m = min_t(unsigned long, max_page_shift - page_shift, m);
skip = 1 << m;
mask = skip - 1;
i = 0;
for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) { for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
len = sg_dma_len(sg) >> page_shift; len = sg_dma_len(sg) >> page_shift;
pfn = sg_dma_address(sg) >> page_shift; pfn = sg_dma_address(sg) >> page_shift;
for (k = 0; k < len; k++) { if (base + p != pfn) {
if (!(i & mask)) { /* If either the offset or the new
tmp = (unsigned long)pfn; * base are unaligned update m
m = min_t(unsigned long, m, find_first_bit(&tmp, BITS_PER_LONG)); */
skip = 1 << m; tmp = (unsigned long)(pfn | p);
mask = skip - 1; if (!IS_ALIGNED(tmp, 1 << m))
base = pfn; m = find_first_bit(&tmp, BITS_PER_LONG);
p = 0;
} else { base = pfn;
if (base + p != pfn) { p = 0;
tmp = (unsigned long)p;
m = find_first_bit(&tmp, BITS_PER_LONG);
skip = 1 << m;
mask = skip - 1;
base = pfn;
p = 0;
}
}
p++;
i++;
} }
p += len;
i += len;
} }
if (i) { if (i) {

View File

@ -47,7 +47,8 @@ enum {
#define MLX5_UMR_ALIGN 2048 #define MLX5_UMR_ALIGN 2048
static int clean_mr(struct mlx5_ib_mr *mr); static int clean_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr);
static int dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr);
static int mr_cache_max_order(struct mlx5_ib_dev *dev); static int mr_cache_max_order(struct mlx5_ib_dev *dev);
static int unreg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr); static int unreg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr);
@ -1270,8 +1271,9 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
err = mlx5_ib_update_xlt(mr, 0, ncont, page_shift, err = mlx5_ib_update_xlt(mr, 0, ncont, page_shift,
update_xlt_flags); update_xlt_flags);
if (err) { if (err) {
mlx5_ib_dereg_mr(&mr->ibmr); dereg_mr(dev, mr);
return ERR_PTR(err); return ERR_PTR(err);
} }
} }
@ -1356,7 +1358,7 @@ int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
err = mr_umem_get(pd, addr, len, access_flags, &mr->umem, err = mr_umem_get(pd, addr, len, access_flags, &mr->umem,
&npages, &page_shift, &ncont, &order); &npages, &page_shift, &ncont, &order);
if (err < 0) { if (err < 0) {
clean_mr(mr); clean_mr(dev, mr);
return err; return err;
} }
} }
@ -1410,7 +1412,7 @@ int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
if (err) { if (err) {
mlx5_ib_warn(dev, "Failed to rereg UMR\n"); mlx5_ib_warn(dev, "Failed to rereg UMR\n");
ib_umem_release(mr->umem); ib_umem_release(mr->umem);
clean_mr(mr); clean_mr(dev, mr);
return err; return err;
} }
} }
@ -1469,9 +1471,8 @@ mlx5_free_priv_descs(struct mlx5_ib_mr *mr)
} }
} }
static int clean_mr(struct mlx5_ib_mr *mr) static int clean_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
{ {
struct mlx5_ib_dev *dev = to_mdev(mr->ibmr.device);
int allocated_from_cache = mr->allocated_from_cache; int allocated_from_cache = mr->allocated_from_cache;
int err; int err;
@ -1507,10 +1508,8 @@ static int clean_mr(struct mlx5_ib_mr *mr)
return 0; return 0;
} }
int mlx5_ib_dereg_mr(struct ib_mr *ibmr) static int dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
{ {
struct mlx5_ib_dev *dev = to_mdev(ibmr->device);
struct mlx5_ib_mr *mr = to_mmr(ibmr);
int npages = mr->npages; int npages = mr->npages;
struct ib_umem *umem = mr->umem; struct ib_umem *umem = mr->umem;
@ -1539,7 +1538,7 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr)
} }
#endif #endif
clean_mr(mr); clean_mr(dev, mr);
if (umem) { if (umem) {
ib_umem_release(umem); ib_umem_release(umem);
@ -1549,6 +1548,14 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr)
return 0; return 0;
} }
int mlx5_ib_dereg_mr(struct ib_mr *ibmr)
{
struct mlx5_ib_dev *dev = to_mdev(ibmr->device);
struct mlx5_ib_mr *mr = to_mmr(ibmr);
return dereg_mr(dev, mr);
}
struct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd, struct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd,
enum ib_mr_type mr_type, enum ib_mr_type mr_type,
u32 max_num_sg) u32 max_num_sg)

View File

@ -3232,7 +3232,7 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
mr->ibmr.iova); mr->ibmr.iova);
set_wqe_32bit_value(wqe->wqe_words, set_wqe_32bit_value(wqe->wqe_words,
NES_IWARP_SQ_FMR_WQE_LENGTH_LOW_IDX, NES_IWARP_SQ_FMR_WQE_LENGTH_LOW_IDX,
mr->ibmr.length); lower_32_bits(mr->ibmr.length));
set_wqe_32bit_value(wqe->wqe_words, set_wqe_32bit_value(wqe->wqe_words,
NES_IWARP_SQ_FMR_WQE_LENGTH_HIGH_IDX, 0); NES_IWARP_SQ_FMR_WQE_LENGTH_HIGH_IDX, 0);
set_wqe_32bit_value(wqe->wqe_words, set_wqe_32bit_value(wqe->wqe_words,
@ -3274,7 +3274,7 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
mr->npages * 8); mr->npages * 8);
nes_debug(NES_DBG_IW_TX, "SQ_REG_MR: iova_start: %llx, " nes_debug(NES_DBG_IW_TX, "SQ_REG_MR: iova_start: %llx, "
"length: %d, rkey: %0x, pgl_paddr: %llx, " "length: %lld, rkey: %0x, pgl_paddr: %llx, "
"page_list_len: %u, wqe_misc: %x\n", "page_list_len: %u, wqe_misc: %x\n",
(unsigned long long) mr->ibmr.iova, (unsigned long long) mr->ibmr.iova,
mr->ibmr.length, mr->ibmr.length,

View File

@ -1000,19 +1000,6 @@ static inline int update_parent_pkey(struct ipoib_dev_priv *priv)
*/ */
priv->dev->broadcast[8] = priv->pkey >> 8; priv->dev->broadcast[8] = priv->pkey >> 8;
priv->dev->broadcast[9] = priv->pkey & 0xff; priv->dev->broadcast[9] = priv->pkey & 0xff;
/*
* Update the broadcast address in the priv->broadcast object,
* in case it already exists, otherwise no one will do that.
*/
if (priv->broadcast) {
spin_lock_irq(&priv->lock);
memcpy(priv->broadcast->mcmember.mgid.raw,
priv->dev->broadcast + 4,
sizeof(union ib_gid));
spin_unlock_irq(&priv->lock);
}
return 0; return 0;
} }

View File

@ -2180,6 +2180,7 @@ static struct net_device *ipoib_add_port(const char *format,
{ {
struct ipoib_dev_priv *priv; struct ipoib_dev_priv *priv;
struct ib_port_attr attr; struct ib_port_attr attr;
struct rdma_netdev *rn;
int result = -ENOMEM; int result = -ENOMEM;
priv = ipoib_intf_alloc(hca, port, format); priv = ipoib_intf_alloc(hca, port, format);
@ -2279,7 +2280,8 @@ static struct net_device *ipoib_add_port(const char *format,
ipoib_dev_cleanup(priv->dev); ipoib_dev_cleanup(priv->dev);
device_init_failed: device_init_failed:
free_netdev(priv->dev); rn = netdev_priv(priv->dev);
rn->free_rdma_netdev(priv->dev);
kfree(priv); kfree(priv);
alloc_mem_failed: alloc_mem_failed:
@ -2328,7 +2330,7 @@ static void ipoib_remove_one(struct ib_device *device, void *client_data)
return; return;
list_for_each_entry_safe(priv, tmp, dev_list, list) { list_for_each_entry_safe(priv, tmp, dev_list, list) {
struct rdma_netdev *rn = netdev_priv(priv->dev); struct rdma_netdev *parent_rn = netdev_priv(priv->dev);
ib_unregister_event_handler(&priv->event_handler); ib_unregister_event_handler(&priv->event_handler);
flush_workqueue(ipoib_workqueue); flush_workqueue(ipoib_workqueue);
@ -2350,10 +2352,15 @@ static void ipoib_remove_one(struct ib_device *device, void *client_data)
unregister_netdev(priv->dev); unregister_netdev(priv->dev);
mutex_unlock(&priv->sysfs_mutex); mutex_unlock(&priv->sysfs_mutex);
rn->free_rdma_netdev(priv->dev); parent_rn->free_rdma_netdev(priv->dev);
list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) {
struct rdma_netdev *child_rn;
child_rn = netdev_priv(cpriv->dev);
child_rn->free_rdma_netdev(cpriv->dev);
kfree(cpriv); kfree(cpriv);
}
kfree(priv); kfree(priv);
} }

View File

@ -141,14 +141,17 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
return restart_syscall(); return restart_syscall();
} }
priv = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name); if (!down_write_trylock(&ppriv->vlan_rwsem)) {
if (!priv) {
rtnl_unlock(); rtnl_unlock();
mutex_unlock(&ppriv->sysfs_mutex); mutex_unlock(&ppriv->sysfs_mutex);
return -ENOMEM; return restart_syscall();
} }
down_write(&ppriv->vlan_rwsem); priv = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name);
if (!priv) {
result = -ENOMEM;
goto out;
}
/* /*
* First ensure this isn't a duplicate. We check the parent device and * First ensure this isn't a duplicate. We check the parent device and
@ -175,8 +178,11 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
rtnl_unlock(); rtnl_unlock();
mutex_unlock(&ppriv->sysfs_mutex); mutex_unlock(&ppriv->sysfs_mutex);
if (result) { if (result && priv) {
free_netdev(priv->dev); struct rdma_netdev *rn;
rn = netdev_priv(priv->dev);
rn->free_rdma_netdev(priv->dev);
kfree(priv); kfree(priv);
} }
@ -204,7 +210,12 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
return restart_syscall(); return restart_syscall();
} }
down_write(&ppriv->vlan_rwsem); if (!down_write_trylock(&ppriv->vlan_rwsem)) {
rtnl_unlock();
mutex_unlock(&ppriv->sysfs_mutex);
return restart_syscall();
}
list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
if (priv->pkey == pkey && if (priv->pkey == pkey &&
priv->child_type == IPOIB_LEGACY_CHILD) { priv->child_type == IPOIB_LEGACY_CHILD) {
@ -224,7 +235,10 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
mutex_unlock(&ppriv->sysfs_mutex); mutex_unlock(&ppriv->sysfs_mutex);
if (dev) { if (dev) {
free_netdev(dev); struct rdma_netdev *rn;
rn = netdev_priv(dev);
rn->free_rdma_netdev(priv->dev);
kfree(priv); kfree(priv);
return 0; return 0;
} }

View File

@ -154,7 +154,7 @@ static void iser_dump_page_vec(struct iser_page_vec *page_vec)
{ {
int i; int i;
iser_err("page vec npages %d data length %d\n", iser_err("page vec npages %d data length %lld\n",
page_vec->npages, page_vec->fake_mr.length); page_vec->npages, page_vec->fake_mr.length);
for (i = 0; i < page_vec->npages; i++) for (i = 0; i < page_vec->npages; i++)
iser_err("vec[%d]: %llx\n", i, page_vec->pages[i]); iser_err("vec[%d]: %llx\n", i, page_vec->pages[i]);

View File

@ -874,7 +874,7 @@ static bool copy_device_table(void)
hi = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET + 4); hi = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET + 4);
entry = (((u64) hi) << 32) + lo; entry = (((u64) hi) << 32) + lo;
if (last_entry && last_entry != entry) { if (last_entry && last_entry != entry) {
pr_err("IOMMU:%d should use the same dev table as others!/n", pr_err("IOMMU:%d should use the same dev table as others!\n",
iommu->index); iommu->index);
return false; return false;
} }
@ -882,7 +882,7 @@ static bool copy_device_table(void)
old_devtb_size = ((entry & ~PAGE_MASK) + 1) << 12; old_devtb_size = ((entry & ~PAGE_MASK) + 1) << 12;
if (old_devtb_size != dev_table_size) { if (old_devtb_size != dev_table_size) {
pr_err("The device table size of IOMMU:%d is not expected!/n", pr_err("The device table size of IOMMU:%d is not expected!\n",
iommu->index); iommu->index);
return false; return false;
} }
@ -890,7 +890,7 @@ static bool copy_device_table(void)
old_devtb_phys = entry & PAGE_MASK; old_devtb_phys = entry & PAGE_MASK;
if (old_devtb_phys >= 0x100000000ULL) { if (old_devtb_phys >= 0x100000000ULL) {
pr_err("The address of old device table is above 4G, not trustworthy!/n"); pr_err("The address of old device table is above 4G, not trustworthy!\n");
return false; return false;
} }
old_devtb = memremap(old_devtb_phys, dev_table_size, MEMREMAP_WB); old_devtb = memremap(old_devtb_phys, dev_table_size, MEMREMAP_WB);
@ -901,7 +901,7 @@ static bool copy_device_table(void)
old_dev_tbl_cpy = (void *)__get_free_pages(gfp_flag, old_dev_tbl_cpy = (void *)__get_free_pages(gfp_flag,
get_order(dev_table_size)); get_order(dev_table_size));
if (old_dev_tbl_cpy == NULL) { if (old_dev_tbl_cpy == NULL) {
pr_err("Failed to allocate memory for copying old device table!/n"); pr_err("Failed to allocate memory for copying old device table!\n");
return false; return false;
} }

View File

@ -245,7 +245,7 @@ static void __arm_v7s_free_table(void *table, int lvl,
static void __arm_v7s_pte_sync(arm_v7s_iopte *ptep, int num_entries, static void __arm_v7s_pte_sync(arm_v7s_iopte *ptep, int num_entries,
struct io_pgtable_cfg *cfg) struct io_pgtable_cfg *cfg)
{ {
if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)) if (cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)
return; return;
dma_sync_single_for_device(cfg->iommu_dev, __arm_v7s_dma_addr(ptep), dma_sync_single_for_device(cfg->iommu_dev, __arm_v7s_dma_addr(ptep),

View File

@ -371,7 +371,8 @@ static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
int ret; int ret;
spin_lock_irqsave(&dom->pgtlock, flags); spin_lock_irqsave(&dom->pgtlock, flags);
ret = dom->iop->map(dom->iop, iova, paddr, size, prot); ret = dom->iop->map(dom->iop, iova, paddr & DMA_BIT_MASK(32),
size, prot);
spin_unlock_irqrestore(&dom->pgtlock, flags); spin_unlock_irqrestore(&dom->pgtlock, flags);
return ret; return ret;

View File

@ -175,14 +175,13 @@ static void gic_mask_irq(struct irq_data *d)
static void gic_unmask_irq(struct irq_data *d) static void gic_unmask_irq(struct irq_data *d)
{ {
struct cpumask *affinity = irq_data_get_affinity_mask(d);
unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq); unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq);
unsigned int cpu; unsigned int cpu;
write_gic_smask(intr); write_gic_smask(intr);
gic_clear_pcpu_masks(intr); gic_clear_pcpu_masks(intr);
cpu = cpumask_first_and(affinity, cpu_online_mask); cpu = cpumask_first(irq_data_get_effective_affinity_mask(d));
set_bit(intr, per_cpu_ptr(pcpu_masks, cpu)); set_bit(intr, per_cpu_ptr(pcpu_masks, cpu));
} }
@ -420,13 +419,17 @@ static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hw, unsigned int cpu) irq_hw_number_t hw, unsigned int cpu)
{ {
int intr = GIC_HWIRQ_TO_SHARED(hw); int intr = GIC_HWIRQ_TO_SHARED(hw);
struct irq_data *data;
unsigned long flags; unsigned long flags;
data = irq_get_irq_data(virq);
spin_lock_irqsave(&gic_lock, flags); spin_lock_irqsave(&gic_lock, flags);
write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin); write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin);
write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu))); write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu)));
gic_clear_pcpu_masks(intr); gic_clear_pcpu_masks(intr);
set_bit(intr, per_cpu_ptr(pcpu_masks, cpu)); set_bit(intr, per_cpu_ptr(pcpu_masks, cpu));
irq_data_update_effective_affinity(data, cpumask_of(cpu));
spin_unlock_irqrestore(&gic_lock, flags); spin_unlock_irqrestore(&gic_lock, flags);
return 0; return 0;
@ -645,7 +648,7 @@ static int __init gic_of_init(struct device_node *node,
/* Find the first available CPU vector. */ /* Find the first available CPU vector. */
i = 0; i = 0;
reserved = (C_SW0 | C_SW1) >> __fls(C_SW0); reserved = (C_SW0 | C_SW1) >> __ffs(C_SW0);
while (!of_property_read_u32_index(node, "mti,reserved-cpu-vectors", while (!of_property_read_u32_index(node, "mti,reserved-cpu-vectors",
i++, &cpu_vec)) i++, &cpu_vec))
reserved |= BIT(cpu_vec); reserved |= BIT(cpu_vec);
@ -684,11 +687,11 @@ static int __init gic_of_init(struct device_node *node,
gicconfig = read_gic_config(); gicconfig = read_gic_config();
gic_shared_intrs = gicconfig & GIC_CONFIG_NUMINTERRUPTS; gic_shared_intrs = gicconfig & GIC_CONFIG_NUMINTERRUPTS;
gic_shared_intrs >>= __fls(GIC_CONFIG_NUMINTERRUPTS); gic_shared_intrs >>= __ffs(GIC_CONFIG_NUMINTERRUPTS);
gic_shared_intrs = (gic_shared_intrs + 1) * 8; gic_shared_intrs = (gic_shared_intrs + 1) * 8;
gic_vpes = gicconfig & GIC_CONFIG_PVPS; gic_vpes = gicconfig & GIC_CONFIG_PVPS;
gic_vpes >>= __fls(GIC_CONFIG_PVPS); gic_vpes >>= __ffs(GIC_CONFIG_PVPS);
gic_vpes = gic_vpes + 1; gic_vpes = gic_vpes + 1;
if (cpu_has_veic) { if (cpu_has_veic) {

View File

@ -112,6 +112,10 @@
#define AS_PEAK_mA_TO_REG(a) \ #define AS_PEAK_mA_TO_REG(a) \
((min_t(u32, AS_PEAK_mA_MAX, a) - 1250) / 250) ((min_t(u32, AS_PEAK_mA_MAX, a) - 1250) / 250)
/* LED numbers for Devicetree */
#define AS_LED_FLASH 0
#define AS_LED_INDICATOR 1
enum as_mode { enum as_mode {
AS_MODE_EXT_TORCH = 0 << AS_CONTROL_MODE_SETTING_SHIFT, AS_MODE_EXT_TORCH = 0 << AS_CONTROL_MODE_SETTING_SHIFT,
AS_MODE_INDICATOR = 1 << AS_CONTROL_MODE_SETTING_SHIFT, AS_MODE_INDICATOR = 1 << AS_CONTROL_MODE_SETTING_SHIFT,
@ -491,10 +495,29 @@ static int as3645a_parse_node(struct as3645a *flash,
struct device_node *node) struct device_node *node)
{ {
struct as3645a_config *cfg = &flash->cfg; struct as3645a_config *cfg = &flash->cfg;
struct device_node *child;
const char *name; const char *name;
int rval; int rval;
flash->flash_node = of_get_child_by_name(node, "flash"); for_each_child_of_node(node, child) {
u32 id = 0;
of_property_read_u32(child, "reg", &id);
switch (id) {
case AS_LED_FLASH:
flash->flash_node = of_node_get(child);
break;
case AS_LED_INDICATOR:
flash->indicator_node = of_node_get(child);
break;
default:
dev_warn(&flash->client->dev,
"unknown LED %u encountered, ignoring\n", id);
break;
}
}
if (!flash->flash_node) { if (!flash->flash_node) {
dev_err(&flash->client->dev, "can't find flash node\n"); dev_err(&flash->client->dev, "can't find flash node\n");
return -ENODEV; return -ENODEV;
@ -534,11 +557,10 @@ static int as3645a_parse_node(struct as3645a *flash,
of_property_read_u32(flash->flash_node, "voltage-reference", of_property_read_u32(flash->flash_node, "voltage-reference",
&cfg->voltage_reference); &cfg->voltage_reference);
of_property_read_u32(flash->flash_node, "peak-current-limit", of_property_read_u32(flash->flash_node, "ams,input-max-microamp",
&cfg->peak); &cfg->peak);
cfg->peak = AS_PEAK_mA_TO_REG(cfg->peak); cfg->peak = AS_PEAK_mA_TO_REG(cfg->peak);
flash->indicator_node = of_get_child_by_name(node, "indicator");
if (!flash->indicator_node) { if (!flash->indicator_node) {
dev_warn(&flash->client->dev, dev_warn(&flash->client->dev,
"can't find indicator node\n"); "can't find indicator node\n");
@ -721,6 +743,7 @@ static int as3645a_remove(struct i2c_client *client)
as3645a_set_control(flash, AS_MODE_EXT_TORCH, false); as3645a_set_control(flash, AS_MODE_EXT_TORCH, false);
v4l2_flash_release(flash->vf); v4l2_flash_release(flash->vf);
v4l2_flash_release(flash->vfind);
led_classdev_flash_unregister(&flash->fled); led_classdev_flash_unregister(&flash->fled);
led_classdev_unregister(&flash->iled_cdev); led_classdev_unregister(&flash->iled_cdev);

View File

@ -3238,7 +3238,7 @@ static int raid_map(struct dm_target *ti, struct bio *bio)
if (unlikely(bio_end_sector(bio) > mddev->array_sectors)) if (unlikely(bio_end_sector(bio) > mddev->array_sectors))
return DM_MAPIO_REQUEUE; return DM_MAPIO_REQUEUE;
mddev->pers->make_request(mddev, bio); md_handle_request(mddev, bio);
return DM_MAPIO_SUBMITTED; return DM_MAPIO_SUBMITTED;
} }

View File

@ -266,6 +266,37 @@ static DEFINE_SPINLOCK(all_mddevs_lock);
* call has finished, the bio has been linked into some internal structure * call has finished, the bio has been linked into some internal structure
* and so is visible to ->quiesce(), so we don't need the refcount any more. * and so is visible to ->quiesce(), so we don't need the refcount any more.
*/ */
void md_handle_request(struct mddev *mddev, struct bio *bio)
{
check_suspended:
rcu_read_lock();
if (mddev->suspended) {
DEFINE_WAIT(__wait);
for (;;) {
prepare_to_wait(&mddev->sb_wait, &__wait,
TASK_UNINTERRUPTIBLE);
if (!mddev->suspended)
break;
rcu_read_unlock();
schedule();
rcu_read_lock();
}
finish_wait(&mddev->sb_wait, &__wait);
}
atomic_inc(&mddev->active_io);
rcu_read_unlock();
if (!mddev->pers->make_request(mddev, bio)) {
atomic_dec(&mddev->active_io);
wake_up(&mddev->sb_wait);
goto check_suspended;
}
if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended)
wake_up(&mddev->sb_wait);
}
EXPORT_SYMBOL(md_handle_request);
static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio) static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
{ {
const int rw = bio_data_dir(bio); const int rw = bio_data_dir(bio);
@ -285,23 +316,6 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
bio_endio(bio); bio_endio(bio);
return BLK_QC_T_NONE; return BLK_QC_T_NONE;
} }
check_suspended:
rcu_read_lock();
if (mddev->suspended) {
DEFINE_WAIT(__wait);
for (;;) {
prepare_to_wait(&mddev->sb_wait, &__wait,
TASK_UNINTERRUPTIBLE);
if (!mddev->suspended)
break;
rcu_read_unlock();
schedule();
rcu_read_lock();
}
finish_wait(&mddev->sb_wait, &__wait);
}
atomic_inc(&mddev->active_io);
rcu_read_unlock();
/* /*
* save the sectors now since our bio can * save the sectors now since our bio can
@ -310,20 +324,14 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
sectors = bio_sectors(bio); sectors = bio_sectors(bio);
/* bio could be mergeable after passing to underlayer */ /* bio could be mergeable after passing to underlayer */
bio->bi_opf &= ~REQ_NOMERGE; bio->bi_opf &= ~REQ_NOMERGE;
if (!mddev->pers->make_request(mddev, bio)) {
atomic_dec(&mddev->active_io); md_handle_request(mddev, bio);
wake_up(&mddev->sb_wait);
goto check_suspended;
}
cpu = part_stat_lock(); cpu = part_stat_lock();
part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]); part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw], sectors); part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw], sectors);
part_stat_unlock(); part_stat_unlock();
if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended)
wake_up(&mddev->sb_wait);
return BLK_QC_T_NONE; return BLK_QC_T_NONE;
} }
@ -439,16 +447,22 @@ static void md_submit_flush_data(struct work_struct *ws)
struct mddev *mddev = container_of(ws, struct mddev, flush_work); struct mddev *mddev = container_of(ws, struct mddev, flush_work);
struct bio *bio = mddev->flush_bio; struct bio *bio = mddev->flush_bio;
/*
* must reset flush_bio before calling into md_handle_request to avoid a
* deadlock, because other bios passed md_handle_request suspend check
* could wait for this and below md_handle_request could wait for those
* bios because of suspend check
*/
mddev->flush_bio = NULL;
wake_up(&mddev->sb_wait);
if (bio->bi_iter.bi_size == 0) if (bio->bi_iter.bi_size == 0)
/* an empty barrier - all done */ /* an empty barrier - all done */
bio_endio(bio); bio_endio(bio);
else { else {
bio->bi_opf &= ~REQ_PREFLUSH; bio->bi_opf &= ~REQ_PREFLUSH;
mddev->pers->make_request(mddev, bio); md_handle_request(mddev, bio);
} }
mddev->flush_bio = NULL;
wake_up(&mddev->sb_wait);
} }
void md_flush_request(struct mddev *mddev, struct bio *bio) void md_flush_request(struct mddev *mddev, struct bio *bio)

View File

@ -692,6 +692,7 @@ extern void md_stop_writes(struct mddev *mddev);
extern int md_rdev_init(struct md_rdev *rdev); extern int md_rdev_init(struct md_rdev *rdev);
extern void md_rdev_clear(struct md_rdev *rdev); extern void md_rdev_clear(struct md_rdev *rdev);
extern void md_handle_request(struct mddev *mddev, struct bio *bio);
extern void mddev_suspend(struct mddev *mddev); extern void mddev_suspend(struct mddev *mddev);
extern void mddev_resume(struct mddev *mddev); extern void mddev_resume(struct mddev *mddev);
extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,

View File

@ -6575,14 +6575,17 @@ static ssize_t
raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len) raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len)
{ {
struct r5conf *conf; struct r5conf *conf;
unsigned long new; unsigned int new;
int err; int err;
struct r5worker_group *new_groups, *old_groups; struct r5worker_group *new_groups, *old_groups;
int group_cnt, worker_cnt_per_group; int group_cnt, worker_cnt_per_group;
if (len >= PAGE_SIZE) if (len >= PAGE_SIZE)
return -EINVAL; return -EINVAL;
if (kstrtoul(page, 10, &new)) if (kstrtouint(page, 10, &new))
return -EINVAL;
/* 8192 should be big enough */
if (new > 8192)
return -EINVAL; return -EINVAL;
err = mddev_lock(mddev); err = mddev_lock(mddev);

View File

@ -392,6 +392,7 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
enum { enum {
INTEL_DSM_FNS = 0, INTEL_DSM_FNS = 0,
INTEL_DSM_V18_SWITCH = 3,
INTEL_DSM_DRV_STRENGTH = 9, INTEL_DSM_DRV_STRENGTH = 9,
INTEL_DSM_D3_RETUNE = 10, INTEL_DSM_D3_RETUNE = 10,
}; };
@ -557,6 +558,19 @@ static void intel_hs400_enhanced_strobe(struct mmc_host *mmc,
sdhci_writel(host, val, INTEL_HS400_ES_REG); sdhci_writel(host, val, INTEL_HS400_ES_REG);
} }
static void sdhci_intel_voltage_switch(struct sdhci_host *host)
{
struct sdhci_pci_slot *slot = sdhci_priv(host);
struct intel_host *intel_host = sdhci_pci_priv(slot);
struct device *dev = &slot->chip->pdev->dev;
u32 result = 0;
int err;
err = intel_dsm(intel_host, dev, INTEL_DSM_V18_SWITCH, &result);
pr_debug("%s: %s DSM error %d result %u\n",
mmc_hostname(host->mmc), __func__, err, result);
}
static const struct sdhci_ops sdhci_intel_byt_ops = { static const struct sdhci_ops sdhci_intel_byt_ops = {
.set_clock = sdhci_set_clock, .set_clock = sdhci_set_clock,
.set_power = sdhci_intel_set_power, .set_power = sdhci_intel_set_power,
@ -565,6 +579,7 @@ static const struct sdhci_ops sdhci_intel_byt_ops = {
.reset = sdhci_reset, .reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
.hw_reset = sdhci_pci_hw_reset, .hw_reset = sdhci_pci_hw_reset,
.voltage_switch = sdhci_intel_voltage_switch,
}; };
static void byt_read_dsm(struct sdhci_pci_slot *slot) static void byt_read_dsm(struct sdhci_pci_slot *slot)

View File

@ -129,50 +129,6 @@ static int tmio_mmc_next_sg(struct tmio_mmc_host *host)
#define CMDREQ_TIMEOUT 5000 #define CMDREQ_TIMEOUT 5000
#ifdef CONFIG_MMC_DEBUG
#define STATUS_TO_TEXT(a, status, i) \
do { \
if ((status) & TMIO_STAT_##a) { \
if ((i)++) \
printk(KERN_DEBUG " | "); \
printk(KERN_DEBUG #a); \
} \
} while (0)
static void pr_debug_status(u32 status)
{
int i = 0;
pr_debug("status: %08x = ", status);
STATUS_TO_TEXT(CARD_REMOVE, status, i);
STATUS_TO_TEXT(CARD_INSERT, status, i);
STATUS_TO_TEXT(SIGSTATE, status, i);
STATUS_TO_TEXT(WRPROTECT, status, i);
STATUS_TO_TEXT(CARD_REMOVE_A, status, i);
STATUS_TO_TEXT(CARD_INSERT_A, status, i);
STATUS_TO_TEXT(SIGSTATE_A, status, i);
STATUS_TO_TEXT(CMD_IDX_ERR, status, i);
STATUS_TO_TEXT(STOPBIT_ERR, status, i);
STATUS_TO_TEXT(ILL_FUNC, status, i);
STATUS_TO_TEXT(CMD_BUSY, status, i);
STATUS_TO_TEXT(CMDRESPEND, status, i);
STATUS_TO_TEXT(DATAEND, status, i);
STATUS_TO_TEXT(CRCFAIL, status, i);
STATUS_TO_TEXT(DATATIMEOUT, status, i);
STATUS_TO_TEXT(CMDTIMEOUT, status, i);
STATUS_TO_TEXT(RXOVERFLOW, status, i);
STATUS_TO_TEXT(TXUNDERRUN, status, i);
STATUS_TO_TEXT(RXRDY, status, i);
STATUS_TO_TEXT(TXRQ, status, i);
STATUS_TO_TEXT(ILL_ACCESS, status, i);
printk("\n");
}
#else
#define pr_debug_status(s) do { } while (0)
#endif
static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
{ {
struct tmio_mmc_host *host = mmc_priv(mmc); struct tmio_mmc_host *host = mmc_priv(mmc);
@ -762,9 +718,6 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid)
status = sd_ctrl_read16_and_16_as_32(host, CTL_STATUS); status = sd_ctrl_read16_and_16_as_32(host, CTL_STATUS);
ireg = status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask; ireg = status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask;
pr_debug_status(status);
pr_debug_status(ireg);
/* Clear the status except the interrupt status */ /* Clear the status except the interrupt status */
sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, TMIO_MASK_IRQ); sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, TMIO_MASK_IRQ);

View File

@ -581,6 +581,14 @@ static struct mtd_part *allocate_partition(struct mtd_info *parent,
slave->mtd.erasesize = parent->erasesize; slave->mtd.erasesize = parent->erasesize;
} }
/*
* Slave erasesize might differ from the master one if the master
* exposes several regions with different erasesize. Adjust
* wr_alignment accordingly.
*/
if (!(slave->mtd.flags & MTD_NO_ERASE))
wr_alignment = slave->mtd.erasesize;
tmp = slave->offset; tmp = slave->offset;
remainder = do_div(tmp, wr_alignment); remainder = do_div(tmp, wr_alignment);
if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) { if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {

View File

@ -363,7 +363,7 @@ atmel_pmecc_create_user(struct atmel_pmecc *pmecc,
size += (req->ecc.strength + 1) * sizeof(u16); size += (req->ecc.strength + 1) * sizeof(u16);
/* Reserve space for mu, dmu and delta. */ /* Reserve space for mu, dmu and delta. */
size = ALIGN(size, sizeof(s32)); size = ALIGN(size, sizeof(s32));
size += (req->ecc.strength + 1) * sizeof(s32); size += (req->ecc.strength + 1) * sizeof(s32) * 3;
user = kzalloc(size, GFP_KERNEL); user = kzalloc(size, GFP_KERNEL);
if (!user) if (!user)

View File

@ -134,8 +134,6 @@ static inline bool nvme_req_needs_retry(struct request *req)
return false; return false;
if (nvme_req(req)->status & NVME_SC_DNR) if (nvme_req(req)->status & NVME_SC_DNR)
return false; return false;
if (jiffies - req->start_time >= req->timeout)
return false;
if (nvme_req(req)->retries >= nvme_max_retries) if (nvme_req(req)->retries >= nvme_max_retries)
return false; return false;
return true; return true;
@ -2590,7 +2588,7 @@ static void nvme_async_event_work(struct work_struct *work)
container_of(work, struct nvme_ctrl, async_event_work); container_of(work, struct nvme_ctrl, async_event_work);
spin_lock_irq(&ctrl->lock); spin_lock_irq(&ctrl->lock);
while (ctrl->event_limit > 0) { while (ctrl->state == NVME_CTRL_LIVE && ctrl->event_limit > 0) {
int aer_idx = --ctrl->event_limit; int aer_idx = --ctrl->event_limit;
spin_unlock_irq(&ctrl->lock); spin_unlock_irq(&ctrl->lock);
@ -2677,7 +2675,8 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,
/*FALLTHRU*/ /*FALLTHRU*/
case NVME_SC_ABORT_REQ: case NVME_SC_ABORT_REQ:
++ctrl->event_limit; ++ctrl->event_limit;
queue_work(nvme_wq, &ctrl->async_event_work); if (ctrl->state == NVME_CTRL_LIVE)
queue_work(nvme_wq, &ctrl->async_event_work);
break; break;
default: default:
break; break;
@ -2692,7 +2691,7 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,
nvme_queue_scan(ctrl); nvme_queue_scan(ctrl);
break; break;
case NVME_AER_NOTICE_FW_ACT_STARTING: case NVME_AER_NOTICE_FW_ACT_STARTING:
schedule_work(&ctrl->fw_act_work); queue_work(nvme_wq, &ctrl->fw_act_work);
break; break;
default: default:
dev_warn(ctrl->device, "async event result %08x\n", result); dev_warn(ctrl->device, "async event result %08x\n", result);

View File

@ -565,6 +565,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
opts->queue_size = NVMF_DEF_QUEUE_SIZE; opts->queue_size = NVMF_DEF_QUEUE_SIZE;
opts->nr_io_queues = num_online_cpus(); opts->nr_io_queues = num_online_cpus();
opts->reconnect_delay = NVMF_DEF_RECONNECT_DELAY; opts->reconnect_delay = NVMF_DEF_RECONNECT_DELAY;
opts->kato = NVME_DEFAULT_KATO;
options = o = kstrdup(buf, GFP_KERNEL); options = o = kstrdup(buf, GFP_KERNEL);
if (!options) if (!options)
@ -655,21 +656,22 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
goto out; goto out;
} }
if (opts->discovery_nqn) {
pr_err("Discovery controllers cannot accept keep_alive_tmo != 0\n");
ret = -EINVAL;
goto out;
}
if (token < 0) { if (token < 0) {
pr_err("Invalid keep_alive_tmo %d\n", token); pr_err("Invalid keep_alive_tmo %d\n", token);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} else if (token == 0) { } else if (token == 0 && !opts->discovery_nqn) {
/* Allowed for debug */ /* Allowed for debug */
pr_warn("keep_alive_tmo 0 won't execute keep alives!!!\n"); pr_warn("keep_alive_tmo 0 won't execute keep alives!!!\n");
} }
opts->kato = token; opts->kato = token;
if (opts->discovery_nqn && opts->kato) {
pr_err("Discovery controllers cannot accept KATO != 0\n");
ret = -EINVAL;
goto out;
}
break; break;
case NVMF_OPT_CTRL_LOSS_TMO: case NVMF_OPT_CTRL_LOSS_TMO:
if (match_int(args, &token)) { if (match_int(args, &token)) {
@ -762,8 +764,6 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
uuid_copy(&opts->host->id, &hostid); uuid_copy(&opts->host->id, &hostid);
out: out:
if (!opts->discovery_nqn && !opts->kato)
opts->kato = NVME_DEFAULT_KATO;
kfree(options); kfree(options);
return ret; return ret;
} }

View File

@ -1376,7 +1376,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req)
if (atomic_read(&op->state) == FCPOP_STATE_ABORTED) if (atomic_read(&op->state) == FCPOP_STATE_ABORTED)
status = cpu_to_le16((NVME_SC_ABORT_REQ | NVME_SC_DNR) << 1); status = cpu_to_le16((NVME_SC_ABORT_REQ | NVME_SC_DNR) << 1);
else if (freq->status) else if (freq->status)
status = cpu_to_le16(NVME_SC_FC_TRANSPORT_ERROR << 1); status = cpu_to_le16(NVME_SC_INTERNAL << 1);
/* /*
* For the linux implementation, if we have an unsuccesful * For the linux implementation, if we have an unsuccesful
@ -1404,7 +1404,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req)
*/ */
if (freq->transferred_length != if (freq->transferred_length !=
be32_to_cpu(op->cmd_iu.data_len)) { be32_to_cpu(op->cmd_iu.data_len)) {
status = cpu_to_le16(NVME_SC_FC_TRANSPORT_ERROR << 1); status = cpu_to_le16(NVME_SC_INTERNAL << 1);
goto done; goto done;
} }
result.u64 = 0; result.u64 = 0;
@ -1421,7 +1421,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req)
freq->transferred_length || freq->transferred_length ||
op->rsp_iu.status_code || op->rsp_iu.status_code ||
sqe->common.command_id != cqe->command_id)) { sqe->common.command_id != cqe->command_id)) {
status = cpu_to_le16(NVME_SC_FC_TRANSPORT_ERROR << 1); status = cpu_to_le16(NVME_SC_INTERNAL << 1);
goto done; goto done;
} }
result = cqe->result; result = cqe->result;
@ -1429,7 +1429,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req)
break; break;
default: default:
status = cpu_to_le16(NVME_SC_FC_TRANSPORT_ERROR << 1); status = cpu_to_le16(NVME_SC_INTERNAL << 1);
goto done; goto done;
} }
@ -1989,16 +1989,17 @@ nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue,
* as well as those by FC-NVME spec. * as well as those by FC-NVME spec.
*/ */
WARN_ON_ONCE(sqe->common.metadata); WARN_ON_ONCE(sqe->common.metadata);
WARN_ON_ONCE(sqe->common.dptr.prp1);
WARN_ON_ONCE(sqe->common.dptr.prp2);
sqe->common.flags |= NVME_CMD_SGL_METABUF; sqe->common.flags |= NVME_CMD_SGL_METABUF;
/* /*
* format SQE DPTR field per FC-NVME rules * format SQE DPTR field per FC-NVME rules:
* type=data block descr; subtype=offset; * type=0x5 Transport SGL Data Block Descriptor
* offset is currently 0. * subtype=0xA Transport-specific value
* address=0
* length=length of the data series
*/ */
sqe->rw.dptr.sgl.type = NVME_SGL_FMT_OFFSET; sqe->rw.dptr.sgl.type = (NVME_TRANSPORT_SGL_DATA_DESC << 4) |
NVME_SGL_FMT_TRANSPORT_A;
sqe->rw.dptr.sgl.length = cpu_to_le32(data_len); sqe->rw.dptr.sgl.length = cpu_to_le32(data_len);
sqe->rw.dptr.sgl.addr = 0; sqe->rw.dptr.sgl.addr = 0;

View File

@ -24,6 +24,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/once.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/poison.h> #include <linux/poison.h>
#include <linux/t10-pi.h> #include <linux/t10-pi.h>
@ -540,6 +541,20 @@ static void nvme_dif_complete(u32 p, u32 v, struct t10_pi_tuple *pi)
} }
#endif #endif
static void nvme_print_sgl(struct scatterlist *sgl, int nents)
{
int i;
struct scatterlist *sg;
for_each_sg(sgl, sg, nents, i) {
dma_addr_t phys = sg_phys(sg);
pr_warn("sg[%d] phys_addr:%pad offset:%d length:%d "
"dma_address:%pad dma_length:%d\n",
i, &phys, sg->offset, sg->length, &sg_dma_address(sg),
sg_dma_len(sg));
}
}
static blk_status_t nvme_setup_prps(struct nvme_dev *dev, struct request *req) static blk_status_t nvme_setup_prps(struct nvme_dev *dev, struct request *req)
{ {
struct nvme_iod *iod = blk_mq_rq_to_pdu(req); struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
@ -622,19 +637,10 @@ static blk_status_t nvme_setup_prps(struct nvme_dev *dev, struct request *req)
return BLK_STS_OK; return BLK_STS_OK;
bad_sgl: bad_sgl:
if (WARN_ONCE(1, "Invalid SGL for payload:%d nents:%d\n", WARN(DO_ONCE(nvme_print_sgl, iod->sg, iod->nents),
blk_rq_payload_bytes(req), iod->nents)) { "Invalid SGL for payload:%d nents:%d\n",
for_each_sg(iod->sg, sg, iod->nents, i) { blk_rq_payload_bytes(req), iod->nents);
dma_addr_t phys = sg_phys(sg);
pr_warn("sg[%d] phys_addr:%pad offset:%d length:%d "
"dma_address:%pad dma_length:%d\n", i, &phys,
sg->offset, sg->length,
&sg_dma_address(sg),
sg_dma_len(sg));
}
}
return BLK_STS_IOERR; return BLK_STS_IOERR;
} }
static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req, static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
@ -1313,11 +1319,11 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid)
if (result < 0) if (result < 0)
goto release_cq; goto release_cq;
nvme_init_queue(nvmeq, qid);
result = queue_request_irq(nvmeq); result = queue_request_irq(nvmeq);
if (result < 0) if (result < 0)
goto release_sq; goto release_sq;
nvme_init_queue(nvmeq, qid);
return result; return result;
release_sq: release_sq:
@ -1464,6 +1470,7 @@ static int nvme_pci_configure_admin_queue(struct nvme_dev *dev)
return result; return result;
nvmeq->cq_vector = 0; nvmeq->cq_vector = 0;
nvme_init_queue(nvmeq, 0);
result = queue_request_irq(nvmeq); result = queue_request_irq(nvmeq);
if (result) { if (result) {
nvmeq->cq_vector = -1; nvmeq->cq_vector = -1;
@ -2156,7 +2163,6 @@ static void nvme_reset_work(struct work_struct *work)
if (result) if (result)
goto out; goto out;
nvme_init_queue(dev->queues[0], 0);
result = nvme_alloc_admin_tags(dev); result = nvme_alloc_admin_tags(dev);
if (result) if (result)
goto out; goto out;

Some files were not shown because too many files have changed in this diff Show More