mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
Merge 25a1298726 ("Merge tag 'trace-v5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace") into android-mainline
Steps on the way to 5.13-rc2 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Ib2fbae76b080fbf6a27d531c966ae543eecaae01
This commit is contained in:
1
.mailmap
1
.mailmap
@@ -160,6 +160,7 @@ Jeff Layton <jlayton@kernel.org> <jlayton@primarydata.com>
|
||||
Jeff Layton <jlayton@kernel.org> <jlayton@redhat.com>
|
||||
Jens Axboe <axboe@suse.de>
|
||||
Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
|
||||
Jernej Skrabec <jernej.skrabec@gmail.com> <jernej.skrabec@siol.net>
|
||||
Jiri Slaby <jirislaby@kernel.org> <jirislaby@gmail.com>
|
||||
Jiri Slaby <jirislaby@kernel.org> <jslaby@novell.com>
|
||||
Jiri Slaby <jirislaby@kernel.org> <jslaby@suse.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
This ABI is renamed and moved to a new location /sys/kernel/fadump/registered.¬
|
||||
This ABI is renamed and moved to a new location /sys/kernel/fadump/registered.
|
||||
|
||||
What: /sys/kernel/fadump_registered
|
||||
Date: Feb 2012
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
This ABI is renamed and moved to a new location /sys/kernel/fadump/release_mem.¬
|
||||
This ABI is renamed and moved to a new location /sys/kernel/fadump/release_mem.
|
||||
|
||||
What: /sys/kernel/fadump_release_mem
|
||||
Date: Feb 2012
|
||||
|
||||
@@ -37,13 +37,13 @@ Description: Maximum time allowed for periodic transfers per microframe (μs)
|
||||
|
||||
What: /sys/module/*/{coresize,initsize}
|
||||
Date: Jan 2012
|
||||
KernelVersion:»·3.3
|
||||
KernelVersion: 3.3
|
||||
Contact: Kay Sievers <kay.sievers@vrfy.org>
|
||||
Description: Module size in bytes.
|
||||
|
||||
What: /sys/module/*/taint
|
||||
Date: Jan 2012
|
||||
KernelVersion:»·3.3
|
||||
KernelVersion: 3.3
|
||||
Contact: Kay Sievers <kay.sievers@vrfy.org>
|
||||
Description: Module taint flags:
|
||||
== =====================
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
==============
|
||||
==============
|
||||
Data Integrity
|
||||
==============
|
||||
|
||||
|
||||
@@ -146,18 +146,18 @@ with the kernel as a block device by registering the following general
|
||||
*struct file_operations*::
|
||||
|
||||
struct file_operations cdrom_fops = {
|
||||
NULL, /∗ lseek ∗/
|
||||
block _read , /∗ read—general block-dev read ∗/
|
||||
block _write, /∗ write—general block-dev write ∗/
|
||||
NULL, /∗ readdir ∗/
|
||||
NULL, /∗ select ∗/
|
||||
cdrom_ioctl, /∗ ioctl ∗/
|
||||
NULL, /∗ mmap ∗/
|
||||
cdrom_open, /∗ open ∗/
|
||||
cdrom_release, /∗ release ∗/
|
||||
NULL, /∗ fsync ∗/
|
||||
NULL, /∗ fasync ∗/
|
||||
NULL /∗ revalidate ∗/
|
||||
NULL, /* lseek */
|
||||
block _read , /* read--general block-dev read */
|
||||
block _write, /* write--general block-dev write */
|
||||
NULL, /* readdir */
|
||||
NULL, /* select */
|
||||
cdrom_ioctl, /* ioctl */
|
||||
NULL, /* mmap */
|
||||
cdrom_open, /* open */
|
||||
cdrom_release, /* release */
|
||||
NULL, /* fsync */
|
||||
NULL, /* fasync */
|
||||
NULL /* revalidate */
|
||||
};
|
||||
|
||||
Every active CD-ROM device shares this *struct*. The routines
|
||||
@@ -250,12 +250,12 @@ The drive-specific, minor-like information that is registered with
|
||||
`cdrom.c`, currently contains the following fields::
|
||||
|
||||
struct cdrom_device_info {
|
||||
const struct cdrom_device_ops * ops; /* device operations for this major */
|
||||
const struct cdrom_device_ops * ops; /* device operations for this major */
|
||||
struct list_head list; /* linked list of all device_info */
|
||||
struct gendisk * disk; /* matching block layer disk */
|
||||
void * handle; /* driver-dependent data */
|
||||
|
||||
int mask; /* mask of capability: disables them */
|
||||
int mask; /* mask of capability: disables them */
|
||||
int speed; /* maximum speed for reading data */
|
||||
int capacity; /* number of discs in a jukebox */
|
||||
|
||||
@@ -569,7 +569,7 @@ the *CDC_CLOSE_TRAY* bit in *mask*.
|
||||
|
||||
In the file `cdrom.c` you will encounter many constructions of the type::
|
||||
|
||||
if (cdo->capability & ∼cdi->mask & CDC _⟨capability⟩) ...
|
||||
if (cdo->capability & ~cdi->mask & CDC _<capability>) ...
|
||||
|
||||
There is no *ioctl* to set the mask... The reason is that
|
||||
I think it is better to control the **behavior** rather than the
|
||||
|
||||
@@ -19,7 +19,6 @@ Serial drivers
|
||||
|
||||
moxa-smartio
|
||||
n_gsm
|
||||
rocket
|
||||
serial-iso7816
|
||||
serial-rs485
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@ Description
|
||||
The TMP103 is a digital output temperature sensor in a four-ball
|
||||
wafer chip-scale package (WCSP). The TMP103 is capable of reading
|
||||
temperatures to a resolution of 1°C. The TMP103 is specified for
|
||||
operation over a temperature range of –40°C to +125°C.
|
||||
operation over a temperature range of -40°C to +125°C.
|
||||
|
||||
Resolution: 8 Bits
|
||||
Accuracy: ±1°C Typ (–10°C to +100°C)
|
||||
Accuracy: ±1°C Typ (-10°C to +100°C)
|
||||
|
||||
The driver provides the common sysfs-interface for temperatures (see
|
||||
Documentation/hwmon/sysfs-interface.rst under Temperatures).
|
||||
|
||||
@@ -173,7 +173,7 @@ Director rule is added from ethtool (Sideband filter), ATR is turned off by the
|
||||
driver. To re-enable ATR, the sideband can be disabled with the ethtool -K
|
||||
option. For example::
|
||||
|
||||
ethtool –K [adapter] ntuple [off|on]
|
||||
ethtool -K [adapter] ntuple [off|on]
|
||||
|
||||
If sideband is re-enabled after ATR is re-enabled, ATR remains enabled until a
|
||||
TCP-IP flow is added. When all TCP-IP sideband rules are deleted, ATR is
|
||||
@@ -688,7 +688,7 @@ shaper bw_rlimit: for each tc, sets minimum and maximum bandwidth rates.
|
||||
Totals must be equal or less than port speed.
|
||||
|
||||
For example: min_rate 1Gbit 3Gbit: Verify bandwidth limit using network
|
||||
monitoring tools such as ifstat or sar –n DEV [interval] [number of samples]
|
||||
monitoring tools such as `ifstat` or `sar -n DEV [interval] [number of samples]`
|
||||
|
||||
2. Enable HW TC offload on interface::
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ shaper bw_rlimit: for each tc, sets minimum and maximum bandwidth rates.
|
||||
Totals must be equal or less than port speed.
|
||||
|
||||
For example: min_rate 1Gbit 3Gbit: Verify bandwidth limit using network
|
||||
monitoring tools such as ifstat or sar –n DEV [interval] [number of samples]
|
||||
monitoring tools such as ``ifstat`` or ``sar -n DEV [interval] [number of samples]``
|
||||
|
||||
NOTE:
|
||||
Setting up channels via ethtool (ethtool -L) is not supported when the
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.. _process_statement_kernel:
|
||||
.. _process_statement_kernel:
|
||||
|
||||
Linux Kernel Enforcement Statement
|
||||
----------------------------------
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
=============================
|
||||
=============================
|
||||
Virtual TPM interface for Xen
|
||||
=============================
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
======================================
|
||||
======================================
|
||||
NO_HZ: Reducing Scheduling-Clock Ticks
|
||||
======================================
|
||||
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
Chinese translated version of Documentation/admin-guide/security-bugs.rst
|
||||
|
||||
If you have any comment or update to the content, please contact the
|
||||
original document maintainer directly. However, if you have a problem
|
||||
communicating in English you can also ask the Chinese maintainer for
|
||||
help. Contact the Chinese maintainer if this translation is outdated
|
||||
or if there is a problem with the translation.
|
||||
|
||||
Chinese maintainer: Harry Wei <harryxiyou@gmail.com>
|
||||
---------------------------------------------------------------------
|
||||
Documentation/admin-guide/security-bugs.rst 的中文翻译
|
||||
|
||||
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
|
||||
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
|
||||
译存在问题,请联系中文版维护者。
|
||||
|
||||
中文版维护者: 贾威威 Harry Wei <harryxiyou@gmail.com>
|
||||
中文版翻译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
|
||||
中文版校译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
|
||||
|
||||
|
||||
以下为正文
|
||||
---------------------------------------------------------------------
|
||||
Linux内核开发者认为安全非常重要。因此,我们想要知道当一个有关于
|
||||
安全的漏洞被发现的时候,并且它可能会被尽快的修复或者公开。请把这个安全
|
||||
漏洞报告给Linux内核安全团队。
|
||||
|
||||
1) 联系
|
||||
|
||||
linux内核安全团队可以通过email<security@kernel.org>来联系。这是
|
||||
一组独立的安全工作人员,可以帮助改善漏洞报告并且公布和取消一个修复。安
|
||||
全团队有可能会从部分的维护者那里引进额外的帮助来了解并且修复安全漏洞。
|
||||
当遇到任何漏洞,所能提供的信息越多就越能诊断和修复。如果你不清楚什么
|
||||
是有帮助的信息,那就请重温一下admin-guide/reporting-bugs.rst文件中的概述过程。任
|
||||
何攻击性的代码都是非常有用的,未经报告者的同意不会被取消,除非它已经
|
||||
被公布于众。
|
||||
|
||||
2) 公开
|
||||
|
||||
Linux内核安全团队的宗旨就是和漏洞提交者一起处理漏洞的解决方案直
|
||||
到公开。我们喜欢尽快地完全公开漏洞。当一个漏洞或者修复还没有被完全地理
|
||||
解,解决方案没有通过测试或者供应商协调,可以合理地延迟公开。然而,我们
|
||||
期望这些延迟尽可能的短些,是可数的几天,而不是几个星期或者几个月。公开
|
||||
日期是通过安全团队和漏洞提供者以及供应商洽谈后的结果。公开时间表是从很
|
||||
短(特殊的,它已经被公众所知道)到几个星期。作为一个基本的默认政策,我
|
||||
们所期望通知公众的日期是7天的安排。
|
||||
|
||||
3) 保密协议
|
||||
|
||||
Linux内核安全团队不是一个正式的团体,因此不能加入任何的保密协议。
|
||||
@@ -1,4 +1,4 @@
|
||||
================
|
||||
================
|
||||
mtouchusb driver
|
||||
================
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
==========
|
||||
==========
|
||||
USB serial
|
||||
==========
|
||||
|
||||
|
||||
@@ -4803,7 +4803,7 @@ KVM_PV_VM_VERIFY
|
||||
4.126 KVM_X86_SET_MSR_FILTER
|
||||
----------------------------
|
||||
|
||||
:Capability: KVM_X86_SET_MSR_FILTER
|
||||
:Capability: KVM_CAP_X86_MSR_FILTER
|
||||
:Architectures: x86
|
||||
:Type: vm ioctl
|
||||
:Parameters: struct kvm_msr_filter
|
||||
@@ -6715,7 +6715,7 @@ accesses that would usually trigger a #GP by KVM into the guest will
|
||||
instead get bounced to user space through the KVM_EXIT_X86_RDMSR and
|
||||
KVM_EXIT_X86_WRMSR exit notifications.
|
||||
|
||||
8.27 KVM_X86_SET_MSR_FILTER
|
||||
8.27 KVM_CAP_X86_MSR_FILTER
|
||||
---------------------------
|
||||
|
||||
:Architectures: x86
|
||||
|
||||
18
MAINTAINERS
18
MAINTAINERS
@@ -1578,7 +1578,7 @@ F: drivers/clk/sunxi/
|
||||
ARM/Allwinner sunXi SoC support
|
||||
M: Maxime Ripard <mripard@kernel.org>
|
||||
M: Chen-Yu Tsai <wens@csie.org>
|
||||
R: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
R: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git
|
||||
@@ -5089,7 +5089,7 @@ S: Maintained
|
||||
F: drivers/net/fddi/defza.*
|
||||
|
||||
DEINTERLACE DRIVERS FOR ALLWINNER H3
|
||||
M: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
M: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
@@ -5632,14 +5632,14 @@ F: include/linux/power/smartreflex.h
|
||||
DRM DRIVER FOR ALLWINNER DE2 AND DE3 ENGINE
|
||||
M: Maxime Ripard <mripard@kernel.org>
|
||||
M: Chen-Yu Tsai <wens@csie.org>
|
||||
R: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
R: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
S: Supported
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: drivers/gpu/drm/sun4i/sun8i*
|
||||
|
||||
DRM DRIVER FOR ARM PL111 CLCD
|
||||
M: Eric Anholt <eric@anholt.net>
|
||||
M: Emma Anholt <emma@anholt.net>
|
||||
S: Supported
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: drivers/gpu/drm/pl111/
|
||||
@@ -5719,7 +5719,7 @@ T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: drivers/gpu/drm/tiny/gm12u320.c
|
||||
|
||||
DRM DRIVER FOR HX8357D PANELS
|
||||
M: Eric Anholt <eric@anholt.net>
|
||||
M: Emma Anholt <emma@anholt.net>
|
||||
S: Maintained
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: Documentation/devicetree/bindings/display/himax,hx8357d.txt
|
||||
@@ -6023,7 +6023,7 @@ M: Neil Armstrong <narmstrong@baylibre.com>
|
||||
M: Robert Foss <robert.foss@linaro.org>
|
||||
R: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
|
||||
R: Jonas Karlman <jonas@kwiboo.se>
|
||||
R: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
R: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
S: Maintained
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: drivers/gpu/drm/bridge/
|
||||
@@ -6177,7 +6177,7 @@ F: Documentation/devicetree/bindings/display/ti/
|
||||
F: drivers/gpu/drm/omapdrm/
|
||||
|
||||
DRM DRIVERS FOR V3D
|
||||
M: Eric Anholt <eric@anholt.net>
|
||||
M: Emma Anholt <emma@anholt.net>
|
||||
S: Supported
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml
|
||||
@@ -6185,7 +6185,7 @@ F: drivers/gpu/drm/v3d/
|
||||
F: include/uapi/drm/v3d_drm.h
|
||||
|
||||
DRM DRIVERS FOR VC4
|
||||
M: Eric Anholt <eric@anholt.net>
|
||||
M: Emma Anholt <emma@anholt.net>
|
||||
M: Maxime Ripard <mripard@kernel.org>
|
||||
S: Supported
|
||||
T: git git://github.com/anholt/linux
|
||||
@@ -15828,7 +15828,7 @@ F: include/uapi/linux/rose.h
|
||||
F: net/rose/
|
||||
|
||||
ROTATION DRIVER FOR ALLWINNER A83T
|
||||
M: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
M: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
|
||||
@@ -175,6 +175,9 @@ vdso_install:
|
||||
$(if $(CONFIG_COMPAT_VDSO), \
|
||||
$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 $@)
|
||||
|
||||
archprepare:
|
||||
$(Q)$(MAKE) $(build)=arch/arm64/tools kapi
|
||||
|
||||
# We use MRPROPER_FILES and CLEAN_FILES now
|
||||
archclean:
|
||||
$(Q)$(MAKE) $(clean)=$(boot)
|
||||
|
||||
@@ -5,3 +5,5 @@ generic-y += qrwlock.h
|
||||
generic-y += qspinlock.h
|
||||
generic-y += set_memory.h
|
||||
generic-y += user.h
|
||||
|
||||
generated-y += cpucaps.h
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* arch/arm64/include/asm/cpucaps.h
|
||||
*
|
||||
* Copyright (C) 2016 ARM Ltd.
|
||||
*/
|
||||
#ifndef __ASM_CPUCAPS_H
|
||||
#define __ASM_CPUCAPS_H
|
||||
|
||||
#define ARM64_WORKAROUND_CLEAN_CACHE 0
|
||||
#define ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE 1
|
||||
#define ARM64_WORKAROUND_845719 2
|
||||
#define ARM64_HAS_SYSREG_GIC_CPUIF 3
|
||||
#define ARM64_HAS_PAN 4
|
||||
#define ARM64_HAS_LSE_ATOMICS 5
|
||||
#define ARM64_WORKAROUND_CAVIUM_23154 6
|
||||
#define ARM64_WORKAROUND_834220 7
|
||||
#define ARM64_HAS_NO_HW_PREFETCH 8
|
||||
#define ARM64_HAS_VIRT_HOST_EXTN 11
|
||||
#define ARM64_WORKAROUND_CAVIUM_27456 12
|
||||
#define ARM64_HAS_32BIT_EL0 13
|
||||
#define ARM64_SPECTRE_V3A 14
|
||||
#define ARM64_HAS_CNP 15
|
||||
#define ARM64_HAS_NO_FPSIMD 16
|
||||
#define ARM64_WORKAROUND_REPEAT_TLBI 17
|
||||
#define ARM64_WORKAROUND_QCOM_FALKOR_E1003 18
|
||||
#define ARM64_WORKAROUND_858921 19
|
||||
#define ARM64_WORKAROUND_CAVIUM_30115 20
|
||||
#define ARM64_HAS_DCPOP 21
|
||||
#define ARM64_SVE 22
|
||||
#define ARM64_UNMAP_KERNEL_AT_EL0 23
|
||||
#define ARM64_SPECTRE_V2 24
|
||||
#define ARM64_HAS_RAS_EXTN 25
|
||||
#define ARM64_WORKAROUND_843419 26
|
||||
#define ARM64_HAS_CACHE_IDC 27
|
||||
#define ARM64_HAS_CACHE_DIC 28
|
||||
#define ARM64_HW_DBM 29
|
||||
#define ARM64_SPECTRE_V4 30
|
||||
#define ARM64_MISMATCHED_CACHE_TYPE 31
|
||||
#define ARM64_HAS_STAGE2_FWB 32
|
||||
#define ARM64_HAS_CRC32 33
|
||||
#define ARM64_SSBS 34
|
||||
#define ARM64_WORKAROUND_1418040 35
|
||||
#define ARM64_HAS_SB 36
|
||||
#define ARM64_WORKAROUND_SPECULATIVE_AT 37
|
||||
#define ARM64_HAS_ADDRESS_AUTH_ARCH 38
|
||||
#define ARM64_HAS_ADDRESS_AUTH_IMP_DEF 39
|
||||
#define ARM64_HAS_GENERIC_AUTH_ARCH 40
|
||||
#define ARM64_HAS_GENERIC_AUTH_IMP_DEF 41
|
||||
#define ARM64_HAS_IRQ_PRIO_MASKING 42
|
||||
#define ARM64_HAS_DCPODP 43
|
||||
#define ARM64_WORKAROUND_1463225 44
|
||||
#define ARM64_WORKAROUND_CAVIUM_TX2_219_TVM 45
|
||||
#define ARM64_WORKAROUND_CAVIUM_TX2_219_PRFM 46
|
||||
#define ARM64_WORKAROUND_1542419 47
|
||||
#define ARM64_HAS_E0PD 48
|
||||
#define ARM64_HAS_RNG 49
|
||||
#define ARM64_HAS_AMU_EXTN 50
|
||||
#define ARM64_HAS_ADDRESS_AUTH 51
|
||||
#define ARM64_HAS_GENERIC_AUTH 52
|
||||
#define ARM64_HAS_32BIT_EL1 53
|
||||
#define ARM64_BTI 54
|
||||
#define ARM64_HAS_ARMv8_4_TTL 55
|
||||
#define ARM64_HAS_TLB_RANGE 56
|
||||
#define ARM64_MTE 57
|
||||
#define ARM64_WORKAROUND_1508412 58
|
||||
#define ARM64_HAS_LDAPR 59
|
||||
#define ARM64_KVM_PROTECTED_MODE 60
|
||||
#define ARM64_WORKAROUND_NVIDIA_CARMEL_CNP 61
|
||||
#define ARM64_HAS_EPAN 62
|
||||
|
||||
#define ARM64_NCAPS 63
|
||||
|
||||
#endif /* __ASM_CPUCAPS_H */
|
||||
@@ -55,8 +55,10 @@ void __sync_icache_dcache(pte_t pte)
|
||||
{
|
||||
struct page *page = pte_page(pte);
|
||||
|
||||
if (!test_and_set_bit(PG_dcache_clean, &page->flags))
|
||||
if (!test_bit(PG_dcache_clean, &page->flags)) {
|
||||
sync_icache_aliases(page_address(page), page_size(page));
|
||||
set_bit(PG_dcache_clean, &page->flags);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__sync_icache_dcache);
|
||||
|
||||
|
||||
@@ -447,6 +447,18 @@ SYM_FUNC_START(__cpu_setup)
|
||||
mov x10, #(SYS_GCR_EL1_RRND | SYS_GCR_EL1_EXCL_MASK)
|
||||
msr_s SYS_GCR_EL1, x10
|
||||
|
||||
/*
|
||||
* If GCR_EL1.RRND=1 is implemented the same way as RRND=0, then
|
||||
* RGSR_EL1.SEED must be non-zero for IRG to produce
|
||||
* pseudorandom numbers. As RGSR_EL1 is UNKNOWN out of reset, we
|
||||
* must initialize it.
|
||||
*/
|
||||
mrs x10, CNTVCT_EL0
|
||||
ands x10, x10, #SYS_RGSR_EL1_SEED_MASK
|
||||
csinc x10, x10, xzr, ne
|
||||
lsl x10, x10, #SYS_RGSR_EL1_SEED_SHIFT
|
||||
msr_s SYS_RGSR_EL1, x10
|
||||
|
||||
/* clear any pending tag check faults in TFSR*_EL1 */
|
||||
msr_s SYS_TFSR_EL1, xzr
|
||||
msr_s SYS_TFSRE0_EL1, xzr
|
||||
|
||||
22
arch/arm64/tools/Makefile
Normal file
22
arch/arm64/tools/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
gen := arch/$(ARCH)/include/generated
|
||||
kapi := $(gen)/asm
|
||||
|
||||
kapi-hdrs-y := $(kapi)/cpucaps.h
|
||||
|
||||
targets += $(addprefix ../../../,$(gen-y) $(kapi-hdrs-y))
|
||||
|
||||
PHONY += kapi
|
||||
|
||||
kapi: $(kapi-hdrs-y) $(gen-y)
|
||||
|
||||
# Create output directory if not already present
|
||||
_dummy := $(shell [ -d '$(kapi)' ] || mkdir -p '$(kapi)')
|
||||
|
||||
quiet_cmd_gen_cpucaps = GEN $@
|
||||
cmd_gen_cpucaps = mkdir -p $(dir $@) && \
|
||||
$(AWK) -f $(filter-out $(PHONY),$^) > $@
|
||||
|
||||
$(kapi)/cpucaps.h: $(src)/gen-cpucaps.awk $(src)/cpucaps FORCE
|
||||
$(call if_changed,gen_cpucaps)
|
||||
65
arch/arm64/tools/cpucaps
Normal file
65
arch/arm64/tools/cpucaps
Normal file
@@ -0,0 +1,65 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Internal CPU capabilities constants, keep this list sorted
|
||||
|
||||
BTI
|
||||
HAS_32BIT_EL0
|
||||
HAS_32BIT_EL1
|
||||
HAS_ADDRESS_AUTH
|
||||
HAS_ADDRESS_AUTH_ARCH
|
||||
HAS_ADDRESS_AUTH_IMP_DEF
|
||||
HAS_AMU_EXTN
|
||||
HAS_ARMv8_4_TTL
|
||||
HAS_CACHE_DIC
|
||||
HAS_CACHE_IDC
|
||||
HAS_CNP
|
||||
HAS_CRC32
|
||||
HAS_DCPODP
|
||||
HAS_DCPOP
|
||||
HAS_E0PD
|
||||
HAS_EPAN
|
||||
HAS_GENERIC_AUTH
|
||||
HAS_GENERIC_AUTH_ARCH
|
||||
HAS_GENERIC_AUTH_IMP_DEF
|
||||
HAS_IRQ_PRIO_MASKING
|
||||
HAS_LDAPR
|
||||
HAS_LSE_ATOMICS
|
||||
HAS_NO_FPSIMD
|
||||
HAS_NO_HW_PREFETCH
|
||||
HAS_PAN
|
||||
HAS_RAS_EXTN
|
||||
HAS_RNG
|
||||
HAS_SB
|
||||
HAS_STAGE2_FWB
|
||||
HAS_SYSREG_GIC_CPUIF
|
||||
HAS_TLB_RANGE
|
||||
HAS_VIRT_HOST_EXTN
|
||||
HW_DBM
|
||||
KVM_PROTECTED_MODE
|
||||
MISMATCHED_CACHE_TYPE
|
||||
MTE
|
||||
SPECTRE_V2
|
||||
SPECTRE_V3A
|
||||
SPECTRE_V4
|
||||
SSBS
|
||||
SVE
|
||||
UNMAP_KERNEL_AT_EL0
|
||||
WORKAROUND_834220
|
||||
WORKAROUND_843419
|
||||
WORKAROUND_845719
|
||||
WORKAROUND_858921
|
||||
WORKAROUND_1418040
|
||||
WORKAROUND_1463225
|
||||
WORKAROUND_1508412
|
||||
WORKAROUND_1542419
|
||||
WORKAROUND_CAVIUM_23154
|
||||
WORKAROUND_CAVIUM_27456
|
||||
WORKAROUND_CAVIUM_30115
|
||||
WORKAROUND_CAVIUM_TX2_219_PRFM
|
||||
WORKAROUND_CAVIUM_TX2_219_TVM
|
||||
WORKAROUND_CLEAN_CACHE
|
||||
WORKAROUND_DEVICE_LOAD_ACQUIRE
|
||||
WORKAROUND_NVIDIA_CARMEL_CNP
|
||||
WORKAROUND_QCOM_FALKOR_E1003
|
||||
WORKAROUND_REPEAT_TLBI
|
||||
WORKAROUND_SPECULATIVE_AT
|
||||
40
arch/arm64/tools/gen-cpucaps.awk
Executable file
40
arch/arm64/tools/gen-cpucaps.awk
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/awk -f
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# gen-cpucaps.awk: arm64 cpucaps header generator
|
||||
#
|
||||
# Usage: awk -f gen-cpucaps.awk cpucaps.txt
|
||||
|
||||
# Log an error and terminate
|
||||
function fatal(msg) {
|
||||
print "Error at line " NR ": " msg > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# skip blank lines and comment lines
|
||||
/^$/ { next }
|
||||
/^#/ { next }
|
||||
|
||||
BEGIN {
|
||||
print "#ifndef __ASM_CPUCAPS_H"
|
||||
print "#define __ASM_CPUCAPS_H"
|
||||
print ""
|
||||
print "/* Generated file - do not edit */"
|
||||
cap_num = 0
|
||||
print ""
|
||||
}
|
||||
|
||||
/^[vA-Z0-9_]+$/ {
|
||||
printf("#define ARM64_%-30s\t%d\n", $0, cap_num++)
|
||||
next
|
||||
}
|
||||
|
||||
END {
|
||||
printf("#define ARM64_NCAPS\t\t\t\t%d\n", cap_num)
|
||||
print ""
|
||||
print "#endif /* __ASM_CPUCAPS_H */"
|
||||
}
|
||||
|
||||
# Any lines not handled by previous rules are unexpected
|
||||
{
|
||||
fatal("unhandled statement")
|
||||
}
|
||||
@@ -113,6 +113,7 @@
|
||||
#define VALID_PAGE(x) ((x) != INVALID_PAGE)
|
||||
|
||||
#define UNMAPPED_GVA (~(gpa_t)0)
|
||||
#define INVALID_GPA (~(gpa_t)0)
|
||||
|
||||
/* KVM Hugepage definitions for x86 */
|
||||
#define KVM_MAX_HUGEPAGE_LEVEL PG_LEVEL_1G
|
||||
@@ -199,6 +200,7 @@ enum x86_intercept_stage;
|
||||
|
||||
#define KVM_NR_DB_REGS 4
|
||||
|
||||
#define DR6_BUS_LOCK (1 << 11)
|
||||
#define DR6_BD (1 << 13)
|
||||
#define DR6_BS (1 << 14)
|
||||
#define DR6_BT (1 << 15)
|
||||
@@ -212,7 +214,7 @@ enum x86_intercept_stage;
|
||||
* DR6_ACTIVE_LOW is also used as the init/reset value for DR6.
|
||||
*/
|
||||
#define DR6_ACTIVE_LOW 0xffff0ff0
|
||||
#define DR6_VOLATILE 0x0001e00f
|
||||
#define DR6_VOLATILE 0x0001e80f
|
||||
#define DR6_FIXED_1 (DR6_ACTIVE_LOW & ~DR6_VOLATILE)
|
||||
|
||||
#define DR7_BP_EN_MASK 0x000000ff
|
||||
@@ -407,7 +409,7 @@ struct kvm_mmu {
|
||||
u32 pkru_mask;
|
||||
|
||||
u64 *pae_root;
|
||||
u64 *lm_root;
|
||||
u64 *pml4_root;
|
||||
|
||||
/*
|
||||
* check zero bits on shadow page table entries, these
|
||||
@@ -1417,6 +1419,7 @@ struct kvm_arch_async_pf {
|
||||
bool direct_map;
|
||||
};
|
||||
|
||||
extern u32 __read_mostly kvm_nr_uret_msrs;
|
||||
extern u64 __read_mostly host_efer;
|
||||
extern bool __read_mostly allow_smaller_maxphyaddr;
|
||||
extern struct kvm_x86_ops kvm_x86_ops;
|
||||
@@ -1775,9 +1778,15 @@ int kvm_pv_send_ipi(struct kvm *kvm, unsigned long ipi_bitmap_low,
|
||||
unsigned long ipi_bitmap_high, u32 min,
|
||||
unsigned long icr, int op_64_bit);
|
||||
|
||||
void kvm_define_user_return_msr(unsigned index, u32 msr);
|
||||
int kvm_add_user_return_msr(u32 msr);
|
||||
int kvm_find_user_return_msr(u32 msr);
|
||||
int kvm_set_user_return_msr(unsigned index, u64 val, u64 mask);
|
||||
|
||||
static inline bool kvm_is_supported_user_return_msr(u32 msr)
|
||||
{
|
||||
return kvm_find_user_return_msr(msr) >= 0;
|
||||
}
|
||||
|
||||
u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc);
|
||||
u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc);
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <uapi/asm/kvm_para.h>
|
||||
|
||||
extern void kvmclock_init(void);
|
||||
|
||||
#ifdef CONFIG_KVM_GUEST
|
||||
bool kvm_check_and_clear_guest_paused(void);
|
||||
#else
|
||||
@@ -86,13 +84,14 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KVM_GUEST
|
||||
void kvmclock_init(void);
|
||||
void kvmclock_disable(void);
|
||||
bool kvm_para_available(void);
|
||||
unsigned int kvm_arch_para_features(void);
|
||||
unsigned int kvm_arch_para_hints(void);
|
||||
void kvm_async_pf_task_wait_schedule(u32 token);
|
||||
void kvm_async_pf_task_wake(u32 token);
|
||||
u32 kvm_read_and_reset_apf_flags(void);
|
||||
void kvm_disable_steal_time(void);
|
||||
bool __kvm_handle_async_pf(struct pt_regs *regs, u32 token);
|
||||
|
||||
DECLARE_STATIC_KEY_FALSE(kvm_async_pf_enabled);
|
||||
@@ -137,11 +136,6 @@ static inline u32 kvm_read_and_reset_apf_flags(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void kvm_disable_steal_time(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static __always_inline bool kvm_handle_async_pf(struct pt_regs *regs, u32 token)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -437,6 +437,8 @@ struct kvm_vmx_nested_state_hdr {
|
||||
__u16 flags;
|
||||
} smm;
|
||||
|
||||
__u16 pad;
|
||||
|
||||
__u32 flags;
|
||||
__u64 preemption_timer_deadline;
|
||||
};
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/swait.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <asm/timer.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/traps.h>
|
||||
@@ -37,6 +38,7 @@
|
||||
#include <asm/tlb.h>
|
||||
#include <asm/cpuidle_haltpoll.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/svm.h>
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(kvm_async_pf_enabled);
|
||||
@@ -345,7 +347,7 @@ static void kvm_guest_cpu_init(void)
|
||||
|
||||
wrmsrl(MSR_KVM_ASYNC_PF_EN, pa);
|
||||
__this_cpu_write(apf_reason.enabled, 1);
|
||||
pr_info("KVM setup async PF for cpu %d\n", smp_processor_id());
|
||||
pr_info("setup async PF for cpu %d\n", smp_processor_id());
|
||||
}
|
||||
|
||||
if (kvm_para_has_feature(KVM_FEATURE_PV_EOI)) {
|
||||
@@ -371,34 +373,17 @@ static void kvm_pv_disable_apf(void)
|
||||
wrmsrl(MSR_KVM_ASYNC_PF_EN, 0);
|
||||
__this_cpu_write(apf_reason.enabled, 0);
|
||||
|
||||
pr_info("Unregister pv shared memory for cpu %d\n", smp_processor_id());
|
||||
pr_info("disable async PF for cpu %d\n", smp_processor_id());
|
||||
}
|
||||
|
||||
static void kvm_pv_guest_cpu_reboot(void *unused)
|
||||
static void kvm_disable_steal_time(void)
|
||||
{
|
||||
/*
|
||||
* We disable PV EOI before we load a new kernel by kexec,
|
||||
* since MSR_KVM_PV_EOI_EN stores a pointer into old kernel's memory.
|
||||
* New kernel can re-enable when it boots.
|
||||
*/
|
||||
if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
|
||||
wrmsrl(MSR_KVM_PV_EOI_EN, 0);
|
||||
kvm_pv_disable_apf();
|
||||
kvm_disable_steal_time();
|
||||
}
|
||||
if (!has_steal_clock)
|
||||
return;
|
||||
|
||||
static int kvm_pv_reboot_notify(struct notifier_block *nb,
|
||||
unsigned long code, void *unused)
|
||||
{
|
||||
if (code == SYS_RESTART)
|
||||
on_each_cpu(kvm_pv_guest_cpu_reboot, NULL, 1);
|
||||
return NOTIFY_DONE;
|
||||
wrmsr(MSR_KVM_STEAL_TIME, 0, 0);
|
||||
}
|
||||
|
||||
static struct notifier_block kvm_pv_reboot_nb = {
|
||||
.notifier_call = kvm_pv_reboot_notify,
|
||||
};
|
||||
|
||||
static u64 kvm_steal_clock(int cpu)
|
||||
{
|
||||
u64 steal;
|
||||
@@ -416,14 +401,6 @@ static u64 kvm_steal_clock(int cpu)
|
||||
return steal;
|
||||
}
|
||||
|
||||
void kvm_disable_steal_time(void)
|
||||
{
|
||||
if (!has_steal_clock)
|
||||
return;
|
||||
|
||||
wrmsr(MSR_KVM_STEAL_TIME, 0, 0);
|
||||
}
|
||||
|
||||
static inline void __set_percpu_decrypted(void *ptr, unsigned long size)
|
||||
{
|
||||
early_set_memory_decrypted((unsigned long) ptr, size);
|
||||
@@ -451,6 +428,27 @@ static void __init sev_map_percpu_data(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_guest_cpu_offline(bool shutdown)
|
||||
{
|
||||
kvm_disable_steal_time();
|
||||
if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
|
||||
wrmsrl(MSR_KVM_PV_EOI_EN, 0);
|
||||
kvm_pv_disable_apf();
|
||||
if (!shutdown)
|
||||
apf_task_wake_all();
|
||||
kvmclock_disable();
|
||||
}
|
||||
|
||||
static int kvm_cpu_online(unsigned int cpu)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
kvm_guest_cpu_init();
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
static DEFINE_PER_CPU(cpumask_var_t, __pv_cpu_mask);
|
||||
@@ -635,33 +633,66 @@ static void __init kvm_smp_prepare_boot_cpu(void)
|
||||
kvm_spinlock_init();
|
||||
}
|
||||
|
||||
static void kvm_guest_cpu_offline(void)
|
||||
{
|
||||
kvm_disable_steal_time();
|
||||
if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
|
||||
wrmsrl(MSR_KVM_PV_EOI_EN, 0);
|
||||
kvm_pv_disable_apf();
|
||||
apf_task_wake_all();
|
||||
}
|
||||
|
||||
static int kvm_cpu_online(unsigned int cpu)
|
||||
{
|
||||
local_irq_disable();
|
||||
kvm_guest_cpu_init();
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_cpu_down_prepare(unsigned int cpu)
|
||||
{
|
||||
local_irq_disable();
|
||||
kvm_guest_cpu_offline();
|
||||
local_irq_enable();
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
kvm_guest_cpu_offline(false);
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int kvm_suspend(void)
|
||||
{
|
||||
kvm_guest_cpu_offline(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kvm_resume(void)
|
||||
{
|
||||
kvm_cpu_online(raw_smp_processor_id());
|
||||
}
|
||||
|
||||
static struct syscore_ops kvm_syscore_ops = {
|
||||
.suspend = kvm_suspend,
|
||||
.resume = kvm_resume,
|
||||
};
|
||||
|
||||
static void kvm_pv_guest_cpu_reboot(void *unused)
|
||||
{
|
||||
kvm_guest_cpu_offline(true);
|
||||
}
|
||||
|
||||
static int kvm_pv_reboot_notify(struct notifier_block *nb,
|
||||
unsigned long code, void *unused)
|
||||
{
|
||||
if (code == SYS_RESTART)
|
||||
on_each_cpu(kvm_pv_guest_cpu_reboot, NULL, 1);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block kvm_pv_reboot_nb = {
|
||||
.notifier_call = kvm_pv_reboot_notify,
|
||||
};
|
||||
|
||||
/*
|
||||
* After a PV feature is registered, the host will keep writing to the
|
||||
* registered memory location. If the guest happens to shutdown, this memory
|
||||
* won't be valid. In cases like kexec, in which you install a new kernel, this
|
||||
* means a random memory location will be kept being written.
|
||||
*/
|
||||
#ifdef CONFIG_KEXEC_CORE
|
||||
static void kvm_crash_shutdown(struct pt_regs *regs)
|
||||
{
|
||||
kvm_guest_cpu_offline(true);
|
||||
native_machine_crash_shutdown(regs);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __init kvm_guest_init(void)
|
||||
{
|
||||
int i;
|
||||
@@ -704,6 +735,12 @@ static void __init kvm_guest_init(void)
|
||||
kvm_guest_cpu_init();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KEXEC_CORE
|
||||
machine_ops.crash_shutdown = kvm_crash_shutdown;
|
||||
#endif
|
||||
|
||||
register_syscore_ops(&kvm_syscore_ops);
|
||||
|
||||
/*
|
||||
* Hard lockup detection is enabled by default. Disable it, as guests
|
||||
* can get false positives too easily, for example if the host is
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <asm/hypervisor.h>
|
||||
#include <asm/mem_encrypt.h>
|
||||
#include <asm/x86_init.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/kvmclock.h>
|
||||
|
||||
static int kvmclock __initdata = 1;
|
||||
@@ -203,28 +202,9 @@ static void kvm_setup_secondary_clock(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* After the clock is registered, the host will keep writing to the
|
||||
* registered memory location. If the guest happens to shutdown, this memory
|
||||
* won't be valid. In cases like kexec, in which you install a new kernel, this
|
||||
* means a random memory location will be kept being written. So before any
|
||||
* kind of shutdown from our side, we unregister the clock by writing anything
|
||||
* that does not have the 'enable' bit set in the msr
|
||||
*/
|
||||
#ifdef CONFIG_KEXEC_CORE
|
||||
static void kvm_crash_shutdown(struct pt_regs *regs)
|
||||
void kvmclock_disable(void)
|
||||
{
|
||||
native_write_msr(msr_kvm_system_time, 0, 0);
|
||||
kvm_disable_steal_time();
|
||||
native_machine_crash_shutdown(regs);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void kvm_shutdown(void)
|
||||
{
|
||||
native_write_msr(msr_kvm_system_time, 0, 0);
|
||||
kvm_disable_steal_time();
|
||||
native_machine_shutdown();
|
||||
}
|
||||
|
||||
static void __init kvmclock_init_mem(void)
|
||||
@@ -351,10 +331,6 @@ void __init kvmclock_init(void)
|
||||
#endif
|
||||
x86_platform.save_sched_clock_state = kvm_save_sched_clock_state;
|
||||
x86_platform.restore_sched_clock_state = kvm_restore_sched_clock_state;
|
||||
machine_ops.shutdown = kvm_shutdown;
|
||||
#ifdef CONFIG_KEXEC_CORE
|
||||
machine_ops.crash_shutdown = kvm_crash_shutdown;
|
||||
#endif
|
||||
kvm_get_preset_lpj();
|
||||
|
||||
/*
|
||||
|
||||
@@ -458,7 +458,7 @@ void kvm_set_cpu_caps(void)
|
||||
F(AVX512_VPOPCNTDQ) | F(UMIP) | F(AVX512_VBMI2) | F(GFNI) |
|
||||
F(VAES) | F(VPCLMULQDQ) | F(AVX512_VNNI) | F(AVX512_BITALG) |
|
||||
F(CLDEMOTE) | F(MOVDIRI) | F(MOVDIR64B) | 0 /*WAITPKG*/ |
|
||||
F(SGX_LC)
|
||||
F(SGX_LC) | F(BUS_LOCK_DETECT)
|
||||
);
|
||||
/* Set LA57 based on hardware capability. */
|
||||
if (cpuid_ecx(7) & F(LA57))
|
||||
@@ -567,6 +567,21 @@ void kvm_set_cpu_caps(void)
|
||||
F(ACE2) | F(ACE2_EN) | F(PHE) | F(PHE_EN) |
|
||||
F(PMM) | F(PMM_EN)
|
||||
);
|
||||
|
||||
/*
|
||||
* Hide RDTSCP and RDPID if either feature is reported as supported but
|
||||
* probing MSR_TSC_AUX failed. This is purely a sanity check and
|
||||
* should never happen, but the guest will likely crash if RDTSCP or
|
||||
* RDPID is misreported, and KVM has botched MSR_TSC_AUX emulation in
|
||||
* the past. For example, the sanity check may fire if this instance of
|
||||
* KVM is running as L1 on top of an older, broken KVM.
|
||||
*/
|
||||
if (WARN_ON((kvm_cpu_cap_has(X86_FEATURE_RDTSCP) ||
|
||||
kvm_cpu_cap_has(X86_FEATURE_RDPID)) &&
|
||||
!kvm_is_supported_user_return_msr(MSR_TSC_AUX))) {
|
||||
kvm_cpu_cap_clear(X86_FEATURE_RDTSCP);
|
||||
kvm_cpu_cap_clear(X86_FEATURE_RDPID);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_set_cpu_caps);
|
||||
|
||||
@@ -637,7 +652,8 @@ static int __do_cpuid_func_emulated(struct kvm_cpuid_array *array, u32 func)
|
||||
case 7:
|
||||
entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
|
||||
entry->eax = 0;
|
||||
entry->ecx = F(RDPID);
|
||||
if (kvm_cpu_cap_has(X86_FEATURE_RDTSCP))
|
||||
entry->ecx = F(RDPID);
|
||||
++array->nent;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -4502,7 +4502,7 @@ static const struct opcode group8[] = {
|
||||
* from the register case of group9.
|
||||
*/
|
||||
static const struct gprefix pfx_0f_c7_7 = {
|
||||
N, N, N, II(DstMem | ModRM | Op3264 | EmulateOnUD, em_rdpid, rdtscp),
|
||||
N, N, N, II(DstMem | ModRM | Op3264 | EmulateOnUD, em_rdpid, rdpid),
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -468,6 +468,7 @@ enum x86_intercept {
|
||||
x86_intercept_clgi,
|
||||
x86_intercept_skinit,
|
||||
x86_intercept_rdtscp,
|
||||
x86_intercept_rdpid,
|
||||
x86_intercept_icebp,
|
||||
x86_intercept_wbinvd,
|
||||
x86_intercept_monitor,
|
||||
|
||||
@@ -1913,8 +1913,8 @@ void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu)
|
||||
if (!apic->lapic_timer.hv_timer_in_use)
|
||||
goto out;
|
||||
WARN_ON(rcuwait_active(&vcpu->wait));
|
||||
cancel_hv_timer(apic);
|
||||
apic_timer_expired(apic, false);
|
||||
cancel_hv_timer(apic);
|
||||
|
||||
if (apic_lvtt_period(apic) && apic->lapic_timer.period) {
|
||||
advance_periodic_target_expiration(apic);
|
||||
|
||||
@@ -3310,12 +3310,12 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
|
||||
if (mmu->shadow_root_level == PT64_ROOT_4LEVEL) {
|
||||
pm_mask |= PT_ACCESSED_MASK | PT_WRITABLE_MASK | PT_USER_MASK;
|
||||
|
||||
if (WARN_ON_ONCE(!mmu->lm_root)) {
|
||||
if (WARN_ON_ONCE(!mmu->pml4_root)) {
|
||||
r = -EIO;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
mmu->lm_root[0] = __pa(mmu->pae_root) | pm_mask;
|
||||
mmu->pml4_root[0] = __pa(mmu->pae_root) | pm_mask;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
@@ -3335,7 +3335,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
|
||||
}
|
||||
|
||||
if (mmu->shadow_root_level == PT64_ROOT_4LEVEL)
|
||||
mmu->root_hpa = __pa(mmu->lm_root);
|
||||
mmu->root_hpa = __pa(mmu->pml4_root);
|
||||
else
|
||||
mmu->root_hpa = __pa(mmu->pae_root);
|
||||
|
||||
@@ -3350,7 +3350,7 @@ out_unlock:
|
||||
static int mmu_alloc_special_roots(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_mmu *mmu = vcpu->arch.mmu;
|
||||
u64 *lm_root, *pae_root;
|
||||
u64 *pml4_root, *pae_root;
|
||||
|
||||
/*
|
||||
* When shadowing 32-bit or PAE NPT with 64-bit NPT, the PML4 and PDP
|
||||
@@ -3369,14 +3369,14 @@ static int mmu_alloc_special_roots(struct kvm_vcpu *vcpu)
|
||||
if (WARN_ON_ONCE(mmu->shadow_root_level != PT64_ROOT_4LEVEL))
|
||||
return -EIO;
|
||||
|
||||
if (mmu->pae_root && mmu->lm_root)
|
||||
if (mmu->pae_root && mmu->pml4_root)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The special roots should always be allocated in concert. Yell and
|
||||
* bail if KVM ends up in a state where only one of the roots is valid.
|
||||
*/
|
||||
if (WARN_ON_ONCE(!tdp_enabled || mmu->pae_root || mmu->lm_root))
|
||||
if (WARN_ON_ONCE(!tdp_enabled || mmu->pae_root || mmu->pml4_root))
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
@@ -3387,14 +3387,14 @@ static int mmu_alloc_special_roots(struct kvm_vcpu *vcpu)
|
||||
if (!pae_root)
|
||||
return -ENOMEM;
|
||||
|
||||
lm_root = (void *)get_zeroed_page(GFP_KERNEL_ACCOUNT);
|
||||
if (!lm_root) {
|
||||
pml4_root = (void *)get_zeroed_page(GFP_KERNEL_ACCOUNT);
|
||||
if (!pml4_root) {
|
||||
free_page((unsigned long)pae_root);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mmu->pae_root = pae_root;
|
||||
mmu->lm_root = lm_root;
|
||||
mmu->pml4_root = pml4_root;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -5261,7 +5261,7 @@ static void free_mmu_pages(struct kvm_mmu *mmu)
|
||||
if (!tdp_enabled && mmu->pae_root)
|
||||
set_memory_encrypted((unsigned long)mmu->pae_root, 1);
|
||||
free_page((unsigned long)mmu->pae_root);
|
||||
free_page((unsigned long)mmu->lm_root);
|
||||
free_page((unsigned long)mmu->pml4_root);
|
||||
}
|
||||
|
||||
static int __kvm_mmu_create(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu)
|
||||
|
||||
@@ -388,7 +388,7 @@ static void handle_removed_tdp_mmu_page(struct kvm *kvm, tdp_ptep_t pt,
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_changed_spte - handle bookkeeping associated with an SPTE change
|
||||
* __handle_changed_spte - handle bookkeeping associated with an SPTE change
|
||||
* @kvm: kvm instance
|
||||
* @as_id: the address space of the paging structure the SPTE was a part of
|
||||
* @gfn: the base GFN that was mapped by the SPTE
|
||||
@@ -444,6 +444,13 @@ static void __handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn,
|
||||
|
||||
trace_kvm_tdp_mmu_spte_changed(as_id, gfn, level, old_spte, new_spte);
|
||||
|
||||
if (is_large_pte(old_spte) != is_large_pte(new_spte)) {
|
||||
if (is_large_pte(old_spte))
|
||||
atomic64_sub(1, (atomic64_t*)&kvm->stat.lpages);
|
||||
else
|
||||
atomic64_add(1, (atomic64_t*)&kvm->stat.lpages);
|
||||
}
|
||||
|
||||
/*
|
||||
* The only times a SPTE should be changed from a non-present to
|
||||
* non-present state is when an MMIO entry is installed/modified/
|
||||
@@ -1009,6 +1016,14 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
|
||||
}
|
||||
|
||||
if (!is_shadow_present_pte(iter.old_spte)) {
|
||||
/*
|
||||
* If SPTE has been forzen by another thread, just
|
||||
* give up and retry, avoiding unnecessary page table
|
||||
* allocation and free.
|
||||
*/
|
||||
if (is_removed_spte(iter.old_spte))
|
||||
break;
|
||||
|
||||
sp = alloc_tdp_mmu_page(vcpu, iter.gfn, iter.level);
|
||||
child_pt = sp->spt;
|
||||
|
||||
|
||||
@@ -764,7 +764,6 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
|
||||
nested_svm_copy_common_state(svm->nested.vmcb02.ptr, svm->vmcb01.ptr);
|
||||
|
||||
svm_switch_vmcb(svm, &svm->vmcb01);
|
||||
WARN_ON_ONCE(svm->vmcb->control.exit_code != SVM_EXIT_VMRUN);
|
||||
|
||||
/*
|
||||
* On vmexit the GIF is set to false and
|
||||
@@ -872,6 +871,15 @@ void svm_free_nested(struct vcpu_svm *svm)
|
||||
__free_page(virt_to_page(svm->nested.vmcb02.ptr));
|
||||
svm->nested.vmcb02.ptr = NULL;
|
||||
|
||||
/*
|
||||
* When last_vmcb12_gpa matches the current vmcb12 gpa,
|
||||
* some vmcb12 fields are not loaded if they are marked clean
|
||||
* in the vmcb12, since in this case they are up to date already.
|
||||
*
|
||||
* When the vmcb02 is freed, this optimization becomes invalid.
|
||||
*/
|
||||
svm->nested.last_vmcb12_gpa = INVALID_GPA;
|
||||
|
||||
svm->nested.initialized = false;
|
||||
}
|
||||
|
||||
@@ -884,9 +892,11 @@ void svm_leave_nested(struct vcpu_svm *svm)
|
||||
|
||||
if (is_guest_mode(vcpu)) {
|
||||
svm->nested.nested_run_pending = 0;
|
||||
svm->nested.vmcb12_gpa = INVALID_GPA;
|
||||
|
||||
leave_guest_mode(vcpu);
|
||||
|
||||
svm_switch_vmcb(svm, &svm->nested.vmcb02);
|
||||
svm_switch_vmcb(svm, &svm->vmcb01);
|
||||
|
||||
nested_svm_uninit_mmu_context(vcpu);
|
||||
vmcb_mark_all_dirty(svm->vmcb);
|
||||
@@ -1298,12 +1308,17 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
|
||||
* L2 registers if needed are moved from the current VMCB to VMCB02.
|
||||
*/
|
||||
|
||||
if (is_guest_mode(vcpu))
|
||||
svm_leave_nested(svm);
|
||||
else
|
||||
svm->nested.vmcb02.ptr->save = svm->vmcb01.ptr->save;
|
||||
|
||||
svm_set_gif(svm, !!(kvm_state->flags & KVM_STATE_NESTED_GIF_SET));
|
||||
|
||||
svm->nested.nested_run_pending =
|
||||
!!(kvm_state->flags & KVM_STATE_NESTED_RUN_PENDING);
|
||||
|
||||
svm->nested.vmcb12_gpa = kvm_state->hdr.svm.vmcb_pa;
|
||||
if (svm->current_vmcb == &svm->vmcb01)
|
||||
svm->nested.vmcb02.ptr->save = svm->vmcb01.ptr->save;
|
||||
|
||||
svm->vmcb01.ptr->save.es = save->es;
|
||||
svm->vmcb01.ptr->save.cs = save->cs;
|
||||
|
||||
@@ -763,7 +763,7 @@ static int __sev_dbg_decrypt(struct kvm *kvm, unsigned long src_paddr,
|
||||
}
|
||||
|
||||
static int __sev_dbg_decrypt_user(struct kvm *kvm, unsigned long paddr,
|
||||
unsigned long __user dst_uaddr,
|
||||
void __user *dst_uaddr,
|
||||
unsigned long dst_paddr,
|
||||
int size, int *err)
|
||||
{
|
||||
@@ -787,8 +787,7 @@ static int __sev_dbg_decrypt_user(struct kvm *kvm, unsigned long paddr,
|
||||
|
||||
if (tpage) {
|
||||
offset = paddr & 15;
|
||||
if (copy_to_user((void __user *)(uintptr_t)dst_uaddr,
|
||||
page_address(tpage) + offset, size))
|
||||
if (copy_to_user(dst_uaddr, page_address(tpage) + offset, size))
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
@@ -800,9 +799,9 @@ e_free:
|
||||
}
|
||||
|
||||
static int __sev_dbg_encrypt_user(struct kvm *kvm, unsigned long paddr,
|
||||
unsigned long __user vaddr,
|
||||
void __user *vaddr,
|
||||
unsigned long dst_paddr,
|
||||
unsigned long __user dst_vaddr,
|
||||
void __user *dst_vaddr,
|
||||
int size, int *error)
|
||||
{
|
||||
struct page *src_tpage = NULL;
|
||||
@@ -810,13 +809,12 @@ static int __sev_dbg_encrypt_user(struct kvm *kvm, unsigned long paddr,
|
||||
int ret, len = size;
|
||||
|
||||
/* If source buffer is not aligned then use an intermediate buffer */
|
||||
if (!IS_ALIGNED(vaddr, 16)) {
|
||||
if (!IS_ALIGNED((unsigned long)vaddr, 16)) {
|
||||
src_tpage = alloc_page(GFP_KERNEL);
|
||||
if (!src_tpage)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(page_address(src_tpage),
|
||||
(void __user *)(uintptr_t)vaddr, size)) {
|
||||
if (copy_from_user(page_address(src_tpage), vaddr, size)) {
|
||||
__free_page(src_tpage);
|
||||
return -EFAULT;
|
||||
}
|
||||
@@ -830,7 +828,7 @@ static int __sev_dbg_encrypt_user(struct kvm *kvm, unsigned long paddr,
|
||||
* - copy the source buffer in an intermediate buffer
|
||||
* - use the intermediate buffer as source buffer
|
||||
*/
|
||||
if (!IS_ALIGNED(dst_vaddr, 16) || !IS_ALIGNED(size, 16)) {
|
||||
if (!IS_ALIGNED((unsigned long)dst_vaddr, 16) || !IS_ALIGNED(size, 16)) {
|
||||
int dst_offset;
|
||||
|
||||
dst_tpage = alloc_page(GFP_KERNEL);
|
||||
@@ -855,7 +853,7 @@ static int __sev_dbg_encrypt_user(struct kvm *kvm, unsigned long paddr,
|
||||
page_address(src_tpage), size);
|
||||
else {
|
||||
if (copy_from_user(page_address(dst_tpage) + dst_offset,
|
||||
(void __user *)(uintptr_t)vaddr, size)) {
|
||||
vaddr, size)) {
|
||||
ret = -EFAULT;
|
||||
goto e_free;
|
||||
}
|
||||
@@ -935,15 +933,15 @@ static int sev_dbg_crypt(struct kvm *kvm, struct kvm_sev_cmd *argp, bool dec)
|
||||
if (dec)
|
||||
ret = __sev_dbg_decrypt_user(kvm,
|
||||
__sme_page_pa(src_p[0]) + s_off,
|
||||
dst_vaddr,
|
||||
(void __user *)dst_vaddr,
|
||||
__sme_page_pa(dst_p[0]) + d_off,
|
||||
len, &argp->error);
|
||||
else
|
||||
ret = __sev_dbg_encrypt_user(kvm,
|
||||
__sme_page_pa(src_p[0]) + s_off,
|
||||
vaddr,
|
||||
(void __user *)vaddr,
|
||||
__sme_page_pa(dst_p[0]) + d_off,
|
||||
dst_vaddr,
|
||||
(void __user *)dst_vaddr,
|
||||
len, &argp->error);
|
||||
|
||||
sev_unpin_memory(kvm, src_p, n);
|
||||
@@ -1764,7 +1762,8 @@ e_mirror_unlock:
|
||||
e_source_unlock:
|
||||
mutex_unlock(&source_kvm->lock);
|
||||
e_source_put:
|
||||
fput(source_kvm_file);
|
||||
if (source_kvm_file)
|
||||
fput(source_kvm_file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2198,7 +2197,7 @@ vmgexit_err:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void pre_sev_es_run(struct vcpu_svm *svm)
|
||||
void sev_es_unmap_ghcb(struct vcpu_svm *svm)
|
||||
{
|
||||
if (!svm->ghcb)
|
||||
return;
|
||||
@@ -2234,9 +2233,6 @@ void pre_sev_run(struct vcpu_svm *svm, int cpu)
|
||||
struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
|
||||
int asid = sev_get_asid(svm->vcpu.kvm);
|
||||
|
||||
/* Perform any SEV-ES pre-run actions */
|
||||
pre_sev_es_run(svm);
|
||||
|
||||
/* Assign the asid allocated with this SEV guest */
|
||||
svm->asid = asid;
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);
|
||||
* RDTSCP and RDPID are not used in the kernel, specifically to allow KVM to
|
||||
* defer the restoration of TSC_AUX until the CPU returns to userspace.
|
||||
*/
|
||||
#define TSC_AUX_URET_SLOT 0
|
||||
static int tsc_aux_uret_slot __read_mostly = -1;
|
||||
|
||||
static const u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000};
|
||||
|
||||
@@ -447,6 +447,11 @@ static int has_svm(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pgtable_l5_enabled()) {
|
||||
pr_info("KVM doesn't yet support 5-level paging on AMD SVM\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -959,8 +964,7 @@ static __init int svm_hardware_setup(void)
|
||||
kvm_tsc_scaling_ratio_frac_bits = 32;
|
||||
}
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_RDTSCP))
|
||||
kvm_define_user_return_msr(TSC_AUX_URET_SLOT, MSR_TSC_AUX);
|
||||
tsc_aux_uret_slot = kvm_add_user_return_msr(MSR_TSC_AUX);
|
||||
|
||||
/* Check for pause filtering support */
|
||||
if (!boot_cpu_has(X86_FEATURE_PAUSEFILTER)) {
|
||||
@@ -1100,7 +1104,9 @@ static u64 svm_write_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
|
||||
return svm->vmcb->control.tsc_offset;
|
||||
}
|
||||
|
||||
static void svm_check_invpcid(struct vcpu_svm *svm)
|
||||
/* Evaluate instruction intercepts that depend on guest CPUID features. */
|
||||
static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu,
|
||||
struct vcpu_svm *svm)
|
||||
{
|
||||
/*
|
||||
* Intercept INVPCID if shadow paging is enabled to sync/free shadow
|
||||
@@ -1113,6 +1119,13 @@ static void svm_check_invpcid(struct vcpu_svm *svm)
|
||||
else
|
||||
svm_clr_intercept(svm, INTERCEPT_INVPCID);
|
||||
}
|
||||
|
||||
if (kvm_cpu_cap_has(X86_FEATURE_RDTSCP)) {
|
||||
if (guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP))
|
||||
svm_clr_intercept(svm, INTERCEPT_RDTSCP);
|
||||
else
|
||||
svm_set_intercept(svm, INTERCEPT_RDTSCP);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_vmcb(struct kvm_vcpu *vcpu)
|
||||
@@ -1235,8 +1248,8 @@ static void init_vmcb(struct kvm_vcpu *vcpu)
|
||||
svm->current_vmcb->asid_generation = 0;
|
||||
svm->asid = 0;
|
||||
|
||||
svm->nested.vmcb12_gpa = 0;
|
||||
svm->nested.last_vmcb12_gpa = 0;
|
||||
svm->nested.vmcb12_gpa = INVALID_GPA;
|
||||
svm->nested.last_vmcb12_gpa = INVALID_GPA;
|
||||
vcpu->arch.hflags = 0;
|
||||
|
||||
if (!kvm_pause_in_guest(vcpu->kvm)) {
|
||||
@@ -1248,7 +1261,7 @@ static void init_vmcb(struct kvm_vcpu *vcpu)
|
||||
svm_clr_intercept(svm, INTERCEPT_PAUSE);
|
||||
}
|
||||
|
||||
svm_check_invpcid(svm);
|
||||
svm_recalc_instruction_intercepts(vcpu, svm);
|
||||
|
||||
/*
|
||||
* If the host supports V_SPEC_CTRL then disable the interception
|
||||
@@ -1424,6 +1437,9 @@ static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu)
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
struct svm_cpu_data *sd = per_cpu(svm_data, vcpu->cpu);
|
||||
|
||||
if (sev_es_guest(vcpu->kvm))
|
||||
sev_es_unmap_ghcb(svm);
|
||||
|
||||
if (svm->guest_state_loaded)
|
||||
return;
|
||||
|
||||
@@ -1445,8 +1461,8 @@ static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu)
|
||||
}
|
||||
}
|
||||
|
||||
if (static_cpu_has(X86_FEATURE_RDTSCP))
|
||||
kvm_set_user_return_msr(TSC_AUX_URET_SLOT, svm->tsc_aux, -1ull);
|
||||
if (likely(tsc_aux_uret_slot >= 0))
|
||||
kvm_set_user_return_msr(tsc_aux_uret_slot, svm->tsc_aux, -1ull);
|
||||
|
||||
svm->guest_state_loaded = true;
|
||||
}
|
||||
@@ -2655,11 +2671,6 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
msr_info->data |= (u64)svm->sysenter_esp_hi << 32;
|
||||
break;
|
||||
case MSR_TSC_AUX:
|
||||
if (!boot_cpu_has(X86_FEATURE_RDTSCP))
|
||||
return 1;
|
||||
if (!msr_info->host_initiated &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP))
|
||||
return 1;
|
||||
msr_info->data = svm->tsc_aux;
|
||||
break;
|
||||
/*
|
||||
@@ -2876,30 +2887,13 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
|
||||
svm->sysenter_esp_hi = guest_cpuid_is_intel(vcpu) ? (data >> 32) : 0;
|
||||
break;
|
||||
case MSR_TSC_AUX:
|
||||
if (!boot_cpu_has(X86_FEATURE_RDTSCP))
|
||||
return 1;
|
||||
|
||||
if (!msr->host_initiated &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Per Intel's SDM, bits 63:32 are reserved, but AMD's APM has
|
||||
* incomplete and conflicting architectural behavior. Current
|
||||
* AMD CPUs completely ignore bits 63:32, i.e. they aren't
|
||||
* reserved and always read as zeros. Emulate AMD CPU behavior
|
||||
* to avoid explosions if the vCPU is migrated from an AMD host
|
||||
* to an Intel host.
|
||||
*/
|
||||
data = (u32)data;
|
||||
|
||||
/*
|
||||
* TSC_AUX is usually changed only during boot and never read
|
||||
* directly. Intercept TSC_AUX instead of exposing it to the
|
||||
* guest via direct_access_msrs, and switch it via user return.
|
||||
*/
|
||||
preempt_disable();
|
||||
r = kvm_set_user_return_msr(TSC_AUX_URET_SLOT, data, -1ull);
|
||||
r = kvm_set_user_return_msr(tsc_aux_uret_slot, data, -1ull);
|
||||
preempt_enable();
|
||||
if (r)
|
||||
return 1;
|
||||
@@ -3084,6 +3078,7 @@ static int (*const svm_exit_handlers[])(struct kvm_vcpu *vcpu) = {
|
||||
[SVM_EXIT_STGI] = stgi_interception,
|
||||
[SVM_EXIT_CLGI] = clgi_interception,
|
||||
[SVM_EXIT_SKINIT] = skinit_interception,
|
||||
[SVM_EXIT_RDTSCP] = kvm_handle_invalid_op,
|
||||
[SVM_EXIT_WBINVD] = kvm_emulate_wbinvd,
|
||||
[SVM_EXIT_MONITOR] = kvm_emulate_monitor,
|
||||
[SVM_EXIT_MWAIT] = kvm_emulate_mwait,
|
||||
@@ -3972,8 +3967,7 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
|
||||
svm->nrips_enabled = kvm_cpu_cap_has(X86_FEATURE_NRIPS) &&
|
||||
guest_cpuid_has(vcpu, X86_FEATURE_NRIPS);
|
||||
|
||||
/* Check again if INVPCID interception if required */
|
||||
svm_check_invpcid(svm);
|
||||
svm_recalc_instruction_intercepts(vcpu, svm);
|
||||
|
||||
/* For sev guests, the memory encryption bit is not reserved in CR3. */
|
||||
if (sev_guest(vcpu->kvm)) {
|
||||
|
||||
@@ -581,6 +581,7 @@ void sev_es_init_vmcb(struct vcpu_svm *svm);
|
||||
void sev_es_create_vcpu(struct vcpu_svm *svm);
|
||||
void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector);
|
||||
void sev_es_prepare_guest_switch(struct vcpu_svm *svm, unsigned int cpu);
|
||||
void sev_es_unmap_ghcb(struct vcpu_svm *svm);
|
||||
|
||||
/* vmenter.S */
|
||||
|
||||
|
||||
@@ -398,6 +398,9 @@ static inline u64 vmx_supported_debugctl(void)
|
||||
{
|
||||
u64 debugctl = 0;
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT))
|
||||
debugctl |= DEBUGCTLMSR_BUS_LOCK_DETECT;
|
||||
|
||||
if (vmx_get_perf_capabilities() & PMU_CAP_LBR_FMT)
|
||||
debugctl |= DEBUGCTLMSR_LBR_MASK;
|
||||
|
||||
|
||||
@@ -3098,15 +3098,8 @@ static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
|
||||
nested_vmx_handle_enlightened_vmptrld(vcpu, false);
|
||||
|
||||
if (evmptrld_status == EVMPTRLD_VMFAIL ||
|
||||
evmptrld_status == EVMPTRLD_ERROR) {
|
||||
pr_debug_ratelimited("%s: enlightened vmptrld failed\n",
|
||||
__func__);
|
||||
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
||||
vcpu->run->internal.suberror =
|
||||
KVM_INTERNAL_ERROR_EMULATION;
|
||||
vcpu->run->internal.ndata = 0;
|
||||
evmptrld_status == EVMPTRLD_ERROR)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -3194,8 +3187,16 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
|
||||
|
||||
static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (!nested_get_evmcs_page(vcpu))
|
||||
if (!nested_get_evmcs_page(vcpu)) {
|
||||
pr_debug_ratelimited("%s: enlightened vmptrld failed\n",
|
||||
__func__);
|
||||
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
||||
vcpu->run->internal.suberror =
|
||||
KVM_INTERNAL_ERROR_EMULATION;
|
||||
vcpu->run->internal.ndata = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_guest_mode(vcpu) && !nested_get_vmcs12_pages(vcpu))
|
||||
return false;
|
||||
@@ -4435,7 +4436,15 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
|
||||
/* Similarly, triple faults in L2 should never escape. */
|
||||
WARN_ON_ONCE(kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu));
|
||||
|
||||
kvm_clear_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
|
||||
if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
|
||||
/*
|
||||
* KVM_REQ_GET_NESTED_STATE_PAGES is also used to map
|
||||
* Enlightened VMCS after migration and we still need to
|
||||
* do that when something is forcing L2->L1 exit prior to
|
||||
* the first L2 run.
|
||||
*/
|
||||
(void)nested_get_evmcs_page(vcpu);
|
||||
}
|
||||
|
||||
/* Service the TLB flush request for L2 before switching to L1. */
|
||||
if (kvm_check_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu))
|
||||
|
||||
@@ -455,21 +455,6 @@ static inline void vmx_segment_cache_clear(struct vcpu_vmx *vmx)
|
||||
|
||||
static unsigned long host_idt_base;
|
||||
|
||||
/*
|
||||
* Though SYSCALL is only supported in 64-bit mode on Intel CPUs, kvm
|
||||
* will emulate SYSCALL in legacy mode if the vendor string in guest
|
||||
* CPUID.0:{EBX,ECX,EDX} is "AuthenticAMD" or "AMDisbetter!" To
|
||||
* support this emulation, IA32_STAR must always be included in
|
||||
* vmx_uret_msrs_list[], even in i386 builds.
|
||||
*/
|
||||
static const u32 vmx_uret_msrs_list[] = {
|
||||
#ifdef CONFIG_X86_64
|
||||
MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR,
|
||||
#endif
|
||||
MSR_EFER, MSR_TSC_AUX, MSR_STAR,
|
||||
MSR_IA32_TSX_CTRL,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
static bool __read_mostly enlightened_vmcs = true;
|
||||
module_param(enlightened_vmcs, bool, 0444);
|
||||
@@ -697,21 +682,11 @@ static bool is_valid_passthrough_msr(u32 msr)
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline int __vmx_find_uret_msr(struct vcpu_vmx *vmx, u32 msr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vmx->nr_uret_msrs; ++i)
|
||||
if (vmx_uret_msrs_list[vmx->guest_uret_msrs[i].slot] == msr)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct vmx_uret_msr *vmx_find_uret_msr(struct vcpu_vmx *vmx, u32 msr)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = __vmx_find_uret_msr(vmx, msr);
|
||||
i = kvm_find_user_return_msr(msr);
|
||||
if (i >= 0)
|
||||
return &vmx->guest_uret_msrs[i];
|
||||
return NULL;
|
||||
@@ -720,13 +695,14 @@ struct vmx_uret_msr *vmx_find_uret_msr(struct vcpu_vmx *vmx, u32 msr)
|
||||
static int vmx_set_guest_uret_msr(struct vcpu_vmx *vmx,
|
||||
struct vmx_uret_msr *msr, u64 data)
|
||||
{
|
||||
unsigned int slot = msr - vmx->guest_uret_msrs;
|
||||
int ret = 0;
|
||||
|
||||
u64 old_msr_data = msr->data;
|
||||
msr->data = data;
|
||||
if (msr - vmx->guest_uret_msrs < vmx->nr_active_uret_msrs) {
|
||||
if (msr->load_into_hardware) {
|
||||
preempt_disable();
|
||||
ret = kvm_set_user_return_msr(msr->slot, msr->data, msr->mask);
|
||||
ret = kvm_set_user_return_msr(slot, msr->data, msr->mask);
|
||||
preempt_enable();
|
||||
if (ret)
|
||||
msr->data = old_msr_data;
|
||||
@@ -1078,7 +1054,7 @@ static bool update_transition_efer(struct vcpu_vmx *vmx)
|
||||
return false;
|
||||
}
|
||||
|
||||
i = __vmx_find_uret_msr(vmx, MSR_EFER);
|
||||
i = kvm_find_user_return_msr(MSR_EFER);
|
||||
if (i < 0)
|
||||
return false;
|
||||
|
||||
@@ -1240,11 +1216,14 @@ void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
|
||||
*/
|
||||
if (!vmx->guest_uret_msrs_loaded) {
|
||||
vmx->guest_uret_msrs_loaded = true;
|
||||
for (i = 0; i < vmx->nr_active_uret_msrs; ++i)
|
||||
kvm_set_user_return_msr(vmx->guest_uret_msrs[i].slot,
|
||||
for (i = 0; i < kvm_nr_uret_msrs; ++i) {
|
||||
if (!vmx->guest_uret_msrs[i].load_into_hardware)
|
||||
continue;
|
||||
|
||||
kvm_set_user_return_msr(i,
|
||||
vmx->guest_uret_msrs[i].data,
|
||||
vmx->guest_uret_msrs[i].mask);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (vmx->nested.need_vmcs12_to_shadow_sync)
|
||||
@@ -1751,19 +1730,16 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu)
|
||||
vmx_clear_hlt(vcpu);
|
||||
}
|
||||
|
||||
static void vmx_setup_uret_msr(struct vcpu_vmx *vmx, unsigned int msr)
|
||||
static void vmx_setup_uret_msr(struct vcpu_vmx *vmx, unsigned int msr,
|
||||
bool load_into_hardware)
|
||||
{
|
||||
struct vmx_uret_msr tmp;
|
||||
int from, to;
|
||||
struct vmx_uret_msr *uret_msr;
|
||||
|
||||
from = __vmx_find_uret_msr(vmx, msr);
|
||||
if (from < 0)
|
||||
uret_msr = vmx_find_uret_msr(vmx, msr);
|
||||
if (!uret_msr)
|
||||
return;
|
||||
to = vmx->nr_active_uret_msrs++;
|
||||
|
||||
tmp = vmx->guest_uret_msrs[to];
|
||||
vmx->guest_uret_msrs[to] = vmx->guest_uret_msrs[from];
|
||||
vmx->guest_uret_msrs[from] = tmp;
|
||||
uret_msr->load_into_hardware = load_into_hardware;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1773,29 +1749,42 @@ static void vmx_setup_uret_msr(struct vcpu_vmx *vmx, unsigned int msr)
|
||||
*/
|
||||
static void setup_msrs(struct vcpu_vmx *vmx)
|
||||
{
|
||||
vmx->guest_uret_msrs_loaded = false;
|
||||
vmx->nr_active_uret_msrs = 0;
|
||||
#ifdef CONFIG_X86_64
|
||||
bool load_syscall_msrs;
|
||||
|
||||
/*
|
||||
* The SYSCALL MSRs are only needed on long mode guests, and only
|
||||
* when EFER.SCE is set.
|
||||
*/
|
||||
if (is_long_mode(&vmx->vcpu) && (vmx->vcpu.arch.efer & EFER_SCE)) {
|
||||
vmx_setup_uret_msr(vmx, MSR_STAR);
|
||||
vmx_setup_uret_msr(vmx, MSR_LSTAR);
|
||||
vmx_setup_uret_msr(vmx, MSR_SYSCALL_MASK);
|
||||
}
|
||||
load_syscall_msrs = is_long_mode(&vmx->vcpu) &&
|
||||
(vmx->vcpu.arch.efer & EFER_SCE);
|
||||
|
||||
vmx_setup_uret_msr(vmx, MSR_STAR, load_syscall_msrs);
|
||||
vmx_setup_uret_msr(vmx, MSR_LSTAR, load_syscall_msrs);
|
||||
vmx_setup_uret_msr(vmx, MSR_SYSCALL_MASK, load_syscall_msrs);
|
||||
#endif
|
||||
if (update_transition_efer(vmx))
|
||||
vmx_setup_uret_msr(vmx, MSR_EFER);
|
||||
vmx_setup_uret_msr(vmx, MSR_EFER, update_transition_efer(vmx));
|
||||
|
||||
if (guest_cpuid_has(&vmx->vcpu, X86_FEATURE_RDTSCP))
|
||||
vmx_setup_uret_msr(vmx, MSR_TSC_AUX);
|
||||
vmx_setup_uret_msr(vmx, MSR_TSC_AUX,
|
||||
guest_cpuid_has(&vmx->vcpu, X86_FEATURE_RDTSCP) ||
|
||||
guest_cpuid_has(&vmx->vcpu, X86_FEATURE_RDPID));
|
||||
|
||||
vmx_setup_uret_msr(vmx, MSR_IA32_TSX_CTRL);
|
||||
/*
|
||||
* hle=0, rtm=0, tsx_ctrl=1 can be found with some combinations of new
|
||||
* kernel and old userspace. If those guests run on a tsx=off host, do
|
||||
* allow guests to use TSX_CTRL, but don't change the value in hardware
|
||||
* so that TSX remains always disabled.
|
||||
*/
|
||||
vmx_setup_uret_msr(vmx, MSR_IA32_TSX_CTRL, boot_cpu_has(X86_FEATURE_RTM));
|
||||
|
||||
if (cpu_has_vmx_msr_bitmap())
|
||||
vmx_update_msr_bitmap(&vmx->vcpu);
|
||||
|
||||
/*
|
||||
* The set of MSRs to load may have changed, reload MSRs before the
|
||||
* next VM-Enter.
|
||||
*/
|
||||
vmx->guest_uret_msrs_loaded = false;
|
||||
}
|
||||
|
||||
static u64 vmx_write_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
|
||||
@@ -1993,11 +1982,6 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
else
|
||||
msr_info->data = vmx->pt_desc.guest.addr_a[index / 2];
|
||||
break;
|
||||
case MSR_TSC_AUX:
|
||||
if (!msr_info->host_initiated &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP))
|
||||
return 1;
|
||||
goto find_uret_msr;
|
||||
case MSR_IA32_DEBUGCTLMSR:
|
||||
msr_info->data = vmcs_read64(GUEST_IA32_DEBUGCTL);
|
||||
break;
|
||||
@@ -2031,6 +2015,9 @@ static u64 vcpu_supported_debugctl(struct kvm_vcpu *vcpu)
|
||||
if (!intel_pmu_lbr_is_enabled(vcpu))
|
||||
debugctl &= ~DEBUGCTLMSR_LBR_MASK;
|
||||
|
||||
if (!guest_cpuid_has(vcpu, X86_FEATURE_BUS_LOCK_DETECT))
|
||||
debugctl &= ~DEBUGCTLMSR_BUS_LOCK_DETECT;
|
||||
|
||||
return debugctl;
|
||||
}
|
||||
|
||||
@@ -2313,14 +2300,6 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
else
|
||||
vmx->pt_desc.guest.addr_a[index / 2] = data;
|
||||
break;
|
||||
case MSR_TSC_AUX:
|
||||
if (!msr_info->host_initiated &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP))
|
||||
return 1;
|
||||
/* Check reserved bit, higher 32 bits should be zero */
|
||||
if ((data >> 32) != 0)
|
||||
return 1;
|
||||
goto find_uret_msr;
|
||||
case MSR_IA32_PERF_CAPABILITIES:
|
||||
if (data && !vcpu_to_pmu(vcpu)->version)
|
||||
return 1;
|
||||
@@ -4369,7 +4348,23 @@ static void vmx_compute_secondary_exec_control(struct vcpu_vmx *vmx)
|
||||
xsaves_enabled, false);
|
||||
}
|
||||
|
||||
vmx_adjust_sec_exec_feature(vmx, &exec_control, rdtscp, RDTSCP);
|
||||
/*
|
||||
* RDPID is also gated by ENABLE_RDTSCP, turn on the control if either
|
||||
* feature is exposed to the guest. This creates a virtualization hole
|
||||
* if both are supported in hardware but only one is exposed to the
|
||||
* guest, but letting the guest execute RDTSCP or RDPID when either one
|
||||
* is advertised is preferable to emulating the advertised instruction
|
||||
* in KVM on #UD, and obviously better than incorrectly injecting #UD.
|
||||
*/
|
||||
if (cpu_has_vmx_rdtscp()) {
|
||||
bool rdpid_or_rdtscp_enabled =
|
||||
guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP) ||
|
||||
guest_cpuid_has(vcpu, X86_FEATURE_RDPID);
|
||||
|
||||
vmx_adjust_secondary_exec_control(vmx, &exec_control,
|
||||
SECONDARY_EXEC_ENABLE_RDTSCP,
|
||||
rdpid_or_rdtscp_enabled, false);
|
||||
}
|
||||
vmx_adjust_sec_exec_feature(vmx, &exec_control, invpcid, INVPCID);
|
||||
|
||||
vmx_adjust_sec_exec_exiting(vmx, &exec_control, rdrand, RDRAND);
|
||||
@@ -6855,6 +6850,7 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
|
||||
|
||||
static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vmx_uret_msr *tsx_ctrl;
|
||||
struct vcpu_vmx *vmx;
|
||||
int i, cpu, err;
|
||||
|
||||
@@ -6877,43 +6873,19 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
|
||||
goto free_vpid;
|
||||
}
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(vmx_uret_msrs_list) != MAX_NR_USER_RETURN_MSRS);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vmx_uret_msrs_list); ++i) {
|
||||
u32 index = vmx_uret_msrs_list[i];
|
||||
u32 data_low, data_high;
|
||||
int j = vmx->nr_uret_msrs;
|
||||
|
||||
if (rdmsr_safe(index, &data_low, &data_high) < 0)
|
||||
continue;
|
||||
if (wrmsr_safe(index, data_low, data_high) < 0)
|
||||
continue;
|
||||
|
||||
vmx->guest_uret_msrs[j].slot = i;
|
||||
vmx->guest_uret_msrs[j].data = 0;
|
||||
switch (index) {
|
||||
case MSR_IA32_TSX_CTRL:
|
||||
/*
|
||||
* TSX_CTRL_CPUID_CLEAR is handled in the CPUID
|
||||
* interception. Keep the host value unchanged to avoid
|
||||
* changing CPUID bits under the host kernel's feet.
|
||||
*
|
||||
* hle=0, rtm=0, tsx_ctrl=1 can be found with some
|
||||
* combinations of new kernel and old userspace. If
|
||||
* those guests run on a tsx=off host, do allow guests
|
||||
* to use TSX_CTRL, but do not change the value on the
|
||||
* host so that TSX remains always disabled.
|
||||
*/
|
||||
if (boot_cpu_has(X86_FEATURE_RTM))
|
||||
vmx->guest_uret_msrs[j].mask = ~(u64)TSX_CTRL_CPUID_CLEAR;
|
||||
else
|
||||
vmx->guest_uret_msrs[j].mask = 0;
|
||||
break;
|
||||
default:
|
||||
vmx->guest_uret_msrs[j].mask = -1ull;
|
||||
break;
|
||||
}
|
||||
++vmx->nr_uret_msrs;
|
||||
for (i = 0; i < kvm_nr_uret_msrs; ++i) {
|
||||
vmx->guest_uret_msrs[i].data = 0;
|
||||
vmx->guest_uret_msrs[i].mask = -1ull;
|
||||
}
|
||||
if (boot_cpu_has(X86_FEATURE_RTM)) {
|
||||
/*
|
||||
* TSX_CTRL_CPUID_CLEAR is handled in the CPUID interception.
|
||||
* Keep the host value unchanged to avoid changing CPUID bits
|
||||
* under the host kernel's feet.
|
||||
*/
|
||||
tsx_ctrl = vmx_find_uret_msr(vmx, MSR_IA32_TSX_CTRL);
|
||||
if (tsx_ctrl)
|
||||
vmx->guest_uret_msrs[i].mask = ~(u64)TSX_CTRL_CPUID_CLEAR;
|
||||
}
|
||||
|
||||
err = alloc_loaded_vmcs(&vmx->vmcs01);
|
||||
@@ -7344,9 +7316,11 @@ static __init void vmx_set_cpu_caps(void)
|
||||
if (!cpu_has_vmx_xsaves())
|
||||
kvm_cpu_cap_clear(X86_FEATURE_XSAVES);
|
||||
|
||||
/* CPUID 0x80000001 */
|
||||
if (!cpu_has_vmx_rdtscp())
|
||||
/* CPUID 0x80000001 and 0x7 (RDPID) */
|
||||
if (!cpu_has_vmx_rdtscp()) {
|
||||
kvm_cpu_cap_clear(X86_FEATURE_RDTSCP);
|
||||
kvm_cpu_cap_clear(X86_FEATURE_RDPID);
|
||||
}
|
||||
|
||||
if (cpu_has_vmx_waitpkg())
|
||||
kvm_cpu_cap_check_and_set(X86_FEATURE_WAITPKG);
|
||||
@@ -7402,8 +7376,9 @@ static int vmx_check_intercept(struct kvm_vcpu *vcpu,
|
||||
/*
|
||||
* RDPID causes #UD if disabled through secondary execution controls.
|
||||
* Because it is marked as EmulateOnUD, we need to intercept it here.
|
||||
* Note, RDPID is hidden behind ENABLE_RDTSCP.
|
||||
*/
|
||||
case x86_intercept_rdtscp:
|
||||
case x86_intercept_rdpid:
|
||||
if (!nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_RDTSCP)) {
|
||||
exception->vector = UD_VECTOR;
|
||||
exception->error_code_valid = false;
|
||||
@@ -7769,17 +7744,42 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
|
||||
.vcpu_deliver_sipi_vector = kvm_vcpu_deliver_sipi_vector,
|
||||
};
|
||||
|
||||
static __init void vmx_setup_user_return_msrs(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Though SYSCALL is only supported in 64-bit mode on Intel CPUs, kvm
|
||||
* will emulate SYSCALL in legacy mode if the vendor string in guest
|
||||
* CPUID.0:{EBX,ECX,EDX} is "AuthenticAMD" or "AMDisbetter!" To
|
||||
* support this emulation, MSR_STAR is included in the list for i386,
|
||||
* but is never loaded into hardware. MSR_CSTAR is also never loaded
|
||||
* into hardware and is here purely for emulation purposes.
|
||||
*/
|
||||
const u32 vmx_uret_msrs_list[] = {
|
||||
#ifdef CONFIG_X86_64
|
||||
MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR,
|
||||
#endif
|
||||
MSR_EFER, MSR_TSC_AUX, MSR_STAR,
|
||||
MSR_IA32_TSX_CTRL,
|
||||
};
|
||||
int i;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(vmx_uret_msrs_list) != MAX_NR_USER_RETURN_MSRS);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vmx_uret_msrs_list); ++i)
|
||||
kvm_add_user_return_msr(vmx_uret_msrs_list[i]);
|
||||
}
|
||||
|
||||
static __init int hardware_setup(void)
|
||||
{
|
||||
unsigned long host_bndcfgs;
|
||||
struct desc_ptr dt;
|
||||
int r, i, ept_lpage_level;
|
||||
int r, ept_lpage_level;
|
||||
|
||||
store_idt(&dt);
|
||||
host_idt_base = dt.address;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vmx_uret_msrs_list); ++i)
|
||||
kvm_define_user_return_msr(i, vmx_uret_msrs_list[i]);
|
||||
vmx_setup_user_return_msrs();
|
||||
|
||||
if (setup_vmcs_config(&vmcs_config, &vmx_capability) < 0)
|
||||
return -EIO;
|
||||
|
||||
@@ -36,7 +36,7 @@ struct vmx_msrs {
|
||||
};
|
||||
|
||||
struct vmx_uret_msr {
|
||||
unsigned int slot; /* The MSR's slot in kvm_user_return_msrs. */
|
||||
bool load_into_hardware;
|
||||
u64 data;
|
||||
u64 mask;
|
||||
};
|
||||
@@ -245,8 +245,16 @@ struct vcpu_vmx {
|
||||
u32 idt_vectoring_info;
|
||||
ulong rflags;
|
||||
|
||||
/*
|
||||
* User return MSRs are always emulated when enabled in the guest, but
|
||||
* only loaded into hardware when necessary, e.g. SYSCALL #UDs outside
|
||||
* of 64-bit mode or if EFER.SCE=1, thus the SYSCALL MSRs don't need to
|
||||
* be loaded into hardware if those conditions aren't met.
|
||||
* nr_active_uret_msrs tracks the number of MSRs that need to be loaded
|
||||
* into hardware when running the guest. guest_uret_msrs[] is resorted
|
||||
* whenever the number of "active" uret MSRs is modified.
|
||||
*/
|
||||
struct vmx_uret_msr guest_uret_msrs[MAX_NR_USER_RETURN_MSRS];
|
||||
int nr_uret_msrs;
|
||||
int nr_active_uret_msrs;
|
||||
bool guest_uret_msrs_loaded;
|
||||
#ifdef CONFIG_X86_64
|
||||
|
||||
@@ -184,11 +184,6 @@ module_param(pi_inject_timer, bint, S_IRUGO | S_IWUSR);
|
||||
*/
|
||||
#define KVM_MAX_NR_USER_RETURN_MSRS 16
|
||||
|
||||
struct kvm_user_return_msrs_global {
|
||||
int nr;
|
||||
u32 msrs[KVM_MAX_NR_USER_RETURN_MSRS];
|
||||
};
|
||||
|
||||
struct kvm_user_return_msrs {
|
||||
struct user_return_notifier urn;
|
||||
bool registered;
|
||||
@@ -198,7 +193,9 @@ struct kvm_user_return_msrs {
|
||||
} values[KVM_MAX_NR_USER_RETURN_MSRS];
|
||||
};
|
||||
|
||||
static struct kvm_user_return_msrs_global __read_mostly user_return_msrs_global;
|
||||
u32 __read_mostly kvm_nr_uret_msrs;
|
||||
EXPORT_SYMBOL_GPL(kvm_nr_uret_msrs);
|
||||
static u32 __read_mostly kvm_uret_msrs_list[KVM_MAX_NR_USER_RETURN_MSRS];
|
||||
static struct kvm_user_return_msrs __percpu *user_return_msrs;
|
||||
|
||||
#define KVM_SUPPORTED_XCR0 (XFEATURE_MASK_FP | XFEATURE_MASK_SSE \
|
||||
@@ -330,23 +327,53 @@ static void kvm_on_user_return(struct user_return_notifier *urn)
|
||||
user_return_notifier_unregister(urn);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
for (slot = 0; slot < user_return_msrs_global.nr; ++slot) {
|
||||
for (slot = 0; slot < kvm_nr_uret_msrs; ++slot) {
|
||||
values = &msrs->values[slot];
|
||||
if (values->host != values->curr) {
|
||||
wrmsrl(user_return_msrs_global.msrs[slot], values->host);
|
||||
wrmsrl(kvm_uret_msrs_list[slot], values->host);
|
||||
values->curr = values->host;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_define_user_return_msr(unsigned slot, u32 msr)
|
||||
static int kvm_probe_user_return_msr(u32 msr)
|
||||
{
|
||||
BUG_ON(slot >= KVM_MAX_NR_USER_RETURN_MSRS);
|
||||
user_return_msrs_global.msrs[slot] = msr;
|
||||
if (slot >= user_return_msrs_global.nr)
|
||||
user_return_msrs_global.nr = slot + 1;
|
||||
u64 val;
|
||||
int ret;
|
||||
|
||||
preempt_disable();
|
||||
ret = rdmsrl_safe(msr, &val);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = wrmsrl_safe(msr, val);
|
||||
out:
|
||||
preempt_enable();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_define_user_return_msr);
|
||||
|
||||
int kvm_add_user_return_msr(u32 msr)
|
||||
{
|
||||
BUG_ON(kvm_nr_uret_msrs >= KVM_MAX_NR_USER_RETURN_MSRS);
|
||||
|
||||
if (kvm_probe_user_return_msr(msr))
|
||||
return -1;
|
||||
|
||||
kvm_uret_msrs_list[kvm_nr_uret_msrs] = msr;
|
||||
return kvm_nr_uret_msrs++;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_add_user_return_msr);
|
||||
|
||||
int kvm_find_user_return_msr(u32 msr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < kvm_nr_uret_msrs; ++i) {
|
||||
if (kvm_uret_msrs_list[i] == msr)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_find_user_return_msr);
|
||||
|
||||
static void kvm_user_return_msr_cpu_online(void)
|
||||
{
|
||||
@@ -355,8 +382,8 @@ static void kvm_user_return_msr_cpu_online(void)
|
||||
u64 value;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < user_return_msrs_global.nr; ++i) {
|
||||
rdmsrl_safe(user_return_msrs_global.msrs[i], &value);
|
||||
for (i = 0; i < kvm_nr_uret_msrs; ++i) {
|
||||
rdmsrl_safe(kvm_uret_msrs_list[i], &value);
|
||||
msrs->values[i].host = value;
|
||||
msrs->values[i].curr = value;
|
||||
}
|
||||
@@ -371,7 +398,7 @@ int kvm_set_user_return_msr(unsigned slot, u64 value, u64 mask)
|
||||
value = (value & mask) | (msrs->values[slot].host & ~mask);
|
||||
if (value == msrs->values[slot].curr)
|
||||
return 0;
|
||||
err = wrmsrl_safe(user_return_msrs_global.msrs[slot], value);
|
||||
err = wrmsrl_safe(kvm_uret_msrs_list[slot], value);
|
||||
if (err)
|
||||
return 1;
|
||||
|
||||
@@ -1149,6 +1176,9 @@ static u64 kvm_dr6_fixed(struct kvm_vcpu *vcpu)
|
||||
|
||||
if (!guest_cpuid_has(vcpu, X86_FEATURE_RTM))
|
||||
fixed |= DR6_RTM;
|
||||
|
||||
if (!guest_cpuid_has(vcpu, X86_FEATURE_BUS_LOCK_DETECT))
|
||||
fixed |= DR6_BUS_LOCK;
|
||||
return fixed;
|
||||
}
|
||||
|
||||
@@ -1615,6 +1645,30 @@ static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data,
|
||||
* invokes 64-bit SYSENTER.
|
||||
*/
|
||||
data = get_canonical(data, vcpu_virt_addr_bits(vcpu));
|
||||
break;
|
||||
case MSR_TSC_AUX:
|
||||
if (!kvm_is_supported_user_return_msr(MSR_TSC_AUX))
|
||||
return 1;
|
||||
|
||||
if (!host_initiated &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP) &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_RDPID))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Per Intel's SDM, bits 63:32 are reserved, but AMD's APM has
|
||||
* incomplete and conflicting architectural behavior. Current
|
||||
* AMD CPUs completely ignore bits 63:32, i.e. they aren't
|
||||
* reserved and always read as zeros. Enforce Intel's reserved
|
||||
* bits check if and only if the guest CPU is Intel, and clear
|
||||
* the bits in all other cases. This ensures cross-vendor
|
||||
* migration will provide consistent behavior for the guest.
|
||||
*/
|
||||
if (guest_cpuid_is_intel(vcpu) && (data >> 32) != 0)
|
||||
return 1;
|
||||
|
||||
data = (u32)data;
|
||||
break;
|
||||
}
|
||||
|
||||
msr.data = data;
|
||||
@@ -1651,6 +1705,18 @@ int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data,
|
||||
if (!host_initiated && !kvm_msr_allowed(vcpu, index, KVM_MSR_FILTER_READ))
|
||||
return KVM_MSR_RET_FILTERED;
|
||||
|
||||
switch (index) {
|
||||
case MSR_TSC_AUX:
|
||||
if (!kvm_is_supported_user_return_msr(MSR_TSC_AUX))
|
||||
return 1;
|
||||
|
||||
if (!host_initiated &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP) &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_RDPID))
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
msr.index = index;
|
||||
msr.host_initiated = host_initiated;
|
||||
|
||||
@@ -5468,14 +5534,18 @@ static void kvm_free_msr_filter(struct kvm_x86_msr_filter *msr_filter)
|
||||
static int kvm_add_msr_filter(struct kvm_x86_msr_filter *msr_filter,
|
||||
struct kvm_msr_filter_range *user_range)
|
||||
{
|
||||
struct msr_bitmap_range range;
|
||||
unsigned long *bitmap = NULL;
|
||||
size_t bitmap_size;
|
||||
int r;
|
||||
|
||||
if (!user_range->nmsrs)
|
||||
return 0;
|
||||
|
||||
if (user_range->flags & ~(KVM_MSR_FILTER_READ | KVM_MSR_FILTER_WRITE))
|
||||
return -EINVAL;
|
||||
|
||||
if (!user_range->flags)
|
||||
return -EINVAL;
|
||||
|
||||
bitmap_size = BITS_TO_LONGS(user_range->nmsrs) * sizeof(long);
|
||||
if (!bitmap_size || bitmap_size > KVM_MSR_FILTER_MAX_BITMAP_SIZE)
|
||||
return -EINVAL;
|
||||
@@ -5484,31 +5554,15 @@ static int kvm_add_msr_filter(struct kvm_x86_msr_filter *msr_filter,
|
||||
if (IS_ERR(bitmap))
|
||||
return PTR_ERR(bitmap);
|
||||
|
||||
range = (struct msr_bitmap_range) {
|
||||
msr_filter->ranges[msr_filter->count] = (struct msr_bitmap_range) {
|
||||
.flags = user_range->flags,
|
||||
.base = user_range->base,
|
||||
.nmsrs = user_range->nmsrs,
|
||||
.bitmap = bitmap,
|
||||
};
|
||||
|
||||
if (range.flags & ~(KVM_MSR_FILTER_READ | KVM_MSR_FILTER_WRITE)) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!range.flags) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Everything ok, add this range identifier. */
|
||||
msr_filter->ranges[msr_filter->count] = range;
|
||||
msr_filter->count++;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
kfree(bitmap);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int kvm_vm_ioctl_set_msr_filter(struct kvm *kvm, void __user *argp)
|
||||
@@ -5937,7 +5991,8 @@ static void kvm_init_msr_list(void)
|
||||
continue;
|
||||
break;
|
||||
case MSR_TSC_AUX:
|
||||
if (!kvm_cpu_cap_has(X86_FEATURE_RDTSCP))
|
||||
if (!kvm_cpu_cap_has(X86_FEATURE_RDTSCP) &&
|
||||
!kvm_cpu_cap_has(X86_FEATURE_RDPID))
|
||||
continue;
|
||||
break;
|
||||
case MSR_IA32_UMWAIT_CONTROL:
|
||||
@@ -8039,6 +8094,18 @@ static void pvclock_gtod_update_fn(struct work_struct *work)
|
||||
|
||||
static DECLARE_WORK(pvclock_gtod_work, pvclock_gtod_update_fn);
|
||||
|
||||
/*
|
||||
* Indirection to move queue_work() out of the tk_core.seq write held
|
||||
* region to prevent possible deadlocks against time accessors which
|
||||
* are invoked with work related locks held.
|
||||
*/
|
||||
static void pvclock_irq_work_fn(struct irq_work *w)
|
||||
{
|
||||
queue_work(system_long_wq, &pvclock_gtod_work);
|
||||
}
|
||||
|
||||
static DEFINE_IRQ_WORK(pvclock_irq_work, pvclock_irq_work_fn);
|
||||
|
||||
/*
|
||||
* Notification about pvclock gtod data update.
|
||||
*/
|
||||
@@ -8050,13 +8117,14 @@ static int pvclock_gtod_notify(struct notifier_block *nb, unsigned long unused,
|
||||
|
||||
update_pvclock_gtod(tk);
|
||||
|
||||
/* disable master clock if host does not trust, or does not
|
||||
* use, TSC based clocksource.
|
||||
/*
|
||||
* Disable master clock if host does not trust, or does not use,
|
||||
* TSC based clocksource. Delegate queue_work() to irq_work as
|
||||
* this is invoked with tk_core.seq write held.
|
||||
*/
|
||||
if (!gtod_is_based_on_tsc(gtod->clock.vclock_mode) &&
|
||||
atomic_read(&kvm_guest_has_master_clock) != 0)
|
||||
queue_work(system_long_wq, &pvclock_gtod_work);
|
||||
|
||||
irq_work_queue(&pvclock_irq_work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8118,6 +8186,7 @@ int kvm_arch_init(void *opaque)
|
||||
printk(KERN_ERR "kvm: failed to allocate percpu kvm_user_return_msrs\n");
|
||||
goto out_free_x86_emulator_cache;
|
||||
}
|
||||
kvm_nr_uret_msrs = 0;
|
||||
|
||||
r = kvm_mmu_module_init();
|
||||
if (r)
|
||||
@@ -8168,6 +8237,8 @@ void kvm_arch_exit(void)
|
||||
cpuhp_remove_state_nocalls(CPUHP_AP_X86_KVM_CLK_ONLINE);
|
||||
#ifdef CONFIG_X86_64
|
||||
pvclock_gtod_unregister_notifier(&pvclock_gtod_notifier);
|
||||
irq_work_sync(&pvclock_irq_work);
|
||||
cancel_work_sync(&pvclock_gtod_work);
|
||||
#endif
|
||||
kvm_x86_ops.hardware_enable = NULL;
|
||||
kvm_mmu_module_exit();
|
||||
|
||||
@@ -1313,6 +1313,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
|
||||
{"PNP0C0B", }, /* Generic ACPI fan */
|
||||
{"INT3404", }, /* Fan */
|
||||
{"INTC1044", }, /* Fan for Tiger Lake generation */
|
||||
{"INTC1048", }, /* Fan for Alder Lake generation */
|
||||
{}
|
||||
};
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
|
||||
@@ -142,6 +142,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev,
|
||||
int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
|
||||
int acpi_power_on_resources(struct acpi_device *device, int state);
|
||||
int acpi_power_transition(struct acpi_device *device, int state);
|
||||
void acpi_turn_off_unused_power_resources(void);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Device Power Management
|
||||
|
||||
@@ -995,6 +995,7 @@ void acpi_resume_power_resources(void)
|
||||
|
||||
mutex_unlock(&power_resource_list_lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
void acpi_turn_off_unused_power_resources(void)
|
||||
{
|
||||
@@ -1015,4 +1016,3 @@ void acpi_turn_off_unused_power_resources(void)
|
||||
|
||||
mutex_unlock(&power_resource_list_lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -700,6 +700,7 @@ int acpi_device_add(struct acpi_device *device,
|
||||
|
||||
result = acpi_device_set_name(device, acpi_device_bus_id);
|
||||
if (result) {
|
||||
kfree_const(acpi_device_bus_id->bus_id);
|
||||
kfree(acpi_device_bus_id);
|
||||
goto err_unlock;
|
||||
}
|
||||
@@ -2359,6 +2360,8 @@ int __init acpi_scan_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
acpi_turn_off_unused_power_resources();
|
||||
|
||||
acpi_scan_initialized = true;
|
||||
|
||||
out:
|
||||
|
||||
@@ -8,7 +8,6 @@ extern struct list_head acpi_wakeup_device_list;
|
||||
extern struct mutex acpi_device_lock;
|
||||
|
||||
extern void acpi_resume_power_resources(void);
|
||||
extern void acpi_turn_off_unused_power_resources(void);
|
||||
|
||||
static inline acpi_status acpi_set_waking_vector(u32 wakeup_address)
|
||||
{
|
||||
|
||||
@@ -1637,6 +1637,7 @@ void pm_runtime_init(struct device *dev)
|
||||
dev->power.request_pending = false;
|
||||
dev->power.request = RPM_REQ_NONE;
|
||||
dev->power.deferred_resume = false;
|
||||
dev->power.needs_force_resume = 0;
|
||||
INIT_WORK(&dev->power.work, pm_runtime_work);
|
||||
|
||||
dev->power.timer_expires = 0;
|
||||
@@ -1804,10 +1805,12 @@ int pm_runtime_force_suspend(struct device *dev)
|
||||
* its parent, but set its status to RPM_SUSPENDED anyway in case this
|
||||
* function will be called again for it in the meantime.
|
||||
*/
|
||||
if (pm_runtime_need_not_resume(dev))
|
||||
if (pm_runtime_need_not_resume(dev)) {
|
||||
pm_runtime_set_suspended(dev);
|
||||
else
|
||||
} else {
|
||||
__update_runtime_status(dev, RPM_SUSPENDED);
|
||||
dev->power.needs_force_resume = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1834,7 +1837,7 @@ int pm_runtime_force_resume(struct device *dev)
|
||||
int (*callback)(struct device *);
|
||||
int ret = 0;
|
||||
|
||||
if (!pm_runtime_status_suspended(dev) || pm_runtime_need_not_resume(dev))
|
||||
if (!pm_runtime_status_suspended(dev) || !dev->power.needs_force_resume)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
@@ -1853,6 +1856,7 @@ int pm_runtime_force_resume(struct device *dev)
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
out:
|
||||
dev->power.needs_force_resume = 0;
|
||||
pm_runtime_enable(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -656,6 +656,7 @@ int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
|
||||
|
||||
if (nr_commands !=
|
||||
be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
|
||||
rc = -EFAULT;
|
||||
tpm_buf_destroy(&buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -709,16 +709,14 @@ static int tpm_tis_gen_interrupt(struct tpm_chip *chip)
|
||||
cap_t cap;
|
||||
int ret;
|
||||
|
||||
/* TPM 2.0 */
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
return tpm2_get_tpm_pt(chip, 0x100, &cap2, desc);
|
||||
|
||||
/* TPM 1.2 */
|
||||
ret = request_locality(chip, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc, 0);
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
ret = tpm2_get_tpm_pt(chip, 0x100, &cap2, desc);
|
||||
else
|
||||
ret = tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc, 0);
|
||||
|
||||
release_locality(chip, 0);
|
||||
|
||||
@@ -1127,12 +1125,20 @@ int tpm_tis_resume(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* TPM 1.2 requires self-test on resume. This function actually returns
|
||||
/*
|
||||
* TPM 1.2 requires self-test on resume. This function actually returns
|
||||
* an error code but for unknown reason it isn't handled.
|
||||
*/
|
||||
if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
|
||||
if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
|
||||
ret = request_locality(chip, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tpm1_do_selftest(chip);
|
||||
|
||||
release_locality(chip, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_tis_resume);
|
||||
|
||||
@@ -3033,6 +3033,14 @@ static const struct x86_cpu_id hwp_support_ids[] __initconst = {
|
||||
{}
|
||||
};
|
||||
|
||||
static bool intel_pstate_hwp_is_enabled(void)
|
||||
{
|
||||
u64 value;
|
||||
|
||||
rdmsrl(MSR_PM_ENABLE, value);
|
||||
return !!(value & 0x1);
|
||||
}
|
||||
|
||||
static int __init intel_pstate_init(void)
|
||||
{
|
||||
const struct x86_cpu_id *id;
|
||||
@@ -3051,8 +3059,12 @@ static int __init intel_pstate_init(void)
|
||||
* Avoid enabling HWP for processors without EPP support,
|
||||
* because that means incomplete HWP implementation which is a
|
||||
* corner case and supporting it is generally problematic.
|
||||
*
|
||||
* If HWP is enabled already, though, there is no choice but to
|
||||
* deal with it.
|
||||
*/
|
||||
if (!no_hwp && boot_cpu_has(X86_FEATURE_HWP_EPP)) {
|
||||
if ((!no_hwp && boot_cpu_has(X86_FEATURE_HWP_EPP)) ||
|
||||
intel_pstate_hwp_is_enabled()) {
|
||||
hwp_active++;
|
||||
hwp_mode_bdw = id->driver_data;
|
||||
intel_pstate.attr = hwp_cpufreq_attrs;
|
||||
|
||||
@@ -1006,6 +1006,7 @@ struct amdgpu_device {
|
||||
struct amdgpu_df df;
|
||||
|
||||
struct amdgpu_ip_block ip_blocks[AMDGPU_MAX_IP_NUM];
|
||||
uint32_t harvest_ip_mask;
|
||||
int num_ip_blocks;
|
||||
struct mutex mn_lock;
|
||||
DECLARE_HASHTABLE(mn_hash, 7);
|
||||
|
||||
@@ -1683,6 +1683,19 @@ int amdgpu_device_ip_block_add(struct amdgpu_device *adev,
|
||||
if (!ip_block_version)
|
||||
return -EINVAL;
|
||||
|
||||
switch (ip_block_version->type) {
|
||||
case AMD_IP_BLOCK_TYPE_VCN:
|
||||
if (adev->harvest_ip_mask & AMD_HARVEST_IP_VCN_MASK)
|
||||
return 0;
|
||||
break;
|
||||
case AMD_IP_BLOCK_TYPE_JPEG:
|
||||
if (adev->harvest_ip_mask & AMD_HARVEST_IP_JPEG_MASK)
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DRM_INFO("add ip block number %d <%s>\n", adev->num_ip_blocks,
|
||||
ip_block_version->funcs->name);
|
||||
|
||||
@@ -3111,7 +3124,6 @@ bool amdgpu_device_has_dc_support(struct amdgpu_device *adev)
|
||||
return amdgpu_device_asic_has_dc_support(adev->asic_type);
|
||||
}
|
||||
|
||||
|
||||
static void amdgpu_device_xgmi_reset_func(struct work_struct *__work)
|
||||
{
|
||||
struct amdgpu_device *adev =
|
||||
@@ -3276,6 +3288,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
adev->vm_manager.vm_pte_funcs = NULL;
|
||||
adev->vm_manager.vm_pte_num_scheds = 0;
|
||||
adev->gmc.gmc_funcs = NULL;
|
||||
adev->harvest_ip_mask = 0x0;
|
||||
adev->fence_context = dma_fence_context_alloc(AMDGPU_MAX_RINGS);
|
||||
bitmap_zero(adev->gfx.pipe_reserve_bitmap, AMDGPU_MAX_COMPUTE_QUEUES);
|
||||
|
||||
|
||||
@@ -373,6 +373,34 @@ int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev)
|
||||
{
|
||||
struct binary_header *bhdr;
|
||||
struct harvest_table *harvest_info;
|
||||
int i;
|
||||
|
||||
bhdr = (struct binary_header *)adev->mman.discovery_bin;
|
||||
harvest_info = (struct harvest_table *)(adev->mman.discovery_bin +
|
||||
le16_to_cpu(bhdr->table_list[HARVEST_INFO].offset));
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (le32_to_cpu(harvest_info->list[i].hw_id) == 0)
|
||||
break;
|
||||
|
||||
switch (le32_to_cpu(harvest_info->list[i].hw_id)) {
|
||||
case VCN_HWID:
|
||||
adev->harvest_ip_mask |= AMD_HARVEST_IP_VCN_MASK;
|
||||
adev->harvest_ip_mask |= AMD_HARVEST_IP_JPEG_MASK;
|
||||
break;
|
||||
case DMU_HWID:
|
||||
adev->harvest_ip_mask |= AMD_HARVEST_IP_DMU_MASK;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev)
|
||||
{
|
||||
struct binary_header *bhdr;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
void amdgpu_discovery_fini(struct amdgpu_device *adev);
|
||||
int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev);
|
||||
void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev);
|
||||
int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id,
|
||||
int *major, int *minor, int *revision);
|
||||
int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev);
|
||||
|
||||
@@ -623,6 +623,16 @@ static const struct amdgpu_ip_block_version nv_common_ip_block =
|
||||
.funcs = &nv_common_ip_funcs,
|
||||
};
|
||||
|
||||
static bool nv_is_headless_sku(struct pci_dev *pdev)
|
||||
{
|
||||
if ((pdev->device == 0x731E &&
|
||||
(pdev->revision == 0xC6 || pdev->revision == 0xC7)) ||
|
||||
(pdev->device == 0x7340 && pdev->revision == 0xC9) ||
|
||||
(pdev->device == 0x7360 && pdev->revision == 0xC7))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int nv_reg_base_init(struct amdgpu_device *adev)
|
||||
{
|
||||
int r;
|
||||
@@ -635,6 +645,12 @@ static int nv_reg_base_init(struct amdgpu_device *adev)
|
||||
goto legacy_init;
|
||||
}
|
||||
|
||||
amdgpu_discovery_harvest_ip(adev);
|
||||
if (nv_is_headless_sku(adev->pdev)) {
|
||||
adev->harvest_ip_mask |= AMD_HARVEST_IP_VCN_MASK;
|
||||
adev->harvest_ip_mask |= AMD_HARVEST_IP_JPEG_MASK;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -671,16 +687,6 @@ void nv_set_virt_ops(struct amdgpu_device *adev)
|
||||
adev->virt.ops = &xgpu_nv_virt_ops;
|
||||
}
|
||||
|
||||
static bool nv_is_headless_sku(struct pci_dev *pdev)
|
||||
{
|
||||
if ((pdev->device == 0x731E &&
|
||||
(pdev->revision == 0xC6 || pdev->revision == 0xC7)) ||
|
||||
(pdev->device == 0x7340 && pdev->revision == 0xC9) ||
|
||||
(pdev->device == 0x7360 && pdev->revision == 0xC7))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int nv_set_ip_blocks(struct amdgpu_device *adev)
|
||||
{
|
||||
int r;
|
||||
@@ -728,8 +734,7 @@ int nv_set_ip_blocks(struct amdgpu_device *adev)
|
||||
if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT &&
|
||||
!amdgpu_sriov_vf(adev))
|
||||
amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block);
|
||||
if (!nv_is_headless_sku(adev->pdev))
|
||||
amdgpu_device_ip_block_add(adev, &vcn_v2_0_ip_block);
|
||||
amdgpu_device_ip_block_add(adev, &vcn_v2_0_ip_block);
|
||||
amdgpu_device_ip_block_add(adev, &jpeg_v2_0_ip_block);
|
||||
if (adev->enable_mes)
|
||||
amdgpu_device_ip_block_add(adev, &mes_v10_1_ip_block);
|
||||
@@ -752,8 +757,7 @@ int nv_set_ip_blocks(struct amdgpu_device *adev)
|
||||
if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT &&
|
||||
!amdgpu_sriov_vf(adev))
|
||||
amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block);
|
||||
if (!nv_is_headless_sku(adev->pdev))
|
||||
amdgpu_device_ip_block_add(adev, &vcn_v2_0_ip_block);
|
||||
amdgpu_device_ip_block_add(adev, &vcn_v2_0_ip_block);
|
||||
if (!amdgpu_sriov_vf(adev))
|
||||
amdgpu_device_ip_block_add(adev, &jpeg_v2_0_ip_block);
|
||||
break;
|
||||
@@ -777,7 +781,6 @@ int nv_set_ip_blocks(struct amdgpu_device *adev)
|
||||
amdgpu_device_ip_block_add(adev, &vcn_v3_0_ip_block);
|
||||
if (!amdgpu_sriov_vf(adev))
|
||||
amdgpu_device_ip_block_add(adev, &jpeg_v3_0_ip_block);
|
||||
|
||||
if (adev->enable_mes)
|
||||
amdgpu_device_ip_block_add(adev, &mes_v10_1_ip_block);
|
||||
break;
|
||||
@@ -1149,6 +1152,11 @@ static int nv_common_early_init(void *handle)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (adev->harvest_ip_mask & AMD_HARVEST_IP_VCN_MASK)
|
||||
adev->pg_flags &= ~(AMD_PG_SUPPORT_VCN |
|
||||
AMD_PG_SUPPORT_VCN_DPG |
|
||||
AMD_PG_SUPPORT_JPEG);
|
||||
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
amdgpu_virt_init_setting(adev);
|
||||
xgpu_nv_mailbox_set_irq_funcs(adev);
|
||||
|
||||
@@ -1401,7 +1401,8 @@ static int soc15_common_early_init(void *handle)
|
||||
AMD_CG_SUPPORT_MC_MGCG |
|
||||
AMD_CG_SUPPORT_MC_LS |
|
||||
AMD_CG_SUPPORT_SDMA_MGCG |
|
||||
AMD_CG_SUPPORT_SDMA_LS;
|
||||
AMD_CG_SUPPORT_SDMA_LS |
|
||||
AMD_CG_SUPPORT_VCN_MGCG;
|
||||
|
||||
adev->pg_flags = AMD_PG_SUPPORT_SDMA |
|
||||
AMD_PG_SUPPORT_MMHUB |
|
||||
|
||||
@@ -1119,10 +1119,10 @@ static int vcn_v1_0_stop_spg_mode(struct amdgpu_device *adev)
|
||||
UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
|
||||
SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_LMI_STATUS, tmp, tmp);
|
||||
|
||||
/* put VCPU into reset */
|
||||
WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_SOFT_RESET),
|
||||
UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK,
|
||||
~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK);
|
||||
/* stall UMC channel */
|
||||
WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_CTRL2),
|
||||
UVD_LMI_CTRL2__STALL_ARB_UMC_MASK,
|
||||
~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
|
||||
|
||||
tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK |
|
||||
UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
|
||||
@@ -1141,6 +1141,11 @@ static int vcn_v1_0_stop_spg_mode(struct amdgpu_device *adev)
|
||||
UVD_SOFT_RESET__LMI_SOFT_RESET_MASK,
|
||||
~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK);
|
||||
|
||||
/* put VCPU into reset */
|
||||
WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_SOFT_RESET),
|
||||
UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK,
|
||||
~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK);
|
||||
|
||||
WREG32_SOC15(UVD, 0, mmUVD_STATUS, 0);
|
||||
|
||||
vcn_v1_0_enable_clock_gating(adev);
|
||||
|
||||
@@ -650,6 +650,7 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct
|
||||
|
||||
/* File created at /sys/class/drm/card0/device/hdcp_srm*/
|
||||
hdcp_work[0].attr = data_attr;
|
||||
sysfs_bin_attr_init(&hdcp_work[0].attr);
|
||||
|
||||
if (sysfs_create_bin_file(&adev->dev->kobj, &hdcp_work[0].attr))
|
||||
DRM_WARN("Failed to create device file hdcp_srm");
|
||||
|
||||
@@ -216,6 +216,12 @@ enum PP_FEATURE_MASK {
|
||||
PP_GFX_DCS_MASK = 0x80000,
|
||||
};
|
||||
|
||||
enum amd_harvest_ip_mask {
|
||||
AMD_HARVEST_IP_VCN_MASK = 0x1,
|
||||
AMD_HARVEST_IP_JPEG_MASK = 0x2,
|
||||
AMD_HARVEST_IP_DMU_MASK = 0x4,
|
||||
};
|
||||
|
||||
enum DC_FEATURE_MASK {
|
||||
DC_FBC_MASK = 0x1,
|
||||
DC_MULTI_MON_PP_MCLK_SWITCH_MASK = 0x2,
|
||||
|
||||
@@ -4817,70 +4817,70 @@ static int si_populate_smc_initial_state(struct amdgpu_device *adev,
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
table->initialState.levels[0].mclk.vDLL_CNTL =
|
||||
table->initialState.level.mclk.vDLL_CNTL =
|
||||
cpu_to_be32(si_pi->clock_registers.dll_cntl);
|
||||
table->initialState.levels[0].mclk.vMCLK_PWRMGT_CNTL =
|
||||
table->initialState.level.mclk.vMCLK_PWRMGT_CNTL =
|
||||
cpu_to_be32(si_pi->clock_registers.mclk_pwrmgt_cntl);
|
||||
table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL =
|
||||
table->initialState.level.mclk.vMPLL_AD_FUNC_CNTL =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_ad_func_cntl);
|
||||
table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL =
|
||||
table->initialState.level.mclk.vMPLL_DQ_FUNC_CNTL =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_dq_func_cntl);
|
||||
table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL =
|
||||
table->initialState.level.mclk.vMPLL_FUNC_CNTL =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_func_cntl);
|
||||
table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL_1 =
|
||||
table->initialState.level.mclk.vMPLL_FUNC_CNTL_1 =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_func_cntl_1);
|
||||
table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL_2 =
|
||||
table->initialState.level.mclk.vMPLL_FUNC_CNTL_2 =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_func_cntl_2);
|
||||
table->initialState.levels[0].mclk.vMPLL_SS =
|
||||
table->initialState.level.mclk.vMPLL_SS =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_ss1);
|
||||
table->initialState.levels[0].mclk.vMPLL_SS2 =
|
||||
table->initialState.level.mclk.vMPLL_SS2 =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_ss2);
|
||||
|
||||
table->initialState.levels[0].mclk.mclk_value =
|
||||
table->initialState.level.mclk.mclk_value =
|
||||
cpu_to_be32(initial_state->performance_levels[0].mclk);
|
||||
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
|
||||
table->initialState.level.sclk.vCG_SPLL_FUNC_CNTL =
|
||||
cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
|
||||
table->initialState.level.sclk.vCG_SPLL_FUNC_CNTL_2 =
|
||||
cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_2);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
|
||||
table->initialState.level.sclk.vCG_SPLL_FUNC_CNTL_3 =
|
||||
cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_3);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 =
|
||||
table->initialState.level.sclk.vCG_SPLL_FUNC_CNTL_4 =
|
||||
cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_4);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
|
||||
table->initialState.level.sclk.vCG_SPLL_SPREAD_SPECTRUM =
|
||||
cpu_to_be32(si_pi->clock_registers.cg_spll_spread_spectrum);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
|
||||
table->initialState.level.sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
|
||||
cpu_to_be32(si_pi->clock_registers.cg_spll_spread_spectrum_2);
|
||||
|
||||
table->initialState.levels[0].sclk.sclk_value =
|
||||
table->initialState.level.sclk.sclk_value =
|
||||
cpu_to_be32(initial_state->performance_levels[0].sclk);
|
||||
|
||||
table->initialState.levels[0].arbRefreshState =
|
||||
table->initialState.level.arbRefreshState =
|
||||
SISLANDS_INITIAL_STATE_ARB_INDEX;
|
||||
|
||||
table->initialState.levels[0].ACIndex = 0;
|
||||
table->initialState.level.ACIndex = 0;
|
||||
|
||||
ret = si_populate_voltage_value(adev, &eg_pi->vddc_voltage_table,
|
||||
initial_state->performance_levels[0].vddc,
|
||||
&table->initialState.levels[0].vddc);
|
||||
&table->initialState.level.vddc);
|
||||
|
||||
if (!ret) {
|
||||
u16 std_vddc;
|
||||
|
||||
ret = si_get_std_voltage_value(adev,
|
||||
&table->initialState.levels[0].vddc,
|
||||
&table->initialState.level.vddc,
|
||||
&std_vddc);
|
||||
if (!ret)
|
||||
si_populate_std_voltage_value(adev, std_vddc,
|
||||
table->initialState.levels[0].vddc.index,
|
||||
&table->initialState.levels[0].std_vddc);
|
||||
table->initialState.level.vddc.index,
|
||||
&table->initialState.level.std_vddc);
|
||||
}
|
||||
|
||||
if (eg_pi->vddci_control)
|
||||
si_populate_voltage_value(adev,
|
||||
&eg_pi->vddci_voltage_table,
|
||||
initial_state->performance_levels[0].vddci,
|
||||
&table->initialState.levels[0].vddci);
|
||||
&table->initialState.level.vddci);
|
||||
|
||||
if (si_pi->vddc_phase_shed_control)
|
||||
si_populate_phase_shedding_value(adev,
|
||||
@@ -4888,41 +4888,41 @@ static int si_populate_smc_initial_state(struct amdgpu_device *adev,
|
||||
initial_state->performance_levels[0].vddc,
|
||||
initial_state->performance_levels[0].sclk,
|
||||
initial_state->performance_levels[0].mclk,
|
||||
&table->initialState.levels[0].vddc);
|
||||
&table->initialState.level.vddc);
|
||||
|
||||
si_populate_initial_mvdd_value(adev, &table->initialState.levels[0].mvdd);
|
||||
si_populate_initial_mvdd_value(adev, &table->initialState.level.mvdd);
|
||||
|
||||
reg = CG_R(0xffff) | CG_L(0);
|
||||
table->initialState.levels[0].aT = cpu_to_be32(reg);
|
||||
table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
|
||||
table->initialState.levels[0].gen2PCIE = (u8)si_pi->boot_pcie_gen;
|
||||
table->initialState.level.aT = cpu_to_be32(reg);
|
||||
table->initialState.level.bSP = cpu_to_be32(pi->dsp);
|
||||
table->initialState.level.gen2PCIE = (u8)si_pi->boot_pcie_gen;
|
||||
|
||||
if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) {
|
||||
table->initialState.levels[0].strobeMode =
|
||||
table->initialState.level.strobeMode =
|
||||
si_get_strobe_mode_settings(adev,
|
||||
initial_state->performance_levels[0].mclk);
|
||||
|
||||
if (initial_state->performance_levels[0].mclk > pi->mclk_edc_enable_threshold)
|
||||
table->initialState.levels[0].mcFlags = SISLANDS_SMC_MC_EDC_RD_FLAG | SISLANDS_SMC_MC_EDC_WR_FLAG;
|
||||
table->initialState.level.mcFlags = SISLANDS_SMC_MC_EDC_RD_FLAG | SISLANDS_SMC_MC_EDC_WR_FLAG;
|
||||
else
|
||||
table->initialState.levels[0].mcFlags = 0;
|
||||
table->initialState.level.mcFlags = 0;
|
||||
}
|
||||
|
||||
table->initialState.levelCount = 1;
|
||||
|
||||
table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
|
||||
|
||||
table->initialState.levels[0].dpm2.MaxPS = 0;
|
||||
table->initialState.levels[0].dpm2.NearTDPDec = 0;
|
||||
table->initialState.levels[0].dpm2.AboveSafeInc = 0;
|
||||
table->initialState.levels[0].dpm2.BelowSafeInc = 0;
|
||||
table->initialState.levels[0].dpm2.PwrEfficiencyRatio = 0;
|
||||
table->initialState.level.dpm2.MaxPS = 0;
|
||||
table->initialState.level.dpm2.NearTDPDec = 0;
|
||||
table->initialState.level.dpm2.AboveSafeInc = 0;
|
||||
table->initialState.level.dpm2.BelowSafeInc = 0;
|
||||
table->initialState.level.dpm2.PwrEfficiencyRatio = 0;
|
||||
|
||||
reg = MIN_POWER_MASK | MAX_POWER_MASK;
|
||||
table->initialState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
|
||||
table->initialState.level.SQPowerThrottle = cpu_to_be32(reg);
|
||||
|
||||
reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
|
||||
table->initialState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
|
||||
table->initialState.level.SQPowerThrottle_2 = cpu_to_be32(reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4953,18 +4953,18 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev,
|
||||
|
||||
if (pi->acpi_vddc) {
|
||||
ret = si_populate_voltage_value(adev, &eg_pi->vddc_voltage_table,
|
||||
pi->acpi_vddc, &table->ACPIState.levels[0].vddc);
|
||||
pi->acpi_vddc, &table->ACPIState.level.vddc);
|
||||
if (!ret) {
|
||||
u16 std_vddc;
|
||||
|
||||
ret = si_get_std_voltage_value(adev,
|
||||
&table->ACPIState.levels[0].vddc, &std_vddc);
|
||||
&table->ACPIState.level.vddc, &std_vddc);
|
||||
if (!ret)
|
||||
si_populate_std_voltage_value(adev, std_vddc,
|
||||
table->ACPIState.levels[0].vddc.index,
|
||||
&table->ACPIState.levels[0].std_vddc);
|
||||
table->ACPIState.level.vddc.index,
|
||||
&table->ACPIState.level.std_vddc);
|
||||
}
|
||||
table->ACPIState.levels[0].gen2PCIE = si_pi->acpi_pcie_gen;
|
||||
table->ACPIState.level.gen2PCIE = si_pi->acpi_pcie_gen;
|
||||
|
||||
if (si_pi->vddc_phase_shed_control) {
|
||||
si_populate_phase_shedding_value(adev,
|
||||
@@ -4972,23 +4972,23 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev,
|
||||
pi->acpi_vddc,
|
||||
0,
|
||||
0,
|
||||
&table->ACPIState.levels[0].vddc);
|
||||
&table->ACPIState.level.vddc);
|
||||
}
|
||||
} else {
|
||||
ret = si_populate_voltage_value(adev, &eg_pi->vddc_voltage_table,
|
||||
pi->min_vddc_in_table, &table->ACPIState.levels[0].vddc);
|
||||
pi->min_vddc_in_table, &table->ACPIState.level.vddc);
|
||||
if (!ret) {
|
||||
u16 std_vddc;
|
||||
|
||||
ret = si_get_std_voltage_value(adev,
|
||||
&table->ACPIState.levels[0].vddc, &std_vddc);
|
||||
&table->ACPIState.level.vddc, &std_vddc);
|
||||
|
||||
if (!ret)
|
||||
si_populate_std_voltage_value(adev, std_vddc,
|
||||
table->ACPIState.levels[0].vddc.index,
|
||||
&table->ACPIState.levels[0].std_vddc);
|
||||
table->ACPIState.level.vddc.index,
|
||||
&table->ACPIState.level.std_vddc);
|
||||
}
|
||||
table->ACPIState.levels[0].gen2PCIE =
|
||||
table->ACPIState.level.gen2PCIE =
|
||||
(u8)amdgpu_get_pcie_gen_support(adev,
|
||||
si_pi->sys_pcie_mask,
|
||||
si_pi->boot_pcie_gen,
|
||||
@@ -5000,14 +5000,14 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev,
|
||||
pi->min_vddc_in_table,
|
||||
0,
|
||||
0,
|
||||
&table->ACPIState.levels[0].vddc);
|
||||
&table->ACPIState.level.vddc);
|
||||
}
|
||||
|
||||
if (pi->acpi_vddc) {
|
||||
if (eg_pi->acpi_vddci)
|
||||
si_populate_voltage_value(adev, &eg_pi->vddci_voltage_table,
|
||||
eg_pi->acpi_vddci,
|
||||
&table->ACPIState.levels[0].vddci);
|
||||
&table->ACPIState.level.vddci);
|
||||
}
|
||||
|
||||
mclk_pwrmgt_cntl |= MRDCK0_RESET | MRDCK1_RESET;
|
||||
@@ -5018,59 +5018,59 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev,
|
||||
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
|
||||
spll_func_cntl_2 |= SCLK_MUX_SEL(4);
|
||||
|
||||
table->ACPIState.levels[0].mclk.vDLL_CNTL =
|
||||
table->ACPIState.level.mclk.vDLL_CNTL =
|
||||
cpu_to_be32(dll_cntl);
|
||||
table->ACPIState.levels[0].mclk.vMCLK_PWRMGT_CNTL =
|
||||
table->ACPIState.level.mclk.vMCLK_PWRMGT_CNTL =
|
||||
cpu_to_be32(mclk_pwrmgt_cntl);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL =
|
||||
table->ACPIState.level.mclk.vMPLL_AD_FUNC_CNTL =
|
||||
cpu_to_be32(mpll_ad_func_cntl);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL =
|
||||
table->ACPIState.level.mclk.vMPLL_DQ_FUNC_CNTL =
|
||||
cpu_to_be32(mpll_dq_func_cntl);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL =
|
||||
table->ACPIState.level.mclk.vMPLL_FUNC_CNTL =
|
||||
cpu_to_be32(mpll_func_cntl);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL_1 =
|
||||
table->ACPIState.level.mclk.vMPLL_FUNC_CNTL_1 =
|
||||
cpu_to_be32(mpll_func_cntl_1);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL_2 =
|
||||
table->ACPIState.level.mclk.vMPLL_FUNC_CNTL_2 =
|
||||
cpu_to_be32(mpll_func_cntl_2);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_SS =
|
||||
table->ACPIState.level.mclk.vMPLL_SS =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_ss1);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_SS2 =
|
||||
table->ACPIState.level.mclk.vMPLL_SS2 =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_ss2);
|
||||
|
||||
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
|
||||
table->ACPIState.level.sclk.vCG_SPLL_FUNC_CNTL =
|
||||
cpu_to_be32(spll_func_cntl);
|
||||
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
|
||||
table->ACPIState.level.sclk.vCG_SPLL_FUNC_CNTL_2 =
|
||||
cpu_to_be32(spll_func_cntl_2);
|
||||
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
|
||||
table->ACPIState.level.sclk.vCG_SPLL_FUNC_CNTL_3 =
|
||||
cpu_to_be32(spll_func_cntl_3);
|
||||
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 =
|
||||
table->ACPIState.level.sclk.vCG_SPLL_FUNC_CNTL_4 =
|
||||
cpu_to_be32(spll_func_cntl_4);
|
||||
|
||||
table->ACPIState.levels[0].mclk.mclk_value = 0;
|
||||
table->ACPIState.levels[0].sclk.sclk_value = 0;
|
||||
table->ACPIState.level.mclk.mclk_value = 0;
|
||||
table->ACPIState.level.sclk.sclk_value = 0;
|
||||
|
||||
si_populate_mvdd_value(adev, 0, &table->ACPIState.levels[0].mvdd);
|
||||
si_populate_mvdd_value(adev, 0, &table->ACPIState.level.mvdd);
|
||||
|
||||
if (eg_pi->dynamic_ac_timing)
|
||||
table->ACPIState.levels[0].ACIndex = 0;
|
||||
table->ACPIState.level.ACIndex = 0;
|
||||
|
||||
table->ACPIState.levels[0].dpm2.MaxPS = 0;
|
||||
table->ACPIState.levels[0].dpm2.NearTDPDec = 0;
|
||||
table->ACPIState.levels[0].dpm2.AboveSafeInc = 0;
|
||||
table->ACPIState.levels[0].dpm2.BelowSafeInc = 0;
|
||||
table->ACPIState.levels[0].dpm2.PwrEfficiencyRatio = 0;
|
||||
table->ACPIState.level.dpm2.MaxPS = 0;
|
||||
table->ACPIState.level.dpm2.NearTDPDec = 0;
|
||||
table->ACPIState.level.dpm2.AboveSafeInc = 0;
|
||||
table->ACPIState.level.dpm2.BelowSafeInc = 0;
|
||||
table->ACPIState.level.dpm2.PwrEfficiencyRatio = 0;
|
||||
|
||||
reg = MIN_POWER_MASK | MAX_POWER_MASK;
|
||||
table->ACPIState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
|
||||
table->ACPIState.level.SQPowerThrottle = cpu_to_be32(reg);
|
||||
|
||||
reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
|
||||
table->ACPIState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
|
||||
table->ACPIState.level.SQPowerThrottle_2 = cpu_to_be32(reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si_populate_ulv_state(struct amdgpu_device *adev,
|
||||
SISLANDS_SMC_SWSTATE *state)
|
||||
struct SISLANDS_SMC_SWSTATE_SINGLE *state)
|
||||
{
|
||||
struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
|
||||
struct si_power_info *si_pi = si_get_pi(adev);
|
||||
@@ -5079,19 +5079,19 @@ static int si_populate_ulv_state(struct amdgpu_device *adev,
|
||||
int ret;
|
||||
|
||||
ret = si_convert_power_level_to_smc(adev, &ulv->pl,
|
||||
&state->levels[0]);
|
||||
&state->level);
|
||||
if (!ret) {
|
||||
if (eg_pi->sclk_deep_sleep) {
|
||||
if (sclk_in_sr <= SCLK_MIN_DEEPSLEEP_FREQ)
|
||||
state->levels[0].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_BYPASS;
|
||||
state->level.stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_BYPASS;
|
||||
else
|
||||
state->levels[0].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE;
|
||||
state->level.stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE;
|
||||
}
|
||||
if (ulv->one_pcie_lane_in_ulv)
|
||||
state->flags |= PPSMC_SWSTATE_FLAG_PCIE_X1;
|
||||
state->levels[0].arbRefreshState = (u8)(SISLANDS_ULV_STATE_ARB_INDEX);
|
||||
state->levels[0].ACIndex = 1;
|
||||
state->levels[0].std_vddc = state->levels[0].vddc;
|
||||
state->level.arbRefreshState = (u8)(SISLANDS_ULV_STATE_ARB_INDEX);
|
||||
state->level.ACIndex = 1;
|
||||
state->level.std_vddc = state->level.vddc;
|
||||
state->levelCount = 1;
|
||||
|
||||
state->flags |= PPSMC_SWSTATE_FLAG_DC;
|
||||
@@ -5190,7 +5190,9 @@ static int si_init_smc_table(struct amdgpu_device *adev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
table->driverState = table->initialState;
|
||||
table->driverState.flags = table->initialState.flags;
|
||||
table->driverState.levelCount = table->initialState.levelCount;
|
||||
table->driverState.levels[0] = table->initialState.level;
|
||||
|
||||
ret = si_do_program_memory_timing_parameters(adev, amdgpu_boot_state,
|
||||
SISLANDS_INITIAL_STATE_ARB_INDEX);
|
||||
@@ -5737,8 +5739,8 @@ static int si_upload_ulv_state(struct amdgpu_device *adev)
|
||||
if (ulv->supported && ulv->pl.vddc) {
|
||||
u32 address = si_pi->state_table_start +
|
||||
offsetof(SISLANDS_SMC_STATETABLE, ULVState);
|
||||
SISLANDS_SMC_SWSTATE *smc_state = &si_pi->smc_statetable.ULVState;
|
||||
u32 state_size = sizeof(SISLANDS_SMC_SWSTATE);
|
||||
struct SISLANDS_SMC_SWSTATE_SINGLE *smc_state = &si_pi->smc_statetable.ULVState;
|
||||
u32 state_size = sizeof(struct SISLANDS_SMC_SWSTATE_SINGLE);
|
||||
|
||||
memset(smc_state, 0, state_size);
|
||||
|
||||
|
||||
@@ -191,6 +191,14 @@ struct SISLANDS_SMC_SWSTATE
|
||||
|
||||
typedef struct SISLANDS_SMC_SWSTATE SISLANDS_SMC_SWSTATE;
|
||||
|
||||
struct SISLANDS_SMC_SWSTATE_SINGLE {
|
||||
uint8_t flags;
|
||||
uint8_t levelCount;
|
||||
uint8_t padding2;
|
||||
uint8_t padding3;
|
||||
SISLANDS_SMC_HW_PERFORMANCE_LEVEL level;
|
||||
};
|
||||
|
||||
#define SISLANDS_SMC_VOLTAGEMASK_VDDC 0
|
||||
#define SISLANDS_SMC_VOLTAGEMASK_MVDD 1
|
||||
#define SISLANDS_SMC_VOLTAGEMASK_VDDCI 2
|
||||
@@ -208,19 +216,19 @@ typedef struct SISLANDS_SMC_VOLTAGEMASKTABLE SISLANDS_SMC_VOLTAGEMASKTABLE;
|
||||
|
||||
struct SISLANDS_SMC_STATETABLE
|
||||
{
|
||||
uint8_t thermalProtectType;
|
||||
uint8_t systemFlags;
|
||||
uint8_t maxVDDCIndexInPPTable;
|
||||
uint8_t extraFlags;
|
||||
uint32_t lowSMIO[SISLANDS_MAX_NO_VREG_STEPS];
|
||||
SISLANDS_SMC_VOLTAGEMASKTABLE voltageMaskTable;
|
||||
SISLANDS_SMC_VOLTAGEMASKTABLE phaseMaskTable;
|
||||
PP_SIslands_DPM2Parameters dpm2Params;
|
||||
SISLANDS_SMC_SWSTATE initialState;
|
||||
SISLANDS_SMC_SWSTATE ACPIState;
|
||||
SISLANDS_SMC_SWSTATE ULVState;
|
||||
SISLANDS_SMC_SWSTATE driverState;
|
||||
SISLANDS_SMC_HW_PERFORMANCE_LEVEL dpmLevels[SISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1];
|
||||
uint8_t thermalProtectType;
|
||||
uint8_t systemFlags;
|
||||
uint8_t maxVDDCIndexInPPTable;
|
||||
uint8_t extraFlags;
|
||||
uint32_t lowSMIO[SISLANDS_MAX_NO_VREG_STEPS];
|
||||
SISLANDS_SMC_VOLTAGEMASKTABLE voltageMaskTable;
|
||||
SISLANDS_SMC_VOLTAGEMASKTABLE phaseMaskTable;
|
||||
PP_SIslands_DPM2Parameters dpm2Params;
|
||||
struct SISLANDS_SMC_SWSTATE_SINGLE initialState;
|
||||
struct SISLANDS_SMC_SWSTATE_SINGLE ACPIState;
|
||||
struct SISLANDS_SMC_SWSTATE_SINGLE ULVState;
|
||||
SISLANDS_SMC_SWSTATE driverState;
|
||||
SISLANDS_SMC_HW_PERFORMANCE_LEVEL dpmLevels[SISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
|
||||
};
|
||||
|
||||
typedef struct SISLANDS_SMC_STATETABLE SISLANDS_SMC_STATETABLE;
|
||||
|
||||
@@ -1687,102 +1687,102 @@ static int ni_populate_smc_initial_state(struct radeon_device *rdev,
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL =
|
||||
table->initialState.level.mclk.vMPLL_AD_FUNC_CNTL =
|
||||
cpu_to_be32(ni_pi->clock_registers.mpll_ad_func_cntl);
|
||||
table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL_2 =
|
||||
table->initialState.level.mclk.vMPLL_AD_FUNC_CNTL_2 =
|
||||
cpu_to_be32(ni_pi->clock_registers.mpll_ad_func_cntl_2);
|
||||
table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL =
|
||||
table->initialState.level.mclk.vMPLL_DQ_FUNC_CNTL =
|
||||
cpu_to_be32(ni_pi->clock_registers.mpll_dq_func_cntl);
|
||||
table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL_2 =
|
||||
table->initialState.level.mclk.vMPLL_DQ_FUNC_CNTL_2 =
|
||||
cpu_to_be32(ni_pi->clock_registers.mpll_dq_func_cntl_2);
|
||||
table->initialState.levels[0].mclk.vMCLK_PWRMGT_CNTL =
|
||||
table->initialState.level.mclk.vMCLK_PWRMGT_CNTL =
|
||||
cpu_to_be32(ni_pi->clock_registers.mclk_pwrmgt_cntl);
|
||||
table->initialState.levels[0].mclk.vDLL_CNTL =
|
||||
table->initialState.level.mclk.vDLL_CNTL =
|
||||
cpu_to_be32(ni_pi->clock_registers.dll_cntl);
|
||||
table->initialState.levels[0].mclk.vMPLL_SS =
|
||||
table->initialState.level.mclk.vMPLL_SS =
|
||||
cpu_to_be32(ni_pi->clock_registers.mpll_ss1);
|
||||
table->initialState.levels[0].mclk.vMPLL_SS2 =
|
||||
table->initialState.level.mclk.vMPLL_SS2 =
|
||||
cpu_to_be32(ni_pi->clock_registers.mpll_ss2);
|
||||
table->initialState.levels[0].mclk.mclk_value =
|
||||
table->initialState.level.mclk.mclk_value =
|
||||
cpu_to_be32(initial_state->performance_levels[0].mclk);
|
||||
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
|
||||
table->initialState.level.sclk.vCG_SPLL_FUNC_CNTL =
|
||||
cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
|
||||
table->initialState.level.sclk.vCG_SPLL_FUNC_CNTL_2 =
|
||||
cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_2);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
|
||||
table->initialState.level.sclk.vCG_SPLL_FUNC_CNTL_3 =
|
||||
cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_3);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 =
|
||||
table->initialState.level.sclk.vCG_SPLL_FUNC_CNTL_4 =
|
||||
cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_4);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
|
||||
table->initialState.level.sclk.vCG_SPLL_SPREAD_SPECTRUM =
|
||||
cpu_to_be32(ni_pi->clock_registers.cg_spll_spread_spectrum);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
|
||||
table->initialState.level.sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
|
||||
cpu_to_be32(ni_pi->clock_registers.cg_spll_spread_spectrum_2);
|
||||
table->initialState.levels[0].sclk.sclk_value =
|
||||
table->initialState.level.sclk.sclk_value =
|
||||
cpu_to_be32(initial_state->performance_levels[0].sclk);
|
||||
table->initialState.levels[0].arbRefreshState =
|
||||
table->initialState.level.arbRefreshState =
|
||||
NISLANDS_INITIAL_STATE_ARB_INDEX;
|
||||
|
||||
table->initialState.levels[0].ACIndex = 0;
|
||||
table->initialState.level.ACIndex = 0;
|
||||
|
||||
ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
|
||||
initial_state->performance_levels[0].vddc,
|
||||
&table->initialState.levels[0].vddc);
|
||||
&table->initialState.level.vddc);
|
||||
if (!ret) {
|
||||
u16 std_vddc;
|
||||
|
||||
ret = ni_get_std_voltage_value(rdev,
|
||||
&table->initialState.levels[0].vddc,
|
||||
&table->initialState.level.vddc,
|
||||
&std_vddc);
|
||||
if (!ret)
|
||||
ni_populate_std_voltage_value(rdev, std_vddc,
|
||||
table->initialState.levels[0].vddc.index,
|
||||
&table->initialState.levels[0].std_vddc);
|
||||
table->initialState.level.vddc.index,
|
||||
&table->initialState.level.std_vddc);
|
||||
}
|
||||
|
||||
if (eg_pi->vddci_control)
|
||||
ni_populate_voltage_value(rdev,
|
||||
&eg_pi->vddci_voltage_table,
|
||||
initial_state->performance_levels[0].vddci,
|
||||
&table->initialState.levels[0].vddci);
|
||||
&table->initialState.level.vddci);
|
||||
|
||||
ni_populate_initial_mvdd_value(rdev, &table->initialState.levels[0].mvdd);
|
||||
ni_populate_initial_mvdd_value(rdev, &table->initialState.level.mvdd);
|
||||
|
||||
reg = CG_R(0xffff) | CG_L(0);
|
||||
table->initialState.levels[0].aT = cpu_to_be32(reg);
|
||||
table->initialState.level.aT = cpu_to_be32(reg);
|
||||
|
||||
table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
|
||||
table->initialState.level.bSP = cpu_to_be32(pi->dsp);
|
||||
|
||||
if (pi->boot_in_gen2)
|
||||
table->initialState.levels[0].gen2PCIE = 1;
|
||||
table->initialState.level.gen2PCIE = 1;
|
||||
else
|
||||
table->initialState.levels[0].gen2PCIE = 0;
|
||||
table->initialState.level.gen2PCIE = 0;
|
||||
|
||||
if (pi->mem_gddr5) {
|
||||
table->initialState.levels[0].strobeMode =
|
||||
table->initialState.level.strobeMode =
|
||||
cypress_get_strobe_mode_settings(rdev,
|
||||
initial_state->performance_levels[0].mclk);
|
||||
|
||||
if (initial_state->performance_levels[0].mclk > pi->mclk_edc_enable_threshold)
|
||||
table->initialState.levels[0].mcFlags = NISLANDS_SMC_MC_EDC_RD_FLAG | NISLANDS_SMC_MC_EDC_WR_FLAG;
|
||||
table->initialState.level.mcFlags = NISLANDS_SMC_MC_EDC_RD_FLAG | NISLANDS_SMC_MC_EDC_WR_FLAG;
|
||||
else
|
||||
table->initialState.levels[0].mcFlags = 0;
|
||||
table->initialState.level.mcFlags = 0;
|
||||
}
|
||||
|
||||
table->initialState.levelCount = 1;
|
||||
|
||||
table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
|
||||
|
||||
table->initialState.levels[0].dpm2.MaxPS = 0;
|
||||
table->initialState.levels[0].dpm2.NearTDPDec = 0;
|
||||
table->initialState.levels[0].dpm2.AboveSafeInc = 0;
|
||||
table->initialState.levels[0].dpm2.BelowSafeInc = 0;
|
||||
table->initialState.level.dpm2.MaxPS = 0;
|
||||
table->initialState.level.dpm2.NearTDPDec = 0;
|
||||
table->initialState.level.dpm2.AboveSafeInc = 0;
|
||||
table->initialState.level.dpm2.BelowSafeInc = 0;
|
||||
|
||||
reg = MIN_POWER_MASK | MAX_POWER_MASK;
|
||||
table->initialState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
|
||||
table->initialState.level.SQPowerThrottle = cpu_to_be32(reg);
|
||||
|
||||
reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
|
||||
table->initialState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
|
||||
table->initialState.level.SQPowerThrottle_2 = cpu_to_be32(reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1813,43 +1813,43 @@ static int ni_populate_smc_acpi_state(struct radeon_device *rdev,
|
||||
if (pi->acpi_vddc) {
|
||||
ret = ni_populate_voltage_value(rdev,
|
||||
&eg_pi->vddc_voltage_table,
|
||||
pi->acpi_vddc, &table->ACPIState.levels[0].vddc);
|
||||
pi->acpi_vddc, &table->ACPIState.level.vddc);
|
||||
if (!ret) {
|
||||
u16 std_vddc;
|
||||
|
||||
ret = ni_get_std_voltage_value(rdev,
|
||||
&table->ACPIState.levels[0].vddc, &std_vddc);
|
||||
&table->ACPIState.level.vddc, &std_vddc);
|
||||
if (!ret)
|
||||
ni_populate_std_voltage_value(rdev, std_vddc,
|
||||
table->ACPIState.levels[0].vddc.index,
|
||||
&table->ACPIState.levels[0].std_vddc);
|
||||
table->ACPIState.level.vddc.index,
|
||||
&table->ACPIState.level.std_vddc);
|
||||
}
|
||||
|
||||
if (pi->pcie_gen2) {
|
||||
if (pi->acpi_pcie_gen2)
|
||||
table->ACPIState.levels[0].gen2PCIE = 1;
|
||||
table->ACPIState.level.gen2PCIE = 1;
|
||||
else
|
||||
table->ACPIState.levels[0].gen2PCIE = 0;
|
||||
table->ACPIState.level.gen2PCIE = 0;
|
||||
} else {
|
||||
table->ACPIState.levels[0].gen2PCIE = 0;
|
||||
table->ACPIState.level.gen2PCIE = 0;
|
||||
}
|
||||
} else {
|
||||
ret = ni_populate_voltage_value(rdev,
|
||||
&eg_pi->vddc_voltage_table,
|
||||
pi->min_vddc_in_table,
|
||||
&table->ACPIState.levels[0].vddc);
|
||||
&table->ACPIState.level.vddc);
|
||||
if (!ret) {
|
||||
u16 std_vddc;
|
||||
|
||||
ret = ni_get_std_voltage_value(rdev,
|
||||
&table->ACPIState.levels[0].vddc,
|
||||
&table->ACPIState.level.vddc,
|
||||
&std_vddc);
|
||||
if (!ret)
|
||||
ni_populate_std_voltage_value(rdev, std_vddc,
|
||||
table->ACPIState.levels[0].vddc.index,
|
||||
&table->ACPIState.levels[0].std_vddc);
|
||||
table->ACPIState.level.vddc.index,
|
||||
&table->ACPIState.level.std_vddc);
|
||||
}
|
||||
table->ACPIState.levels[0].gen2PCIE = 0;
|
||||
table->ACPIState.level.gen2PCIE = 0;
|
||||
}
|
||||
|
||||
if (eg_pi->acpi_vddci) {
|
||||
@@ -1857,7 +1857,7 @@ static int ni_populate_smc_acpi_state(struct radeon_device *rdev,
|
||||
ni_populate_voltage_value(rdev,
|
||||
&eg_pi->vddci_voltage_table,
|
||||
eg_pi->acpi_vddci,
|
||||
&table->ACPIState.levels[0].vddci);
|
||||
&table->ACPIState.level.vddci);
|
||||
}
|
||||
|
||||
|
||||
@@ -1900,37 +1900,37 @@ static int ni_populate_smc_acpi_state(struct radeon_device *rdev,
|
||||
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
|
||||
spll_func_cntl_2 |= SCLK_MUX_SEL(4);
|
||||
|
||||
table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
|
||||
table->ACPIState.levels[0].mclk.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
|
||||
table->ACPIState.levels[0].mclk.vDLL_CNTL = cpu_to_be32(dll_cntl);
|
||||
table->ACPIState.level.mclk.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
|
||||
table->ACPIState.level.mclk.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
|
||||
table->ACPIState.level.mclk.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
|
||||
table->ACPIState.level.mclk.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
|
||||
table->ACPIState.level.mclk.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
|
||||
table->ACPIState.level.mclk.vDLL_CNTL = cpu_to_be32(dll_cntl);
|
||||
|
||||
table->ACPIState.levels[0].mclk.mclk_value = 0;
|
||||
table->ACPIState.level.mclk.mclk_value = 0;
|
||||
|
||||
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
|
||||
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
|
||||
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
|
||||
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 = cpu_to_be32(spll_func_cntl_4);
|
||||
table->ACPIState.level.sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
|
||||
table->ACPIState.level.sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
|
||||
table->ACPIState.level.sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
|
||||
table->ACPIState.level.sclk.vCG_SPLL_FUNC_CNTL_4 = cpu_to_be32(spll_func_cntl_4);
|
||||
|
||||
table->ACPIState.levels[0].sclk.sclk_value = 0;
|
||||
table->ACPIState.level.sclk.sclk_value = 0;
|
||||
|
||||
ni_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
|
||||
ni_populate_mvdd_value(rdev, 0, &table->ACPIState.level.mvdd);
|
||||
|
||||
if (eg_pi->dynamic_ac_timing)
|
||||
table->ACPIState.levels[0].ACIndex = 1;
|
||||
table->ACPIState.level.ACIndex = 1;
|
||||
|
||||
table->ACPIState.levels[0].dpm2.MaxPS = 0;
|
||||
table->ACPIState.levels[0].dpm2.NearTDPDec = 0;
|
||||
table->ACPIState.levels[0].dpm2.AboveSafeInc = 0;
|
||||
table->ACPIState.levels[0].dpm2.BelowSafeInc = 0;
|
||||
table->ACPIState.level.dpm2.MaxPS = 0;
|
||||
table->ACPIState.level.dpm2.NearTDPDec = 0;
|
||||
table->ACPIState.level.dpm2.AboveSafeInc = 0;
|
||||
table->ACPIState.level.dpm2.BelowSafeInc = 0;
|
||||
|
||||
reg = MIN_POWER_MASK | MAX_POWER_MASK;
|
||||
table->ACPIState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
|
||||
table->ACPIState.level.SQPowerThrottle = cpu_to_be32(reg);
|
||||
|
||||
reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
|
||||
table->ACPIState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
|
||||
table->ACPIState.level.SQPowerThrottle_2 = cpu_to_be32(reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1980,7 +1980,9 @@ static int ni_init_smc_table(struct radeon_device *rdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
table->driverState = table->initialState;
|
||||
table->driverState.flags = table->initialState.flags;
|
||||
table->driverState.levelCount = table->initialState.levelCount;
|
||||
table->driverState.levels[0] = table->initialState.level;
|
||||
|
||||
table->ULVState = table->initialState;
|
||||
|
||||
|
||||
@@ -143,6 +143,14 @@ struct NISLANDS_SMC_SWSTATE
|
||||
|
||||
typedef struct NISLANDS_SMC_SWSTATE NISLANDS_SMC_SWSTATE;
|
||||
|
||||
struct NISLANDS_SMC_SWSTATE_SINGLE {
|
||||
uint8_t flags;
|
||||
uint8_t levelCount;
|
||||
uint8_t padding2;
|
||||
uint8_t padding3;
|
||||
NISLANDS_SMC_HW_PERFORMANCE_LEVEL level;
|
||||
};
|
||||
|
||||
#define NISLANDS_SMC_VOLTAGEMASK_VDDC 0
|
||||
#define NISLANDS_SMC_VOLTAGEMASK_MVDD 1
|
||||
#define NISLANDS_SMC_VOLTAGEMASK_VDDCI 2
|
||||
@@ -160,19 +168,19 @@ typedef struct NISLANDS_SMC_VOLTAGEMASKTABLE NISLANDS_SMC_VOLTAGEMASKTABLE;
|
||||
|
||||
struct NISLANDS_SMC_STATETABLE
|
||||
{
|
||||
uint8_t thermalProtectType;
|
||||
uint8_t systemFlags;
|
||||
uint8_t maxVDDCIndexInPPTable;
|
||||
uint8_t extraFlags;
|
||||
uint8_t highSMIO[NISLANDS_MAX_NO_VREG_STEPS];
|
||||
uint32_t lowSMIO[NISLANDS_MAX_NO_VREG_STEPS];
|
||||
NISLANDS_SMC_VOLTAGEMASKTABLE voltageMaskTable;
|
||||
PP_NIslands_DPM2Parameters dpm2Params;
|
||||
NISLANDS_SMC_SWSTATE initialState;
|
||||
NISLANDS_SMC_SWSTATE ACPIState;
|
||||
NISLANDS_SMC_SWSTATE ULVState;
|
||||
NISLANDS_SMC_SWSTATE driverState;
|
||||
NISLANDS_SMC_HW_PERFORMANCE_LEVEL dpmLevels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1];
|
||||
uint8_t thermalProtectType;
|
||||
uint8_t systemFlags;
|
||||
uint8_t maxVDDCIndexInPPTable;
|
||||
uint8_t extraFlags;
|
||||
uint8_t highSMIO[NISLANDS_MAX_NO_VREG_STEPS];
|
||||
uint32_t lowSMIO[NISLANDS_MAX_NO_VREG_STEPS];
|
||||
NISLANDS_SMC_VOLTAGEMASKTABLE voltageMaskTable;
|
||||
PP_NIslands_DPM2Parameters dpm2Params;
|
||||
struct NISLANDS_SMC_SWSTATE_SINGLE initialState;
|
||||
struct NISLANDS_SMC_SWSTATE_SINGLE ACPIState;
|
||||
struct NISLANDS_SMC_SWSTATE_SINGLE ULVState;
|
||||
NISLANDS_SMC_SWSTATE driverState;
|
||||
NISLANDS_SMC_HW_PERFORMANCE_LEVEL dpmLevels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
|
||||
};
|
||||
|
||||
typedef struct NISLANDS_SMC_STATETABLE NISLANDS_SMC_STATETABLE;
|
||||
|
||||
@@ -1549,6 +1549,7 @@ struct radeon_dpm {
|
||||
void *priv;
|
||||
u32 new_active_crtcs;
|
||||
int new_active_crtc_count;
|
||||
int high_pixelclock_count;
|
||||
u32 current_active_crtcs;
|
||||
int current_active_crtc_count;
|
||||
bool single_display;
|
||||
|
||||
@@ -1767,6 +1767,7 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
|
||||
struct drm_device *ddev = rdev->ddev;
|
||||
struct drm_crtc *crtc;
|
||||
struct radeon_crtc *radeon_crtc;
|
||||
struct radeon_connector *radeon_connector;
|
||||
|
||||
if (!rdev->pm.dpm_enabled)
|
||||
return;
|
||||
@@ -1776,6 +1777,7 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
|
||||
/* update active crtc counts */
|
||||
rdev->pm.dpm.new_active_crtcs = 0;
|
||||
rdev->pm.dpm.new_active_crtc_count = 0;
|
||||
rdev->pm.dpm.high_pixelclock_count = 0;
|
||||
if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) {
|
||||
list_for_each_entry(crtc,
|
||||
&ddev->mode_config.crtc_list, head) {
|
||||
@@ -1783,6 +1785,12 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
|
||||
if (crtc->enabled) {
|
||||
rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id);
|
||||
rdev->pm.dpm.new_active_crtc_count++;
|
||||
if (!radeon_crtc->connector)
|
||||
continue;
|
||||
|
||||
radeon_connector = to_radeon_connector(radeon_crtc->connector);
|
||||
if (radeon_connector->pixelclock_for_modeset > 297000)
|
||||
rdev->pm.dpm.high_pixelclock_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2979,6 +2979,9 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
|
||||
(rdev->pdev->device == 0x6605)) {
|
||||
max_sclk = 75000;
|
||||
}
|
||||
|
||||
if (rdev->pm.dpm.high_pixelclock_count > 1)
|
||||
disable_sclk_switching = true;
|
||||
}
|
||||
|
||||
if (rps->vce_active) {
|
||||
@@ -4350,70 +4353,70 @@ static int si_populate_smc_initial_state(struct radeon_device *rdev,
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
table->initialState.levels[0].mclk.vDLL_CNTL =
|
||||
table->initialState.level.mclk.vDLL_CNTL =
|
||||
cpu_to_be32(si_pi->clock_registers.dll_cntl);
|
||||
table->initialState.levels[0].mclk.vMCLK_PWRMGT_CNTL =
|
||||
table->initialState.level.mclk.vMCLK_PWRMGT_CNTL =
|
||||
cpu_to_be32(si_pi->clock_registers.mclk_pwrmgt_cntl);
|
||||
table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL =
|
||||
table->initialState.level.mclk.vMPLL_AD_FUNC_CNTL =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_ad_func_cntl);
|
||||
table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL =
|
||||
table->initialState.level.mclk.vMPLL_DQ_FUNC_CNTL =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_dq_func_cntl);
|
||||
table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL =
|
||||
table->initialState.level.mclk.vMPLL_FUNC_CNTL =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_func_cntl);
|
||||
table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL_1 =
|
||||
table->initialState.level.mclk.vMPLL_FUNC_CNTL_1 =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_func_cntl_1);
|
||||
table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL_2 =
|
||||
table->initialState.level.mclk.vMPLL_FUNC_CNTL_2 =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_func_cntl_2);
|
||||
table->initialState.levels[0].mclk.vMPLL_SS =
|
||||
table->initialState.level.mclk.vMPLL_SS =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_ss1);
|
||||
table->initialState.levels[0].mclk.vMPLL_SS2 =
|
||||
table->initialState.level.mclk.vMPLL_SS2 =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_ss2);
|
||||
|
||||
table->initialState.levels[0].mclk.mclk_value =
|
||||
table->initialState.level.mclk.mclk_value =
|
||||
cpu_to_be32(initial_state->performance_levels[0].mclk);
|
||||
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
|
||||
table->initialState.level.sclk.vCG_SPLL_FUNC_CNTL =
|
||||
cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
|
||||
table->initialState.level.sclk.vCG_SPLL_FUNC_CNTL_2 =
|
||||
cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_2);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
|
||||
table->initialState.level.sclk.vCG_SPLL_FUNC_CNTL_3 =
|
||||
cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_3);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 =
|
||||
table->initialState.level.sclk.vCG_SPLL_FUNC_CNTL_4 =
|
||||
cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_4);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
|
||||
table->initialState.level.sclk.vCG_SPLL_SPREAD_SPECTRUM =
|
||||
cpu_to_be32(si_pi->clock_registers.cg_spll_spread_spectrum);
|
||||
table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
|
||||
table->initialState.level.sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
|
||||
cpu_to_be32(si_pi->clock_registers.cg_spll_spread_spectrum_2);
|
||||
|
||||
table->initialState.levels[0].sclk.sclk_value =
|
||||
table->initialState.level.sclk.sclk_value =
|
||||
cpu_to_be32(initial_state->performance_levels[0].sclk);
|
||||
|
||||
table->initialState.levels[0].arbRefreshState =
|
||||
table->initialState.level.arbRefreshState =
|
||||
SISLANDS_INITIAL_STATE_ARB_INDEX;
|
||||
|
||||
table->initialState.levels[0].ACIndex = 0;
|
||||
table->initialState.level.ACIndex = 0;
|
||||
|
||||
ret = si_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
|
||||
initial_state->performance_levels[0].vddc,
|
||||
&table->initialState.levels[0].vddc);
|
||||
&table->initialState.level.vddc);
|
||||
|
||||
if (!ret) {
|
||||
u16 std_vddc;
|
||||
|
||||
ret = si_get_std_voltage_value(rdev,
|
||||
&table->initialState.levels[0].vddc,
|
||||
&table->initialState.level.vddc,
|
||||
&std_vddc);
|
||||
if (!ret)
|
||||
si_populate_std_voltage_value(rdev, std_vddc,
|
||||
table->initialState.levels[0].vddc.index,
|
||||
&table->initialState.levels[0].std_vddc);
|
||||
table->initialState.level.vddc.index,
|
||||
&table->initialState.level.std_vddc);
|
||||
}
|
||||
|
||||
if (eg_pi->vddci_control)
|
||||
si_populate_voltage_value(rdev,
|
||||
&eg_pi->vddci_voltage_table,
|
||||
initial_state->performance_levels[0].vddci,
|
||||
&table->initialState.levels[0].vddci);
|
||||
&table->initialState.level.vddci);
|
||||
|
||||
if (si_pi->vddc_phase_shed_control)
|
||||
si_populate_phase_shedding_value(rdev,
|
||||
@@ -4421,43 +4424,43 @@ static int si_populate_smc_initial_state(struct radeon_device *rdev,
|
||||
initial_state->performance_levels[0].vddc,
|
||||
initial_state->performance_levels[0].sclk,
|
||||
initial_state->performance_levels[0].mclk,
|
||||
&table->initialState.levels[0].vddc);
|
||||
&table->initialState.level.vddc);
|
||||
|
||||
si_populate_initial_mvdd_value(rdev, &table->initialState.levels[0].mvdd);
|
||||
si_populate_initial_mvdd_value(rdev, &table->initialState.level.mvdd);
|
||||
|
||||
reg = CG_R(0xffff) | CG_L(0);
|
||||
table->initialState.levels[0].aT = cpu_to_be32(reg);
|
||||
table->initialState.level.aT = cpu_to_be32(reg);
|
||||
|
||||
table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
|
||||
table->initialState.level.bSP = cpu_to_be32(pi->dsp);
|
||||
|
||||
table->initialState.levels[0].gen2PCIE = (u8)si_pi->boot_pcie_gen;
|
||||
table->initialState.level.gen2PCIE = (u8)si_pi->boot_pcie_gen;
|
||||
|
||||
if (pi->mem_gddr5) {
|
||||
table->initialState.levels[0].strobeMode =
|
||||
table->initialState.level.strobeMode =
|
||||
si_get_strobe_mode_settings(rdev,
|
||||
initial_state->performance_levels[0].mclk);
|
||||
|
||||
if (initial_state->performance_levels[0].mclk > pi->mclk_edc_enable_threshold)
|
||||
table->initialState.levels[0].mcFlags = SISLANDS_SMC_MC_EDC_RD_FLAG | SISLANDS_SMC_MC_EDC_WR_FLAG;
|
||||
table->initialState.level.mcFlags = SISLANDS_SMC_MC_EDC_RD_FLAG | SISLANDS_SMC_MC_EDC_WR_FLAG;
|
||||
else
|
||||
table->initialState.levels[0].mcFlags = 0;
|
||||
table->initialState.level.mcFlags = 0;
|
||||
}
|
||||
|
||||
table->initialState.levelCount = 1;
|
||||
|
||||
table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
|
||||
|
||||
table->initialState.levels[0].dpm2.MaxPS = 0;
|
||||
table->initialState.levels[0].dpm2.NearTDPDec = 0;
|
||||
table->initialState.levels[0].dpm2.AboveSafeInc = 0;
|
||||
table->initialState.levels[0].dpm2.BelowSafeInc = 0;
|
||||
table->initialState.levels[0].dpm2.PwrEfficiencyRatio = 0;
|
||||
table->initialState.level.dpm2.MaxPS = 0;
|
||||
table->initialState.level.dpm2.NearTDPDec = 0;
|
||||
table->initialState.level.dpm2.AboveSafeInc = 0;
|
||||
table->initialState.level.dpm2.BelowSafeInc = 0;
|
||||
table->initialState.level.dpm2.PwrEfficiencyRatio = 0;
|
||||
|
||||
reg = MIN_POWER_MASK | MAX_POWER_MASK;
|
||||
table->initialState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
|
||||
table->initialState.level.SQPowerThrottle = cpu_to_be32(reg);
|
||||
|
||||
reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
|
||||
table->initialState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
|
||||
table->initialState.level.SQPowerThrottle_2 = cpu_to_be32(reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4488,18 +4491,18 @@ static int si_populate_smc_acpi_state(struct radeon_device *rdev,
|
||||
|
||||
if (pi->acpi_vddc) {
|
||||
ret = si_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
|
||||
pi->acpi_vddc, &table->ACPIState.levels[0].vddc);
|
||||
pi->acpi_vddc, &table->ACPIState.level.vddc);
|
||||
if (!ret) {
|
||||
u16 std_vddc;
|
||||
|
||||
ret = si_get_std_voltage_value(rdev,
|
||||
&table->ACPIState.levels[0].vddc, &std_vddc);
|
||||
&table->ACPIState.level.vddc, &std_vddc);
|
||||
if (!ret)
|
||||
si_populate_std_voltage_value(rdev, std_vddc,
|
||||
table->ACPIState.levels[0].vddc.index,
|
||||
&table->ACPIState.levels[0].std_vddc);
|
||||
table->ACPIState.level.vddc.index,
|
||||
&table->ACPIState.level.std_vddc);
|
||||
}
|
||||
table->ACPIState.levels[0].gen2PCIE = si_pi->acpi_pcie_gen;
|
||||
table->ACPIState.level.gen2PCIE = si_pi->acpi_pcie_gen;
|
||||
|
||||
if (si_pi->vddc_phase_shed_control) {
|
||||
si_populate_phase_shedding_value(rdev,
|
||||
@@ -4507,23 +4510,23 @@ static int si_populate_smc_acpi_state(struct radeon_device *rdev,
|
||||
pi->acpi_vddc,
|
||||
0,
|
||||
0,
|
||||
&table->ACPIState.levels[0].vddc);
|
||||
&table->ACPIState.level.vddc);
|
||||
}
|
||||
} else {
|
||||
ret = si_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
|
||||
pi->min_vddc_in_table, &table->ACPIState.levels[0].vddc);
|
||||
pi->min_vddc_in_table, &table->ACPIState.level.vddc);
|
||||
if (!ret) {
|
||||
u16 std_vddc;
|
||||
|
||||
ret = si_get_std_voltage_value(rdev,
|
||||
&table->ACPIState.levels[0].vddc, &std_vddc);
|
||||
&table->ACPIState.level.vddc, &std_vddc);
|
||||
|
||||
if (!ret)
|
||||
si_populate_std_voltage_value(rdev, std_vddc,
|
||||
table->ACPIState.levels[0].vddc.index,
|
||||
&table->ACPIState.levels[0].std_vddc);
|
||||
table->ACPIState.level.vddc.index,
|
||||
&table->ACPIState.level.std_vddc);
|
||||
}
|
||||
table->ACPIState.levels[0].gen2PCIE = (u8)r600_get_pcie_gen_support(rdev,
|
||||
table->ACPIState.level.gen2PCIE = (u8)r600_get_pcie_gen_support(rdev,
|
||||
si_pi->sys_pcie_mask,
|
||||
si_pi->boot_pcie_gen,
|
||||
RADEON_PCIE_GEN1);
|
||||
@@ -4534,14 +4537,14 @@ static int si_populate_smc_acpi_state(struct radeon_device *rdev,
|
||||
pi->min_vddc_in_table,
|
||||
0,
|
||||
0,
|
||||
&table->ACPIState.levels[0].vddc);
|
||||
&table->ACPIState.level.vddc);
|
||||
}
|
||||
|
||||
if (pi->acpi_vddc) {
|
||||
if (eg_pi->acpi_vddci)
|
||||
si_populate_voltage_value(rdev, &eg_pi->vddci_voltage_table,
|
||||
eg_pi->acpi_vddci,
|
||||
&table->ACPIState.levels[0].vddci);
|
||||
&table->ACPIState.level.vddci);
|
||||
}
|
||||
|
||||
mclk_pwrmgt_cntl |= MRDCK0_RESET | MRDCK1_RESET;
|
||||
@@ -4552,59 +4555,59 @@ static int si_populate_smc_acpi_state(struct radeon_device *rdev,
|
||||
spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
|
||||
spll_func_cntl_2 |= SCLK_MUX_SEL(4);
|
||||
|
||||
table->ACPIState.levels[0].mclk.vDLL_CNTL =
|
||||
table->ACPIState.level.mclk.vDLL_CNTL =
|
||||
cpu_to_be32(dll_cntl);
|
||||
table->ACPIState.levels[0].mclk.vMCLK_PWRMGT_CNTL =
|
||||
table->ACPIState.level.mclk.vMCLK_PWRMGT_CNTL =
|
||||
cpu_to_be32(mclk_pwrmgt_cntl);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL =
|
||||
table->ACPIState.level.mclk.vMPLL_AD_FUNC_CNTL =
|
||||
cpu_to_be32(mpll_ad_func_cntl);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL =
|
||||
table->ACPIState.level.mclk.vMPLL_DQ_FUNC_CNTL =
|
||||
cpu_to_be32(mpll_dq_func_cntl);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL =
|
||||
table->ACPIState.level.mclk.vMPLL_FUNC_CNTL =
|
||||
cpu_to_be32(mpll_func_cntl);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL_1 =
|
||||
table->ACPIState.level.mclk.vMPLL_FUNC_CNTL_1 =
|
||||
cpu_to_be32(mpll_func_cntl_1);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL_2 =
|
||||
table->ACPIState.level.mclk.vMPLL_FUNC_CNTL_2 =
|
||||
cpu_to_be32(mpll_func_cntl_2);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_SS =
|
||||
table->ACPIState.level.mclk.vMPLL_SS =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_ss1);
|
||||
table->ACPIState.levels[0].mclk.vMPLL_SS2 =
|
||||
table->ACPIState.level.mclk.vMPLL_SS2 =
|
||||
cpu_to_be32(si_pi->clock_registers.mpll_ss2);
|
||||
|
||||
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
|
||||
table->ACPIState.level.sclk.vCG_SPLL_FUNC_CNTL =
|
||||
cpu_to_be32(spll_func_cntl);
|
||||
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
|
||||
table->ACPIState.level.sclk.vCG_SPLL_FUNC_CNTL_2 =
|
||||
cpu_to_be32(spll_func_cntl_2);
|
||||
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
|
||||
table->ACPIState.level.sclk.vCG_SPLL_FUNC_CNTL_3 =
|
||||
cpu_to_be32(spll_func_cntl_3);
|
||||
table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 =
|
||||
table->ACPIState.level.sclk.vCG_SPLL_FUNC_CNTL_4 =
|
||||
cpu_to_be32(spll_func_cntl_4);
|
||||
|
||||
table->ACPIState.levels[0].mclk.mclk_value = 0;
|
||||
table->ACPIState.levels[0].sclk.sclk_value = 0;
|
||||
table->ACPIState.level.mclk.mclk_value = 0;
|
||||
table->ACPIState.level.sclk.sclk_value = 0;
|
||||
|
||||
si_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
|
||||
si_populate_mvdd_value(rdev, 0, &table->ACPIState.level.mvdd);
|
||||
|
||||
if (eg_pi->dynamic_ac_timing)
|
||||
table->ACPIState.levels[0].ACIndex = 0;
|
||||
table->ACPIState.level.ACIndex = 0;
|
||||
|
||||
table->ACPIState.levels[0].dpm2.MaxPS = 0;
|
||||
table->ACPIState.levels[0].dpm2.NearTDPDec = 0;
|
||||
table->ACPIState.levels[0].dpm2.AboveSafeInc = 0;
|
||||
table->ACPIState.levels[0].dpm2.BelowSafeInc = 0;
|
||||
table->ACPIState.levels[0].dpm2.PwrEfficiencyRatio = 0;
|
||||
table->ACPIState.level.dpm2.MaxPS = 0;
|
||||
table->ACPIState.level.dpm2.NearTDPDec = 0;
|
||||
table->ACPIState.level.dpm2.AboveSafeInc = 0;
|
||||
table->ACPIState.level.dpm2.BelowSafeInc = 0;
|
||||
table->ACPIState.level.dpm2.PwrEfficiencyRatio = 0;
|
||||
|
||||
reg = MIN_POWER_MASK | MAX_POWER_MASK;
|
||||
table->ACPIState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
|
||||
table->ACPIState.level.SQPowerThrottle = cpu_to_be32(reg);
|
||||
|
||||
reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
|
||||
table->ACPIState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
|
||||
table->ACPIState.level.SQPowerThrottle_2 = cpu_to_be32(reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si_populate_ulv_state(struct radeon_device *rdev,
|
||||
SISLANDS_SMC_SWSTATE *state)
|
||||
struct SISLANDS_SMC_SWSTATE_SINGLE *state)
|
||||
{
|
||||
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
|
||||
struct si_power_info *si_pi = si_get_pi(rdev);
|
||||
@@ -4613,19 +4616,19 @@ static int si_populate_ulv_state(struct radeon_device *rdev,
|
||||
int ret;
|
||||
|
||||
ret = si_convert_power_level_to_smc(rdev, &ulv->pl,
|
||||
&state->levels[0]);
|
||||
&state->level);
|
||||
if (!ret) {
|
||||
if (eg_pi->sclk_deep_sleep) {
|
||||
if (sclk_in_sr <= SCLK_MIN_DEEPSLEEP_FREQ)
|
||||
state->levels[0].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_BYPASS;
|
||||
state->level.stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_BYPASS;
|
||||
else
|
||||
state->levels[0].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE;
|
||||
state->level.stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE;
|
||||
}
|
||||
if (ulv->one_pcie_lane_in_ulv)
|
||||
state->flags |= PPSMC_SWSTATE_FLAG_PCIE_X1;
|
||||
state->levels[0].arbRefreshState = (u8)(SISLANDS_ULV_STATE_ARB_INDEX);
|
||||
state->levels[0].ACIndex = 1;
|
||||
state->levels[0].std_vddc = state->levels[0].vddc;
|
||||
state->level.arbRefreshState = (u8)(SISLANDS_ULV_STATE_ARB_INDEX);
|
||||
state->level.ACIndex = 1;
|
||||
state->level.std_vddc = state->level.vddc;
|
||||
state->levelCount = 1;
|
||||
|
||||
state->flags |= PPSMC_SWSTATE_FLAG_DC;
|
||||
@@ -4725,7 +4728,9 @@ static int si_init_smc_table(struct radeon_device *rdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
table->driverState = table->initialState;
|
||||
table->driverState.flags = table->initialState.flags;
|
||||
table->driverState.levelCount = table->initialState.levelCount;
|
||||
table->driverState.levels[0] = table->initialState.level;
|
||||
|
||||
ret = si_do_program_memory_timing_parameters(rdev, radeon_boot_state,
|
||||
SISLANDS_INITIAL_STATE_ARB_INDEX);
|
||||
@@ -5275,8 +5280,8 @@ static int si_upload_ulv_state(struct radeon_device *rdev)
|
||||
if (ulv->supported && ulv->pl.vddc) {
|
||||
u32 address = si_pi->state_table_start +
|
||||
offsetof(SISLANDS_SMC_STATETABLE, ULVState);
|
||||
SISLANDS_SMC_SWSTATE *smc_state = &si_pi->smc_statetable.ULVState;
|
||||
u32 state_size = sizeof(SISLANDS_SMC_SWSTATE);
|
||||
struct SISLANDS_SMC_SWSTATE_SINGLE *smc_state = &si_pi->smc_statetable.ULVState;
|
||||
u32 state_size = sizeof(struct SISLANDS_SMC_SWSTATE_SINGLE);
|
||||
|
||||
memset(smc_state, 0, state_size);
|
||||
|
||||
|
||||
@@ -191,6 +191,14 @@ struct SISLANDS_SMC_SWSTATE
|
||||
|
||||
typedef struct SISLANDS_SMC_SWSTATE SISLANDS_SMC_SWSTATE;
|
||||
|
||||
struct SISLANDS_SMC_SWSTATE_SINGLE {
|
||||
uint8_t flags;
|
||||
uint8_t levelCount;
|
||||
uint8_t padding2;
|
||||
uint8_t padding3;
|
||||
SISLANDS_SMC_HW_PERFORMANCE_LEVEL level;
|
||||
};
|
||||
|
||||
#define SISLANDS_SMC_VOLTAGEMASK_VDDC 0
|
||||
#define SISLANDS_SMC_VOLTAGEMASK_MVDD 1
|
||||
#define SISLANDS_SMC_VOLTAGEMASK_VDDCI 2
|
||||
@@ -208,19 +216,19 @@ typedef struct SISLANDS_SMC_VOLTAGEMASKTABLE SISLANDS_SMC_VOLTAGEMASKTABLE;
|
||||
|
||||
struct SISLANDS_SMC_STATETABLE
|
||||
{
|
||||
uint8_t thermalProtectType;
|
||||
uint8_t systemFlags;
|
||||
uint8_t maxVDDCIndexInPPTable;
|
||||
uint8_t extraFlags;
|
||||
uint32_t lowSMIO[SISLANDS_MAX_NO_VREG_STEPS];
|
||||
SISLANDS_SMC_VOLTAGEMASKTABLE voltageMaskTable;
|
||||
SISLANDS_SMC_VOLTAGEMASKTABLE phaseMaskTable;
|
||||
PP_SIslands_DPM2Parameters dpm2Params;
|
||||
SISLANDS_SMC_SWSTATE initialState;
|
||||
SISLANDS_SMC_SWSTATE ACPIState;
|
||||
SISLANDS_SMC_SWSTATE ULVState;
|
||||
SISLANDS_SMC_SWSTATE driverState;
|
||||
SISLANDS_SMC_HW_PERFORMANCE_LEVEL dpmLevels[SISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1];
|
||||
uint8_t thermalProtectType;
|
||||
uint8_t systemFlags;
|
||||
uint8_t maxVDDCIndexInPPTable;
|
||||
uint8_t extraFlags;
|
||||
uint32_t lowSMIO[SISLANDS_MAX_NO_VREG_STEPS];
|
||||
SISLANDS_SMC_VOLTAGEMASKTABLE voltageMaskTable;
|
||||
SISLANDS_SMC_VOLTAGEMASKTABLE phaseMaskTable;
|
||||
PP_SIslands_DPM2Parameters dpm2Params;
|
||||
struct SISLANDS_SMC_SWSTATE_SINGLE initialState;
|
||||
struct SISLANDS_SMC_SWSTATE_SINGLE ACPIState;
|
||||
struct SISLANDS_SMC_SWSTATE_SINGLE ULVState;
|
||||
SISLANDS_SMC_SWSTATE driverState;
|
||||
SISLANDS_SMC_HW_PERFORMANCE_LEVEL dpmLevels[SISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
|
||||
};
|
||||
|
||||
typedef struct SISLANDS_SMC_STATETABLE SISLANDS_SMC_STATETABLE;
|
||||
|
||||
@@ -197,12 +197,6 @@ struct vc4_vec_connector {
|
||||
struct drm_encoder *encoder;
|
||||
};
|
||||
|
||||
static inline struct vc4_vec_connector *
|
||||
to_vc4_vec_connector(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(connector, struct vc4_vec_connector, base);
|
||||
}
|
||||
|
||||
enum vc4_vec_tv_mode_id {
|
||||
VC4_VEC_TV_MODE_NTSC,
|
||||
VC4_VEC_TV_MODE_NTSC_J,
|
||||
|
||||
@@ -485,7 +485,7 @@ static int adm9240_in_write(struct device *dev, u32 attr, int channel, long val)
|
||||
reg = ADM9240_REG_IN_MIN(channel);
|
||||
break;
|
||||
case hwmon_in_max:
|
||||
reg = ADM9240_REG_IN(channel);
|
||||
reg = ADM9240_REG_IN_MAX(channel);
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@@ -355,7 +355,7 @@ static umode_t corsairpsu_hwmon_power_is_visible(const struct corsairpsu_data *p
|
||||
return 0444;
|
||||
default:
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static umode_t corsairpsu_hwmon_in_is_visible(const struct corsairpsu_data *priv, u32 attr,
|
||||
@@ -376,7 +376,7 @@ static umode_t corsairpsu_hwmon_in_is_visible(const struct corsairpsu_data *priv
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -900,11 +900,15 @@ static int ltc2992_parse_dt(struct ltc2992_state *st)
|
||||
|
||||
fwnode_for_each_available_child_node(fwnode, child) {
|
||||
ret = fwnode_property_read_u32(child, "reg", &addr);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
fwnode_handle_put(child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (addr > 1)
|
||||
if (addr > 1) {
|
||||
fwnode_handle_put(child);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = fwnode_property_read_u32(child, "shunt-resistor-micro-ohms", &val);
|
||||
if (!ret)
|
||||
|
||||
@@ -217,9 +217,9 @@ int occ_update_response(struct occ *occ)
|
||||
return rc;
|
||||
|
||||
/* limit the maximum rate of polling the OCC */
|
||||
if (time_after(jiffies, occ->last_update + OCC_UPDATE_FREQUENCY)) {
|
||||
if (time_after(jiffies, occ->next_update)) {
|
||||
rc = occ_poll(occ);
|
||||
occ->last_update = jiffies;
|
||||
occ->next_update = jiffies + OCC_UPDATE_FREQUENCY;
|
||||
} else {
|
||||
rc = occ->last_error;
|
||||
}
|
||||
@@ -1165,6 +1165,7 @@ int occ_setup(struct occ *occ, const char *name)
|
||||
return rc;
|
||||
}
|
||||
|
||||
occ->next_update = jiffies + OCC_UPDATE_FREQUENCY;
|
||||
occ_parse_poll_response(occ);
|
||||
|
||||
rc = occ_setup_sensor_attrs(occ);
|
||||
|
||||
@@ -99,7 +99,7 @@ struct occ {
|
||||
u8 poll_cmd_data; /* to perform OCC poll command */
|
||||
int (*send_cmd)(struct occ *occ, u8 *cmd);
|
||||
|
||||
unsigned long last_update;
|
||||
unsigned long next_update;
|
||||
struct mutex lock; /* lock OCC access */
|
||||
|
||||
struct device *hwmon;
|
||||
|
||||
@@ -57,7 +57,7 @@ static int page_log_to_page_real(int page_log, enum chips chip)
|
||||
case YH5151E_PAGE_12V_LOG:
|
||||
return YH5151E_PAGE_12V_REAL;
|
||||
case YH5151E_PAGE_5V_LOG:
|
||||
return YH5151E_PAGE_5V_LOG;
|
||||
return YH5151E_PAGE_5V_REAL;
|
||||
case YH5151E_PAGE_3V3_LOG:
|
||||
return YH5151E_PAGE_3V3_REAL;
|
||||
}
|
||||
@@ -103,8 +103,18 @@ static int set_page(struct i2c_client *client, int page_log)
|
||||
|
||||
static int fsp3y_read_byte_data(struct i2c_client *client, int page, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
struct fsp3y_data *data = to_fsp3y_data(info);
|
||||
int rv;
|
||||
|
||||
/*
|
||||
* YH5151-E outputs vout in linear11. The conversion is done when
|
||||
* reading. Here, we have to inject pmbus_core with the correct
|
||||
* exponent (it is -6).
|
||||
*/
|
||||
if (data->chip == yh5151e && reg == PMBUS_VOUT_MODE)
|
||||
return 0x1A;
|
||||
|
||||
rv = set_page(client, page);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
@@ -114,6 +124,8 @@ static int fsp3y_read_byte_data(struct i2c_client *client, int page, int reg)
|
||||
|
||||
static int fsp3y_read_word_data(struct i2c_client *client, int page, int phase, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
struct fsp3y_data *data = to_fsp3y_data(info);
|
||||
int rv;
|
||||
|
||||
/*
|
||||
@@ -144,7 +156,18 @@ static int fsp3y_read_word_data(struct i2c_client *client, int page, int phase,
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
return i2c_smbus_read_word_data(client, reg);
|
||||
rv = i2c_smbus_read_word_data(client, reg);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
/*
|
||||
* YH-5151E is non-compliant and outputs output voltages in linear11
|
||||
* instead of linear16.
|
||||
*/
|
||||
if (data->chip == yh5151e && reg == PMBUS_READ_VOUT)
|
||||
rv = sign_extend32(rv, 10) & 0xffff;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static struct pmbus_driver_info fsp3y_info[] = {
|
||||
|
||||
@@ -671,21 +671,58 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs)
|
||||
if (copy_from_user(&v, cs, sizeof(struct vt_consize)))
|
||||
return -EFAULT;
|
||||
|
||||
if (v.v_vlin)
|
||||
pr_info_once("\"struct vt_consize\"->v_vlin is ignored. Please report if you need this.\n");
|
||||
if (v.v_clin)
|
||||
pr_info_once("\"struct vt_consize\"->v_clin is ignored. Please report if you need this.\n");
|
||||
/* FIXME: Should check the copies properly */
|
||||
if (!v.v_vlin)
|
||||
v.v_vlin = vc->vc_scan_lines;
|
||||
|
||||
console_lock();
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++) {
|
||||
vc = vc_cons[i].d;
|
||||
|
||||
if (vc) {
|
||||
vc->vc_resize_user = 1;
|
||||
vc_resize(vc, v.v_cols, v.v_rows);
|
||||
if (v.v_clin) {
|
||||
int rows = v.v_vlin / v.v_clin;
|
||||
if (v.v_rows != rows) {
|
||||
if (v.v_rows) /* Parameters don't add up */
|
||||
return -EINVAL;
|
||||
v.v_rows = rows;
|
||||
}
|
||||
}
|
||||
console_unlock();
|
||||
|
||||
if (v.v_vcol && v.v_ccol) {
|
||||
int cols = v.v_vcol / v.v_ccol;
|
||||
if (v.v_cols != cols) {
|
||||
if (v.v_cols)
|
||||
return -EINVAL;
|
||||
v.v_cols = cols;
|
||||
}
|
||||
}
|
||||
|
||||
if (v.v_clin > 32)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++) {
|
||||
struct vc_data *vcp;
|
||||
|
||||
if (!vc_cons[i].d)
|
||||
continue;
|
||||
console_lock();
|
||||
vcp = vc_cons[i].d;
|
||||
if (vcp) {
|
||||
int ret;
|
||||
int save_scan_lines = vcp->vc_scan_lines;
|
||||
int save_cell_height = vcp->vc_cell_height;
|
||||
|
||||
if (v.v_vlin)
|
||||
vcp->vc_scan_lines = v.v_vlin;
|
||||
if (v.v_clin)
|
||||
vcp->vc_cell_height = v.v_clin;
|
||||
vcp->vc_resize_user = 1;
|
||||
ret = vc_resize(vcp, v.v_cols, v.v_rows);
|
||||
if (ret) {
|
||||
vcp->vc_scan_lines = save_scan_lines;
|
||||
vcp->vc_cell_height = save_cell_height;
|
||||
console_unlock();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
console_unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -380,7 +380,7 @@ static void vgacon_init(struct vc_data *c, int init)
|
||||
vc_resize(c, vga_video_num_columns, vga_video_num_lines);
|
||||
|
||||
c->vc_scan_lines = vga_scan_lines;
|
||||
c->vc_font.height = vga_video_font_height;
|
||||
c->vc_font.height = c->vc_cell_height = vga_video_font_height;
|
||||
c->vc_complement_mask = 0x7700;
|
||||
if (vga_512_chars)
|
||||
c->vc_hi_font_mask = 0x0800;
|
||||
@@ -515,32 +515,32 @@ static void vgacon_cursor(struct vc_data *c, int mode)
|
||||
switch (CUR_SIZE(c->vc_cursor_type)) {
|
||||
case CUR_UNDERLINE:
|
||||
vgacon_set_cursor_size(c->state.x,
|
||||
c->vc_font.height -
|
||||
(c->vc_font.height <
|
||||
c->vc_cell_height -
|
||||
(c->vc_cell_height <
|
||||
10 ? 2 : 3),
|
||||
c->vc_font.height -
|
||||
(c->vc_font.height <
|
||||
c->vc_cell_height -
|
||||
(c->vc_cell_height <
|
||||
10 ? 1 : 2));
|
||||
break;
|
||||
case CUR_TWO_THIRDS:
|
||||
vgacon_set_cursor_size(c->state.x,
|
||||
c->vc_font.height / 3,
|
||||
c->vc_font.height -
|
||||
(c->vc_font.height <
|
||||
c->vc_cell_height / 3,
|
||||
c->vc_cell_height -
|
||||
(c->vc_cell_height <
|
||||
10 ? 1 : 2));
|
||||
break;
|
||||
case CUR_LOWER_THIRD:
|
||||
vgacon_set_cursor_size(c->state.x,
|
||||
(c->vc_font.height * 2) / 3,
|
||||
c->vc_font.height -
|
||||
(c->vc_font.height <
|
||||
(c->vc_cell_height * 2) / 3,
|
||||
c->vc_cell_height -
|
||||
(c->vc_cell_height <
|
||||
10 ? 1 : 2));
|
||||
break;
|
||||
case CUR_LOWER_HALF:
|
||||
vgacon_set_cursor_size(c->state.x,
|
||||
c->vc_font.height / 2,
|
||||
c->vc_font.height -
|
||||
(c->vc_font.height <
|
||||
c->vc_cell_height / 2,
|
||||
c->vc_cell_height -
|
||||
(c->vc_cell_height <
|
||||
10 ? 1 : 2));
|
||||
break;
|
||||
case CUR_NONE:
|
||||
@@ -551,7 +551,7 @@ static void vgacon_cursor(struct vc_data *c, int mode)
|
||||
break;
|
||||
default:
|
||||
vgacon_set_cursor_size(c->state.x, 1,
|
||||
c->vc_font.height);
|
||||
c->vc_cell_height);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -562,13 +562,13 @@ static int vgacon_doresize(struct vc_data *c,
|
||||
unsigned int width, unsigned int height)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int scanlines = height * c->vc_font.height;
|
||||
unsigned int scanlines = height * c->vc_cell_height;
|
||||
u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
|
||||
|
||||
raw_spin_lock_irqsave(&vga_lock, flags);
|
||||
|
||||
vgacon_xres = width * VGA_FONTWIDTH;
|
||||
vgacon_yres = height * c->vc_font.height;
|
||||
vgacon_yres = height * c->vc_cell_height;
|
||||
if (vga_video_type >= VIDEO_TYPE_VGAC) {
|
||||
outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
|
||||
max_scan = inb_p(vga_video_port_val);
|
||||
@@ -623,9 +623,9 @@ static int vgacon_doresize(struct vc_data *c,
|
||||
static int vgacon_switch(struct vc_data *c)
|
||||
{
|
||||
int x = c->vc_cols * VGA_FONTWIDTH;
|
||||
int y = c->vc_rows * c->vc_font.height;
|
||||
int y = c->vc_rows * c->vc_cell_height;
|
||||
int rows = screen_info.orig_video_lines * vga_default_font_height/
|
||||
c->vc_font.height;
|
||||
c->vc_cell_height;
|
||||
/*
|
||||
* We need to save screen size here as it's the only way
|
||||
* we can spot the screen has been resized and we need to
|
||||
@@ -1038,7 +1038,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
|
||||
cursor_size_lastto = 0;
|
||||
c->vc_sw->con_cursor(c, CM_DRAW);
|
||||
}
|
||||
c->vc_font.height = fontheight;
|
||||
c->vc_font.height = c->vc_cell_height = fontheight;
|
||||
vc_resize(c, 0, rows); /* Adjust console size */
|
||||
}
|
||||
}
|
||||
@@ -1086,12 +1086,20 @@ static int vgacon_resize(struct vc_data *c, unsigned int width,
|
||||
if ((width << 1) * height > vga_vram_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (user) {
|
||||
/*
|
||||
* Ho ho! Someone (svgatextmode, eh?) may have reprogrammed
|
||||
* the video mode! Set the new defaults then and go away.
|
||||
*/
|
||||
screen_info.orig_video_cols = width;
|
||||
screen_info.orig_video_lines = height;
|
||||
vga_default_font_height = c->vc_cell_height;
|
||||
return 0;
|
||||
}
|
||||
if (width % 2 || width > screen_info.orig_video_cols ||
|
||||
height > (screen_info.orig_video_lines * vga_default_font_height)/
|
||||
c->vc_font.height)
|
||||
/* let svgatextmode tinker with video timings and
|
||||
return success */
|
||||
return (user) ? 0 : -EINVAL;
|
||||
c->vc_cell_height)
|
||||
return -EINVAL;
|
||||
|
||||
if (con_is_visible(c) && !vga_is_gfx) /* who knows */
|
||||
vgacon_doresize(c, width, height);
|
||||
|
||||
@@ -3127,7 +3127,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_inode *inode, u64 new_size,
|
||||
u32 min_type);
|
||||
|
||||
int btrfs_start_delalloc_snapshot(struct btrfs_root *root);
|
||||
int btrfs_start_delalloc_snapshot(struct btrfs_root *root, bool in_reclaim_context);
|
||||
int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
|
||||
bool in_reclaim_context);
|
||||
int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
|
||||
|
||||
@@ -1340,12 +1340,16 @@ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
|
||||
stripe = bbio->stripes;
|
||||
for (i = 0; i < bbio->num_stripes; i++, stripe++) {
|
||||
u64 bytes;
|
||||
struct btrfs_device *device = stripe->dev;
|
||||
|
||||
if (!stripe->dev->bdev) {
|
||||
if (!device->bdev) {
|
||||
ASSERT(btrfs_test_opt(fs_info, DEGRADED));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state))
|
||||
continue;
|
||||
|
||||
ret = do_discard_extent(stripe, &bytes);
|
||||
if (!ret) {
|
||||
discarded_bytes += bytes;
|
||||
|
||||
@@ -2067,6 +2067,30 @@ static int start_ordered_ops(struct inode *inode, loff_t start, loff_t end)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline bool skip_inode_logging(const struct btrfs_log_ctx *ctx)
|
||||
{
|
||||
struct btrfs_inode *inode = BTRFS_I(ctx->inode);
|
||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||
|
||||
if (btrfs_inode_in_log(inode, fs_info->generation) &&
|
||||
list_empty(&ctx->ordered_extents))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* If we are doing a fast fsync we can not bail out if the inode's
|
||||
* last_trans is <= then the last committed transaction, because we only
|
||||
* update the last_trans of the inode during ordered extent completion,
|
||||
* and for a fast fsync we don't wait for that, we only wait for the
|
||||
* writeback to complete.
|
||||
*/
|
||||
if (inode->last_trans <= fs_info->last_trans_committed &&
|
||||
(test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &inode->runtime_flags) ||
|
||||
list_empty(&ctx->ordered_extents)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* fsync call for both files and directories. This logs the inode into
|
||||
* the tree log instead of forcing full commits whenever possible.
|
||||
@@ -2185,17 +2209,8 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
|
||||
atomic_inc(&root->log_batch);
|
||||
|
||||
/*
|
||||
* If we are doing a fast fsync we can not bail out if the inode's
|
||||
* last_trans is <= then the last committed transaction, because we only
|
||||
* update the last_trans of the inode during ordered extent completion,
|
||||
* and for a fast fsync we don't wait for that, we only wait for the
|
||||
* writeback to complete.
|
||||
*/
|
||||
smp_mb();
|
||||
if (btrfs_inode_in_log(BTRFS_I(inode), fs_info->generation) ||
|
||||
(BTRFS_I(inode)->last_trans <= fs_info->last_trans_committed &&
|
||||
(full_sync || list_empty(&ctx.ordered_extents)))) {
|
||||
if (skip_inode_logging(&ctx)) {
|
||||
/*
|
||||
* We've had everything committed since the last time we were
|
||||
* modified so clear this flag in case it was set for whatever
|
||||
|
||||
@@ -3949,7 +3949,7 @@ static int cleanup_free_space_cache_v1(struct btrfs_fs_info *fs_info,
|
||||
{
|
||||
struct btrfs_block_group *block_group;
|
||||
struct rb_node *node;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
btrfs_info(fs_info, "cleaning free space cache v1");
|
||||
|
||||
|
||||
@@ -9678,7 +9678,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_start_delalloc_snapshot(struct btrfs_root *root)
|
||||
int btrfs_start_delalloc_snapshot(struct btrfs_root *root, bool in_reclaim_context)
|
||||
{
|
||||
struct writeback_control wbc = {
|
||||
.nr_to_write = LONG_MAX,
|
||||
@@ -9691,7 +9691,7 @@ int btrfs_start_delalloc_snapshot(struct btrfs_root *root)
|
||||
if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
|
||||
return -EROFS;
|
||||
|
||||
return start_delalloc_inodes(root, &wbc, true, false);
|
||||
return start_delalloc_inodes(root, &wbc, true, in_reclaim_context);
|
||||
}
|
||||
|
||||
int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
|
||||
|
||||
@@ -259,6 +259,8 @@ int btrfs_fileattr_set(struct user_namespace *mnt_userns,
|
||||
if (!fa->flags_valid) {
|
||||
/* 1 item for the inode */
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
if (IS_ERR(trans))
|
||||
return PTR_ERR(trans);
|
||||
goto update_flags;
|
||||
}
|
||||
|
||||
@@ -907,7 +909,7 @@ static noinline int btrfs_mksnapshot(const struct path *parent,
|
||||
*/
|
||||
btrfs_drew_read_lock(&root->snapshot_lock);
|
||||
|
||||
ret = btrfs_start_delalloc_snapshot(root);
|
||||
ret = btrfs_start_delalloc_snapshot(root, false);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -984,7 +984,7 @@ int btrfs_split_ordered_extent(struct btrfs_ordered_extent *ordered, u64 pre,
|
||||
|
||||
if (pre)
|
||||
ret = clone_ordered_extent(ordered, 0, pre);
|
||||
if (post)
|
||||
if (ret == 0 && post)
|
||||
ret = clone_ordered_extent(ordered, pre + ordered->disk_num_bytes,
|
||||
post);
|
||||
|
||||
|
||||
@@ -3545,11 +3545,15 @@ static int try_flush_qgroup(struct btrfs_root *root)
|
||||
struct btrfs_trans_handle *trans;
|
||||
int ret;
|
||||
|
||||
/* Can't hold an open transaction or we run the risk of deadlocking */
|
||||
ASSERT(current->journal_info == NULL ||
|
||||
current->journal_info == BTRFS_SEND_TRANS_STUB);
|
||||
if (WARN_ON(current->journal_info &&
|
||||
current->journal_info != BTRFS_SEND_TRANS_STUB))
|
||||
/*
|
||||
* Can't hold an open transaction or we run the risk of deadlocking,
|
||||
* and can't either be under the context of a send operation (where
|
||||
* current->journal_info is set to BTRFS_SEND_TRANS_STUB), as that
|
||||
* would result in a crash when starting a transaction and does not
|
||||
* make sense either (send is a read-only operation).
|
||||
*/
|
||||
ASSERT(current->journal_info == NULL);
|
||||
if (WARN_ON(current->journal_info))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@@ -3562,7 +3566,7 @@ static int try_flush_qgroup(struct btrfs_root *root)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = btrfs_start_delalloc_snapshot(root);
|
||||
ret = btrfs_start_delalloc_snapshot(root, true);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
|
||||
|
||||
@@ -7170,7 +7170,7 @@ static int flush_delalloc_roots(struct send_ctx *sctx)
|
||||
int i;
|
||||
|
||||
if (root) {
|
||||
ret = btrfs_start_delalloc_snapshot(root);
|
||||
ret = btrfs_start_delalloc_snapshot(root, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
btrfs_wait_ordered_extents(root, U64_MAX, 0, U64_MAX);
|
||||
@@ -7178,7 +7178,7 @@ static int flush_delalloc_roots(struct send_ctx *sctx)
|
||||
|
||||
for (i = 0; i < sctx->clone_roots_cnt; i++) {
|
||||
root = sctx->clone_roots[i].root;
|
||||
ret = btrfs_start_delalloc_snapshot(root);
|
||||
ret = btrfs_start_delalloc_snapshot(root, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
btrfs_wait_ordered_extents(root, U64_MAX, 0, U64_MAX);
|
||||
|
||||
@@ -6061,7 +6061,8 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
|
||||
* (since logging them is pointless, a link count of 0 means they
|
||||
* will never be accessible).
|
||||
*/
|
||||
if (btrfs_inode_in_log(inode, trans->transid) ||
|
||||
if ((btrfs_inode_in_log(inode, trans->transid) &&
|
||||
list_empty(&ctx->ordered_extents)) ||
|
||||
inode->vfs_inode.i_nlink == 0) {
|
||||
ret = BTRFS_NO_LOG_SYNC;
|
||||
goto end_no_trans;
|
||||
|
||||
@@ -1126,6 +1126,11 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (zone.type == BLK_ZONE_TYPE_CONVENTIONAL) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (zone.cond) {
|
||||
case BLK_ZONE_COND_OFFLINE:
|
||||
case BLK_ZONE_COND_READONLY:
|
||||
|
||||
@@ -117,19 +117,6 @@ static void f2fs_unlock_rpages(struct compress_ctx *cc, int len)
|
||||
f2fs_drop_rpages(cc, len, true);
|
||||
}
|
||||
|
||||
static void f2fs_put_rpages_mapping(struct address_space *mapping,
|
||||
pgoff_t start, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
struct page *page = find_get_page(mapping, start + i);
|
||||
|
||||
put_page(page);
|
||||
put_page(page);
|
||||
}
|
||||
}
|
||||
|
||||
static void f2fs_put_rpages_wbc(struct compress_ctx *cc,
|
||||
struct writeback_control *wbc, bool redirty, int unlock)
|
||||
{
|
||||
@@ -158,13 +145,14 @@ int f2fs_init_compress_ctx(struct compress_ctx *cc)
|
||||
return cc->rpages ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
void f2fs_destroy_compress_ctx(struct compress_ctx *cc)
|
||||
void f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse)
|
||||
{
|
||||
page_array_free(cc->inode, cc->rpages, cc->cluster_size);
|
||||
cc->rpages = NULL;
|
||||
cc->nr_rpages = 0;
|
||||
cc->nr_cpages = 0;
|
||||
cc->cluster_idx = NULL_CLUSTER;
|
||||
if (!reuse)
|
||||
cc->cluster_idx = NULL_CLUSTER;
|
||||
}
|
||||
|
||||
void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page)
|
||||
@@ -1036,7 +1024,7 @@ retry:
|
||||
}
|
||||
|
||||
if (PageUptodate(page))
|
||||
unlock_page(page);
|
||||
f2fs_put_page(page, 1);
|
||||
else
|
||||
f2fs_compress_ctx_add_page(cc, page);
|
||||
}
|
||||
@@ -1046,33 +1034,35 @@ retry:
|
||||
|
||||
ret = f2fs_read_multi_pages(cc, &bio, cc->cluster_size,
|
||||
&last_block_in_bio, false, true);
|
||||
f2fs_destroy_compress_ctx(cc);
|
||||
f2fs_put_rpages(cc);
|
||||
f2fs_destroy_compress_ctx(cc, true);
|
||||
if (ret)
|
||||
goto release_pages;
|
||||
goto out;
|
||||
if (bio)
|
||||
f2fs_submit_bio(sbi, bio, DATA);
|
||||
|
||||
ret = f2fs_init_compress_ctx(cc);
|
||||
if (ret)
|
||||
goto release_pages;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < cc->cluster_size; i++) {
|
||||
f2fs_bug_on(sbi, cc->rpages[i]);
|
||||
|
||||
page = find_lock_page(mapping, start_idx + i);
|
||||
f2fs_bug_on(sbi, !page);
|
||||
if (!page) {
|
||||
/* page can be truncated */
|
||||
goto release_and_retry;
|
||||
}
|
||||
|
||||
f2fs_wait_on_page_writeback(page, DATA, true, true);
|
||||
|
||||
f2fs_compress_ctx_add_page(cc, page);
|
||||
f2fs_put_page(page, 0);
|
||||
|
||||
if (!PageUptodate(page)) {
|
||||
release_and_retry:
|
||||
f2fs_put_rpages(cc);
|
||||
f2fs_unlock_rpages(cc, i + 1);
|
||||
f2fs_put_rpages_mapping(mapping, start_idx,
|
||||
cc->cluster_size);
|
||||
f2fs_destroy_compress_ctx(cc);
|
||||
f2fs_destroy_compress_ctx(cc, true);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
@@ -1103,10 +1093,10 @@ retry:
|
||||
}
|
||||
|
||||
unlock_pages:
|
||||
f2fs_put_rpages(cc);
|
||||
f2fs_unlock_rpages(cc, i);
|
||||
release_pages:
|
||||
f2fs_put_rpages_mapping(mapping, start_idx, i);
|
||||
f2fs_destroy_compress_ctx(cc);
|
||||
f2fs_destroy_compress_ctx(cc, true);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1141,7 +1131,7 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata,
|
||||
set_cluster_dirty(&cc);
|
||||
|
||||
f2fs_put_rpages_wbc(&cc, NULL, false, 1);
|
||||
f2fs_destroy_compress_ctx(&cc);
|
||||
f2fs_destroy_compress_ctx(&cc, false);
|
||||
|
||||
return first_index;
|
||||
}
|
||||
@@ -1361,7 +1351,7 @@ unlock_continue:
|
||||
f2fs_put_rpages(cc);
|
||||
page_array_free(cc->inode, cc->cpages, cc->nr_cpages);
|
||||
cc->cpages = NULL;
|
||||
f2fs_destroy_compress_ctx(cc);
|
||||
f2fs_destroy_compress_ctx(cc, false);
|
||||
return 0;
|
||||
|
||||
out_destroy_crypt:
|
||||
@@ -1372,7 +1362,8 @@ out_destroy_crypt:
|
||||
for (i = 0; i < cc->nr_cpages; i++) {
|
||||
if (!cc->cpages[i])
|
||||
continue;
|
||||
f2fs_put_page(cc->cpages[i], 1);
|
||||
f2fs_compress_free_page(cc->cpages[i]);
|
||||
cc->cpages[i] = NULL;
|
||||
}
|
||||
out_put_cic:
|
||||
kmem_cache_free(cic_entry_slab, cic);
|
||||
@@ -1522,7 +1513,7 @@ write:
|
||||
err = f2fs_write_raw_pages(cc, submitted, wbc, io_type);
|
||||
f2fs_put_rpages_wbc(cc, wbc, false, 0);
|
||||
destroy_out:
|
||||
f2fs_destroy_compress_ctx(cc);
|
||||
f2fs_destroy_compress_ctx(cc, false);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -2292,7 +2292,7 @@ static int f2fs_mpage_readpages(struct inode *inode,
|
||||
max_nr_pages,
|
||||
&last_block_in_bio,
|
||||
rac != NULL, false);
|
||||
f2fs_destroy_compress_ctx(&cc);
|
||||
f2fs_destroy_compress_ctx(&cc, false);
|
||||
if (ret)
|
||||
goto set_error_page;
|
||||
}
|
||||
@@ -2337,7 +2337,7 @@ next_page:
|
||||
max_nr_pages,
|
||||
&last_block_in_bio,
|
||||
rac != NULL, false);
|
||||
f2fs_destroy_compress_ctx(&cc);
|
||||
f2fs_destroy_compress_ctx(&cc, false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -3038,7 +3038,7 @@ next:
|
||||
}
|
||||
}
|
||||
if (f2fs_compressed_file(inode))
|
||||
f2fs_destroy_compress_ctx(&cc);
|
||||
f2fs_destroy_compress_ctx(&cc, false);
|
||||
#endif
|
||||
if (retry) {
|
||||
index = 0;
|
||||
@@ -3942,7 +3942,7 @@ static int check_swap_activate_fast(struct swap_info_struct *sis,
|
||||
/* hole */
|
||||
if (!(map.m_flags & F2FS_MAP_FLAGS)) {
|
||||
f2fs_err(sbi, "Swapfile has holes\n");
|
||||
ret = -ENOENT;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -4098,7 +4098,7 @@ out:
|
||||
return ret;
|
||||
bad_bmap:
|
||||
f2fs_err(sbi, "Swapfile has holes\n");
|
||||
return -ENOENT;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,
|
||||
|
||||
@@ -3956,7 +3956,7 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc);
|
||||
void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed);
|
||||
void f2fs_put_page_dic(struct page *page);
|
||||
int f2fs_init_compress_ctx(struct compress_ctx *cc);
|
||||
void f2fs_destroy_compress_ctx(struct compress_ctx *cc);
|
||||
void f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse);
|
||||
void f2fs_init_compress_info(struct f2fs_sb_info *sbi);
|
||||
int f2fs_init_page_array_cache(struct f2fs_sb_info *sbi);
|
||||
void f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi);
|
||||
|
||||
@@ -3574,12 +3574,12 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
|
||||
|
||||
return err;
|
||||
drop_bio:
|
||||
if (fio->bio) {
|
||||
if (fio->bio && *(fio->bio)) {
|
||||
struct bio *bio = *(fio->bio);
|
||||
|
||||
bio->bi_status = BLK_STS_IOERR;
|
||||
bio_endio(bio);
|
||||
fio->bio = NULL;
|
||||
*(fio->bio) = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -101,6 +101,7 @@ struct vc_data {
|
||||
unsigned int vc_rows;
|
||||
unsigned int vc_size_row; /* Bytes per row */
|
||||
unsigned int vc_scan_lines; /* # of scan lines */
|
||||
unsigned int vc_cell_height; /* CRTC character cell height */
|
||||
unsigned long vc_origin; /* [!] Start of real screen */
|
||||
unsigned long vc_scr_end; /* [!] End of real screen */
|
||||
unsigned long vc_visible_origin; /* [!] Top of visible window */
|
||||
|
||||
@@ -601,6 +601,7 @@ struct dev_pm_info {
|
||||
unsigned int idle_notification:1;
|
||||
unsigned int request_pending:1;
|
||||
unsigned int deferred_resume:1;
|
||||
unsigned int needs_force_resume:1;
|
||||
unsigned int runtime_auto:1;
|
||||
bool ignore_children:1;
|
||||
unsigned int no_callbacks:1;
|
||||
|
||||
@@ -170,6 +170,21 @@ void __ptrace_unlink(struct task_struct *child)
|
||||
spin_unlock(&child->sighand->siglock);
|
||||
}
|
||||
|
||||
static bool looks_like_a_spurious_pid(struct task_struct *task)
|
||||
{
|
||||
if (task->exit_code != ((PTRACE_EVENT_EXEC << 8) | SIGTRAP))
|
||||
return false;
|
||||
|
||||
if (task_pid_vnr(task) == task->ptrace_message)
|
||||
return false;
|
||||
/*
|
||||
* The tracee changed its pid but the PTRACE_EVENT_EXEC event
|
||||
* was not wait()'ed, most probably debugger targets the old
|
||||
* leader which was destroyed in de_thread().
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Ensure that nothing can wake it up, even SIGKILL */
|
||||
static bool ptrace_freeze_traced(struct task_struct *task)
|
||||
{
|
||||
@@ -180,7 +195,8 @@ static bool ptrace_freeze_traced(struct task_struct *task)
|
||||
return ret;
|
||||
|
||||
spin_lock_irq(&task->sighand->siglock);
|
||||
if (task_is_traced(task) && !__fatal_signal_pending(task)) {
|
||||
if (task_is_traced(task) && !looks_like_a_spurious_pid(task) &&
|
||||
!__fatal_signal_pending(task)) {
|
||||
task->state = __TASK_TRACED;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
@@ -3705,6 +3705,9 @@ void trace_check_vprintf(struct trace_iterator *iter, const char *fmt,
|
||||
goto print;
|
||||
|
||||
while (*p) {
|
||||
bool star = false;
|
||||
int len = 0;
|
||||
|
||||
j = 0;
|
||||
|
||||
/* We only care about %s and variants */
|
||||
@@ -3726,13 +3729,17 @@ void trace_check_vprintf(struct trace_iterator *iter, const char *fmt,
|
||||
/* Need to test cases like %08.*s */
|
||||
for (j = 1; p[i+j]; j++) {
|
||||
if (isdigit(p[i+j]) ||
|
||||
p[i+j] == '*' ||
|
||||
p[i+j] == '.')
|
||||
continue;
|
||||
if (p[i+j] == '*') {
|
||||
star = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (p[i+j] == 's')
|
||||
break;
|
||||
star = false;
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
@@ -3745,6 +3752,9 @@ void trace_check_vprintf(struct trace_iterator *iter, const char *fmt,
|
||||
iter->fmt[i] = '\0';
|
||||
trace_seq_vprintf(&iter->seq, iter->fmt, ap);
|
||||
|
||||
if (star)
|
||||
len = va_arg(ap, int);
|
||||
|
||||
/* The ap now points to the string data of the %s */
|
||||
str = va_arg(ap, const char *);
|
||||
|
||||
@@ -3763,8 +3773,18 @@ void trace_check_vprintf(struct trace_iterator *iter, const char *fmt,
|
||||
int ret;
|
||||
|
||||
/* Try to safely read the string */
|
||||
ret = strncpy_from_kernel_nofault(iter->fmt, str,
|
||||
iter->fmt_size);
|
||||
if (star) {
|
||||
if (len + 1 > iter->fmt_size)
|
||||
len = iter->fmt_size - 1;
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
ret = copy_from_kernel_nofault(iter->fmt, str, len);
|
||||
iter->fmt[len] = 0;
|
||||
star = false;
|
||||
} else {
|
||||
ret = strncpy_from_kernel_nofault(iter->fmt, str,
|
||||
iter->fmt_size);
|
||||
}
|
||||
if (ret < 0)
|
||||
trace_seq_printf(&iter->seq, "(0x%px)", str);
|
||||
else
|
||||
@@ -3776,7 +3796,10 @@ void trace_check_vprintf(struct trace_iterator *iter, const char *fmt,
|
||||
strncpy(iter->fmt, p + i, j + 1);
|
||||
iter->fmt[j+1] = '\0';
|
||||
}
|
||||
trace_seq_printf(&iter->seq, iter->fmt, str);
|
||||
if (star)
|
||||
trace_seq_printf(&iter->seq, iter->fmt, len, str);
|
||||
else
|
||||
trace_seq_printf(&iter->seq, iter->fmt, str);
|
||||
|
||||
p += i + j + 1;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user