Linux 6.1-rc7
-----BEGIN PGP SIGNATURE----- iQFSBAABCAA8FiEEq68RxlopcLEwq+PEeb4+QwBBGIYFAmOD10QeHHRvcnZhbGRz QGxpbnV4LWZvdW5kYXRpb24ub3JnAAoJEHm+PkMAQRiGGz4H+wZRlo4Bd7/zKaYZ Zy40ylCfnsMsm2dD+fPdYsr1Izxh3PQ7ithk21TL1PWSXLGcHZzJCjF2cN//z02S 0IZE59Zc5vsLUPvnTZHdHBD4p+pKe5dk3dUP2AlanoxptumXpdZtLBs74R0yv6Fa Js1+2qxOQqC/BuWjW2SoJJzvcpMEtIXPCpizdkme95aGw+TfzuRw3Nn+lgJ0TTIr 1N98IbTz+7bqj9PvrFuVgbkMyJHwquVFc/r/vq6Yv+B6Mn/N1CrKW2VPxW299F3Z kvvjosSilrzzQsG7MYQWES6q6JdAQD0VOZDRI11WhwXbKsQobZ6hjgK1wOmInasS fTsOVmA= =PkFi -----END PGP SIGNATURE----- Merge 6.1-rc7 into android-mainline Linux 6.1-rc7 Change-Id: I5273a4225425a0f7f770c0e361df67d1abdcd5f6 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
commit
e00ac7661f
2
.mailmap
2
.mailmap
@ -29,6 +29,7 @@ Alexandre Belloni <alexandre.belloni@bootlin.com> <alexandre.belloni@free-electr
|
||||
Alexei Starovoitov <ast@kernel.org> <alexei.starovoitov@gmail.com>
|
||||
Alexei Starovoitov <ast@kernel.org> <ast@fb.com>
|
||||
Alexei Starovoitov <ast@kernel.org> <ast@plumgrid.com>
|
||||
Alex Hung <alexhung@gmail.com> <alex.hung@canonical.com>
|
||||
Alex Shi <alexs@kernel.org> <alex.shi@intel.com>
|
||||
Alex Shi <alexs@kernel.org> <alex.shi@linaro.org>
|
||||
Alex Shi <alexs@kernel.org> <alex.shi@linux.alibaba.com>
|
||||
@ -382,6 +383,7 @@ Santosh Shilimkar <santosh.shilimkar@oracle.org>
|
||||
Santosh Shilimkar <ssantosh@kernel.org>
|
||||
Sarangdhar Joshi <spjoshi@codeaurora.org>
|
||||
Sascha Hauer <s.hauer@pengutronix.de>
|
||||
Satya Priya <quic_c_skakit@quicinc.com> <skakit@codeaurora.org>
|
||||
S.Çağlar Onur <caglar@pardus.org.tr>
|
||||
Sean Christopherson <seanjc@google.com> <sean.j.christopherson@intel.com>
|
||||
Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk>
|
||||
|
@ -6967,3 +6967,14 @@
|
||||
memory, and other data can't be written using
|
||||
xmon commands.
|
||||
off xmon is disabled.
|
||||
|
||||
amd_pstate= [X86]
|
||||
disable
|
||||
Do not enable amd_pstate as the default
|
||||
scaling driver for the supported processors
|
||||
passive
|
||||
Use amd_pstate as a scaling driver, driver requests a
|
||||
desired performance on this abstract scale and the power
|
||||
management firmware translates the requests into actual
|
||||
hardware states (core frequency, data fabric and memory
|
||||
clocks etc.)
|
||||
|
@ -283,23 +283,19 @@ efficiency frequency management method on AMD processors.
|
||||
Kernel Module Options for ``amd-pstate``
|
||||
=========================================
|
||||
|
||||
.. _shared_mem:
|
||||
Passive Mode
|
||||
------------
|
||||
|
||||
``shared_mem``
|
||||
Use a module param (shared_mem) to enable related processors manually with
|
||||
**amd_pstate.shared_mem=1**.
|
||||
Due to the performance issue on the processors with `Shared Memory Support
|
||||
<perf_cap_>`_, we disable it presently and will re-enable this by default
|
||||
once we address performance issue with this solution.
|
||||
``amd_pstate=passive``
|
||||
|
||||
To check whether the current processor is using `Full MSR Support <perf_cap_>`_
|
||||
or `Shared Memory Support <perf_cap_>`_ : ::
|
||||
|
||||
ray@hr-test1:~$ lscpu | grep cppc
|
||||
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd cppc arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip pku ospke vaes vpclmulqdq rdpid overflow_recov succor smca fsrm
|
||||
|
||||
If the CPU flags have ``cppc``, then this processor supports `Full MSR Support
|
||||
<perf_cap_>`_. Otherwise, it supports `Shared Memory Support <perf_cap_>`_.
|
||||
It will be enabled if the ``amd_pstate=passive`` is passed to the kernel in the command line.
|
||||
In this mode, ``amd_pstate`` driver software specifies a desired QoS target in the CPPC
|
||||
performance scale as a relative number. This can be expressed as percentage of nominal
|
||||
performance (infrastructure max). Below the nominal sustained performance level,
|
||||
desired performance expresses the average performance level of the processor subject
|
||||
to the Performance Reduction Tolerance register. Above the nominal performance level,
|
||||
processor must provide at least nominal performance requested and go higher if current
|
||||
operating conditions allow.
|
||||
|
||||
|
||||
``cpupower`` tool support for ``amd-pstate``
|
||||
|
@ -62,13 +62,6 @@ properties:
|
||||
description:
|
||||
Inform the driver that last channel will be used to sensor battery.
|
||||
|
||||
aspeed,trim-data-valid:
|
||||
type: boolean
|
||||
description: |
|
||||
The ADC reference voltage can be calibrated to obtain the trimming
|
||||
data which will be stored in otp. This property informs the driver that
|
||||
the data store in the otp is valid.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -24,7 +24,7 @@ properties:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,sc7280-bwmon
|
||||
- qcom,sc7280-cpu-bwmon
|
||||
- qcom,sdm845-bwmon
|
||||
- const: qcom,msm8998-bwmon
|
||||
- const: qcom,msm8998-bwmon # BWMON v4
|
||||
|
13
MAINTAINERS
13
MAINTAINERS
@ -10294,7 +10294,7 @@ T: git https://github.com/intel/gvt-linux.git
|
||||
F: drivers/gpu/drm/i915/gvt/
|
||||
|
||||
INTEL HID EVENT DRIVER
|
||||
M: Alex Hung <alex.hung@canonical.com>
|
||||
M: Alex Hung <alexhung@gmail.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/intel/hid.c
|
||||
@ -18018,7 +18018,7 @@ L: linux-fbdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/video/fbdev/savage/
|
||||
|
||||
S390
|
||||
S390 ARCHITECTURE
|
||||
M: Heiko Carstens <hca@linux.ibm.com>
|
||||
M: Vasily Gorbik <gor@linux.ibm.com>
|
||||
M: Alexander Gordeev <agordeev@linux.ibm.com>
|
||||
@ -18073,6 +18073,15 @@ L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/s390/net/
|
||||
|
||||
S390 MM
|
||||
M: Alexander Gordeev <agordeev@linux.ibm.com>
|
||||
M: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
|
||||
L: linux-s390@vger.kernel.org
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git
|
||||
F: arch/s390/include/asm/pgtable.h
|
||||
F: arch/s390/mm
|
||||
|
||||
S390 PCI SUBSYSTEM
|
||||
M: Niklas Schnelle <schnelle@linux.ibm.com>
|
||||
M: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
|
||||
|
2
Makefile
2
Makefile
@ -2,7 +2,7 @@
|
||||
VERSION = 6
|
||||
PATCHLEVEL = 1
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc6
|
||||
EXTRAVERSION = -rc7
|
||||
NAME = Hurr durr I'ma ninja sloth
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
@ -67,12 +67,12 @@ linux.bin.ub linux.bin.gz: linux.bin
|
||||
linux.bin: vmlinux
|
||||
linux.bin linux.bin.gz linux.bin.ub:
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||
@echo 'Kernel: $(boot)/$@ is ready' ' (#'`cat .version`')'
|
||||
@echo 'Kernel: $(boot)/$@ is ready' ' (#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')'
|
||||
|
||||
PHONY += simpleImage.$(DTB)
|
||||
simpleImage.$(DTB): vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(addprefix $(boot)/$@., ub unstrip strip)
|
||||
@echo 'Kernel: $(boot)/$@ is ready' ' (#'`cat .version`')'
|
||||
@echo 'Kernel: $(boot)/$@ is ready' ' (#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')'
|
||||
|
||||
define archhelp
|
||||
echo '* linux.bin - Create raw binary'
|
||||
|
@ -20,7 +20,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
|
||||
$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
|
||||
$(obj)/vmImage: $(obj)/vmlinux.gz
|
||||
$(obj)/vmImage: $(obj)/vmlinux.gz FORCE
|
||||
$(call if_changed,uimage)
|
||||
@$(kecho) 'Kernel: $@ is ready'
|
||||
|
||||
|
@ -46,7 +46,7 @@ struct save_area {
|
||||
u64 fprs[16];
|
||||
u32 fpc;
|
||||
u32 prefix;
|
||||
u64 todpreg;
|
||||
u32 todpreg;
|
||||
u64 timer;
|
||||
u64 todcmp;
|
||||
u64 vxrs_low[16];
|
||||
|
@ -83,7 +83,7 @@ cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \
|
||||
|
||||
$(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
|
||||
$(call if_changed,image)
|
||||
@$(kecho) 'Kernel: $@ is ready' ' (#'`cat .version`')'
|
||||
@$(kecho) 'Kernel: $@ is ready' ' (#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')'
|
||||
|
||||
OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S
|
||||
$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
|
||||
|
@ -77,7 +77,7 @@ static int hyperv_init_ghcb(void)
|
||||
static int hv_cpu_init(unsigned int cpu)
|
||||
{
|
||||
union hv_vp_assist_msr_contents msr = { 0 };
|
||||
struct hv_vp_assist_page **hvp = &hv_vp_assist_page[smp_processor_id()];
|
||||
struct hv_vp_assist_page **hvp = &hv_vp_assist_page[cpu];
|
||||
int ret;
|
||||
|
||||
ret = hv_common_cpu_init(cpu);
|
||||
@ -87,34 +87,32 @@ static int hv_cpu_init(unsigned int cpu)
|
||||
if (!hv_vp_assist_page)
|
||||
return 0;
|
||||
|
||||
if (!*hvp) {
|
||||
if (hv_root_partition) {
|
||||
/*
|
||||
* For root partition we get the hypervisor provided VP assist
|
||||
* page, instead of allocating a new page.
|
||||
*/
|
||||
rdmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
|
||||
*hvp = memremap(msr.pfn <<
|
||||
HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT,
|
||||
PAGE_SIZE, MEMREMAP_WB);
|
||||
} else {
|
||||
/*
|
||||
* The VP assist page is an "overlay" page (see Hyper-V TLFS's
|
||||
* Section 5.2.1 "GPA Overlay Pages"). Here it must be zeroed
|
||||
* out to make sure we always write the EOI MSR in
|
||||
* hv_apic_eoi_write() *after* the EOI optimization is disabled
|
||||
* in hv_cpu_die(), otherwise a CPU may not be stopped in the
|
||||
* case of CPU offlining and the VM will hang.
|
||||
*/
|
||||
if (hv_root_partition) {
|
||||
/*
|
||||
* For root partition we get the hypervisor provided VP assist
|
||||
* page, instead of allocating a new page.
|
||||
*/
|
||||
rdmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
|
||||
*hvp = memremap(msr.pfn << HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT,
|
||||
PAGE_SIZE, MEMREMAP_WB);
|
||||
} else {
|
||||
/*
|
||||
* The VP assist page is an "overlay" page (see Hyper-V TLFS's
|
||||
* Section 5.2.1 "GPA Overlay Pages"). Here it must be zeroed
|
||||
* out to make sure we always write the EOI MSR in
|
||||
* hv_apic_eoi_write() *after* the EOI optimization is disabled
|
||||
* in hv_cpu_die(), otherwise a CPU may not be stopped in the
|
||||
* case of CPU offlining and the VM will hang.
|
||||
*/
|
||||
if (!*hvp)
|
||||
*hvp = __vmalloc(PAGE_SIZE, GFP_KERNEL | __GFP_ZERO);
|
||||
if (*hvp)
|
||||
msr.pfn = vmalloc_to_pfn(*hvp);
|
||||
}
|
||||
WARN_ON(!(*hvp));
|
||||
if (*hvp) {
|
||||
msr.enable = 1;
|
||||
wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
|
||||
}
|
||||
if (*hvp)
|
||||
msr.pfn = vmalloc_to_pfn(*hvp);
|
||||
|
||||
}
|
||||
if (!WARN_ON(!(*hvp))) {
|
||||
msr.enable = 1;
|
||||
wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
|
||||
}
|
||||
|
||||
return hyperv_init_ghcb();
|
||||
|
@ -305,6 +305,9 @@
|
||||
#define X86_FEATURE_USE_IBPB_FW (11*32+16) /* "" Use IBPB during runtime firmware calls */
|
||||
#define X86_FEATURE_RSB_VMEXIT_LITE (11*32+17) /* "" Fill RSB on VM exit when EIBRS is enabled */
|
||||
|
||||
|
||||
#define X86_FEATURE_MSR_TSX_CTRL (11*32+20) /* "" MSR IA32_TSX_CTRL (Intel) implemented */
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
|
||||
#define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */
|
||||
#define X86_FEATURE_AVX512_BF16 (12*32+ 5) /* AVX512 BFLOAT16 instructions */
|
||||
|
@ -58,24 +58,6 @@ static void tsx_enable(void)
|
||||
wrmsrl(MSR_IA32_TSX_CTRL, tsx);
|
||||
}
|
||||
|
||||
static bool tsx_ctrl_is_supported(void)
|
||||
{
|
||||
u64 ia32_cap = x86_read_arch_cap_msr();
|
||||
|
||||
/*
|
||||
* TSX is controlled via MSR_IA32_TSX_CTRL. However, support for this
|
||||
* MSR is enumerated by ARCH_CAP_TSX_MSR bit in MSR_IA32_ARCH_CAPABILITIES.
|
||||
*
|
||||
* TSX control (aka MSR_IA32_TSX_CTRL) is only available after a
|
||||
* microcode update on CPUs that have their MSR_IA32_ARCH_CAPABILITIES
|
||||
* bit MDS_NO=1. CPUs with MDS_NO=0 are not planned to get
|
||||
* MSR_IA32_TSX_CTRL support even after a microcode update. Thus,
|
||||
* tsx= cmdline requests will do nothing on CPUs without
|
||||
* MSR_IA32_TSX_CTRL support.
|
||||
*/
|
||||
return !!(ia32_cap & ARCH_CAP_TSX_CTRL_MSR);
|
||||
}
|
||||
|
||||
static enum tsx_ctrl_states x86_get_tsx_auto_mode(void)
|
||||
{
|
||||
if (boot_cpu_has_bug(X86_BUG_TAA))
|
||||
@ -135,7 +117,7 @@ static void tsx_clear_cpuid(void)
|
||||
rdmsrl(MSR_TSX_FORCE_ABORT, msr);
|
||||
msr |= MSR_TFA_TSX_CPUID_CLEAR;
|
||||
wrmsrl(MSR_TSX_FORCE_ABORT, msr);
|
||||
} else if (tsx_ctrl_is_supported()) {
|
||||
} else if (cpu_feature_enabled(X86_FEATURE_MSR_TSX_CTRL)) {
|
||||
rdmsrl(MSR_IA32_TSX_CTRL, msr);
|
||||
msr |= TSX_CTRL_CPUID_CLEAR;
|
||||
wrmsrl(MSR_IA32_TSX_CTRL, msr);
|
||||
@ -158,7 +140,8 @@ static void tsx_dev_mode_disable(void)
|
||||
u64 mcu_opt_ctrl;
|
||||
|
||||
/* Check if RTM_ALLOW exists */
|
||||
if (!boot_cpu_has_bug(X86_BUG_TAA) || !tsx_ctrl_is_supported() ||
|
||||
if (!boot_cpu_has_bug(X86_BUG_TAA) ||
|
||||
!cpu_feature_enabled(X86_FEATURE_MSR_TSX_CTRL) ||
|
||||
!cpu_feature_enabled(X86_FEATURE_SRBDS_CTRL))
|
||||
return;
|
||||
|
||||
@ -191,7 +174,20 @@ void __init tsx_init(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tsx_ctrl_is_supported()) {
|
||||
/*
|
||||
* TSX is controlled via MSR_IA32_TSX_CTRL. However, support for this
|
||||
* MSR is enumerated by ARCH_CAP_TSX_MSR bit in MSR_IA32_ARCH_CAPABILITIES.
|
||||
*
|
||||
* TSX control (aka MSR_IA32_TSX_CTRL) is only available after a
|
||||
* microcode update on CPUs that have their MSR_IA32_ARCH_CAPABILITIES
|
||||
* bit MDS_NO=1. CPUs with MDS_NO=0 are not planned to get
|
||||
* MSR_IA32_TSX_CTRL support even after a microcode update. Thus,
|
||||
* tsx= cmdline requests will do nothing on CPUs without
|
||||
* MSR_IA32_TSX_CTRL support.
|
||||
*/
|
||||
if (x86_read_arch_cap_msr() & ARCH_CAP_TSX_CTRL_MSR) {
|
||||
setup_force_cpu_cap(X86_FEATURE_MSR_TSX_CTRL);
|
||||
} else {
|
||||
tsx_ctrl_state = TSX_CTRL_NOT_SUPPORTED;
|
||||
return;
|
||||
}
|
||||
|
@ -2443,6 +2443,7 @@ static bool __kvm_mmu_prepare_zap_page(struct kvm *kvm,
|
||||
{
|
||||
bool list_unstable, zapped_root = false;
|
||||
|
||||
lockdep_assert_held_write(&kvm->mmu_lock);
|
||||
trace_kvm_mmu_prepare_zap_page(sp);
|
||||
++kvm->stat.mmu_shadow_zapped;
|
||||
*nr_zapped = mmu_zap_unsync_children(kvm, sp, invalid_list);
|
||||
@ -4262,14 +4263,14 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
|
||||
if (is_page_fault_stale(vcpu, fault, mmu_seq))
|
||||
goto out_unlock;
|
||||
|
||||
r = make_mmu_pages_available(vcpu);
|
||||
if (r)
|
||||
goto out_unlock;
|
||||
|
||||
if (is_tdp_mmu_fault)
|
||||
if (is_tdp_mmu_fault) {
|
||||
r = kvm_tdp_mmu_map(vcpu, fault);
|
||||
else
|
||||
} else {
|
||||
r = make_mmu_pages_available(vcpu);
|
||||
if (r)
|
||||
goto out_unlock;
|
||||
r = __direct_map(vcpu, fault);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
if (is_tdp_mmu_fault)
|
||||
|
@ -1091,6 +1091,12 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
|
||||
|
||||
static void nested_svm_triple_fault(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
if (!vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_SHUTDOWN))
|
||||
return;
|
||||
|
||||
kvm_clear_request(KVM_REQ_TRIPLE_FAULT, vcpu);
|
||||
nested_svm_simple_vmexit(to_svm(vcpu), SVM_EXIT_SHUTDOWN);
|
||||
}
|
||||
|
||||
@ -1125,6 +1131,9 @@ void svm_free_nested(struct vcpu_svm *svm)
|
||||
if (!svm->nested.initialized)
|
||||
return;
|
||||
|
||||
if (WARN_ON_ONCE(svm->vmcb != svm->vmcb01.ptr))
|
||||
svm_switch_vmcb(svm, &svm->vmcb01);
|
||||
|
||||
svm_vcpu_free_msrpm(svm->nested.msrpm);
|
||||
svm->nested.msrpm = NULL;
|
||||
|
||||
@ -1143,9 +1152,6 @@ void svm_free_nested(struct vcpu_svm *svm)
|
||||
svm->nested.initialized = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Forcibly leave nested mode in order to be able to reset the VCPU later on.
|
||||
*/
|
||||
void svm_leave_nested(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
@ -346,12 +346,6 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_external_interrupt(u32 info)
|
||||
{
|
||||
info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
|
||||
return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR);
|
||||
}
|
||||
|
||||
static u32 svm_get_interrupt_shadow(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
@ -1438,6 +1432,7 @@ static void svm_vcpu_free(struct kvm_vcpu *vcpu)
|
||||
*/
|
||||
svm_clear_current_vmcb(svm->vmcb);
|
||||
|
||||
svm_leave_nested(vcpu);
|
||||
svm_free_nested(svm);
|
||||
|
||||
sev_free_vcpu(vcpu);
|
||||
@ -3425,15 +3420,6 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_external_interrupt(svm->vmcb->control.exit_int_info) &&
|
||||
exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR &&
|
||||
exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH &&
|
||||
exit_code != SVM_EXIT_INTR && exit_code != SVM_EXIT_NMI)
|
||||
printk(KERN_ERR "%s: unexpected exit_int_info 0x%x "
|
||||
"exit_code 0x%x\n",
|
||||
__func__, svm->vmcb->control.exit_int_info,
|
||||
exit_code);
|
||||
|
||||
if (exit_fastpath != EXIT_FASTPATH_NONE)
|
||||
return 1;
|
||||
|
||||
|
@ -4854,6 +4854,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
|
||||
|
||||
static void nested_vmx_triple_fault(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvm_clear_request(KVM_REQ_TRIPLE_FAULT, vcpu);
|
||||
nested_vmx_vmexit(vcpu, EXIT_REASON_TRIPLE_FAULT, 0, 0);
|
||||
}
|
||||
|
||||
@ -6440,9 +6441,6 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
|
||||
return kvm_state.size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Forcibly leave nested mode in order to be able to reset the VCPU later on.
|
||||
*/
|
||||
void vmx_leave_nested(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (is_guest_mode(vcpu)) {
|
||||
|
@ -628,6 +628,12 @@ static void kvm_queue_exception_vmexit(struct kvm_vcpu *vcpu, unsigned int vecto
|
||||
ex->payload = payload;
|
||||
}
|
||||
|
||||
/* Forcibly leave the nested mode in cases like a vCPU reset */
|
||||
static void kvm_leave_nested(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvm_x86_ops.nested_ops->leave_nested(vcpu);
|
||||
}
|
||||
|
||||
static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
|
||||
unsigned nr, bool has_error, u32 error_code,
|
||||
bool has_payload, unsigned long payload, bool reinject)
|
||||
@ -5195,7 +5201,7 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
|
||||
|
||||
if (events->flags & KVM_VCPUEVENT_VALID_SMM) {
|
||||
if (!!(vcpu->arch.hflags & HF_SMM_MASK) != events->smi.smm) {
|
||||
kvm_x86_ops.nested_ops->leave_nested(vcpu);
|
||||
kvm_leave_nested(vcpu);
|
||||
kvm_smm_changed(vcpu, events->smi.smm);
|
||||
}
|
||||
|
||||
@ -9805,7 +9811,7 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
|
||||
|
||||
int kvm_check_nested_events(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
|
||||
if (kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
|
||||
kvm_x86_ops.nested_ops->triple_fault(vcpu);
|
||||
return 1;
|
||||
}
|
||||
@ -10560,15 +10566,16 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
|
||||
if (is_guest_mode(vcpu)) {
|
||||
if (kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
|
||||
if (is_guest_mode(vcpu))
|
||||
kvm_x86_ops.nested_ops->triple_fault(vcpu);
|
||||
} else {
|
||||
|
||||
if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
|
||||
vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
|
||||
vcpu->mmio_needed = 0;
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
if (kvm_check_request(KVM_REQ_APF_HALT, vcpu)) {
|
||||
/* Page is swapped out. Do synthetic halt */
|
||||
@ -11997,8 +12004,18 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
|
||||
WARN_ON_ONCE(!init_event &&
|
||||
(old_cr0 || kvm_read_cr3(vcpu) || kvm_read_cr4(vcpu)));
|
||||
|
||||
/*
|
||||
* SVM doesn't unconditionally VM-Exit on INIT and SHUTDOWN, thus it's
|
||||
* possible to INIT the vCPU while L2 is active. Force the vCPU back
|
||||
* into L1 as EFER.SVME is cleared on INIT (along with all other EFER
|
||||
* bits), i.e. virtualization is disabled.
|
||||
*/
|
||||
if (is_guest_mode(vcpu))
|
||||
kvm_leave_nested(vcpu);
|
||||
|
||||
kvm_lapic_reset(vcpu, init_event);
|
||||
|
||||
WARN_ON_ONCE(is_guest_mode(vcpu) || is_smm(vcpu));
|
||||
vcpu->arch.hflags = 0;
|
||||
|
||||
vcpu->arch.smi_pending = 0;
|
||||
|
@ -954,6 +954,14 @@ static int kvm_xen_hypercall_complete_userspace(struct kvm_vcpu *vcpu)
|
||||
return kvm_xen_hypercall_set_result(vcpu, run->xen.u.hcall.result);
|
||||
}
|
||||
|
||||
static inline int max_evtchn_port(struct kvm *kvm)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_64BIT) && kvm->arch.xen.long_mode)
|
||||
return EVTCHN_2L_NR_CHANNELS;
|
||||
else
|
||||
return COMPAT_EVTCHN_2L_NR_CHANNELS;
|
||||
}
|
||||
|
||||
static bool wait_pending_event(struct kvm_vcpu *vcpu, int nr_ports,
|
||||
evtchn_port_t *ports)
|
||||
{
|
||||
@ -1042,6 +1050,10 @@ static bool kvm_xen_schedop_poll(struct kvm_vcpu *vcpu, bool longmode,
|
||||
*r = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (ports[i] >= max_evtchn_port(vcpu->kvm)) {
|
||||
*r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (sched_poll.nr_ports == 1)
|
||||
@ -1215,6 +1227,7 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
|
||||
bool longmode;
|
||||
u64 input, params[6], r = -ENOSYS;
|
||||
bool handled = false;
|
||||
u8 cpl;
|
||||
|
||||
input = (u64)kvm_register_read(vcpu, VCPU_REGS_RAX);
|
||||
|
||||
@ -1242,9 +1255,17 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
|
||||
params[5] = (u64)kvm_r9_read(vcpu);
|
||||
}
|
||||
#endif
|
||||
cpl = static_call(kvm_x86_get_cpl)(vcpu);
|
||||
trace_kvm_xen_hypercall(input, params[0], params[1], params[2],
|
||||
params[3], params[4], params[5]);
|
||||
|
||||
/*
|
||||
* Only allow hypercall acceleration for CPL0. The rare hypercalls that
|
||||
* are permitted in guest userspace can be handled by the VMM.
|
||||
*/
|
||||
if (unlikely(cpl > 0))
|
||||
goto handle_in_userspace;
|
||||
|
||||
switch (input) {
|
||||
case __HYPERVISOR_xen_version:
|
||||
if (params[0] == XENVER_version && vcpu->kvm->arch.xen.xen_version) {
|
||||
@ -1279,10 +1300,11 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
|
||||
if (handled)
|
||||
return kvm_xen_hypercall_set_result(vcpu, r);
|
||||
|
||||
handle_in_userspace:
|
||||
vcpu->run->exit_reason = KVM_EXIT_XEN;
|
||||
vcpu->run->xen.type = KVM_EXIT_XEN_HCALL;
|
||||
vcpu->run->xen.u.hcall.longmode = longmode;
|
||||
vcpu->run->xen.u.hcall.cpl = static_call(kvm_x86_get_cpl)(vcpu);
|
||||
vcpu->run->xen.u.hcall.cpl = cpl;
|
||||
vcpu->run->xen.u.hcall.input = input;
|
||||
vcpu->run->xen.u.hcall.params[0] = params[0];
|
||||
vcpu->run->xen.u.hcall.params[1] = params[1];
|
||||
@ -1297,14 +1319,6 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int max_evtchn_port(struct kvm *kvm)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_64BIT) && kvm->arch.xen.long_mode)
|
||||
return EVTCHN_2L_NR_CHANNELS;
|
||||
else
|
||||
return COMPAT_EVTCHN_2L_NR_CHANNELS;
|
||||
}
|
||||
|
||||
static void kvm_xen_check_poller(struct kvm_vcpu *vcpu, int port)
|
||||
{
|
||||
int poll_evtchn = vcpu->arch.xen.poll_evtchn;
|
||||
|
@ -217,9 +217,15 @@ __ioremap_caller(resource_size_t phys_addr, unsigned long size,
|
||||
* Mappings have to be page-aligned
|
||||
*/
|
||||
offset = phys_addr & ~PAGE_MASK;
|
||||
phys_addr &= PHYSICAL_PAGE_MASK;
|
||||
phys_addr &= PAGE_MASK;
|
||||
size = PAGE_ALIGN(last_addr+1) - phys_addr;
|
||||
|
||||
/*
|
||||
* Mask out any bits not part of the actual physical
|
||||
* address, like memory encryption bits.
|
||||
*/
|
||||
phys_addr &= PHYSICAL_PAGE_MASK;
|
||||
|
||||
retval = memtype_reserve(phys_addr, (u64)phys_addr + size,
|
||||
pcm, &new_pcm);
|
||||
if (retval) {
|
||||
|
@ -513,16 +513,23 @@ static int pm_cpu_check(const struct x86_cpu_id *c)
|
||||
|
||||
static void pm_save_spec_msr(void)
|
||||
{
|
||||
u32 spec_msr_id[] = {
|
||||
MSR_IA32_SPEC_CTRL,
|
||||
MSR_IA32_TSX_CTRL,
|
||||
MSR_TSX_FORCE_ABORT,
|
||||
MSR_IA32_MCU_OPT_CTRL,
|
||||
MSR_AMD64_LS_CFG,
|
||||
MSR_AMD64_DE_CFG,
|
||||
struct msr_enumeration {
|
||||
u32 msr_no;
|
||||
u32 feature;
|
||||
} msr_enum[] = {
|
||||
{ MSR_IA32_SPEC_CTRL, X86_FEATURE_MSR_SPEC_CTRL },
|
||||
{ MSR_IA32_TSX_CTRL, X86_FEATURE_MSR_TSX_CTRL },
|
||||
{ MSR_TSX_FORCE_ABORT, X86_FEATURE_TSX_FORCE_ABORT },
|
||||
{ MSR_IA32_MCU_OPT_CTRL, X86_FEATURE_SRBDS_CTRL },
|
||||
{ MSR_AMD64_LS_CFG, X86_FEATURE_LS_CFG_SSBD },
|
||||
{ MSR_AMD64_DE_CFG, X86_FEATURE_LFENCE_RDTSC },
|
||||
};
|
||||
int i;
|
||||
|
||||
msr_build_context(spec_msr_id, ARRAY_SIZE(spec_msr_id));
|
||||
for (i = 0; i < ARRAY_SIZE(msr_enum); i++) {
|
||||
if (boot_cpu_has(msr_enum[i].feature))
|
||||
msr_build_context(&msr_enum[i].msr_no, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int pm_check_save_msr(void)
|
||||
|
@ -4045,9 +4045,14 @@ EXPORT_SYMBOL(__blk_mq_alloc_disk);
|
||||
struct gendisk *blk_mq_alloc_disk_for_queue(struct request_queue *q,
|
||||
struct lock_class_key *lkclass)
|
||||
{
|
||||
struct gendisk *disk;
|
||||
|
||||
if (!blk_get_queue(q))
|
||||
return NULL;
|
||||
return __alloc_disk_node(q, NUMA_NO_NODE, lkclass);
|
||||
disk = __alloc_disk_node(q, NUMA_NO_NODE, lkclass);
|
||||
if (!disk)
|
||||
blk_put_queue(q);
|
||||
return disk;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_mq_alloc_disk_for_queue);
|
||||
|
||||
|
@ -57,10 +57,8 @@
|
||||
#define UBLK_PARAM_TYPE_ALL (UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DISCARD)
|
||||
|
||||
struct ublk_rq_data {
|
||||
union {
|
||||
struct callback_head work;
|
||||
struct llist_node node;
|
||||
};
|
||||
struct llist_node node;
|
||||
struct callback_head work;
|
||||
};
|
||||
|
||||
struct ublk_uring_cmd_pdu {
|
||||
@ -766,15 +764,31 @@ static inline void __ublk_rq_task_work(struct request *req)
|
||||
ubq_complete_io_cmd(io, UBLK_IO_RES_OK);
|
||||
}
|
||||
|
||||
static inline void ublk_forward_io_cmds(struct ublk_queue *ubq)
|
||||
{
|
||||
struct llist_node *io_cmds = llist_del_all(&ubq->io_cmds);
|
||||
struct ublk_rq_data *data, *tmp;
|
||||
|
||||
io_cmds = llist_reverse_order(io_cmds);
|
||||
llist_for_each_entry_safe(data, tmp, io_cmds, node)
|
||||
__ublk_rq_task_work(blk_mq_rq_from_pdu(data));
|
||||
}
|
||||
|
||||
static inline void ublk_abort_io_cmds(struct ublk_queue *ubq)
|
||||
{
|
||||
struct llist_node *io_cmds = llist_del_all(&ubq->io_cmds);
|
||||
struct ublk_rq_data *data, *tmp;
|
||||
|
||||
llist_for_each_entry_safe(data, tmp, io_cmds, node)
|
||||
__ublk_abort_rq(ubq, blk_mq_rq_from_pdu(data));
|
||||
}
|
||||
|
||||
static void ublk_rq_task_work_cb(struct io_uring_cmd *cmd)
|
||||
{
|
||||
struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
|
||||
struct ublk_queue *ubq = pdu->ubq;
|
||||
struct llist_node *io_cmds = llist_del_all(&ubq->io_cmds);
|
||||
struct ublk_rq_data *data;
|
||||
|
||||
llist_for_each_entry(data, io_cmds, node)
|
||||
__ublk_rq_task_work(blk_mq_rq_from_pdu(data));
|
||||
ublk_forward_io_cmds(ubq);
|
||||
}
|
||||
|
||||
static void ublk_rq_task_work_fn(struct callback_head *work)
|
||||
@ -782,14 +796,20 @@ static void ublk_rq_task_work_fn(struct callback_head *work)
|
||||
struct ublk_rq_data *data = container_of(work,
|
||||
struct ublk_rq_data, work);
|
||||
struct request *req = blk_mq_rq_from_pdu(data);
|
||||
struct ublk_queue *ubq = req->mq_hctx->driver_data;
|
||||
|
||||
__ublk_rq_task_work(req);
|
||||
ublk_forward_io_cmds(ubq);
|
||||
}
|
||||
|
||||
static void ublk_submit_cmd(struct ublk_queue *ubq, const struct request *rq)
|
||||
static void ublk_queue_cmd(struct ublk_queue *ubq, struct request *rq)
|
||||
{
|
||||
struct ublk_io *io = &ubq->ios[rq->tag];
|
||||
struct ublk_rq_data *data = blk_mq_rq_to_pdu(rq);
|
||||
struct ublk_io *io;
|
||||
|
||||
if (!llist_add(&data->node, &ubq->io_cmds))
|
||||
return;
|
||||
|
||||
io = &ubq->ios[rq->tag];
|
||||
/*
|
||||
* If the check pass, we know that this is a re-issued request aborted
|
||||
* previously in monitor_work because the ubq_daemon(cmd's task) is
|
||||
@ -803,11 +823,11 @@ static void ublk_submit_cmd(struct ublk_queue *ubq, const struct request *rq)
|
||||
* guarantees that here is a re-issued request aborted previously.
|
||||
*/
|
||||
if (unlikely(io->flags & UBLK_IO_FLAG_ABORTED)) {
|
||||
struct llist_node *io_cmds = llist_del_all(&ubq->io_cmds);
|
||||
struct ublk_rq_data *data;
|
||||
|
||||
llist_for_each_entry(data, io_cmds, node)
|
||||
__ublk_abort_rq(ubq, blk_mq_rq_from_pdu(data));
|
||||
ublk_abort_io_cmds(ubq);
|
||||
} else if (ublk_can_use_task_work(ubq)) {
|
||||
if (task_work_add(ubq->ubq_daemon, &data->work,
|
||||
TWA_SIGNAL_NO_IPI))
|
||||
ublk_abort_io_cmds(ubq);
|
||||
} else {
|
||||
struct io_uring_cmd *cmd = io->cmd;
|
||||
struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
|
||||
@ -817,23 +837,6 @@ static void ublk_submit_cmd(struct ublk_queue *ubq, const struct request *rq)
|
||||
}
|
||||
}
|
||||
|
||||
static void ublk_queue_cmd(struct ublk_queue *ubq, struct request *rq,
|
||||
bool last)
|
||||
{
|
||||
struct ublk_rq_data *data = blk_mq_rq_to_pdu(rq);
|
||||
|
||||
if (ublk_can_use_task_work(ubq)) {
|
||||
enum task_work_notify_mode notify_mode = last ?
|
||||
TWA_SIGNAL_NO_IPI : TWA_NONE;
|
||||
|
||||
if (task_work_add(ubq->ubq_daemon, &data->work, notify_mode))
|
||||
__ublk_abort_rq(ubq, rq);
|
||||
} else {
|
||||
if (llist_add(&data->node, &ubq->io_cmds))
|
||||
ublk_submit_cmd(ubq, rq);
|
||||
}
|
||||
}
|
||||
|
||||
static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx,
|
||||
const struct blk_mq_queue_data *bd)
|
||||
{
|
||||
@ -865,19 +868,11 @@ static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx,
|
||||
return BLK_STS_OK;
|
||||
}
|
||||
|
||||
ublk_queue_cmd(ubq, rq, bd->last);
|
||||
ublk_queue_cmd(ubq, rq);
|
||||
|
||||
return BLK_STS_OK;
|
||||
}
|
||||
|
||||
static void ublk_commit_rqs(struct blk_mq_hw_ctx *hctx)
|
||||
{
|
||||
struct ublk_queue *ubq = hctx->driver_data;
|
||||
|
||||
if (ublk_can_use_task_work(ubq))
|
||||
__set_notify_signal(ubq->ubq_daemon);
|
||||
}
|
||||
|
||||
static int ublk_init_hctx(struct blk_mq_hw_ctx *hctx, void *driver_data,
|
||||
unsigned int hctx_idx)
|
||||
{
|
||||
@ -899,7 +894,6 @@ static int ublk_init_rq(struct blk_mq_tag_set *set, struct request *req,
|
||||
|
||||
static const struct blk_mq_ops ublk_mq_ops = {
|
||||
.queue_rq = ublk_queue_rq,
|
||||
.commit_rqs = ublk_commit_rqs,
|
||||
.init_hctx = ublk_init_hctx,
|
||||
.init_request = ublk_init_rq,
|
||||
};
|
||||
@ -1197,7 +1191,7 @@ static void ublk_handle_need_get_data(struct ublk_device *ub, int q_id,
|
||||
struct ublk_queue *ubq = ublk_get_queue(ub, q_id);
|
||||
struct request *req = blk_mq_tag_to_rq(ub->tag_set.tags[q_id], tag);
|
||||
|
||||
ublk_queue_cmd(ubq, req, true);
|
||||
ublk_queue_cmd(ubq, req);
|
||||
}
|
||||
|
||||
static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
|
||||
|
@ -806,6 +806,9 @@ static u64 __arch_timer_check_delta(void)
|
||||
/*
|
||||
* XGene-1 implements CVAL in terms of TVAL, meaning
|
||||
* that the maximum timer range is 32bit. Shame on them.
|
||||
*
|
||||
* Note that TVAL is signed, thus has only 31 of its
|
||||
* 32 bits to express magnitude.
|
||||
*/
|
||||
MIDR_ALL_VERSIONS(MIDR_CPU_MODEL(ARM_CPU_IMP_APM,
|
||||
APM_CPU_PART_POTENZA)),
|
||||
@ -813,8 +816,8 @@ static u64 __arch_timer_check_delta(void)
|
||||
};
|
||||
|
||||
if (is_midr_in_range_list(read_cpuid_id(), broken_cval_midrs)) {
|
||||
pr_warn_once("Broken CNTx_CVAL_EL1, limiting width to 32bits");
|
||||
return CLOCKSOURCE_MASK(32);
|
||||
pr_warn_once("Broken CNTx_CVAL_EL1, using 31 bit TVAL instead.\n");
|
||||
return CLOCKSOURCE_MASK(31);
|
||||
}
|
||||
#endif
|
||||
return CLOCKSOURCE_MASK(arch_counter_get_width());
|
||||
|
@ -35,7 +35,7 @@ config X86_PCC_CPUFREQ
|
||||
If in doubt, say N.
|
||||
|
||||
config X86_AMD_PSTATE
|
||||
tristate "AMD Processor P-State driver"
|
||||
bool "AMD Processor P-State driver"
|
||||
depends on X86 && ACPI
|
||||
select ACPI_PROCESSOR
|
||||
select ACPI_CPPC_LIB if X86_64
|
||||
|
@ -59,12 +59,8 @@
|
||||
* we disable it by default to go acpi-cpufreq on these processors and add a
|
||||
* module parameter to be able to enable it manually for debugging.
|
||||
*/
|
||||
static bool shared_mem = false;
|
||||
module_param(shared_mem, bool, 0444);
|
||||
MODULE_PARM_DESC(shared_mem,
|
||||
"enable amd-pstate on processors with shared memory solution (false = disabled (default), true = enabled)");
|
||||
|
||||
static struct cpufreq_driver amd_pstate_driver;
|
||||
static int cppc_load __initdata;
|
||||
|
||||
static inline int pstate_enable(bool enable)
|
||||
{
|
||||
@ -424,12 +420,22 @@ static void amd_pstate_boost_init(struct amd_cpudata *cpudata)
|
||||
amd_pstate_driver.boost_enabled = true;
|
||||
}
|
||||
|
||||
static void amd_perf_ctl_reset(unsigned int cpu)
|
||||
{
|
||||
wrmsrl_on_cpu(cpu, MSR_AMD_PERF_CTL, 0);
|
||||
}
|
||||
|
||||
static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret;
|
||||
struct device *dev;
|
||||
struct amd_cpudata *cpudata;
|
||||
|
||||
/*
|
||||
* Resetting PERF_CTL_MSR will put the CPU in P0 frequency,
|
||||
* which is ideal for initialization process.
|
||||
*/
|
||||
amd_perf_ctl_reset(policy->cpu);
|
||||
dev = get_cpu_device(policy->cpu);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
@ -616,6 +622,15 @@ static int __init amd_pstate_init(void)
|
||||
|
||||
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
|
||||
return -ENODEV;
|
||||
/*
|
||||
* by default the pstate driver is disabled to load
|
||||
* enable the amd_pstate passive mode driver explicitly
|
||||
* with amd_pstate=passive in kernel command line
|
||||
*/
|
||||
if (!cppc_load) {
|
||||
pr_debug("driver load is disabled, boot with amd_pstate=passive to enable this\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!acpi_cpc_valid()) {
|
||||
pr_warn_once("the _CPC object is not present in SBIOS or ACPI disabled\n");
|
||||
@ -630,13 +645,11 @@ static int __init amd_pstate_init(void)
|
||||
if (boot_cpu_has(X86_FEATURE_CPPC)) {
|
||||
pr_debug("AMD CPPC MSR based functionality is supported\n");
|
||||
amd_pstate_driver.adjust_perf = amd_pstate_adjust_perf;
|
||||
} else if (shared_mem) {
|
||||
} else {
|
||||
pr_debug("AMD CPPC shared memory based functionality is supported\n");
|
||||
static_call_update(amd_pstate_enable, cppc_enable);
|
||||
static_call_update(amd_pstate_init_perf, cppc_init_perf);
|
||||
static_call_update(amd_pstate_update_perf, cppc_update_perf);
|
||||
} else {
|
||||
pr_info("This processor supports shared memory solution, you can enable it with amd_pstate.shared_mem=1\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* enable amd pstate feature */
|
||||
@ -653,16 +666,22 @@ static int __init amd_pstate_init(void)
|
||||
|
||||
return ret;
|
||||
}
|
||||
device_initcall(amd_pstate_init);
|
||||
|
||||
static void __exit amd_pstate_exit(void)
|
||||
static int __init amd_pstate_param(char *str)
|
||||
{
|
||||
cpufreq_unregister_driver(&amd_pstate_driver);
|
||||
if (!str)
|
||||
return -EINVAL;
|
||||
|
||||
amd_pstate_enable(false);
|
||||
if (!strcmp(str, "disable")) {
|
||||
cppc_load = 0;
|
||||
pr_info("driver is explicitly disabled\n");
|
||||
} else if (!strcmp(str, "passive"))
|
||||
cppc_load = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(amd_pstate_init);
|
||||
module_exit(amd_pstate_exit);
|
||||
early_param("amd_pstate", amd_pstate_param);
|
||||
|
||||
MODULE_AUTHOR("Huang Rui <ray.huang@amd.com>");
|
||||
MODULE_DESCRIPTION("AMD Processor P-state Frequency Driver");
|
||||
|
@ -246,7 +246,9 @@ config FPGA_MGR_VERSAL_FPGA
|
||||
|
||||
config FPGA_M10_BMC_SEC_UPDATE
|
||||
tristate "Intel MAX10 BMC Secure Update driver"
|
||||
depends on MFD_INTEL_M10_BMC && FW_UPLOAD
|
||||
depends on MFD_INTEL_M10_BMC
|
||||
select FW_LOADER
|
||||
select FW_UPLOAD
|
||||
help
|
||||
Secure update support for the Intel MAX10 board management
|
||||
controller.
|
||||
|
@ -533,13 +533,17 @@ static void vmbus_add_channel_work(struct work_struct *work)
|
||||
* Add the new device to the bus. This will kick off device-driver
|
||||
* binding which eventually invokes the device driver's AddDevice()
|
||||
* method.
|
||||
*
|
||||
* If vmbus_device_register() fails, the 'device_obj' is freed in
|
||||
* vmbus_device_release() as called by device_unregister() in the
|
||||
* error path of vmbus_device_register(). In the outside error
|
||||
* path, there's no need to free it.
|
||||
*/
|
||||
ret = vmbus_device_register(newchannel->device_obj);
|
||||
|
||||
if (ret != 0) {
|
||||
pr_err("unable to add child device object (relid %d)\n",
|
||||
newchannel->offermsg.child_relid);
|
||||
kfree(newchannel->device_obj);
|
||||
goto err_deq_chan;
|
||||
}
|
||||
|
||||
|
@ -2082,6 +2082,7 @@ int vmbus_device_register(struct hv_device *child_device_obj)
|
||||
ret = device_register(&child_device_obj->device);
|
||||
if (ret) {
|
||||
pr_err("Unable to register child device\n");
|
||||
put_device(&child_device_obj->device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -805,8 +805,10 @@ static int bma400_get_steps_reg(struct bma400_data *data, int *val)
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, BMA400_STEP_CNT0_REG,
|
||||
steps_raw, BMA400_STEP_RAW_LEN);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
kfree(steps_raw);
|
||||
return ret;
|
||||
}
|
||||
*val = get_unaligned_le24(steps_raw);
|
||||
kfree(steps_raw);
|
||||
return IIO_VAL_INT;
|
||||
|
@ -202,6 +202,8 @@ static int aspeed_adc_set_trim_data(struct iio_dev *indio_dev)
|
||||
((scu_otp) &
|
||||
(data->model_data->trim_locate->field)) >>
|
||||
__ffs(data->model_data->trim_locate->field);
|
||||
if (!trimming_val)
|
||||
trimming_val = 0x8;
|
||||
}
|
||||
dev_dbg(data->dev,
|
||||
"trimming val = %d, offset = %08x, fields = %08x\n",
|
||||
@ -563,12 +565,9 @@ static int aspeed_adc_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (of_find_property(data->dev->of_node, "aspeed,trim-data-valid",
|
||||
NULL)) {
|
||||
ret = aspeed_adc_set_trim_data(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = aspeed_adc_set_trim_data(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (of_find_property(data->dev->of_node, "aspeed,battery-sensing",
|
||||
NULL)) {
|
||||
|
@ -245,14 +245,14 @@ static int afe4403_read_raw(struct iio_dev *indio_dev,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct afe4403_data *afe = iio_priv(indio_dev);
|
||||
unsigned int reg = afe4403_channel_values[chan->address];
|
||||
unsigned int field = afe4403_channel_leds[chan->address];
|
||||
unsigned int reg, field;
|
||||
int ret;
|
||||
|
||||
switch (chan->type) {
|
||||
case IIO_INTENSITY:
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
reg = afe4403_channel_values[chan->address];
|
||||
ret = afe4403_read(afe, reg, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -262,6 +262,7 @@ static int afe4403_read_raw(struct iio_dev *indio_dev,
|
||||
case IIO_CURRENT:
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
field = afe4403_channel_leds[chan->address];
|
||||
ret = regmap_field_read(afe->fields[field], val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -250,20 +250,20 @@ static int afe4404_read_raw(struct iio_dev *indio_dev,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct afe4404_data *afe = iio_priv(indio_dev);
|
||||
unsigned int value_reg = afe4404_channel_values[chan->address];
|
||||
unsigned int led_field = afe4404_channel_leds[chan->address];
|
||||
unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
|
||||
unsigned int value_reg, led_field, offdac_field;
|
||||
int ret;
|
||||
|
||||
switch (chan->type) {
|
||||
case IIO_INTENSITY:
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
value_reg = afe4404_channel_values[chan->address];
|
||||
ret = regmap_read(afe->regmap, value_reg, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
offdac_field = afe4404_channel_offdacs[chan->address];
|
||||
ret = regmap_field_read(afe->fields[offdac_field], val);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -273,6 +273,7 @@ static int afe4404_read_raw(struct iio_dev *indio_dev,
|
||||
case IIO_CURRENT:
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
led_field = afe4404_channel_leds[chan->address];
|
||||
ret = regmap_field_read(afe->fields[led_field], val);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -295,19 +296,20 @@ static int afe4404_write_raw(struct iio_dev *indio_dev,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct afe4404_data *afe = iio_priv(indio_dev);
|
||||
unsigned int led_field = afe4404_channel_leds[chan->address];
|
||||
unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
|
||||
unsigned int led_field, offdac_field;
|
||||
|
||||
switch (chan->type) {
|
||||
case IIO_INTENSITY:
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
offdac_field = afe4404_channel_offdacs[chan->address];
|
||||
return regmap_field_write(afe->fields[offdac_field], val);
|
||||
}
|
||||
break;
|
||||
case IIO_CURRENT:
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
led_field = afe4404_channel_leds[chan->address];
|
||||
return regmap_field_write(afe->fields[led_field], val);
|
||||
}
|
||||
break;
|
||||
|
@ -58,8 +58,12 @@ int iio_register_sw_trigger_type(struct iio_sw_trigger_type *t)
|
||||
|
||||
t->group = configfs_register_default_group(iio_triggers_group, t->name,
|
||||
&iio_trigger_type_group_type);
|
||||
if (IS_ERR(t->group))
|
||||
if (IS_ERR(t->group)) {
|
||||
mutex_lock(&iio_trigger_types_lock);
|
||||
list_del(&t->list);
|
||||
mutex_unlock(&iio_trigger_types_lock);
|
||||
ret = PTR_ERR(t->group);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -293,6 +293,8 @@ config RPR0521
|
||||
tristate "ROHM RPR0521 ALS and proximity sensor driver"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say Y here if you want to build support for ROHM's RPR0521
|
||||
ambient light and proximity sensor device.
|
||||
|
@ -54,9 +54,6 @@
|
||||
#define APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT 2
|
||||
|
||||
#define APDS9960_REG_CONFIG_2 0x90
|
||||
#define APDS9960_REG_CONFIG_2_GGAIN_MASK 0x60
|
||||
#define APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT 5
|
||||
|
||||
#define APDS9960_REG_ID 0x92
|
||||
|
||||
#define APDS9960_REG_STATUS 0x93
|
||||
@ -77,6 +74,9 @@
|
||||
#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT 6
|
||||
|
||||
#define APDS9960_REG_GCONF_2 0xa3
|
||||
#define APDS9960_REG_GCONF_2_GGAIN_MASK 0x60
|
||||
#define APDS9960_REG_GCONF_2_GGAIN_MASK_SHIFT 5
|
||||
|
||||
#define APDS9960_REG_GOFFSET_U 0xa4
|
||||
#define APDS9960_REG_GOFFSET_D 0xa5
|
||||
#define APDS9960_REG_GPULSE 0xa6
|
||||
@ -396,9 +396,9 @@ static int apds9960_set_pxs_gain(struct apds9960_data *data, int val)
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(data->regmap,
|
||||
APDS9960_REG_CONFIG_2,
|
||||
APDS9960_REG_CONFIG_2_GGAIN_MASK,
|
||||
idx << APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT);
|
||||
APDS9960_REG_GCONF_2,
|
||||
APDS9960_REG_GCONF_2_GGAIN_MASK,
|
||||
idx << APDS9960_REG_GCONF_2_GGAIN_MASK_SHIFT);
|
||||
if (!ret)
|
||||
data->pxs_gain = idx;
|
||||
mutex_unlock(&data->lock);
|
||||
|
@ -36,7 +36,7 @@ struct lan9662_otp {
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static bool lan9662_otp_wait_flag_clear(void __iomem *reg, u32 flag)
|
||||
static int lan9662_otp_wait_flag_clear(void __iomem *reg, u32 flag)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
|
@ -37,9 +37,9 @@ static int rmem_read(void *context, unsigned int offset,
|
||||
* but as of Dec 2020 this isn't possible on arm64.
|
||||
*/
|
||||
addr = memremap(priv->mem->base, available, MEMREMAP_WB);
|
||||
if (IS_ERR(addr)) {
|
||||
if (!addr) {
|
||||
dev_err(priv->dev, "Failed to remap memory region\n");
|
||||
return PTR_ERR(addr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
count = memory_read_from_buffer(val, bytes, &off, addr, available);
|
||||
|
@ -1613,7 +1613,7 @@ static void hv_pci_compose_compl(void *context, struct pci_response *resp,
|
||||
}
|
||||
|
||||
static u32 hv_compose_msi_req_v1(
|
||||
struct pci_create_interrupt *int_pkt, const struct cpumask *affinity,
|
||||
struct pci_create_interrupt *int_pkt,
|
||||
u32 slot, u8 vector, u16 vector_count)
|
||||
{
|
||||
int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE;
|
||||
@ -1631,6 +1631,35 @@ static u32 hv_compose_msi_req_v1(
|
||||
return sizeof(*int_pkt);
|
||||
}
|
||||
|
||||
/*
|
||||
* The vCPU selected by hv_compose_multi_msi_req_get_cpu() and
|
||||
* hv_compose_msi_req_get_cpu() is a "dummy" vCPU because the final vCPU to be
|
||||
* interrupted is specified later in hv_irq_unmask() and communicated to Hyper-V
|
||||
* via the HVCALL_RETARGET_INTERRUPT hypercall. But the choice of dummy vCPU is
|
||||
* not irrelevant because Hyper-V chooses the physical CPU to handle the
|
||||
* interrupts based on the vCPU specified in message sent to the vPCI VSP in
|
||||
* hv_compose_msi_msg(). Hyper-V's choice of pCPU is not visible to the guest,
|
||||
* but assigning too many vPCI device interrupts to the same pCPU can cause a
|
||||
* performance bottleneck. So we spread out the dummy vCPUs to influence Hyper-V
|
||||
* to spread out the pCPUs that it selects.
|
||||
*
|
||||
* For the single-MSI and MSI-X cases, it's OK for hv_compose_msi_req_get_cpu()
|
||||
* to always return the same dummy vCPU, because a second call to
|
||||
* hv_compose_msi_msg() contains the "real" vCPU, causing Hyper-V to choose a
|
||||
* new pCPU for the interrupt. But for the multi-MSI case, the second call to
|
||||
* hv_compose_msi_msg() exits without sending a message to the vPCI VSP, so the
|
||||
* original dummy vCPU is used. This dummy vCPU must be round-robin'ed so that
|
||||
* the pCPUs are spread out. All interrupts for a multi-MSI device end up using
|
||||
* the same pCPU, even though the vCPUs will be spread out by later calls
|
||||
* to hv_irq_unmask(), but that is the best we can do now.
|
||||
*
|
||||
* With Hyper-V in Nov 2022, the HVCALL_RETARGET_INTERRUPT hypercall does *not*
|
||||
* cause Hyper-V to reselect the pCPU based on the specified vCPU. Such an
|
||||
* enhancement is planned for a future version. With that enhancement, the
|
||||
* dummy vCPU selection won't matter, and interrupts for the same multi-MSI
|
||||
* device will be spread across multiple pCPUs.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create MSI w/ dummy vCPU set targeting just one vCPU, overwritten
|
||||
* by subsequent retarget in hv_irq_unmask().
|
||||
@ -1640,18 +1669,39 @@ static int hv_compose_msi_req_get_cpu(const struct cpumask *affinity)
|
||||
return cpumask_first_and(affinity, cpu_online_mask);
|
||||
}
|
||||
|
||||
static u32 hv_compose_msi_req_v2(
|
||||
struct pci_create_interrupt2 *int_pkt, const struct cpumask *affinity,
|
||||
u32 slot, u8 vector, u16 vector_count)
|
||||
/*
|
||||
* Make sure the dummy vCPU values for multi-MSI don't all point to vCPU0.
|
||||
*/
|
||||
static int hv_compose_multi_msi_req_get_cpu(void)
|
||||
{
|
||||
static DEFINE_SPINLOCK(multi_msi_cpu_lock);
|
||||
|
||||
/* -1 means starting with CPU 0 */
|
||||
static int cpu_next = -1;
|
||||
|
||||
unsigned long flags;
|
||||
int cpu;
|
||||
|
||||
spin_lock_irqsave(&multi_msi_cpu_lock, flags);
|
||||
|
||||
cpu_next = cpumask_next_wrap(cpu_next, cpu_online_mask, nr_cpu_ids,
|
||||
false);
|
||||
cpu = cpu_next;
|
||||
|
||||
spin_unlock_irqrestore(&multi_msi_cpu_lock, flags);
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
||||
static u32 hv_compose_msi_req_v2(
|
||||
struct pci_create_interrupt2 *int_pkt, int cpu,
|
||||
u32 slot, u8 vector, u16 vector_count)
|
||||
{
|
||||
int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE2;
|
||||
int_pkt->wslot.slot = slot;
|
||||
int_pkt->int_desc.vector = vector;
|
||||
int_pkt->int_desc.vector_count = vector_count;
|
||||
int_pkt->int_desc.delivery_mode = DELIVERY_MODE;
|
||||
cpu = hv_compose_msi_req_get_cpu(affinity);
|
||||
int_pkt->int_desc.processor_array[0] =
|
||||
hv_cpu_number_to_vp_number(cpu);
|
||||
int_pkt->int_desc.processor_count = 1;
|
||||
@ -1660,18 +1710,15 @@ static u32 hv_compose_msi_req_v2(
|
||||
}
|
||||
|
||||
static u32 hv_compose_msi_req_v3(
|
||||
struct pci_create_interrupt3 *int_pkt, const struct cpumask *affinity,
|
||||
struct pci_create_interrupt3 *int_pkt, int cpu,
|
||||
u32 slot, u32 vector, u16 vector_count)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE3;
|
||||
int_pkt->wslot.slot = slot;
|
||||
int_pkt->int_desc.vector = vector;
|
||||
int_pkt->int_desc.reserved = 0;
|
||||
int_pkt->int_desc.vector_count = vector_count;
|
||||
int_pkt->int_desc.delivery_mode = DELIVERY_MODE;
|
||||
cpu = hv_compose_msi_req_get_cpu(affinity);
|
||||
int_pkt->int_desc.processor_array[0] =
|
||||
hv_cpu_number_to_vp_number(cpu);
|
||||
int_pkt->int_desc.processor_count = 1;
|
||||
@ -1715,12 +1762,18 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
struct pci_create_interrupt3 v3;
|
||||
} int_pkts;
|
||||
} __packed ctxt;
|
||||
bool multi_msi;
|
||||
u64 trans_id;
|
||||
u32 size;
|
||||
int ret;
|
||||
int cpu;
|
||||
|
||||
msi_desc = irq_data_get_msi_desc(data);
|
||||
multi_msi = !msi_desc->pci.msi_attrib.is_msix &&
|
||||
msi_desc->nvec_used > 1;
|
||||
|
||||
/* Reuse the previous allocation */
|
||||
if (data->chip_data) {
|
||||
if (data->chip_data && multi_msi) {
|
||||
int_desc = data->chip_data;
|
||||
msg->address_hi = int_desc->address >> 32;
|
||||
msg->address_lo = int_desc->address & 0xffffffff;
|
||||
@ -1728,7 +1781,6 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
return;
|
||||
}
|
||||
|
||||
msi_desc = irq_data_get_msi_desc(data);
|
||||
pdev = msi_desc_to_pci_dev(msi_desc);
|
||||
dest = irq_data_get_effective_affinity_mask(data);
|
||||
pbus = pdev->bus;
|
||||
@ -1738,11 +1790,18 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
if (!hpdev)
|
||||
goto return_null_message;
|
||||
|
||||
/* Free any previous message that might have already been composed. */
|
||||
if (data->chip_data && !multi_msi) {
|
||||
int_desc = data->chip_data;
|
||||
data->chip_data = NULL;
|
||||
hv_int_desc_free(hpdev, int_desc);
|
||||
}
|
||||
|
||||
int_desc = kzalloc(sizeof(*int_desc), GFP_ATOMIC);
|
||||
if (!int_desc)
|
||||
goto drop_reference;
|
||||
|
||||
if (!msi_desc->pci.msi_attrib.is_msix && msi_desc->nvec_used > 1) {
|
||||
if (multi_msi) {
|
||||
/*
|
||||
* If this is not the first MSI of Multi MSI, we already have
|
||||
* a mapping. Can exit early.
|
||||
@ -1767,9 +1826,11 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
*/
|
||||
vector = 32;
|
||||
vector_count = msi_desc->nvec_used;
|
||||
cpu = hv_compose_multi_msi_req_get_cpu();
|
||||
} else {
|
||||
vector = hv_msi_get_int_vector(data);
|
||||
vector_count = 1;
|
||||
cpu = hv_compose_msi_req_get_cpu(dest);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1785,7 +1846,6 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
switch (hbus->protocol_version) {
|
||||
case PCI_PROTOCOL_VERSION_1_1:
|
||||
size = hv_compose_msi_req_v1(&ctxt.int_pkts.v1,
|
||||
dest,
|
||||
hpdev->desc.win_slot.slot,
|
||||
(u8)vector,
|
||||
vector_count);
|
||||
@ -1794,7 +1854,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
case PCI_PROTOCOL_VERSION_1_2:
|
||||
case PCI_PROTOCOL_VERSION_1_3:
|
||||
size = hv_compose_msi_req_v2(&ctxt.int_pkts.v2,
|
||||
dest,
|
||||
cpu,
|
||||
hpdev->desc.win_slot.slot,
|
||||
(u8)vector,
|
||||
vector_count);
|
||||
@ -1802,7 +1862,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
|
||||
case PCI_PROTOCOL_VERSION_1_4:
|
||||
size = hv_compose_msi_req_v3(&ctxt.int_pkts.v3,
|
||||
dest,
|
||||
cpu,
|
||||
hpdev->desc.win_slot.slot,
|
||||
vector,
|
||||
vector_count);
|
||||
|
@ -725,7 +725,14 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
|
||||
/* Get thermal zone and ADC */
|
||||
di->tz = thermal_zone_get_zone_by_name("battery-thermal");
|
||||
if (IS_ERR(di->tz)) {
|
||||
return dev_err_probe(dev, PTR_ERR(di->tz),
|
||||
ret = PTR_ERR(di->tz);
|
||||
/*
|
||||
* This usually just means we are probing before the thermal
|
||||
* zone, so just defer.
|
||||
*/
|
||||
if (ret == -ENODEV)
|
||||
ret = -EPROBE_DEFER;
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to get battery thermal zone\n");
|
||||
}
|
||||
di->bat_ctrl = devm_iio_channel_get(dev, "bat_ctrl");
|
||||
|
@ -352,7 +352,7 @@ static int ip5xxx_battery_get_property(struct power_supply *psy,
|
||||
ret = ip5xxx_battery_read_adc(ip5xxx, IP5XXX_BATIADC_DAT0,
|
||||
IP5XXX_BATIADC_DAT1, &raw);
|
||||
|
||||
val->intval = DIV_ROUND_CLOSEST(raw * 745985, 1000);
|
||||
val->intval = DIV_ROUND_CLOSEST(raw * 149197, 200);
|
||||
return 0;
|
||||
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
|
||||
|
@ -121,7 +121,7 @@ struct rk817_charger {
|
||||
#define ADC_TO_CHARGE_UAH(adc_value, res_div) \
|
||||
(adc_value / 3600 * 172 / res_div)
|
||||
|
||||
static u8 rk817_chg_cur_to_reg(u32 chg_cur_ma)
|
||||
static int rk817_chg_cur_to_reg(u32 chg_cur_ma)
|
||||
{
|
||||
if (chg_cur_ma >= 3500)
|
||||
return CHG_3_5A;
|
||||
@ -864,8 +864,8 @@ static int rk817_battery_init(struct rk817_charger *charger,
|
||||
{
|
||||
struct rk808 *rk808 = charger->rk808;
|
||||
u32 tmp, max_chg_vol_mv, max_chg_cur_ma;
|
||||
u8 max_chg_vol_reg, chg_term_i_reg, max_chg_cur_reg;
|
||||
int ret, chg_term_ma;
|
||||
u8 max_chg_vol_reg, chg_term_i_reg;
|
||||
int ret, chg_term_ma, max_chg_cur_reg;
|
||||
u8 bulk_reg[2];
|
||||
|
||||
/* Get initial plug state */
|
||||
@ -1116,14 +1116,12 @@ static int rk817_charger_probe(struct platform_device *pdev)
|
||||
|
||||
charger->bat_ps = devm_power_supply_register(&pdev->dev,
|
||||
&rk817_bat_desc, &pscfg);
|
||||
|
||||
charger->chg_ps = devm_power_supply_register(&pdev->dev,
|
||||
&rk817_chg_desc, &pscfg);
|
||||
|
||||
if (IS_ERR(charger->chg_ps))
|
||||
if (IS_ERR(charger->bat_ps))
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Battery failed to probe\n");
|
||||
|
||||
charger->chg_ps = devm_power_supply_register(&pdev->dev,
|
||||
&rk817_chg_desc, &pscfg);
|
||||
if (IS_ERR(charger->chg_ps))
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Charger failed to probe\n");
|
||||
|
@ -5154,6 +5154,7 @@ static void regulator_dev_release(struct device *dev)
|
||||
{
|
||||
struct regulator_dev *rdev = dev_get_drvdata(dev);
|
||||
|
||||
debugfs_remove_recursive(rdev->debugfs);
|
||||
kfree(rdev->constraints);
|
||||
of_node_put(rdev->dev.of_node);
|
||||
kfree(rdev);
|
||||
@ -5644,11 +5645,15 @@ regulator_register(const struct regulator_desc *regulator_desc,
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
regulator_ena_gpio_free(rdev);
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
put_device(&rdev->dev);
|
||||
rdev = NULL;
|
||||
clean:
|
||||
if (dangling_of_gpiod)
|
||||
gpiod_put(config->ena_gpiod);
|
||||
if (rdev && rdev->dev.of_node)
|
||||
of_node_put(rdev->dev.of_node);
|
||||
kfree(rdev);
|
||||
kfree(config);
|
||||
put_device(&rdev->dev);
|
||||
rinse:
|
||||
if (dangling_cfg_gpiod)
|
||||
gpiod_put(cfg->ena_gpiod);
|
||||
@ -5677,7 +5682,6 @@ void regulator_unregister(struct regulator_dev *rdev)
|
||||
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
|
||||
debugfs_remove_recursive(rdev->debugfs);
|
||||
WARN_ON(rdev->open_count);
|
||||
regulator_remove_coupling(rdev);
|
||||
unset_regulator_supplies(rdev);
|
||||
|
@ -243,6 +243,7 @@ static int rt5759_regulator_register(struct rt5759_priv *priv)
|
||||
if (priv->chip_type == CHIP_TYPE_RT5759A)
|
||||
reg_desc->uV_step = RT5759A_STEP_UV;
|
||||
|
||||
memset(®_cfg, 0, sizeof(reg_cfg));
|
||||
reg_cfg.dev = priv->dev;
|
||||
reg_cfg.of_node = np;
|
||||
reg_cfg.init_data = of_get_regulator_init_data(priv->dev, np, reg_desc);
|
||||
|
@ -457,6 +457,8 @@ static int slg51000_i2c_probe(struct i2c_client *client)
|
||||
chip->cs_gpiod = cs_gpiod;
|
||||
}
|
||||
|
||||
usleep_range(10000, 11000);
|
||||
|
||||
i2c_set_clientdata(client, chip);
|
||||
chip->chip_irq = client->irq;
|
||||
chip->dev = dev;
|
||||
|
@ -67,6 +67,7 @@ struct twlreg_info {
|
||||
#define TWL6030_CFG_STATE_SLEEP 0x03
|
||||
#define TWL6030_CFG_STATE_GRP_SHIFT 5
|
||||
#define TWL6030_CFG_STATE_APP_SHIFT 2
|
||||
#define TWL6030_CFG_STATE_MASK 0x03
|
||||
#define TWL6030_CFG_STATE_APP_MASK (0x03 << TWL6030_CFG_STATE_APP_SHIFT)
|
||||
#define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\
|
||||
TWL6030_CFG_STATE_APP_SHIFT)
|
||||
@ -128,13 +129,14 @@ static int twl6030reg_is_enabled(struct regulator_dev *rdev)
|
||||
if (grp < 0)
|
||||
return grp;
|
||||
grp &= P1_GRP_6030;
|
||||
val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
|
||||
val = TWL6030_CFG_STATE_APP(val);
|
||||
} else {
|
||||
val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
|
||||
val &= TWL6030_CFG_STATE_MASK;
|
||||
grp = 1;
|
||||
}
|
||||
|
||||
val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
|
||||
val = TWL6030_CFG_STATE_APP(val);
|
||||
|
||||
return grp && (val == TWL6030_CFG_STATE_ON);
|
||||
}
|
||||
|
||||
@ -187,7 +189,12 @@ static int twl6030reg_get_status(struct regulator_dev *rdev)
|
||||
|
||||
val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
|
||||
|
||||
switch (TWL6030_CFG_STATE_APP(val)) {
|
||||
if (info->features & TWL6032_SUBCLASS)
|
||||
val &= TWL6030_CFG_STATE_MASK;
|
||||
else
|
||||
val = TWL6030_CFG_STATE_APP(val);
|
||||
|
||||
switch (val) {
|
||||
case TWL6030_CFG_STATE_ON:
|
||||
return REGULATOR_STATUS_NORMAL;
|
||||
|
||||
@ -530,6 +537,7 @@ static const struct twlreg_info TWL6030_INFO_##label = { \
|
||||
#define TWL6032_ADJUSTABLE_LDO(label, offset) \
|
||||
static const struct twlreg_info TWL6032_INFO_##label = { \
|
||||
.base = offset, \
|
||||
.features = TWL6032_SUBCLASS, \
|
||||
.desc = { \
|
||||
.name = #label, \
|
||||
.id = TWL6032_REG_##label, \
|
||||
@ -562,6 +570,7 @@ static const struct twlreg_info TWLFIXED_INFO_##label = { \
|
||||
#define TWL6032_ADJUSTABLE_SMPS(label, offset) \
|
||||
static const struct twlreg_info TWLSMPS_INFO_##label = { \
|
||||
.base = offset, \
|
||||
.features = TWL6032_SUBCLASS, \
|
||||
.desc = { \
|
||||
.name = #label, \
|
||||
.id = TWL6032_REG_##label, \
|
||||
|
@ -1954,7 +1954,7 @@ dasd_copy_pair_show(struct device *dev,
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!copy->entry[i].primary)
|
||||
if (i == DASD_CP_ENTRIES)
|
||||
goto out;
|
||||
|
||||
/* print all secondary */
|
||||
|
@ -4722,7 +4722,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
|
||||
struct dasd_device *basedev;
|
||||
struct req_iterator iter;
|
||||
struct dasd_ccw_req *cqr;
|
||||
unsigned int first_offs;
|
||||
unsigned int trkcount;
|
||||
unsigned long *idaws;
|
||||
unsigned int size;
|
||||
@ -4756,7 +4755,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
|
||||
last_trk = (blk_rq_pos(req) + blk_rq_sectors(req) - 1) /
|
||||
DASD_RAW_SECTORS_PER_TRACK;
|
||||
trkcount = last_trk - first_trk + 1;
|
||||
first_offs = 0;
|
||||
|
||||
if (rq_data_dir(req) == READ)
|
||||
cmd = DASD_ECKD_CCW_READ_TRACK;
|
||||
@ -4800,13 +4798,13 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
|
||||
|
||||
if (use_prefix) {
|
||||
prefix_LRE(ccw++, data, first_trk, last_trk, cmd, basedev,
|
||||
startdev, 1, first_offs + 1, trkcount, 0, 0);
|
||||
startdev, 1, 0, trkcount, 0, 0);
|
||||
} else {
|
||||
define_extent(ccw++, data, first_trk, last_trk, cmd, basedev, 0);
|
||||
ccw[-1].flags |= CCW_FLAG_CC;
|
||||
|
||||
data += sizeof(struct DE_eckd_data);
|
||||
locate_record_ext(ccw++, data, first_trk, first_offs + 1,
|
||||
locate_record_ext(ccw++, data, first_trk, 0,
|
||||
trkcount, cmd, basedev, 0, 0);
|
||||
}
|
||||
|
||||
@ -5500,7 +5498,7 @@ dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
|
||||
* Dump the range of CCWs into 'page' buffer
|
||||
* and return number of printed chars.
|
||||
*/
|
||||
static int
|
||||
static void
|
||||
dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
|
||||
{
|
||||
int len, count;
|
||||
@ -5518,16 +5516,21 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
|
||||
else
|
||||
datap = (char *) ((addr_t) from->cda);
|
||||
|
||||
/* dump data (max 32 bytes) */
|
||||
for (count = 0; count < from->count && count < 32; count++) {
|
||||
if (count % 8 == 0) len += sprintf(page + len, " ");
|
||||
if (count % 4 == 0) len += sprintf(page + len, " ");
|
||||
/* dump data (max 128 bytes) */
|
||||
for (count = 0; count < from->count && count < 128; count++) {
|
||||
if (count % 32 == 0)
|
||||
len += sprintf(page + len, "\n");
|
||||
if (count % 8 == 0)
|
||||
len += sprintf(page + len, " ");
|
||||
if (count % 4 == 0)
|
||||
len += sprintf(page + len, " ");
|
||||
len += sprintf(page + len, "%02x", datap[count]);
|
||||
}
|
||||
len += sprintf(page + len, "\n");
|
||||
from++;
|
||||
}
|
||||
return len;
|
||||
if (len > 0)
|
||||
printk(KERN_ERR "%s", page);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -5619,37 +5622,33 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
|
||||
if (req) {
|
||||
/* req == NULL for unsolicited interrupts */
|
||||
/* dump the Channel Program (max 140 Bytes per line) */
|
||||
/* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
|
||||
/* Count CCW and print first CCWs (maximum 7) */
|
||||
first = req->cpaddr;
|
||||
for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
|
||||
to = min(first + 6, last);
|
||||
len = sprintf(page, PRINTK_HEADER
|
||||
" Related CP in req: %p\n", req);
|
||||
dasd_eckd_dump_ccw_range(first, to, page + len);
|
||||
printk(KERN_ERR "%s", page);
|
||||
printk(KERN_ERR PRINTK_HEADER " Related CP in req: %p\n", req);
|
||||
dasd_eckd_dump_ccw_range(first, to, page);
|
||||
|
||||
/* print failing CCW area (maximum 4) */
|
||||
/* scsw->cda is either valid or zero */
|
||||
len = 0;
|
||||
from = ++to;
|
||||
fail = (struct ccw1 *)(addr_t)
|
||||
irb->scsw.cmd.cpa; /* failing CCW */
|
||||
if (from < fail - 2) {
|
||||
from = fail - 2; /* there is a gap - print header */
|
||||
len += sprintf(page, PRINTK_HEADER "......\n");
|
||||
printk(KERN_ERR PRINTK_HEADER "......\n");
|
||||
}
|
||||
to = min(fail + 1, last);
|
||||
len += dasd_eckd_dump_ccw_range(from, to, page + len);
|
||||
dasd_eckd_dump_ccw_range(from, to, page + len);
|
||||
|
||||
/* print last CCWs (maximum 2) */
|
||||
len = 0;
|
||||
from = max(from, ++to);
|
||||
if (from < last - 1) {
|
||||
from = last - 1; /* there is a gap - print header */
|
||||
len += sprintf(page + len, PRINTK_HEADER "......\n");
|
||||
printk(KERN_ERR PRINTK_HEADER "......\n");
|
||||
}
|
||||
len += dasd_eckd_dump_ccw_range(from, last, page + len);
|
||||
if (len > 0)
|
||||
printk(KERN_ERR "%s", page);
|
||||
dasd_eckd_dump_ccw_range(from, last, page + len);
|
||||
}
|
||||
free_page((unsigned long) page);
|
||||
}
|
||||
|
@ -401,7 +401,7 @@ dasd_ioctl_copy_pair_swap(struct block_device *bdev, void __user *argp)
|
||||
return -EFAULT;
|
||||
}
|
||||
if (memchr_inv(data.reserved, 0, sizeof(data.reserved))) {
|
||||
pr_warn("%s: Ivalid swap data specified.\n",
|
||||
pr_warn("%s: Invalid swap data specified\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
dasd_put_device(device);
|
||||
return DASD_COPYPAIRSWAP_INVALID;
|
||||
|
@ -233,8 +233,11 @@ static void __init ap_init_qci_info(void)
|
||||
if (!ap_qci_info)
|
||||
return;
|
||||
ap_qci_info_old = kzalloc(sizeof(*ap_qci_info_old), GFP_KERNEL);
|
||||
if (!ap_qci_info_old)
|
||||
if (!ap_qci_info_old) {
|
||||
kfree(ap_qci_info);
|
||||
ap_qci_info = NULL;
|
||||
return;
|
||||
}
|
||||
if (ap_fetch_qci_info(ap_qci_info) != 0) {
|
||||
kfree(ap_qci_info);
|
||||
kfree(ap_qci_info_old);
|
||||
|
@ -303,16 +303,21 @@ enum storvsc_request_type {
|
||||
};
|
||||
|
||||
/*
|
||||
* SRB status codes and masks; a subset of the codes used here.
|
||||
* SRB status codes and masks. In the 8-bit field, the two high order bits
|
||||
* are flags, while the remaining 6 bits are an integer status code. The
|
||||
* definitions here include only the subset of the integer status codes that
|
||||
* are tested for in this driver.
|
||||
*/
|
||||
|
||||
#define SRB_STATUS_AUTOSENSE_VALID 0x80
|
||||
#define SRB_STATUS_QUEUE_FROZEN 0x40
|
||||
#define SRB_STATUS_INVALID_LUN 0x20
|
||||
#define SRB_STATUS_SUCCESS 0x01
|
||||
#define SRB_STATUS_ABORTED 0x02
|
||||
#define SRB_STATUS_ERROR 0x04
|
||||
#define SRB_STATUS_DATA_OVERRUN 0x12
|
||||
|
||||
/* SRB status integer codes */
|
||||
#define SRB_STATUS_SUCCESS 0x01
|
||||
#define SRB_STATUS_ABORTED 0x02
|
||||
#define SRB_STATUS_ERROR 0x04
|
||||
#define SRB_STATUS_INVALID_REQUEST 0x06
|
||||
#define SRB_STATUS_DATA_OVERRUN 0x12
|
||||
#define SRB_STATUS_INVALID_LUN 0x20
|
||||
|
||||
#define SRB_STATUS(status) \
|
||||
(status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN))
|
||||
@ -969,38 +974,25 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
|
||||
void (*process_err_fn)(struct work_struct *work);
|
||||
struct hv_host_device *host_dev = shost_priv(host);
|
||||
|
||||
/*
|
||||
* In some situations, Hyper-V sets multiple bits in the
|
||||
* srb_status, such as ABORTED and ERROR. So process them
|
||||
* individually, with the most specific bits first.
|
||||
*/
|
||||
switch (SRB_STATUS(vm_srb->srb_status)) {
|
||||
case SRB_STATUS_ERROR:
|
||||
case SRB_STATUS_ABORTED:
|
||||
case SRB_STATUS_INVALID_REQUEST:
|
||||
if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID) {
|
||||
/* Check for capacity change */
|
||||
if ((asc == 0x2a) && (ascq == 0x9)) {
|
||||
process_err_fn = storvsc_device_scan;
|
||||
/* Retry the I/O that triggered this. */
|
||||
set_host_byte(scmnd, DID_REQUEUE);
|
||||
goto do_work;
|
||||
}
|
||||
|
||||
if (vm_srb->srb_status & SRB_STATUS_INVALID_LUN) {
|
||||
set_host_byte(scmnd, DID_NO_CONNECT);
|
||||
process_err_fn = storvsc_remove_lun;
|
||||
goto do_work;
|
||||
}
|
||||
|
||||
if (vm_srb->srb_status & SRB_STATUS_ABORTED) {
|
||||
if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID &&
|
||||
/* Capacity data has changed */
|
||||
(asc == 0x2a) && (ascq == 0x9)) {
|
||||
process_err_fn = storvsc_device_scan;
|
||||
/*
|
||||
* Retry the I/O that triggered this.
|
||||
* Otherwise, let upper layer deal with the
|
||||
* error when sense message is present
|
||||
*/
|
||||
set_host_byte(scmnd, DID_REQUEUE);
|
||||
goto do_work;
|
||||
}
|
||||
}
|
||||
|
||||
if (vm_srb->srb_status & SRB_STATUS_ERROR) {
|
||||
/*
|
||||
* Let upper layer deal with error when
|
||||
* sense message is present.
|
||||
*/
|
||||
if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is an error; offline the device since all
|
||||
@ -1023,6 +1015,13 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
|
||||
default:
|
||||
set_host_byte(scmnd, DID_ERROR);
|
||||
}
|
||||
return;
|
||||
|
||||
case SRB_STATUS_INVALID_LUN:
|
||||
set_host_byte(scmnd, DID_NO_CONNECT);
|
||||
process_err_fn = storvsc_remove_lun;
|
||||
goto do_work;
|
||||
|
||||
}
|
||||
return;
|
||||
|
||||
|
@ -600,11 +600,11 @@ int cdnsp_halt_endpoint(struct cdnsp_device *pdev,
|
||||
|
||||
trace_cdnsp_ep_halt(value ? "Set" : "Clear");
|
||||
|
||||
if (value) {
|
||||
ret = cdnsp_cmd_stop_ep(pdev, pep);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = cdnsp_cmd_stop_ep(pdev, pep);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (value) {
|
||||
if (GET_EP_CTX_STATE(pep->out_ctx) == EP_STATE_STOPPED) {
|
||||
cdnsp_queue_halt_endpoint(pdev, pep->idx);
|
||||
cdnsp_ring_cmd_db(pdev);
|
||||
@ -613,10 +613,6 @@ int cdnsp_halt_endpoint(struct cdnsp_device *pdev,
|
||||
|
||||
pep->ep_state |= EP_HALTED;
|
||||
} else {
|
||||
/*
|
||||
* In device mode driver can call reset endpoint command
|
||||
* from any endpoint state.
|
||||
*/
|
||||
cdnsp_queue_reset_ep(pdev, pep->idx);
|
||||
cdnsp_ring_cmd_db(pdev);
|
||||
ret = cdnsp_wait_for_cmd_compl(pdev);
|
||||
|
@ -1763,10 +1763,15 @@ static u32 cdnsp_td_remainder(struct cdnsp_device *pdev,
|
||||
int trb_buff_len,
|
||||
unsigned int td_total_len,
|
||||
struct cdnsp_request *preq,
|
||||
bool more_trbs_coming)
|
||||
bool more_trbs_coming,
|
||||
bool zlp)
|
||||
{
|
||||
u32 maxp, total_packet_count;
|
||||
|
||||
/* Before ZLP driver needs set TD_SIZE = 1. */
|
||||
if (zlp)
|
||||
return 1;
|
||||
|
||||
/* One TRB with a zero-length data packet. */
|
||||
if (!more_trbs_coming || (transferred == 0 && trb_buff_len == 0) ||
|
||||
trb_buff_len == td_total_len)
|
||||
@ -1960,7 +1965,8 @@ int cdnsp_queue_bulk_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
|
||||
/* Set the TRB length, TD size, and interrupter fields. */
|
||||
remainder = cdnsp_td_remainder(pdev, enqd_len, trb_buff_len,
|
||||
full_len, preq,
|
||||
more_trbs_coming);
|
||||
more_trbs_coming,
|
||||
zero_len_trb);
|
||||
|
||||
length_field = TRB_LEN(trb_buff_len) | TRB_TD_SIZE(remainder) |
|
||||
TRB_INTR_TARGET(0);
|
||||
@ -2025,7 +2031,7 @@ int cdnsp_queue_ctrl_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
|
||||
|
||||
if (preq->request.length > 0) {
|
||||
remainder = cdnsp_td_remainder(pdev, 0, preq->request.length,
|
||||
preq->request.length, preq, 1);
|
||||
preq->request.length, preq, 1, 0);
|
||||
|
||||
length_field = TRB_LEN(preq->request.length) |
|
||||
TRB_TD_SIZE(remainder) | TRB_INTR_TARGET(0);
|
||||
@ -2076,7 +2082,8 @@ int cdnsp_cmd_stop_ep(struct cdnsp_device *pdev, struct cdnsp_ep *pep)
|
||||
u32 ep_state = GET_EP_CTX_STATE(pep->out_ctx);
|
||||
int ret = 0;
|
||||
|
||||
if (ep_state == EP_STATE_STOPPED || ep_state == EP_STATE_DISABLED) {
|
||||
if (ep_state == EP_STATE_STOPPED || ep_state == EP_STATE_DISABLED ||
|
||||
ep_state == EP_STATE_HALTED) {
|
||||
trace_cdnsp_ep_stopped_or_disabled(pep->out_ctx);
|
||||
goto ep_stopped;
|
||||
}
|
||||
@ -2225,7 +2232,7 @@ static int cdnsp_queue_isoc_tx(struct cdnsp_device *pdev,
|
||||
/* Set the TRB length, TD size, & interrupter fields. */
|
||||
remainder = cdnsp_td_remainder(pdev, running_total,
|
||||
trb_buff_len, td_len, preq,
|
||||
more_trbs_coming);
|
||||
more_trbs_coming, 0);
|
||||
|
||||
length_field = TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0);
|
||||
|
||||
|
@ -37,15 +37,6 @@ struct dwc3_exynos {
|
||||
struct regulator *vdd10;
|
||||
};
|
||||
|
||||
static int dwc3_exynos_remove_child(struct device *dev, void *unused)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_exynos_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_exynos *exynos;
|
||||
@ -142,7 +133,7 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
|
||||
struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
|
||||
of_platform_depopulate(&pdev->dev);
|
||||
|
||||
for (i = exynos->num_clks - 1; i >= 0; i--)
|
||||
clk_disable_unprepare(exynos->clks[i]);
|
||||
|
@ -291,7 +291,8 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
|
||||
*
|
||||
* DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section 3.2.2
|
||||
*/
|
||||
if (dwc->gadget->speed <= USB_SPEED_HIGH) {
|
||||
if (dwc->gadget->speed <= USB_SPEED_HIGH ||
|
||||
DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_ENDTRANSFER) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
|
||||
saved_config |= DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
@ -1023,12 +1024,6 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
|
||||
reg &= ~DWC3_DALEPENA_EP(dep->number);
|
||||
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
|
||||
|
||||
/* Clear out the ep descriptors for non-ep0 */
|
||||
if (dep->number > 1) {
|
||||
dep->endpoint.comp_desc = NULL;
|
||||
dep->endpoint.desc = NULL;
|
||||
}
|
||||
|
||||
dwc3_remove_requests(dwc, dep, -ESHUTDOWN);
|
||||
|
||||
dep->stream_capable = false;
|
||||
@ -1043,6 +1038,12 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
|
||||
mask |= (DWC3_EP_DELAY_STOP | DWC3_EP_TRANSFER_STARTED);
|
||||
dep->flags &= mask;
|
||||
|
||||
/* Clear out the ep descriptors for non-ep0 */
|
||||
if (dep->number > 1) {
|
||||
dep->endpoint.comp_desc = NULL;
|
||||
dep->endpoint.desc = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -199,16 +199,6 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
|
||||
* V4L2 ioctls
|
||||
*/
|
||||
|
||||
struct uvc_format {
|
||||
u8 bpp;
|
||||
u32 fcc;
|
||||
};
|
||||
|
||||
static struct uvc_format uvc_formats[] = {
|
||||
{ 16, V4L2_PIX_FMT_YUYV },
|
||||
{ 0, V4L2_PIX_FMT_MJPEG },
|
||||
};
|
||||
|
||||
static int
|
||||
uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
|
||||
{
|
||||
@ -242,47 +232,6 @@ uvc_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *fmt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct uvc_device *uvc = video_get_drvdata(vdev);
|
||||
struct uvc_video *video = &uvc->video;
|
||||
struct uvc_format *format;
|
||||
unsigned int imagesize;
|
||||
unsigned int bpl;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(uvc_formats); ++i) {
|
||||
format = &uvc_formats[i];
|
||||
if (format->fcc == fmt->fmt.pix.pixelformat)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(uvc_formats)) {
|
||||
uvcg_info(&uvc->func, "Unsupported format 0x%08x.\n",
|
||||
fmt->fmt.pix.pixelformat);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bpl = format->bpp * fmt->fmt.pix.width / 8;
|
||||
imagesize = bpl ? bpl * fmt->fmt.pix.height : fmt->fmt.pix.sizeimage;
|
||||
|
||||
video->fcc = format->fcc;
|
||||
video->bpp = format->bpp;
|
||||
video->width = fmt->fmt.pix.width;
|
||||
video->height = fmt->fmt.pix.height;
|
||||
video->imagesize = imagesize;
|
||||
|
||||
fmt->fmt.pix.field = V4L2_FIELD_NONE;
|
||||
fmt->fmt.pix.bytesperline = bpl;
|
||||
fmt->fmt.pix.sizeimage = imagesize;
|
||||
fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
|
||||
fmt->fmt.pix.priv = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_v4l2_try_format(struct file *file, void *fh, struct v4l2_format *fmt)
|
||||
{
|
||||
@ -323,6 +272,27 @@ uvc_v4l2_try_format(struct file *file, void *fh, struct v4l2_format *fmt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct uvc_device *uvc = video_get_drvdata(vdev);
|
||||
struct uvc_video *video = &uvc->video;
|
||||
int ret;
|
||||
|
||||
ret = uvc_v4l2_try_format(file, fh, fmt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
video->fcc = fmt->fmt.pix.pixelformat;
|
||||
video->bpp = fmt->fmt.pix.bytesperline * 8 / video->width;
|
||||
video->width = fmt->fmt.pix.width;
|
||||
video->height = fmt->fmt.pix.height;
|
||||
video->imagesize = fmt->fmt.pix.sizeimage;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_v4l2_enum_frameintervals(struct file *file, void *fh,
|
||||
struct v4l2_frmivalenum *fival)
|
||||
|
@ -67,8 +67,27 @@ static bool is_vmpck_empty(struct snp_guest_dev *snp_dev)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If an error is received from the host or AMD Secure Processor (ASP) there
|
||||
* are two options. Either retry the exact same encrypted request or discontinue
|
||||
* using the VMPCK.
|
||||
*
|
||||
* This is because in the current encryption scheme GHCB v2 uses AES-GCM to
|
||||
* encrypt the requests. The IV for this scheme is the sequence number. GCM
|
||||
* cannot tolerate IV reuse.
|
||||
*
|
||||
* The ASP FW v1.51 only increments the sequence numbers on a successful
|
||||
* guest<->ASP back and forth and only accepts messages at its exact sequence
|
||||
* number.
|
||||
*
|
||||
* So if the sequence number were to be reused the encryption scheme is
|
||||
* vulnerable. If the sequence number were incremented for a fresh IV the ASP
|
||||
* will reject the request.
|
||||
*/
|
||||
static void snp_disable_vmpck(struct snp_guest_dev *snp_dev)
|
||||
{
|
||||
dev_alert(snp_dev->dev, "Disabling vmpck_id %d to prevent IV reuse.\n",
|
||||
vmpck_id);
|
||||
memzero_explicit(snp_dev->vmpck, VMPCK_KEY_LEN);
|
||||
snp_dev->vmpck = NULL;
|
||||
}
|
||||
@ -321,34 +340,71 @@ static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, in
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Call firmware to process the request */
|
||||
/*
|
||||
* Call firmware to process the request. In this function the encrypted
|
||||
* message enters shared memory with the host. So after this call the
|
||||
* sequence number must be incremented or the VMPCK must be deleted to
|
||||
* prevent reuse of the IV.
|
||||
*/
|
||||
rc = snp_issue_guest_request(exit_code, &snp_dev->input, &err);
|
||||
|
||||
/*
|
||||
* If the extended guest request fails due to having too small of a
|
||||
* certificate data buffer, retry the same guest request without the
|
||||
* extended data request in order to increment the sequence number
|
||||
* and thus avoid IV reuse.
|
||||
*/
|
||||
if (exit_code == SVM_VMGEXIT_EXT_GUEST_REQUEST &&
|
||||
err == SNP_GUEST_REQ_INVALID_LEN) {
|
||||
const unsigned int certs_npages = snp_dev->input.data_npages;
|
||||
|
||||
exit_code = SVM_VMGEXIT_GUEST_REQUEST;
|
||||
|
||||
/*
|
||||
* If this call to the firmware succeeds, the sequence number can
|
||||
* be incremented allowing for continued use of the VMPCK. If
|
||||
* there is an error reflected in the return value, this value
|
||||
* is checked further down and the result will be the deletion
|
||||
* of the VMPCK and the error code being propagated back to the
|
||||
* user as an ioctl() return code.
|
||||
*/
|
||||
rc = snp_issue_guest_request(exit_code, &snp_dev->input, &err);
|
||||
|
||||
/*
|
||||
* Override the error to inform callers the given extended
|
||||
* request buffer size was too small and give the caller the
|
||||
* required buffer size.
|
||||
*/
|
||||
err = SNP_GUEST_REQ_INVALID_LEN;
|
||||
snp_dev->input.data_npages = certs_npages;
|
||||
}
|
||||
|
||||
if (fw_err)
|
||||
*fw_err = err;
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
if (rc) {
|
||||
dev_alert(snp_dev->dev,
|
||||
"Detected error from ASP request. rc: %d, fw_err: %llu\n",
|
||||
rc, *fw_err);
|
||||
goto disable_vmpck;
|
||||
}
|
||||
|
||||
/*
|
||||
* The verify_and_dec_payload() will fail only if the hypervisor is
|
||||
* actively modifying the message header or corrupting the encrypted payload.
|
||||
* This hints that hypervisor is acting in a bad faith. Disable the VMPCK so that
|
||||
* the key cannot be used for any communication. The key is disabled to ensure
|
||||
* that AES-GCM does not use the same IV while encrypting the request payload.
|
||||
*/
|
||||
rc = verify_and_dec_payload(snp_dev, resp_buf, resp_sz);
|
||||
if (rc) {
|
||||
dev_alert(snp_dev->dev,
|
||||
"Detected unexpected decode failure, disabling the vmpck_id %d\n",
|
||||
vmpck_id);
|
||||
snp_disable_vmpck(snp_dev);
|
||||
return rc;
|
||||
"Detected unexpected decode failure from ASP. rc: %d\n",
|
||||
rc);
|
||||
goto disable_vmpck;
|
||||
}
|
||||
|
||||
/* Increment to new message sequence after payload decryption was successful. */
|
||||
snp_inc_msg_seqno(snp_dev);
|
||||
|
||||
return 0;
|
||||
|
||||
disable_vmpck:
|
||||
snp_disable_vmpck(snp_dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg)
|
||||
|
@ -4663,7 +4663,12 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ASSERT(!path->nowait);
|
||||
/*
|
||||
* The nowait semantics are used only for write paths, where we don't
|
||||
* use the tree mod log and sequence numbers.
|
||||
*/
|
||||
if (time_seq)
|
||||
ASSERT(!path->nowait);
|
||||
|
||||
nritems = btrfs_header_nritems(path->nodes[0]);
|
||||
if (nritems == 0)
|
||||
@ -4683,7 +4688,14 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
|
||||
if (path->need_commit_sem) {
|
||||
path->need_commit_sem = 0;
|
||||
need_commit_sem = true;
|
||||
down_read(&fs_info->commit_root_sem);
|
||||
if (path->nowait) {
|
||||
if (!down_read_trylock(&fs_info->commit_root_sem)) {
|
||||
ret = -EAGAIN;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
down_read(&fs_info->commit_root_sem);
|
||||
}
|
||||
}
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
}
|
||||
@ -4759,7 +4771,7 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
|
||||
next = c;
|
||||
ret = read_block_for_search(root, path, &next, level,
|
||||
slot, &key);
|
||||
if (ret == -EAGAIN)
|
||||
if (ret == -EAGAIN && !path->nowait)
|
||||
goto again;
|
||||
|
||||
if (ret < 0) {
|
||||
@ -4769,6 +4781,10 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
|
||||
|
||||
if (!path->skip_locking) {
|
||||
ret = btrfs_try_tree_read_lock(next);
|
||||
if (!ret && path->nowait) {
|
||||
ret = -EAGAIN;
|
||||
goto done;
|
||||
}
|
||||
if (!ret && time_seq) {
|
||||
/*
|
||||
* If we don't get the lock, we may be racing
|
||||
@ -4799,7 +4815,7 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
|
||||
|
||||
ret = read_block_for_search(root, path, &next, level,
|
||||
0, &key);
|
||||
if (ret == -EAGAIN)
|
||||
if (ret == -EAGAIN && !path->nowait)
|
||||
goto again;
|
||||
|
||||
if (ret < 0) {
|
||||
@ -4807,8 +4823,16 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!path->skip_locking)
|
||||
btrfs_tree_read_lock(next);
|
||||
if (!path->skip_locking) {
|
||||
if (path->nowait) {
|
||||
if (!btrfs_try_tree_read_lock(next)) {
|
||||
ret = -EAGAIN;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
btrfs_tree_read_lock(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
done:
|
||||
|
@ -3105,6 +3105,8 @@ static int btrfs_ioctl_get_subvol_info(struct inode *inode, void __user *argp)
|
||||
}
|
||||
}
|
||||
|
||||
btrfs_free_path(path);
|
||||
path = NULL;
|
||||
if (copy_to_user(argp, subvol_info, sizeof(*subvol_info)))
|
||||
ret = -EFAULT;
|
||||
|
||||
@ -3194,6 +3196,8 @@ static int btrfs_ioctl_get_subvol_rootref(struct btrfs_root *root,
|
||||
}
|
||||
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
|
||||
if (!ret || ret == -EOVERFLOW) {
|
||||
rootrefs->num_items = found;
|
||||
/* update min_treeid for next search */
|
||||
@ -3205,7 +3209,6 @@ static int btrfs_ioctl_get_subvol_rootref(struct btrfs_root *root,
|
||||
}
|
||||
|
||||
kfree(rootrefs);
|
||||
btrfs_free_path(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -4231,6 +4234,8 @@ static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg)
|
||||
ipath->fspath->val[i] = rel_ptr;
|
||||
}
|
||||
|
||||
btrfs_free_path(path);
|
||||
path = NULL;
|
||||
ret = copy_to_user((void __user *)(unsigned long)ipa->fspath,
|
||||
ipath->fspath, size);
|
||||
if (ret) {
|
||||
@ -4281,21 +4286,20 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_fs_info *fs_info,
|
||||
size = min_t(u32, loi->size, SZ_16M);
|
||||
}
|
||||
|
||||
inodes = init_data_container(size);
|
||||
if (IS_ERR(inodes)) {
|
||||
ret = PTR_ERR(inodes);
|
||||
goto out_loi;
|
||||
}
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
inodes = init_data_container(size);
|
||||
if (IS_ERR(inodes)) {
|
||||
ret = PTR_ERR(inodes);
|
||||
inodes = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = iterate_inodes_from_logical(loi->logical, fs_info, path,
|
||||
inodes, ignore_offset);
|
||||
btrfs_free_path(path);
|
||||
if (ret == -EINVAL)
|
||||
ret = -ENOENT;
|
||||
if (ret < 0)
|
||||
@ -4307,7 +4311,6 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_fs_info *fs_info,
|
||||
ret = -EFAULT;
|
||||
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
kvfree(inodes);
|
||||
out_loi:
|
||||
kfree(loi);
|
||||
|
@ -2951,14 +2951,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
|
||||
dstgroup->rsv_rfer = inherit->lim.rsv_rfer;
|
||||
dstgroup->rsv_excl = inherit->lim.rsv_excl;
|
||||
|
||||
ret = update_qgroup_limit_item(trans, dstgroup);
|
||||
if (ret) {
|
||||
qgroup_mark_inconsistent(fs_info);
|
||||
btrfs_info(fs_info,
|
||||
"unable to update quota limit for %llu",
|
||||
dstgroup->qgroupid);
|
||||
goto unlock;
|
||||
}
|
||||
qgroup_dirty(fs_info, dstgroup);
|
||||
}
|
||||
|
||||
if (srcid) {
|
||||
|
@ -5702,6 +5702,7 @@ static int clone_range(struct send_ctx *sctx, struct btrfs_path *dst_path,
|
||||
u64 ext_len;
|
||||
u64 clone_len;
|
||||
u64 clone_data_offset;
|
||||
bool crossed_src_i_size = false;
|
||||
|
||||
if (slot >= btrfs_header_nritems(leaf)) {
|
||||
ret = btrfs_next_leaf(clone_root->root, path);
|
||||
@ -5759,8 +5760,10 @@ static int clone_range(struct send_ctx *sctx, struct btrfs_path *dst_path,
|
||||
if (key.offset >= clone_src_i_size)
|
||||
break;
|
||||
|
||||
if (key.offset + ext_len > clone_src_i_size)
|
||||
if (key.offset + ext_len > clone_src_i_size) {
|
||||
ext_len = clone_src_i_size - key.offset;
|
||||
crossed_src_i_size = true;
|
||||
}
|
||||
|
||||
clone_data_offset = btrfs_file_extent_offset(leaf, ei);
|
||||
if (btrfs_file_extent_disk_bytenr(leaf, ei) == disk_byte) {
|
||||
@ -5821,6 +5824,25 @@ static int clone_range(struct send_ctx *sctx, struct btrfs_path *dst_path,
|
||||
ret = send_clone(sctx, offset, clone_len,
|
||||
clone_root);
|
||||
}
|
||||
} else if (crossed_src_i_size && clone_len < len) {
|
||||
/*
|
||||
* If we are at i_size of the clone source inode and we
|
||||
* can not clone from it, terminate the loop. This is
|
||||
* to avoid sending two write operations, one with a
|
||||
* length matching clone_len and the final one after
|
||||
* this loop with a length of len - clone_len.
|
||||
*
|
||||
* When using encoded writes (BTRFS_SEND_FLAG_COMPRESSED
|
||||
* was passed to the send ioctl), this helps avoid
|
||||
* sending an encoded write for an offset that is not
|
||||
* sector size aligned, in case the i_size of the source
|
||||
* inode is not sector size aligned. That will make the
|
||||
* receiver fallback to decompression of the data and
|
||||
* writing it using regular buffered IO, therefore while
|
||||
* not incorrect, it's not optimal due decompression and
|
||||
* possible re-compression at the receiver.
|
||||
*/
|
||||
break;
|
||||
} else {
|
||||
ret = send_extent_data(sctx, dst_path, offset,
|
||||
clone_len);
|
||||
|
@ -2321,8 +2321,11 @@ int __init btrfs_init_sysfs(void)
|
||||
|
||||
#ifdef CONFIG_BTRFS_DEBUG
|
||||
ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group);
|
||||
if (ret)
|
||||
goto out2;
|
||||
if (ret) {
|
||||
sysfs_unmerge_group(&btrfs_kset->kobj,
|
||||
&btrfs_static_feature_attr_group);
|
||||
goto out_remove_group;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
@ -3694,15 +3694,29 @@ static int process_dir_items_leaf(struct btrfs_trans_handle *trans,
|
||||
u64 *last_old_dentry_offset)
|
||||
{
|
||||
struct btrfs_root *log = inode->root->log_root;
|
||||
struct extent_buffer *src = path->nodes[0];
|
||||
const int nritems = btrfs_header_nritems(src);
|
||||
struct extent_buffer *src;
|
||||
const int nritems = btrfs_header_nritems(path->nodes[0]);
|
||||
const u64 ino = btrfs_ino(inode);
|
||||
bool last_found = false;
|
||||
int batch_start = 0;
|
||||
int batch_size = 0;
|
||||
int i;
|
||||
|
||||
for (i = path->slots[0]; i < nritems; i++) {
|
||||
/*
|
||||
* We need to clone the leaf, release the read lock on it, and use the
|
||||
* clone before modifying the log tree. See the comment at copy_items()
|
||||
* about why we need to do this.
|
||||
*/
|
||||
src = btrfs_clone_extent_buffer(path->nodes[0]);
|
||||
if (!src)
|
||||
return -ENOMEM;
|
||||
|
||||
i = path->slots[0];
|
||||
btrfs_release_path(path);
|
||||
path->nodes[0] = src;
|
||||
path->slots[0] = i;
|
||||
|
||||
for (; i < nritems; i++) {
|
||||
struct btrfs_dir_item *di;
|
||||
struct btrfs_key key;
|
||||
int ret;
|
||||
@ -4303,7 +4317,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
|
||||
{
|
||||
struct btrfs_root *log = inode->root->log_root;
|
||||
struct btrfs_file_extent_item *extent;
|
||||
struct extent_buffer *src = src_path->nodes[0];
|
||||
struct extent_buffer *src;
|
||||
int ret = 0;
|
||||
struct btrfs_key *ins_keys;
|
||||
u32 *ins_sizes;
|
||||
@ -4314,6 +4328,43 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
|
||||
const bool skip_csum = (inode->flags & BTRFS_INODE_NODATASUM);
|
||||
const u64 i_size = i_size_read(&inode->vfs_inode);
|
||||
|
||||
/*
|
||||
* To keep lockdep happy and avoid deadlocks, clone the source leaf and
|
||||
* use the clone. This is because otherwise we would be changing the log
|
||||
* tree, to insert items from the subvolume tree or insert csum items,
|
||||
* while holding a read lock on a leaf from the subvolume tree, which
|
||||
* creates a nasty lock dependency when COWing log tree nodes/leaves:
|
||||
*
|
||||
* 1) Modifying the log tree triggers an extent buffer allocation while
|
||||
* holding a write lock on a parent extent buffer from the log tree.
|
||||
* Allocating the pages for an extent buffer, or the extent buffer
|
||||
* struct, can trigger inode eviction and finally the inode eviction
|
||||
* will trigger a release/remove of a delayed node, which requires
|
||||
* taking the delayed node's mutex;
|
||||
*
|
||||
* 2) Allocating a metadata extent for a log tree can trigger the async
|
||||
* reclaim thread and make us wait for it to release enough space and
|
||||
* unblock our reservation ticket. The reclaim thread can start
|
||||
* flushing delayed items, and that in turn results in the need to
|
||||
* lock delayed node mutexes and in the need to write lock extent
|
||||
* buffers of a subvolume tree - all this while holding a write lock
|
||||
* on the parent extent buffer in the log tree.
|
||||
*
|
||||
* So one task in scenario 1) running in parallel with another task in
|
||||
* scenario 2) could lead to a deadlock, one wanting to lock a delayed
|
||||
* node mutex while having a read lock on a leaf from the subvolume,
|
||||
* while the other is holding the delayed node's mutex and wants to
|
||||
* write lock the same subvolume leaf for flushing delayed items.
|
||||
*/
|
||||
src = btrfs_clone_extent_buffer(src_path->nodes[0]);
|
||||
if (!src)
|
||||
return -ENOMEM;
|
||||
|
||||
i = src_path->slots[0];
|
||||
btrfs_release_path(src_path);
|
||||
src_path->nodes[0] = src;
|
||||
src_path->slots[0] = i;
|
||||
|
||||
ins_data = kmalloc(nr * sizeof(struct btrfs_key) +
|
||||
nr * sizeof(u32), GFP_NOFS);
|
||||
if (!ins_data)
|
||||
|
@ -134,7 +134,8 @@ static int sb_write_pointer(struct block_device *bdev, struct blk_zone *zones,
|
||||
super[i] = page_address(page[i]);
|
||||
}
|
||||
|
||||
if (super[0]->generation > super[1]->generation)
|
||||
if (btrfs_super_generation(super[0]) >
|
||||
btrfs_super_generation(super[1]))
|
||||
sector = zones[1].start;
|
||||
else
|
||||
sector = zones[0].start;
|
||||
@ -466,7 +467,7 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
|
||||
goto out;
|
||||
}
|
||||
|
||||
zones = kcalloc(BTRFS_REPORT_NR_ZONES, sizeof(struct blk_zone), GFP_KERNEL);
|
||||
zones = kvcalloc(BTRFS_REPORT_NR_ZONES, sizeof(struct blk_zone), GFP_KERNEL);
|
||||
if (!zones) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
@ -585,7 +586,7 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
|
||||
}
|
||||
|
||||
|
||||
kfree(zones);
|
||||
kvfree(zones);
|
||||
|
||||
switch (bdev_zoned_model(bdev)) {
|
||||
case BLK_ZONED_HM:
|
||||
@ -617,7 +618,7 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
|
||||
return 0;
|
||||
|
||||
out:
|
||||
kfree(zones);
|
||||
kvfree(zones);
|
||||
out_free_zone_info:
|
||||
btrfs_destroy_dev_zone_info(device);
|
||||
|
||||
|
@ -1281,7 +1281,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
|
||||
rc = filemap_write_and_wait_range(src_inode->i_mapping, off,
|
||||
off + len - 1);
|
||||
if (rc)
|
||||
goto out;
|
||||
goto unlock;
|
||||
|
||||
/* should we flush first and last page first */
|
||||
truncate_inode_pages(&target_inode->i_data, 0);
|
||||
@ -1297,6 +1297,8 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
|
||||
* that target is updated on the server
|
||||
*/
|
||||
CIFS_I(target_inode)->time = 0;
|
||||
|
||||
unlock:
|
||||
/* although unlocking in the reverse order from locking is not
|
||||
* strictly necessary here it is a little cleaner to be consistent
|
||||
*/
|
||||
|
@ -302,14 +302,14 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
|
||||
|
||||
/* now drop the ref to the current iface */
|
||||
if (old_iface && iface) {
|
||||
kref_put(&old_iface->refcount, release_iface);
|
||||
cifs_dbg(FYI, "replacing iface: %pIS with %pIS\n",
|
||||
&old_iface->sockaddr,
|
||||
&iface->sockaddr);
|
||||
} else if (old_iface) {
|
||||
kref_put(&old_iface->refcount, release_iface);
|
||||
} else if (old_iface) {
|
||||
cifs_dbg(FYI, "releasing ref to iface: %pIS\n",
|
||||
&old_iface->sockaddr);
|
||||
kref_put(&old_iface->refcount, release_iface);
|
||||
} else {
|
||||
WARN_ON(!iface);
|
||||
cifs_dbg(FYI, "adding new iface: %pIS\n", &iface->sockaddr);
|
||||
|
11
fs/file.c
11
fs/file.c
@ -1003,7 +1003,16 @@ static unsigned long __fget_light(unsigned int fd, fmode_t mask)
|
||||
struct files_struct *files = current->files;
|
||||
struct file *file;
|
||||
|
||||
if (atomic_read(&files->count) == 1) {
|
||||
/*
|
||||
* If another thread is concurrently calling close_fd() followed
|
||||
* by put_files_struct(), we must not observe the old table
|
||||
* entry combined with the new refcount - otherwise we could
|
||||
* return a file that is concurrently being freed.
|
||||
*
|
||||
* atomic_read_acquire() pairs with atomic_dec_and_test() in
|
||||
* put_files_struct().
|
||||
*/
|
||||
if (atomic_read_acquire(&files->count) == 1) {
|
||||
file = files_lookup_fd_raw(files, fd);
|
||||
if (!file || unlikely(file->f_mode & mask))
|
||||
return 0;
|
||||
|
@ -1794,9 +1794,9 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
|
||||
ret = vfs_copy_file_range(src_fp->filp, src_off,
|
||||
dst_fp->filp, dst_off, len, 0);
|
||||
if (ret == -EOPNOTSUPP || ret == -EXDEV)
|
||||
ret = generic_copy_file_range(src_fp->filp, src_off,
|
||||
dst_fp->filp, dst_off,
|
||||
len, 0);
|
||||
ret = vfs_copy_file_range(src_fp->filp, src_off,
|
||||
dst_fp->filp, dst_off, len,
|
||||
COPY_FILE_SPLICE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -3591,6 +3591,7 @@ static int vfs_tmpfile(struct user_namespace *mnt_userns,
|
||||
struct inode *dir = d_inode(parentpath->dentry);
|
||||
struct inode *inode;
|
||||
int error;
|
||||
int open_flag = file->f_flags;
|
||||
|
||||
/* we want directory to be writable */
|
||||
error = inode_permission(mnt_userns, dir, MAY_WRITE | MAY_EXEC);
|
||||
@ -3613,7 +3614,7 @@ static int vfs_tmpfile(struct user_namespace *mnt_userns,
|
||||
if (error)
|
||||
return error;
|
||||
inode = file_inode(file);
|
||||
if (!(file->f_flags & O_EXCL)) {
|
||||
if (!(open_flag & O_EXCL)) {
|
||||
spin_lock(&inode->i_lock);
|
||||
inode->i_state |= I_LINKABLE;
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
@ -596,8 +596,8 @@ ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,
|
||||
ret = vfs_copy_file_range(src, src_pos, dst, dst_pos, count, 0);
|
||||
|
||||
if (ret == -EOPNOTSUPP || ret == -EXDEV)
|
||||
ret = generic_copy_file_range(src, src_pos, dst, dst_pos,
|
||||
count, 0);
|
||||
ret = vfs_copy_file_range(src, src_pos, dst, dst_pos, count,
|
||||
COPY_FILE_SPLICE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -871,10 +871,11 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
|
||||
struct svc_rqst *rqstp = sd->u.data;
|
||||
struct page *page = buf->page; // may be a compound one
|
||||
unsigned offset = buf->offset;
|
||||
struct page *last_page;
|
||||
|
||||
page += offset / PAGE_SIZE;
|
||||
for (int i = sd->len; i > 0; i -= PAGE_SIZE)
|
||||
svc_rqst_replace_page(rqstp, page++);
|
||||
last_page = page + (offset + sd->len - 1) / PAGE_SIZE;
|
||||
for (page += offset / PAGE_SIZE; page <= last_page; page++)
|
||||
svc_rqst_replace_page(rqstp, page);
|
||||
if (rqstp->rq_res.page_len == 0) // first call
|
||||
rqstp->rq_res.page_base = offset % PAGE_SIZE;
|
||||
rqstp->rq_res.page_len += sd->len;
|
||||
|
@ -495,14 +495,22 @@ void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
|
||||
int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum)
|
||||
{
|
||||
struct buffer_head *bh;
|
||||
void *kaddr;
|
||||
struct nilfs_segment_usage *su;
|
||||
int ret;
|
||||
|
||||
down_write(&NILFS_MDT(sufile)->mi_sem);
|
||||
ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
|
||||
if (!ret) {
|
||||
mark_buffer_dirty(bh);
|
||||
nilfs_mdt_mark_dirty(sufile);
|
||||
kaddr = kmap_atomic(bh->b_page);
|
||||
su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr);
|
||||
nilfs_segment_usage_set_dirty(su);
|
||||
kunmap_atomic(kaddr);
|
||||
brelse(bh);
|
||||
}
|
||||
up_write(&NILFS_MDT(sufile)->mi_sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
|
||||
#endif
|
||||
show_val_kb(m, "PageTables: ",
|
||||
global_node_page_state(NR_PAGETABLE));
|
||||
show_val_kb(m, "SecPageTables: ",
|
||||
show_val_kb(m, "SecPageTables: ",
|
||||
global_node_page_state(NR_SECONDARY_PAGETABLE));
|
||||
|
||||
show_val_kb(m, "NFS_Unstable: ", 0);
|
||||
|
@ -1388,6 +1388,8 @@ ssize_t generic_copy_file_range(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
size_t len, unsigned int flags)
|
||||
{
|
||||
lockdep_assert(sb_write_started(file_inode(file_out)->i_sb));
|
||||
|
||||
return do_splice_direct(file_in, &pos_in, file_out, &pos_out,
|
||||
len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0);
|
||||
}
|
||||
@ -1424,7 +1426,9 @@ static int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
|
||||
* and several different sets of file_operations, but they all end up
|
||||
* using the same ->copy_file_range() function pointer.
|
||||
*/
|
||||
if (file_out->f_op->copy_file_range) {
|
||||
if (flags & COPY_FILE_SPLICE) {
|
||||
/* cross sb splice is allowed */
|
||||
} else if (file_out->f_op->copy_file_range) {
|
||||
if (file_in->f_op->copy_file_range !=
|
||||
file_out->f_op->copy_file_range)
|
||||
return -EXDEV;
|
||||
@ -1474,8 +1478,9 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
|
||||
size_t len, unsigned int flags)
|
||||
{
|
||||
ssize_t ret;
|
||||
bool splice = flags & COPY_FILE_SPLICE;
|
||||
|
||||
if (flags != 0)
|
||||
if (flags & ~COPY_FILE_SPLICE)
|
||||
return -EINVAL;
|
||||
|
||||
ret = generic_copy_file_checks(file_in, pos_in, file_out, pos_out, &len,
|
||||
@ -1501,14 +1506,14 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
|
||||
* same sb using clone, but for filesystems where both clone and copy
|
||||
* are supported (e.g. nfs,cifs), we only call the copy method.
|
||||
*/
|
||||
if (file_out->f_op->copy_file_range) {
|
||||
if (!splice && file_out->f_op->copy_file_range) {
|
||||
ret = file_out->f_op->copy_file_range(file_in, pos_in,
|
||||
file_out, pos_out,
|
||||
len, flags);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (file_in->f_op->remap_file_range &&
|
||||
if (!splice && file_in->f_op->remap_file_range &&
|
||||
file_inode(file_in)->i_sb == file_inode(file_out)->i_sb) {
|
||||
ret = file_in->f_op->remap_file_range(file_in, pos_in,
|
||||
file_out, pos_out,
|
||||
@ -1528,6 +1533,8 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
|
||||
* consistent story about which filesystems support copy_file_range()
|
||||
* and which filesystems do not, that will allow userspace tools to
|
||||
* make consistent desicions w.r.t using copy_file_range().
|
||||
*
|
||||
* We also get here if caller (e.g. nfsd) requested COPY_FILE_SPLICE.
|
||||
*/
|
||||
ret = generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
|
||||
flags);
|
||||
@ -1582,6 +1589,10 @@ SYSCALL_DEFINE6(copy_file_range, int, fd_in, loff_t __user *, off_in,
|
||||
pos_out = f_out.file->f_pos;
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
if (flags != 0)
|
||||
goto out;
|
||||
|
||||
ret = vfs_copy_file_range(f_in.file, pos_in, f_out.file, pos_out, len,
|
||||
flags);
|
||||
if (ret > 0) {
|
||||
|
@ -40,6 +40,13 @@ static void zonefs_account_active(struct inode *inode)
|
||||
if (zi->i_ztype != ZONEFS_ZTYPE_SEQ)
|
||||
return;
|
||||
|
||||
/*
|
||||
* For zones that transitioned to the offline or readonly condition,
|
||||
* we only need to clear the active state.
|
||||
*/
|
||||
if (zi->i_flags & (ZONEFS_ZONE_OFFLINE | ZONEFS_ZONE_READONLY))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* If the zone is active, that is, if it is explicitly open or
|
||||
* partially written, check if it was already accounted as active.
|
||||
@ -53,6 +60,7 @@ static void zonefs_account_active(struct inode *inode)
|
||||
return;
|
||||
}
|
||||
|
||||
out:
|
||||
/* The zone is not active. If it was, update the active count */
|
||||
if (zi->i_flags & ZONEFS_ZONE_ACTIVE) {
|
||||
zi->i_flags &= ~ZONEFS_ZONE_ACTIVE;
|
||||
@ -324,6 +332,7 @@ static loff_t zonefs_check_zone_condition(struct inode *inode,
|
||||
inode->i_flags |= S_IMMUTABLE;
|
||||
inode->i_mode &= ~0777;
|
||||
zone->wp = zone->start;
|
||||
zi->i_flags |= ZONEFS_ZONE_OFFLINE;
|
||||
return 0;
|
||||
case BLK_ZONE_COND_READONLY:
|
||||
/*
|
||||
@ -342,8 +351,10 @@ static loff_t zonefs_check_zone_condition(struct inode *inode,
|
||||
zone->cond = BLK_ZONE_COND_OFFLINE;
|
||||
inode->i_mode &= ~0777;
|
||||
zone->wp = zone->start;
|
||||
zi->i_flags |= ZONEFS_ZONE_OFFLINE;
|
||||
return 0;
|
||||
}
|
||||
zi->i_flags |= ZONEFS_ZONE_READONLY;
|
||||
inode->i_mode &= ~0222;
|
||||
return i_size_read(inode);
|
||||
case BLK_ZONE_COND_FULL:
|
||||
@ -1922,18 +1933,18 @@ static int __init zonefs_init(void)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = register_filesystem(&zonefs_type);
|
||||
ret = zonefs_sysfs_init();
|
||||
if (ret)
|
||||
goto destroy_inodecache;
|
||||
|
||||
ret = zonefs_sysfs_init();
|
||||
ret = register_filesystem(&zonefs_type);
|
||||
if (ret)
|
||||
goto unregister_fs;
|
||||
goto sysfs_exit;
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_fs:
|
||||
unregister_filesystem(&zonefs_type);
|
||||
sysfs_exit:
|
||||
zonefs_sysfs_exit();
|
||||
destroy_inodecache:
|
||||
zonefs_destroy_inodecache();
|
||||
|
||||
@ -1942,9 +1953,9 @@ static int __init zonefs_init(void)
|
||||
|
||||
static void __exit zonefs_exit(void)
|
||||
{
|
||||
unregister_filesystem(&zonefs_type);
|
||||
zonefs_sysfs_exit();
|
||||
zonefs_destroy_inodecache();
|
||||
unregister_filesystem(&zonefs_type);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Damien Le Moal");
|
||||
|
@ -39,8 +39,10 @@ static inline enum zonefs_ztype zonefs_zone_type(struct blk_zone *zone)
|
||||
return ZONEFS_ZTYPE_SEQ;
|
||||
}
|
||||
|
||||
#define ZONEFS_ZONE_OPEN (1 << 0)
|
||||
#define ZONEFS_ZONE_ACTIVE (1 << 1)
|
||||
#define ZONEFS_ZONE_OPEN (1U << 0)
|
||||
#define ZONEFS_ZONE_ACTIVE (1U << 1)
|
||||
#define ZONEFS_ZONE_OFFLINE (1U << 2)
|
||||
#define ZONEFS_ZONE_READONLY (1U << 3)
|
||||
|
||||
/*
|
||||
* In-memory inode data.
|
||||
|
@ -20,7 +20,6 @@ struct fault_attr {
|
||||
atomic_t space;
|
||||
unsigned long verbose;
|
||||
bool task_filter;
|
||||
bool no_warn;
|
||||
unsigned long stacktrace_depth;
|
||||
unsigned long require_start;
|
||||
unsigned long require_end;
|
||||
@ -32,6 +31,10 @@ struct fault_attr {
|
||||
struct dentry *dname;
|
||||
};
|
||||
|
||||
enum fault_flags {
|
||||
FAULT_NOWARN = 1 << 0,
|
||||
};
|
||||
|
||||
#define FAULT_ATTR_INITIALIZER { \
|
||||
.interval = 1, \
|
||||
.times = ATOMIC_INIT(1), \
|
||||
@ -40,11 +43,11 @@ struct fault_attr {
|
||||
.ratelimit_state = RATELIMIT_STATE_INIT_DISABLED, \
|
||||
.verbose = 2, \
|
||||
.dname = NULL, \
|
||||
.no_warn = false, \
|
||||
}
|
||||
|
||||
#define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER
|
||||
int setup_fault_attr(struct fault_attr *attr, char *str);
|
||||
bool should_fail_ex(struct fault_attr *attr, ssize_t size, int flags);
|
||||
bool should_fail(struct fault_attr *attr, ssize_t size);
|
||||
|
||||
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
|
||||
|
@ -2089,6 +2089,14 @@ struct dir_context {
|
||||
*/
|
||||
#define REMAP_FILE_ADVISORY (REMAP_FILE_CAN_SHORTEN)
|
||||
|
||||
/*
|
||||
* These flags control the behavior of vfs_copy_file_range().
|
||||
* They are not available to the user via syscall.
|
||||
*
|
||||
* COPY_FILE_SPLICE: call splice direct instead of fs clone/copy ops
|
||||
*/
|
||||
#define COPY_FILE_SPLICE (1 << 0)
|
||||
|
||||
struct iov_iter;
|
||||
struct io_uring_cmd;
|
||||
|
||||
|
@ -776,6 +776,7 @@ struct kvm {
|
||||
struct srcu_struct srcu;
|
||||
struct srcu_struct irq_srcu;
|
||||
pid_t userspace_pid;
|
||||
bool override_halt_poll_ns;
|
||||
unsigned int max_halt_poll_ns;
|
||||
u32 dirty_ring_size;
|
||||
bool vm_bugged;
|
||||
|
@ -2,6 +2,8 @@
|
||||
#ifndef __LICENSE_H
|
||||
#define __LICENSE_H
|
||||
|
||||
#include <linux/string.h>
|
||||
|
||||
static inline int license_is_gpl_compatible(const char *license)
|
||||
{
|
||||
return (strcmp(license, "GPL") == 0
|
||||
|
@ -84,8 +84,8 @@ enum sof_ipc_dai_type {
|
||||
SOF_DAI_AMD_BT, /**< AMD ACP BT*/
|
||||
SOF_DAI_AMD_SP, /**< AMD ACP SP */
|
||||
SOF_DAI_AMD_DMIC, /**< AMD ACP DMIC */
|
||||
SOF_DAI_AMD_HS, /**< Amd HS */
|
||||
SOF_DAI_MEDIATEK_AFE, /**< Mediatek AFE */
|
||||
SOF_DAI_AMD_HS, /**< Amd HS */
|
||||
};
|
||||
|
||||
/* general purpose DAI configuration */
|
||||
|
@ -171,15 +171,15 @@ TRACE_EVENT(mm_collapse_huge_page_swapin,
|
||||
|
||||
TRACE_EVENT(mm_khugepaged_scan_file,
|
||||
|
||||
TP_PROTO(struct mm_struct *mm, struct page *page, const char *filename,
|
||||
TP_PROTO(struct mm_struct *mm, struct page *page, struct file *file,
|
||||
int present, int swap, int result),
|
||||
|
||||
TP_ARGS(mm, page, filename, present, swap, result),
|
||||
TP_ARGS(mm, page, file, present, swap, result),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(struct mm_struct *, mm)
|
||||
__field(unsigned long, pfn)
|
||||
__string(filename, filename)
|
||||
__string(filename, file->f_path.dentry->d_iname)
|
||||
__field(int, present)
|
||||
__field(int, swap)
|
||||
__field(int, result)
|
||||
@ -188,7 +188,7 @@ TRACE_EVENT(mm_khugepaged_scan_file,
|
||||
TP_fast_assign(
|
||||
__entry->mm = mm;
|
||||
__entry->pfn = page ? page_to_pfn(page) : -1;
|
||||
__assign_str(filename, filename);
|
||||
__assign_str(filename, file->f_path.dentry->d_iname);
|
||||
__entry->present = present;
|
||||
__entry->swap = swap;
|
||||
__entry->result = result;
|
||||
|
@ -87,7 +87,7 @@ config CC_HAS_ASM_GOTO_OUTPUT
|
||||
config CC_HAS_ASM_GOTO_TIED_OUTPUT
|
||||
depends on CC_HAS_ASM_GOTO_OUTPUT
|
||||
# Detect buggy gcc and clang, fixed in gcc-11 clang-14.
|
||||
def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .\n": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null)
|
||||
def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null)
|
||||
|
||||
config TOOLS_SUPPORT_RELR
|
||||
def_bool $(success,env "CC=$(CC)" "LD=$(LD)" "NM=$(NM)" "OBJCOPY=$(OBJCOPY)" $(srctree)/scripts/tools-support-relr.sh)
|
||||
|
@ -101,8 +101,6 @@ static int io_install_fixed_file(struct io_ring_ctx *ctx, struct file *file,
|
||||
err:
|
||||
if (needs_switch)
|
||||
io_rsrc_node_switch(ctx, ctx->file_data);
|
||||
if (ret)
|
||||
fput(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -238,9 +238,14 @@ static inline unsigned int io_sqring_entries(struct io_ring_ctx *ctx)
|
||||
|
||||
static inline int io_run_task_work(void)
|
||||
{
|
||||
/*
|
||||
* Always check-and-clear the task_work notification signal. With how
|
||||
* signaling works for task_work, we can find it set with nothing to
|
||||
* run. We need to clear it for that case, like get_signal() does.
|
||||
*/
|
||||
if (test_thread_flag(TIF_NOTIFY_SIGNAL))
|
||||
clear_notify_signal();
|
||||
if (task_work_pending(current)) {
|
||||
if (test_thread_flag(TIF_NOTIFY_SIGNAL))
|
||||
clear_notify_signal();
|
||||
__set_current_state(TASK_RUNNING);
|
||||
task_work_run();
|
||||
return 1;
|
||||
|
@ -40,7 +40,14 @@ struct io_poll_table {
|
||||
};
|
||||
|
||||
#define IO_POLL_CANCEL_FLAG BIT(31)
|
||||
#define IO_POLL_REF_MASK GENMASK(30, 0)
|
||||
#define IO_POLL_RETRY_FLAG BIT(30)
|
||||
#define IO_POLL_REF_MASK GENMASK(29, 0)
|
||||
|
||||
/*
|
||||
* We usually have 1-2 refs taken, 128 is more than enough and we want to
|
||||
* maximise the margin between this amount and the moment when it overflows.
|
||||
*/
|
||||
#define IO_POLL_REF_BIAS 128
|
||||
|
||||
#define IO_WQE_F_DOUBLE 1
|
||||
|
||||
@ -58,6 +65,21 @@ static inline bool wqe_is_double(struct wait_queue_entry *wqe)
|
||||
return priv & IO_WQE_F_DOUBLE;
|
||||
}
|
||||
|
||||
static bool io_poll_get_ownership_slowpath(struct io_kiocb *req)
|
||||
{
|
||||
int v;
|
||||
|
||||
/*
|
||||
* poll_refs are already elevated and we don't have much hope for
|
||||
* grabbing the ownership. Instead of incrementing set a retry flag
|
||||
* to notify the loop that there might have been some change.
|
||||
*/
|
||||
v = atomic_fetch_or(IO_POLL_RETRY_FLAG, &req->poll_refs);
|
||||
if (v & IO_POLL_REF_MASK)
|
||||
return false;
|
||||
return !(atomic_fetch_inc(&req->poll_refs) & IO_POLL_REF_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* If refs part of ->poll_refs (see IO_POLL_REF_MASK) is 0, it's free. We can
|
||||
* bump it and acquire ownership. It's disallowed to modify requests while not
|
||||
@ -66,6 +88,8 @@ static inline bool wqe_is_double(struct wait_queue_entry *wqe)
|
||||
*/
|
||||
static inline bool io_poll_get_ownership(struct io_kiocb *req)
|
||||
{
|
||||
if (unlikely(atomic_read(&req->poll_refs) >= IO_POLL_REF_BIAS))
|
||||
return io_poll_get_ownership_slowpath(req);
|
||||
return !(atomic_fetch_inc(&req->poll_refs) & IO_POLL_REF_MASK);
|
||||
}
|
||||
|
||||
@ -235,6 +259,16 @@ static int io_poll_check_events(struct io_kiocb *req, bool *locked)
|
||||
*/
|
||||
if ((v & IO_POLL_REF_MASK) != 1)
|
||||
req->cqe.res = 0;
|
||||
if (v & IO_POLL_RETRY_FLAG) {
|
||||
req->cqe.res = 0;
|
||||
/*
|
||||
* We won't find new events that came in between
|
||||
* vfs_poll and the ref put unless we clear the flag
|
||||
* in advance.
|
||||
*/
|
||||
atomic_andnot(IO_POLL_RETRY_FLAG, &req->poll_refs);
|
||||
v &= ~IO_POLL_RETRY_FLAG;
|
||||
}
|
||||
|
||||
/* the mask was stashed in __io_poll_execute */
|
||||
if (!req->cqe.res) {
|
||||
@ -274,7 +308,8 @@ static int io_poll_check_events(struct io_kiocb *req, bool *locked)
|
||||
* Release all references, retry if someone tried to restart
|
||||
* task_work while we were executing it.
|
||||
*/
|
||||
} while (atomic_sub_return(v & IO_POLL_REF_MASK, &req->poll_refs));
|
||||
} while (atomic_sub_return(v & IO_POLL_REF_MASK, &req->poll_refs) &
|
||||
IO_POLL_REF_MASK);
|
||||
|
||||
return IOU_POLL_NO_ACTION;
|
||||
}
|
||||
@ -518,7 +553,6 @@ static int __io_arm_poll_handler(struct io_kiocb *req,
|
||||
unsigned issue_flags)
|
||||
{
|
||||
struct io_ring_ctx *ctx = req->ctx;
|
||||
int v;
|
||||
|
||||
INIT_HLIST_NODE(&req->hash_node);
|
||||
req->work.cancel_seq = atomic_read(&ctx->cancel_seq);
|
||||
@ -586,11 +620,10 @@ static int __io_arm_poll_handler(struct io_kiocb *req,
|
||||
|
||||
if (ipt->owning) {
|
||||
/*
|
||||
* Release ownership. If someone tried to queue a tw while it was
|
||||
* locked, kick it off for them.
|
||||
* Try to release ownership. If we see a change of state, e.g.
|
||||
* poll was waken up, queue up a tw, it'll deal with it.
|
||||
*/
|
||||
v = atomic_dec_return(&req->poll_refs);
|
||||
if (unlikely(v & IO_POLL_REF_MASK))
|
||||
if (atomic_cmpxchg(&req->poll_refs, 1, 0) != 1)
|
||||
__io_poll_execute(req, 0);
|
||||
}
|
||||
return 0;
|
||||
|
34
ipc/shm.c
34
ipc/shm.c
@ -275,10 +275,8 @@ static inline void shm_rmid(struct shmid_kernel *s)
|
||||
}
|
||||
|
||||
|
||||
static int __shm_open(struct vm_area_struct *vma)
|
||||
static int __shm_open(struct shm_file_data *sfd)
|
||||
{
|
||||
struct file *file = vma->vm_file;
|
||||
struct shm_file_data *sfd = shm_file_data(file);
|
||||
struct shmid_kernel *shp;
|
||||
|
||||
shp = shm_lock(sfd->ns, sfd->id);
|
||||
@ -302,7 +300,15 @@ static int __shm_open(struct vm_area_struct *vma)
|
||||
/* This is called by fork, once for every shm attach. */
|
||||
static void shm_open(struct vm_area_struct *vma)
|
||||
{
|
||||
int err = __shm_open(vma);
|
||||
struct file *file = vma->vm_file;
|
||||
struct shm_file_data *sfd = shm_file_data(file);
|
||||
int err;
|
||||
|
||||
/* Always call underlying open if present */
|
||||
if (sfd->vm_ops->open)
|
||||
sfd->vm_ops->open(vma);
|
||||
|
||||
err = __shm_open(sfd);
|
||||
/*
|
||||
* We raced in the idr lookup or with shm_destroy().
|
||||
* Either way, the ID is busted.
|
||||
@ -359,10 +365,8 @@ static bool shm_may_destroy(struct shmid_kernel *shp)
|
||||
* The descriptor has already been removed from the current->mm->mmap list
|
||||
* and will later be kfree()d.
|
||||
*/
|
||||
static void shm_close(struct vm_area_struct *vma)
|
||||
static void __shm_close(struct shm_file_data *sfd)
|
||||
{
|
||||
struct file *file = vma->vm_file;
|
||||
struct shm_file_data *sfd = shm_file_data(file);
|
||||
struct shmid_kernel *shp;
|
||||
struct ipc_namespace *ns = sfd->ns;
|
||||
|
||||
@ -388,6 +392,18 @@ static void shm_close(struct vm_area_struct *vma)
|
||||
up_write(&shm_ids(ns).rwsem);
|
||||
}
|
||||
|
||||
static void shm_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct file *file = vma->vm_file;
|
||||
struct shm_file_data *sfd = shm_file_data(file);
|
||||
|
||||
/* Always call underlying close if present */
|
||||
if (sfd->vm_ops->close)
|
||||
sfd->vm_ops->close(vma);
|
||||
|
||||
__shm_close(sfd);
|
||||
}
|
||||
|
||||
/* Called with ns->shm_ids(ns).rwsem locked */
|
||||
static int shm_try_destroy_orphaned(int id, void *p, void *data)
|
||||
{
|
||||
@ -583,13 +599,13 @@ static int shm_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
* IPC ID that was removed, and possibly even reused by another shm
|
||||
* segment already. Propagate this case as an error to caller.
|
||||
*/
|
||||
ret = __shm_open(vma);
|
||||
ret = __shm_open(sfd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = call_mmap(sfd->file, vma);
|
||||
if (ret) {
|
||||
shm_close(vma);
|
||||
__shm_close(sfd);
|
||||
return ret;
|
||||
}
|
||||
sfd->vm_ops = vma->vm_ops;
|
||||
|
@ -9259,6 +9259,19 @@ int perf_event_account_interrupt(struct perf_event *event)
|
||||
return __perf_event_account_interrupt(event, 1);
|
||||
}
|
||||
|
||||
static inline bool sample_is_allowed(struct perf_event *event, struct pt_regs *regs)
|
||||
{
|
||||
/*
|
||||
* Due to interrupt latency (AKA "skid"), we may enter the
|
||||
* kernel before taking an overflow, even if the PMU is only
|
||||
* counting user events.
|
||||
*/
|
||||
if (event->attr.exclude_kernel && !user_mode(regs))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic event overflow handling, sampling.
|
||||
*/
|
||||
@ -9292,6 +9305,13 @@ static int __perf_event_overflow(struct perf_event *event,
|
||||
}
|
||||
|
||||
if (event->attr.sigtrap) {
|
||||
/*
|
||||
* The desired behaviour of sigtrap vs invalid samples is a bit
|
||||
* tricky; on the one hand, one should not loose the SIGTRAP if
|
||||
* it is the first event, on the other hand, we should also not
|
||||
* trigger the WARN or override the data address.
|
||||
*/
|
||||
bool valid_sample = sample_is_allowed(event, regs);
|
||||
unsigned int pending_id = 1;
|
||||
|
||||
if (regs)
|
||||
@ -9299,7 +9319,7 @@ static int __perf_event_overflow(struct perf_event *event,
|
||||
if (!event->pending_sigtrap) {
|
||||
event->pending_sigtrap = pending_id;
|
||||
local_inc(&event->ctx->nr_pending);
|
||||
} else if (event->attr.exclude_kernel) {
|
||||
} else if (event->attr.exclude_kernel && valid_sample) {
|
||||
/*
|
||||
* Should not be able to return to user space without
|
||||
* consuming pending_sigtrap; with exceptions:
|
||||
@ -9314,7 +9334,10 @@ static int __perf_event_overflow(struct perf_event *event,
|
||||
*/
|
||||
WARN_ON_ONCE(event->pending_sigtrap != pending_id);
|
||||
}
|
||||
event->pending_addr = data->addr;
|
||||
|
||||
event->pending_addr = 0;
|
||||
if (valid_sample && (data->sample_flags & PERF_SAMPLE_ADDR))
|
||||
event->pending_addr = data->addr;
|
||||
irq_work_queue(&event->pending_irq);
|
||||
}
|
||||
|
||||
|
@ -280,6 +280,8 @@ void gcov_info_add(struct gcov_info *dst, struct gcov_info *src)
|
||||
|
||||
for (i = 0; i < sfn_ptr->num_counters; i++)
|
||||
dfn_ptr->counters[i] += sfn_ptr->counters[i];
|
||||
|
||||
sfn_ptr = list_next_entry(sfn_ptr, head);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,9 +25,6 @@ struct sugov_policy {
|
||||
unsigned int next_freq;
|
||||
unsigned int cached_raw_freq;
|
||||
|
||||
/* max CPU capacity, which is equal for all CPUs in freq. domain */
|
||||
unsigned long max;
|
||||
|
||||
/* The next fields are only needed if fast switch cannot be used: */
|
||||
struct irq_work irq_work;
|
||||
struct kthread_work work;
|
||||
@ -51,6 +48,7 @@ struct sugov_cpu {
|
||||
|
||||
unsigned long util;
|
||||
unsigned long bw_dl;
|
||||
unsigned long max;
|
||||
|
||||
/* The field below is for single-CPU policies only: */
|
||||
#ifdef CONFIG_NO_HZ_COMMON
|
||||
@ -160,6 +158,7 @@ static void sugov_get_util(struct sugov_cpu *sg_cpu)
|
||||
{
|
||||
struct rq *rq = cpu_rq(sg_cpu->cpu);
|
||||
|
||||
sg_cpu->max = arch_scale_cpu_capacity(sg_cpu->cpu);
|
||||
sg_cpu->bw_dl = cpu_bw_dl(rq);
|
||||
sg_cpu->util = effective_cpu_util(sg_cpu->cpu, cpu_util_cfs(sg_cpu->cpu),
|
||||
FREQUENCY_UTIL, NULL);
|
||||
@ -254,7 +253,6 @@ static void sugov_iowait_boost(struct sugov_cpu *sg_cpu, u64 time,
|
||||
*/
|
||||
static void sugov_iowait_apply(struct sugov_cpu *sg_cpu, u64 time)
|
||||
{
|
||||
struct sugov_policy *sg_policy = sg_cpu->sg_policy;
|
||||
unsigned long boost;
|
||||
|
||||
/* No boost currently required */
|
||||
@ -282,8 +280,7 @@ static void sugov_iowait_apply(struct sugov_cpu *sg_cpu, u64 time)
|
||||
* sg_cpu->util is already in capacity scale; convert iowait_boost
|
||||
* into the same scale so we can compare.
|
||||
*/
|
||||
boost = sg_cpu->iowait_boost * sg_policy->max;
|
||||
boost >>= SCHED_CAPACITY_SHIFT;
|
||||
boost = (sg_cpu->iowait_boost * sg_cpu->max) >> SCHED_CAPACITY_SHIFT;
|
||||
boost = uclamp_rq_util_with(cpu_rq(sg_cpu->cpu), boost, NULL);
|
||||
if (sg_cpu->util < boost)
|
||||
sg_cpu->util = boost;
|
||||
@ -340,7 +337,7 @@ static void sugov_update_single_freq(struct update_util_data *hook, u64 time,
|
||||
if (!sugov_update_single_common(sg_cpu, time, flags))
|
||||
return;
|
||||
|
||||
next_f = get_next_freq(sg_policy, sg_cpu->util, sg_policy->max);
|
||||
next_f = get_next_freq(sg_policy, sg_cpu->util, sg_cpu->max);
|
||||
/*
|
||||
* Do not reduce the frequency if the CPU has not been idle
|
||||
* recently, as the reduction is likely to be premature then.
|
||||
@ -376,7 +373,6 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct sugov_cpu *sg_cpu = container_of(hook, struct sugov_cpu, update_util);
|
||||
struct sugov_policy *sg_policy = sg_cpu->sg_policy;
|
||||
unsigned long prev_util = sg_cpu->util;
|
||||
|
||||
/*
|
||||
@ -403,8 +399,7 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time,
|
||||
sg_cpu->util = prev_util;
|
||||
|
||||
cpufreq_driver_adjust_perf(sg_cpu->cpu, map_util_perf(sg_cpu->bw_dl),
|
||||
map_util_perf(sg_cpu->util),
|
||||
sg_policy->max);
|
||||
map_util_perf(sg_cpu->util), sg_cpu->max);
|
||||
|
||||
sg_cpu->sg_policy->last_freq_update_time = time;
|
||||
}
|
||||
@ -413,19 +408,25 @@ static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu, u64 time)
|
||||
{
|
||||
struct sugov_policy *sg_policy = sg_cpu->sg_policy;
|
||||
struct cpufreq_policy *policy = sg_policy->policy;
|
||||
unsigned long util = 0;
|
||||
unsigned long util = 0, max = 1;
|
||||
unsigned int j;
|
||||
|
||||
for_each_cpu(j, policy->cpus) {
|
||||
struct sugov_cpu *j_sg_cpu = &per_cpu(sugov_cpu, j);
|
||||
unsigned long j_util, j_max;
|
||||
|
||||
sugov_get_util(j_sg_cpu);
|
||||
sugov_iowait_apply(j_sg_cpu, time);
|
||||
j_util = j_sg_cpu->util;
|
||||
j_max = j_sg_cpu->max;
|
||||
|
||||
util = max(j_sg_cpu->util, util);
|
||||
if (j_util * max > j_max * util) {
|
||||
util = j_util;
|
||||
max = j_max;
|
||||
}
|
||||
}
|
||||
|
||||
return get_next_freq(sg_policy, util, sg_policy->max);
|
||||
return get_next_freq(sg_policy, util, max);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -751,7 +752,7 @@ static int sugov_start(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct sugov_policy *sg_policy = policy->governor_data;
|
||||
void (*uu)(struct update_util_data *data, u64 time, unsigned int flags);
|
||||
unsigned int cpu = cpumask_first(policy->cpus);
|
||||
unsigned int cpu;
|
||||
|
||||
sg_policy->freq_update_delay_ns = sg_policy->tunables->rate_limit_us * NSEC_PER_USEC;
|
||||
sg_policy->last_freq_update_time = 0;
|
||||
@ -759,7 +760,6 @@ static int sugov_start(struct cpufreq_policy *policy)
|
||||
sg_policy->work_in_progress = false;
|
||||
sg_policy->limits_changed = false;
|
||||
sg_policy->cached_raw_freq = 0;
|
||||
sg_policy->max = arch_scale_cpu_capacity(cpu);
|
||||
|
||||
sg_policy->need_freq_update = cpufreq_driver_test_flags(CPUFREQ_NEED_UPDATE_LIMITS);
|
||||
|
||||
|
@ -2107,6 +2107,7 @@ config KPROBES_SANITY_TEST
|
||||
depends on DEBUG_KERNEL
|
||||
depends on KPROBES
|
||||
depends on KUNIT
|
||||
select STACKTRACE if ARCH_CORRECT_STACKTRACE_ON_KRETPROBE
|
||||
default KUNIT_ALL_TESTS
|
||||
help
|
||||
This option provides for testing basic kprobes functionality on
|
||||
|
@ -41,9 +41,6 @@ EXPORT_SYMBOL_GPL(setup_fault_attr);
|
||||
|
||||
static void fail_dump(struct fault_attr *attr)
|
||||
{
|
||||
if (attr->no_warn)
|
||||
return;
|
||||
|
||||
if (attr->verbose > 0 && __ratelimit(&attr->ratelimit_state)) {
|
||||
printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure.\n"
|
||||
"name %pd, interval %lu, probability %lu, "
|
||||
@ -103,7 +100,7 @@ static inline bool fail_stacktrace(struct fault_attr *attr)
|
||||
* http://www.nongnu.org/failmalloc/
|
||||
*/
|
||||
|
||||
bool should_fail(struct fault_attr *attr, ssize_t size)
|
||||
bool should_fail_ex(struct fault_attr *attr, ssize_t size, int flags)
|
||||
{
|
||||
if (in_task()) {
|
||||
unsigned int fail_nth = READ_ONCE(current->fail_nth);
|
||||
@ -146,13 +143,19 @@ bool should_fail(struct fault_attr *attr, ssize_t size)
|
||||
return false;
|
||||
|
||||
fail:
|
||||
fail_dump(attr);
|
||||
if (!(flags & FAULT_NOWARN))
|
||||
fail_dump(attr);
|
||||
|
||||
if (atomic_read(&attr->times) != -1)
|
||||
atomic_dec_not_zero(&attr->times);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool should_fail(struct fault_attr *attr, ssize_t size)
|
||||
{
|
||||
return should_fail_ex(attr, size, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(should_fail);
|
||||
|
||||
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
|
||||
|
@ -17,6 +17,6 @@ $(error ARCH_REL_TYPE_ABS is not set)
|
||||
endif
|
||||
|
||||
quiet_cmd_vdso_check = VDSOCHK $@
|
||||
cmd_vdso_check = if $(OBJDUMP) -R $@ | egrep -h "$(ARCH_REL_TYPE_ABS)"; \
|
||||
cmd_vdso_check = if $(OBJDUMP) -R $@ | grep -E -h "$(ARCH_REL_TYPE_ABS)"; \
|
||||
then (echo >&2 "$@: dynamic relocations are not supported"; \
|
||||
rm -f $@; /bin/false); fi
|
||||
|
@ -2339,6 +2339,10 @@ static int damon_sysfs_upd_schemes_stats(struct damon_sysfs_kdamond *kdamond)
|
||||
damon_for_each_scheme(scheme, ctx) {
|
||||
struct damon_sysfs_stats *sysfs_stats;
|
||||
|
||||
/* user could have removed the scheme sysfs dir */
|
||||
if (schemes_idx >= sysfs_schemes->nr)
|
||||
break;
|
||||
|
||||
sysfs_stats = sysfs_schemes->schemes_arr[schemes_idx++]->stats;
|
||||
sysfs_stats->nr_tried = scheme->stat.nr_tried;
|
||||
sysfs_stats->sz_tried = scheme->stat.sz_tried;
|
||||
|
@ -16,6 +16,8 @@ static struct {
|
||||
|
||||
bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
/* No fault-injection for bootstrap cache */
|
||||
if (unlikely(s == kmem_cache))
|
||||
return false;
|
||||
@ -30,10 +32,16 @@ bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags)
|
||||
if (failslab.cache_filter && !(s->flags & SLAB_FAILSLAB))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* In some cases, it expects to specify __GFP_NOWARN
|
||||
* to avoid printing any information(not just a warning),
|
||||
* thus avoiding deadlocks. See commit 6b9dbedbe349 for
|
||||
* details.
|
||||
*/
|
||||
if (gfpflags & __GFP_NOWARN)
|
||||
failslab.attr.no_warn = true;
|
||||
flags |= FAULT_NOWARN;
|
||||
|
||||
return should_fail(&failslab.attr, s->object_size);
|
||||
return should_fail_ex(&failslab.attr, s->object_size, flags);
|
||||
}
|
||||
|
||||
static int __init setup_failslab(char *str)
|
||||
|
@ -1800,6 +1800,7 @@ static bool __prep_compound_gigantic_page(struct page *page, unsigned int order,
|
||||
|
||||
/* we rely on prep_new_huge_page to set the destructor */
|
||||
set_compound_order(page, order);
|
||||
__ClearPageReserved(page);
|
||||
__SetPageHead(page);
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
p = nth_page(page, i);
|
||||
@ -1816,7 +1817,8 @@ static bool __prep_compound_gigantic_page(struct page *page, unsigned int order,
|
||||
* on the head page when they need know if put_page() is needed
|
||||
* after get_user_pages().
|
||||
*/
|
||||
__ClearPageReserved(p);
|
||||
if (i != 0) /* head page cleared above */
|
||||
__ClearPageReserved(p);
|
||||
/*
|
||||
* Subtle and very unlikely
|
||||
*
|
||||
|
@ -75,18 +75,23 @@ static int get_stack_skipnr(const unsigned long stack_entries[], int num_entries
|
||||
|
||||
if (str_has_prefix(buf, ARCH_FUNC_PREFIX "kfence_") ||
|
||||
str_has_prefix(buf, ARCH_FUNC_PREFIX "__kfence_") ||
|
||||
str_has_prefix(buf, ARCH_FUNC_PREFIX "__kmem_cache_free") ||
|
||||
!strncmp(buf, ARCH_FUNC_PREFIX "__slab_free", len)) {
|
||||
/*
|
||||
* In case of tail calls from any of the below
|
||||
* to any of the above.
|
||||
* In case of tail calls from any of the below to any of
|
||||
* the above, optimized by the compiler such that the
|
||||
* stack trace would omit the initial entry point below.
|
||||
*/
|
||||
fallback = skipnr + 1;
|
||||
}
|
||||
|
||||
/* Also the *_bulk() variants by only checking prefixes. */
|
||||
/*
|
||||
* The below list should only include the initial entry points
|
||||
* into the slab allocators. Includes the *_bulk() variants by
|
||||
* checking prefixes.
|
||||
*/
|
||||
if (str_has_prefix(buf, ARCH_FUNC_PREFIX "kfree") ||
|
||||
str_has_prefix(buf, ARCH_FUNC_PREFIX "kmem_cache_free") ||
|
||||
str_has_prefix(buf, ARCH_FUNC_PREFIX "__kmem_cache_free") ||
|
||||
str_has_prefix(buf, ARCH_FUNC_PREFIX "__kmalloc") ||
|
||||
str_has_prefix(buf, ARCH_FUNC_PREFIX "kmem_cache_alloc"))
|
||||
goto found;
|
||||
|
@ -97,8 +97,8 @@ struct collapse_control {
|
||||
/* Num pages scanned per node */
|
||||
u32 node_load[MAX_NUMNODES];
|
||||
|
||||
/* Last target selected in hpage_collapse_find_target_node() */
|
||||
int last_target_node;
|
||||
/* nodemask for allocation fallback */
|
||||
nodemask_t alloc_nmask;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -734,7 +734,6 @@ static void khugepaged_alloc_sleep(void)
|
||||
|
||||
struct collapse_control khugepaged_collapse_control = {
|
||||
.is_khugepaged = true,
|
||||
.last_target_node = NUMA_NO_NODE,
|
||||
};
|
||||
|
||||
static bool hpage_collapse_scan_abort(int nid, struct collapse_control *cc)
|
||||
@ -783,16 +782,11 @@ static int hpage_collapse_find_target_node(struct collapse_control *cc)
|
||||
target_node = nid;
|
||||
}
|
||||
|
||||
/* do some balance if several nodes have the same hit record */
|
||||
if (target_node <= cc->last_target_node)
|
||||
for (nid = cc->last_target_node + 1; nid < MAX_NUMNODES;
|
||||
nid++)
|
||||
if (max_value == cc->node_load[nid]) {
|
||||
target_node = nid;
|
||||
break;
|
||||
}
|
||||
for_each_online_node(nid) {
|
||||
if (max_value == cc->node_load[nid])
|
||||
node_set(nid, cc->alloc_nmask);
|
||||
}
|
||||
|
||||
cc->last_target_node = target_node;
|
||||
return target_node;
|
||||
}
|
||||
#else
|
||||
@ -802,9 +796,10 @@ static int hpage_collapse_find_target_node(struct collapse_control *cc)
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool hpage_collapse_alloc_page(struct page **hpage, gfp_t gfp, int node)
|
||||
static bool hpage_collapse_alloc_page(struct page **hpage, gfp_t gfp, int node,
|
||||
nodemask_t *nmask)
|
||||
{
|
||||
*hpage = __alloc_pages_node(node, gfp, HPAGE_PMD_ORDER);
|
||||
*hpage = __alloc_pages(gfp, HPAGE_PMD_ORDER, node, nmask);
|
||||
if (unlikely(!*hpage)) {
|
||||
count_vm_event(THP_COLLAPSE_ALLOC_FAILED);
|
||||
return false;
|
||||
@ -955,12 +950,11 @@ static int __collapse_huge_page_swapin(struct mm_struct *mm,
|
||||
static int alloc_charge_hpage(struct page **hpage, struct mm_struct *mm,
|
||||
struct collapse_control *cc)
|
||||
{
|
||||
/* Only allocate from the target node */
|
||||
gfp_t gfp = (cc->is_khugepaged ? alloc_hugepage_khugepaged_gfpmask() :
|
||||
GFP_TRANSHUGE) | __GFP_THISNODE;
|
||||
GFP_TRANSHUGE);
|
||||
int node = hpage_collapse_find_target_node(cc);
|
||||
|
||||
if (!hpage_collapse_alloc_page(hpage, gfp, node))
|
||||
if (!hpage_collapse_alloc_page(hpage, gfp, node, &cc->alloc_nmask))
|
||||
return SCAN_ALLOC_HUGE_PAGE_FAIL;
|
||||
if (unlikely(mem_cgroup_charge(page_folio(*hpage), mm, gfp)))
|
||||
return SCAN_CGROUP_CHARGE_FAIL;
|
||||
@ -1144,6 +1138,7 @@ static int hpage_collapse_scan_pmd(struct mm_struct *mm,
|
||||
goto out;
|
||||
|
||||
memset(cc->node_load, 0, sizeof(cc->node_load));
|
||||
nodes_clear(cc->alloc_nmask);
|
||||
pte = pte_offset_map_lock(mm, pmd, address, &ptl);
|
||||
for (_address = address, _pte = pte; _pte < pte + HPAGE_PMD_NR;
|
||||
_pte++, _address += PAGE_SIZE) {
|
||||
@ -2077,6 +2072,7 @@ static int hpage_collapse_scan_file(struct mm_struct *mm, unsigned long addr,
|
||||
present = 0;
|
||||
swap = 0;
|
||||
memset(cc->node_load, 0, sizeof(cc->node_load));
|
||||
nodes_clear(cc->alloc_nmask);
|
||||
rcu_read_lock();
|
||||
xas_for_each(&xas, page, start + HPAGE_PMD_NR - 1) {
|
||||
if (xas_retry(&xas, page))
|
||||
@ -2157,8 +2153,7 @@ static int hpage_collapse_scan_file(struct mm_struct *mm, unsigned long addr,
|
||||
}
|
||||
}
|
||||
|
||||
trace_mm_khugepaged_scan_file(mm, page, file->f_path.dentry->d_iname,
|
||||
present, swap, result);
|
||||
trace_mm_khugepaged_scan_file(mm, page, file, present, swap, result);
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
@ -2576,7 +2571,6 @@ int madvise_collapse(struct vm_area_struct *vma, struct vm_area_struct **prev,
|
||||
if (!cc)
|
||||
return -ENOMEM;
|
||||
cc->is_khugepaged = false;
|
||||
cc->last_target_node = NUMA_NO_NODE;
|
||||
|
||||
mmgrab(mm);
|
||||
lru_add_drain_all();
|
||||
@ -2602,6 +2596,7 @@ int madvise_collapse(struct vm_area_struct *vma, struct vm_area_struct **prev,
|
||||
}
|
||||
mmap_assert_locked(mm);
|
||||
memset(cc->node_load, 0, sizeof(cc->node_load));
|
||||
nodes_clear(cc->alloc_nmask);
|
||||
if (IS_ENABLED(CONFIG_SHMEM) && vma->vm_file) {
|
||||
struct file *file = get_file(vma->vm_file);
|
||||
pgoff_t pgoff = linear_page_index(vma, addr);
|
||||
|
@ -3026,7 +3026,7 @@ struct obj_cgroup *get_obj_cgroup_from_page(struct page *page)
|
||||
{
|
||||
struct obj_cgroup *objcg;
|
||||
|
||||
if (!memcg_kmem_enabled() || memcg_kmem_bypass())
|
||||
if (!memcg_kmem_enabled())
|
||||
return NULL;
|
||||
|
||||
if (PageMemcgKmem(page)) {
|
||||
|
@ -3764,7 +3764,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
|
||||
*/
|
||||
get_page(vmf->page);
|
||||
pte_unmap_unlock(vmf->pte, vmf->ptl);
|
||||
vmf->page->pgmap->ops->migrate_to_ram(vmf);
|
||||
ret = vmf->page->pgmap->ops->migrate_to_ram(vmf);
|
||||
put_page(vmf->page);
|
||||
} else if (is_hwpoison_entry(entry)) {
|
||||
ret = VM_FAULT_HWPOISON;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user