Merge 5.10-rc7 into char-misc-next

We want the fixes in here, and this resolves a merge issue with
drivers/misc/habanalabs/common/memory.c.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Greg Kroah-Hartman 2020-12-07 10:08:14 +01:00
commit a3ab07c642
236 changed files with 2012 additions and 2025 deletions

View File

@ -322,6 +322,8 @@ TripleX Chung <xxx.phy@gmail.com> <zhongyu@18mail.cn>
Tsuneo Yoshioka <Tsuneo.Yoshioka@f-secure.com>
Tycho Andersen <tycho@tycho.pizza> <tycho@tycho.ws>
Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Uwe Kleine-König <ukleinek@strlen.de>
Uwe Kleine-König <ukl@pengutronix.de>
Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com>
Valdis Kletnieks <Valdis.Kletnieks@vt.edu>

View File

@ -740,6 +740,11 @@ S: (ask for current address)
S: Portland, Oregon
S: USA
N: Jason Cooper
D: ARM/Marvell SOC co-maintainer
D: irqchip co-maintainer
D: MVEBU PCI DRIVER co-maintainer
N: Robin Cornelius
E: robincornelius@users.sourceforge.net
D: Ralink rt2x00 WLAN driver

View File

@ -137,15 +137,24 @@ Boot Kernel With a Boot Config
==============================
Since the boot configuration file is loaded with initrd, it will be added
to the end of the initrd (initramfs) image file with size, checksum and
12-byte magic word as below.
to the end of the initrd (initramfs) image file with padding, size,
checksum and 12-byte magic word as below.
[initrd][bootconfig][size(u32)][checksum(u32)][#BOOTCONFIG\n]
[initrd][bootconfig][padding][size(le32)][checksum(le32)][#BOOTCONFIG\n]
The size and checksum fields are unsigned 32bit little endian value.
When the boot configuration is added to the initrd image, the total
file size is aligned to 4 bytes. To fill the gap, null characters
(``\0``) will be added. Thus the ``size`` is the length of the bootconfig
file + padding bytes.
The Linux kernel decodes the last part of the initrd image in memory to
get the boot configuration data.
Because of this "piggyback" method, there is no need to change or
update the boot loader and the kernel image itself.
update the boot loader and the kernel image itself as long as the boot
loader passes the correct initrd file size. If by any chance, the boot
loader passes a longer size, the kernel feils to find the bootconfig data.
To do this operation, Linux kernel provides "bootconfig" command under
tools/bootconfig, which allows admin to apply or delete the config file
@ -176,7 +185,8 @@ up to 512 key-value pairs. If keys contains 3 words in average, it can
contain 256 key-value pairs. In most cases, the number of config items
will be under 100 entries and smaller than 8KB, so it would be enough.
If the node number exceeds 1024, parser returns an error even if the file
size is smaller than 32KB.
size is smaller than 32KB. (Note that this maximum size is not including
the padding null characters.)
Anyway, since bootconfig command verifies it when appending a boot config
to initrd image, user can notice it before boot.

View File

@ -33,7 +33,7 @@ tcan4x5x: tcan4x5x@0 {
spi-max-frequency = <10000000>;
bosch,mram-cfg = <0x0 0 0 32 0 0 1 1>;
interrupt-parent = <&gpio1>;
interrupts = <14 GPIO_ACTIVE_LOW>;
interrupts = <14 IRQ_TYPE_LEVEL_LOW>;
device-state-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
device-wake-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>;

View File

@ -25,7 +25,7 @@ Example (for ARM-based BeagleBone with NPC100 NFC controller on I2C2):
clock-frequency = <100000>;
interrupt-parent = <&gpio1>;
interrupts = <29 GPIO_ACTIVE_HIGH>;
interrupts = <29 IRQ_TYPE_LEVEL_HIGH>;
enable-gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>;
firmware-gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>;

View File

@ -25,7 +25,7 @@ Example (for ARM-based BeagleBone with PN544 on I2C2):
clock-frequency = <400000>;
interrupt-parent = <&gpio1>;
interrupts = <17 GPIO_ACTIVE_HIGH>;
interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
enable-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
firmware-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;

View File

@ -2014,7 +2014,6 @@ M: Philipp Zabel <philipp.zabel@gmail.com>
S: Maintained
ARM/Marvell Dove/MV78xx0/Orion SOC support
M: Jason Cooper <jason@lakedaemon.net>
M: Andrew Lunn <andrew@lunn.ch>
M: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
M: Gregory Clement <gregory.clement@bootlin.com>
@ -2031,7 +2030,6 @@ F: arch/arm/plat-orion/
F: drivers/soc/dove/
ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K, CN9130 SOC support
M: Jason Cooper <jason@lakedaemon.net>
M: Andrew Lunn <andrew@lunn.ch>
M: Gregory Clement <gregory.clement@bootlin.com>
M: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
@ -3357,6 +3355,17 @@ S: Supported
F: arch/x86/net/
X: arch/x86/net/bpf_jit_comp32.c
BPF LSM (Security Audit and Enforcement using BPF)
M: KP Singh <kpsingh@chromium.org>
R: Florent Revest <revest@chromium.org>
R: Brendan Jackman <jackmanb@chromium.org>
L: bpf@vger.kernel.org
S: Maintained
F: Documentation/bpf/bpf_lsm.rst
F: include/linux/bpf_lsm.h
F: kernel/bpf/bpf_lsm.c
F: security/bpf/
BROADCOM B44 10/100 ETHERNET DRIVER
M: Michael Chan <michael.chan@broadcom.com>
L: netdev@vger.kernel.org
@ -4276,6 +4285,7 @@ B: https://github.com/ClangBuiltLinux/linux/issues
C: irc://chat.freenode.net/clangbuiltlinux
F: Documentation/kbuild/llvm.rst
F: scripts/clang-tools/
F: scripts/lld-version.sh
K: \b(?i:clang|llvm)\b
CLEANCACHE API
@ -9069,10 +9079,7 @@ S: Supported
F: drivers/net/wireless/intel/iwlegacy/
INTEL WIRELESS WIFI LINK (iwlwifi)
M: Johannes Berg <johannes.berg@intel.com>
M: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
M: Luca Coelho <luciano.coelho@intel.com>
M: Intel Linux Wireless <linuxwifi@intel.com>
L: linux-wireless@vger.kernel.org
S: Supported
W: https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi
@ -9248,7 +9255,6 @@ F: kernel/irq/
IRQCHIP DRIVERS
M: Thomas Gleixner <tglx@linutronix.de>
M: Jason Cooper <jason@lakedaemon.net>
M: Marc Zyngier <maz@kernel.org>
L: linux-kernel@vger.kernel.org
S: Maintained
@ -13394,7 +13400,6 @@ F: drivers/pci/controller/mobiveil/pcie-mobiveil*
PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support)
M: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
M: Jason Cooper <jason@lakedaemon.net>
L: linux-pci@vger.kernel.org
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
@ -19122,12 +19127,17 @@ L: netdev@vger.kernel.org
L: bpf@vger.kernel.org
S: Supported
F: include/net/xdp.h
F: include/net/xdp_priv.h
F: include/trace/events/xdp.h
F: kernel/bpf/cpumap.c
F: kernel/bpf/devmap.c
F: net/core/xdp.c
N: xdp
K: xdp
F: samples/bpf/xdp*
F: tools/testing/selftests/bpf/*xdp*
F: tools/testing/selftests/bpf/*/*xdp*
F: drivers/net/ethernet/*/*/*/*/*xdp*
F: drivers/net/ethernet/*/*/*xdp*
K: (?:\b|_)xdp(?:\b|_)
XDP SOCKETS (AF_XDP)
M: Björn Töpel <bjorn.topel@intel.com>
@ -19136,9 +19146,12 @@ R: Jonathan Lemon <jonathan.lemon@gmail.com>
L: netdev@vger.kernel.org
L: bpf@vger.kernel.org
S: Maintained
F: Documentation/networking/af_xdp.rst
F: include/net/xdp_sock*
F: include/net/xsk_buff_pool.h
F: include/uapi/linux/if_xdp.h
F: include/uapi/linux/xdp_diag.h
F: include/net/netns/xdp.h
F: net/xdp/
F: samples/bpf/xdpsock*
F: tools/lib/bpf/xsk*

View File

@ -2,7 +2,7 @@
VERSION = 5
PATCHLEVEL = 10
SUBLEVEL = 0
EXTRAVERSION = -rc6
EXTRAVERSION = -rc7
NAME = Kleptomaniac Octopus
# *DOCUMENTATION*
@ -826,7 +826,9 @@ else
DEBUG_CFLAGS += -g
endif
ifneq ($(LLVM_IAS),1)
KBUILD_AFLAGS += -Wa,-gdwarf-2
endif
ifdef CONFIG_DEBUG_INFO_DWARF4
DEBUG_CFLAGS += -gdwarf-4
@ -944,7 +946,7 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=incompatible-pointer-types)
KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init)
# change __FILE__ to the relative path from the srctree
KBUILD_CFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
# ensure -fcf-protection is disabled when using retpoline as it is
# incompatible with -mindirect-branch=thunk-extern
@ -982,6 +984,12 @@ ifeq ($(CONFIG_RELR),y)
LDFLAGS_vmlinux += --pack-dyn-relocs=relr
endif
# We never want expected sections to be placed heuristically by the
# linker. All sections should be explicitly named in the linker script.
ifdef CONFIG_LD_ORPHAN_WARN
LDFLAGS_vmlinux += --orphan-handling=warn
endif
# Align the bit size of userspace programs with the kernel
KBUILD_USERCFLAGS += $(filter -m32 -m64 --target=%, $(KBUILD_CFLAGS))
KBUILD_USERLDFLAGS += $(filter -m32 -m64 --target=%, $(KBUILD_CFLAGS))

View File

@ -1028,6 +1028,15 @@ config HAVE_STATIC_CALL_INLINE
bool
depends on HAVE_STATIC_CALL
config ARCH_WANT_LD_ORPHAN_WARN
bool
help
An arch should select this symbol once all linker sections are explicitly
included, size-asserted, or discarded in the linker scripts. This is
important because we never want expected sections to be placed heuristically
by the linker, since the locations of such sections can change between linker
versions.
source "kernel/gcov/Kconfig"
source "scripts/gcc-plugins/Kconfig"

View File

@ -35,6 +35,7 @@ config ARM
select ARCH_USE_CMPXCHG_LOCKREF
select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_WANT_LD_ORPHAN_WARN
select BINFMT_FLAT_ARGVP_ENVP_ON_STACK
select BUILDTIME_TABLE_SORT if MMU
select CLONE_BACKWARDS

View File

@ -16,10 +16,6 @@ LDFLAGS_vmlinux += --be8
KBUILD_LDFLAGS_MODULE += --be8
endif
# We never want expected sections to be placed heuristically by the
# linker. All sections should be explicitly named in the linker script.
LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn)
GZFLAGS :=-9
#KBUILD_CFLAGS +=-pipe

View File

@ -129,7 +129,9 @@ LDFLAGS_vmlinux += --no-undefined
# Delete all temporary local symbols
LDFLAGS_vmlinux += -X
# Report orphan sections
LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn)
ifdef CONFIG_LD_ORPHAN_WARN
LDFLAGS_vmlinux += --orphan-handling=warn
endif
# Next argument is a linker script
LDFLAGS_vmlinux += -T

View File

@ -81,7 +81,6 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_BINFMT_MISC=y
CONFIG_CMA=y
CONFIG_ZSMALLOC=m
CONFIG_ZSMALLOC_PGTABLE_MAPPING=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y

View File

@ -288,7 +288,7 @@ static struct gpiod_lookup_table osk_usb_gpio_table = {
.dev_id = "ohci",
.table = {
/* Power GPIO on the I2C-attached TPS65010 */
GPIO_LOOKUP("i2c-tps65010", 1, "power", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("tps65010", 0, "power", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP(OMAP_GPIO_LABEL, 9, "overcurrent",
GPIO_ACTIVE_HIGH),
},

View File

@ -81,6 +81,7 @@ config ARM64
select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
select ARCH_WANT_FRAME_POINTERS
select ARCH_WANT_HUGE_PMD_SHARE if ARM64_4K_PAGES || (ARM64_16K_PAGES && !ARM64_VA_BITS_36)
select ARCH_WANT_LD_ORPHAN_WARN
select ARCH_HAS_UBSAN_SANITIZE_ALL
select ARM_AMBA
select ARM_ARCH_TIMER

View File

@ -28,10 +28,6 @@ LDFLAGS_vmlinux += --fix-cortex-a53-843419
endif
endif
# We never want expected sections to be placed heuristically by the
# linker. All sections should be explicitly named in the linker script.
LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn)
ifeq ($(CONFIG_ARM64_USE_LSE_ATOMICS), y)
ifneq ($(CONFIG_ARM64_LSE_ATOMICS), y)
$(warning LSE atomics not supported by binutils)

View File

@ -128,6 +128,9 @@ static inline void local_daif_inherit(struct pt_regs *regs)
{
unsigned long flags = regs->pstate & DAIF_MASK;
if (interrupts_enabled(regs))
trace_hardirqs_on();
/*
* We can't use local_daif_restore(regs->pstate) here as
* system_has_prio_mask_debugging() won't restore the I bit if it can

View File

@ -31,7 +31,12 @@ static inline u32 disr_to_esr(u64 disr)
return esr;
}
asmlinkage void noinstr enter_el1_irq_or_nmi(struct pt_regs *regs);
asmlinkage void noinstr exit_el1_irq_or_nmi(struct pt_regs *regs);
asmlinkage void enter_from_user_mode(void);
asmlinkage void exit_to_user_mode(void);
void arm64_enter_nmi(struct pt_regs *regs);
void arm64_exit_nmi(struct pt_regs *regs);
void do_mem_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs);
void do_undefinstr(struct pt_regs *regs);
void do_bti(struct pt_regs *regs);

View File

@ -193,6 +193,10 @@ struct pt_regs {
/* Only valid when ARM64_HAS_IRQ_PRIO_MASKING is enabled. */
u64 pmr_save;
u64 stackframe[2];
/* Only valid for some EL1 exceptions. */
u64 lockdep_hardirqs;
u64 exit_rcu;
};
static inline bool in_syscall(struct pt_regs const *regs)

View File

@ -987,7 +987,7 @@
#define SYS_TFSR_EL1_TF0_SHIFT 0
#define SYS_TFSR_EL1_TF1_SHIFT 1
#define SYS_TFSR_EL1_TF0 (UL(1) << SYS_TFSR_EL1_TF0_SHIFT)
#define SYS_TFSR_EL1_TF1 (UK(2) << SYS_TFSR_EL1_TF1_SHIFT)
#define SYS_TFSR_EL1_TF1 (UL(1) << SYS_TFSR_EL1_TF1_SHIFT)
/* Safe value for MPIDR_EL1: Bit31:RES1, Bit30:U:0, Bit24:MT:0 */
#define SYS_MPIDR_SAFE_VAL (BIT(31))

View File

@ -17,40 +17,164 @@
#include <asm/mmu.h>
#include <asm/sysreg.h>
static void notrace el1_abort(struct pt_regs *regs, unsigned long esr)
/*
* This is intended to match the logic in irqentry_enter(), handling the kernel
* mode transitions only.
*/
static void noinstr enter_from_kernel_mode(struct pt_regs *regs)
{
regs->exit_rcu = false;
if (!IS_ENABLED(CONFIG_TINY_RCU) && is_idle_task(current)) {
lockdep_hardirqs_off(CALLER_ADDR0);
rcu_irq_enter();
trace_hardirqs_off_finish();
regs->exit_rcu = true;
return;
}
lockdep_hardirqs_off(CALLER_ADDR0);
rcu_irq_enter_check_tick();
trace_hardirqs_off_finish();
}
/*
* This is intended to match the logic in irqentry_exit(), handling the kernel
* mode transitions only, and with preemption handled elsewhere.
*/
static void noinstr exit_to_kernel_mode(struct pt_regs *regs)
{
lockdep_assert_irqs_disabled();
if (interrupts_enabled(regs)) {
if (regs->exit_rcu) {
trace_hardirqs_on_prepare();
lockdep_hardirqs_on_prepare(CALLER_ADDR0);
rcu_irq_exit();
lockdep_hardirqs_on(CALLER_ADDR0);
return;
}
trace_hardirqs_on();
} else {
if (regs->exit_rcu)
rcu_irq_exit();
}
}
void noinstr arm64_enter_nmi(struct pt_regs *regs)
{
regs->lockdep_hardirqs = lockdep_hardirqs_enabled();
__nmi_enter();
lockdep_hardirqs_off(CALLER_ADDR0);
lockdep_hardirq_enter();
rcu_nmi_enter();
trace_hardirqs_off_finish();
ftrace_nmi_enter();
}
void noinstr arm64_exit_nmi(struct pt_regs *regs)
{
bool restore = regs->lockdep_hardirqs;
ftrace_nmi_exit();
if (restore) {
trace_hardirqs_on_prepare();
lockdep_hardirqs_on_prepare(CALLER_ADDR0);
}
rcu_nmi_exit();
lockdep_hardirq_exit();
if (restore)
lockdep_hardirqs_on(CALLER_ADDR0);
__nmi_exit();
}
asmlinkage void noinstr enter_el1_irq_or_nmi(struct pt_regs *regs)
{
if (IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && !interrupts_enabled(regs))
arm64_enter_nmi(regs);
else
enter_from_kernel_mode(regs);
}
asmlinkage void noinstr exit_el1_irq_or_nmi(struct pt_regs *regs)
{
if (IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && !interrupts_enabled(regs))
arm64_exit_nmi(regs);
else
exit_to_kernel_mode(regs);
}
static void noinstr el1_abort(struct pt_regs *regs, unsigned long esr)
{
unsigned long far = read_sysreg(far_el1);
enter_from_kernel_mode(regs);
local_daif_inherit(regs);
far = untagged_addr(far);
do_mem_abort(far, esr, regs);
local_daif_mask();
exit_to_kernel_mode(regs);
}
NOKPROBE_SYMBOL(el1_abort);
static void notrace el1_pc(struct pt_regs *regs, unsigned long esr)
static void noinstr el1_pc(struct pt_regs *regs, unsigned long esr)
{
unsigned long far = read_sysreg(far_el1);
enter_from_kernel_mode(regs);
local_daif_inherit(regs);
do_sp_pc_abort(far, esr, regs);
local_daif_mask();
exit_to_kernel_mode(regs);
}
NOKPROBE_SYMBOL(el1_pc);
static void notrace el1_undef(struct pt_regs *regs)
static void noinstr el1_undef(struct pt_regs *regs)
{
enter_from_kernel_mode(regs);
local_daif_inherit(regs);
do_undefinstr(regs);
local_daif_mask();
exit_to_kernel_mode(regs);
}
NOKPROBE_SYMBOL(el1_undef);
static void notrace el1_inv(struct pt_regs *regs, unsigned long esr)
static void noinstr el1_inv(struct pt_regs *regs, unsigned long esr)
{
enter_from_kernel_mode(regs);
local_daif_inherit(regs);
bad_mode(regs, 0, esr);
local_daif_mask();
exit_to_kernel_mode(regs);
}
NOKPROBE_SYMBOL(el1_inv);
static void notrace el1_dbg(struct pt_regs *regs, unsigned long esr)
static void noinstr arm64_enter_el1_dbg(struct pt_regs *regs)
{
regs->lockdep_hardirqs = lockdep_hardirqs_enabled();
lockdep_hardirqs_off(CALLER_ADDR0);
rcu_nmi_enter();
trace_hardirqs_off_finish();
}
static void noinstr arm64_exit_el1_dbg(struct pt_regs *regs)
{
bool restore = regs->lockdep_hardirqs;
if (restore) {
trace_hardirqs_on_prepare();
lockdep_hardirqs_on_prepare(CALLER_ADDR0);
}
rcu_nmi_exit();
if (restore)
lockdep_hardirqs_on(CALLER_ADDR0);
}
static void noinstr el1_dbg(struct pt_regs *regs, unsigned long esr)
{
unsigned long far = read_sysreg(far_el1);
@ -62,18 +186,21 @@ static void notrace el1_dbg(struct pt_regs *regs, unsigned long esr)
if (system_uses_irq_prio_masking())
gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET);
arm64_enter_el1_dbg(regs);
do_debug_exception(far, esr, regs);
arm64_exit_el1_dbg(regs);
}
NOKPROBE_SYMBOL(el1_dbg);
static void notrace el1_fpac(struct pt_regs *regs, unsigned long esr)
static void noinstr el1_fpac(struct pt_regs *regs, unsigned long esr)
{
enter_from_kernel_mode(regs);
local_daif_inherit(regs);
do_ptrauth_fault(regs, esr);
local_daif_mask();
exit_to_kernel_mode(regs);
}
NOKPROBE_SYMBOL(el1_fpac);
asmlinkage void notrace el1_sync_handler(struct pt_regs *regs)
asmlinkage void noinstr el1_sync_handler(struct pt_regs *regs)
{
unsigned long esr = read_sysreg(esr_el1);
@ -106,20 +233,34 @@ asmlinkage void notrace el1_sync_handler(struct pt_regs *regs)
el1_inv(regs, esr);
}
}
NOKPROBE_SYMBOL(el1_sync_handler);
static void notrace el0_da(struct pt_regs *regs, unsigned long esr)
asmlinkage void noinstr enter_from_user_mode(void)
{
lockdep_hardirqs_off(CALLER_ADDR0);
CT_WARN_ON(ct_state() != CONTEXT_USER);
user_exit_irqoff();
trace_hardirqs_off_finish();
}
asmlinkage void noinstr exit_to_user_mode(void)
{
trace_hardirqs_on_prepare();
lockdep_hardirqs_on_prepare(CALLER_ADDR0);
user_enter_irqoff();
lockdep_hardirqs_on(CALLER_ADDR0);
}
static void noinstr el0_da(struct pt_regs *regs, unsigned long esr)
{
unsigned long far = read_sysreg(far_el1);
user_exit_irqoff();
enter_from_user_mode();
local_daif_restore(DAIF_PROCCTX);
far = untagged_addr(far);
do_mem_abort(far, esr, regs);
}
NOKPROBE_SYMBOL(el0_da);
static void notrace el0_ia(struct pt_regs *regs, unsigned long esr)
static void noinstr el0_ia(struct pt_regs *regs, unsigned long esr)
{
unsigned long far = read_sysreg(far_el1);
@ -131,90 +272,80 @@ static void notrace el0_ia(struct pt_regs *regs, unsigned long esr)
if (!is_ttbr0_addr(far))
arm64_apply_bp_hardening();
user_exit_irqoff();
enter_from_user_mode();
local_daif_restore(DAIF_PROCCTX);
do_mem_abort(far, esr, regs);
}
NOKPROBE_SYMBOL(el0_ia);
static void notrace el0_fpsimd_acc(struct pt_regs *regs, unsigned long esr)
static void noinstr el0_fpsimd_acc(struct pt_regs *regs, unsigned long esr)
{
user_exit_irqoff();
enter_from_user_mode();
local_daif_restore(DAIF_PROCCTX);
do_fpsimd_acc(esr, regs);
}
NOKPROBE_SYMBOL(el0_fpsimd_acc);
static void notrace el0_sve_acc(struct pt_regs *regs, unsigned long esr)
static void noinstr el0_sve_acc(struct pt_regs *regs, unsigned long esr)
{
user_exit_irqoff();
enter_from_user_mode();
local_daif_restore(DAIF_PROCCTX);
do_sve_acc(esr, regs);
}
NOKPROBE_SYMBOL(el0_sve_acc);
static void notrace el0_fpsimd_exc(struct pt_regs *regs, unsigned long esr)
static void noinstr el0_fpsimd_exc(struct pt_regs *regs, unsigned long esr)
{
user_exit_irqoff();
enter_from_user_mode();
local_daif_restore(DAIF_PROCCTX);
do_fpsimd_exc(esr, regs);
}
NOKPROBE_SYMBOL(el0_fpsimd_exc);
static void notrace el0_sys(struct pt_regs *regs, unsigned long esr)
static void noinstr el0_sys(struct pt_regs *regs, unsigned long esr)
{
user_exit_irqoff();
enter_from_user_mode();
local_daif_restore(DAIF_PROCCTX);
do_sysinstr(esr, regs);
}
NOKPROBE_SYMBOL(el0_sys);
static void notrace el0_pc(struct pt_regs *regs, unsigned long esr)
static void noinstr el0_pc(struct pt_regs *regs, unsigned long esr)
{
unsigned long far = read_sysreg(far_el1);
if (!is_ttbr0_addr(instruction_pointer(regs)))
arm64_apply_bp_hardening();
user_exit_irqoff();
enter_from_user_mode();
local_daif_restore(DAIF_PROCCTX);
do_sp_pc_abort(far, esr, regs);
}
NOKPROBE_SYMBOL(el0_pc);
static void notrace el0_sp(struct pt_regs *regs, unsigned long esr)
static void noinstr el0_sp(struct pt_regs *regs, unsigned long esr)
{
user_exit_irqoff();
enter_from_user_mode();
local_daif_restore(DAIF_PROCCTX);
do_sp_pc_abort(regs->sp, esr, regs);
}
NOKPROBE_SYMBOL(el0_sp);
static void notrace el0_undef(struct pt_regs *regs)
static void noinstr el0_undef(struct pt_regs *regs)
{
user_exit_irqoff();
enter_from_user_mode();
local_daif_restore(DAIF_PROCCTX);
do_undefinstr(regs);
}
NOKPROBE_SYMBOL(el0_undef);
static void notrace el0_bti(struct pt_regs *regs)
static void noinstr el0_bti(struct pt_regs *regs)
{
user_exit_irqoff();
enter_from_user_mode();
local_daif_restore(DAIF_PROCCTX);
do_bti(regs);
}
NOKPROBE_SYMBOL(el0_bti);
static void notrace el0_inv(struct pt_regs *regs, unsigned long esr)
static void noinstr el0_inv(struct pt_regs *regs, unsigned long esr)
{
user_exit_irqoff();
enter_from_user_mode();
local_daif_restore(DAIF_PROCCTX);
bad_el0_sync(regs, 0, esr);
}
NOKPROBE_SYMBOL(el0_inv);
static void notrace el0_dbg(struct pt_regs *regs, unsigned long esr)
static void noinstr el0_dbg(struct pt_regs *regs, unsigned long esr)
{
/* Only watchpoints write FAR_EL1, otherwise its UNKNOWN */
unsigned long far = read_sysreg(far_el1);
@ -222,30 +353,28 @@ static void notrace el0_dbg(struct pt_regs *regs, unsigned long esr)
if (system_uses_irq_prio_masking())
gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET);
user_exit_irqoff();
enter_from_user_mode();
do_debug_exception(far, esr, regs);
local_daif_restore(DAIF_PROCCTX_NOIRQ);
}
NOKPROBE_SYMBOL(el0_dbg);
static void notrace el0_svc(struct pt_regs *regs)
static void noinstr el0_svc(struct pt_regs *regs)
{
if (system_uses_irq_prio_masking())
gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET);
enter_from_user_mode();
do_el0_svc(regs);
}
NOKPROBE_SYMBOL(el0_svc);
static void notrace el0_fpac(struct pt_regs *regs, unsigned long esr)
static void noinstr el0_fpac(struct pt_regs *regs, unsigned long esr)
{
user_exit_irqoff();
enter_from_user_mode();
local_daif_restore(DAIF_PROCCTX);
do_ptrauth_fault(regs, esr);
}
NOKPROBE_SYMBOL(el0_fpac);
asmlinkage void notrace el0_sync_handler(struct pt_regs *regs)
asmlinkage void noinstr el0_sync_handler(struct pt_regs *regs)
{
unsigned long esr = read_sysreg(esr_el1);
@ -297,27 +426,25 @@ asmlinkage void notrace el0_sync_handler(struct pt_regs *regs)
el0_inv(regs, esr);
}
}
NOKPROBE_SYMBOL(el0_sync_handler);
#ifdef CONFIG_COMPAT
static void notrace el0_cp15(struct pt_regs *regs, unsigned long esr)
static void noinstr el0_cp15(struct pt_regs *regs, unsigned long esr)
{
user_exit_irqoff();
enter_from_user_mode();
local_daif_restore(DAIF_PROCCTX);
do_cp15instr(esr, regs);
}
NOKPROBE_SYMBOL(el0_cp15);
static void notrace el0_svc_compat(struct pt_regs *regs)
static void noinstr el0_svc_compat(struct pt_regs *regs)
{
if (system_uses_irq_prio_masking())
gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET);
enter_from_user_mode();
do_el0_svc_compat(regs);
}
NOKPROBE_SYMBOL(el0_svc_compat);
asmlinkage void notrace el0_sync_compat_handler(struct pt_regs *regs)
asmlinkage void noinstr el0_sync_compat_handler(struct pt_regs *regs)
{
unsigned long esr = read_sysreg(esr_el1);
@ -360,5 +487,4 @@ asmlinkage void notrace el0_sync_compat_handler(struct pt_regs *regs)
el0_inv(regs, esr);
}
}
NOKPROBE_SYMBOL(el0_sync_compat_handler);
#endif /* CONFIG_COMPAT */

View File

@ -30,18 +30,18 @@
#include <asm/unistd.h>
/*
* Context tracking subsystem. Used to instrument transitions
* between user and kernel mode.
* Context tracking and irqflag tracing need to instrument transitions between
* user and kernel mode.
*/
.macro ct_user_exit_irqoff
#ifdef CONFIG_CONTEXT_TRACKING
.macro user_exit_irqoff
#if defined(CONFIG_CONTEXT_TRACKING) || defined(CONFIG_TRACE_IRQFLAGS)
bl enter_from_user_mode
#endif
.endm
.macro ct_user_enter
#ifdef CONFIG_CONTEXT_TRACKING
bl context_tracking_user_enter
.macro user_enter_irqoff
#if defined(CONFIG_CONTEXT_TRACKING) || defined(CONFIG_TRACE_IRQFLAGS)
bl exit_to_user_mode
#endif
.endm
@ -298,9 +298,6 @@ alternative_if ARM64_HAS_IRQ_PRIO_MASKING
alternative_else_nop_endif
ldp x21, x22, [sp, #S_PC] // load ELR, SPSR
.if \el == 0
ct_user_enter
.endif
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
alternative_if_not ARM64_HAS_PAN
@ -637,16 +634,8 @@ SYM_CODE_START_LOCAL_NOALIGN(el1_irq)
gic_prio_irq_setup pmr=x20, tmp=x1
enable_da_f
#ifdef CONFIG_ARM64_PSEUDO_NMI
test_irqs_unmasked res=x0, pmr=x20
cbz x0, 1f
bl asm_nmi_enter
1:
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_off
#endif
mov x0, sp
bl enter_el1_irq_or_nmi
irq_handler
@ -665,26 +654,8 @@ alternative_else_nop_endif
1:
#endif
#ifdef CONFIG_ARM64_PSEUDO_NMI
/*
* When using IRQ priority masking, we can get spurious interrupts while
* PMR is set to GIC_PRIO_IRQOFF. An NMI might also have occurred in a
* section with interrupts disabled. Skip tracing in those cases.
*/
test_irqs_unmasked res=x0, pmr=x20
cbz x0, 1f
bl asm_nmi_exit
1:
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
#ifdef CONFIG_ARM64_PSEUDO_NMI
test_irqs_unmasked res=x0, pmr=x20
cbnz x0, 1f
#endif
bl trace_hardirqs_on
1:
#endif
mov x0, sp
bl exit_el1_irq_or_nmi
kernel_exit 1
SYM_CODE_END(el1_irq)
@ -726,21 +697,14 @@ SYM_CODE_START_LOCAL_NOALIGN(el0_irq)
kernel_entry 0
el0_irq_naked:
gic_prio_irq_setup pmr=x20, tmp=x0
ct_user_exit_irqoff
user_exit_irqoff
enable_da_f
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_off
#endif
tbz x22, #55, 1f
bl do_el0_irq_bp_hardening
1:
irq_handler
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_on
#endif
b ret_to_user
SYM_CODE_END(el0_irq)
@ -759,7 +723,7 @@ SYM_CODE_START_LOCAL(el0_error)
el0_error_naked:
mrs x25, esr_el1
gic_prio_kentry_setup tmp=x2
ct_user_exit_irqoff
user_exit_irqoff
enable_dbg
mov x0, sp
mov x1, x25
@ -774,13 +738,17 @@ SYM_CODE_END(el0_error)
SYM_CODE_START_LOCAL(ret_to_user)
disable_daif
gic_prio_kentry_setup tmp=x3
ldr x1, [tsk, #TSK_TI_FLAGS]
and x2, x1, #_TIF_WORK_MASK
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_off
#endif
ldr x19, [tsk, #TSK_TI_FLAGS]
and x2, x19, #_TIF_WORK_MASK
cbnz x2, work_pending
finish_ret_to_user:
user_enter_irqoff
/* Ignore asynchronous tag check faults in the uaccess routines */
clear_mte_async_tcf
enable_step_tsk x1, x2
enable_step_tsk x19, x2
#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
bl stackleak_erase
#endif
@ -791,11 +759,9 @@ finish_ret_to_user:
*/
work_pending:
mov x0, sp // 'regs'
mov x1, x19
bl do_notify_resume
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_on // enabled while in userspace
#endif
ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for single-step
ldr x19, [tsk, #TSK_TI_FLAGS] // re-check for single-step
b finish_ret_to_user
SYM_CODE_END(ret_to_user)

View File

@ -67,18 +67,3 @@ void __init init_IRQ(void)
local_daif_restore(DAIF_PROCCTX_NOIRQ);
}
}
/*
* Stubs to make nmi_enter/exit() code callable from ASM
*/
asmlinkage void notrace asm_nmi_enter(void)
{
nmi_enter();
}
NOKPROBE_SYMBOL(asm_nmi_enter);
asmlinkage void notrace asm_nmi_exit(void)
{
nmi_exit();
}
NOKPROBE_SYMBOL(asm_nmi_exit);

View File

@ -72,13 +72,13 @@ EXPORT_SYMBOL_GPL(pm_power_off);
void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
static void __cpu_do_idle(void)
static void noinstr __cpu_do_idle(void)
{
dsb(sy);
wfi();
}
static void __cpu_do_idle_irqprio(void)
static void noinstr __cpu_do_idle_irqprio(void)
{
unsigned long pmr;
unsigned long daif_bits;
@ -108,7 +108,7 @@ static void __cpu_do_idle_irqprio(void)
* ensure that interrupts are not masked at the PMR (because the core will
* not wake up if we block the wake up signal in the interrupt controller).
*/
void cpu_do_idle(void)
void noinstr cpu_do_idle(void)
{
if (system_uses_irq_prio_masking())
__cpu_do_idle_irqprio();
@ -119,7 +119,7 @@ void cpu_do_idle(void)
/*
* This is our default idle handler.
*/
void arch_cpu_idle(void)
void noinstr arch_cpu_idle(void)
{
/*
* This should do all the clock switching and wait for interrupt

View File

@ -10,6 +10,7 @@
#include <linux/uaccess.h>
#include <asm/alternative.h>
#include <asm/exception.h>
#include <asm/kprobes.h>
#include <asm/mmu.h>
#include <asm/ptrace.h>
@ -223,16 +224,16 @@ static __kprobes unsigned long _sdei_handler(struct pt_regs *regs,
}
asmlinkage __kprobes notrace unsigned long
asmlinkage noinstr unsigned long
__sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
{
unsigned long ret;
nmi_enter();
arm64_enter_nmi(regs);
ret = _sdei_handler(regs, arg);
nmi_exit();
arm64_exit_nmi(regs);
return ret;
}

View File

@ -121,7 +121,6 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
cortex_a76_erratum_1463225_svc_handler();
local_daif_restore(DAIF_PROCCTX);
user_exit();
if (system_supports_mte() && (flags & _TIF_MTE_ASYNC_FAULT)) {
/*

View File

@ -34,6 +34,7 @@
#include <asm/daifflags.h>
#include <asm/debug-monitors.h>
#include <asm/esr.h>
#include <asm/exception.h>
#include <asm/extable.h>
#include <asm/insn.h>
#include <asm/kprobes.h>
@ -753,8 +754,10 @@ const char *esr_get_class_string(u32 esr)
* bad_mode handles the impossible case in the exception vector. This is always
* fatal.
*/
asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
asmlinkage void notrace bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
{
arm64_enter_nmi(regs);
console_verbose();
pr_crit("Bad mode in %s handler detected on CPU%d, code 0x%08x -- %s\n",
@ -786,7 +789,7 @@ void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr)
DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack)
__aligned(16);
asmlinkage void handle_bad_stack(struct pt_regs *regs)
asmlinkage void noinstr handle_bad_stack(struct pt_regs *regs)
{
unsigned long tsk_stk = (unsigned long)current->stack;
unsigned long irq_stk = (unsigned long)this_cpu_read(irq_stack_ptr);
@ -794,6 +797,8 @@ asmlinkage void handle_bad_stack(struct pt_regs *regs)
unsigned int esr = read_sysreg(esr_el1);
unsigned long far = read_sysreg(far_el1);
arm64_enter_nmi(regs);
console_verbose();
pr_emerg("Insufficient stack space to handle exception!");
@ -865,24 +870,17 @@ bool arm64_is_fatal_ras_serror(struct pt_regs *regs, unsigned int esr)
}
}
asmlinkage void do_serror(struct pt_regs *regs, unsigned int esr)
asmlinkage void noinstr do_serror(struct pt_regs *regs, unsigned int esr)
{
nmi_enter();
arm64_enter_nmi(regs);
/* non-RAS errors are not containable */
if (!arm64_is_ras_serror(esr) || arm64_is_fatal_ras_serror(regs, esr))
arm64_serror_panic(regs, esr);
nmi_exit();
arm64_exit_nmi(regs);
}
asmlinkage void enter_from_user_mode(void)
{
CT_WARN_ON(ct_state() != CONTEXT_USER);
user_exit_irqoff();
}
NOKPROBE_SYMBOL(enter_from_user_mode);
/* GENERIC_BUG traps */
int is_valid_bugaddr(unsigned long addr)

View File

@ -789,25 +789,6 @@ void __init hook_debug_fault_code(int nr,
*/
static void debug_exception_enter(struct pt_regs *regs)
{
/*
* Tell lockdep we disabled irqs in entry.S. Do nothing if they were
* already disabled to preserve the last enabled/disabled addresses.
*/
if (interrupts_enabled(regs))
trace_hardirqs_off();
if (user_mode(regs)) {
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
} else {
/*
* We might have interrupted pretty much anything. In
* fact, if we're a debug exception, we can even interrupt
* NMI processing. We don't want this code makes in_nmi()
* to return true, but we need to notify RCU.
*/
rcu_nmi_enter();
}
preempt_disable();
/* This code is a bit fragile. Test it. */
@ -818,12 +799,6 @@ NOKPROBE_SYMBOL(debug_exception_enter);
static void debug_exception_exit(struct pt_regs *regs)
{
preempt_enable_no_resched();
if (!user_mode(regs))
rcu_nmi_exit();
if (interrupts_enabled(regs))
trace_hardirqs_on();
}
NOKPROBE_SYMBOL(debug_exception_exit);

View File

@ -152,6 +152,7 @@ config PPC
select ARCH_USE_QUEUED_SPINLOCKS if PPC_QUEUED_SPINLOCKS
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_WANT_IRQS_OFF_ACTIVATE_MM
select ARCH_WANT_LD_ORPHAN_WARN
select ARCH_WEAK_RELEASE_ACQUIRE
select BINFMT_ELF
select BUILDTIME_TABLE_SORT

View File

@ -123,7 +123,6 @@ endif
LDFLAGS_vmlinux-y := -Bstatic
LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) := -pie
LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-y)
LDFLAGS_vmlinux += $(call ld-option,--orphan-handling=warn)
ifdef CONFIG_PPC64
ifeq ($(call cc-option-yn,-mcmodel=medium),y)

View File

@ -242,6 +242,18 @@ extern void radix_init_pseries(void);
static inline void radix_init_pseries(void) { };
#endif
#ifdef CONFIG_HOTPLUG_CPU
#define arch_clear_mm_cpumask_cpu(cpu, mm) \
do { \
if (cpumask_test_cpu(cpu, mm_cpumask(mm))) { \
atomic_dec(&(mm)->context.active_cpus); \
cpumask_clear_cpu(cpu, mm_cpumask(mm)); \
} \
} while (0)
void cleanup_cpu_mmu_context(void);
#endif
static inline int get_user_context(mm_context_t *ctx, unsigned long ea)
{
int index = ea >> MAX_EA_BITS_PER_CONTEXT;

View File

@ -1214,12 +1214,9 @@ void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu)
static bool kvmppc_xive_vcpu_id_valid(struct kvmppc_xive *xive, u32 cpu)
{
/* We have a block of xive->nr_servers VPs. We just need to check
* raw vCPU ids are below the expected limit for this guest's
* core stride ; kvmppc_pack_vcpu_id() will pack them down to an
* index that can be safely used to compute a VP id that belongs
* to the VP block.
* packed vCPU ids are below that.
*/
return cpu < xive->nr_servers * xive->kvm->arch.emul_smt_mode;
return kvmppc_pack_vcpu_id(xive->kvm, cpu) < xive->nr_servers;
}
int kvmppc_xive_compute_vp_id(struct kvmppc_xive *xive, u32 cpu, u32 *vp)

View File

@ -68,7 +68,7 @@ static __always_inline void tlbiel_hash_set_isa300(unsigned int set, unsigned in
rs = ((unsigned long)pid << PPC_BITLSHIFT(31));
asm volatile(PPC_TLBIEL(%0, %1, %2, %3, %4)
: : "r"(rb), "r"(rs), "i"(ric), "i"(prs), "r"(r)
: : "r"(rb), "r"(rs), "i"(ric), "i"(prs), "i"(r)
: "memory");
}
@ -92,16 +92,15 @@ static void tlbiel_all_isa300(unsigned int num_sets, unsigned int is)
asm volatile("ptesync": : :"memory");
/*
* Flush the first set of the TLB, and any caching of partition table
* entries. Then flush the remaining sets of the TLB. Hash mode uses
* partition scoped TLB translations.
* Flush the partition table cache if this is HV mode.
*/
tlbiel_hash_set_isa300(0, is, 0, 2, 0);
for (set = 1; set < num_sets; set++)
tlbiel_hash_set_isa300(set, is, 0, 0, 0);
if (early_cpu_has_feature(CPU_FTR_HVMODE))
tlbiel_hash_set_isa300(0, is, 0, 2, 0);
/*
* Now invalidate the process table cache.
* Now invalidate the process table cache. UPRT=0 HPT modes (what
* current hardware implements) do not use the process table, but
* add the flushes anyway.
*
* From ISA v3.0B p. 1078:
* The following forms are invalid.
@ -110,6 +109,14 @@ static void tlbiel_all_isa300(unsigned int num_sets, unsigned int is)
*/
tlbiel_hash_set_isa300(0, is, 0, 2, 1);
/*
* Then flush the sets of the TLB proper. Hash mode uses
* partition scoped TLB translations, which may be flushed
* in !HV mode.
*/
for (set = 0; set < num_sets; set++)
tlbiel_hash_set_isa300(set, is, 0, 0, 0);
ppc_after_tlbiel_barrier();
asm volatile(PPC_ISA_3_0_INVALIDATE_ERAT "; isync" : : :"memory");

View File

@ -17,6 +17,7 @@
#include <linux/export.h>
#include <linux/gfp.h>
#include <linux/slab.h>
#include <linux/cpu.h>
#include <asm/mmu_context.h>
#include <asm/pgalloc.h>
@ -307,3 +308,22 @@ void radix__switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
isync();
}
#endif
/**
* cleanup_cpu_mmu_context - Clean up MMU details for this CPU (newly offlined)
*
* This clears the CPU from mm_cpumask for all processes, and then flushes the
* local TLB to ensure TLB coherency in case the CPU is onlined again.
*
* KVM guest translations are not necessarily flushed here. If KVM started
* using mm_cpumask or the Linux APIs which do, this would have to be resolved.
*/
#ifdef CONFIG_HOTPLUG_CPU
void cleanup_cpu_mmu_context(void)
{
int cpu = smp_processor_id();
clear_tasks_mm_cpumask(cpu);
tlbiel_all();
}
#endif

View File

@ -742,8 +742,7 @@ static int __init parse_numa_properties(void)
of_node_put(cpu);
}
if (likely(nid > 0))
node_set_online(nid);
node_set_online(nid);
}
get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells);

View File

@ -911,6 +911,8 @@ static int smp_core99_cpu_disable(void)
mpic_cpu_set_priority(0xf);
cleanup_cpu_mmu_context();
return 0;
}

View File

@ -211,11 +211,16 @@ static void __init pnv_init(void)
add_preferred_console("hvc", 0, NULL);
if (!radix_enabled()) {
size_t size = sizeof(struct slb_entry) * mmu_slb_size;
int i;
/* Allocate per cpu area to save old slb contents during MCE */
for_each_possible_cpu(i)
paca_ptrs[i]->mce_faulty_slbs = memblock_alloc_node(mmu_slb_size, __alignof__(*paca_ptrs[i]->mce_faulty_slbs), cpu_to_node(i));
for_each_possible_cpu(i) {
paca_ptrs[i]->mce_faulty_slbs =
memblock_alloc_node(size,
__alignof__(struct slb_entry),
cpu_to_node(i));
}
}
}

View File

@ -143,6 +143,9 @@ static int pnv_smp_cpu_disable(void)
xive_smp_disable_cpu();
else
xics_migrate_irqs_away();
cleanup_cpu_mmu_context();
return 0;
}

View File

@ -90,6 +90,9 @@ static int pseries_cpu_disable(void)
xive_smp_disable_cpu();
else
xics_migrate_irqs_away();
cleanup_cpu_mmu_context();
return 0;
}

View File

@ -458,7 +458,8 @@ again:
return hwirq;
}
virq = irq_create_mapping(NULL, hwirq);
virq = irq_create_mapping_affinity(NULL, hwirq,
entry->affinity);
if (!virq) {
pr_debug("rtas_msi: Failed mapping hwirq %d\n", hwirq);

View File

@ -763,12 +763,7 @@ ENTRY(io_int_handler)
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
TSTMSK __LC_CPU_FLAGS,_CIF_IGNORE_IRQ
jo .Lio_restore
#if IS_ENABLED(CONFIG_TRACE_IRQFLAGS)
tmhh %r8,0x300
jz 1f
TRACE_IRQS_OFF
1:
#endif
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
.Lio_loop:
lgr %r2,%r11 # pass pointer to pt_regs
@ -791,12 +786,7 @@ ENTRY(io_int_handler)
TSTMSK __LC_CPU_FLAGS,_CIF_WORK
jnz .Lio_work
.Lio_restore:
#if IS_ENABLED(CONFIG_TRACE_IRQFLAGS)
tm __PT_PSW(%r11),3
jno 0f
TRACE_IRQS_ON
0:
#endif
mvc __LC_RETURN_PSW(16),__PT_PSW(%r11)
tm __PT_PSW+1(%r11),0x01 # returning to user ?
jno .Lio_exit_kernel
@ -976,12 +966,7 @@ ENTRY(ext_int_handler)
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
TSTMSK __LC_CPU_FLAGS,_CIF_IGNORE_IRQ
jo .Lio_restore
#if IS_ENABLED(CONFIG_TRACE_IRQFLAGS)
tmhh %r8,0x300
jz 1f
TRACE_IRQS_OFF
1:
#endif
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
lgr %r2,%r11 # pass pointer to pt_regs
lghi %r3,EXT_INTERRUPT

View File

@ -33,7 +33,7 @@ EXPORT_SYMBOL(__delay);
static void __udelay_disabled(unsigned long long usecs)
{
unsigned long cr0, cr0_new, psw_mask, flags;
unsigned long cr0, cr0_new, psw_mask;
struct s390_idle_data idle;
u64 end;
@ -45,9 +45,8 @@ static void __udelay_disabled(unsigned long long usecs)
psw_mask = __extract_psw() | PSW_MASK_EXT | PSW_MASK_WAIT;
set_clock_comparator(end);
set_cpu_flag(CIF_IGNORE_IRQ);
local_irq_save(flags);
psw_idle(&idle, psw_mask);
local_irq_restore(flags);
trace_hardirqs_off();
clear_cpu_flag(CIF_IGNORE_IRQ);
set_clock_comparator(S390_lowcore.clock_comparator);
__ctl_load(cr0, 0, 0);

View File

@ -103,9 +103,10 @@ static int zpci_set_irq_affinity(struct irq_data *data, const struct cpumask *de
{
struct msi_desc *entry = irq_get_msi_desc(data->irq);
struct msi_msg msg = entry->msg;
int cpu_addr = smp_cpu_get_cpu_address(cpumask_first(dest));
msg.address_lo &= 0xff0000ff;
msg.address_lo |= (cpumask_first(dest) << 8);
msg.address_lo |= (cpu_addr << 8);
pci_write_msi_msg(data->irq, &msg);
return IRQ_SET_MASK_OK;
@ -238,6 +239,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
unsigned long bit;
struct msi_desc *msi;
struct msi_msg msg;
int cpu_addr;
int rc, irq;
zdev->aisb = -1UL;
@ -287,9 +289,15 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
handle_percpu_irq);
msg.data = hwirq - bit;
if (irq_delivery == DIRECTED) {
if (msi->affinity)
cpu = cpumask_first(&msi->affinity->mask);
else
cpu = 0;
cpu_addr = smp_cpu_get_cpu_address(cpu);
msg.address_lo = zdev->msi_addr & 0xff0000ff;
msg.address_lo |= msi->affinity ?
(cpumask_first(&msi->affinity->mask) << 8) : 0;
msg.address_lo |= (cpu_addr << 8);
for_each_possible_cpu(cpu) {
airq_iv_set_data(zpci_ibv[cpu], hwirq, irq);
}

View File

@ -100,6 +100,7 @@ config X86
select ARCH_WANT_DEFAULT_BPF_JIT if X86_64
select ARCH_WANTS_DYNAMIC_TASK_STRUCT
select ARCH_WANT_HUGE_PMD_SHARE
select ARCH_WANT_LD_ORPHAN_WARN
select ARCH_WANTS_THP_SWAP if X86_64
select BUILDTIME_TABLE_SORT
select CLKEVT_I8253

View File

@ -209,9 +209,6 @@ ifdef CONFIG_X86_64
LDFLAGS_vmlinux += -z max-page-size=0x200000
endif
# We never want expected sections to be placed heuristically by the
# linker. All sections should be explicitly named in the linker script.
LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn)
archscripts: scripts_basic
$(Q)$(MAKE) $(build)=arch/x86/tools relocs

View File

@ -61,7 +61,9 @@ KBUILD_LDFLAGS += $(call ld-option,--no-ld-generated-unwind-info)
# Compressed kernel should be built as PIE since it may be loaded at any
# address by the bootloader.
LDFLAGS_vmlinux := -pie $(call ld-option, --no-dynamic-linker)
LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn)
ifdef CONFIG_LD_ORPHAN_WARN
LDFLAGS_vmlinux += --orphan-handling=warn
endif
LDFLAGS_vmlinux += -T
hostprogs := mkpiggy

View File

@ -32,13 +32,12 @@ struct ghcb *boot_ghcb;
*/
static bool insn_has_rep_prefix(struct insn *insn)
{
insn_byte_t p;
int i;
insn_get_prefixes(insn);
for (i = 0; i < insn->prefixes.nbytes; i++) {
insn_byte_t p = insn->prefixes.bytes[i];
for_each_insn_prefix(insn, i, p) {
if (p == 0xf2 || p == 0xf3)
return true;
}

View File

@ -1916,7 +1916,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs, struct perf_sample_d
* that caused the PEBS record. It's called collision.
* If collision happened, the record will be dropped.
*/
if (p->status != (1ULL << bit)) {
if (pebs_status != (1ULL << bit)) {
for_each_set_bit(i, (unsigned long *)&pebs_status, size)
error[i]++;
continue;
@ -1940,7 +1940,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs, struct perf_sample_d
if (error[bit]) {
perf_log_lost_samples(event, error[bit]);
if (perf_event_account_interrupt(event))
if (iregs && perf_event_account_interrupt(event))
x86_pmu_stop(event, 0);
}

View File

@ -201,6 +201,21 @@ static inline int insn_offset_immediate(struct insn *insn)
return insn_offset_displacement(insn) + insn->displacement.nbytes;
}
/**
* for_each_insn_prefix() -- Iterate prefixes in the instruction
* @insn: Pointer to struct insn.
* @idx: Index storage.
* @prefix: Prefix byte.
*
* Iterate prefix bytes of given @insn. Each prefix byte is stored in @prefix
* and the index is stored in @idx (note that this @idx is just for a cursor,
* do not change it.)
* Since prefixes.nbytes can be bigger than 4 if some prefixes
* are repeated, it cannot be used for looping over the prefixes.
*/
#define for_each_insn_prefix(insn, idx, prefix) \
for (idx = 0; idx < ARRAY_SIZE(insn->prefixes.bytes) && (prefix = insn->prefixes.bytes[idx]) != 0; idx++)
#define POP_SS_OPCODE 0x1f
#define MOV_SREG_OPCODE 0x8e

View File

@ -161,7 +161,7 @@ static int __init early_set_hub_type(void)
/* UV4/4A only have a revision difference */
case UV4_HUB_PART_NUMBER:
uv_min_hub_revision_id = node_id.s.revision
+ UV4_HUB_REVISION_BASE;
+ UV4_HUB_REVISION_BASE - 1;
uv_hub_type_set(UV4);
if (uv_min_hub_revision_id == UV4A_HUB_REVISION_BASE)
uv_hub_type_set(UV4|UV4A);

View File

@ -570,6 +570,8 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
if (d) {
cpumask_set_cpu(cpu, &d->cpu_mask);
if (r->cache.arch_has_per_cpu_cfg)
rdt_domain_reconfigure_cdp(r);
return;
}
@ -923,6 +925,7 @@ static __init void rdt_init_res_defs_intel(void)
r->rid == RDT_RESOURCE_L2CODE) {
r->cache.arch_has_sparse_bitmaps = false;
r->cache.arch_has_empty_bitmaps = false;
r->cache.arch_has_per_cpu_cfg = false;
} else if (r->rid == RDT_RESOURCE_MBA) {
r->msr_base = MSR_IA32_MBA_THRTL_BASE;
r->msr_update = mba_wrmsr_intel;
@ -943,6 +946,7 @@ static __init void rdt_init_res_defs_amd(void)
r->rid == RDT_RESOURCE_L2CODE) {
r->cache.arch_has_sparse_bitmaps = true;
r->cache.arch_has_empty_bitmaps = true;
r->cache.arch_has_per_cpu_cfg = true;
} else if (r->rid == RDT_RESOURCE_MBA) {
r->msr_base = MSR_IA32_MBA_BW_BASE;
r->msr_update = mba_wrmsr_amd;

View File

@ -360,6 +360,8 @@ struct msr_param {
* executing entities
* @arch_has_sparse_bitmaps: True if a bitmap like f00f is valid.
* @arch_has_empty_bitmaps: True if the '0' bitmap is valid.
* @arch_has_per_cpu_cfg: True if QOS_CFG register for this cache
* level has CPU scope.
*/
struct rdt_cache {
unsigned int cbm_len;
@ -369,6 +371,7 @@ struct rdt_cache {
unsigned int shareable_bits;
bool arch_has_sparse_bitmaps;
bool arch_has_empty_bitmaps;
bool arch_has_per_cpu_cfg;
};
/**

View File

@ -1909,8 +1909,13 @@ static int set_cache_qos_cfg(int level, bool enable)
r_l = &rdt_resources_all[level];
list_for_each_entry(d, &r_l->domains, list) {
/* Pick one CPU from each domain instance to update MSR */
cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
if (r_l->cache.arch_has_per_cpu_cfg)
/* Pick all the CPUs in the domain instance */
for_each_cpu(cpu, &d->cpu_mask)
cpumask_set_cpu(cpu, cpu_mask);
else
/* Pick one CPU from each domain instance to update MSR */
cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
}
cpu = get_cpu();
/* Update QOS_CFG MSR on this cpu if it's in cpu_mask. */

View File

@ -255,12 +255,13 @@ static volatile u32 good_2byte_insns[256 / 32] = {
static bool is_prefix_bad(struct insn *insn)
{
insn_byte_t p;
int i;
for (i = 0; i < insn->prefixes.nbytes; i++) {
for_each_insn_prefix(insn, i, p) {
insn_attr_t attr;
attr = inat_get_opcode_attribute(insn->prefixes.bytes[i]);
attr = inat_get_opcode_attribute(p);
switch (attr) {
case INAT_MAKE_PREFIX(INAT_PFX_ES):
case INAT_MAKE_PREFIX(INAT_PFX_CS):
@ -715,6 +716,7 @@ static const struct uprobe_xol_ops push_xol_ops = {
static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn)
{
u8 opc1 = OPCODE1(insn);
insn_byte_t p;
int i;
switch (opc1) {
@ -746,8 +748,8 @@ static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn)
* Intel and AMD behavior differ in 64-bit mode: Intel ignores 66 prefix.
* No one uses these insns, reject any branch insns with such prefix.
*/
for (i = 0; i < insn->prefixes.nbytes; i++) {
if (insn->prefixes.bytes[i] == 0x66)
for_each_insn_prefix(insn, i, p) {
if (p == 0x66)
return -ENOTSUPP;
}

View File

@ -63,13 +63,12 @@ static bool is_string_insn(struct insn *insn)
*/
bool insn_has_rep_prefix(struct insn *insn)
{
insn_byte_t p;
int i;
insn_get_prefixes(insn);
for (i = 0; i < insn->prefixes.nbytes; i++) {
insn_byte_t p = insn->prefixes.bytes[i];
for_each_insn_prefix(insn, i, p) {
if (p == 0xf2 || p == 0xf3)
return true;
}
@ -95,14 +94,15 @@ static int get_seg_reg_override_idx(struct insn *insn)
{
int idx = INAT_SEG_REG_DEFAULT;
int num_overrides = 0, i;
insn_byte_t p;
insn_get_prefixes(insn);
/* Look for any segment override prefixes. */
for (i = 0; i < insn->prefixes.nbytes; i++) {
for_each_insn_prefix(insn, i, p) {
insn_attr_t attr;
attr = inat_get_opcode_attribute(insn->prefixes.bytes[i]);
attr = inat_get_opcode_attribute(p);
switch (attr) {
case INAT_MAKE_PREFIX(INAT_PFX_CS):
idx = INAT_SEG_REG_CS;

View File

@ -144,7 +144,7 @@ static struct bio *blk_bio_write_same_split(struct request_queue *q,
static inline unsigned get_max_io_size(struct request_queue *q,
struct bio *bio)
{
unsigned sectors = blk_max_size_offset(q, bio->bi_iter.bi_sector);
unsigned sectors = blk_max_size_offset(q, bio->bi_iter.bi_sector, 0);
unsigned max_sectors = sectors;
unsigned pbs = queue_physical_block_size(q) >> SECTOR_SHIFT;
unsigned lbs = queue_logical_block_size(q) >> SECTOR_SHIFT;

View File

@ -547,7 +547,10 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
t->io_min = max(t->io_min, b->io_min);
t->io_opt = lcm_not_zero(t->io_opt, b->io_opt);
t->chunk_sectors = lcm_not_zero(t->chunk_sectors, b->chunk_sectors);
/* Set non-power-of-2 compatible chunk_sectors boundary */
if (b->chunk_sectors)
t->chunk_sectors = gcd(t->chunk_sectors, b->chunk_sectors);
/* Physical block size a multiple of the logical block size? */
if (t->physical_block_size & (t->logical_block_size - 1)) {

View File

@ -145,6 +145,7 @@ obj-$(CONFIG_OF) += of/
obj-$(CONFIG_SSB) += ssb/
obj-$(CONFIG_BCMA) += bcma/
obj-$(CONFIG_VHOST_RING) += vhost/
obj-$(CONFIG_VHOST_IOTLB) += vhost/
obj-$(CONFIG_VHOST) += vhost/
obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_GREYBUS) += greybus/

View File

@ -47,27 +47,20 @@ static int spk_ttyio_ldisc_open(struct tty_struct *tty)
{
struct spk_ldisc_data *ldisc_data;
if (tty != speakup_tty)
/* Somebody tried to use this line discipline outside speakup */
return -ENODEV;
if (!tty->ops->write)
return -EOPNOTSUPP;
mutex_lock(&speakup_tty_mutex);
if (speakup_tty) {
mutex_unlock(&speakup_tty_mutex);
return -EBUSY;
}
speakup_tty = tty;
ldisc_data = kmalloc(sizeof(*ldisc_data), GFP_KERNEL);
if (!ldisc_data) {
speakup_tty = NULL;
mutex_unlock(&speakup_tty_mutex);
if (!ldisc_data)
return -ENOMEM;
}
init_completion(&ldisc_data->completion);
ldisc_data->buf_free = true;
speakup_tty->disc_data = ldisc_data;
mutex_unlock(&speakup_tty_mutex);
tty->disc_data = ldisc_data;
return 0;
}
@ -191,9 +184,25 @@ static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
tty_unlock(tty);
mutex_lock(&speakup_tty_mutex);
speakup_tty = tty;
ret = tty_set_ldisc(tty, N_SPEAKUP);
if (ret)
pr_err("speakup: Failed to set N_SPEAKUP on tty\n");
speakup_tty = NULL;
mutex_unlock(&speakup_tty_mutex);
if (!ret)
/* Success */
return 0;
pr_err("speakup: Failed to set N_SPEAKUP on tty\n");
tty_lock(tty);
if (tty->ops->close)
tty->ops->close(tty, NULL);
tty_unlock(tty);
tty_kclose(tty);
return ret;
}

View File

@ -142,6 +142,7 @@ config FPGA_DFL
tristate "FPGA Device Feature List (DFL) support"
select FPGA_BRIDGE
select FPGA_REGION
depends on HAS_IOMEM
help
Device Feature List (DFL) defines a feature list structure that
creates a linked list of feature headers within the MMIO space

View File

@ -1011,6 +1011,11 @@ static int vcn_v3_0_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, boo
tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
WREG32_SOC15(VCN, inst_idx, mmUVD_RBC_RB_CNTL, tmp);
/* Stall DPG before WPTR/RPTR reset */
WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS),
UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK,
~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);
/* set the write pointer delay */
WREG32_SOC15(VCN, inst_idx, mmUVD_RBC_RB_WPTR_CNTL, 0);
@ -1033,6 +1038,10 @@ static int vcn_v3_0_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, boo
WREG32_SOC15(VCN, inst_idx, mmUVD_RBC_RB_WPTR,
lower_32_bits(ring->wptr));
/* Unstall DPG */
WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS),
0, ~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);
return 0;
}
@ -1556,8 +1565,14 @@ static int vcn_v3_0_pause_dpg_mode(struct amdgpu_device *adev,
UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK,
UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK);
/* Stall DPG before WPTR/RPTR reset */
WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS),
UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK,
~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);
/* Restore */
ring = &adev->vcn.inst[inst_idx].ring_enc[0];
ring->wptr = 0;
WREG32_SOC15(VCN, inst_idx, mmUVD_RB_BASE_LO, ring->gpu_addr);
WREG32_SOC15(VCN, inst_idx, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
WREG32_SOC15(VCN, inst_idx, mmUVD_RB_SIZE, ring->ring_size / 4);
@ -1565,14 +1580,16 @@ static int vcn_v3_0_pause_dpg_mode(struct amdgpu_device *adev,
WREG32_SOC15(VCN, inst_idx, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
ring = &adev->vcn.inst[inst_idx].ring_enc[1];
ring->wptr = 0;
WREG32_SOC15(VCN, inst_idx, mmUVD_RB_BASE_LO2, ring->gpu_addr);
WREG32_SOC15(VCN, inst_idx, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
WREG32_SOC15(VCN, inst_idx, mmUVD_RB_SIZE2, ring->ring_size / 4);
WREG32_SOC15(VCN, inst_idx, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
WREG32_SOC15(VCN, inst_idx, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
WREG32_SOC15(VCN, inst_idx, mmUVD_RBC_RB_WPTR,
RREG32_SOC15(VCN, inst_idx, mmUVD_SCRATCH2) & 0x7FFFFFFF);
/* Unstall DPG */
WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS),
0, ~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);
SOC15_WAIT_ON_RREG(VCN, inst_idx, mmUVD_POWER_STATUS,
UVD_PGFSM_CONFIG__UVDM_UVDU_PWR_ON, UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
@ -1630,10 +1647,6 @@ static void vcn_v3_0_dec_ring_set_wptr(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
WREG32_SOC15(VCN, ring->me, mmUVD_SCRATCH2,
lower_32_bits(ring->wptr) | 0x80000000);
if (ring->use_doorbell) {
adev->wb.wb[ring->wptr_offs] = lower_32_bits(ring->wptr);
WDOORBELL32(ring->doorbell_index, lower_32_bits(ring->wptr));

View File

@ -163,8 +163,17 @@ void rn_update_clocks(struct clk_mgr *clk_mgr_base,
new_clocks->dppclk_khz = 100000;
}
if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) {
if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz)
/*
* Temporally ignore thew 0 cases for disp and dpp clks.
* We may have a new feature that requires 0 clks in the future.
*/
if (new_clocks->dppclk_khz == 0 || new_clocks->dispclk_khz == 0) {
new_clocks->dppclk_khz = clk_mgr_base->clks.dppclk_khz;
new_clocks->dispclk_khz = clk_mgr_base->clks.dispclk_khz;
}
if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr_base->clks.dppclk_khz)) {
if (clk_mgr_base->clks.dppclk_khz > new_clocks->dppclk_khz)
dpp_clock_lowered = true;
clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
update_dppclk = true;

View File

@ -1164,7 +1164,12 @@ int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu,
if (ret)
return ret;
crystal_clock_freq = amdgpu_asic_get_xclk(adev);
/*
* crystal_clock_freq div by 4 is required since the fan control
* module refers to 25MHz
*/
crystal_clock_freq = amdgpu_asic_get_xclk(adev) / 4;
tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
WREG32_SOC15(THM, 0, mmCG_TACH_CTRL,
REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL),

View File

@ -18021,16 +18021,6 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915)
if (!HAS_GMCH(i915))
sanitize_watermarks(i915);
/*
* Force all active planes to recompute their states. So that on
* mode_setcrtc after probe, all the intel_plane_state variables
* are already calculated and there is no assert_plane warnings
* during bootup.
*/
ret = intel_initial_commit(dev);
if (ret)
drm_dbg_kms(&i915->drm, "Initial commit in probe failed.\n");
return 0;
}
@ -18039,11 +18029,21 @@ int intel_modeset_init(struct drm_i915_private *i915)
{
int ret;
intel_overlay_setup(i915);
if (!HAS_DISPLAY(i915))
return 0;
/*
* Force all active planes to recompute their states. So that on
* mode_setcrtc after probe, all the intel_plane_state variables
* are already calculated and there is no assert_plane warnings
* during bootup.
*/
ret = intel_initial_commit(&i915->drm);
if (ret)
return ret;
intel_overlay_setup(i915);
ret = intel_fbdev_init(&i915->drm);
if (ret)
return ret;

View File

@ -101,18 +101,37 @@ static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b)
intel_gt_pm_put_async(b->irq_engine->gt);
}
static void intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b)
{
spin_lock(&b->irq_lock);
if (b->irq_armed)
__intel_breadcrumbs_disarm_irq(b);
spin_unlock(&b->irq_lock);
}
static void add_signaling_context(struct intel_breadcrumbs *b,
struct intel_context *ce)
{
intel_context_get(ce);
list_add_tail(&ce->signal_link, &b->signalers);
lockdep_assert_held(&ce->signal_lock);
spin_lock(&b->signalers_lock);
list_add_rcu(&ce->signal_link, &b->signalers);
spin_unlock(&b->signalers_lock);
}
static void remove_signaling_context(struct intel_breadcrumbs *b,
static bool remove_signaling_context(struct intel_breadcrumbs *b,
struct intel_context *ce)
{
list_del(&ce->signal_link);
intel_context_put(ce);
lockdep_assert_held(&ce->signal_lock);
if (!list_empty(&ce->signals))
return false;
spin_lock(&b->signalers_lock);
list_del_rcu(&ce->signal_link);
spin_unlock(&b->signalers_lock);
return true;
}
static inline bool __request_completed(const struct i915_request *rq)
@ -175,6 +194,8 @@ static void add_retire(struct intel_breadcrumbs *b, struct intel_timeline *tl)
static bool __signal_request(struct i915_request *rq)
{
GEM_BUG_ON(test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags));
if (!__dma_fence_signal(&rq->fence)) {
i915_request_put(rq);
return false;
@ -195,15 +216,12 @@ static void signal_irq_work(struct irq_work *work)
struct intel_breadcrumbs *b = container_of(work, typeof(*b), irq_work);
const ktime_t timestamp = ktime_get();
struct llist_node *signal, *sn;
struct intel_context *ce, *cn;
struct list_head *pos, *next;
struct intel_context *ce;
signal = NULL;
if (unlikely(!llist_empty(&b->signaled_requests)))
signal = llist_del_all(&b->signaled_requests);
spin_lock(&b->irq_lock);
/*
* Keep the irq armed until the interrupt after all listeners are gone.
*
@ -229,47 +247,44 @@ static void signal_irq_work(struct irq_work *work)
* interrupt draw less ire from other users of the system and tools
* like powertop.
*/
if (!signal && b->irq_armed && list_empty(&b->signalers))
__intel_breadcrumbs_disarm_irq(b);
if (!signal && READ_ONCE(b->irq_armed) && list_empty(&b->signalers))
intel_breadcrumbs_disarm_irq(b);
list_for_each_entry_safe(ce, cn, &b->signalers, signal_link) {
GEM_BUG_ON(list_empty(&ce->signals));
rcu_read_lock();
list_for_each_entry_rcu(ce, &b->signalers, signal_link) {
struct i915_request *rq;
list_for_each_safe(pos, next, &ce->signals) {
struct i915_request *rq =
list_entry(pos, typeof(*rq), signal_link);
list_for_each_entry_rcu(rq, &ce->signals, signal_link) {
bool release;
GEM_BUG_ON(!check_signal_order(ce, rq));
if (!__request_completed(rq))
break;
if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL,
&rq->fence.flags))
break;
/*
* Queue for execution after dropping the signaling
* spinlock as the callback chain may end up adding
* more signalers to the same context or engine.
*/
clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
spin_lock(&ce->signal_lock);
list_del_rcu(&rq->signal_link);
release = remove_signaling_context(b, ce);
spin_unlock(&ce->signal_lock);
if (__signal_request(rq))
/* We own signal_node now, xfer to local list */
signal = slist_add(&rq->signal_node, signal);
}
/*
* We process the list deletion in bulk, only using a list_add
* (not list_move) above but keeping the status of
* rq->signal_link known with the I915_FENCE_FLAG_SIGNAL bit.
*/
if (!list_is_first(pos, &ce->signals)) {
/* Advance the list to the first incomplete request */
__list_del_many(&ce->signals, pos);
if (&ce->signals == pos) { /* now empty */
if (release) {
add_retire(b, ce->timeline);
remove_signaling_context(b, ce);
intel_context_put(ce);
}
}
}
spin_unlock(&b->irq_lock);
rcu_read_unlock();
llist_for_each_safe(signal, sn, signal) {
struct i915_request *rq =
@ -298,14 +313,15 @@ intel_breadcrumbs_create(struct intel_engine_cs *irq_engine)
if (!b)
return NULL;
spin_lock_init(&b->irq_lock);
b->irq_engine = irq_engine;
spin_lock_init(&b->signalers_lock);
INIT_LIST_HEAD(&b->signalers);
init_llist_head(&b->signaled_requests);
spin_lock_init(&b->irq_lock);
init_irq_work(&b->irq_work, signal_irq_work);
b->irq_engine = irq_engine;
return b;
}
@ -347,9 +363,9 @@ void intel_breadcrumbs_free(struct intel_breadcrumbs *b)
kfree(b);
}
static void insert_breadcrumb(struct i915_request *rq,
struct intel_breadcrumbs *b)
static void insert_breadcrumb(struct i915_request *rq)
{
struct intel_breadcrumbs *b = READ_ONCE(rq->engine)->breadcrumbs;
struct intel_context *ce = rq->context;
struct list_head *pos;
@ -371,6 +387,7 @@ static void insert_breadcrumb(struct i915_request *rq,
}
if (list_empty(&ce->signals)) {
intel_context_get(ce);
add_signaling_context(b, ce);
pos = &ce->signals;
} else {
@ -396,8 +413,9 @@ static void insert_breadcrumb(struct i915_request *rq,
break;
}
}
list_add(&rq->signal_link, pos);
list_add_rcu(&rq->signal_link, pos);
GEM_BUG_ON(!check_signal_order(ce, rq));
GEM_BUG_ON(test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags));
set_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
/*
@ -410,7 +428,7 @@ static void insert_breadcrumb(struct i915_request *rq,
bool i915_request_enable_breadcrumb(struct i915_request *rq)
{
struct intel_breadcrumbs *b;
struct intel_context *ce = rq->context;
/* Serialises with i915_request_retire() using rq->lock */
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags))
@ -425,67 +443,30 @@ bool i915_request_enable_breadcrumb(struct i915_request *rq)
if (!test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags))
return true;
/*
* rq->engine is locked by rq->engine->active.lock. That however
* is not known until after rq->engine has been dereferenced and
* the lock acquired. Hence we acquire the lock and then validate
* that rq->engine still matches the lock we hold for it.
*
* Here, we are using the breadcrumb lock as a proxy for the
* rq->engine->active.lock, and we know that since the breadcrumb
* will be serialised within i915_request_submit/i915_request_unsubmit,
* the engine cannot change while active as long as we hold the
* breadcrumb lock on that engine.
*
* From the dma_fence_enable_signaling() path, we are outside of the
* request submit/unsubmit path, and so we must be more careful to
* acquire the right lock.
*/
b = READ_ONCE(rq->engine)->breadcrumbs;
spin_lock(&b->irq_lock);
while (unlikely(b != READ_ONCE(rq->engine)->breadcrumbs)) {
spin_unlock(&b->irq_lock);
b = READ_ONCE(rq->engine)->breadcrumbs;
spin_lock(&b->irq_lock);
}
/*
* Now that we are finally serialised with request submit/unsubmit,
* [with b->irq_lock] and with i915_request_retire() [via checking
* SIGNALED with rq->lock] confirm the request is indeed active. If
* it is no longer active, the breadcrumb will be attached upon
* i915_request_submit().
*/
spin_lock(&ce->signal_lock);
if (test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags))
insert_breadcrumb(rq, b);
spin_unlock(&b->irq_lock);
insert_breadcrumb(rq);
spin_unlock(&ce->signal_lock);
return true;
}
void i915_request_cancel_breadcrumb(struct i915_request *rq)
{
struct intel_breadcrumbs *b = rq->engine->breadcrumbs;
struct intel_context *ce = rq->context;
bool release;
/*
* We must wait for b->irq_lock so that we know the interrupt handler
* has released its reference to the intel_context and has completed
* the DMA_FENCE_FLAG_SIGNALED_BIT/I915_FENCE_FLAG_SIGNAL dance (if
* required).
*/
spin_lock(&b->irq_lock);
if (test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags)) {
struct intel_context *ce = rq->context;
if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags))
return;
list_del(&rq->signal_link);
if (list_empty(&ce->signals))
remove_signaling_context(b, ce);
spin_lock(&ce->signal_lock);
list_del_rcu(&rq->signal_link);
release = remove_signaling_context(rq->engine->breadcrumbs, ce);
spin_unlock(&ce->signal_lock);
if (release)
intel_context_put(ce);
clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
i915_request_put(rq);
}
spin_unlock(&b->irq_lock);
i915_request_put(rq);
}
static void print_signals(struct intel_breadcrumbs *b, struct drm_printer *p)
@ -495,18 +476,17 @@ static void print_signals(struct intel_breadcrumbs *b, struct drm_printer *p)
drm_printf(p, "Signals:\n");
spin_lock_irq(&b->irq_lock);
list_for_each_entry(ce, &b->signalers, signal_link) {
list_for_each_entry(rq, &ce->signals, signal_link) {
rcu_read_lock();
list_for_each_entry_rcu(ce, &b->signalers, signal_link) {
list_for_each_entry_rcu(rq, &ce->signals, signal_link)
drm_printf(p, "\t[%llx:%llx%s] @ %dms\n",
rq->fence.context, rq->fence.seqno,
i915_request_completed(rq) ? "!" :
i915_request_started(rq) ? "*" :
"",
jiffies_to_msecs(jiffies - rq->emitted_jiffies));
}
}
spin_unlock_irq(&b->irq_lock);
rcu_read_unlock();
}
void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine,

View File

@ -29,18 +29,16 @@
* the overhead of waking that client is much preferred.
*/
struct intel_breadcrumbs {
spinlock_t irq_lock; /* protects the lists used in hardirq context */
/* Not all breadcrumbs are attached to physical HW */
struct intel_engine_cs *irq_engine;
spinlock_t signalers_lock; /* protects the list of signalers */
struct list_head signalers;
struct llist_head signaled_requests;
spinlock_t irq_lock; /* protects the interrupt from hardirq context */
struct irq_work irq_work; /* for use from inside irq_lock */
unsigned int irq_enabled;
bool irq_armed;
};

View File

@ -25,9 +25,16 @@ static struct intel_context *intel_context_alloc(void)
return kmem_cache_zalloc(global.slab_ce, GFP_KERNEL);
}
static void rcu_context_free(struct rcu_head *rcu)
{
struct intel_context *ce = container_of(rcu, typeof(*ce), rcu);
kmem_cache_free(global.slab_ce, ce);
}
void intel_context_free(struct intel_context *ce)
{
kmem_cache_free(global.slab_ce, ce);
call_rcu(&ce->rcu, rcu_context_free);
}
struct intel_context *
@ -356,8 +363,7 @@ static int __intel_context_active(struct i915_active *active)
}
void
intel_context_init(struct intel_context *ce,
struct intel_engine_cs *engine)
intel_context_init(struct intel_context *ce, struct intel_engine_cs *engine)
{
GEM_BUG_ON(!engine->cops);
GEM_BUG_ON(!engine->gt->vm);
@ -373,7 +379,8 @@ intel_context_init(struct intel_context *ce,
ce->vm = i915_vm_get(engine->gt->vm);
INIT_LIST_HEAD(&ce->signal_link);
/* NB ce->signal_link/lock is used under RCU */
spin_lock_init(&ce->signal_lock);
INIT_LIST_HEAD(&ce->signals);
mutex_init(&ce->pin_mutex);

View File

@ -25,6 +25,7 @@ DECLARE_EWMA(runtime, 3, 8);
struct i915_gem_context;
struct i915_gem_ww_ctx;
struct i915_vma;
struct intel_breadcrumbs;
struct intel_context;
struct intel_ring;
@ -44,7 +45,16 @@ struct intel_context_ops {
};
struct intel_context {
struct kref ref;
/*
* Note: Some fields may be accessed under RCU.
*
* Unless otherwise noted a field can safely be assumed to be protected
* by strong reference counting.
*/
union {
struct kref ref; /* no kref_get_unless_zero()! */
struct rcu_head rcu;
};
struct intel_engine_cs *engine;
struct intel_engine_cs *inflight;
@ -54,8 +64,15 @@ struct intel_context {
struct i915_address_space *vm;
struct i915_gem_context __rcu *gem_context;
struct list_head signal_link;
struct list_head signals;
/*
* @signal_lock protects the list of requests that need signaling,
* @signals. While there are any requests that need signaling,
* we add the context to the breadcrumbs worker, and remove it
* upon completion/cancellation of the last request.
*/
struct list_head signal_link; /* Accessed under RCU */
struct list_head signals; /* Guarded by signal_lock */
spinlock_t signal_lock; /* protects signals, the list of requests */
struct i915_vma *state;
struct intel_ring *ring;

View File

@ -131,7 +131,19 @@ static const struct drm_i915_mocs_entry skl_mocs_table[] = {
GEN9_MOCS_ENTRIES,
MOCS_ENTRY(I915_MOCS_CACHED,
LE_3_WB | LE_TC_2_LLC_ELLC | LE_LRUM(3),
L3_3_WB)
L3_3_WB),
/*
* mocs:63
* - used by the L3 for all of its evictions.
* Thus it is expected to allow LLC cacheability to enable coherent
* flows to be maintained.
* - used to force L3 uncachable cycles.
* Thus it is expected to make the surface L3 uncacheable.
*/
MOCS_ENTRY(63,
LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
L3_1_UC)
};
/* NOTE: the LE_TGT_CACHE is not used on Broxton */

View File

@ -883,6 +883,10 @@ void intel_rps_park(struct intel_rps *rps)
adj = -2;
rps->last_adj = adj;
rps->cur_freq = max_t(int, rps->cur_freq + adj, rps->min_freq);
if (rps->cur_freq < rps->efficient_freq) {
rps->cur_freq = rps->efficient_freq;
rps->last_adj = 0;
}
GT_TRACE(rps_to_gt(rps), "park:%x\n", rps->cur_freq);
}

View File

@ -103,10 +103,13 @@ static int __shmem_rw(struct file *file, loff_t off,
return PTR_ERR(page);
vaddr = kmap(page);
if (write)
if (write) {
memcpy(vaddr + offset_in_page(off), ptr, this);
else
set_page_dirty(page);
} else {
memcpy(ptr, vaddr + offset_in_page(off), this);
}
mark_page_accessed(page);
kunmap(page);
put_page(page);

View File

@ -177,10 +177,8 @@ struct i915_request {
struct intel_ring *ring;
struct intel_timeline __rcu *timeline;
union {
struct list_head signal_link;
struct llist_node signal_node;
};
struct list_head signal_link;
struct llist_node signal_node;
/*
* The rcu epoch of when this request was allocated. Used to judiciously

View File

@ -22,6 +22,7 @@
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_plane.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_vblank.h>
@ -484,17 +485,27 @@ static void mxsfb_plane_overlay_atomic_update(struct drm_plane *plane,
writel(ctrl, mxsfb->base + LCDC_AS_CTRL);
}
static bool mxsfb_format_mod_supported(struct drm_plane *plane,
uint32_t format,
uint64_t modifier)
{
return modifier == DRM_FORMAT_MOD_LINEAR;
}
static const struct drm_plane_helper_funcs mxsfb_plane_primary_helper_funcs = {
.prepare_fb = drm_gem_fb_prepare_fb,
.atomic_check = mxsfb_plane_atomic_check,
.atomic_update = mxsfb_plane_primary_atomic_update,
};
static const struct drm_plane_helper_funcs mxsfb_plane_overlay_helper_funcs = {
.prepare_fb = drm_gem_fb_prepare_fb,
.atomic_check = mxsfb_plane_atomic_check,
.atomic_update = mxsfb_plane_overlay_atomic_update,
};
static const struct drm_plane_funcs mxsfb_plane_funcs = {
.format_mod_supported = mxsfb_format_mod_supported,
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_plane_cleanup,

View File

@ -1214,8 +1214,8 @@ retry:
}
reg->bus.offset = handle;
ret = 0;
}
ret = 0;
break;
default:
ret = -EINVAL;

View File

@ -195,8 +195,7 @@ static void sdi_bridge_mode_set(struct drm_bridge *bridge,
sdi->pixelclock = adjusted_mode->clock * 1000;
}
static void sdi_bridge_enable(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state)
static void sdi_bridge_enable(struct drm_bridge *bridge)
{
struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
struct dispc_clock_info dispc_cinfo;
@ -259,8 +258,7 @@ err_get_dispc:
regulator_disable(sdi->vdds_sdi_reg);
}
static void sdi_bridge_disable(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state)
static void sdi_bridge_disable(struct drm_bridge *bridge)
{
struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
@ -278,8 +276,8 @@ static const struct drm_bridge_funcs sdi_bridge_funcs = {
.mode_valid = sdi_bridge_mode_valid,
.mode_fixup = sdi_bridge_mode_fixup,
.mode_set = sdi_bridge_mode_set,
.atomic_enable = sdi_bridge_enable,
.atomic_disable = sdi_bridge_disable,
.enable = sdi_bridge_enable,
.disable = sdi_bridge_disable,
};
static void sdi_bridge_init(struct sdi_device *sdi)

View File

@ -629,7 +629,7 @@ static int acx565akm_probe(struct spi_device *spi)
lcd->spi = spi;
mutex_init(&lcd->mutex);
lcd->reset_gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW);
lcd->reset_gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(lcd->reset_gpio)) {
dev_err(&spi->dev, "failed to get reset GPIO\n");
return PTR_ERR(lcd->reset_gpio);

View File

@ -544,7 +544,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
struct device_node *port, *endpoint;
int ret = 0, child_count = 0;
const char *name;
u32 endpoint_id;
u32 endpoint_id = 0;
lvds->drm_dev = drm_dev;
port = of_graph_get_port_by_id(dev->of_node, 1);

View File

@ -90,7 +90,7 @@ static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp)
if (!fpriv)
return -ENOMEM;
idr_init(&fpriv->contexts);
idr_init_base(&fpriv->contexts, 1);
mutex_init(&fpriv->lock);
filp->driver_priv = fpriv;

View File

@ -129,7 +129,6 @@ int tegra_output_probe(struct tegra_output *output)
if (!output->ddc) {
err = -EPROBE_DEFER;
of_node_put(ddc);
return err;
}
}

View File

@ -397,7 +397,6 @@ struct tegra_sor;
struct tegra_sor_ops {
const char *name;
int (*probe)(struct tegra_sor *sor);
int (*remove)(struct tegra_sor *sor);
void (*audio_enable)(struct tegra_sor *sor);
void (*audio_disable)(struct tegra_sor *sor);
};
@ -2942,6 +2941,24 @@ static const struct drm_encoder_helper_funcs tegra_sor_dp_helpers = {
.atomic_check = tegra_sor_encoder_atomic_check,
};
static void tegra_sor_disable_regulator(void *data)
{
struct regulator *reg = data;
regulator_disable(reg);
}
static int tegra_sor_enable_regulator(struct tegra_sor *sor, struct regulator *reg)
{
int err;
err = regulator_enable(reg);
if (err)
return err;
return devm_add_action_or_reset(sor->dev, tegra_sor_disable_regulator, reg);
}
static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
{
int err;
@ -2953,7 +2970,7 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
return PTR_ERR(sor->avdd_io_supply);
}
err = regulator_enable(sor->avdd_io_supply);
err = tegra_sor_enable_regulator(sor, sor->avdd_io_supply);
if (err < 0) {
dev_err(sor->dev, "failed to enable AVDD I/O supply: %d\n",
err);
@ -2967,7 +2984,7 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
return PTR_ERR(sor->vdd_pll_supply);
}
err = regulator_enable(sor->vdd_pll_supply);
err = tegra_sor_enable_regulator(sor, sor->vdd_pll_supply);
if (err < 0) {
dev_err(sor->dev, "failed to enable VDD PLL supply: %d\n",
err);
@ -2981,7 +2998,7 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
return PTR_ERR(sor->hdmi_supply);
}
err = regulator_enable(sor->hdmi_supply);
err = tegra_sor_enable_regulator(sor, sor->hdmi_supply);
if (err < 0) {
dev_err(sor->dev, "failed to enable HDMI supply: %d\n", err);
return err;
@ -2992,19 +3009,9 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
return 0;
}
static int tegra_sor_hdmi_remove(struct tegra_sor *sor)
{
regulator_disable(sor->hdmi_supply);
regulator_disable(sor->vdd_pll_supply);
regulator_disable(sor->avdd_io_supply);
return 0;
}
static const struct tegra_sor_ops tegra_sor_hdmi_ops = {
.name = "HDMI",
.probe = tegra_sor_hdmi_probe,
.remove = tegra_sor_hdmi_remove,
.audio_enable = tegra_sor_hdmi_audio_enable,
.audio_disable = tegra_sor_hdmi_audio_disable,
};
@ -3017,7 +3024,7 @@ static int tegra_sor_dp_probe(struct tegra_sor *sor)
if (IS_ERR(sor->avdd_io_supply))
return PTR_ERR(sor->avdd_io_supply);
err = regulator_enable(sor->avdd_io_supply);
err = tegra_sor_enable_regulator(sor, sor->avdd_io_supply);
if (err < 0)
return err;
@ -3025,25 +3032,16 @@ static int tegra_sor_dp_probe(struct tegra_sor *sor)
if (IS_ERR(sor->vdd_pll_supply))
return PTR_ERR(sor->vdd_pll_supply);
err = regulator_enable(sor->vdd_pll_supply);
err = tegra_sor_enable_regulator(sor, sor->vdd_pll_supply);
if (err < 0)
return err;
return 0;
}
static int tegra_sor_dp_remove(struct tegra_sor *sor)
{
regulator_disable(sor->vdd_pll_supply);
regulator_disable(sor->avdd_io_supply);
return 0;
}
static const struct tegra_sor_ops tegra_sor_dp_ops = {
.name = "DP",
.probe = tegra_sor_dp_probe,
.remove = tegra_sor_dp_remove,
};
static int tegra_sor_init(struct host1x_client *client)
@ -3145,6 +3143,7 @@ static int tegra_sor_init(struct host1x_client *client)
if (err < 0) {
dev_err(sor->dev, "failed to deassert SOR reset: %d\n",
err);
clk_disable_unprepare(sor->clk);
return err;
}
@ -3152,12 +3151,17 @@ static int tegra_sor_init(struct host1x_client *client)
}
err = clk_prepare_enable(sor->clk_safe);
if (err < 0)
if (err < 0) {
clk_disable_unprepare(sor->clk);
return err;
}
err = clk_prepare_enable(sor->clk_dp);
if (err < 0)
if (err < 0) {
clk_disable_unprepare(sor->clk_safe);
clk_disable_unprepare(sor->clk);
return err;
}
return 0;
}
@ -3764,17 +3768,16 @@ static int tegra_sor_probe(struct platform_device *pdev)
return err;
err = tegra_output_probe(&sor->output);
if (err < 0) {
dev_err(&pdev->dev, "failed to probe output: %d\n", err);
return err;
}
if (err < 0)
return dev_err_probe(&pdev->dev, err,
"failed to probe output\n");
if (sor->ops && sor->ops->probe) {
err = sor->ops->probe(sor);
if (err < 0) {
dev_err(&pdev->dev, "failed to probe %s: %d\n",
sor->ops->name, err);
goto output;
goto remove;
}
}
@ -3955,9 +3958,6 @@ unregister:
rpm_disable:
pm_runtime_disable(&pdev->dev);
remove:
if (sor->ops && sor->ops->remove)
sor->ops->remove(sor);
output:
tegra_output_remove(&sor->output);
return err;
}
@ -3976,12 +3976,6 @@ static int tegra_sor_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
if (sor->ops && sor->ops->remove) {
err = sor->ops->remove(sor);
if (err < 0)
dev_err(&pdev->dev, "failed to remove SOR: %d\n", err);
}
tegra_output_remove(&sor->output);
return 0;

View File

@ -734,6 +734,7 @@ config I2C_LPC2K
config I2C_MLXBF
tristate "Mellanox BlueField I2C controller"
depends on MELLANOX_PLATFORM && ARM64
select I2C_SLAVE
help
Enabling this option will add I2C SMBus support for Mellanox BlueField
system.

View File

@ -412,6 +412,19 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
dma->chan_using = NULL;
}
static void i2c_imx_clear_irq(struct imx_i2c_struct *i2c_imx, unsigned int bits)
{
unsigned int temp;
/*
* i2sr_clr_opcode is the value to clear all interrupts. Here we want to
* clear only <bits>, so we write ~i2sr_clr_opcode with just <bits>
* toggled. This is required because i.MX needs W0C and Vybrid uses W1C.
*/
temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ bits;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
}
static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool atomic)
{
unsigned long orig_jiffies = jiffies;
@ -424,8 +437,7 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool a
/* check for arbitration lost */
if (temp & I2SR_IAL) {
temp &= ~I2SR_IAL;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
return -EAGAIN;
}
@ -469,7 +481,7 @@ static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx, bool atomic)
*/
readb_poll_timeout_atomic(addr, regval, regval & I2SR_IIF, 5, 1000 + 100);
i2c_imx->i2csr = regval;
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
i2c_imx_clear_irq(i2c_imx, I2SR_IIF | I2SR_IAL);
} else {
wait_event_timeout(i2c_imx->queue, i2c_imx->i2csr & I2SR_IIF, HZ / 10);
}
@ -478,6 +490,16 @@ static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx, bool atomic)
dev_dbg(&i2c_imx->adapter.dev, "<%s> Timeout\n", __func__);
return -ETIMEDOUT;
}
/* check for arbitration lost */
if (i2c_imx->i2csr & I2SR_IAL) {
dev_dbg(&i2c_imx->adapter.dev, "<%s> Arbitration lost\n", __func__);
i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
i2c_imx->i2csr = 0;
return -EAGAIN;
}
dev_dbg(&i2c_imx->adapter.dev, "<%s> TRX complete\n", __func__);
i2c_imx->i2csr = 0;
return 0;
@ -593,6 +615,8 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx, bool atomic)
/* Stop I2C transaction */
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
if (!(temp & I2CR_MSTA))
i2c_imx->stopped = 1;
temp &= ~(I2CR_MSTA | I2CR_MTX);
if (i2c_imx->dma)
temp &= ~I2CR_DMAEN;
@ -623,9 +647,7 @@ static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
if (temp & I2SR_IIF) {
/* save status register */
i2c_imx->i2csr = temp;
temp &= ~I2SR_IIF;
temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
i2c_imx_clear_irq(i2c_imx, I2SR_IIF);
wake_up(&i2c_imx->queue);
return IRQ_HANDLED;
}
@ -758,9 +780,12 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
*/
dev_dbg(dev, "<%s> clear MSTA\n", __func__);
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
if (!(temp & I2CR_MSTA))
i2c_imx->stopped = 1;
temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
i2c_imx_bus_busy(i2c_imx, 0, false);
if (!i2c_imx->stopped)
i2c_imx_bus_busy(i2c_imx, 0, false);
} else {
/*
* For i2c master receiver repeat restart operation like:
@ -885,9 +910,12 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
dev_dbg(&i2c_imx->adapter.dev,
"<%s> clear MSTA\n", __func__);
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
if (!(temp & I2CR_MSTA))
i2c_imx->stopped = 1;
temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
i2c_imx_bus_busy(i2c_imx, 0, atomic);
if (!i2c_imx->stopped)
i2c_imx_bus_busy(i2c_imx, 0, atomic);
} else {
/*
* For i2c master receiver repeat restart operation like:

View File

@ -1258,9 +1258,9 @@ static int mlxbf_i2c_get_gpio(struct platform_device *pdev,
return -EFAULT;
gpio_res->io = devm_ioremap(dev, params->start, size);
if (IS_ERR(gpio_res->io)) {
if (!gpio_res->io) {
devm_release_mem_region(dev, params->start, size);
return PTR_ERR(gpio_res->io);
return -ENOMEM;
}
return 0;
@ -1323,9 +1323,9 @@ static int mlxbf_i2c_get_corepll(struct platform_device *pdev,
return -EFAULT;
corepll_res->io = devm_ioremap(dev, params->start, size);
if (IS_ERR(corepll_res->io)) {
if (!corepll_res->io) {
devm_release_mem_region(dev, params->start, size);
return PTR_ERR(corepll_res->io);
return -ENOMEM;
}
return 0;
@ -1717,9 +1717,9 @@ static int mlxbf_i2c_init_coalesce(struct platform_device *pdev,
return -EFAULT;
coalesce_res->io = ioremap(params->start, size);
if (IS_ERR(coalesce_res->io)) {
if (!coalesce_res->io) {
release_mem_region(params->start, size);
return PTR_ERR(coalesce_res->io);
return -ENOMEM;
}
priv->coalesce = coalesce_res;

View File

@ -194,9 +194,9 @@ static irqreturn_t cci_isr(int irq, void *dev)
if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M1_ERROR)) {
if (val & CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERR ||
val & CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERR)
cci->master[0].status = -ENXIO;
cci->master[1].status = -ENXIO;
else
cci->master[0].status = -EIO;
cci->master[1].status = -EIO;
writel(CCI_HALT_REQ_I2C_M1_Q0Q1, cci->base + CCI_HALT_REQ);
ret = IRQ_HANDLED;

View File

@ -801,7 +801,8 @@ static int qup_i2c_bam_schedule_desc(struct qup_i2c_dev *qup)
if (ret || qup->bus_err || qup->qup_err) {
reinit_completion(&qup->xfer);
if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
if (ret) {
dev_err(qup->dev, "change to run state timed out");
goto desc_err;
}

View File

@ -1140,6 +1140,20 @@ static bool __init intel_idle_max_cstate_reached(int cstate)
return false;
}
static bool __init intel_idle_state_needs_timer_stop(struct cpuidle_state *state)
{
unsigned long eax = flg2MWAIT(state->flags);
if (boot_cpu_has(X86_FEATURE_ARAT))
return false;
/*
* Switch over to one-shot tick broadcast if the target C-state
* is deeper than C1.
*/
return !!((eax >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK);
}
#ifdef CONFIG_ACPI_PROCESSOR_CSTATE
#include <acpi/processor.h>
@ -1210,20 +1224,6 @@ static bool __init intel_idle_acpi_cst_extract(void)
return false;
}
static bool __init intel_idle_state_needs_timer_stop(struct cpuidle_state *state)
{
unsigned long eax = flg2MWAIT(state->flags);
if (boot_cpu_has(X86_FEATURE_ARAT))
return false;
/*
* Switch over to one-shot tick broadcast if the target C-state
* is deeper than C1.
*/
return !!((eax >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK);
}
static void __init intel_idle_init_cstates_acpi(struct cpuidle_driver *drv)
{
int cstate, limit = min_t(int, CPUIDLE_STATE_MAX, acpi_state_table.count);

View File

@ -241,6 +241,7 @@ static const struct xpad_device {
{ 0x1038, 0x1430, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
{ 0x1038, 0x1431, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
{ 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 },
{ 0x1209, 0x2882, "Ardwiino Controller", 0, XTYPE_XBOX360 },
{ 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 },
{ 0x12ab, 0x0303, "Mortal Kombat Klassic FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
@ -418,6 +419,7 @@ static const struct usb_device_id xpad_table[] = {
XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */
XPAD_XBOX360_VENDOR(0x1038), /* SteelSeries Controllers */
XPAD_XBOX360_VENDOR(0x11c9), /* Nacon GC100XF */
XPAD_XBOX360_VENDOR(0x1209), /* Ardwiino Controllers */
XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */
XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */
XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */

View File

@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/dmi.h>

View File

@ -219,6 +219,10 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"),
DMI_MATCH(DMI_PRODUCT_NAME, "C15B"),
},
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ByteSpeed LLC"),
DMI_MATCH(DMI_PRODUCT_NAME, "ByteSpeed Laptop C15B"),
},
},
{ }
};

View File

@ -1471,7 +1471,8 @@ static int __init i8042_setup_aux(void)
if (error)
goto err_free_ports;
if (aux_enable())
error = aux_enable();
if (error)
goto err_free_irq;
i8042_aux_irq_registered = true;

View File

@ -2183,11 +2183,11 @@ static int mxt_initialize(struct mxt_data *data)
msleep(MXT_FW_RESET_TIME);
}
error = mxt_acquire_irq(data);
error = mxt_check_retrigen(data);
if (error)
return error;
error = mxt_check_retrigen(data);
error = mxt_acquire_irq(data);
if (error)
return error;

View File

@ -712,10 +712,6 @@ static bool block_size_is_power_of_two(struct cache *cache)
return cache->sectors_per_block_shift >= 0;
}
/* gcc on ARM generates spurious references to __udivdi3 and __umoddi3 */
#if defined(CONFIG_ARM) && __GNUC__ == 4 && __GNUC_MINOR__ <= 6
__always_inline
#endif
static dm_block_t block_div(dm_block_t b, uint32_t n)
{
do_div(b, n);

View File

@ -3462,7 +3462,7 @@ static int get_mac(struct crypto_shash **hash, struct alg_spec *a, char **error,
int r;
if (a->alg_string) {
*hash = crypto_alloc_shash(a->alg_string, 0, 0);
*hash = crypto_alloc_shash(a->alg_string, 0, CRYPTO_ALG_ALLOCATES_MEMORY);
if (IS_ERR(*hash)) {
*error = error_alg;
r = PTR_ERR(*hash);
@ -3519,7 +3519,7 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
struct journal_completion comp;
comp.ic = ic;
ic->journal_crypt = crypto_alloc_skcipher(ic->journal_crypt_alg.alg_string, 0, 0);
ic->journal_crypt = crypto_alloc_skcipher(ic->journal_crypt_alg.alg_string, 0, CRYPTO_ALG_ALLOCATES_MEMORY);
if (IS_ERR(ic->journal_crypt)) {
*error = "Invalid journal cipher";
r = PTR_ERR(ic->journal_crypt);

View File

@ -18,7 +18,6 @@
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/atomic.h>
#include <linux/lcm.h>
#include <linux/blk-mq.h>
#include <linux/mount.h>
#include <linux/dax.h>
@ -1247,12 +1246,6 @@ void dm_table_event_callback(struct dm_table *t,
void dm_table_event(struct dm_table *t)
{
/*
* You can no longer call dm_table_event() from interrupt
* context, use a bottom half instead.
*/
BUG_ON(in_interrupt());
mutex_lock(&_event_lock);
if (t->event_fn)
t->event_fn(t->event_context);
@ -1455,10 +1448,6 @@ int dm_calculate_queue_limits(struct dm_table *table,
zone_sectors = ti_limits.chunk_sectors;
}
/* Stack chunk_sectors if target-specific splitting is required */
if (ti->max_io_len)
ti_limits.chunk_sectors = lcm_not_zero(ti->max_io_len,
ti_limits.chunk_sectors);
/* Set I/O hints portion of queue limits */
if (ti->type->io_hints)
ti->type->io_hints(ti, &ti_limits);

View File

@ -319,7 +319,7 @@ err1:
#else
static int persistent_memory_claim(struct dm_writecache *wc)
{
BUG();
return -EOPNOTSUPP;
}
#endif
@ -2041,7 +2041,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
struct wc_memory_superblock s;
static struct dm_arg _args[] = {
{0, 10, "Invalid number of feature args"},
{0, 16, "Invalid number of feature args"},
};
as.argc = argc;
@ -2479,6 +2479,8 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
extra_args += 2;
if (wc->autocommit_time_set)
extra_args += 2;
if (wc->max_age != MAX_AGE_UNSPECIFIED)
extra_args += 2;
if (wc->cleaner)
extra_args++;
if (wc->writeback_fua_set)

View File

@ -476,8 +476,10 @@ static int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
return -EAGAIN;
map = dm_get_live_table(md, &srcu_idx);
if (!map)
return -EIO;
if (!map) {
ret = -EIO;
goto out;
}
do {
struct dm_target *tgt;
@ -507,7 +509,6 @@ out:
static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx,
struct block_device **bdev)
__acquires(md->io_barrier)
{
struct dm_target *tgt;
struct dm_table *map;
@ -541,7 +542,6 @@ retry:
}
static void dm_unprepare_ioctl(struct mapped_device *md, int srcu_idx)
__releases(md->io_barrier)
{
dm_put_live_table(md, srcu_idx);
}
@ -1037,15 +1037,18 @@ static sector_t max_io_len(struct dm_target *ti, sector_t sector)
sector_t max_len;
/*
* Does the target need to split even further?
* - q->limits.chunk_sectors reflects ti->max_io_len so
* blk_max_size_offset() provides required splitting.
* - blk_max_size_offset() also respects q->limits.max_sectors
* Does the target need to split IO even further?
* - varied (per target) IO splitting is a tenet of DM; this
* explains why stacked chunk_sectors based splitting via
* blk_max_size_offset() isn't possible here. So pass in
* ti->max_io_len to override stacked chunk_sectors.
*/
max_len = blk_max_size_offset(ti->table->md->queue,
target_offset);
if (len > max_len)
len = max_len;
if (ti->max_io_len) {
max_len = blk_max_size_offset(ti->table->md->queue,
target_offset, ti->max_io_len);
if (len > max_len)
len = max_len;
}
return len;
}
@ -1196,11 +1199,9 @@ static int dm_dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
* ->zero_page_range() is mandatory dax operation. If we are
* here, something is wrong.
*/
dm_put_live_table(md, srcu_idx);
goto out;
}
ret = ti->type->dax_zero_page_range(ti, pgoff, nr_pages);
out:
dm_put_live_table(md, srcu_idx);

View File

@ -242,16 +242,16 @@ delete_cdev_device:
static void device_cdev_sysfs_del(struct hl_device *hdev)
{
/* device_release() won't be called so must free devices explicitly */
if (!hdev->cdev_sysfs_created) {
kfree(hdev->dev_ctrl);
kfree(hdev->dev);
return;
}
if (!hdev->cdev_sysfs_created)
goto put_devices;
hl_sysfs_fini(hdev);
cdev_device_del(&hdev->cdev_ctrl, hdev->dev_ctrl);
cdev_device_del(&hdev->cdev, hdev->dev);
put_devices:
put_device(hdev->dev);
put_device(hdev->dev_ctrl);
}
static void device_hard_reset_pending(struct work_struct *work)
@ -1430,9 +1430,9 @@ sw_fini:
early_fini:
device_early_fini(hdev);
free_dev_ctrl:
kfree(hdev->dev_ctrl);
put_device(hdev->dev_ctrl);
free_dev:
kfree(hdev->dev);
put_device(hdev->dev);
out_disabled:
hdev->disabled = true;
if (add_cdev_sysfs_on_err)

View File

@ -46,14 +46,4 @@ config INTEL_MEI_TXE
Supported SoCs:
Intel Bay Trail
config INTEL_MEI_VIRTIO
tristate "Intel MEI interface emulation with virtio framework"
select INTEL_MEI
depends on X86 && PCI && VIRTIO_PCI
help
This module implements mei hw emulation over virtio transport.
The module will be called mei_virtio.
Enable this if your virtual machine supports virtual mei
device over virtio.
source "drivers/misc/mei/hdcp/Kconfig"

View File

@ -22,9 +22,6 @@ obj-$(CONFIG_INTEL_MEI_TXE) += mei-txe.o
mei-txe-objs := pci-txe.o
mei-txe-objs += hw-txe.o
obj-$(CONFIG_INTEL_MEI_VIRTIO) += mei-virtio.o
mei-virtio-objs := hw-virtio.o
mei-$(CONFIG_EVENT_TRACING) += mei-trace.o
CFLAGS_mei-trace.o = -I$(src)

View File

@ -1,874 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Intel Management Engine Interface (Intel MEI) Linux driver
* Copyright (c) 2018-2020, Intel Corporation.
*/
#include <linux/err.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/scatterlist.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/virtio.h>
#include <linux/virtio_config.h>
#include <linux/virtio_ids.h>
#include <linux/atomic.h>
#include "mei_dev.h"
#include "hbm.h"
#include "client.h"
#define MEI_VIRTIO_RPM_TIMEOUT 500
/* ACRN virtio device types */
#ifndef VIRTIO_ID_MEI
#define VIRTIO_ID_MEI 0xFFFE /* virtio mei */
#endif
/**
* struct mei_virtio_cfg - settings passed from the virtio backend
* @buf_depth: read buffer depth in slots (4bytes)
* @hw_ready: hw is ready for operation
* @host_reset: synchronize reset with virtio backend
* @reserved: reserved for alignment
* @fw_status: FW status
*/
struct mei_virtio_cfg {
u32 buf_depth;
u8 hw_ready;
u8 host_reset;
u8 reserved[2];
u32 fw_status[MEI_FW_STATUS_MAX];
} __packed;
struct mei_virtio_hw {
struct mei_device mdev;
char name[32];
struct virtqueue *in;
struct virtqueue *out;
bool host_ready;
struct work_struct intr_handler;
u32 *recv_buf;
u8 recv_rdy;
size_t recv_sz;
u32 recv_idx;
u32 recv_len;
/* send buffer */
atomic_t hbuf_ready;
const void *send_hdr;
const void *send_buf;
struct mei_virtio_cfg cfg;
};
#define to_virtio_hw(_dev) container_of(_dev, struct mei_virtio_hw, mdev)
/**
* mei_virtio_fw_status() - read status register of mei
* @dev: mei device
* @fw_status: fw status register values
*
* Return: always 0
*/
static int mei_virtio_fw_status(struct mei_device *dev,
struct mei_fw_status *fw_status)
{
struct virtio_device *vdev = dev_to_virtio(dev->dev);
fw_status->count = MEI_FW_STATUS_MAX;
virtio_cread_bytes(vdev, offsetof(struct mei_virtio_cfg, fw_status),
fw_status->status, sizeof(fw_status->status));
return 0;
}
/**
* mei_virtio_pg_state() - translate internal pg state
* to the mei power gating state
* There is no power management in ACRN mode always return OFF
* @dev: mei device
*
* Return:
* * MEI_PG_OFF - if aliveness is on (always)
* * MEI_PG_ON - (never)
*/
static inline enum mei_pg_state mei_virtio_pg_state(struct mei_device *dev)
{
return MEI_PG_OFF;
}
/**
* mei_virtio_hw_config() - configure hw dependent settings
*
* @dev: mei device
*
* Return: always 0
*/
static int mei_virtio_hw_config(struct mei_device *dev)
{
return 0;
}
/**
* mei_virtio_hbuf_empty_slots() - counts write empty slots.
* @dev: the device structure
*
* Return: always return frontend buf size if buffer is ready, 0 otherwise
*/
static int mei_virtio_hbuf_empty_slots(struct mei_device *dev)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
return (atomic_read(&hw->hbuf_ready) == 1) ? hw->cfg.buf_depth : 0;
}
/**
* mei_virtio_hbuf_is_ready() - checks if write buffer is ready
* @dev: the device structure
*
* Return: true if hbuf is ready
*/
static bool mei_virtio_hbuf_is_ready(struct mei_device *dev)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
return atomic_read(&hw->hbuf_ready) == 1;
}
/**
* mei_virtio_hbuf_max_depth() - returns depth of FE write buffer.
* @dev: the device structure
*
* Return: size of frontend write buffer in bytes
*/
static u32 mei_virtio_hbuf_depth(const struct mei_device *dev)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
return hw->cfg.buf_depth;
}
/**
* mei_virtio_intr_clear() - clear and stop interrupts
* @dev: the device structure
*/
static void mei_virtio_intr_clear(struct mei_device *dev)
{
/*
* In our virtio solution, there are two types of interrupts,
* vq interrupt and config change interrupt.
* 1) start/reset rely on virtio config changed interrupt;
* 2) send/recv rely on virtio virtqueue interrupts.
* They are all virtual interrupts. So, we don't have corresponding
* operation to do here.
*/
}
/**
* mei_virtio_intr_enable() - enables mei BE virtqueues callbacks
* @dev: the device structure
*/
static void mei_virtio_intr_enable(struct mei_device *dev)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
struct virtio_device *vdev = dev_to_virtio(dev->dev);
virtio_config_enable(vdev);
virtqueue_enable_cb(hw->in);
virtqueue_enable_cb(hw->out);
}
/**
* mei_virtio_intr_disable() - disables mei BE virtqueues callbacks
*
* @dev: the device structure
*/
static void mei_virtio_intr_disable(struct mei_device *dev)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
struct virtio_device *vdev = dev_to_virtio(dev->dev);
virtio_config_disable(vdev);
virtqueue_disable_cb(hw->in);
virtqueue_disable_cb(hw->out);
}
/**
* mei_virtio_synchronize_irq() - wait for pending IRQ handlers for all
* virtqueue
* @dev: the device structure
*/
static void mei_virtio_synchronize_irq(struct mei_device *dev)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
/*
* Now, all IRQ handlers are converted to workqueue.
* Change synchronize irq to flush this work.
*/
flush_work(&hw->intr_handler);
}
static void mei_virtio_free_outbufs(struct mei_virtio_hw *hw)
{
kfree(hw->send_hdr);
kfree(hw->send_buf);
hw->send_hdr = NULL;
hw->send_buf = NULL;
}
/**
* mei_virtio_write_message() - writes a message to mei virtio back-end service.
* @dev: the device structure
* @hdr: mei header of message
* @hdr_len: header length
* @data: message payload will be written
* @data_len: message payload length
*
* Return:
* * 0: on success
* * -EIO: if write has failed
* * -ENOMEM: on memory allocation failure
*/
static int mei_virtio_write_message(struct mei_device *dev,
const void *hdr, size_t hdr_len,
const void *data, size_t data_len)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
struct scatterlist sg[2];
const void *hbuf, *dbuf;
int ret;
if (WARN_ON(!atomic_add_unless(&hw->hbuf_ready, -1, 0)))
return -EIO;
hbuf = kmemdup(hdr, hdr_len, GFP_KERNEL);
hw->send_hdr = hbuf;
dbuf = kmemdup(data, data_len, GFP_KERNEL);
hw->send_buf = dbuf;
if (!hbuf || !dbuf) {
ret = -ENOMEM;
goto fail;
}
sg_init_table(sg, 2);
sg_set_buf(&sg[0], hbuf, hdr_len);
sg_set_buf(&sg[1], dbuf, data_len);
ret = virtqueue_add_outbuf(hw->out, sg, 2, hw, GFP_KERNEL);
if (ret) {
dev_err(dev->dev, "failed to add outbuf\n");
goto fail;
}
virtqueue_kick(hw->out);
return 0;
fail:
mei_virtio_free_outbufs(hw);
return ret;
}
/**
* mei_virtio_count_full_read_slots() - counts read full slots.
* @dev: the device structure
*
* Return: -EOVERFLOW if overflow, otherwise filled slots count
*/
static int mei_virtio_count_full_read_slots(struct mei_device *dev)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
if (hw->recv_idx > hw->recv_len)
return -EOVERFLOW;
return hw->recv_len - hw->recv_idx;
}
/**
* mei_virtio_read_hdr() - Reads 32bit dword from mei virtio receive buffer
*
* @dev: the device structure
*
* Return: 32bit dword of receive buffer (u32)
*/
static inline u32 mei_virtio_read_hdr(const struct mei_device *dev)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
WARN_ON(hw->cfg.buf_depth < hw->recv_idx + 1);
return hw->recv_buf[hw->recv_idx++];
}
static int mei_virtio_read(struct mei_device *dev, unsigned char *buffer,
unsigned long len)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
u32 slots = mei_data2slots(len);
if (WARN_ON(hw->cfg.buf_depth < hw->recv_idx + slots))
return -EOVERFLOW;
/*
* Assumption: There is only one MEI message in recv_buf each time.
* Backend service need follow this rule too.
*/
memcpy(buffer, hw->recv_buf + hw->recv_idx, len);
hw->recv_idx += slots;
return 0;
}
static bool mei_virtio_pg_is_enabled(struct mei_device *dev)
{
return false;
}
static bool mei_virtio_pg_in_transition(struct mei_device *dev)
{
return false;
}
static void mei_virtio_add_recv_buf(struct mei_virtio_hw *hw)
{
struct scatterlist sg;
if (hw->recv_rdy) /* not needed */
return;
/* refill the recv_buf to IN virtqueue to get next message */
sg_init_one(&sg, hw->recv_buf, mei_slots2data(hw->cfg.buf_depth));
hw->recv_len = 0;
hw->recv_idx = 0;
hw->recv_rdy = 1;
virtqueue_add_inbuf(hw->in, &sg, 1, hw->recv_buf, GFP_KERNEL);
virtqueue_kick(hw->in);
}
/**
* mei_virtio_hw_is_ready() - check whether the BE(hw) has turned ready
* @dev: mei device
* Return: bool
*/
static bool mei_virtio_hw_is_ready(struct mei_device *dev)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
struct virtio_device *vdev = dev_to_virtio(dev->dev);
virtio_cread(vdev, struct mei_virtio_cfg,
hw_ready, &hw->cfg.hw_ready);
dev_dbg(dev->dev, "hw ready %d\n", hw->cfg.hw_ready);
return hw->cfg.hw_ready;
}
/**
* mei_virtio_hw_reset - resets virtio hw.
*
* @dev: the device structure
* @intr_enable: virtio use data/config callbacks
*
* Return: 0 on success an error code otherwise
*/
static int mei_virtio_hw_reset(struct mei_device *dev, bool intr_enable)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
struct virtio_device *vdev = dev_to_virtio(dev->dev);
dev_dbg(dev->dev, "hw reset\n");
dev->recvd_hw_ready = false;
hw->host_ready = false;
atomic_set(&hw->hbuf_ready, 0);
hw->recv_len = 0;
hw->recv_idx = 0;
hw->cfg.host_reset = 1;
virtio_cwrite(vdev, struct mei_virtio_cfg,
host_reset, &hw->cfg.host_reset);
mei_virtio_hw_is_ready(dev);
if (intr_enable)
mei_virtio_intr_enable(dev);
return 0;
}
/**
* mei_virtio_hw_reset_release() - release device from the reset
* @dev: the device structure
*/
static void mei_virtio_hw_reset_release(struct mei_device *dev)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
struct virtio_device *vdev = dev_to_virtio(dev->dev);
dev_dbg(dev->dev, "hw reset release\n");
hw->cfg.host_reset = 0;
virtio_cwrite(vdev, struct mei_virtio_cfg,
host_reset, &hw->cfg.host_reset);
}
/**
* mei_virtio_hw_ready_wait() - wait until the virtio(hw) has turned ready
* or timeout is reached
* @dev: mei device
*
* Return: 0 on success, error otherwise
*/
static int mei_virtio_hw_ready_wait(struct mei_device *dev)
{
mutex_unlock(&dev->device_lock);
wait_event_timeout(dev->wait_hw_ready,
dev->recvd_hw_ready,
mei_secs_to_jiffies(MEI_HW_READY_TIMEOUT));
mutex_lock(&dev->device_lock);
if (!dev->recvd_hw_ready) {
dev_err(dev->dev, "wait hw ready failed\n");
return -ETIMEDOUT;
}
dev->recvd_hw_ready = false;
return 0;
}
/**
* mei_virtio_hw_start() - hw start routine
* @dev: mei device
*
* Return: 0 on success, error otherwise
*/
static int mei_virtio_hw_start(struct mei_device *dev)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
int ret;
dev_dbg(dev->dev, "hw start\n");
mei_virtio_hw_reset_release(dev);
ret = mei_virtio_hw_ready_wait(dev);
if (ret)
return ret;
mei_virtio_add_recv_buf(hw);
atomic_set(&hw->hbuf_ready, 1);
dev_dbg(dev->dev, "hw is ready\n");
hw->host_ready = true;
return 0;
}
/**
* mei_virtio_host_is_ready() - check whether the FE has turned ready
* @dev: mei device
*
* Return: bool
*/
static bool mei_virtio_host_is_ready(struct mei_device *dev)
{
struct mei_virtio_hw *hw = to_virtio_hw(dev);
dev_dbg(dev->dev, "host ready %d\n", hw->host_ready);
return hw->host_ready;
}
/**
* mei_virtio_data_in() - The callback of recv virtqueue of virtio mei
* @vq: receiving virtqueue
*/
static void mei_virtio_data_in(struct virtqueue *vq)
{
struct mei_virtio_hw *hw = vq->vdev->priv;
/* disable interrupts (enabled again from in the interrupt worker) */
virtqueue_disable_cb(hw->in);
schedule_work(&hw->intr_handler);
}
/**
* mei_virtio_data_out() - The callback of send virtqueue of virtio mei
* @vq: transmitting virtqueue
*/
static void mei_virtio_data_out(struct virtqueue *vq)
{
struct mei_virtio_hw *hw = vq->vdev->priv;
schedule_work(&hw->intr_handler);
}
static void mei_virtio_intr_handler(struct work_struct *work)
{
struct mei_virtio_hw *hw =
container_of(work, struct mei_virtio_hw, intr_handler);
struct mei_device *dev = &hw->mdev;
LIST_HEAD(complete_list);
s32 slots;
int rets = 0;
void *data;
unsigned int len;
mutex_lock(&dev->device_lock);
if (dev->dev_state == MEI_DEV_DISABLED) {
dev_warn(dev->dev, "Interrupt in disabled state.\n");
mei_virtio_intr_disable(dev);
goto end;
}
/* check if ME wants a reset */
if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) {
dev_warn(dev->dev, "BE service not ready: resetting.\n");
schedule_work(&dev->reset_work);
goto end;
}
/* check if we need to start the dev */
if (!mei_host_is_ready(dev)) {
if (mei_hw_is_ready(dev)) {
dev_dbg(dev->dev, "we need to start the dev.\n");
dev->recvd_hw_ready = true;
wake_up(&dev->wait_hw_ready);
} else {
dev_warn(dev->dev, "Spurious Interrupt\n");
}
goto end;
}
/* read */
if (hw->recv_rdy) {
data = virtqueue_get_buf(hw->in, &len);
if (!data || !len) {
dev_dbg(dev->dev, "No data %d", len);
} else {
dev_dbg(dev->dev, "data_in %d\n", len);
WARN_ON(data != hw->recv_buf);
hw->recv_len = mei_data2slots(len);
hw->recv_rdy = 0;
}
}
/* write */
if (!atomic_read(&hw->hbuf_ready)) {
if (!virtqueue_get_buf(hw->out, &len)) {
dev_warn(dev->dev, "Failed to getbuf\n");
} else {
mei_virtio_free_outbufs(hw);
atomic_inc(&hw->hbuf_ready);
}
}
/* check slots available for reading */
slots = mei_count_full_read_slots(dev);
while (slots > 0) {
dev_dbg(dev->dev, "slots to read = %08x\n", slots);
rets = mei_irq_read_handler(dev, &complete_list, &slots);
if (rets &&
(dev->dev_state != MEI_DEV_RESETTING &&
dev->dev_state != MEI_DEV_POWER_DOWN)) {
dev_err(dev->dev, "mei_irq_read_handler ret = %d.\n",
rets);
schedule_work(&dev->reset_work);
goto end;
}
}
dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
mei_irq_write_handler(dev, &complete_list);
dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
mei_irq_compl_handler(dev, &complete_list);
mei_virtio_add_recv_buf(hw);
end:
if (dev->dev_state != MEI_DEV_DISABLED) {
if (!virtqueue_enable_cb(hw->in))
schedule_work(&hw->intr_handler);
}
mutex_unlock(&dev->device_lock);
}
static void mei_virtio_config_changed(struct virtio_device *vdev)
{
struct mei_virtio_hw *hw = vdev->priv;
struct mei_device *dev = &hw->mdev;
virtio_cread(vdev, struct mei_virtio_cfg,
hw_ready, &hw->cfg.hw_ready);
if (dev->dev_state == MEI_DEV_DISABLED) {
dev_dbg(dev->dev, "disabled state don't start\n");
return;
}
/* Run intr handler once to handle reset notify */
schedule_work(&hw->intr_handler);
}
static void mei_virtio_remove_vqs(struct virtio_device *vdev)
{
struct mei_virtio_hw *hw = vdev->priv;
virtqueue_detach_unused_buf(hw->in);
hw->recv_len = 0;
hw->recv_idx = 0;
hw->recv_rdy = 0;
virtqueue_detach_unused_buf(hw->out);
mei_virtio_free_outbufs(hw);
vdev->config->del_vqs(vdev);
}
/*
* There are two virtqueues, one is for send and another is for recv.
*/
static int mei_virtio_init_vqs(struct mei_virtio_hw *hw,
struct virtio_device *vdev)
{
struct virtqueue *vqs[2];
vq_callback_t *cbs[] = {
mei_virtio_data_in,
mei_virtio_data_out,
};
static const char * const names[] = {
"in",
"out",
};
int ret;
ret = virtio_find_vqs(vdev, 2, vqs, cbs, names, NULL);
if (ret)
return ret;
hw->in = vqs[0];
hw->out = vqs[1];
return 0;
}
static const struct mei_hw_ops mei_virtio_ops = {
.fw_status = mei_virtio_fw_status,
.pg_state = mei_virtio_pg_state,
.host_is_ready = mei_virtio_host_is_ready,
.hw_is_ready = mei_virtio_hw_is_ready,
.hw_reset = mei_virtio_hw_reset,
.hw_config = mei_virtio_hw_config,
.hw_start = mei_virtio_hw_start,
.pg_in_transition = mei_virtio_pg_in_transition,
.pg_is_enabled = mei_virtio_pg_is_enabled,
.intr_clear = mei_virtio_intr_clear,
.intr_enable = mei_virtio_intr_enable,
.intr_disable = mei_virtio_intr_disable,
.synchronize_irq = mei_virtio_synchronize_irq,
.hbuf_free_slots = mei_virtio_hbuf_empty_slots,
.hbuf_is_ready = mei_virtio_hbuf_is_ready,
.hbuf_depth = mei_virtio_hbuf_depth,
.write = mei_virtio_write_message,
.rdbuf_full_slots = mei_virtio_count_full_read_slots,
.read_hdr = mei_virtio_read_hdr,
.read = mei_virtio_read,
};
static int mei_virtio_probe(struct virtio_device *vdev)
{
struct mei_virtio_hw *hw;
int ret;
hw = devm_kzalloc(&vdev->dev, sizeof(*hw), GFP_KERNEL);
if (!hw)
return -ENOMEM;
vdev->priv = hw;
INIT_WORK(&hw->intr_handler, mei_virtio_intr_handler);
ret = mei_virtio_init_vqs(hw, vdev);
if (ret)
goto vqs_failed;
virtio_cread(vdev, struct mei_virtio_cfg,
buf_depth, &hw->cfg.buf_depth);
hw->recv_buf = kzalloc(mei_slots2data(hw->cfg.buf_depth), GFP_KERNEL);
if (!hw->recv_buf) {
ret = -ENOMEM;
goto hbuf_failed;
}
atomic_set(&hw->hbuf_ready, 0);
virtio_device_ready(vdev);
mei_device_init(&hw->mdev, &vdev->dev, &mei_virtio_ops);
pm_runtime_get_noresume(&vdev->dev);
pm_runtime_set_active(&vdev->dev);
pm_runtime_enable(&vdev->dev);
ret = mei_start(&hw->mdev);
if (ret)
goto mei_start_failed;
pm_runtime_set_autosuspend_delay(&vdev->dev, MEI_VIRTIO_RPM_TIMEOUT);
pm_runtime_use_autosuspend(&vdev->dev);
ret = mei_register(&hw->mdev, &vdev->dev);
if (ret)
goto mei_failed;
pm_runtime_put(&vdev->dev);
return 0;
mei_failed:
mei_stop(&hw->mdev);
mei_start_failed:
mei_cancel_work(&hw->mdev);
mei_disable_interrupts(&hw->mdev);
kfree(hw->recv_buf);
hbuf_failed:
vdev->config->del_vqs(vdev);
vqs_failed:
return ret;
}
static int __maybe_unused mei_virtio_pm_runtime_idle(struct device *device)
{
struct virtio_device *vdev = dev_to_virtio(device);
struct mei_virtio_hw *hw = vdev->priv;
dev_dbg(&vdev->dev, "rpm: mei_virtio : runtime_idle\n");
if (!hw)
return -ENODEV;
if (mei_write_is_idle(&hw->mdev))
pm_runtime_autosuspend(device);
return -EBUSY;
}
static int __maybe_unused mei_virtio_pm_runtime_suspend(struct device *device)
{
return 0;
}
static int __maybe_unused mei_virtio_pm_runtime_resume(struct device *device)
{
return 0;
}
static int __maybe_unused mei_virtio_freeze(struct virtio_device *vdev)
{
struct mei_virtio_hw *hw = vdev->priv;
dev_dbg(&vdev->dev, "freeze\n");
if (!hw)
return -ENODEV;
mei_stop(&hw->mdev);
mei_disable_interrupts(&hw->mdev);
cancel_work_sync(&hw->intr_handler);
vdev->config->reset(vdev);
mei_virtio_remove_vqs(vdev);
return 0;
}
static int __maybe_unused mei_virtio_restore(struct virtio_device *vdev)
{
struct mei_virtio_hw *hw = vdev->priv;
int ret;
dev_dbg(&vdev->dev, "restore\n");
if (!hw)
return -ENODEV;
ret = mei_virtio_init_vqs(hw, vdev);
if (ret)
return ret;
virtio_device_ready(vdev);
ret = mei_restart(&hw->mdev);
if (ret)
return ret;
/* Start timer if stopped in suspend */
schedule_delayed_work(&hw->mdev.timer_work, HZ);
return 0;
}
static const struct dev_pm_ops mei_virtio_pm_ops = {
SET_RUNTIME_PM_OPS(mei_virtio_pm_runtime_suspend,
mei_virtio_pm_runtime_resume,
mei_virtio_pm_runtime_idle)
};
static void mei_virtio_remove(struct virtio_device *vdev)
{
struct mei_virtio_hw *hw = vdev->priv;
mei_stop(&hw->mdev);
mei_disable_interrupts(&hw->mdev);
cancel_work_sync(&hw->intr_handler);
mei_deregister(&hw->mdev);
vdev->config->reset(vdev);
mei_virtio_remove_vqs(vdev);
kfree(hw->recv_buf);
pm_runtime_disable(&vdev->dev);
}
static struct virtio_device_id id_table[] = {
{ VIRTIO_ID_MEI, VIRTIO_DEV_ANY_ID },
{ }
};
static struct virtio_driver mei_virtio_driver = {
.id_table = id_table,
.probe = mei_virtio_probe,
.remove = mei_virtio_remove,
.config_changed = mei_virtio_config_changed,
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
.pm = &mei_virtio_pm_ops,
},
#ifdef CONFIG_PM_SLEEP
.freeze = mei_virtio_freeze,
.restore = mei_virtio_restore,
#endif
};
module_virtio_driver(mei_virtio_driver);
MODULE_DEVICE_TABLE(virtio, id_table);
MODULE_DESCRIPTION("Virtio MEI frontend driver");
MODULE_LICENSE("GPL v2");

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