Merge tag 'v5.16-rc4' into android-mainline
Linux 5.16-rc4 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I2b4d55977a326a410a9d5ede92f66dc6c6a9e4d3
This commit is contained in:
@@ -16509,6 +16509,12 @@ T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml
|
||||
F: drivers/media/platform/sunxi/sun8i-rotate/
|
||||
|
||||
RPMSG TTY DRIVER
|
||||
M: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
|
||||
L: linux-remoteproc@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/tty/rpmsg_tty.c
|
||||
|
||||
RTL2830 MEDIA DRIVER
|
||||
M: Antti Palosaari <crope@iki.fi>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
VERSION = 5
|
||||
PATCHLEVEL = 16
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc3
|
||||
EXTRAVERSION = -rc4
|
||||
NAME = Gobble Gobble
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
||||
@@ -15,7 +15,12 @@
|
||||
# Mike Shaver, Helge Deller and Martin K. Petersen
|
||||
#
|
||||
|
||||
ifdef CONFIG_PARISC_SELF_EXTRACT
|
||||
boot := arch/parisc/boot
|
||||
KBUILD_IMAGE := $(boot)/bzImage
|
||||
else
|
||||
KBUILD_IMAGE := vmlinuz
|
||||
endif
|
||||
|
||||
NM = sh $(srctree)/arch/parisc/nm
|
||||
CHECKFLAGS += -D__hppa__=1
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
CONFIG_LOCALVERSION="-64bit"
|
||||
# CONFIG_LOCALVERSION_AUTO is not set
|
||||
CONFIG_KERNEL_LZ4=y
|
||||
CONFIG_SYSVIPC=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_AUDIT=y
|
||||
CONFIG_BSD_PROCESS_ACCT=y
|
||||
CONFIG_BSD_PROCESS_ACCT_V3=y
|
||||
CONFIG_TASKSTATS=y
|
||||
@@ -35,6 +37,7 @@ CONFIG_MODVERSIONS=y
|
||||
CONFIG_BLK_DEV_INTEGRITY=y
|
||||
CONFIG_BINFMT_MISC=m
|
||||
# CONFIG_COMPACTION is not set
|
||||
CONFIG_MEMORY_FAILURE=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
@@ -65,12 +68,15 @@ CONFIG_SCSI_ISCSI_ATTRS=y
|
||||
CONFIG_SCSI_SRP_ATTRS=y
|
||||
CONFIG_ISCSI_BOOT_SYSFS=y
|
||||
CONFIG_SCSI_MPT2SAS=y
|
||||
CONFIG_SCSI_LASI700=m
|
||||
CONFIG_SCSI_LASI700=y
|
||||
CONFIG_SCSI_SYM53C8XX_2=y
|
||||
CONFIG_SCSI_ZALON=y
|
||||
CONFIG_SCSI_QLA_ISCSI=m
|
||||
CONFIG_SCSI_DH=y
|
||||
CONFIG_ATA=y
|
||||
CONFIG_SATA_SIL=y
|
||||
CONFIG_SATA_SIS=y
|
||||
CONFIG_SATA_VIA=y
|
||||
CONFIG_PATA_NS87415=y
|
||||
CONFIG_PATA_SIL680=y
|
||||
CONFIG_ATA_GENERIC=y
|
||||
@@ -79,6 +85,7 @@ CONFIG_MD_LINEAR=m
|
||||
CONFIG_BLK_DEV_DM=m
|
||||
CONFIG_DM_RAID=m
|
||||
CONFIG_DM_UEVENT=y
|
||||
CONFIG_DM_AUDIT=y
|
||||
CONFIG_FUSION=y
|
||||
CONFIG_FUSION_SPI=y
|
||||
CONFIG_FUSION_SAS=y
|
||||
@@ -196,10 +203,15 @@ CONFIG_FB_MATROX_G=y
|
||||
CONFIG_FB_MATROX_I2C=y
|
||||
CONFIG_FB_MATROX_MAVEN=y
|
||||
CONFIG_FB_RADEON=y
|
||||
CONFIG_LOGO=y
|
||||
# CONFIG_LOGO_LINUX_CLUT224 is not set
|
||||
CONFIG_HIDRAW=y
|
||||
CONFIG_HID_PID=y
|
||||
CONFIG_USB_HIDDEV=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_EHCI_HCD=y
|
||||
CONFIG_USB_OHCI_HCD=y
|
||||
CONFIG_USB_OHCI_HCD_PLATFORM=y
|
||||
CONFIG_UIO=y
|
||||
CONFIG_UIO_PDRV_GENIRQ=m
|
||||
CONFIG_UIO_AEC=m
|
||||
|
||||
@@ -39,6 +39,7 @@ verify "$3"
|
||||
if [ -n "${INSTALLKERNEL}" ]; then
|
||||
if [ -x ~/bin/${INSTALLKERNEL} ]; then exec ~/bin/${INSTALLKERNEL} "$@"; fi
|
||||
if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi
|
||||
if [ -x /usr/sbin/${INSTALLKERNEL} ]; then exec /usr/sbin/${INSTALLKERNEL} "$@"; fi
|
||||
fi
|
||||
|
||||
# Default install
|
||||
|
||||
@@ -249,30 +249,16 @@ void __init time_init(void)
|
||||
static int __init init_cr16_clocksource(void)
|
||||
{
|
||||
/*
|
||||
* The cr16 interval timers are not syncronized across CPUs on
|
||||
* different sockets, so mark them unstable and lower rating on
|
||||
* multi-socket SMP systems.
|
||||
* The cr16 interval timers are not syncronized across CPUs, even if
|
||||
* they share the same socket.
|
||||
*/
|
||||
if (num_online_cpus() > 1 && !running_on_qemu) {
|
||||
int cpu;
|
||||
unsigned long cpu0_loc;
|
||||
cpu0_loc = per_cpu(cpu_data, 0).cpu_loc;
|
||||
/* mark sched_clock unstable */
|
||||
clear_sched_clock_stable();
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
if (cpu == 0)
|
||||
continue;
|
||||
if ((cpu0_loc != 0) &&
|
||||
(cpu0_loc == per_cpu(cpu_data, cpu).cpu_loc))
|
||||
continue;
|
||||
|
||||
/* mark sched_clock unstable */
|
||||
clear_sched_clock_stable();
|
||||
|
||||
clocksource_cr16.name = "cr16_unstable";
|
||||
clocksource_cr16.flags = CLOCK_SOURCE_UNSTABLE;
|
||||
clocksource_cr16.rating = 0;
|
||||
break;
|
||||
}
|
||||
clocksource_cr16.name = "cr16_unstable";
|
||||
clocksource_cr16.flags = CLOCK_SOURCE_UNSTABLE;
|
||||
clocksource_cr16.rating = 0;
|
||||
}
|
||||
|
||||
/* register at clocksource framework */
|
||||
|
||||
+18
-19
@@ -574,6 +574,10 @@ SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
|
||||
ud2
|
||||
1:
|
||||
#endif
|
||||
#ifdef CONFIG_XEN_PV
|
||||
ALTERNATIVE "", "jmp xenpv_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV
|
||||
#endif
|
||||
|
||||
POP_REGS pop_rdi=0
|
||||
|
||||
/*
|
||||
@@ -890,6 +894,7 @@ SYM_CODE_START_LOCAL(paranoid_entry)
|
||||
.Lparanoid_entry_checkgs:
|
||||
/* EBX = 1 -> kernel GSBASE active, no restore required */
|
||||
movl $1, %ebx
|
||||
|
||||
/*
|
||||
* The kernel-enforced convention is a negative GSBASE indicates
|
||||
* a kernel value. No SWAPGS needed on entry and exit.
|
||||
@@ -897,21 +902,14 @@ SYM_CODE_START_LOCAL(paranoid_entry)
|
||||
movl $MSR_GS_BASE, %ecx
|
||||
rdmsr
|
||||
testl %edx, %edx
|
||||
jns .Lparanoid_entry_swapgs
|
||||
ret
|
||||
|
||||
.Lparanoid_entry_swapgs:
|
||||
swapgs
|
||||
|
||||
/*
|
||||
* The above SAVE_AND_SWITCH_TO_KERNEL_CR3 macro doesn't do an
|
||||
* unconditional CR3 write, even in the PTI case. So do an lfence
|
||||
* to prevent GS speculation, regardless of whether PTI is enabled.
|
||||
*/
|
||||
FENCE_SWAPGS_KERNEL_ENTRY
|
||||
js .Lparanoid_kernel_gsbase
|
||||
|
||||
/* EBX = 0 -> SWAPGS required on exit */
|
||||
xorl %ebx, %ebx
|
||||
swapgs
|
||||
.Lparanoid_kernel_gsbase:
|
||||
|
||||
FENCE_SWAPGS_KERNEL_ENTRY
|
||||
ret
|
||||
SYM_CODE_END(paranoid_entry)
|
||||
|
||||
@@ -993,11 +991,6 @@ SYM_CODE_START_LOCAL(error_entry)
|
||||
pushq %r12
|
||||
ret
|
||||
|
||||
.Lerror_entry_done_lfence:
|
||||
FENCE_SWAPGS_KERNEL_ENTRY
|
||||
.Lerror_entry_done:
|
||||
ret
|
||||
|
||||
/*
|
||||
* There are two places in the kernel that can potentially fault with
|
||||
* usergs. Handle them here. B stepping K8s sometimes report a
|
||||
@@ -1020,8 +1013,14 @@ SYM_CODE_START_LOCAL(error_entry)
|
||||
* .Lgs_change's error handler with kernel gsbase.
|
||||
*/
|
||||
SWAPGS
|
||||
FENCE_SWAPGS_USER_ENTRY
|
||||
jmp .Lerror_entry_done
|
||||
|
||||
/*
|
||||
* Issue an LFENCE to prevent GS speculation, regardless of whether it is a
|
||||
* kernel or user gsbase.
|
||||
*/
|
||||
.Lerror_entry_done_lfence:
|
||||
FENCE_SWAPGS_KERNEL_ENTRY
|
||||
ret
|
||||
|
||||
.Lbstep_iret:
|
||||
/* Fix truncated RIP */
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
#define INTEL_FAM6_ALDERLAKE 0x97 /* Golden Cove / Gracemont */
|
||||
#define INTEL_FAM6_ALDERLAKE_L 0x9A /* Golden Cove / Gracemont */
|
||||
|
||||
#define INTEL_FAM6_RAPTOR_LAKE 0xB7
|
||||
#define INTEL_FAM6_RAPTORLAKE 0xB7
|
||||
|
||||
/* "Small Core" Processors (Atom) */
|
||||
|
||||
|
||||
@@ -1036,6 +1036,7 @@ struct kvm_x86_msr_filter {
|
||||
#define APICV_INHIBIT_REASON_PIT_REINJ 4
|
||||
#define APICV_INHIBIT_REASON_X2APIC 5
|
||||
#define APICV_INHIBIT_REASON_BLOCKIRQ 6
|
||||
#define APICV_INHIBIT_REASON_ABSENT 7
|
||||
|
||||
struct kvm_arch {
|
||||
unsigned long n_used_mmu_pages;
|
||||
|
||||
@@ -73,4 +73,15 @@
|
||||
|
||||
#define GHCB_RESP_CODE(v) ((v) & GHCB_MSR_INFO_MASK)
|
||||
|
||||
/*
|
||||
* Error codes related to GHCB input that can be communicated back to the guest
|
||||
* by setting the lower 32-bits of the GHCB SW_EXITINFO1 field to 2.
|
||||
*/
|
||||
#define GHCB_ERR_NOT_REGISTERED 1
|
||||
#define GHCB_ERR_INVALID_USAGE 2
|
||||
#define GHCB_ERR_INVALID_SCRATCH_AREA 3
|
||||
#define GHCB_ERR_MISSING_INPUT 4
|
||||
#define GHCB_ERR_INVALID_INPUT 5
|
||||
#define GHCB_ERR_INVALID_EVENT 6
|
||||
|
||||
#endif
|
||||
|
||||
@@ -118,7 +118,7 @@ static inline bool save_xstate_epilog(void __user *buf, int ia32_frame,
|
||||
struct fpstate *fpstate)
|
||||
{
|
||||
struct xregs_state __user *x = buf;
|
||||
struct _fpx_sw_bytes sw_bytes;
|
||||
struct _fpx_sw_bytes sw_bytes = {};
|
||||
u32 xfeatures;
|
||||
int err;
|
||||
|
||||
|
||||
+39
-18
@@ -294,11 +294,6 @@ static enum es_result vc_write_mem(struct es_em_ctxt *ctxt,
|
||||
char *dst, char *buf, size_t size)
|
||||
{
|
||||
unsigned long error_code = X86_PF_PROT | X86_PF_WRITE;
|
||||
char __user *target = (char __user *)dst;
|
||||
u64 d8;
|
||||
u32 d4;
|
||||
u16 d2;
|
||||
u8 d1;
|
||||
|
||||
/*
|
||||
* This function uses __put_user() independent of whether kernel or user
|
||||
@@ -320,26 +315,42 @@ static enum es_result vc_write_mem(struct es_em_ctxt *ctxt,
|
||||
* instructions here would cause infinite nesting.
|
||||
*/
|
||||
switch (size) {
|
||||
case 1:
|
||||
case 1: {
|
||||
u8 d1;
|
||||
u8 __user *target = (u8 __user *)dst;
|
||||
|
||||
memcpy(&d1, buf, 1);
|
||||
if (__put_user(d1, target))
|
||||
goto fault;
|
||||
break;
|
||||
case 2:
|
||||
}
|
||||
case 2: {
|
||||
u16 d2;
|
||||
u16 __user *target = (u16 __user *)dst;
|
||||
|
||||
memcpy(&d2, buf, 2);
|
||||
if (__put_user(d2, target))
|
||||
goto fault;
|
||||
break;
|
||||
case 4:
|
||||
}
|
||||
case 4: {
|
||||
u32 d4;
|
||||
u32 __user *target = (u32 __user *)dst;
|
||||
|
||||
memcpy(&d4, buf, 4);
|
||||
if (__put_user(d4, target))
|
||||
goto fault;
|
||||
break;
|
||||
case 8:
|
||||
}
|
||||
case 8: {
|
||||
u64 d8;
|
||||
u64 __user *target = (u64 __user *)dst;
|
||||
|
||||
memcpy(&d8, buf, 8);
|
||||
if (__put_user(d8, target))
|
||||
goto fault;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size);
|
||||
return ES_UNSUPPORTED;
|
||||
@@ -362,11 +373,6 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
|
||||
char *src, char *buf, size_t size)
|
||||
{
|
||||
unsigned long error_code = X86_PF_PROT;
|
||||
char __user *s = (char __user *)src;
|
||||
u64 d8;
|
||||
u32 d4;
|
||||
u16 d2;
|
||||
u8 d1;
|
||||
|
||||
/*
|
||||
* This function uses __get_user() independent of whether kernel or user
|
||||
@@ -388,26 +394,41 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
|
||||
* instructions here would cause infinite nesting.
|
||||
*/
|
||||
switch (size) {
|
||||
case 1:
|
||||
case 1: {
|
||||
u8 d1;
|
||||
u8 __user *s = (u8 __user *)src;
|
||||
|
||||
if (__get_user(d1, s))
|
||||
goto fault;
|
||||
memcpy(buf, &d1, 1);
|
||||
break;
|
||||
case 2:
|
||||
}
|
||||
case 2: {
|
||||
u16 d2;
|
||||
u16 __user *s = (u16 __user *)src;
|
||||
|
||||
if (__get_user(d2, s))
|
||||
goto fault;
|
||||
memcpy(buf, &d2, 2);
|
||||
break;
|
||||
case 4:
|
||||
}
|
||||
case 4: {
|
||||
u32 d4;
|
||||
u32 __user *s = (u32 __user *)src;
|
||||
|
||||
if (__get_user(d4, s))
|
||||
goto fault;
|
||||
memcpy(buf, &d4, 4);
|
||||
break;
|
||||
case 8:
|
||||
}
|
||||
case 8: {
|
||||
u64 d8;
|
||||
u64 __user *s = (u64 __user *)src;
|
||||
if (__get_user(d8, s))
|
||||
goto fault;
|
||||
memcpy(buf, &d8, 8);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size);
|
||||
return ES_UNSUPPORTED;
|
||||
|
||||
+24
-4
@@ -1180,6 +1180,12 @@ void mark_tsc_unstable(char *reason)
|
||||
|
||||
EXPORT_SYMBOL_GPL(mark_tsc_unstable);
|
||||
|
||||
static void __init tsc_disable_clocksource_watchdog(void)
|
||||
{
|
||||
clocksource_tsc_early.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
|
||||
clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
|
||||
}
|
||||
|
||||
static void __init check_system_tsc_reliable(void)
|
||||
{
|
||||
#if defined(CONFIG_MGEODEGX1) || defined(CONFIG_MGEODE_LX) || defined(CONFIG_X86_GENERIC)
|
||||
@@ -1196,6 +1202,23 @@ static void __init check_system_tsc_reliable(void)
|
||||
#endif
|
||||
if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE))
|
||||
tsc_clocksource_reliable = 1;
|
||||
|
||||
/*
|
||||
* Disable the clocksource watchdog when the system has:
|
||||
* - TSC running at constant frequency
|
||||
* - TSC which does not stop in C-States
|
||||
* - the TSC_ADJUST register which allows to detect even minimal
|
||||
* modifications
|
||||
* - not more than two sockets. As the number of sockets cannot be
|
||||
* evaluated at the early boot stage where this has to be
|
||||
* invoked, check the number of online memory nodes as a
|
||||
* fallback solution which is an reasonable estimate.
|
||||
*/
|
||||
if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) &&
|
||||
boot_cpu_has(X86_FEATURE_NONSTOP_TSC) &&
|
||||
boot_cpu_has(X86_FEATURE_TSC_ADJUST) &&
|
||||
nr_online_nodes <= 2)
|
||||
tsc_disable_clocksource_watchdog();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1387,9 +1410,6 @@ static int __init init_tsc_clocksource(void)
|
||||
if (tsc_unstable)
|
||||
goto unreg;
|
||||
|
||||
if (tsc_clocksource_reliable || no_tsc_watchdog)
|
||||
clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC_S3))
|
||||
clocksource_tsc.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP;
|
||||
|
||||
@@ -1527,7 +1547,7 @@ void __init tsc_init(void)
|
||||
}
|
||||
|
||||
if (tsc_clocksource_reliable || no_tsc_watchdog)
|
||||
clocksource_tsc_early.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
|
||||
tsc_disable_clocksource_watchdog();
|
||||
|
||||
clocksource_register_khz(&clocksource_tsc_early, tsc_khz);
|
||||
detect_art();
|
||||
|
||||
@@ -30,6 +30,7 @@ struct tsc_adjust {
|
||||
};
|
||||
|
||||
static DEFINE_PER_CPU(struct tsc_adjust, tsc_adjust);
|
||||
static struct timer_list tsc_sync_check_timer;
|
||||
|
||||
/*
|
||||
* TSC's on different sockets may be reset asynchronously.
|
||||
@@ -77,6 +78,46 @@ void tsc_verify_tsc_adjust(bool resume)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Normally the tsc_sync will be checked every time system enters idle
|
||||
* state, but there is still caveat that a system won't enter idle,
|
||||
* either because it's too busy or configured purposely to not enter
|
||||
* idle.
|
||||
*
|
||||
* So setup a periodic timer (every 10 minutes) to make sure the check
|
||||
* is always on.
|
||||
*/
|
||||
|
||||
#define SYNC_CHECK_INTERVAL (HZ * 600)
|
||||
|
||||
static void tsc_sync_check_timer_fn(struct timer_list *unused)
|
||||
{
|
||||
int next_cpu;
|
||||
|
||||
tsc_verify_tsc_adjust(false);
|
||||
|
||||
/* Run the check for all onlined CPUs in turn */
|
||||
next_cpu = cpumask_next(raw_smp_processor_id(), cpu_online_mask);
|
||||
if (next_cpu >= nr_cpu_ids)
|
||||
next_cpu = cpumask_first(cpu_online_mask);
|
||||
|
||||
tsc_sync_check_timer.expires += SYNC_CHECK_INTERVAL;
|
||||
add_timer_on(&tsc_sync_check_timer, next_cpu);
|
||||
}
|
||||
|
||||
static int __init start_sync_check_timer(void)
|
||||
{
|
||||
if (!cpu_feature_enabled(X86_FEATURE_TSC_ADJUST) || tsc_clocksource_reliable)
|
||||
return 0;
|
||||
|
||||
timer_setup(&tsc_sync_check_timer, tsc_sync_check_timer_fn, 0);
|
||||
tsc_sync_check_timer.expires = jiffies + SYNC_CHECK_INTERVAL;
|
||||
add_timer(&tsc_sync_check_timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
late_initcall(start_sync_check_timer);
|
||||
|
||||
static void tsc_sanitize_first_cpu(struct tsc_adjust *cur, s64 bootval,
|
||||
unsigned int cpu, bool bootcpu)
|
||||
{
|
||||
|
||||
+21
-2
@@ -1936,7 +1936,11 @@ static void mmu_audit_disable(void) { }
|
||||
|
||||
static bool is_obsolete_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
|
||||
{
|
||||
return sp->role.invalid ||
|
||||
if (sp->role.invalid)
|
||||
return true;
|
||||
|
||||
/* TDP MMU pages due not use the MMU generation. */
|
||||
return !sp->tdp_mmu_page &&
|
||||
unlikely(sp->mmu_valid_gen != kvm->arch.mmu_valid_gen);
|
||||
}
|
||||
|
||||
@@ -3976,6 +3980,20 @@ out_retry:
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the page fault is stale and needs to be retried, i.e. if the
|
||||
* root was invalidated by a memslot update or a relevant mmu_notifier fired.
|
||||
*/
|
||||
static bool is_page_fault_stale(struct kvm_vcpu *vcpu,
|
||||
struct kvm_page_fault *fault, int mmu_seq)
|
||||
{
|
||||
if (is_obsolete_sp(vcpu->kvm, to_shadow_page(vcpu->arch.mmu->root_hpa)))
|
||||
return true;
|
||||
|
||||
return fault->slot &&
|
||||
mmu_notifier_retry_hva(vcpu->kvm, mmu_seq, fault->hva);
|
||||
}
|
||||
|
||||
static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
|
||||
{
|
||||
bool is_tdp_mmu_fault = is_tdp_mmu(vcpu->arch.mmu);
|
||||
@@ -4013,8 +4031,9 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
|
||||
else
|
||||
write_lock(&vcpu->kvm->mmu_lock);
|
||||
|
||||
if (fault->slot && mmu_notifier_retry_hva(vcpu->kvm, mmu_seq, fault->hva))
|
||||
if (is_page_fault_stale(vcpu, fault, mmu_seq))
|
||||
goto out_unlock;
|
||||
|
||||
r = make_mmu_pages_available(vcpu);
|
||||
if (r)
|
||||
goto out_unlock;
|
||||
|
||||
@@ -911,7 +911,8 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
|
||||
|
||||
r = RET_PF_RETRY;
|
||||
write_lock(&vcpu->kvm->mmu_lock);
|
||||
if (fault->slot && mmu_notifier_retry_hva(vcpu->kvm, mmu_seq, fault->hva))
|
||||
|
||||
if (is_page_fault_stale(vcpu, fault, mmu_seq))
|
||||
goto out_unlock;
|
||||
|
||||
kvm_mmu_audit(vcpu, AUDIT_PRE_PAGE_FAULT);
|
||||
|
||||
@@ -900,6 +900,7 @@ out:
|
||||
bool svm_check_apicv_inhibit_reasons(ulong bit)
|
||||
{
|
||||
ulong supported = BIT(APICV_INHIBIT_REASON_DISABLE) |
|
||||
BIT(APICV_INHIBIT_REASON_ABSENT) |
|
||||
BIT(APICV_INHIBIT_REASON_HYPERV) |
|
||||
BIT(APICV_INHIBIT_REASON_NESTED) |
|
||||
BIT(APICV_INHIBIT_REASON_IRQWIN) |
|
||||
|
||||
@@ -281,7 +281,7 @@ static void amd_pmu_refresh(struct kvm_vcpu *vcpu)
|
||||
pmu->nr_arch_gp_counters = AMD64_NUM_COUNTERS;
|
||||
|
||||
pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << 48) - 1;
|
||||
pmu->reserved_bits = 0xffffffff00200000ull;
|
||||
pmu->reserved_bits = 0xfffffff000280000ull;
|
||||
pmu->version = 1;
|
||||
/* not applicable to AMD; but clean them to prevent any fall out */
|
||||
pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
|
||||
|
||||
+60
-42
@@ -2260,7 +2260,7 @@ void sev_free_vcpu(struct kvm_vcpu *vcpu)
|
||||
__free_page(virt_to_page(svm->sev_es.vmsa));
|
||||
|
||||
if (svm->sev_es.ghcb_sa_free)
|
||||
kfree(svm->sev_es.ghcb_sa);
|
||||
kvfree(svm->sev_es.ghcb_sa);
|
||||
}
|
||||
|
||||
static void dump_ghcb(struct vcpu_svm *svm)
|
||||
@@ -2352,24 +2352,29 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm)
|
||||
memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap));
|
||||
}
|
||||
|
||||
static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
|
||||
static bool sev_es_validate_vmgexit(struct vcpu_svm *svm)
|
||||
{
|
||||
struct kvm_vcpu *vcpu;
|
||||
struct ghcb *ghcb;
|
||||
u64 exit_code = 0;
|
||||
u64 exit_code;
|
||||
u64 reason;
|
||||
|
||||
ghcb = svm->sev_es.ghcb;
|
||||
|
||||
/* Only GHCB Usage code 0 is supported */
|
||||
if (ghcb->ghcb_usage)
|
||||
goto vmgexit_err;
|
||||
|
||||
/*
|
||||
* Retrieve the exit code now even though is may not be marked valid
|
||||
* Retrieve the exit code now even though it may not be marked valid
|
||||
* as it could help with debugging.
|
||||
*/
|
||||
exit_code = ghcb_get_sw_exit_code(ghcb);
|
||||
|
||||
/* Only GHCB Usage code 0 is supported */
|
||||
if (ghcb->ghcb_usage) {
|
||||
reason = GHCB_ERR_INVALID_USAGE;
|
||||
goto vmgexit_err;
|
||||
}
|
||||
|
||||
reason = GHCB_ERR_MISSING_INPUT;
|
||||
|
||||
if (!ghcb_sw_exit_code_is_valid(ghcb) ||
|
||||
!ghcb_sw_exit_info_1_is_valid(ghcb) ||
|
||||
!ghcb_sw_exit_info_2_is_valid(ghcb))
|
||||
@@ -2448,30 +2453,34 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
|
||||
case SVM_VMGEXIT_UNSUPPORTED_EVENT:
|
||||
break;
|
||||
default:
|
||||
reason = GHCB_ERR_INVALID_EVENT;
|
||||
goto vmgexit_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
|
||||
vmgexit_err:
|
||||
vcpu = &svm->vcpu;
|
||||
|
||||
if (ghcb->ghcb_usage) {
|
||||
if (reason == GHCB_ERR_INVALID_USAGE) {
|
||||
vcpu_unimpl(vcpu, "vmgexit: ghcb usage %#x is not valid\n",
|
||||
ghcb->ghcb_usage);
|
||||
} else if (reason == GHCB_ERR_INVALID_EVENT) {
|
||||
vcpu_unimpl(vcpu, "vmgexit: exit code %#llx is not valid\n",
|
||||
exit_code);
|
||||
} else {
|
||||
vcpu_unimpl(vcpu, "vmgexit: exit reason %#llx is not valid\n",
|
||||
vcpu_unimpl(vcpu, "vmgexit: exit code %#llx input is not valid\n",
|
||||
exit_code);
|
||||
dump_ghcb(svm);
|
||||
}
|
||||
|
||||
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
||||
vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON;
|
||||
vcpu->run->internal.ndata = 2;
|
||||
vcpu->run->internal.data[0] = exit_code;
|
||||
vcpu->run->internal.data[1] = vcpu->arch.last_vmentry_cpu;
|
||||
/* Clear the valid entries fields */
|
||||
memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap));
|
||||
|
||||
return -EINVAL;
|
||||
ghcb_set_sw_exit_info_1(ghcb, 2);
|
||||
ghcb_set_sw_exit_info_2(ghcb, reason);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void sev_es_unmap_ghcb(struct vcpu_svm *svm)
|
||||
@@ -2493,7 +2502,7 @@ void sev_es_unmap_ghcb(struct vcpu_svm *svm)
|
||||
svm->sev_es.ghcb_sa_sync = false;
|
||||
}
|
||||
|
||||
kfree(svm->sev_es.ghcb_sa);
|
||||
kvfree(svm->sev_es.ghcb_sa);
|
||||
svm->sev_es.ghcb_sa = NULL;
|
||||
svm->sev_es.ghcb_sa_free = false;
|
||||
}
|
||||
@@ -2541,14 +2550,14 @@ static bool setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
|
||||
scratch_gpa_beg = ghcb_get_sw_scratch(ghcb);
|
||||
if (!scratch_gpa_beg) {
|
||||
pr_err("vmgexit: scratch gpa not provided\n");
|
||||
return false;
|
||||
goto e_scratch;
|
||||
}
|
||||
|
||||
scratch_gpa_end = scratch_gpa_beg + len;
|
||||
if (scratch_gpa_end < scratch_gpa_beg) {
|
||||
pr_err("vmgexit: scratch length (%#llx) not valid for scratch address (%#llx)\n",
|
||||
len, scratch_gpa_beg);
|
||||
return false;
|
||||
goto e_scratch;
|
||||
}
|
||||
|
||||
if ((scratch_gpa_beg & PAGE_MASK) == control->ghcb_gpa) {
|
||||
@@ -2566,7 +2575,7 @@ static bool setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
|
||||
scratch_gpa_end > ghcb_scratch_end) {
|
||||
pr_err("vmgexit: scratch area is outside of GHCB shared buffer area (%#llx - %#llx)\n",
|
||||
scratch_gpa_beg, scratch_gpa_end);
|
||||
return false;
|
||||
goto e_scratch;
|
||||
}
|
||||
|
||||
scratch_va = (void *)svm->sev_es.ghcb;
|
||||
@@ -2579,18 +2588,18 @@ static bool setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
|
||||
if (len > GHCB_SCRATCH_AREA_LIMIT) {
|
||||
pr_err("vmgexit: scratch area exceeds KVM limits (%#llx requested, %#llx limit)\n",
|
||||
len, GHCB_SCRATCH_AREA_LIMIT);
|
||||
return false;
|
||||
goto e_scratch;
|
||||
}
|
||||
scratch_va = kzalloc(len, GFP_KERNEL_ACCOUNT);
|
||||
scratch_va = kvzalloc(len, GFP_KERNEL_ACCOUNT);
|
||||
if (!scratch_va)
|
||||
return false;
|
||||
goto e_scratch;
|
||||
|
||||
if (kvm_read_guest(svm->vcpu.kvm, scratch_gpa_beg, scratch_va, len)) {
|
||||
/* Unable to copy scratch area from guest */
|
||||
pr_err("vmgexit: kvm_read_guest for scratch area failed\n");
|
||||
|
||||
kfree(scratch_va);
|
||||
return false;
|
||||
kvfree(scratch_va);
|
||||
goto e_scratch;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2607,6 +2616,12 @@ static bool setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
|
||||
svm->sev_es.ghcb_sa_len = len;
|
||||
|
||||
return true;
|
||||
|
||||
e_scratch:
|
||||
ghcb_set_sw_exit_info_1(ghcb, 2);
|
||||
ghcb_set_sw_exit_info_2(ghcb, GHCB_ERR_INVALID_SCRATCH_AREA);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void set_ghcb_msr_bits(struct vcpu_svm *svm, u64 value, u64 mask,
|
||||
@@ -2657,7 +2672,7 @@ static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
|
||||
|
||||
ret = svm_invoke_exit_handler(vcpu, SVM_EXIT_CPUID);
|
||||
if (!ret) {
|
||||
ret = -EINVAL;
|
||||
/* Error, keep GHCB MSR value as-is */
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2693,10 +2708,13 @@ static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
|
||||
GHCB_MSR_TERM_REASON_POS);
|
||||
pr_info("SEV-ES guest requested termination: %#llx:%#llx\n",
|
||||
reason_set, reason_code);
|
||||
fallthrough;
|
||||
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
/* Error, keep GHCB MSR value as-is */
|
||||
break;
|
||||
}
|
||||
|
||||
trace_kvm_vmgexit_msr_protocol_exit(svm->vcpu.vcpu_id,
|
||||
@@ -2720,14 +2738,18 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
|
||||
|
||||
if (!ghcb_gpa) {
|
||||
vcpu_unimpl(vcpu, "vmgexit: GHCB gpa is not set\n");
|
||||
return -EINVAL;
|
||||
|
||||
/* Without a GHCB, just return right back to the guest */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (kvm_vcpu_map(vcpu, ghcb_gpa >> PAGE_SHIFT, &svm->sev_es.ghcb_map)) {
|
||||
/* Unable to map GHCB from guest */
|
||||
vcpu_unimpl(vcpu, "vmgexit: error mapping GHCB [%#llx] from guest\n",
|
||||
ghcb_gpa);
|
||||
return -EINVAL;
|
||||
|
||||
/* Without a GHCB, just return right back to the guest */
|
||||
return 1;
|
||||
}
|
||||
|
||||
svm->sev_es.ghcb = svm->sev_es.ghcb_map.hva;
|
||||
@@ -2737,15 +2759,14 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
|
||||
|
||||
exit_code = ghcb_get_sw_exit_code(ghcb);
|
||||
|
||||
ret = sev_es_validate_vmgexit(svm);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!sev_es_validate_vmgexit(svm))
|
||||
return 1;
|
||||
|
||||
sev_es_sync_from_ghcb(svm);
|
||||
ghcb_set_sw_exit_info_1(ghcb, 0);
|
||||
ghcb_set_sw_exit_info_2(ghcb, 0);
|
||||
|
||||
ret = -EINVAL;
|
||||
ret = 1;
|
||||
switch (exit_code) {
|
||||
case SVM_VMGEXIT_MMIO_READ:
|
||||
if (!setup_vmgexit_scratch(svm, true, control->exit_info_2))
|
||||
@@ -2786,20 +2807,17 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
|
||||
default:
|
||||
pr_err("svm: vmgexit: unsupported AP jump table request - exit_info_1=%#llx\n",
|
||||
control->exit_info_1);
|
||||
ghcb_set_sw_exit_info_1(ghcb, 1);
|
||||
ghcb_set_sw_exit_info_2(ghcb,
|
||||
X86_TRAP_UD |
|
||||
SVM_EVTINJ_TYPE_EXEPT |
|
||||
SVM_EVTINJ_VALID);
|
||||
ghcb_set_sw_exit_info_1(ghcb, 2);
|
||||
ghcb_set_sw_exit_info_2(ghcb, GHCB_ERR_INVALID_INPUT);
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
case SVM_VMGEXIT_UNSUPPORTED_EVENT:
|
||||
vcpu_unimpl(vcpu,
|
||||
"vmgexit: unsupported event - exit_info_1=%#llx, exit_info_2=%#llx\n",
|
||||
control->exit_info_1, control->exit_info_2);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
ret = svm_invoke_exit_handler(vcpu, exit_code);
|
||||
@@ -2821,7 +2839,7 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in)
|
||||
return -EINVAL;
|
||||
|
||||
if (!setup_vmgexit_scratch(svm, in, bytes))
|
||||
return -EINVAL;
|
||||
return 1;
|
||||
|
||||
return kvm_sev_es_string_io(&svm->vcpu, size, port, svm->sev_es.ghcb_sa,
|
||||
count, in);
|
||||
|
||||
@@ -2591,8 +2591,10 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
|
||||
|
||||
if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL) &&
|
||||
WARN_ON_ONCE(kvm_set_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL,
|
||||
vmcs12->guest_ia32_perf_global_ctrl)))
|
||||
vmcs12->guest_ia32_perf_global_ctrl))) {
|
||||
*entry_failure_code = ENTRY_FAIL_DEFAULT;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
kvm_rsp_write(vcpu, vmcs12->guest_rsp);
|
||||
kvm_rip_write(vcpu, vmcs12->guest_rip);
|
||||
|
||||
@@ -7525,6 +7525,7 @@ static void hardware_unsetup(void)
|
||||
static bool vmx_check_apicv_inhibit_reasons(ulong bit)
|
||||
{
|
||||
ulong supported = BIT(APICV_INHIBIT_REASON_DISABLE) |
|
||||
BIT(APICV_INHIBIT_REASON_ABSENT) |
|
||||
BIT(APICV_INHIBIT_REASON_HYPERV) |
|
||||
BIT(APICV_INHIBIT_REASON_BLOCKIRQ);
|
||||
|
||||
|
||||
+5
-4
@@ -5740,6 +5740,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
|
||||
smp_wmb();
|
||||
kvm->arch.irqchip_mode = KVM_IRQCHIP_SPLIT;
|
||||
kvm->arch.nr_reserved_ioapic_pins = cap->args[0];
|
||||
kvm_request_apicv_update(kvm, true, APICV_INHIBIT_REASON_ABSENT);
|
||||
r = 0;
|
||||
split_irqchip_unlock:
|
||||
mutex_unlock(&kvm->lock);
|
||||
@@ -6120,6 +6121,7 @@ set_identity_unlock:
|
||||
/* Write kvm->irq_routing before enabling irqchip_in_kernel. */
|
||||
smp_wmb();
|
||||
kvm->arch.irqchip_mode = KVM_IRQCHIP_KERNEL;
|
||||
kvm_request_apicv_update(kvm, true, APICV_INHIBIT_REASON_ABSENT);
|
||||
create_irqchip_unlock:
|
||||
mutex_unlock(&kvm->lock);
|
||||
break;
|
||||
@@ -8818,10 +8820,9 @@ static void kvm_apicv_init(struct kvm *kvm)
|
||||
{
|
||||
init_rwsem(&kvm->arch.apicv_update_lock);
|
||||
|
||||
if (enable_apicv)
|
||||
clear_bit(APICV_INHIBIT_REASON_DISABLE,
|
||||
&kvm->arch.apicv_inhibit_reasons);
|
||||
else
|
||||
set_bit(APICV_INHIBIT_REASON_ABSENT,
|
||||
&kvm->arch.apicv_inhibit_reasons);
|
||||
if (!enable_apicv)
|
||||
set_bit(APICV_INHIBIT_REASON_DISABLE,
|
||||
&kvm->arch.apicv_inhibit_reasons);
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ static void __init setup_real_mode(void)
|
||||
#ifdef CONFIG_X86_64
|
||||
u64 *trampoline_pgd;
|
||||
u64 efer;
|
||||
int i;
|
||||
#endif
|
||||
|
||||
base = (unsigned char *)real_mode_header;
|
||||
@@ -128,8 +129,17 @@ static void __init setup_real_mode(void)
|
||||
trampoline_header->flags = 0;
|
||||
|
||||
trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd);
|
||||
|
||||
/* Map the real mode stub as virtual == physical */
|
||||
trampoline_pgd[0] = trampoline_pgd_entry.pgd;
|
||||
trampoline_pgd[511] = init_top_pgt[511].pgd;
|
||||
|
||||
/*
|
||||
* Include the entirety of the kernel mapping into the trampoline
|
||||
* PGD. This way, all mappings present in the normal kernel page
|
||||
* tables are usable while running on trampoline_pgd.
|
||||
*/
|
||||
for (i = pgd_index(__PAGE_OFFSET); i < PTRS_PER_PGD; i++)
|
||||
trampoline_pgd[i] = init_top_pgt[i].pgd;
|
||||
#endif
|
||||
|
||||
sme_sev_setup_real_mode(trampoline_header);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <../entry/calling.h>
|
||||
|
||||
.pushsection .noinstr.text, "ax"
|
||||
/*
|
||||
@@ -192,6 +193,25 @@ SYM_CODE_START(xen_iret)
|
||||
jmp hypercall_iret
|
||||
SYM_CODE_END(xen_iret)
|
||||
|
||||
/*
|
||||
* XEN pv doesn't use trampoline stack, PER_CPU_VAR(cpu_tss_rw + TSS_sp0) is
|
||||
* also the kernel stack. Reusing swapgs_restore_regs_and_return_to_usermode()
|
||||
* in XEN pv would cause %rsp to move up to the top of the kernel stack and
|
||||
* leave the IRET frame below %rsp, which is dangerous to be corrupted if #NMI
|
||||
* interrupts. And swapgs_restore_regs_and_return_to_usermode() pushing the IRET
|
||||
* frame at the same address is useless.
|
||||
*/
|
||||
SYM_CODE_START(xenpv_restore_regs_and_return_to_usermode)
|
||||
UNWIND_HINT_REGS
|
||||
POP_REGS
|
||||
|
||||
/* stackleak_erase() can work safely on the kernel stack. */
|
||||
STACKLEAK_ERASE_NOCLOBBER
|
||||
|
||||
addq $8, %rsp /* skip regs->orig_ax */
|
||||
jmp xen_iret
|
||||
SYM_CODE_END(xenpv_restore_regs_and_return_to_usermode)
|
||||
|
||||
/*
|
||||
* Xen handles syscall callbacks much like ordinary exceptions, which
|
||||
* means we have:
|
||||
|
||||
@@ -281,7 +281,7 @@ agp_ioc_init(void __iomem *ioc_regs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
static int __init
|
||||
lba_find_capability(int cap)
|
||||
{
|
||||
struct _parisc_agp_info *info = &parisc_agp_info;
|
||||
@@ -366,7 +366,7 @@ fail:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
static int __init
|
||||
find_quicksilver(struct device *dev, void *data)
|
||||
{
|
||||
struct parisc_device **lba = data;
|
||||
@@ -378,7 +378,7 @@ find_quicksilver(struct device *dev, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
static int __init
|
||||
parisc_agp_init(void)
|
||||
{
|
||||
extern struct sba_device *sba_list;
|
||||
|
||||
@@ -237,6 +237,7 @@ struct brcmuart_priv {
|
||||
u32 rx_err;
|
||||
u32 rx_timeout;
|
||||
u32 rx_abort;
|
||||
u32 saved_mctrl;
|
||||
};
|
||||
|
||||
static struct dentry *brcmuart_debugfs_root;
|
||||
@@ -1133,16 +1134,27 @@ static int brcmuart_remove(struct platform_device *pdev)
|
||||
static int __maybe_unused brcmuart_suspend(struct device *dev)
|
||||
{
|
||||
struct brcmuart_priv *priv = dev_get_drvdata(dev);
|
||||
struct uart_8250_port *up = serial8250_get_port(priv->line);
|
||||
struct uart_port *port = &up->port;
|
||||
|
||||
serial8250_suspend_port(priv->line);
|
||||
clk_disable_unprepare(priv->baud_mux_clk);
|
||||
|
||||
/*
|
||||
* This will prevent resume from enabling RTS before the
|
||||
* baud rate has been resored.
|
||||
*/
|
||||
priv->saved_mctrl = port->mctrl;
|
||||
port->mctrl = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused brcmuart_resume(struct device *dev)
|
||||
{
|
||||
struct brcmuart_priv *priv = dev_get_drvdata(dev);
|
||||
struct uart_8250_port *up = serial8250_get_port(priv->line);
|
||||
struct uart_port *port = &up->port;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(priv->baud_mux_clk);
|
||||
@@ -1165,6 +1177,7 @@ static int __maybe_unused brcmuart_resume(struct device *dev)
|
||||
start_rx_dma(serial8250_get_port(priv->line));
|
||||
}
|
||||
serial8250_resume_port(priv->line);
|
||||
port->mctrl = priv->saved_mctrl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1324,29 +1324,33 @@ pericom_do_set_divisor(struct uart_port *port, unsigned int baud,
|
||||
{
|
||||
int scr;
|
||||
int lcr;
|
||||
int actual_baud;
|
||||
int tolerance;
|
||||
|
||||
for (scr = 5 ; scr <= 15 ; scr++) {
|
||||
actual_baud = 921600 * 16 / scr;
|
||||
tolerance = actual_baud / 50;
|
||||
for (scr = 16; scr > 4; scr--) {
|
||||
unsigned int maxrate = port->uartclk / scr;
|
||||
unsigned int divisor = max(maxrate / baud, 1U);
|
||||
int delta = maxrate / divisor - baud;
|
||||
|
||||
if ((baud < actual_baud + tolerance) &&
|
||||
(baud > actual_baud - tolerance)) {
|
||||
if (baud > maxrate + baud / 50)
|
||||
continue;
|
||||
|
||||
if (delta > baud / 50)
|
||||
divisor++;
|
||||
|
||||
if (divisor > 0xffff)
|
||||
continue;
|
||||
|
||||
/* Update delta due to possible divisor change */
|
||||
delta = maxrate / divisor - baud;
|
||||
if (abs(delta) < baud / 50) {
|
||||
lcr = serial_port_in(port, UART_LCR);
|
||||
serial_port_out(port, UART_LCR, lcr | 0x80);
|
||||
|
||||
serial_port_out(port, UART_DLL, 1);
|
||||
serial_port_out(port, UART_DLM, 0);
|
||||
serial_port_out(port, UART_DLL, divisor & 0xff);
|
||||
serial_port_out(port, UART_DLM, divisor >> 8 & 0xff);
|
||||
serial_port_out(port, 2, 16 - scr);
|
||||
serial_port_out(port, UART_LCR, lcr);
|
||||
return;
|
||||
} else if (baud > actual_baud) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
serial8250_do_set_divisor(port, baud, quot, quot_frac);
|
||||
}
|
||||
static int pci_pericom_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
@@ -2291,12 +2295,19 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
|
||||
|
||||
@@ -2024,13 +2024,6 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned char mcr;
|
||||
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
if (serial8250_in_MCR(up) & UART_MCR_RTS)
|
||||
mctrl |= TIOCM_RTS;
|
||||
else
|
||||
mctrl &= ~TIOCM_RTS;
|
||||
}
|
||||
|
||||
mcr = serial8250_TIOCM_to_MCR(mctrl);
|
||||
|
||||
mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
|
||||
|
||||
@@ -1532,7 +1532,7 @@ config SERIAL_LITEUART
|
||||
tristate "LiteUART serial port support"
|
||||
depends on HAS_IOMEM
|
||||
depends on OF || COMPILE_TEST
|
||||
depends on LITEX
|
||||
depends on LITEX || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver is for the FPGA-based LiteUART serial controller from LiteX
|
||||
|
||||
@@ -2947,6 +2947,7 @@ MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
|
||||
|
||||
static const struct acpi_device_id __maybe_unused sbsa_uart_acpi_match[] = {
|
||||
{ "ARMH0011", 0 },
|
||||
{ "ARMHB000", 0 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match);
|
||||
|
||||
@@ -2625,6 +2625,7 @@ OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1028a-lpuart", ls1028a_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(lpuart32, "fsl,imx8qxp-lpuart", lpuart32_imx_early_console_setup);
|
||||
EARLYCON_DECLARE(lpuart, lpuart_early_console_setup);
|
||||
EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup);
|
||||
|
||||
|
||||
@@ -270,8 +270,10 @@ static int liteuart_probe(struct platform_device *pdev)
|
||||
|
||||
/* get membase */
|
||||
port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
|
||||
if (IS_ERR(port->membase))
|
||||
return PTR_ERR(port->membase);
|
||||
if (IS_ERR(port->membase)) {
|
||||
ret = PTR_ERR(port->membase);
|
||||
goto err_erase_id;
|
||||
}
|
||||
|
||||
/* values not from device tree */
|
||||
port->dev = &pdev->dev;
|
||||
@@ -285,7 +287,18 @@ static int liteuart_probe(struct platform_device *pdev)
|
||||
port->line = dev_id;
|
||||
spin_lock_init(&port->lock);
|
||||
|
||||
return uart_add_one_port(&liteuart_driver, &uart->port);
|
||||
platform_set_drvdata(pdev, port);
|
||||
|
||||
ret = uart_add_one_port(&liteuart_driver, &uart->port);
|
||||
if (ret)
|
||||
goto err_erase_id;
|
||||
|
||||
return 0;
|
||||
|
||||
err_erase_id:
|
||||
xa_erase(&liteuart_array, uart->id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int liteuart_remove(struct platform_device *pdev)
|
||||
@@ -293,6 +306,7 @@ static int liteuart_remove(struct platform_device *pdev)
|
||||
struct uart_port *port = platform_get_drvdata(pdev);
|
||||
struct liteuart_port *uart = to_liteuart_port(port);
|
||||
|
||||
uart_remove_one_port(&liteuart_driver, port);
|
||||
xa_erase(&liteuart_array, uart->id);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -598,6 +598,9 @@ static void msm_start_rx_dma(struct msm_port *msm_port)
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_CONSOLE_POLL))
|
||||
return;
|
||||
|
||||
if (!dma->chan)
|
||||
return;
|
||||
|
||||
|
||||
@@ -1506,7 +1506,7 @@ static struct tegra_uart_chip_data tegra20_uart_chip_data = {
|
||||
.fifo_mode_enable_status = false,
|
||||
.uart_max_port = 5,
|
||||
.max_dma_burst_bytes = 4,
|
||||
.error_tolerance_low_range = 0,
|
||||
.error_tolerance_low_range = -4,
|
||||
.error_tolerance_high_range = 4,
|
||||
};
|
||||
|
||||
@@ -1517,7 +1517,7 @@ static struct tegra_uart_chip_data tegra30_uart_chip_data = {
|
||||
.fifo_mode_enable_status = false,
|
||||
.uart_max_port = 5,
|
||||
.max_dma_burst_bytes = 4,
|
||||
.error_tolerance_low_range = 0,
|
||||
.error_tolerance_low_range = -4,
|
||||
.error_tolerance_high_range = 4,
|
||||
};
|
||||
|
||||
|
||||
@@ -1075,6 +1075,11 @@ uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
|
||||
goto out;
|
||||
|
||||
if (!tty_io_error(tty)) {
|
||||
if (uport->rs485.flags & SER_RS485_ENABLED) {
|
||||
set &= ~TIOCM_RTS;
|
||||
clear &= ~TIOCM_RTS;
|
||||
}
|
||||
|
||||
uart_update_mctrl(uport, set, clear);
|
||||
ret = 0;
|
||||
}
|
||||
@@ -1549,6 +1554,7 @@ static void uart_tty_port_shutdown(struct tty_port *port)
|
||||
{
|
||||
struct uart_state *state = container_of(port, struct uart_state, port);
|
||||
struct uart_port *uport = uart_port_check(state);
|
||||
char *buf;
|
||||
|
||||
/*
|
||||
* At this point, we stop accepting input. To do this, we
|
||||
@@ -1570,8 +1576,18 @@ static void uart_tty_port_shutdown(struct tty_port *port)
|
||||
*/
|
||||
tty_port_set_suspended(port, 0);
|
||||
|
||||
uart_change_pm(state, UART_PM_STATE_OFF);
|
||||
/*
|
||||
* Free the transmit buffer.
|
||||
*/
|
||||
spin_lock_irq(&uport->lock);
|
||||
buf = state->xmit.buf;
|
||||
state->xmit.buf = NULL;
|
||||
spin_unlock_irq(&uport->lock);
|
||||
|
||||
if (buf)
|
||||
free_page((unsigned long)buf);
|
||||
|
||||
uart_change_pm(state, UART_PM_STATE_OFF);
|
||||
}
|
||||
|
||||
static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||
|
||||
@@ -337,19 +337,6 @@ static void cdns3_ep_inc_deq(struct cdns3_endpoint *priv_ep)
|
||||
cdns3_ep_inc_trb(&priv_ep->dequeue, &priv_ep->ccs, priv_ep->num_trbs);
|
||||
}
|
||||
|
||||
static void cdns3_move_deq_to_next_trb(struct cdns3_request *priv_req)
|
||||
{
|
||||
struct cdns3_endpoint *priv_ep = priv_req->priv_ep;
|
||||
int current_trb = priv_req->start_trb;
|
||||
|
||||
while (current_trb != priv_req->end_trb) {
|
||||
cdns3_ep_inc_deq(priv_ep);
|
||||
current_trb = priv_ep->dequeue;
|
||||
}
|
||||
|
||||
cdns3_ep_inc_deq(priv_ep);
|
||||
}
|
||||
|
||||
/**
|
||||
* cdns3_allow_enable_l1 - enable/disable permits to transition to L1.
|
||||
* @priv_dev: Extended gadget object
|
||||
@@ -1517,10 +1504,11 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
|
||||
|
||||
trb = priv_ep->trb_pool + priv_ep->dequeue;
|
||||
|
||||
/* Request was dequeued and TRB was changed to TRB_LINK. */
|
||||
if (TRB_FIELD_TO_TYPE(le32_to_cpu(trb->control)) == TRB_LINK) {
|
||||
/* The TRB was changed as link TRB, and the request was handled at ep_dequeue */
|
||||
while (TRB_FIELD_TO_TYPE(le32_to_cpu(trb->control)) == TRB_LINK) {
|
||||
trace_cdns3_complete_trb(priv_ep, trb);
|
||||
cdns3_move_deq_to_next_trb(priv_req);
|
||||
cdns3_ep_inc_deq(priv_ep);
|
||||
trb = priv_ep->trb_pool + priv_ep->dequeue;
|
||||
}
|
||||
|
||||
if (!request->stream_id) {
|
||||
|
||||
@@ -987,6 +987,9 @@ int cdnsp_endpoint_init(struct cdnsp_device *pdev,
|
||||
|
||||
/* Set up the endpoint ring. */
|
||||
pep->ring = cdnsp_ring_alloc(pdev, 2, ring_type, max_packet, mem_flags);
|
||||
if (!pep->ring)
|
||||
return -ENOMEM;
|
||||
|
||||
pep->skip = false;
|
||||
|
||||
/* Fill the endpoint context */
|
||||
|
||||
@@ -366,7 +366,9 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
|
||||
/* Must be called with xhci->lock held, releases and aquires lock back */
|
||||
static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags)
|
||||
{
|
||||
u32 temp_32;
|
||||
struct xhci_segment *new_seg = xhci->cmd_ring->deq_seg;
|
||||
union xhci_trb *new_deq = xhci->cmd_ring->dequeue;
|
||||
u64 crcr;
|
||||
int ret;
|
||||
|
||||
xhci_dbg(xhci, "Abort command ring\n");
|
||||
@@ -375,13 +377,18 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags)
|
||||
|
||||
/*
|
||||
* The control bits like command stop, abort are located in lower
|
||||
* dword of the command ring control register. Limit the write
|
||||
* to the lower dword to avoid corrupting the command ring pointer
|
||||
* in case if the command ring is stopped by the time upper dword
|
||||
* is written.
|
||||
* dword of the command ring control register.
|
||||
* Some controllers require all 64 bits to be written to abort the ring.
|
||||
* Make sure the upper dword is valid, pointing to the next command,
|
||||
* avoiding corrupting the command ring pointer in case the command ring
|
||||
* is stopped by the time the upper dword is written.
|
||||
*/
|
||||
temp_32 = readl(&xhci->op_regs->cmd_ring);
|
||||
writel(temp_32 | CMD_RING_ABORT, &xhci->op_regs->cmd_ring);
|
||||
next_trb(xhci, NULL, &new_seg, &new_deq);
|
||||
if (trb_is_link(new_deq))
|
||||
next_trb(xhci, NULL, &new_seg, &new_deq);
|
||||
|
||||
crcr = xhci_trb_virt_to_dma(new_seg, new_deq);
|
||||
xhci_write_64(xhci, crcr | CMD_RING_ABORT, &xhci->op_regs->cmd_ring);
|
||||
|
||||
/* Section 4.6.1.2 of xHCI 1.0 spec says software should also time the
|
||||
* completion of the Command Abort operation. If CRR is not negated in 5
|
||||
|
||||
@@ -4110,11 +4110,7 @@ static void run_state_machine(struct tcpm_port *port)
|
||||
tcpm_try_src(port) ? SRC_TRY
|
||||
: SNK_ATTACHED,
|
||||
0);
|
||||
else
|
||||
/* Wait for VBUS, but not forever */
|
||||
tcpm_set_state(port, PORT_RESET, PD_T_PS_SOURCE_ON);
|
||||
break;
|
||||
|
||||
case SRC_TRY:
|
||||
port->try_src_count++;
|
||||
tcpm_set_cc(port, tcpm_rp_cc(port));
|
||||
|
||||
@@ -366,11 +366,17 @@ static void vgacon_init(struct vc_data *c, int init)
|
||||
struct uni_pagedir *p;
|
||||
|
||||
/*
|
||||
* We cannot be loaded as a module, therefore init is always 1,
|
||||
* but vgacon_init can be called more than once, and init will
|
||||
* not be 1.
|
||||
* We cannot be loaded as a module, therefore init will be 1
|
||||
* if we are the default console, however if we are a fallback
|
||||
* console, for example if fbcon has failed registration, then
|
||||
* init will be 0, so we need to make sure our boot parameters
|
||||
* have been copied to the console structure for vgacon_resize
|
||||
* ultimately called by vc_resize. Any subsequent calls to
|
||||
* vgacon_init init will have init set to 0 too.
|
||||
*/
|
||||
c->vc_can_do_color = vga_can_do_color;
|
||||
c->vc_scan_lines = vga_scan_lines;
|
||||
c->vc_font.height = c->vc_cell_height = vga_video_font_height;
|
||||
|
||||
/* set dimensions manually if init != 0 since vc_resize() will fail */
|
||||
if (init) {
|
||||
@@ -379,8 +385,6 @@ static void vgacon_init(struct vc_data *c, int init)
|
||||
} else
|
||||
vc_resize(c, vga_video_num_columns, vga_video_num_lines);
|
||||
|
||||
c->vc_scan_lines = vga_scan_lines;
|
||||
c->vc_font.height = c->vc_cell_height = vga_video_font_height;
|
||||
c->vc_complement_mask = 0x7700;
|
||||
if (vga_512_chars)
|
||||
c->vc_hi_font_mask = 0x0800;
|
||||
|
||||
@@ -18,15 +18,16 @@
|
||||
#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
|
||||
|
||||
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
|
||||
extern void task_cputime(struct task_struct *t,
|
||||
extern bool task_cputime(struct task_struct *t,
|
||||
u64 *utime, u64 *stime);
|
||||
extern u64 task_gtime(struct task_struct *t);
|
||||
#else
|
||||
static inline void task_cputime(struct task_struct *t,
|
||||
static inline bool task_cputime(struct task_struct *t,
|
||||
u64 *utime, u64 *stime)
|
||||
{
|
||||
*utime = t->utime;
|
||||
*stime = t->stime;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline u64 task_gtime(struct task_struct *t)
|
||||
|
||||
+3
-3
@@ -1935,7 +1935,7 @@ static void __init init_uclamp_rq(struct rq *rq)
|
||||
};
|
||||
}
|
||||
|
||||
rq->uclamp_flags = 0;
|
||||
rq->uclamp_flags = UCLAMP_FLAG_IDLE;
|
||||
}
|
||||
|
||||
static void __init init_uclamp(void)
|
||||
@@ -6694,11 +6694,11 @@ static int __init setup_preempt_mode(char *str)
|
||||
int mode = sched_dynamic_mode(str);
|
||||
if (mode < 0) {
|
||||
pr_warn("Dynamic Preempt: unsupported mode: %s\n", str);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sched_dynamic_update(mode);
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
__setup("preempt=", setup_preempt_mode);
|
||||
|
||||
|
||||
@@ -627,7 +627,8 @@ void task_cputime_adjusted(struct task_struct *p, u64 *ut, u64 *st)
|
||||
.sum_exec_runtime = p->se.sum_exec_runtime,
|
||||
};
|
||||
|
||||
task_cputime(p, &cputime.utime, &cputime.stime);
|
||||
if (task_cputime(p, &cputime.utime, &cputime.stime))
|
||||
cputime.sum_exec_runtime = task_sched_runtime(p);
|
||||
cputime_adjust(&cputime, &p->prev_cputime, ut, st);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(task_cputime_adjusted);
|
||||
@@ -842,19 +843,21 @@ u64 task_gtime(struct task_struct *t)
|
||||
* add up the pending nohz execution time since the last
|
||||
* cputime snapshot.
|
||||
*/
|
||||
void task_cputime(struct task_struct *t, u64 *utime, u64 *stime)
|
||||
bool task_cputime(struct task_struct *t, u64 *utime, u64 *stime)
|
||||
{
|
||||
struct vtime *vtime = &t->vtime;
|
||||
unsigned int seq;
|
||||
u64 delta;
|
||||
int ret;
|
||||
|
||||
if (!vtime_accounting_enabled()) {
|
||||
*utime = t->utime;
|
||||
*stime = t->stime;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
ret = false;
|
||||
seq = read_seqcount_begin(&vtime->seqcount);
|
||||
|
||||
*utime = t->utime;
|
||||
@@ -864,6 +867,7 @@ void task_cputime(struct task_struct *t, u64 *utime, u64 *stime)
|
||||
if (vtime->state < VTIME_SYS)
|
||||
continue;
|
||||
|
||||
ret = true;
|
||||
delta = vtime_delta(vtime);
|
||||
|
||||
/*
|
||||
@@ -875,6 +879,8 @@ void task_cputime(struct task_struct *t, u64 *utime, u64 *stime)
|
||||
else
|
||||
*utime += vtime->utime + delta;
|
||||
} while (read_seqcount_retry(&vtime->seqcount, seq));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vtime_state_fetch(struct vtime *vtime, int cpu)
|
||||
|
||||
+2
-1
@@ -605,7 +605,8 @@ void irq_enter_rcu(void)
|
||||
{
|
||||
__irq_enter_raw();
|
||||
|
||||
if (is_idle_task(current) && (irq_count() == HARDIRQ_OFFSET))
|
||||
if (tick_nohz_full_cpu(smp_processor_id()) ||
|
||||
(is_idle_task(current) && (irq_count() == HARDIRQ_OFFSET)))
|
||||
tick_irq_enter();
|
||||
|
||||
account_hardirq_enter(current);
|
||||
|
||||
@@ -1380,6 +1380,13 @@ static inline void tick_nohz_irq_enter(void)
|
||||
now = ktime_get();
|
||||
if (ts->idle_active)
|
||||
tick_nohz_stop_idle(ts, now);
|
||||
/*
|
||||
* If all CPUs are idle. We may need to update a stale jiffies value.
|
||||
* Note nohz_full is a special case: a timekeeper is guaranteed to stay
|
||||
* alive but it might be busy looping with interrupts disabled in some
|
||||
* rare case (typically stop machine). So we must make sure we have a
|
||||
* last resort.
|
||||
*/
|
||||
if (ts->tick_stopped)
|
||||
tick_nohz_update_jiffies(now);
|
||||
}
|
||||
|
||||
@@ -375,6 +375,7 @@ static int read_symbols(struct elf *elf)
|
||||
return -1;
|
||||
}
|
||||
memset(sym, 0, sizeof(*sym));
|
||||
INIT_LIST_HEAD(&sym->pv_target);
|
||||
sym->alias = sym;
|
||||
|
||||
sym->idx = i;
|
||||
|
||||
@@ -153,6 +153,10 @@ void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func)
|
||||
!strcmp(func->name, "_paravirt_ident_64"))
|
||||
return;
|
||||
|
||||
/* already added this function */
|
||||
if (!list_empty(&func->pv_target))
|
||||
return;
|
||||
|
||||
list_add(&func->pv_target, &f->pv_ops[idx].targets);
|
||||
f->pv_ops[idx].clean = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user