mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Cross-merge networking fixes after downstream PR (net-7.0-rc7). Conflicts: net/vmw_vsock/af_vsock.cb18c833888("vsock: initialize child_ns_mode_locked in vsock_net_init()")0de607dc4f("vsock: add G2H fallback for CIDs not owned by H2G transport") Adjacent changes: drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.cceee35e567("bnxt_en: Refactor some basic ring setup and adjustment logic")57cdfe0dc7("bnxt_en: Resize RSS contexts on channel count change") drivers/net/wireless/intel/iwlwifi/mld/mac80211.c4d56037a02("wifi: iwlwifi: mld: block EMLSR during TDLS connections")687a95d204("wifi: iwlwifi: mld: correctly set wifi generation data") drivers/net/wireless/intel/iwlwifi/mld/scan.hb6045c899e("wifi: iwlwifi: mld: Refactor scan command handling")ec66ec6a5a("wifi: iwlwifi: mld: Fix MLO scan timing") drivers/net/wireless/intel/iwlwifi/mvm/fw.c078df640ef("wifi: iwlwifi: mld: add support for iwl_mcc_allowed_ap_type_cmd v 2")323156c354("wifi: iwlwifi: mvm: don't send a 6E related command when not supported") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
1
.mailmap
1
.mailmap
@@ -316,6 +316,7 @@ Hans Verkuil <hverkuil@kernel.org> <hverkuil-cisco@xs4all.nl>
|
|||||||
Hans Verkuil <hverkuil@kernel.org> <hansverk@cisco.com>
|
Hans Verkuil <hverkuil@kernel.org> <hansverk@cisco.com>
|
||||||
Hao Ge <hao.ge@linux.dev> <gehao@kylinos.cn>
|
Hao Ge <hao.ge@linux.dev> <gehao@kylinos.cn>
|
||||||
Harry Yoo <harry.yoo@oracle.com> <42.hyeyoo@gmail.com>
|
Harry Yoo <harry.yoo@oracle.com> <42.hyeyoo@gmail.com>
|
||||||
|
Harry Yoo <harry@kernel.org> <harry.yoo@oracle.com>
|
||||||
Heiko Carstens <hca@linux.ibm.com> <h.carstens@de.ibm.com>
|
Heiko Carstens <hca@linux.ibm.com> <h.carstens@de.ibm.com>
|
||||||
Heiko Carstens <hca@linux.ibm.com> <heiko.carstens@de.ibm.com>
|
Heiko Carstens <hca@linux.ibm.com> <heiko.carstens@de.ibm.com>
|
||||||
Heiko Stuebner <heiko@sntech.de> <heiko.stuebner@bqreaders.com>
|
Heiko Stuebner <heiko@sntech.de> <heiko.stuebner@bqreaders.com>
|
||||||
|
|||||||
@@ -85,6 +85,16 @@ In the example, 'Requester ID' means the ID of the device that sent
|
|||||||
the error message to the Root Port. Please refer to PCIe specs for other
|
the error message to the Root Port. Please refer to PCIe specs for other
|
||||||
fields.
|
fields.
|
||||||
|
|
||||||
|
The 'TLP Header' is the prefix/header of the TLP that caused the error
|
||||||
|
in raw hex format. To decode the TLP Header into human-readable form
|
||||||
|
one may use tlp-tool:
|
||||||
|
|
||||||
|
https://github.com/mmpg-x86/tlp-tool
|
||||||
|
|
||||||
|
Example usage::
|
||||||
|
|
||||||
|
curl -L https://git.kernel.org/linus/2ca1c94ce0b6 | rtlp-tool --aer
|
||||||
|
|
||||||
AER Ratelimits
|
AER Ratelimits
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ then:
|
|||||||
required:
|
required:
|
||||||
- refresh-rate-hz
|
- refresh-rate-hz
|
||||||
|
|
||||||
additionalProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ properties:
|
|||||||
- const: rockchip,rk3066-spdif
|
- const: rockchip,rk3066-spdif
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
|
- rockchip,rk3576-spdif
|
||||||
- rockchip,rk3588-spdif
|
- rockchip,rk3588-spdif
|
||||||
- const: rockchip,rk3568-spdif
|
- const: rockchip,rk3568-spdif
|
||||||
|
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ allOf:
|
|||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
contains:
|
contains:
|
||||||
const: st,stm32mph7-sai
|
const: st,stm32h7-sai
|
||||||
then:
|
then:
|
||||||
properties:
|
properties:
|
||||||
clocks:
|
clocks:
|
||||||
|
|||||||
@@ -783,6 +783,56 @@ controlled by the "uuid" mount option, which supports these values:
|
|||||||
mounted with "uuid=on".
|
mounted with "uuid=on".
|
||||||
|
|
||||||
|
|
||||||
|
Durability and copy up
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
The fsync(2) system call ensures that the data and metadata of a file
|
||||||
|
are safely written to the backing storage, which is expected to
|
||||||
|
guarantee the existence of the information post system crash.
|
||||||
|
|
||||||
|
Without an fsync(2) call, there is no guarantee that the observed
|
||||||
|
data after a system crash will be either the old or the new data, but
|
||||||
|
in practice, the observed data after crash is often the old or new data
|
||||||
|
or a mix of both.
|
||||||
|
|
||||||
|
When an overlayfs file is modified for the first time, copy up will
|
||||||
|
create a copy of the lower file and its parent directories in the upper
|
||||||
|
layer. Since the Linux filesystem API does not enforce any particular
|
||||||
|
ordering on storing changes without explicit fsync(2) calls, in case
|
||||||
|
of a system crash, the upper file could end up with no data at all
|
||||||
|
(i.e. zeros), which would be an unusual outcome. To avoid this
|
||||||
|
experience, overlayfs calls fsync(2) on the upper file before completing
|
||||||
|
data copy up with rename(2) or link(2) to make the copy up "atomic".
|
||||||
|
|
||||||
|
By default, overlayfs does not explicitly call fsync(2) on copied up
|
||||||
|
directories or on metadata-only copy up, so it provides no guarantee to
|
||||||
|
persist the user's modification unless the user calls fsync(2).
|
||||||
|
The fsync during copy up only guarantees that if a copy up is observed
|
||||||
|
after a crash, the observed data is not zeroes or intermediate values
|
||||||
|
from the copy up staging area.
|
||||||
|
|
||||||
|
On traditional local filesystems with a single journal (e.g. ext4, xfs),
|
||||||
|
fsync on a file also persists the parent directory changes, because they
|
||||||
|
are usually modified in the same transaction, so metadata durability during
|
||||||
|
data copy up effectively comes for free. Overlayfs further limits risk by
|
||||||
|
disallowing network filesystems as upper layer.
|
||||||
|
|
||||||
|
Overlayfs can be tuned to prefer performance or durability when storing
|
||||||
|
to the underlying upper layer. This is controlled by the "fsync" mount
|
||||||
|
option, which supports these values:
|
||||||
|
|
||||||
|
- "auto": (default)
|
||||||
|
Call fsync(2) on upper file before completion of data copy up.
|
||||||
|
No explicit fsync(2) on directory or metadata-only copy up.
|
||||||
|
- "strict":
|
||||||
|
Call fsync(2) on upper file and directories before completion of any
|
||||||
|
copy up.
|
||||||
|
- "volatile": [*]
|
||||||
|
Prefer performance over durability (see `Volatile mount`_)
|
||||||
|
|
||||||
|
[*] The mount option "volatile" is an alias to "fsync=volatile".
|
||||||
|
|
||||||
|
|
||||||
Volatile mount
|
Volatile mount
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ for details.
|
|||||||
Sysfs entries
|
Sysfs entries
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The following attributes are supported. Current maxim attribute
|
The following attributes are supported. Current maximum attribute
|
||||||
is read-write, all other attributes are read-only.
|
is read-write, all other attributes are read-only.
|
||||||
|
|
||||||
in0_input Measured voltage in microvolts.
|
in0_input Measured voltage in millivolts.
|
||||||
|
|
||||||
curr1_input Measured current in microamperes.
|
curr1_input Measured current in milliamperes.
|
||||||
curr1_max_alarm Overcurrent alarm in microamperes.
|
curr1_max Overcurrent shutdown threshold in milliamperes.
|
||||||
|
|||||||
@@ -51,8 +51,9 @@ temp1_max Provides thermal control temperature of the CPU package
|
|||||||
temp1_crit Provides shutdown temperature of the CPU package which
|
temp1_crit Provides shutdown temperature of the CPU package which
|
||||||
is also known as the maximum processor junction
|
is also known as the maximum processor junction
|
||||||
temperature, Tjmax or Tprochot.
|
temperature, Tjmax or Tprochot.
|
||||||
temp1_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
|
temp1_crit_hyst Provides the hysteresis temperature of the CPU
|
||||||
the CPU package.
|
package. Returns Tcontrol, the temperature at which
|
||||||
|
the critical condition clears.
|
||||||
|
|
||||||
temp2_label "DTS"
|
temp2_label "DTS"
|
||||||
temp2_input Provides current temperature of the CPU package scaled
|
temp2_input Provides current temperature of the CPU package scaled
|
||||||
@@ -62,8 +63,9 @@ temp2_max Provides thermal control temperature of the CPU package
|
|||||||
temp2_crit Provides shutdown temperature of the CPU package which
|
temp2_crit Provides shutdown temperature of the CPU package which
|
||||||
is also known as the maximum processor junction
|
is also known as the maximum processor junction
|
||||||
temperature, Tjmax or Tprochot.
|
temperature, Tjmax or Tprochot.
|
||||||
temp2_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
|
temp2_crit_hyst Provides the hysteresis temperature of the CPU
|
||||||
the CPU package.
|
package. Returns Tcontrol, the temperature at which
|
||||||
|
the critical condition clears.
|
||||||
|
|
||||||
temp3_label "Tcontrol"
|
temp3_label "Tcontrol"
|
||||||
temp3_input Provides current Tcontrol temperature of the CPU
|
temp3_input Provides current Tcontrol temperature of the CPU
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Landlock: unprivileged access control
|
|||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
:Author: Mickaël Salaün
|
:Author: Mickaël Salaün
|
||||||
:Date: January 2026
|
:Date: March 2026
|
||||||
|
|
||||||
The goal of Landlock is to enable restriction of ambient rights (e.g. global
|
The goal of Landlock is to enable restriction of ambient rights (e.g. global
|
||||||
filesystem or network access) for a set of processes. Because Landlock
|
filesystem or network access) for a set of processes. Because Landlock
|
||||||
@@ -197,12 +197,27 @@ similar backwards compatibility check is needed for the restrict flags
|
|||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
__u32 restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON;
|
__u32 restrict_flags =
|
||||||
if (abi < 7) {
|
LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON |
|
||||||
/* Clear logging flags unsupported before ABI 7. */
|
LANDLOCK_RESTRICT_SELF_TSYNC;
|
||||||
|
switch (abi) {
|
||||||
|
case 1 ... 6:
|
||||||
|
/* Removes logging flags for ABI < 7 */
|
||||||
restrict_flags &= ~(LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF |
|
restrict_flags &= ~(LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF |
|
||||||
LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON |
|
LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON |
|
||||||
LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF);
|
LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF);
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case 7:
|
||||||
|
/*
|
||||||
|
* Removes multithreaded enforcement flag for ABI < 8
|
||||||
|
*
|
||||||
|
* WARNING: Without this flag, calling landlock_restrict_self(2) is
|
||||||
|
* only equivalent if the calling process is single-threaded. Below
|
||||||
|
* ABI v8 (and as of ABI v8, when not using this flag), a Landlock
|
||||||
|
* policy would only be enforced for the calling thread and its
|
||||||
|
* children (and not for all threads, including parents and siblings).
|
||||||
|
*/
|
||||||
|
restrict_flags &= ~LANDLOCK_RESTRICT_SELF_TSYNC;
|
||||||
}
|
}
|
||||||
|
|
||||||
The next step is to restrict the current thread from gaining more privileges
|
The next step is to restrict the current thread from gaining more privileges
|
||||||
|
|||||||
21
MAINTAINERS
21
MAINTAINERS
@@ -8628,8 +8628,14 @@ F: drivers/gpu/drm/lima/
|
|||||||
F: include/uapi/drm/lima_drm.h
|
F: include/uapi/drm/lima_drm.h
|
||||||
|
|
||||||
DRM DRIVERS FOR LOONGSON
|
DRM DRIVERS FOR LOONGSON
|
||||||
|
M: Jianmin Lv <lvjianmin@loongson.cn>
|
||||||
|
M: Qianhai Wu <wuqianhai@loongson.cn>
|
||||||
|
R: Huacai Chen <chenhuacai@kernel.org>
|
||||||
|
R: Mingcong Bai <jeffbai@aosc.io>
|
||||||
|
R: Xi Ruoyao <xry111@xry111.site>
|
||||||
|
R: Icenowy Zheng <zhengxingda@iscas.ac.cn>
|
||||||
L: dri-devel@lists.freedesktop.org
|
L: dri-devel@lists.freedesktop.org
|
||||||
S: Orphan
|
S: Maintained
|
||||||
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
||||||
F: drivers/gpu/drm/loongson/
|
F: drivers/gpu/drm/loongson/
|
||||||
|
|
||||||
@@ -9612,7 +9618,12 @@ F: include/linux/ext2*
|
|||||||
|
|
||||||
EXT4 FILE SYSTEM
|
EXT4 FILE SYSTEM
|
||||||
M: "Theodore Ts'o" <tytso@mit.edu>
|
M: "Theodore Ts'o" <tytso@mit.edu>
|
||||||
M: Andreas Dilger <adilger.kernel@dilger.ca>
|
R: Andreas Dilger <adilger.kernel@dilger.ca>
|
||||||
|
R: Baokun Li <libaokun@linux.alibaba.com>
|
||||||
|
R: Jan Kara <jack@suse.cz>
|
||||||
|
R: Ojaswin Mujoo <ojaswin@linux.ibm.com>
|
||||||
|
R: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
|
||||||
|
R: Zhang Yi <yi.zhang@huawei.com>
|
||||||
L: linux-ext4@vger.kernel.org
|
L: linux-ext4@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
W: http://ext4.wiki.kernel.org
|
W: http://ext4.wiki.kernel.org
|
||||||
@@ -12007,7 +12018,6 @@ I2C SUBSYSTEM
|
|||||||
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
|
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||||
L: linux-i2c@vger.kernel.org
|
L: linux-i2c@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
W: https://i2c.wiki.kernel.org/
|
|
||||||
Q: https://patchwork.ozlabs.org/project/linux-i2c/list/
|
Q: https://patchwork.ozlabs.org/project/linux-i2c/list/
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
|
||||||
F: Documentation/i2c/
|
F: Documentation/i2c/
|
||||||
@@ -12033,7 +12043,6 @@ I2C SUBSYSTEM HOST DRIVERS
|
|||||||
M: Andi Shyti <andi.shyti@kernel.org>
|
M: Andi Shyti <andi.shyti@kernel.org>
|
||||||
L: linux-i2c@vger.kernel.org
|
L: linux-i2c@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
W: https://i2c.wiki.kernel.org/
|
|
||||||
Q: https://patchwork.ozlabs.org/project/linux-i2c/list/
|
Q: https://patchwork.ozlabs.org/project/linux-i2c/list/
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git
|
||||||
F: Documentation/devicetree/bindings/i2c/
|
F: Documentation/devicetree/bindings/i2c/
|
||||||
@@ -16875,7 +16884,7 @@ M: Lorenzo Stoakes <ljs@kernel.org>
|
|||||||
R: Rik van Riel <riel@surriel.com>
|
R: Rik van Riel <riel@surriel.com>
|
||||||
R: Liam R. Howlett <Liam.Howlett@oracle.com>
|
R: Liam R. Howlett <Liam.Howlett@oracle.com>
|
||||||
R: Vlastimil Babka <vbabka@kernel.org>
|
R: Vlastimil Babka <vbabka@kernel.org>
|
||||||
R: Harry Yoo <harry.yoo@oracle.com>
|
R: Harry Yoo <harry@kernel.org>
|
||||||
R: Jann Horn <jannh@google.com>
|
R: Jann Horn <jannh@google.com>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
@@ -24341,7 +24350,7 @@ F: drivers/nvmem/layouts/sl28vpd.c
|
|||||||
|
|
||||||
SLAB ALLOCATOR
|
SLAB ALLOCATOR
|
||||||
M: Vlastimil Babka <vbabka@kernel.org>
|
M: Vlastimil Babka <vbabka@kernel.org>
|
||||||
M: Harry Yoo <harry.yoo@oracle.com>
|
M: Harry Yoo <harry@kernel.org>
|
||||||
M: Andrew Morton <akpm@linux-foundation.org>
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
R: Hao Li <hao.li@linux.dev>
|
R: Hao Li <hao.li@linux.dev>
|
||||||
R: Christoph Lameter <cl@gentwo.org>
|
R: Christoph Lameter <cl@gentwo.org>
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -2,7 +2,7 @@
|
|||||||
VERSION = 7
|
VERSION = 7
|
||||||
PATCHLEVEL = 0
|
PATCHLEVEL = 0
|
||||||
SUBLEVEL = 0
|
SUBLEVEL = 0
|
||||||
EXTRAVERSION = -rc5
|
EXTRAVERSION = -rc6
|
||||||
NAME = Baby Opossum Posse
|
NAME = Baby Opossum Posse
|
||||||
|
|
||||||
# *DOCUMENTATION*
|
# *DOCUMENTATION*
|
||||||
|
|||||||
@@ -41,4 +41,40 @@
|
|||||||
.cfi_endproc; \
|
.cfi_endproc; \
|
||||||
SYM_END(name, SYM_T_NONE)
|
SYM_END(name, SYM_T_NONE)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is for the signal handler trampoline, which is used as the return
|
||||||
|
* address of the signal handlers in userspace instead of called normally.
|
||||||
|
* The long standing libgcc bug https://gcc.gnu.org/PR124050 requires a
|
||||||
|
* nop between .cfi_startproc and the actual address of the trampoline, so
|
||||||
|
* we cannot simply use SYM_FUNC_START.
|
||||||
|
*
|
||||||
|
* This wrapper also contains all the .cfi_* directives for recovering
|
||||||
|
* the content of the GPRs and the "return address" (where the rt_sigreturn
|
||||||
|
* syscall will jump to), assuming there is a struct rt_sigframe (where
|
||||||
|
* a struct sigcontext containing those information we need to recover) at
|
||||||
|
* $sp. The "DWARF for the LoongArch(TM) Architecture" manual states
|
||||||
|
* column 0 is for $zero, but it does not make too much sense to
|
||||||
|
* save/restore the hardware zero register. Repurpose this column here
|
||||||
|
* for the return address (here it's not the content of $ra we cannot use
|
||||||
|
* the default column 3).
|
||||||
|
*/
|
||||||
|
#define SYM_SIGFUNC_START(name) \
|
||||||
|
.cfi_startproc; \
|
||||||
|
.cfi_signal_frame; \
|
||||||
|
.cfi_def_cfa 3, RT_SIGFRAME_SC; \
|
||||||
|
.cfi_return_column 0; \
|
||||||
|
.cfi_offset 0, SC_PC; \
|
||||||
|
\
|
||||||
|
.irp num, 1, 2, 3, 4, 5, 6, 7, 8, \
|
||||||
|
9, 10, 11, 12, 13, 14, 15, 16, \
|
||||||
|
17, 18, 19, 20, 21, 22, 23, 24, \
|
||||||
|
25, 26, 27, 28, 29, 30, 31; \
|
||||||
|
.cfi_offset \num, SC_REGS + \num * SZREG; \
|
||||||
|
.endr; \
|
||||||
|
\
|
||||||
|
nop; \
|
||||||
|
SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN)
|
||||||
|
|
||||||
|
#define SYM_SIGFUNC_END(name) SYM_FUNC_END(name)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
9
arch/loongarch/include/asm/sigframe.h
Normal file
9
arch/loongarch/include/asm/sigframe.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
|
|
||||||
|
#include <asm/siginfo.h>
|
||||||
|
#include <asm/ucontext.h>
|
||||||
|
|
||||||
|
struct rt_sigframe {
|
||||||
|
struct siginfo rs_info;
|
||||||
|
struct ucontext rs_uctx;
|
||||||
|
};
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <asm/ftrace.h>
|
#include <asm/ftrace.h>
|
||||||
|
#include <asm/sigframe.h>
|
||||||
#include <vdso/datapage.h>
|
#include <vdso/datapage.h>
|
||||||
|
|
||||||
static void __used output_ptreg_defines(void)
|
static void __used output_ptreg_defines(void)
|
||||||
@@ -220,6 +221,7 @@ static void __used output_sc_defines(void)
|
|||||||
COMMENT("Linux sigcontext offsets.");
|
COMMENT("Linux sigcontext offsets.");
|
||||||
OFFSET(SC_REGS, sigcontext, sc_regs);
|
OFFSET(SC_REGS, sigcontext, sc_regs);
|
||||||
OFFSET(SC_PC, sigcontext, sc_pc);
|
OFFSET(SC_PC, sigcontext, sc_pc);
|
||||||
|
OFFSET(RT_SIGFRAME_SC, rt_sigframe, rs_uctx.uc_mcontext);
|
||||||
BLANK();
|
BLANK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,16 +42,15 @@ static int __init init_cpu_fullname(void)
|
|||||||
int cpu, ret;
|
int cpu, ret;
|
||||||
char *cpuname;
|
char *cpuname;
|
||||||
const char *model;
|
const char *model;
|
||||||
struct device_node *root;
|
|
||||||
|
|
||||||
/* Parsing cpuname from DTS model property */
|
/* Parsing cpuname from DTS model property */
|
||||||
root = of_find_node_by_path("/");
|
ret = of_property_read_string(of_root, "model", &model);
|
||||||
ret = of_property_read_string(root, "model", &model);
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
cpuname = kstrdup(model, GFP_KERNEL);
|
cpuname = kstrdup(model, GFP_KERNEL);
|
||||||
|
if (!cpuname)
|
||||||
|
return -ENOMEM;
|
||||||
loongson_sysconf.cpuname = strsep(&cpuname, " ");
|
loongson_sysconf.cpuname = strsep(&cpuname, " ");
|
||||||
}
|
}
|
||||||
of_node_put(root);
|
|
||||||
|
|
||||||
if (loongson_sysconf.cpuname && !strncmp(loongson_sysconf.cpuname, "Loongson", 8)) {
|
if (loongson_sysconf.cpuname && !strncmp(loongson_sysconf.cpuname, "Loongson", 8)) {
|
||||||
for (cpu = 0; cpu < NR_CPUS; cpu++)
|
for (cpu = 0; cpu < NR_CPUS; cpu++)
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <asm/cpu-features.h>
|
#include <asm/cpu-features.h>
|
||||||
#include <asm/fpu.h>
|
#include <asm/fpu.h>
|
||||||
#include <asm/lbt.h>
|
#include <asm/lbt.h>
|
||||||
|
#include <asm/sigframe.h>
|
||||||
#include <asm/ucontext.h>
|
#include <asm/ucontext.h>
|
||||||
#include <asm/vdso.h>
|
#include <asm/vdso.h>
|
||||||
|
|
||||||
@@ -51,11 +52,6 @@
|
|||||||
#define lock_lbt_owner() ({ preempt_disable(); pagefault_disable(); })
|
#define lock_lbt_owner() ({ preempt_disable(); pagefault_disable(); })
|
||||||
#define unlock_lbt_owner() ({ pagefault_enable(); preempt_enable(); })
|
#define unlock_lbt_owner() ({ pagefault_enable(); preempt_enable(); })
|
||||||
|
|
||||||
struct rt_sigframe {
|
|
||||||
struct siginfo rs_info;
|
|
||||||
struct ucontext rs_uctx;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _ctx_layout {
|
struct _ctx_layout {
|
||||||
struct sctx_info *addr;
|
struct sctx_info *addr;
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ static inline void eiointc_update_sw_coremap(struct loongarch_eiointc *s,
|
|||||||
|
|
||||||
if (!(s->status & BIT(EIOINTC_ENABLE_CPU_ENCODE))) {
|
if (!(s->status & BIT(EIOINTC_ENABLE_CPU_ENCODE))) {
|
||||||
cpuid = ffs(cpuid) - 1;
|
cpuid = ffs(cpuid) - 1;
|
||||||
cpuid = (cpuid >= 4) ? 0 : cpuid;
|
cpuid = ((cpuid < 0) || (cpuid >= 4)) ? 0 : cpuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
vcpu = kvm_get_vcpu_by_cpuid(s->kvm, cpuid);
|
vcpu = kvm_get_vcpu_by_cpuid(s->kvm, cpuid);
|
||||||
@@ -472,34 +472,34 @@ static int kvm_eiointc_regs_access(struct kvm_device *dev,
|
|||||||
switch (addr) {
|
switch (addr) {
|
||||||
case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
|
case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
|
||||||
offset = (addr - EIOINTC_NODETYPE_START) / 4;
|
offset = (addr - EIOINTC_NODETYPE_START) / 4;
|
||||||
p = s->nodetype + offset * 4;
|
p = (void *)s->nodetype + offset * 4;
|
||||||
break;
|
break;
|
||||||
case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
|
case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
|
||||||
offset = (addr - EIOINTC_IPMAP_START) / 4;
|
offset = (addr - EIOINTC_IPMAP_START) / 4;
|
||||||
p = &s->ipmap + offset * 4;
|
p = (void *)&s->ipmap + offset * 4;
|
||||||
break;
|
break;
|
||||||
case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
|
case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
|
||||||
offset = (addr - EIOINTC_ENABLE_START) / 4;
|
offset = (addr - EIOINTC_ENABLE_START) / 4;
|
||||||
p = s->enable + offset * 4;
|
p = (void *)s->enable + offset * 4;
|
||||||
break;
|
break;
|
||||||
case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
|
case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
|
||||||
offset = (addr - EIOINTC_BOUNCE_START) / 4;
|
offset = (addr - EIOINTC_BOUNCE_START) / 4;
|
||||||
p = s->bounce + offset * 4;
|
p = (void *)s->bounce + offset * 4;
|
||||||
break;
|
break;
|
||||||
case EIOINTC_ISR_START ... EIOINTC_ISR_END:
|
case EIOINTC_ISR_START ... EIOINTC_ISR_END:
|
||||||
offset = (addr - EIOINTC_ISR_START) / 4;
|
offset = (addr - EIOINTC_ISR_START) / 4;
|
||||||
p = s->isr + offset * 4;
|
p = (void *)s->isr + offset * 4;
|
||||||
break;
|
break;
|
||||||
case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
|
case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
|
||||||
if (cpu >= s->num_cpu)
|
if (cpu >= s->num_cpu)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
offset = (addr - EIOINTC_COREISR_START) / 4;
|
offset = (addr - EIOINTC_COREISR_START) / 4;
|
||||||
p = s->coreisr[cpu] + offset * 4;
|
p = (void *)s->coreisr[cpu] + offset * 4;
|
||||||
break;
|
break;
|
||||||
case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
|
case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
|
||||||
offset = (addr - EIOINTC_COREMAP_START) / 4;
|
offset = (addr - EIOINTC_COREMAP_START) / 4;
|
||||||
p = s->coremap + offset * 4;
|
p = (void *)s->coremap + offset * 4;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr);
|
kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr);
|
||||||
|
|||||||
@@ -588,6 +588,9 @@ struct kvm_vcpu *kvm_get_vcpu_by_cpuid(struct kvm *kvm, int cpuid)
|
|||||||
{
|
{
|
||||||
struct kvm_phyid_map *map;
|
struct kvm_phyid_map *map;
|
||||||
|
|
||||||
|
if (cpuid < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (cpuid >= KVM_MAX_PHYID)
|
if (cpuid >= KVM_MAX_PHYID)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,11 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/vgaarb.h>
|
#include <linux/vgaarb.h>
|
||||||
|
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
#include <asm/loongson.h>
|
#include <asm/loongson.h>
|
||||||
|
|
||||||
@@ -15,6 +17,9 @@
|
|||||||
#define PCI_DEVICE_ID_LOONGSON_DC1 0x7a06
|
#define PCI_DEVICE_ID_LOONGSON_DC1 0x7a06
|
||||||
#define PCI_DEVICE_ID_LOONGSON_DC2 0x7a36
|
#define PCI_DEVICE_ID_LOONGSON_DC2 0x7a36
|
||||||
#define PCI_DEVICE_ID_LOONGSON_DC3 0x7a46
|
#define PCI_DEVICE_ID_LOONGSON_DC3 0x7a46
|
||||||
|
#define PCI_DEVICE_ID_LOONGSON_GPU1 0x7a15
|
||||||
|
#define PCI_DEVICE_ID_LOONGSON_GPU2 0x7a25
|
||||||
|
#define PCI_DEVICE_ID_LOONGSON_GPU3 0x7a35
|
||||||
|
|
||||||
int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
|
int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
|
||||||
int reg, int len, u32 *val)
|
int reg, int len, u32 *val)
|
||||||
@@ -99,3 +104,78 @@ static void pci_fixup_vgadev(struct pci_dev *pdev)
|
|||||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC1, pci_fixup_vgadev);
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC1, pci_fixup_vgadev);
|
||||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC2, pci_fixup_vgadev);
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC2, pci_fixup_vgadev);
|
||||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC3, pci_fixup_vgadev);
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC3, pci_fixup_vgadev);
|
||||||
|
|
||||||
|
#define CRTC_NUM_MAX 2
|
||||||
|
#define CRTC_OUTPUT_ENABLE 0x100
|
||||||
|
|
||||||
|
static void loongson_gpu_fixup_dma_hang(struct pci_dev *pdev, bool on)
|
||||||
|
{
|
||||||
|
u32 i, val, count, crtc_offset, device;
|
||||||
|
void __iomem *crtc_reg, *base, *regbase;
|
||||||
|
static u32 crtc_status[CRTC_NUM_MAX] = { 0 };
|
||||||
|
|
||||||
|
base = pdev->bus->ops->map_bus(pdev->bus, pdev->devfn + 1, 0);
|
||||||
|
device = readw(base + PCI_DEVICE_ID);
|
||||||
|
|
||||||
|
regbase = ioremap(readq(base + PCI_BASE_ADDRESS_0) & ~0xffull, SZ_64K);
|
||||||
|
if (!regbase) {
|
||||||
|
pci_err(pdev, "Failed to ioremap()\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (device) {
|
||||||
|
case PCI_DEVICE_ID_LOONGSON_DC2:
|
||||||
|
crtc_reg = regbase + 0x1240;
|
||||||
|
crtc_offset = 0x10;
|
||||||
|
break;
|
||||||
|
case PCI_DEVICE_ID_LOONGSON_DC3:
|
||||||
|
crtc_reg = regbase;
|
||||||
|
crtc_offset = 0x400;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < CRTC_NUM_MAX; i++, crtc_reg += crtc_offset) {
|
||||||
|
val = readl(crtc_reg);
|
||||||
|
|
||||||
|
if (!on)
|
||||||
|
crtc_status[i] = val;
|
||||||
|
|
||||||
|
/* No need to fixup if the status is off at startup. */
|
||||||
|
if (!(crtc_status[i] & CRTC_OUTPUT_ENABLE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (on)
|
||||||
|
val |= CRTC_OUTPUT_ENABLE;
|
||||||
|
else
|
||||||
|
val &= ~CRTC_OUTPUT_ENABLE;
|
||||||
|
|
||||||
|
mb();
|
||||||
|
writel(val, crtc_reg);
|
||||||
|
|
||||||
|
for (count = 0; count < 40; count++) {
|
||||||
|
val = readl(crtc_reg) & CRTC_OUTPUT_ENABLE;
|
||||||
|
if ((on && val) || (!on && !val))
|
||||||
|
break;
|
||||||
|
udelay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_info(pdev, "DMA hang fixup at reg[0x%lx]: 0x%x\n",
|
||||||
|
(unsigned long)crtc_reg & 0xffff, readl(crtc_reg));
|
||||||
|
}
|
||||||
|
|
||||||
|
iounmap(regbase);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pci_fixup_dma_hang_early(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
loongson_gpu_fixup_dma_hang(pdev, false);
|
||||||
|
}
|
||||||
|
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU2, pci_fixup_dma_hang_early);
|
||||||
|
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU3, pci_fixup_dma_hang_early);
|
||||||
|
|
||||||
|
static void pci_fixup_dma_hang_final(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
loongson_gpu_fixup_dma_hang(pdev, true);
|
||||||
|
}
|
||||||
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU2, pci_fixup_dma_hang_final);
|
||||||
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU3, pci_fixup_dma_hang_final);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ cflags-vdso := $(ccflags-vdso) \
|
|||||||
$(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
|
$(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
|
||||||
-std=gnu11 -fms-extensions -O2 -g -fno-strict-aliasing -fno-common -fno-builtin \
|
-std=gnu11 -fms-extensions -O2 -g -fno-strict-aliasing -fno-common -fno-builtin \
|
||||||
-fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \
|
-fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \
|
||||||
$(call cc-option, -fno-asynchronous-unwind-tables) \
|
$(call cc-option, -fasynchronous-unwind-tables) \
|
||||||
$(call cc-option, -fno-stack-protector)
|
$(call cc-option, -fno-stack-protector)
|
||||||
aflags-vdso := $(ccflags-vdso) \
|
aflags-vdso := $(ccflags-vdso) \
|
||||||
-D__ASSEMBLY__ -Wa,-gdwarf-2
|
-D__ASSEMBLY__ -Wa,-gdwarf-2
|
||||||
@@ -41,7 +41,7 @@ endif
|
|||||||
|
|
||||||
# VDSO linker flags.
|
# VDSO linker flags.
|
||||||
ldflags-y := -Bsymbolic --no-undefined -soname=linux-vdso.so.1 \
|
ldflags-y := -Bsymbolic --no-undefined -soname=linux-vdso.so.1 \
|
||||||
$(filter -E%,$(KBUILD_CFLAGS)) -shared --build-id -T
|
$(filter -E%,$(KBUILD_CFLAGS)) -shared --build-id --eh-frame-hdr -T
|
||||||
|
|
||||||
#
|
#
|
||||||
# Shared build commands.
|
# Shared build commands.
|
||||||
|
|||||||
@@ -12,13 +12,13 @@
|
|||||||
|
|
||||||
#include <asm/regdef.h>
|
#include <asm/regdef.h>
|
||||||
#include <asm/asm.h>
|
#include <asm/asm.h>
|
||||||
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
.cfi_sections .debug_frame
|
|
||||||
|
|
||||||
SYM_FUNC_START(__vdso_rt_sigreturn)
|
SYM_SIGFUNC_START(__vdso_rt_sigreturn)
|
||||||
|
|
||||||
li.w a7, __NR_rt_sigreturn
|
li.w a7, __NR_rt_sigreturn
|
||||||
syscall 0
|
syscall 0
|
||||||
|
|
||||||
SYM_FUNC_END(__vdso_rt_sigreturn)
|
SYM_SIGFUNC_END(__vdso_rt_sigreturn)
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ do { \
|
|||||||
* @size: number of elements in array
|
* @size: number of elements in array
|
||||||
*/
|
*/
|
||||||
#define array_index_mask_nospec array_index_mask_nospec
|
#define array_index_mask_nospec array_index_mask_nospec
|
||||||
static inline unsigned long array_index_mask_nospec(unsigned long index,
|
static __always_inline unsigned long array_index_mask_nospec(unsigned long index,
|
||||||
unsigned long size)
|
unsigned long size)
|
||||||
{
|
{
|
||||||
unsigned long mask;
|
unsigned long mask;
|
||||||
|
|
||||||
|
|||||||
@@ -271,6 +271,7 @@ SYM_CODE_START(system_call)
|
|||||||
xgr %r9,%r9
|
xgr %r9,%r9
|
||||||
xgr %r10,%r10
|
xgr %r10,%r10
|
||||||
xgr %r11,%r11
|
xgr %r11,%r11
|
||||||
|
xgr %r12,%r12
|
||||||
la %r2,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs
|
la %r2,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs
|
||||||
mvc __PT_R8(64,%r2),__LC_SAVE_AREA(%r13)
|
mvc __PT_R8(64,%r2),__LC_SAVE_AREA(%r13)
|
||||||
MBEAR %r2,%r13
|
MBEAR %r2,%r13
|
||||||
@@ -407,6 +408,7 @@ SYM_CODE_START(\name)
|
|||||||
xgr %r6,%r6
|
xgr %r6,%r6
|
||||||
xgr %r7,%r7
|
xgr %r7,%r7
|
||||||
xgr %r10,%r10
|
xgr %r10,%r10
|
||||||
|
xgr %r12,%r12
|
||||||
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
|
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
|
||||||
mvc __PT_R8(64,%r11),__LC_SAVE_AREA(%r13)
|
mvc __PT_R8(64,%r11),__LC_SAVE_AREA(%r13)
|
||||||
MBEAR %r11,%r13
|
MBEAR %r11,%r13
|
||||||
@@ -496,6 +498,7 @@ SYM_CODE_START(mcck_int_handler)
|
|||||||
xgr %r6,%r6
|
xgr %r6,%r6
|
||||||
xgr %r7,%r7
|
xgr %r7,%r7
|
||||||
xgr %r10,%r10
|
xgr %r10,%r10
|
||||||
|
xgr %r12,%r12
|
||||||
stmg %r8,%r9,__PT_PSW(%r11)
|
stmg %r8,%r9,__PT_PSW(%r11)
|
||||||
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
|
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
|
||||||
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/cpufeature.h>
|
#include <linux/cpufeature.h>
|
||||||
|
#include <linux/nospec.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
@@ -131,8 +132,10 @@ void noinstr __do_syscall(struct pt_regs *regs, int per_trap)
|
|||||||
if (unlikely(test_and_clear_pt_regs_flag(regs, PIF_SYSCALL_RET_SET)))
|
if (unlikely(test_and_clear_pt_regs_flag(regs, PIF_SYSCALL_RET_SET)))
|
||||||
goto out;
|
goto out;
|
||||||
regs->gprs[2] = -ENOSYS;
|
regs->gprs[2] = -ENOSYS;
|
||||||
if (likely(nr < NR_syscalls))
|
if (likely(nr < NR_syscalls)) {
|
||||||
|
nr = array_index_nospec(nr, NR_syscalls);
|
||||||
regs->gprs[2] = sys_call_table[nr](regs);
|
regs->gprs[2] = sys_call_table[nr](regs);
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
syscall_exit_to_user_mode(regs);
|
syscall_exit_to_user_mode(regs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,32 +134,6 @@ int dat_set_asce_limit(struct kvm_s390_mmu_cache *mc, union asce *asce, int newt
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* dat_crstep_xchg() - Exchange a gmap CRSTE with another.
|
|
||||||
* @crstep: Pointer to the CRST entry
|
|
||||||
* @new: Replacement entry.
|
|
||||||
* @gfn: The affected guest address.
|
|
||||||
* @asce: The ASCE of the address space.
|
|
||||||
*
|
|
||||||
* Context: This function is assumed to be called with kvm->mmu_lock held.
|
|
||||||
*/
|
|
||||||
void dat_crstep_xchg(union crste *crstep, union crste new, gfn_t gfn, union asce asce)
|
|
||||||
{
|
|
||||||
if (crstep->h.i) {
|
|
||||||
WRITE_ONCE(*crstep, new);
|
|
||||||
return;
|
|
||||||
} else if (cpu_has_edat2()) {
|
|
||||||
crdte_crste(crstep, *crstep, new, gfn, asce);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (machine_has_tlb_guest())
|
|
||||||
idte_crste(crstep, gfn, IDTE_GUEST_ASCE, asce, IDTE_GLOBAL);
|
|
||||||
else
|
|
||||||
idte_crste(crstep, gfn, 0, NULL_ASCE, IDTE_GLOBAL);
|
|
||||||
WRITE_ONCE(*crstep, new);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dat_crstep_xchg_atomic() - Atomically exchange a gmap CRSTE with another.
|
* dat_crstep_xchg_atomic() - Atomically exchange a gmap CRSTE with another.
|
||||||
* @crstep: Pointer to the CRST entry.
|
* @crstep: Pointer to the CRST entry.
|
||||||
@@ -175,8 +149,8 @@ void dat_crstep_xchg(union crste *crstep, union crste new, gfn_t gfn, union asce
|
|||||||
*
|
*
|
||||||
* Return: %true if the exchange was successful.
|
* Return: %true if the exchange was successful.
|
||||||
*/
|
*/
|
||||||
bool dat_crstep_xchg_atomic(union crste *crstep, union crste old, union crste new, gfn_t gfn,
|
bool __must_check dat_crstep_xchg_atomic(union crste *crstep, union crste old, union crste new,
|
||||||
union asce asce)
|
gfn_t gfn, union asce asce)
|
||||||
{
|
{
|
||||||
if (old.h.i)
|
if (old.h.i)
|
||||||
return arch_try_cmpxchg((long *)crstep, &old.val, new.val);
|
return arch_try_cmpxchg((long *)crstep, &old.val, new.val);
|
||||||
@@ -292,6 +266,7 @@ static int dat_split_ste(struct kvm_s390_mmu_cache *mc, union pmd *pmdp, gfn_t g
|
|||||||
pt->ptes[i].val = init.val | i * PAGE_SIZE;
|
pt->ptes[i].val = init.val | i * PAGE_SIZE;
|
||||||
/* No need to take locks as the page table is not installed yet. */
|
/* No need to take locks as the page table is not installed yet. */
|
||||||
pgste_init.prefix_notif = old.s.fc1.prefix_notif;
|
pgste_init.prefix_notif = old.s.fc1.prefix_notif;
|
||||||
|
pgste_init.vsie_notif = old.s.fc1.vsie_notif;
|
||||||
pgste_init.pcl = uses_skeys && init.h.i;
|
pgste_init.pcl = uses_skeys && init.h.i;
|
||||||
dat_init_pgstes(pt, pgste_init.val);
|
dat_init_pgstes(pt, pgste_init.val);
|
||||||
} else {
|
} else {
|
||||||
@@ -893,7 +868,8 @@ static long _dat_slot_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct d
|
|||||||
|
|
||||||
/* This table entry needs to be updated. */
|
/* This table entry needs to be updated. */
|
||||||
if (walk->start <= gfn && walk->end >= next) {
|
if (walk->start <= gfn && walk->end >= next) {
|
||||||
dat_crstep_xchg_atomic(crstep, crste, new_crste, gfn, walk->asce);
|
if (!dat_crstep_xchg_atomic(crstep, crste, new_crste, gfn, walk->asce))
|
||||||
|
return -EINVAL;
|
||||||
/* A lower level table was present, needs to be freed. */
|
/* A lower level table was present, needs to be freed. */
|
||||||
if (!crste.h.fc && !crste.h.i) {
|
if (!crste.h.fc && !crste.h.i) {
|
||||||
if (is_pmd(crste))
|
if (is_pmd(crste))
|
||||||
@@ -1021,67 +997,21 @@ bool dat_test_age_gfn(union asce asce, gfn_t start, gfn_t end)
|
|||||||
return _dat_walk_gfn_range(start, end, asce, &test_age_ops, 0, NULL) > 0;
|
return _dat_walk_gfn_range(start, end, asce, &test_age_ops, 0, NULL) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dat_link(struct kvm_s390_mmu_cache *mc, union asce asce, int level,
|
|
||||||
bool uses_skeys, struct guest_fault *f)
|
|
||||||
{
|
|
||||||
union crste oldval, newval;
|
|
||||||
union pte newpte, oldpte;
|
|
||||||
union pgste pgste;
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
rc = dat_entry_walk(mc, f->gfn, asce, DAT_WALK_ALLOC_CONTINUE, level, &f->crstep, &f->ptep);
|
|
||||||
if (rc == -EINVAL || rc == -ENOMEM)
|
|
||||||
return rc;
|
|
||||||
if (rc)
|
|
||||||
return -EAGAIN;
|
|
||||||
|
|
||||||
if (WARN_ON_ONCE(unlikely(get_level(f->crstep, f->ptep) > level)))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (f->ptep) {
|
|
||||||
pgste = pgste_get_lock(f->ptep);
|
|
||||||
oldpte = *f->ptep;
|
|
||||||
newpte = _pte(f->pfn, f->writable, f->write_attempt | oldpte.s.d, !f->page);
|
|
||||||
newpte.s.sd = oldpte.s.sd;
|
|
||||||
oldpte.s.sd = 0;
|
|
||||||
if (oldpte.val == _PTE_EMPTY.val || oldpte.h.pfra == f->pfn) {
|
|
||||||
pgste = __dat_ptep_xchg(f->ptep, pgste, newpte, f->gfn, asce, uses_skeys);
|
|
||||||
if (f->callback)
|
|
||||||
f->callback(f);
|
|
||||||
} else {
|
|
||||||
rc = -EAGAIN;
|
|
||||||
}
|
|
||||||
pgste_set_unlock(f->ptep, pgste);
|
|
||||||
} else {
|
|
||||||
oldval = READ_ONCE(*f->crstep);
|
|
||||||
newval = _crste_fc1(f->pfn, oldval.h.tt, f->writable,
|
|
||||||
f->write_attempt | oldval.s.fc1.d);
|
|
||||||
newval.s.fc1.sd = oldval.s.fc1.sd;
|
|
||||||
if (oldval.val != _CRSTE_EMPTY(oldval.h.tt).val &&
|
|
||||||
crste_origin_large(oldval) != crste_origin_large(newval))
|
|
||||||
return -EAGAIN;
|
|
||||||
if (!dat_crstep_xchg_atomic(f->crstep, oldval, newval, f->gfn, asce))
|
|
||||||
return -EAGAIN;
|
|
||||||
if (f->callback)
|
|
||||||
f->callback(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long dat_set_pn_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
static long dat_set_pn_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
||||||
{
|
{
|
||||||
union crste crste = READ_ONCE(*crstep);
|
union crste newcrste, oldcrste;
|
||||||
int *n = walk->priv;
|
int *n = walk->priv;
|
||||||
|
|
||||||
if (!crste.h.fc || crste.h.i || crste.h.p)
|
do {
|
||||||
return 0;
|
oldcrste = READ_ONCE(*crstep);
|
||||||
|
if (!oldcrste.h.fc || oldcrste.h.i || oldcrste.h.p)
|
||||||
|
return 0;
|
||||||
|
if (oldcrste.s.fc1.prefix_notif)
|
||||||
|
break;
|
||||||
|
newcrste = oldcrste;
|
||||||
|
newcrste.s.fc1.prefix_notif = 1;
|
||||||
|
} while (!dat_crstep_xchg_atomic(crstep, oldcrste, newcrste, gfn, walk->asce));
|
||||||
*n = 2;
|
*n = 2;
|
||||||
if (crste.s.fc1.prefix_notif)
|
|
||||||
return 0;
|
|
||||||
crste.s.fc1.prefix_notif = 1;
|
|
||||||
dat_crstep_xchg(crstep, crste, gfn, walk->asce);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -160,14 +160,14 @@ union pmd {
|
|||||||
unsigned long :44; /* HW */
|
unsigned long :44; /* HW */
|
||||||
unsigned long : 3; /* Unused */
|
unsigned long : 3; /* Unused */
|
||||||
unsigned long : 1; /* HW */
|
unsigned long : 1; /* HW */
|
||||||
|
unsigned long s : 1; /* Special */
|
||||||
unsigned long w : 1; /* Writable soft-bit */
|
unsigned long w : 1; /* Writable soft-bit */
|
||||||
unsigned long r : 1; /* Readable soft-bit */
|
unsigned long r : 1; /* Readable soft-bit */
|
||||||
unsigned long d : 1; /* Dirty */
|
unsigned long d : 1; /* Dirty */
|
||||||
unsigned long y : 1; /* Young */
|
unsigned long y : 1; /* Young */
|
||||||
unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
|
|
||||||
unsigned long : 3; /* HW */
|
unsigned long : 3; /* HW */
|
||||||
|
unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
|
||||||
unsigned long vsie_notif : 1; /* Referenced in a shadow table */
|
unsigned long vsie_notif : 1; /* Referenced in a shadow table */
|
||||||
unsigned long : 1; /* Unused */
|
|
||||||
unsigned long : 4; /* HW */
|
unsigned long : 4; /* HW */
|
||||||
unsigned long sd : 1; /* Soft-Dirty */
|
unsigned long sd : 1; /* Soft-Dirty */
|
||||||
unsigned long pr : 1; /* Present */
|
unsigned long pr : 1; /* Present */
|
||||||
@@ -183,14 +183,14 @@ union pud {
|
|||||||
unsigned long :33; /* HW */
|
unsigned long :33; /* HW */
|
||||||
unsigned long :14; /* Unused */
|
unsigned long :14; /* Unused */
|
||||||
unsigned long : 1; /* HW */
|
unsigned long : 1; /* HW */
|
||||||
|
unsigned long s : 1; /* Special */
|
||||||
unsigned long w : 1; /* Writable soft-bit */
|
unsigned long w : 1; /* Writable soft-bit */
|
||||||
unsigned long r : 1; /* Readable soft-bit */
|
unsigned long r : 1; /* Readable soft-bit */
|
||||||
unsigned long d : 1; /* Dirty */
|
unsigned long d : 1; /* Dirty */
|
||||||
unsigned long y : 1; /* Young */
|
unsigned long y : 1; /* Young */
|
||||||
unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
|
|
||||||
unsigned long : 3; /* HW */
|
unsigned long : 3; /* HW */
|
||||||
|
unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
|
||||||
unsigned long vsie_notif : 1; /* Referenced in a shadow table */
|
unsigned long vsie_notif : 1; /* Referenced in a shadow table */
|
||||||
unsigned long : 1; /* Unused */
|
|
||||||
unsigned long : 4; /* HW */
|
unsigned long : 4; /* HW */
|
||||||
unsigned long sd : 1; /* Soft-Dirty */
|
unsigned long sd : 1; /* Soft-Dirty */
|
||||||
unsigned long pr : 1; /* Present */
|
unsigned long pr : 1; /* Present */
|
||||||
@@ -254,14 +254,14 @@ union crste {
|
|||||||
struct {
|
struct {
|
||||||
unsigned long :47;
|
unsigned long :47;
|
||||||
unsigned long : 1; /* HW (should be 0) */
|
unsigned long : 1; /* HW (should be 0) */
|
||||||
|
unsigned long s : 1; /* Special */
|
||||||
unsigned long w : 1; /* Writable */
|
unsigned long w : 1; /* Writable */
|
||||||
unsigned long r : 1; /* Readable */
|
unsigned long r : 1; /* Readable */
|
||||||
unsigned long d : 1; /* Dirty */
|
unsigned long d : 1; /* Dirty */
|
||||||
unsigned long y : 1; /* Young */
|
unsigned long y : 1; /* Young */
|
||||||
unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
|
|
||||||
unsigned long : 3; /* HW */
|
unsigned long : 3; /* HW */
|
||||||
|
unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
|
||||||
unsigned long vsie_notif : 1; /* Referenced in a shadow table */
|
unsigned long vsie_notif : 1; /* Referenced in a shadow table */
|
||||||
unsigned long : 1;
|
|
||||||
unsigned long : 4; /* HW */
|
unsigned long : 4; /* HW */
|
||||||
unsigned long sd : 1; /* Soft-Dirty */
|
unsigned long sd : 1; /* Soft-Dirty */
|
||||||
unsigned long pr : 1; /* Present */
|
unsigned long pr : 1; /* Present */
|
||||||
@@ -540,8 +540,6 @@ int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gf
|
|||||||
u16 type, u16 param);
|
u16 type, u16 param);
|
||||||
int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn);
|
int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn);
|
||||||
bool dat_test_age_gfn(union asce asce, gfn_t start, gfn_t end);
|
bool dat_test_age_gfn(union asce asce, gfn_t start, gfn_t end);
|
||||||
int dat_link(struct kvm_s390_mmu_cache *mc, union asce asce, int level,
|
|
||||||
bool uses_skeys, struct guest_fault *f);
|
|
||||||
|
|
||||||
int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state *state, bool *dirty);
|
int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state *state, bool *dirty);
|
||||||
long dat_reset_cmma(union asce asce, gfn_t start_gfn);
|
long dat_reset_cmma(union asce asce, gfn_t start_gfn);
|
||||||
@@ -938,11 +936,14 @@ static inline bool dat_pudp_xchg_atomic(union pud *pudp, union pud old, union pu
|
|||||||
return dat_crstep_xchg_atomic(_CRSTEP(pudp), _CRSTE(old), _CRSTE(new), gfn, asce);
|
return dat_crstep_xchg_atomic(_CRSTEP(pudp), _CRSTE(old), _CRSTE(new), gfn, asce);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void dat_crstep_clear(union crste *crstep, gfn_t gfn, union asce asce)
|
static inline union crste dat_crstep_clear_atomic(union crste *crstep, gfn_t gfn, union asce asce)
|
||||||
{
|
{
|
||||||
union crste newcrste = _CRSTE_EMPTY(crstep->h.tt);
|
union crste oldcrste, empty = _CRSTE_EMPTY(crstep->h.tt);
|
||||||
|
|
||||||
dat_crstep_xchg(crstep, newcrste, gfn, asce);
|
do {
|
||||||
|
oldcrste = READ_ONCE(*crstep);
|
||||||
|
} while (!dat_crstep_xchg_atomic(crstep, oldcrste, empty, gfn, asce));
|
||||||
|
return oldcrste;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int get_level(union crste *crstep, union pte *ptep)
|
static inline int get_level(union crste *crstep, union pte *ptep)
|
||||||
|
|||||||
@@ -1436,13 +1436,21 @@ static int _do_shadow_pte(struct gmap *sg, gpa_t raddr, union pte *ptep_h, union
|
|||||||
|
|
||||||
if (!pgste_get_trylock(ptep_h, &pgste))
|
if (!pgste_get_trylock(ptep_h, &pgste))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
newpte = _pte(f->pfn, f->writable, !p, 0);
|
newpte = _pte(f->pfn, f->writable, !p, ptep_h->s.s);
|
||||||
newpte.s.d |= ptep->s.d;
|
newpte.s.d |= ptep_h->s.d;
|
||||||
newpte.s.sd |= ptep->s.sd;
|
newpte.s.sd |= ptep_h->s.sd;
|
||||||
newpte.h.p &= ptep->h.p;
|
newpte.h.p &= ptep_h->h.p;
|
||||||
pgste = _gmap_ptep_xchg(sg->parent, ptep_h, newpte, pgste, f->gfn, false);
|
if (!newpte.h.p && !f->writable) {
|
||||||
pgste.vsie_notif = 1;
|
rc = -EOPNOTSUPP;
|
||||||
|
} else {
|
||||||
|
pgste = _gmap_ptep_xchg(sg->parent, ptep_h, newpte, pgste, f->gfn, false);
|
||||||
|
pgste.vsie_notif = 1;
|
||||||
|
}
|
||||||
pgste_set_unlock(ptep_h, pgste);
|
pgste_set_unlock(ptep_h, pgste);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
if (!sg->parent)
|
||||||
|
return -EAGAIN;
|
||||||
|
|
||||||
newpte = _pte(f->pfn, 0, !p, 0);
|
newpte = _pte(f->pfn, 0, !p, 0);
|
||||||
if (!pgste_get_trylock(ptep, &pgste))
|
if (!pgste_get_trylock(ptep, &pgste))
|
||||||
@@ -1456,7 +1464,7 @@ static int _do_shadow_pte(struct gmap *sg, gpa_t raddr, union pte *ptep_h, union
|
|||||||
static int _do_shadow_crste(struct gmap *sg, gpa_t raddr, union crste *host, union crste *table,
|
static int _do_shadow_crste(struct gmap *sg, gpa_t raddr, union crste *host, union crste *table,
|
||||||
struct guest_fault *f, bool p)
|
struct guest_fault *f, bool p)
|
||||||
{
|
{
|
||||||
union crste newcrste;
|
union crste newcrste, oldcrste;
|
||||||
gfn_t gfn;
|
gfn_t gfn;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -1469,16 +1477,28 @@ static int _do_shadow_crste(struct gmap *sg, gpa_t raddr, union crste *host, uni
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
newcrste = _crste_fc1(f->pfn, host->h.tt, f->writable, !p);
|
do {
|
||||||
newcrste.s.fc1.d |= host->s.fc1.d;
|
/* _gmap_crstep_xchg_atomic() could have unshadowed this shadow gmap */
|
||||||
newcrste.s.fc1.sd |= host->s.fc1.sd;
|
if (!sg->parent)
|
||||||
newcrste.h.p &= host->h.p;
|
return -EAGAIN;
|
||||||
newcrste.s.fc1.vsie_notif = 1;
|
oldcrste = READ_ONCE(*host);
|
||||||
newcrste.s.fc1.prefix_notif = host->s.fc1.prefix_notif;
|
newcrste = _crste_fc1(f->pfn, oldcrste.h.tt, f->writable, !p);
|
||||||
_gmap_crstep_xchg(sg->parent, host, newcrste, f->gfn, false);
|
newcrste.s.fc1.d |= oldcrste.s.fc1.d;
|
||||||
|
newcrste.s.fc1.sd |= oldcrste.s.fc1.sd;
|
||||||
|
newcrste.h.p &= oldcrste.h.p;
|
||||||
|
newcrste.s.fc1.vsie_notif = 1;
|
||||||
|
newcrste.s.fc1.prefix_notif = oldcrste.s.fc1.prefix_notif;
|
||||||
|
newcrste.s.fc1.s = oldcrste.s.fc1.s;
|
||||||
|
if (!newcrste.h.p && !f->writable)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
} while (!_gmap_crstep_xchg_atomic(sg->parent, host, oldcrste, newcrste, f->gfn, false));
|
||||||
|
if (!sg->parent)
|
||||||
|
return -EAGAIN;
|
||||||
|
|
||||||
newcrste = _crste_fc1(f->pfn, host->h.tt, 0, !p);
|
newcrste = _crste_fc1(f->pfn, oldcrste.h.tt, 0, !p);
|
||||||
dat_crstep_xchg(table, newcrste, gpa_to_gfn(raddr), sg->asce);
|
gfn = gpa_to_gfn(raddr);
|
||||||
|
while (!dat_crstep_xchg_atomic(table, READ_ONCE(*table), newcrste, gfn, sg->asce))
|
||||||
|
;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1502,21 +1522,31 @@ static int _gaccess_do_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *sg,
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* A race occourred. The shadow mapping is already valid, nothing to do */
|
/* A race occurred. The shadow mapping is already valid, nothing to do */
|
||||||
if ((ptep && !ptep->h.i) || (!ptep && crste_leaf(*table)))
|
if ((ptep && !ptep->h.i && ptep->h.p == w->p) ||
|
||||||
|
(!ptep && crste_leaf(*table) && !table->h.i && table->h.p == w->p))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
gl = get_level(table, ptep);
|
gl = get_level(table, ptep);
|
||||||
|
|
||||||
|
/* In case of a real address space */
|
||||||
|
if (w->level <= LEVEL_MEM) {
|
||||||
|
l = TABLE_TYPE_PAGE_TABLE;
|
||||||
|
hl = TABLE_TYPE_REGION1;
|
||||||
|
goto real_address_space;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip levels that are already protected. For each level, protect
|
* Skip levels that are already protected. For each level, protect
|
||||||
* only the page containing the entry, not the whole table.
|
* only the page containing the entry, not the whole table.
|
||||||
*/
|
*/
|
||||||
for (i = gl ; i >= w->level; i--) {
|
for (i = gl ; i >= w->level; i--) {
|
||||||
rc = gmap_protect_rmap(mc, sg, entries[i - 1].gfn, gpa_to_gfn(saddr),
|
rc = gmap_protect_rmap(mc, sg, entries[i].gfn, gpa_to_gfn(saddr),
|
||||||
entries[i - 1].pfn, i, entries[i - 1].writable);
|
entries[i].pfn, i + 1, entries[i].writable);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
if (!sg->parent)
|
||||||
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = dat_entry_walk(NULL, entries[LEVEL_MEM].gfn, sg->parent->asce, DAT_WALK_LEAF,
|
rc = dat_entry_walk(NULL, entries[LEVEL_MEM].gfn, sg->parent->asce, DAT_WALK_LEAF,
|
||||||
@@ -1528,6 +1558,7 @@ static int _gaccess_do_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *sg,
|
|||||||
/* Get the smallest granularity */
|
/* Get the smallest granularity */
|
||||||
l = min3(gl, hl, w->level);
|
l = min3(gl, hl, w->level);
|
||||||
|
|
||||||
|
real_address_space:
|
||||||
flags = DAT_WALK_SPLIT_ALLOC | (uses_skeys(sg->parent) ? DAT_WALK_USES_SKEYS : 0);
|
flags = DAT_WALK_SPLIT_ALLOC | (uses_skeys(sg->parent) ? DAT_WALK_USES_SKEYS : 0);
|
||||||
/* If necessary, create the shadow mapping */
|
/* If necessary, create the shadow mapping */
|
||||||
if (l < gl) {
|
if (l < gl) {
|
||||||
|
|||||||
@@ -313,13 +313,16 @@ static long gmap_clear_young_crste(union crste *crstep, gfn_t gfn, gfn_t end, st
|
|||||||
struct clear_young_pte_priv *priv = walk->priv;
|
struct clear_young_pte_priv *priv = walk->priv;
|
||||||
union crste crste, new;
|
union crste crste, new;
|
||||||
|
|
||||||
crste = READ_ONCE(*crstep);
|
do {
|
||||||
|
crste = READ_ONCE(*crstep);
|
||||||
|
|
||||||
|
if (!crste.h.fc)
|
||||||
|
return 0;
|
||||||
|
if (!crste.s.fc1.y && crste.h.i)
|
||||||
|
return 0;
|
||||||
|
if (crste_prefix(crste) && !gmap_mkold_prefix(priv->gmap, gfn, end))
|
||||||
|
break;
|
||||||
|
|
||||||
if (!crste.h.fc)
|
|
||||||
return 0;
|
|
||||||
if (!crste.s.fc1.y && crste.h.i)
|
|
||||||
return 0;
|
|
||||||
if (!crste_prefix(crste) || gmap_mkold_prefix(priv->gmap, gfn, end)) {
|
|
||||||
new = crste;
|
new = crste;
|
||||||
new.h.i = 1;
|
new.h.i = 1;
|
||||||
new.s.fc1.y = 0;
|
new.s.fc1.y = 0;
|
||||||
@@ -328,8 +331,8 @@ static long gmap_clear_young_crste(union crste *crstep, gfn_t gfn, gfn_t end, st
|
|||||||
folio_set_dirty(phys_to_folio(crste_origin_large(crste)));
|
folio_set_dirty(phys_to_folio(crste_origin_large(crste)));
|
||||||
new.s.fc1.d = 0;
|
new.s.fc1.d = 0;
|
||||||
new.h.p = 1;
|
new.h.p = 1;
|
||||||
dat_crstep_xchg(crstep, new, gfn, walk->asce);
|
} while (!dat_crstep_xchg_atomic(crstep, crste, new, gfn, walk->asce));
|
||||||
}
|
|
||||||
priv->young = 1;
|
priv->young = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -391,14 +394,18 @@ static long _gmap_unmap_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct
|
|||||||
{
|
{
|
||||||
struct gmap_unmap_priv *priv = walk->priv;
|
struct gmap_unmap_priv *priv = walk->priv;
|
||||||
struct folio *folio = NULL;
|
struct folio *folio = NULL;
|
||||||
|
union crste old = *crstep;
|
||||||
|
|
||||||
if (crstep->h.fc) {
|
if (!old.h.fc)
|
||||||
if (crstep->s.fc1.pr && test_bit(GMAP_FLAG_EXPORT_ON_UNMAP, &priv->gmap->flags))
|
return 0;
|
||||||
folio = phys_to_folio(crste_origin_large(*crstep));
|
|
||||||
gmap_crstep_xchg(priv->gmap, crstep, _CRSTE_EMPTY(crstep->h.tt), gfn);
|
if (old.s.fc1.pr && test_bit(GMAP_FLAG_EXPORT_ON_UNMAP, &priv->gmap->flags))
|
||||||
if (folio)
|
folio = phys_to_folio(crste_origin_large(old));
|
||||||
uv_convert_from_secure_folio(folio);
|
/* No races should happen because kvm->mmu_lock is held in write mode */
|
||||||
}
|
KVM_BUG_ON(!gmap_crstep_xchg_atomic(priv->gmap, crstep, old, _CRSTE_EMPTY(old.h.tt), gfn),
|
||||||
|
priv->gmap->kvm);
|
||||||
|
if (folio)
|
||||||
|
uv_convert_from_secure_folio(folio);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -474,23 +481,24 @@ static long _crste_test_and_clear_softdirty(union crste *table, gfn_t gfn, gfn_t
|
|||||||
|
|
||||||
if (fatal_signal_pending(current))
|
if (fatal_signal_pending(current))
|
||||||
return 1;
|
return 1;
|
||||||
crste = READ_ONCE(*table);
|
do {
|
||||||
if (!crste.h.fc)
|
crste = READ_ONCE(*table);
|
||||||
return 0;
|
if (!crste.h.fc)
|
||||||
if (crste.h.p && !crste.s.fc1.sd)
|
return 0;
|
||||||
return 0;
|
if (crste.h.p && !crste.s.fc1.sd)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this large page contains one or more prefixes of vCPUs that are
|
* If this large page contains one or more prefixes of vCPUs that are
|
||||||
* currently running, do not reset the protection, leave it marked as
|
* currently running, do not reset the protection, leave it marked as
|
||||||
* dirty.
|
* dirty.
|
||||||
*/
|
*/
|
||||||
if (!crste.s.fc1.prefix_notif || gmap_mkold_prefix(gmap, gfn, end)) {
|
if (crste.s.fc1.prefix_notif && !gmap_mkold_prefix(gmap, gfn, end))
|
||||||
|
break;
|
||||||
new = crste;
|
new = crste;
|
||||||
new.h.p = 1;
|
new.h.p = 1;
|
||||||
new.s.fc1.sd = 0;
|
new.s.fc1.sd = 0;
|
||||||
gmap_crstep_xchg(gmap, table, new, gfn);
|
} while (!gmap_crstep_xchg_atomic(gmap, table, crste, new, gfn));
|
||||||
}
|
|
||||||
|
|
||||||
for ( ; gfn < end; gfn++)
|
for ( ; gfn < end; gfn++)
|
||||||
mark_page_dirty(gmap->kvm, gfn);
|
mark_page_dirty(gmap->kvm, gfn);
|
||||||
@@ -511,7 +519,7 @@ void gmap_sync_dirty_log(struct gmap *gmap, gfn_t start, gfn_t end)
|
|||||||
_dat_walk_gfn_range(start, end, gmap->asce, &walk_ops, 0, gmap);
|
_dat_walk_gfn_range(start, end, gmap->asce, &walk_ops, 0, gmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gmap_handle_minor_crste_fault(union asce asce, struct guest_fault *f)
|
static int gmap_handle_minor_crste_fault(struct gmap *gmap, struct guest_fault *f)
|
||||||
{
|
{
|
||||||
union crste newcrste, oldcrste = READ_ONCE(*f->crstep);
|
union crste newcrste, oldcrste = READ_ONCE(*f->crstep);
|
||||||
|
|
||||||
@@ -536,10 +544,8 @@ static int gmap_handle_minor_crste_fault(union asce asce, struct guest_fault *f)
|
|||||||
newcrste.s.fc1.d = 1;
|
newcrste.s.fc1.d = 1;
|
||||||
newcrste.s.fc1.sd = 1;
|
newcrste.s.fc1.sd = 1;
|
||||||
}
|
}
|
||||||
if (!oldcrste.s.fc1.d && newcrste.s.fc1.d)
|
|
||||||
SetPageDirty(phys_to_page(crste_origin_large(newcrste)));
|
|
||||||
/* In case of races, let the slow path deal with it. */
|
/* In case of races, let the slow path deal with it. */
|
||||||
return !dat_crstep_xchg_atomic(f->crstep, oldcrste, newcrste, f->gfn, asce);
|
return !gmap_crstep_xchg_atomic(gmap, f->crstep, oldcrste, newcrste, f->gfn);
|
||||||
}
|
}
|
||||||
/* Trying to write on a read-only page, let the slow path deal with it. */
|
/* Trying to write on a read-only page, let the slow path deal with it. */
|
||||||
return 1;
|
return 1;
|
||||||
@@ -568,8 +574,6 @@ static int _gmap_handle_minor_pte_fault(struct gmap *gmap, union pgste *pgste,
|
|||||||
newpte.s.d = 1;
|
newpte.s.d = 1;
|
||||||
newpte.s.sd = 1;
|
newpte.s.sd = 1;
|
||||||
}
|
}
|
||||||
if (!oldpte.s.d && newpte.s.d)
|
|
||||||
SetPageDirty(pfn_to_page(newpte.h.pfra));
|
|
||||||
*pgste = gmap_ptep_xchg(gmap, f->ptep, newpte, *pgste, f->gfn);
|
*pgste = gmap_ptep_xchg(gmap, f->ptep, newpte, *pgste, f->gfn);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -606,7 +610,7 @@ int gmap_try_fixup_minor(struct gmap *gmap, struct guest_fault *fault)
|
|||||||
fault->callback(fault);
|
fault->callback(fault);
|
||||||
pgste_set_unlock(fault->ptep, pgste);
|
pgste_set_unlock(fault->ptep, pgste);
|
||||||
} else {
|
} else {
|
||||||
rc = gmap_handle_minor_crste_fault(gmap->asce, fault);
|
rc = gmap_handle_minor_crste_fault(gmap, fault);
|
||||||
if (!rc && fault->callback)
|
if (!rc && fault->callback)
|
||||||
fault->callback(fault);
|
fault->callback(fault);
|
||||||
}
|
}
|
||||||
@@ -623,10 +627,61 @@ static inline bool gmap_1m_allowed(struct gmap *gmap, gfn_t gfn)
|
|||||||
return test_bit(GMAP_FLAG_ALLOW_HPAGE_1M, &gmap->flags);
|
return test_bit(GMAP_FLAG_ALLOW_HPAGE_1M, &gmap->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, int level,
|
||||||
|
struct guest_fault *f)
|
||||||
|
{
|
||||||
|
union crste oldval, newval;
|
||||||
|
union pte newpte, oldpte;
|
||||||
|
union pgste pgste;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
rc = dat_entry_walk(mc, f->gfn, gmap->asce, DAT_WALK_ALLOC_CONTINUE, level,
|
||||||
|
&f->crstep, &f->ptep);
|
||||||
|
if (rc == -ENOMEM)
|
||||||
|
return rc;
|
||||||
|
if (KVM_BUG_ON(rc == -EINVAL, gmap->kvm))
|
||||||
|
return rc;
|
||||||
|
if (rc)
|
||||||
|
return -EAGAIN;
|
||||||
|
if (KVM_BUG_ON(get_level(f->crstep, f->ptep) > level, gmap->kvm))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (f->ptep) {
|
||||||
|
pgste = pgste_get_lock(f->ptep);
|
||||||
|
oldpte = *f->ptep;
|
||||||
|
newpte = _pte(f->pfn, f->writable, f->write_attempt | oldpte.s.d, !f->page);
|
||||||
|
newpte.s.sd = oldpte.s.sd;
|
||||||
|
oldpte.s.sd = 0;
|
||||||
|
if (oldpte.val == _PTE_EMPTY.val || oldpte.h.pfra == f->pfn) {
|
||||||
|
pgste = gmap_ptep_xchg(gmap, f->ptep, newpte, pgste, f->gfn);
|
||||||
|
if (f->callback)
|
||||||
|
f->callback(f);
|
||||||
|
} else {
|
||||||
|
rc = -EAGAIN;
|
||||||
|
}
|
||||||
|
pgste_set_unlock(f->ptep, pgste);
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
oldval = READ_ONCE(*f->crstep);
|
||||||
|
newval = _crste_fc1(f->pfn, oldval.h.tt, f->writable,
|
||||||
|
f->write_attempt | oldval.s.fc1.d);
|
||||||
|
newval.s.fc1.s = !f->page;
|
||||||
|
newval.s.fc1.sd = oldval.s.fc1.sd;
|
||||||
|
if (oldval.val != _CRSTE_EMPTY(oldval.h.tt).val &&
|
||||||
|
crste_origin_large(oldval) != crste_origin_large(newval))
|
||||||
|
return -EAGAIN;
|
||||||
|
} while (!gmap_crstep_xchg_atomic(gmap, f->crstep, oldval, newval, f->gfn));
|
||||||
|
if (f->callback)
|
||||||
|
f->callback(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
int gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, struct guest_fault *f)
|
int gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, struct guest_fault *f)
|
||||||
{
|
{
|
||||||
unsigned int order;
|
unsigned int order;
|
||||||
int rc, level;
|
int level;
|
||||||
|
|
||||||
lockdep_assert_held(&gmap->kvm->mmu_lock);
|
lockdep_assert_held(&gmap->kvm->mmu_lock);
|
||||||
|
|
||||||
@@ -638,16 +693,14 @@ int gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, struct guest_fau
|
|||||||
else if (order >= get_order(_SEGMENT_SIZE) && gmap_1m_allowed(gmap, f->gfn))
|
else if (order >= get_order(_SEGMENT_SIZE) && gmap_1m_allowed(gmap, f->gfn))
|
||||||
level = TABLE_TYPE_SEGMENT;
|
level = TABLE_TYPE_SEGMENT;
|
||||||
}
|
}
|
||||||
rc = dat_link(mc, gmap->asce, level, uses_skeys(gmap), f);
|
return _gmap_link(mc, gmap, level, f);
|
||||||
KVM_BUG_ON(rc == -EINVAL, gmap->kvm);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gmap_ucas_map_one(struct kvm_s390_mmu_cache *mc, struct gmap *gmap,
|
static int gmap_ucas_map_one(struct kvm_s390_mmu_cache *mc, struct gmap *gmap,
|
||||||
gfn_t p_gfn, gfn_t c_gfn, bool force_alloc)
|
gfn_t p_gfn, gfn_t c_gfn, bool force_alloc)
|
||||||
{
|
{
|
||||||
|
union crste newcrste, oldcrste;
|
||||||
struct page_table *pt;
|
struct page_table *pt;
|
||||||
union crste newcrste;
|
|
||||||
union crste *crstep;
|
union crste *crstep;
|
||||||
union pte *ptep;
|
union pte *ptep;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -673,7 +726,11 @@ static int gmap_ucas_map_one(struct kvm_s390_mmu_cache *mc, struct gmap *gmap,
|
|||||||
&crstep, &ptep);
|
&crstep, &ptep);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
dat_crstep_xchg(crstep, newcrste, c_gfn, gmap->asce);
|
do {
|
||||||
|
oldcrste = READ_ONCE(*crstep);
|
||||||
|
if (oldcrste.val == newcrste.val)
|
||||||
|
break;
|
||||||
|
} while (!dat_crstep_xchg_atomic(crstep, oldcrste, newcrste, c_gfn, gmap->asce));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -777,8 +834,10 @@ static void gmap_ucas_unmap_one(struct gmap *gmap, gfn_t c_gfn)
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = dat_entry_walk(NULL, c_gfn, gmap->asce, 0, TABLE_TYPE_SEGMENT, &crstep, &ptep);
|
rc = dat_entry_walk(NULL, c_gfn, gmap->asce, 0, TABLE_TYPE_SEGMENT, &crstep, &ptep);
|
||||||
if (!rc)
|
if (rc)
|
||||||
dat_crstep_xchg(crstep, _PMD_EMPTY, c_gfn, gmap->asce);
|
return;
|
||||||
|
while (!dat_crstep_xchg_atomic(crstep, READ_ONCE(*crstep), _PMD_EMPTY, c_gfn, gmap->asce))
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gmap_ucas_unmap(struct gmap *gmap, gfn_t c_gfn, unsigned long count)
|
void gmap_ucas_unmap(struct gmap *gmap, gfn_t c_gfn, unsigned long count)
|
||||||
@@ -1017,8 +1076,8 @@ static void gmap_unshadow_level(struct gmap *sg, gfn_t r_gfn, int level)
|
|||||||
dat_ptep_xchg(ptep, _PTE_EMPTY, r_gfn, sg->asce, uses_skeys(sg));
|
dat_ptep_xchg(ptep, _PTE_EMPTY, r_gfn, sg->asce, uses_skeys(sg));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
crste = READ_ONCE(*crstep);
|
|
||||||
dat_crstep_clear(crstep, r_gfn, sg->asce);
|
crste = dat_crstep_clear_atomic(crstep, r_gfn, sg->asce);
|
||||||
if (crste_leaf(crste) || crste.h.i)
|
if (crste_leaf(crste) || crste.h.i)
|
||||||
return;
|
return;
|
||||||
if (is_pmd(crste))
|
if (is_pmd(crste))
|
||||||
@@ -1101,6 +1160,7 @@ struct gmap_protect_asce_top_level {
|
|||||||
static inline int __gmap_protect_asce_top_level(struct kvm_s390_mmu_cache *mc, struct gmap *sg,
|
static inline int __gmap_protect_asce_top_level(struct kvm_s390_mmu_cache *mc, struct gmap *sg,
|
||||||
struct gmap_protect_asce_top_level *context)
|
struct gmap_protect_asce_top_level *context)
|
||||||
{
|
{
|
||||||
|
struct gmap *parent;
|
||||||
int rc, i;
|
int rc, i;
|
||||||
|
|
||||||
guard(write_lock)(&sg->kvm->mmu_lock);
|
guard(write_lock)(&sg->kvm->mmu_lock);
|
||||||
@@ -1108,7 +1168,12 @@ static inline int __gmap_protect_asce_top_level(struct kvm_s390_mmu_cache *mc, s
|
|||||||
if (kvm_s390_array_needs_retry_safe(sg->kvm, context->seq, context->f))
|
if (kvm_s390_array_needs_retry_safe(sg->kvm, context->seq, context->f))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
scoped_guard(spinlock, &sg->parent->children_lock) {
|
parent = READ_ONCE(sg->parent);
|
||||||
|
if (!parent)
|
||||||
|
return -EAGAIN;
|
||||||
|
scoped_guard(spinlock, &parent->children_lock) {
|
||||||
|
if (READ_ONCE(sg->parent) != parent)
|
||||||
|
return -EAGAIN;
|
||||||
for (i = 0; i < CRST_TABLE_PAGES; i++) {
|
for (i = 0; i < CRST_TABLE_PAGES; i++) {
|
||||||
if (!context->f[i].valid)
|
if (!context->f[i].valid)
|
||||||
continue;
|
continue;
|
||||||
@@ -1191,6 +1256,9 @@ struct gmap *gmap_create_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *pare
|
|||||||
struct gmap *sg, *new;
|
struct gmap *sg, *new;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
if (WARN_ON(!parent))
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
scoped_guard(spinlock, &parent->children_lock) {
|
scoped_guard(spinlock, &parent->children_lock) {
|
||||||
sg = gmap_find_shadow(parent, asce, edat_level);
|
sg = gmap_find_shadow(parent, asce, edat_level);
|
||||||
if (sg) {
|
if (sg) {
|
||||||
|
|||||||
@@ -185,6 +185,8 @@ static inline union pgste _gmap_ptep_xchg(struct gmap *gmap, union pte *ptep, un
|
|||||||
else
|
else
|
||||||
_gmap_handle_vsie_unshadow_event(gmap, gfn);
|
_gmap_handle_vsie_unshadow_event(gmap, gfn);
|
||||||
}
|
}
|
||||||
|
if (!ptep->s.d && newpte.s.d && !newpte.s.s)
|
||||||
|
SetPageDirty(pfn_to_page(newpte.h.pfra));
|
||||||
return __dat_ptep_xchg(ptep, pgste, newpte, gfn, gmap->asce, uses_skeys(gmap));
|
return __dat_ptep_xchg(ptep, pgste, newpte, gfn, gmap->asce, uses_skeys(gmap));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,35 +196,42 @@ static inline union pgste gmap_ptep_xchg(struct gmap *gmap, union pte *ptep, uni
|
|||||||
return _gmap_ptep_xchg(gmap, ptep, newpte, pgste, gfn, true);
|
return _gmap_ptep_xchg(gmap, ptep, newpte, pgste, gfn, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _gmap_crstep_xchg(struct gmap *gmap, union crste *crstep, union crste ne,
|
static inline bool __must_check _gmap_crstep_xchg_atomic(struct gmap *gmap, union crste *crstep,
|
||||||
gfn_t gfn, bool needs_lock)
|
union crste oldcrste, union crste newcrste,
|
||||||
|
gfn_t gfn, bool needs_lock)
|
||||||
{
|
{
|
||||||
unsigned long align = 8 + (is_pmd(*crstep) ? 0 : 11);
|
unsigned long align = is_pmd(newcrste) ? _PAGE_ENTRIES : _PAGE_ENTRIES * _CRST_ENTRIES;
|
||||||
|
|
||||||
|
if (KVM_BUG_ON(crstep->h.tt != oldcrste.h.tt || newcrste.h.tt != oldcrste.h.tt, gmap->kvm))
|
||||||
|
return true;
|
||||||
|
|
||||||
lockdep_assert_held(&gmap->kvm->mmu_lock);
|
lockdep_assert_held(&gmap->kvm->mmu_lock);
|
||||||
if (!needs_lock)
|
if (!needs_lock)
|
||||||
lockdep_assert_held(&gmap->children_lock);
|
lockdep_assert_held(&gmap->children_lock);
|
||||||
|
|
||||||
gfn = ALIGN_DOWN(gfn, align);
|
gfn = ALIGN_DOWN(gfn, align);
|
||||||
if (crste_prefix(*crstep) && (ne.h.p || ne.h.i || !crste_prefix(ne))) {
|
if (crste_prefix(oldcrste) && (newcrste.h.p || newcrste.h.i || !crste_prefix(newcrste))) {
|
||||||
ne.s.fc1.prefix_notif = 0;
|
newcrste.s.fc1.prefix_notif = 0;
|
||||||
gmap_unmap_prefix(gmap, gfn, gfn + align);
|
gmap_unmap_prefix(gmap, gfn, gfn + align);
|
||||||
}
|
}
|
||||||
if (crste_leaf(*crstep) && crstep->s.fc1.vsie_notif &&
|
if (crste_leaf(oldcrste) && oldcrste.s.fc1.vsie_notif &&
|
||||||
(ne.h.p || ne.h.i || !ne.s.fc1.vsie_notif)) {
|
(newcrste.h.p || newcrste.h.i || !newcrste.s.fc1.vsie_notif)) {
|
||||||
ne.s.fc1.vsie_notif = 0;
|
newcrste.s.fc1.vsie_notif = 0;
|
||||||
if (needs_lock)
|
if (needs_lock)
|
||||||
gmap_handle_vsie_unshadow_event(gmap, gfn);
|
gmap_handle_vsie_unshadow_event(gmap, gfn);
|
||||||
else
|
else
|
||||||
_gmap_handle_vsie_unshadow_event(gmap, gfn);
|
_gmap_handle_vsie_unshadow_event(gmap, gfn);
|
||||||
}
|
}
|
||||||
dat_crstep_xchg(crstep, ne, gfn, gmap->asce);
|
if (!oldcrste.s.fc1.d && newcrste.s.fc1.d && !newcrste.s.fc1.s)
|
||||||
|
SetPageDirty(phys_to_page(crste_origin_large(newcrste)));
|
||||||
|
return dat_crstep_xchg_atomic(crstep, oldcrste, newcrste, gfn, gmap->asce);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gmap_crstep_xchg(struct gmap *gmap, union crste *crstep, union crste ne,
|
static inline bool __must_check gmap_crstep_xchg_atomic(struct gmap *gmap, union crste *crstep,
|
||||||
gfn_t gfn)
|
union crste oldcrste, union crste newcrste,
|
||||||
|
gfn_t gfn)
|
||||||
{
|
{
|
||||||
return _gmap_crstep_xchg(gmap, crstep, ne, gfn, true);
|
return _gmap_crstep_xchg_atomic(gmap, crstep, oldcrste, newcrste, gfn, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5520,9 +5520,21 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
case KVM_S390_VCPU_FAULT: {
|
case KVM_S390_VCPU_FAULT: {
|
||||||
idx = srcu_read_lock(&vcpu->kvm->srcu);
|
gpa_t gaddr = arg;
|
||||||
r = vcpu_dat_fault_handler(vcpu, arg, 0);
|
|
||||||
srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
scoped_guard(srcu, &vcpu->kvm->srcu) {
|
||||||
|
r = vcpu_ucontrol_translate(vcpu, &gaddr);
|
||||||
|
if (r)
|
||||||
|
break;
|
||||||
|
|
||||||
|
r = kvm_s390_faultin_gfn_simple(vcpu, NULL, gpa_to_gfn(gaddr), false);
|
||||||
|
if (r == PGM_ADDRESSING)
|
||||||
|
r = -EFAULT;
|
||||||
|
if (r <= 0)
|
||||||
|
break;
|
||||||
|
r = -EIO;
|
||||||
|
KVM_BUG_ON(r, vcpu->kvm);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case KVM_ENABLE_CAP:
|
case KVM_ENABLE_CAP:
|
||||||
|
|||||||
@@ -1328,7 +1328,7 @@ static void unregister_shadow_scb(struct kvm_vcpu *vcpu)
|
|||||||
static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
|
static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
|
||||||
{
|
{
|
||||||
struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
|
struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
|
||||||
struct gmap *sg;
|
struct gmap *sg = NULL;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -1368,6 +1368,8 @@ static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
|
|||||||
sg = gmap_put(sg);
|
sg = gmap_put(sg);
|
||||||
cond_resched();
|
cond_resched();
|
||||||
}
|
}
|
||||||
|
if (sg)
|
||||||
|
sg = gmap_put(sg);
|
||||||
|
|
||||||
if (rc == -EFAULT) {
|
if (rc == -EFAULT) {
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -121,6 +121,9 @@ noinstr struct ghcb *__sev_get_ghcb(struct ghcb_state *state)
|
|||||||
|
|
||||||
WARN_ON(!irqs_disabled());
|
WARN_ON(!irqs_disabled());
|
||||||
|
|
||||||
|
if (!sev_cfg.ghcbs_initialized)
|
||||||
|
return boot_ghcb;
|
||||||
|
|
||||||
data = this_cpu_read(runtime_data);
|
data = this_cpu_read(runtime_data);
|
||||||
ghcb = &data->ghcb_page;
|
ghcb = &data->ghcb_page;
|
||||||
|
|
||||||
@@ -164,6 +167,9 @@ noinstr void __sev_put_ghcb(struct ghcb_state *state)
|
|||||||
|
|
||||||
WARN_ON(!irqs_disabled());
|
WARN_ON(!irqs_disabled());
|
||||||
|
|
||||||
|
if (!sev_cfg.ghcbs_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
data = this_cpu_read(runtime_data);
|
data = this_cpu_read(runtime_data);
|
||||||
ghcb = &data->ghcb_page;
|
ghcb = &data->ghcb_page;
|
||||||
|
|
||||||
|
|||||||
@@ -177,6 +177,16 @@ static noinstr void fred_extint(struct pt_regs *regs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_AMD_MEM_ENCRYPT
|
||||||
|
noinstr void exc_vmm_communication(struct pt_regs *regs, unsigned long error_code)
|
||||||
|
{
|
||||||
|
if (user_mode(regs))
|
||||||
|
return user_exc_vmm_communication(regs, error_code);
|
||||||
|
else
|
||||||
|
return kernel_exc_vmm_communication(regs, error_code);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static noinstr void fred_hwexc(struct pt_regs *regs, unsigned long error_code)
|
static noinstr void fred_hwexc(struct pt_regs *regs, unsigned long error_code)
|
||||||
{
|
{
|
||||||
/* Optimize for #PF. That's the only exception which matters performance wise */
|
/* Optimize for #PF. That's the only exception which matters performance wise */
|
||||||
@@ -207,6 +217,10 @@ static noinstr void fred_hwexc(struct pt_regs *regs, unsigned long error_code)
|
|||||||
#ifdef CONFIG_X86_CET
|
#ifdef CONFIG_X86_CET
|
||||||
case X86_TRAP_CP: return exc_control_protection(regs, error_code);
|
case X86_TRAP_CP: return exc_control_protection(regs, error_code);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_AMD_MEM_ENCRYPT
|
||||||
|
case X86_TRAP_VC: return exc_vmm_communication(regs, error_code);
|
||||||
|
#endif
|
||||||
|
|
||||||
default: return fred_bad_type(regs, error_code);
|
default: return fred_bad_type(regs, error_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -433,7 +433,20 @@ static __always_inline void setup_lass(struct cpuinfo_x86 *c)
|
|||||||
|
|
||||||
/* These bits should not change their value after CPU init is finished. */
|
/* These bits should not change their value after CPU init is finished. */
|
||||||
static const unsigned long cr4_pinned_mask = X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP |
|
static const unsigned long cr4_pinned_mask = X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP |
|
||||||
X86_CR4_FSGSBASE | X86_CR4_CET | X86_CR4_FRED;
|
X86_CR4_FSGSBASE | X86_CR4_CET;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The CR pinning protects against ROP on the 'mov %reg, %CRn' instruction(s).
|
||||||
|
* Since you can ROP directly to these instructions (barring shadow stack),
|
||||||
|
* any protection must follow immediately and unconditionally after that.
|
||||||
|
*
|
||||||
|
* Specifically, the CR[04] write functions below will have the value
|
||||||
|
* validation controlled by the @cr_pinning static_branch which is
|
||||||
|
* __ro_after_init, just like the cr4_pinned_bits value.
|
||||||
|
*
|
||||||
|
* Once set, an attacker will have to defeat page-tables to get around these
|
||||||
|
* restrictions. Which is a much bigger ask than 'simple' ROP.
|
||||||
|
*/
|
||||||
static DEFINE_STATIC_KEY_FALSE_RO(cr_pinning);
|
static DEFINE_STATIC_KEY_FALSE_RO(cr_pinning);
|
||||||
static unsigned long cr4_pinned_bits __ro_after_init;
|
static unsigned long cr4_pinned_bits __ro_after_init;
|
||||||
|
|
||||||
@@ -2050,12 +2063,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
|
|||||||
setup_umip(c);
|
setup_umip(c);
|
||||||
setup_lass(c);
|
setup_lass(c);
|
||||||
|
|
||||||
/* Enable FSGSBASE instructions if available. */
|
|
||||||
if (cpu_has(c, X86_FEATURE_FSGSBASE)) {
|
|
||||||
cr4_set_bits(X86_CR4_FSGSBASE);
|
|
||||||
elf_hwcap2 |= HWCAP2_FSGSBASE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The vendor-specific functions might have changed features.
|
* The vendor-specific functions might have changed features.
|
||||||
* Now we do "generic changes."
|
* Now we do "generic changes."
|
||||||
@@ -2416,6 +2423,18 @@ void cpu_init_exception_handling(bool boot_cpu)
|
|||||||
/* GHCB needs to be setup to handle #VC. */
|
/* GHCB needs to be setup to handle #VC. */
|
||||||
setup_ghcb();
|
setup_ghcb();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On CPUs with FSGSBASE support, paranoid_entry() uses
|
||||||
|
* ALTERNATIVE-patched RDGSBASE/WRGSBASE instructions. Secondary CPUs
|
||||||
|
* boot after alternatives are patched globally, so early exceptions
|
||||||
|
* execute patched code that depends on FSGSBASE. Enable the feature
|
||||||
|
* before any exceptions occur.
|
||||||
|
*/
|
||||||
|
if (cpu_feature_enabled(X86_FEATURE_FSGSBASE)) {
|
||||||
|
cr4_set_bits(X86_CR4_FSGSBASE);
|
||||||
|
elf_hwcap2 |= HWCAP2_FSGSBASE;
|
||||||
|
}
|
||||||
|
|
||||||
if (cpu_feature_enabled(X86_FEATURE_FRED)) {
|
if (cpu_feature_enabled(X86_FEATURE_FRED)) {
|
||||||
/* The boot CPU has enabled FRED during early boot */
|
/* The boot CPU has enabled FRED during early boot */
|
||||||
if (!boot_cpu)
|
if (!boot_cpu)
|
||||||
|
|||||||
@@ -3044,12 +3044,6 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot,
|
|||||||
bool prefetch = !fault || fault->prefetch;
|
bool prefetch = !fault || fault->prefetch;
|
||||||
bool write_fault = fault && fault->write;
|
bool write_fault = fault && fault->write;
|
||||||
|
|
||||||
if (unlikely(is_noslot_pfn(pfn))) {
|
|
||||||
vcpu->stat.pf_mmio_spte_created++;
|
|
||||||
mark_mmio_spte(vcpu, sptep, gfn, pte_access);
|
|
||||||
return RET_PF_EMULATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_shadow_present_pte(*sptep)) {
|
if (is_shadow_present_pte(*sptep)) {
|
||||||
if (prefetch && is_last_spte(*sptep, level) &&
|
if (prefetch && is_last_spte(*sptep, level) &&
|
||||||
pfn == spte_to_pfn(*sptep))
|
pfn == spte_to_pfn(*sptep))
|
||||||
@@ -3066,13 +3060,22 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot,
|
|||||||
child = spte_to_child_sp(pte);
|
child = spte_to_child_sp(pte);
|
||||||
drop_parent_pte(vcpu->kvm, child, sptep);
|
drop_parent_pte(vcpu->kvm, child, sptep);
|
||||||
flush = true;
|
flush = true;
|
||||||
} else if (WARN_ON_ONCE(pfn != spte_to_pfn(*sptep))) {
|
} else if (pfn != spte_to_pfn(*sptep)) {
|
||||||
|
WARN_ON_ONCE(vcpu->arch.mmu->root_role.direct);
|
||||||
drop_spte(vcpu->kvm, sptep);
|
drop_spte(vcpu->kvm, sptep);
|
||||||
flush = true;
|
flush = true;
|
||||||
} else
|
} else
|
||||||
was_rmapped = 1;
|
was_rmapped = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unlikely(is_noslot_pfn(pfn))) {
|
||||||
|
vcpu->stat.pf_mmio_spte_created++;
|
||||||
|
mark_mmio_spte(vcpu, sptep, gfn, pte_access);
|
||||||
|
if (flush)
|
||||||
|
kvm_flush_remote_tlbs_gfn(vcpu->kvm, gfn, level);
|
||||||
|
return RET_PF_EMULATE;
|
||||||
|
}
|
||||||
|
|
||||||
wrprot = make_spte(vcpu, sp, slot, pte_access, gfn, pfn, *sptep, prefetch,
|
wrprot = make_spte(vcpu, sp, slot, pte_access, gfn, pfn, *sptep, prefetch,
|
||||||
false, host_writable, &spte);
|
false, host_writable, &spte);
|
||||||
|
|
||||||
|
|||||||
@@ -424,7 +424,7 @@ void __init efi_unmap_boot_services(void)
|
|||||||
if (efi_enabled(EFI_DBG))
|
if (efi_enabled(EFI_DBG))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sz = sizeof(*ranges_to_free) * efi.memmap.nr_map + 1;
|
sz = sizeof(*ranges_to_free) * (efi.memmap.nr_map + 1);
|
||||||
ranges_to_free = kzalloc(sz, GFP_KERNEL);
|
ranges_to_free = kzalloc(sz, GFP_KERNEL);
|
||||||
if (!ranges_to_free) {
|
if (!ranges_to_free) {
|
||||||
pr_err("Failed to allocate storage for freeable EFI regions\n");
|
pr_err("Failed to allocate storage for freeable EFI regions\n");
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#define IVPU_HW_IP_60XX 60
|
#define IVPU_HW_IP_60XX 60
|
||||||
|
|
||||||
#define IVPU_HW_IP_REV_LNL_B0 4
|
#define IVPU_HW_IP_REV_LNL_B0 4
|
||||||
|
#define IVPU_HW_IP_REV_NVL_A0 0
|
||||||
|
|
||||||
#define IVPU_HW_BTRS_MTL 1
|
#define IVPU_HW_BTRS_MTL 1
|
||||||
#define IVPU_HW_BTRS_LNL 2
|
#define IVPU_HW_BTRS_LNL 2
|
||||||
|
|||||||
@@ -70,8 +70,10 @@ static void wa_init(struct ivpu_device *vdev)
|
|||||||
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
|
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
|
||||||
vdev->wa.interrupt_clear_with_0 = ivpu_hw_btrs_irqs_clear_with_0_mtl(vdev);
|
vdev->wa.interrupt_clear_with_0 = ivpu_hw_btrs_irqs_clear_with_0_mtl(vdev);
|
||||||
|
|
||||||
if (ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL &&
|
if ((ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL &&
|
||||||
ivpu_revision(vdev) < IVPU_HW_IP_REV_LNL_B0)
|
ivpu_revision(vdev) < IVPU_HW_IP_REV_LNL_B0) ||
|
||||||
|
(ivpu_device_id(vdev) == PCI_DEVICE_ID_NVL &&
|
||||||
|
ivpu_revision(vdev) == IVPU_HW_IP_REV_NVL_A0))
|
||||||
vdev->wa.disable_clock_relinquish = true;
|
vdev->wa.disable_clock_relinquish = true;
|
||||||
|
|
||||||
if (ivpu_test_mode & IVPU_TEST_MODE_CLK_RELINQ_ENABLE)
|
if (ivpu_test_mode & IVPU_TEST_MODE_CLK_RELINQ_ENABLE)
|
||||||
|
|||||||
@@ -1656,6 +1656,8 @@ static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, bool ca
|
|||||||
|
|
||||||
ret = ec_install_handlers(ec, device, call_reg);
|
ret = ec_install_handlers(ec, device, call_reg);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
ec_remove_handlers(ec);
|
||||||
|
|
||||||
if (ec == first_ec)
|
if (ec == first_ec)
|
||||||
first_ec = NULL;
|
first_ec = NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -99,8 +99,13 @@ static int lcd2s_print(struct charlcd *lcd, int c)
|
|||||||
{
|
{
|
||||||
struct lcd2s_data *lcd2s = lcd->drvdata;
|
struct lcd2s_data *lcd2s = lcd->drvdata;
|
||||||
u8 buf[2] = { LCD2S_CMD_WRITE, c };
|
u8 buf[2] = { LCD2S_CMD_WRITE, c };
|
||||||
|
int ret;
|
||||||
|
|
||||||
lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf));
|
ret = lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
if (ret != sizeof(buf))
|
||||||
|
return -EIO;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,9 +113,13 @@ static int lcd2s_gotoxy(struct charlcd *lcd, unsigned int x, unsigned int y)
|
|||||||
{
|
{
|
||||||
struct lcd2s_data *lcd2s = lcd->drvdata;
|
struct lcd2s_data *lcd2s = lcd->drvdata;
|
||||||
u8 buf[3] = { LCD2S_CMD_CUR_POS, y + 1, x + 1 };
|
u8 buf[3] = { LCD2S_CMD_CUR_POS, y + 1, x + 1 };
|
||||||
|
int ret;
|
||||||
|
|
||||||
lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf));
|
ret = lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
if (ret != sizeof(buf))
|
||||||
|
return -EIO;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ static DEFINE_IDA(linedisp_id);
|
|||||||
|
|
||||||
static void linedisp_release(struct device *dev)
|
static void linedisp_release(struct device *dev)
|
||||||
{
|
{
|
||||||
struct linedisp *linedisp = to_linedisp(dev);
|
struct linedisp *linedisp = container_of(dev, struct linedisp, dev);
|
||||||
|
|
||||||
kfree(linedisp->map);
|
kfree(linedisp->map);
|
||||||
kfree(linedisp->message);
|
kfree(linedisp->message);
|
||||||
|
|||||||
@@ -1545,6 +1545,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
|
|||||||
unsigned int val_num)
|
unsigned int val_num)
|
||||||
{
|
{
|
||||||
void *orig_work_buf;
|
void *orig_work_buf;
|
||||||
|
unsigned int selector_reg;
|
||||||
unsigned int win_offset;
|
unsigned int win_offset;
|
||||||
unsigned int win_page;
|
unsigned int win_page;
|
||||||
bool page_chg;
|
bool page_chg;
|
||||||
@@ -1563,10 +1564,31 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* It is possible to have selector register inside data window.
|
/*
|
||||||
In that case, selector register is located on every page and
|
* Calculate the address of the selector register in the corresponding
|
||||||
it needs no page switching, when accessed alone. */
|
* data window if it is located on every page.
|
||||||
|
*/
|
||||||
|
page_chg = in_range(range->selector_reg, range->window_start, range->window_len);
|
||||||
|
if (page_chg)
|
||||||
|
selector_reg = range->range_min + win_page * range->window_len +
|
||||||
|
range->selector_reg - range->window_start;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It is possible to have selector register inside data window.
|
||||||
|
* In that case, selector register is located on every page and it
|
||||||
|
* needs no page switching, when accessed alone.
|
||||||
|
*
|
||||||
|
* Nevertheless we should synchronize the cache values for it.
|
||||||
|
* This can't be properly achieved if the selector register is
|
||||||
|
* the first and the only one to be read inside the data window.
|
||||||
|
* That's why we update it in that case as well.
|
||||||
|
*
|
||||||
|
* However, we specifically avoid updating it for the default page,
|
||||||
|
* when it's overlapped with the real data window, to prevent from
|
||||||
|
* infinite looping.
|
||||||
|
*/
|
||||||
if (val_num > 1 ||
|
if (val_num > 1 ||
|
||||||
|
(page_chg && selector_reg != range->selector_reg) ||
|
||||||
range->window_start + win_offset != range->selector_reg) {
|
range->window_start + win_offset != range->selector_reg) {
|
||||||
/* Use separate work_buf during page switching */
|
/* Use separate work_buf during page switching */
|
||||||
orig_work_buf = map->work_buf;
|
orig_work_buf = map->work_buf;
|
||||||
@@ -1575,7 +1597,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
|
|||||||
ret = _regmap_update_bits(map, range->selector_reg,
|
ret = _regmap_update_bits(map, range->selector_reg,
|
||||||
range->selector_mask,
|
range->selector_mask,
|
||||||
win_page << range->selector_shift,
|
win_page << range->selector_shift,
|
||||||
&page_chg, false);
|
NULL, false);
|
||||||
|
|
||||||
map->work_buf = orig_work_buf;
|
map->work_buf = orig_work_buf;
|
||||||
|
|
||||||
|
|||||||
@@ -109,9 +109,6 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count)
|
|||||||
{
|
{
|
||||||
struct h4_struct *h4 = hu->priv;
|
struct h4_struct *h4 = hu->priv;
|
||||||
|
|
||||||
if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
|
|
||||||
return -EUNATCH;
|
|
||||||
|
|
||||||
h4->rx_skb = h4_recv_buf(hu, h4->rx_skb, data, count,
|
h4->rx_skb = h4_recv_buf(hu, h4->rx_skb, data, count,
|
||||||
h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts));
|
h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts));
|
||||||
if (IS_ERR(h4->rx_skb)) {
|
if (IS_ERR(h4->rx_skb)) {
|
||||||
|
|||||||
@@ -1427,12 +1427,9 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy,
|
|||||||
* If there is a problem with its frequency table, take it
|
* If there is a problem with its frequency table, take it
|
||||||
* offline and drop it.
|
* offline and drop it.
|
||||||
*/
|
*/
|
||||||
if (policy->freq_table_sorted != CPUFREQ_TABLE_SORTED_ASCENDING &&
|
ret = cpufreq_table_validate_and_sort(policy);
|
||||||
policy->freq_table_sorted != CPUFREQ_TABLE_SORTED_DESCENDING) {
|
if (ret)
|
||||||
ret = cpufreq_table_validate_and_sort(policy);
|
goto out_offline_policy;
|
||||||
if (ret)
|
|
||||||
goto out_offline_policy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* related_cpus should at least include policy->cpus. */
|
/* related_cpus should at least include policy->cpus. */
|
||||||
cpumask_copy(policy->related_cpus, policy->cpus);
|
cpumask_copy(policy->related_cpus, policy->cpus);
|
||||||
|
|||||||
@@ -313,6 +313,17 @@ static void cs_start(struct cpufreq_policy *policy)
|
|||||||
dbs_info->requested_freq = policy->cur;
|
dbs_info->requested_freq = policy->cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cs_limits(struct cpufreq_policy *policy)
|
||||||
|
{
|
||||||
|
struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The limits have changed, so may have the current frequency. Reset
|
||||||
|
* requested_freq to avoid any unintended outcomes due to the mismatch.
|
||||||
|
*/
|
||||||
|
dbs_info->requested_freq = policy->cur;
|
||||||
|
}
|
||||||
|
|
||||||
static struct dbs_governor cs_governor = {
|
static struct dbs_governor cs_governor = {
|
||||||
.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
|
.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
|
||||||
.kobj_type = { .default_groups = cs_groups },
|
.kobj_type = { .default_groups = cs_groups },
|
||||||
@@ -322,6 +333,7 @@ static struct dbs_governor cs_governor = {
|
|||||||
.init = cs_init,
|
.init = cs_init,
|
||||||
.exit = cs_exit,
|
.exit = cs_exit,
|
||||||
.start = cs_start,
|
.start = cs_start,
|
||||||
|
.limits = cs_limits,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CPU_FREQ_GOV_CONSERVATIVE (cs_governor.gov)
|
#define CPU_FREQ_GOV_CONSERVATIVE (cs_governor.gov)
|
||||||
|
|||||||
@@ -563,6 +563,7 @@ EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop);
|
|||||||
|
|
||||||
void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
|
void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
|
struct dbs_governor *gov = dbs_governor_of(policy);
|
||||||
struct policy_dbs_info *policy_dbs;
|
struct policy_dbs_info *policy_dbs;
|
||||||
|
|
||||||
/* Protect gov->gdbs_data against cpufreq_dbs_governor_exit() */
|
/* Protect gov->gdbs_data against cpufreq_dbs_governor_exit() */
|
||||||
@@ -574,6 +575,8 @@ void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
|
|||||||
mutex_lock(&policy_dbs->update_mutex);
|
mutex_lock(&policy_dbs->update_mutex);
|
||||||
cpufreq_policy_apply_limits(policy);
|
cpufreq_policy_apply_limits(policy);
|
||||||
gov_update_sample_delay(policy_dbs, 0);
|
gov_update_sample_delay(policy_dbs, 0);
|
||||||
|
if (gov->limits)
|
||||||
|
gov->limits(policy);
|
||||||
mutex_unlock(&policy_dbs->update_mutex);
|
mutex_unlock(&policy_dbs->update_mutex);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ struct dbs_governor {
|
|||||||
int (*init)(struct dbs_data *dbs_data);
|
int (*init)(struct dbs_data *dbs_data);
|
||||||
void (*exit)(struct dbs_data *dbs_data);
|
void (*exit)(struct dbs_data *dbs_data);
|
||||||
void (*start)(struct cpufreq_policy *policy);
|
void (*start)(struct cpufreq_policy *policy);
|
||||||
|
void (*limits)(struct cpufreq_policy *policy);
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy)
|
static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy)
|
||||||
|
|||||||
@@ -360,6 +360,10 @@ int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy)
|
|||||||
if (policy_has_boost_freq(policy))
|
if (policy_has_boost_freq(policy))
|
||||||
policy->boost_supported = true;
|
policy->boost_supported = true;
|
||||||
|
|
||||||
|
if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING ||
|
||||||
|
policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_DESCENDING)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return set_freq_table_sorted(policy);
|
return set_freq_table_sorted(policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -844,6 +844,7 @@ static int dw_edma_irq_request(struct dw_edma *dw,
|
|||||||
{
|
{
|
||||||
struct dw_edma_chip *chip = dw->chip;
|
struct dw_edma_chip *chip = dw->chip;
|
||||||
struct device *dev = dw->chip->dev;
|
struct device *dev = dw->chip->dev;
|
||||||
|
struct msi_desc *msi_desc;
|
||||||
u32 wr_mask = 1;
|
u32 wr_mask = 1;
|
||||||
u32 rd_mask = 1;
|
u32 rd_mask = 1;
|
||||||
int i, err = 0;
|
int i, err = 0;
|
||||||
@@ -895,9 +896,12 @@ static int dw_edma_irq_request(struct dw_edma *dw,
|
|||||||
&dw->irq[i]);
|
&dw->irq[i]);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_irq_free;
|
goto err_irq_free;
|
||||||
|
msi_desc = irq_get_msi_desc(irq);
|
||||||
if (irq_get_msi_desc(irq))
|
if (msi_desc) {
|
||||||
get_cached_msi_msg(irq, &dw->irq[i].msi);
|
get_cached_msi_msg(irq, &dw->irq[i].msi);
|
||||||
|
if (!msi_desc->pci.msi_attrib.is_msix)
|
||||||
|
dw->irq[i].msi.data = dw->irq[0].msi.data + i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dw->nr_irqs = i;
|
dw->nr_irqs = i;
|
||||||
|
|||||||
@@ -252,10 +252,10 @@ static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
|
|||||||
lower_32_bits(chunk->ll_region.paddr));
|
lower_32_bits(chunk->ll_region.paddr));
|
||||||
SET_CH_32(dw, chan->dir, chan->id, llp.msb,
|
SET_CH_32(dw, chan->dir, chan->id, llp.msb,
|
||||||
upper_32_bits(chunk->ll_region.paddr));
|
upper_32_bits(chunk->ll_region.paddr));
|
||||||
|
/* Set consumer cycle */
|
||||||
|
SET_CH_32(dw, chan->dir, chan->id, cycle_sync,
|
||||||
|
HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT);
|
||||||
}
|
}
|
||||||
/* Set consumer cycle */
|
|
||||||
SET_CH_32(dw, chan->dir, chan->id, cycle_sync,
|
|
||||||
HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT);
|
|
||||||
|
|
||||||
dw_hdma_v0_sync_ll_data(chunk);
|
dw_hdma_v0_sync_ll_data(chunk);
|
||||||
|
|
||||||
|
|||||||
@@ -317,10 +317,8 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
|
|||||||
return NULL;
|
return NULL;
|
||||||
i = fsl_chan - fsl_edma->chans;
|
i = fsl_chan - fsl_edma->chans;
|
||||||
|
|
||||||
fsl_chan->priority = dma_spec->args[1];
|
if (!b_chmux && i != dma_spec->args[0])
|
||||||
fsl_chan->is_rxchan = dma_spec->args[2] & FSL_EDMA_RX;
|
continue;
|
||||||
fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE;
|
|
||||||
fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO;
|
|
||||||
|
|
||||||
if ((dma_spec->args[2] & FSL_EDMA_EVEN_CH) && (i & 0x1))
|
if ((dma_spec->args[2] & FSL_EDMA_EVEN_CH) && (i & 0x1))
|
||||||
continue;
|
continue;
|
||||||
@@ -328,17 +326,15 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
|
|||||||
if ((dma_spec->args[2] & FSL_EDMA_ODD_CH) && !(i & 0x1))
|
if ((dma_spec->args[2] & FSL_EDMA_ODD_CH) && !(i & 0x1))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!b_chmux && i == dma_spec->args[0]) {
|
fsl_chan->srcid = dma_spec->args[0];
|
||||||
chan = dma_get_slave_channel(chan);
|
fsl_chan->priority = dma_spec->args[1];
|
||||||
chan->device->privatecnt++;
|
fsl_chan->is_rxchan = dma_spec->args[2] & FSL_EDMA_RX;
|
||||||
return chan;
|
fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE;
|
||||||
} else if (b_chmux && !fsl_chan->srcid) {
|
fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO;
|
||||||
/* if controller support channel mux, choose a free channel */
|
|
||||||
chan = dma_get_slave_channel(chan);
|
chan = dma_get_slave_channel(chan);
|
||||||
chan->device->privatecnt++;
|
chan->device->privatecnt++;
|
||||||
fsl_chan->srcid = dma_spec->args[0];
|
return chan;
|
||||||
return chan;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,11 +158,7 @@ static const struct device_type idxd_cdev_file_type = {
|
|||||||
static void idxd_cdev_dev_release(struct device *dev)
|
static void idxd_cdev_dev_release(struct device *dev)
|
||||||
{
|
{
|
||||||
struct idxd_cdev *idxd_cdev = dev_to_cdev(dev);
|
struct idxd_cdev *idxd_cdev = dev_to_cdev(dev);
|
||||||
struct idxd_cdev_context *cdev_ctx;
|
|
||||||
struct idxd_wq *wq = idxd_cdev->wq;
|
|
||||||
|
|
||||||
cdev_ctx = &ictx[wq->idxd->data->type];
|
|
||||||
ida_free(&cdev_ctx->minor_ida, idxd_cdev->minor);
|
|
||||||
kfree(idxd_cdev);
|
kfree(idxd_cdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -582,11 +578,15 @@ int idxd_wq_add_cdev(struct idxd_wq *wq)
|
|||||||
|
|
||||||
void idxd_wq_del_cdev(struct idxd_wq *wq)
|
void idxd_wq_del_cdev(struct idxd_wq *wq)
|
||||||
{
|
{
|
||||||
|
struct idxd_cdev_context *cdev_ctx;
|
||||||
struct idxd_cdev *idxd_cdev;
|
struct idxd_cdev *idxd_cdev;
|
||||||
|
|
||||||
idxd_cdev = wq->idxd_cdev;
|
idxd_cdev = wq->idxd_cdev;
|
||||||
wq->idxd_cdev = NULL;
|
wq->idxd_cdev = NULL;
|
||||||
cdev_device_del(&idxd_cdev->cdev, cdev_dev(idxd_cdev));
|
cdev_device_del(&idxd_cdev->cdev, cdev_dev(idxd_cdev));
|
||||||
|
|
||||||
|
cdev_ctx = &ictx[wq->idxd->data->type];
|
||||||
|
ida_free(&cdev_ctx->minor_ida, idxd_cdev->minor);
|
||||||
put_device(cdev_dev(idxd_cdev));
|
put_device(cdev_dev(idxd_cdev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ void idxd_wq_free_resources(struct idxd_wq *wq)
|
|||||||
free_descs(wq);
|
free_descs(wq);
|
||||||
dma_free_coherent(dev, wq->compls_size, wq->compls, wq->compls_addr);
|
dma_free_coherent(dev, wq->compls_size, wq->compls, wq->compls_addr);
|
||||||
sbitmap_queue_free(&wq->sbq);
|
sbitmap_queue_free(&wq->sbq);
|
||||||
|
wq->type = IDXD_WQT_NONE;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_NS_GPL(idxd_wq_free_resources, "IDXD");
|
EXPORT_SYMBOL_NS_GPL(idxd_wq_free_resources, "IDXD");
|
||||||
|
|
||||||
@@ -382,7 +383,6 @@ static void idxd_wq_disable_cleanup(struct idxd_wq *wq)
|
|||||||
lockdep_assert_held(&wq->wq_lock);
|
lockdep_assert_held(&wq->wq_lock);
|
||||||
wq->state = IDXD_WQ_DISABLED;
|
wq->state = IDXD_WQ_DISABLED;
|
||||||
memset(wq->wqcfg, 0, idxd->wqcfg_size);
|
memset(wq->wqcfg, 0, idxd->wqcfg_size);
|
||||||
wq->type = IDXD_WQT_NONE;
|
|
||||||
wq->threshold = 0;
|
wq->threshold = 0;
|
||||||
wq->priority = 0;
|
wq->priority = 0;
|
||||||
wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES;
|
wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES;
|
||||||
@@ -831,8 +831,7 @@ static void idxd_device_evl_free(struct idxd_device *idxd)
|
|||||||
struct device *dev = &idxd->pdev->dev;
|
struct device *dev = &idxd->pdev->dev;
|
||||||
struct idxd_evl *evl = idxd->evl;
|
struct idxd_evl *evl = idxd->evl;
|
||||||
|
|
||||||
gencfg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET);
|
if (!evl)
|
||||||
if (!gencfg.evl_en)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_lock(&evl->lock);
|
mutex_lock(&evl->lock);
|
||||||
@@ -1125,7 +1124,11 @@ int idxd_device_config(struct idxd_device *idxd)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
lockdep_assert_held(&idxd->dev_lock);
|
guard(spinlock)(&idxd->dev_lock);
|
||||||
|
|
||||||
|
if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
|
||||||
|
return 0;
|
||||||
|
|
||||||
rc = idxd_wqs_setup(idxd);
|
rc = idxd_wqs_setup(idxd);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
@@ -1332,6 +1335,11 @@ void idxd_wq_free_irq(struct idxd_wq *wq)
|
|||||||
|
|
||||||
free_irq(ie->vector, ie);
|
free_irq(ie->vector, ie);
|
||||||
idxd_flush_pending_descs(ie);
|
idxd_flush_pending_descs(ie);
|
||||||
|
|
||||||
|
/* The interrupt might have been already released by FLR */
|
||||||
|
if (ie->int_handle == INVALID_INT_HANDLE)
|
||||||
|
return;
|
||||||
|
|
||||||
if (idxd->request_int_handles)
|
if (idxd->request_int_handles)
|
||||||
idxd_device_release_int_handle(idxd, ie->int_handle, IDXD_IRQ_MSIX);
|
idxd_device_release_int_handle(idxd, ie->int_handle, IDXD_IRQ_MSIX);
|
||||||
idxd_device_clear_perm_entry(idxd, ie);
|
idxd_device_clear_perm_entry(idxd, ie);
|
||||||
@@ -1340,6 +1348,23 @@ void idxd_wq_free_irq(struct idxd_wq *wq)
|
|||||||
ie->pasid = IOMMU_PASID_INVALID;
|
ie->pasid = IOMMU_PASID_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void idxd_wq_flush_descs(struct idxd_wq *wq)
|
||||||
|
{
|
||||||
|
struct idxd_irq_entry *ie = &wq->ie;
|
||||||
|
struct idxd_device *idxd = wq->idxd;
|
||||||
|
|
||||||
|
guard(mutex)(&wq->wq_lock);
|
||||||
|
|
||||||
|
if (wq->state != IDXD_WQ_ENABLED || wq->type != IDXD_WQT_KERNEL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
idxd_flush_pending_descs(ie);
|
||||||
|
if (idxd->request_int_handles)
|
||||||
|
idxd_device_release_int_handle(idxd, ie->int_handle, IDXD_IRQ_MSIX);
|
||||||
|
idxd_device_clear_perm_entry(idxd, ie);
|
||||||
|
ie->int_handle = INVALID_INT_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
int idxd_wq_request_irq(struct idxd_wq *wq)
|
int idxd_wq_request_irq(struct idxd_wq *wq)
|
||||||
{
|
{
|
||||||
struct idxd_device *idxd = wq->idxd;
|
struct idxd_device *idxd = wq->idxd;
|
||||||
@@ -1454,11 +1479,7 @@ int idxd_drv_enable_wq(struct idxd_wq *wq)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = 0;
|
rc = idxd_device_config(idxd);
|
||||||
spin_lock(&idxd->dev_lock);
|
|
||||||
if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
|
|
||||||
rc = idxd_device_config(idxd);
|
|
||||||
spin_unlock(&idxd->dev_lock);
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
dev_dbg(dev, "Writing wq %d config failed: %d\n", wq->id, rc);
|
dev_dbg(dev, "Writing wq %d config failed: %d\n", wq->id, rc);
|
||||||
goto err;
|
goto err;
|
||||||
@@ -1533,7 +1554,6 @@ void idxd_drv_disable_wq(struct idxd_wq *wq)
|
|||||||
idxd_wq_reset(wq);
|
idxd_wq_reset(wq);
|
||||||
idxd_wq_free_resources(wq);
|
idxd_wq_free_resources(wq);
|
||||||
percpu_ref_exit(&wq->wq_active);
|
percpu_ref_exit(&wq->wq_active);
|
||||||
wq->type = IDXD_WQT_NONE;
|
|
||||||
wq->client_count = 0;
|
wq->client_count = 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_NS_GPL(idxd_drv_disable_wq, "IDXD");
|
EXPORT_SYMBOL_NS_GPL(idxd_drv_disable_wq, "IDXD");
|
||||||
@@ -1554,10 +1574,7 @@ int idxd_device_drv_probe(struct idxd_dev *idxd_dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Device configuration */
|
/* Device configuration */
|
||||||
spin_lock(&idxd->dev_lock);
|
rc = idxd_device_config(idxd);
|
||||||
if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
|
|
||||||
rc = idxd_device_config(idxd);
|
|
||||||
spin_unlock(&idxd->dev_lock);
|
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
|
|||||||
@@ -194,6 +194,22 @@ static void idxd_dma_release(struct dma_device *device)
|
|||||||
kfree(idxd_dma);
|
kfree(idxd_dma);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int idxd_dma_terminate_all(struct dma_chan *c)
|
||||||
|
{
|
||||||
|
struct idxd_wq *wq = to_idxd_wq(c);
|
||||||
|
|
||||||
|
idxd_wq_flush_descs(wq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void idxd_dma_synchronize(struct dma_chan *c)
|
||||||
|
{
|
||||||
|
struct idxd_wq *wq = to_idxd_wq(c);
|
||||||
|
|
||||||
|
idxd_wq_drain(wq);
|
||||||
|
}
|
||||||
|
|
||||||
int idxd_register_dma_device(struct idxd_device *idxd)
|
int idxd_register_dma_device(struct idxd_device *idxd)
|
||||||
{
|
{
|
||||||
struct idxd_dma_dev *idxd_dma;
|
struct idxd_dma_dev *idxd_dma;
|
||||||
@@ -224,6 +240,8 @@ int idxd_register_dma_device(struct idxd_device *idxd)
|
|||||||
dma->device_issue_pending = idxd_dma_issue_pending;
|
dma->device_issue_pending = idxd_dma_issue_pending;
|
||||||
dma->device_alloc_chan_resources = idxd_dma_alloc_chan_resources;
|
dma->device_alloc_chan_resources = idxd_dma_alloc_chan_resources;
|
||||||
dma->device_free_chan_resources = idxd_dma_free_chan_resources;
|
dma->device_free_chan_resources = idxd_dma_free_chan_resources;
|
||||||
|
dma->device_terminate_all = idxd_dma_terminate_all;
|
||||||
|
dma->device_synchronize = idxd_dma_synchronize;
|
||||||
|
|
||||||
rc = dma_async_device_register(dma);
|
rc = dma_async_device_register(dma);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
|
|||||||
@@ -803,6 +803,7 @@ void idxd_wq_quiesce(struct idxd_wq *wq);
|
|||||||
int idxd_wq_init_percpu_ref(struct idxd_wq *wq);
|
int idxd_wq_init_percpu_ref(struct idxd_wq *wq);
|
||||||
void idxd_wq_free_irq(struct idxd_wq *wq);
|
void idxd_wq_free_irq(struct idxd_wq *wq);
|
||||||
int idxd_wq_request_irq(struct idxd_wq *wq);
|
int idxd_wq_request_irq(struct idxd_wq *wq);
|
||||||
|
void idxd_wq_flush_descs(struct idxd_wq *wq);
|
||||||
|
|
||||||
/* submission */
|
/* submission */
|
||||||
int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc);
|
int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc);
|
||||||
|
|||||||
@@ -973,7 +973,8 @@ static void idxd_device_config_restore(struct idxd_device *idxd,
|
|||||||
|
|
||||||
idxd->rdbuf_limit = idxd_saved->saved_idxd.rdbuf_limit;
|
idxd->rdbuf_limit = idxd_saved->saved_idxd.rdbuf_limit;
|
||||||
|
|
||||||
idxd->evl->size = saved_evl->size;
|
if (idxd->evl)
|
||||||
|
idxd->evl->size = saved_evl->size;
|
||||||
|
|
||||||
for (i = 0; i < idxd->max_groups; i++) {
|
for (i = 0; i < idxd->max_groups; i++) {
|
||||||
struct idxd_group *saved_group, *group;
|
struct idxd_group *saved_group, *group;
|
||||||
@@ -1104,12 +1105,10 @@ static void idxd_reset_done(struct pci_dev *pdev)
|
|||||||
idxd_device_config_restore(idxd, idxd->idxd_saved);
|
idxd_device_config_restore(idxd, idxd->idxd_saved);
|
||||||
|
|
||||||
/* Re-configure IDXD device if allowed. */
|
/* Re-configure IDXD device if allowed. */
|
||||||
if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) {
|
rc = idxd_device_config(idxd);
|
||||||
rc = idxd_device_config(idxd);
|
if (rc < 0) {
|
||||||
if (rc < 0) {
|
dev_err(dev, "HALT: %s config fails\n", idxd_name);
|
||||||
dev_err(dev, "HALT: %s config fails\n", idxd_name);
|
goto out;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bind IDXD device to driver. */
|
/* Bind IDXD device to driver. */
|
||||||
@@ -1147,6 +1146,7 @@ static void idxd_reset_done(struct pci_dev *pdev)
|
|||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
kfree(idxd->idxd_saved);
|
kfree(idxd->idxd_saved);
|
||||||
|
idxd->idxd_saved = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pci_error_handlers idxd_error_handler = {
|
static const struct pci_error_handlers idxd_error_handler = {
|
||||||
|
|||||||
@@ -397,6 +397,17 @@ static void idxd_device_flr(struct work_struct *work)
|
|||||||
dev_err(&idxd->pdev->dev, "FLR failed\n");
|
dev_err(&idxd->pdev->dev, "FLR failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void idxd_wqs_flush_descs(struct idxd_device *idxd)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < idxd->max_wqs; i++) {
|
||||||
|
struct idxd_wq *wq = idxd->wqs[i];
|
||||||
|
|
||||||
|
idxd_wq_flush_descs(wq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static irqreturn_t idxd_halt(struct idxd_device *idxd)
|
static irqreturn_t idxd_halt(struct idxd_device *idxd)
|
||||||
{
|
{
|
||||||
union gensts_reg gensts;
|
union gensts_reg gensts;
|
||||||
@@ -415,6 +426,11 @@ static irqreturn_t idxd_halt(struct idxd_device *idxd)
|
|||||||
} else if (gensts.reset_type == IDXD_DEVICE_RESET_FLR) {
|
} else if (gensts.reset_type == IDXD_DEVICE_RESET_FLR) {
|
||||||
idxd->state = IDXD_DEV_HALTED;
|
idxd->state = IDXD_DEV_HALTED;
|
||||||
idxd_mask_error_interrupts(idxd);
|
idxd_mask_error_interrupts(idxd);
|
||||||
|
/* Flush all pending descriptors, and disable
|
||||||
|
* interrupts, they will be re-enabled when FLR
|
||||||
|
* concludes.
|
||||||
|
*/
|
||||||
|
idxd_wqs_flush_descs(idxd);
|
||||||
dev_dbg(&idxd->pdev->dev,
|
dev_dbg(&idxd->pdev->dev,
|
||||||
"idxd halted, doing FLR. After FLR, configs are restored\n");
|
"idxd halted, doing FLR. After FLR, configs are restored\n");
|
||||||
INIT_WORK(&idxd->work, idxd_device_flr);
|
INIT_WORK(&idxd->work, idxd_device_flr);
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie,
|
|||||||
*/
|
*/
|
||||||
list_for_each_entry_safe(d, t, &flist, list) {
|
list_for_each_entry_safe(d, t, &flist, list) {
|
||||||
list_del_init(&d->list);
|
list_del_init(&d->list);
|
||||||
idxd_dma_complete_txd(found, IDXD_COMPLETE_ABORT, true,
|
idxd_dma_complete_txd(d, IDXD_COMPLETE_ABORT, true,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1836,6 +1836,7 @@ static void idxd_conf_device_release(struct device *dev)
|
|||||||
{
|
{
|
||||||
struct idxd_device *idxd = confdev_to_idxd(dev);
|
struct idxd_device *idxd = confdev_to_idxd(dev);
|
||||||
|
|
||||||
|
destroy_workqueue(idxd->wq);
|
||||||
kfree(idxd->groups);
|
kfree(idxd->groups);
|
||||||
bitmap_free(idxd->wq_enable_map);
|
bitmap_free(idxd->wq_enable_map);
|
||||||
kfree(idxd->wqs);
|
kfree(idxd->wqs);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/bitfield.h>
|
#include <linux/bitfield.h>
|
||||||
|
#include <linux/cleanup.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/dmaengine.h>
|
#include <linux/dmaengine.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
@@ -296,13 +297,10 @@ static void rz_dmac_disable_hw(struct rz_dmac_chan *channel)
|
|||||||
{
|
{
|
||||||
struct dma_chan *chan = &channel->vc.chan;
|
struct dma_chan *chan = &channel->vc.chan;
|
||||||
struct rz_dmac *dmac = to_rz_dmac(chan->device);
|
struct rz_dmac *dmac = to_rz_dmac(chan->device);
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
dev_dbg(dmac->dev, "%s channel %d\n", __func__, channel->index);
|
dev_dbg(dmac->dev, "%s channel %d\n", __func__, channel->index);
|
||||||
|
|
||||||
local_irq_save(flags);
|
|
||||||
rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
|
rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
|
||||||
local_irq_restore(flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rz_dmac_set_dmars_register(struct rz_dmac *dmac, int nr, u32 dmars)
|
static void rz_dmac_set_dmars_register(struct rz_dmac *dmac, int nr, u32 dmars)
|
||||||
@@ -447,6 +445,7 @@ static int rz_dmac_alloc_chan_resources(struct dma_chan *chan)
|
|||||||
if (!desc)
|
if (!desc)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* No need to lock. This is called only for the 1st client. */
|
||||||
list_add_tail(&desc->node, &channel->ld_free);
|
list_add_tail(&desc->node, &channel->ld_free);
|
||||||
channel->descs_allocated++;
|
channel->descs_allocated++;
|
||||||
}
|
}
|
||||||
@@ -502,18 +501,21 @@ rz_dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
|
|||||||
dev_dbg(dmac->dev, "%s channel: %d src=0x%pad dst=0x%pad len=%zu\n",
|
dev_dbg(dmac->dev, "%s channel: %d src=0x%pad dst=0x%pad len=%zu\n",
|
||||||
__func__, channel->index, &src, &dest, len);
|
__func__, channel->index, &src, &dest, len);
|
||||||
|
|
||||||
if (list_empty(&channel->ld_free))
|
scoped_guard(spinlock_irqsave, &channel->vc.lock) {
|
||||||
return NULL;
|
if (list_empty(&channel->ld_free))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
|
desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
|
||||||
|
|
||||||
desc->type = RZ_DMAC_DESC_MEMCPY;
|
desc->type = RZ_DMAC_DESC_MEMCPY;
|
||||||
desc->src = src;
|
desc->src = src;
|
||||||
desc->dest = dest;
|
desc->dest = dest;
|
||||||
desc->len = len;
|
desc->len = len;
|
||||||
desc->direction = DMA_MEM_TO_MEM;
|
desc->direction = DMA_MEM_TO_MEM;
|
||||||
|
|
||||||
|
list_move_tail(channel->ld_free.next, &channel->ld_queue);
|
||||||
|
}
|
||||||
|
|
||||||
list_move_tail(channel->ld_free.next, &channel->ld_queue);
|
|
||||||
return vchan_tx_prep(&channel->vc, &desc->vd, flags);
|
return vchan_tx_prep(&channel->vc, &desc->vd, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,27 +531,29 @@ rz_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||||||
int dma_length = 0;
|
int dma_length = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
if (list_empty(&channel->ld_free))
|
scoped_guard(spinlock_irqsave, &channel->vc.lock) {
|
||||||
return NULL;
|
if (list_empty(&channel->ld_free))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
|
desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
|
||||||
|
|
||||||
for_each_sg(sgl, sg, sg_len, i) {
|
for_each_sg(sgl, sg, sg_len, i)
|
||||||
dma_length += sg_dma_len(sg);
|
dma_length += sg_dma_len(sg);
|
||||||
|
|
||||||
|
desc->type = RZ_DMAC_DESC_SLAVE_SG;
|
||||||
|
desc->sg = sgl;
|
||||||
|
desc->sgcount = sg_len;
|
||||||
|
desc->len = dma_length;
|
||||||
|
desc->direction = direction;
|
||||||
|
|
||||||
|
if (direction == DMA_DEV_TO_MEM)
|
||||||
|
desc->src = channel->src_per_address;
|
||||||
|
else
|
||||||
|
desc->dest = channel->dst_per_address;
|
||||||
|
|
||||||
|
list_move_tail(channel->ld_free.next, &channel->ld_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
desc->type = RZ_DMAC_DESC_SLAVE_SG;
|
|
||||||
desc->sg = sgl;
|
|
||||||
desc->sgcount = sg_len;
|
|
||||||
desc->len = dma_length;
|
|
||||||
desc->direction = direction;
|
|
||||||
|
|
||||||
if (direction == DMA_DEV_TO_MEM)
|
|
||||||
desc->src = channel->src_per_address;
|
|
||||||
else
|
|
||||||
desc->dest = channel->dst_per_address;
|
|
||||||
|
|
||||||
list_move_tail(channel->ld_free.next, &channel->ld_queue);
|
|
||||||
return vchan_tx_prep(&channel->vc, &desc->vd, flags);
|
return vchan_tx_prep(&channel->vc, &desc->vd, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,8 +565,8 @@ static int rz_dmac_terminate_all(struct dma_chan *chan)
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
LIST_HEAD(head);
|
LIST_HEAD(head);
|
||||||
|
|
||||||
rz_dmac_disable_hw(channel);
|
|
||||||
spin_lock_irqsave(&channel->vc.lock, flags);
|
spin_lock_irqsave(&channel->vc.lock, flags);
|
||||||
|
rz_dmac_disable_hw(channel);
|
||||||
for (i = 0; i < DMAC_NR_LMDESC; i++)
|
for (i = 0; i < DMAC_NR_LMDESC; i++)
|
||||||
lmdesc[i].header = 0;
|
lmdesc[i].header = 0;
|
||||||
|
|
||||||
@@ -699,7 +703,9 @@ static void rz_dmac_irq_handle_channel(struct rz_dmac_chan *channel)
|
|||||||
if (chstat & CHSTAT_ER) {
|
if (chstat & CHSTAT_ER) {
|
||||||
dev_err(dmac->dev, "DMAC err CHSTAT_%d = %08X\n",
|
dev_err(dmac->dev, "DMAC err CHSTAT_%d = %08X\n",
|
||||||
channel->index, chstat);
|
channel->index, chstat);
|
||||||
rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
|
|
||||||
|
scoped_guard(spinlock_irqsave, &channel->vc.lock)
|
||||||
|
rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1234,8 +1234,8 @@ static int xdma_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
xdev->rmap = devm_regmap_init_mmio(&pdev->dev, reg_base,
|
xdev->rmap = devm_regmap_init_mmio(&pdev->dev, reg_base,
|
||||||
&xdma_regmap_config);
|
&xdma_regmap_config);
|
||||||
if (!xdev->rmap) {
|
if (IS_ERR(xdev->rmap)) {
|
||||||
xdma_err(xdev, "config regmap failed: %d", ret);
|
xdma_err(xdev, "config regmap failed: %pe", xdev->rmap);
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
INIT_LIST_HEAD(&xdev->dma_dev.channels);
|
INIT_LIST_HEAD(&xdev->dma_dev.channels);
|
||||||
|
|||||||
@@ -997,16 +997,16 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
|
|||||||
struct xilinx_cdma_tx_segment,
|
struct xilinx_cdma_tx_segment,
|
||||||
node);
|
node);
|
||||||
cdma_hw = &cdma_seg->hw;
|
cdma_hw = &cdma_seg->hw;
|
||||||
residue += (cdma_hw->control - cdma_hw->status) &
|
residue += (cdma_hw->control & chan->xdev->max_buffer_len) -
|
||||||
chan->xdev->max_buffer_len;
|
(cdma_hw->status & chan->xdev->max_buffer_len);
|
||||||
} else if (chan->xdev->dma_config->dmatype ==
|
} else if (chan->xdev->dma_config->dmatype ==
|
||||||
XDMA_TYPE_AXIDMA) {
|
XDMA_TYPE_AXIDMA) {
|
||||||
axidma_seg = list_entry(entry,
|
axidma_seg = list_entry(entry,
|
||||||
struct xilinx_axidma_tx_segment,
|
struct xilinx_axidma_tx_segment,
|
||||||
node);
|
node);
|
||||||
axidma_hw = &axidma_seg->hw;
|
axidma_hw = &axidma_seg->hw;
|
||||||
residue += (axidma_hw->control - axidma_hw->status) &
|
residue += (axidma_hw->control & chan->xdev->max_buffer_len) -
|
||||||
chan->xdev->max_buffer_len;
|
(axidma_hw->status & chan->xdev->max_buffer_len);
|
||||||
} else {
|
} else {
|
||||||
aximcdma_seg =
|
aximcdma_seg =
|
||||||
list_entry(entry,
|
list_entry(entry,
|
||||||
@@ -1014,8 +1014,8 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
|
|||||||
node);
|
node);
|
||||||
aximcdma_hw = &aximcdma_seg->hw;
|
aximcdma_hw = &aximcdma_seg->hw;
|
||||||
residue +=
|
residue +=
|
||||||
(aximcdma_hw->control - aximcdma_hw->status) &
|
(aximcdma_hw->control & chan->xdev->max_buffer_len) -
|
||||||
chan->xdev->max_buffer_len;
|
(aximcdma_hw->status & chan->xdev->max_buffer_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1235,14 +1235,6 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan)
|
|||||||
|
|
||||||
dma_cookie_init(dchan);
|
dma_cookie_init(dchan);
|
||||||
|
|
||||||
if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
|
|
||||||
/* For AXI DMA resetting once channel will reset the
|
|
||||||
* other channel as well so enable the interrupts here.
|
|
||||||
*/
|
|
||||||
dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
|
|
||||||
XILINX_DMA_DMAXR_ALL_IRQ_MASK);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) && chan->has_sg)
|
if ((chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) && chan->has_sg)
|
||||||
dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
|
dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
|
||||||
XILINX_CDMA_CR_SGMODE);
|
XILINX_CDMA_CR_SGMODE);
|
||||||
@@ -1564,8 +1556,29 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
|
|||||||
if (chan->err)
|
if (chan->err)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (list_empty(&chan->pending_list))
|
if (list_empty(&chan->pending_list)) {
|
||||||
|
if (chan->cyclic) {
|
||||||
|
struct xilinx_dma_tx_descriptor *desc;
|
||||||
|
struct list_head *entry;
|
||||||
|
|
||||||
|
desc = list_last_entry(&chan->done_list,
|
||||||
|
struct xilinx_dma_tx_descriptor, node);
|
||||||
|
list_for_each(entry, &desc->segments) {
|
||||||
|
struct xilinx_axidma_tx_segment *axidma_seg;
|
||||||
|
struct xilinx_axidma_desc_hw *axidma_hw;
|
||||||
|
axidma_seg = list_entry(entry,
|
||||||
|
struct xilinx_axidma_tx_segment,
|
||||||
|
node);
|
||||||
|
axidma_hw = &axidma_seg->hw;
|
||||||
|
axidma_hw->status = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_splice_tail_init(&chan->done_list, &chan->active_list);
|
||||||
|
chan->desc_pendingcount = 0;
|
||||||
|
chan->idle = false;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!chan->idle)
|
if (!chan->idle)
|
||||||
return;
|
return;
|
||||||
@@ -1591,6 +1604,7 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
|
|||||||
head_desc->async_tx.phys);
|
head_desc->async_tx.phys);
|
||||||
reg &= ~XILINX_DMA_CR_DELAY_MAX;
|
reg &= ~XILINX_DMA_CR_DELAY_MAX;
|
||||||
reg |= chan->irq_delay << XILINX_DMA_CR_DELAY_SHIFT;
|
reg |= chan->irq_delay << XILINX_DMA_CR_DELAY_SHIFT;
|
||||||
|
reg |= XILINX_DMA_DMAXR_ALL_IRQ_MASK;
|
||||||
dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
|
dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
|
||||||
|
|
||||||
xilinx_dma_start(chan);
|
xilinx_dma_start(chan);
|
||||||
@@ -3024,7 +3038,7 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
xdev->common.directions |= chan->direction;
|
xdev->common.directions |= BIT(chan->direction);
|
||||||
|
|
||||||
/* Request the interrupt */
|
/* Request the interrupt */
|
||||||
chan->irq = of_irq_get(node, chan->tdest);
|
chan->irq = of_irq_get(node, chan->tdest);
|
||||||
|
|||||||
@@ -692,9 +692,9 @@ int amdgpu_amdkfd_submit_ib(struct amdgpu_device *adev,
|
|||||||
goto err_ib_sched;
|
goto err_ib_sched;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drop the initial kref_init count (see drm_sched_main as example) */
|
|
||||||
dma_fence_put(f);
|
|
||||||
ret = dma_fence_wait(f, false);
|
ret = dma_fence_wait(f, false);
|
||||||
|
/* Drop the returned fence reference after the wait completes */
|
||||||
|
dma_fence_put(f);
|
||||||
|
|
||||||
err_ib_sched:
|
err_ib_sched:
|
||||||
amdgpu_job_free(job);
|
amdgpu_job_free(job);
|
||||||
|
|||||||
@@ -4207,7 +4207,8 @@ fail:
|
|||||||
|
|
||||||
static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev)
|
static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev)
|
||||||
{
|
{
|
||||||
char *input = amdgpu_lockup_timeout;
|
char buf[AMDGPU_MAX_TIMEOUT_PARAM_LENGTH];
|
||||||
|
char *input = buf;
|
||||||
char *timeout_setting = NULL;
|
char *timeout_setting = NULL;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
long timeout;
|
long timeout;
|
||||||
@@ -4217,9 +4218,17 @@ static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev)
|
|||||||
adev->gfx_timeout = adev->compute_timeout = adev->sdma_timeout =
|
adev->gfx_timeout = adev->compute_timeout = adev->sdma_timeout =
|
||||||
adev->video_timeout = msecs_to_jiffies(2000);
|
adev->video_timeout = msecs_to_jiffies(2000);
|
||||||
|
|
||||||
if (!strnlen(input, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH))
|
if (!strnlen(amdgpu_lockup_timeout, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* strsep() destructively modifies its input by replacing delimiters
|
||||||
|
* with '\0'. Use a stack copy so the global module parameter buffer
|
||||||
|
* remains intact for multi-GPU systems where this function is called
|
||||||
|
* once per device.
|
||||||
|
*/
|
||||||
|
strscpy(buf, amdgpu_lockup_timeout, sizeof(buf));
|
||||||
|
|
||||||
while ((timeout_setting = strsep(&input, ",")) &&
|
while ((timeout_setting = strsep(&input, ",")) &&
|
||||||
strnlen(timeout_setting, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) {
|
strnlen(timeout_setting, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) {
|
||||||
ret = kstrtol(timeout_setting, 0, &timeout);
|
ret = kstrtol(timeout_setting, 0, &timeout);
|
||||||
|
|||||||
@@ -35,10 +35,13 @@
|
|||||||
* PASIDs are global address space identifiers that can be shared
|
* PASIDs are global address space identifiers that can be shared
|
||||||
* between the GPU, an IOMMU and the driver. VMs on different devices
|
* between the GPU, an IOMMU and the driver. VMs on different devices
|
||||||
* may use the same PASID if they share the same address
|
* may use the same PASID if they share the same address
|
||||||
* space. Therefore PASIDs are allocated using a global IDA. VMs are
|
* space. Therefore PASIDs are allocated using IDR cyclic allocator
|
||||||
* looked up from the PASID per amdgpu_device.
|
* (similar to kernel PID allocation) which naturally delays reuse.
|
||||||
|
* VMs are looked up from the PASID per amdgpu_device.
|
||||||
*/
|
*/
|
||||||
static DEFINE_IDA(amdgpu_pasid_ida);
|
|
||||||
|
static DEFINE_IDR(amdgpu_pasid_idr);
|
||||||
|
static DEFINE_SPINLOCK(amdgpu_pasid_idr_lock);
|
||||||
|
|
||||||
/* Helper to free pasid from a fence callback */
|
/* Helper to free pasid from a fence callback */
|
||||||
struct amdgpu_pasid_cb {
|
struct amdgpu_pasid_cb {
|
||||||
@@ -50,8 +53,8 @@ struct amdgpu_pasid_cb {
|
|||||||
* amdgpu_pasid_alloc - Allocate a PASID
|
* amdgpu_pasid_alloc - Allocate a PASID
|
||||||
* @bits: Maximum width of the PASID in bits, must be at least 1
|
* @bits: Maximum width of the PASID in bits, must be at least 1
|
||||||
*
|
*
|
||||||
* Allocates a PASID of the given width while keeping smaller PASIDs
|
* Uses kernel's IDR cyclic allocator (same as PID allocation).
|
||||||
* available if possible.
|
* Allocates sequentially with automatic wrap-around.
|
||||||
*
|
*
|
||||||
* Returns a positive integer on success. Returns %-EINVAL if bits==0.
|
* Returns a positive integer on success. Returns %-EINVAL if bits==0.
|
||||||
* Returns %-ENOSPC if no PASID was available. Returns %-ENOMEM on
|
* Returns %-ENOSPC if no PASID was available. Returns %-ENOMEM on
|
||||||
@@ -59,14 +62,15 @@ struct amdgpu_pasid_cb {
|
|||||||
*/
|
*/
|
||||||
int amdgpu_pasid_alloc(unsigned int bits)
|
int amdgpu_pasid_alloc(unsigned int bits)
|
||||||
{
|
{
|
||||||
int pasid = -EINVAL;
|
int pasid;
|
||||||
|
|
||||||
for (bits = min(bits, 31U); bits > 0; bits--) {
|
if (bits == 0)
|
||||||
pasid = ida_alloc_range(&amdgpu_pasid_ida, 1U << (bits - 1),
|
return -EINVAL;
|
||||||
(1U << bits) - 1, GFP_KERNEL);
|
|
||||||
if (pasid != -ENOSPC)
|
spin_lock(&amdgpu_pasid_idr_lock);
|
||||||
break;
|
pasid = idr_alloc_cyclic(&amdgpu_pasid_idr, NULL, 1,
|
||||||
}
|
1U << bits, GFP_KERNEL);
|
||||||
|
spin_unlock(&amdgpu_pasid_idr_lock);
|
||||||
|
|
||||||
if (pasid >= 0)
|
if (pasid >= 0)
|
||||||
trace_amdgpu_pasid_allocated(pasid);
|
trace_amdgpu_pasid_allocated(pasid);
|
||||||
@@ -81,7 +85,10 @@ int amdgpu_pasid_alloc(unsigned int bits)
|
|||||||
void amdgpu_pasid_free(u32 pasid)
|
void amdgpu_pasid_free(u32 pasid)
|
||||||
{
|
{
|
||||||
trace_amdgpu_pasid_freed(pasid);
|
trace_amdgpu_pasid_freed(pasid);
|
||||||
ida_free(&amdgpu_pasid_ida, pasid);
|
|
||||||
|
spin_lock(&amdgpu_pasid_idr_lock);
|
||||||
|
idr_remove(&amdgpu_pasid_idr, pasid);
|
||||||
|
spin_unlock(&amdgpu_pasid_idr_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void amdgpu_pasid_free_cb(struct dma_fence *fence,
|
static void amdgpu_pasid_free_cb(struct dma_fence *fence,
|
||||||
@@ -616,3 +623,15 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* amdgpu_pasid_mgr_cleanup - cleanup PASID manager
|
||||||
|
*
|
||||||
|
* Cleanup the IDR allocator.
|
||||||
|
*/
|
||||||
|
void amdgpu_pasid_mgr_cleanup(void)
|
||||||
|
{
|
||||||
|
spin_lock(&amdgpu_pasid_idr_lock);
|
||||||
|
idr_destroy(&amdgpu_pasid_idr);
|
||||||
|
spin_unlock(&amdgpu_pasid_idr_lock);
|
||||||
|
}
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ int amdgpu_pasid_alloc(unsigned int bits);
|
|||||||
void amdgpu_pasid_free(u32 pasid);
|
void amdgpu_pasid_free(u32 pasid);
|
||||||
void amdgpu_pasid_free_delayed(struct dma_resv *resv,
|
void amdgpu_pasid_free_delayed(struct dma_resv *resv,
|
||||||
u32 pasid);
|
u32 pasid);
|
||||||
|
void amdgpu_pasid_mgr_cleanup(void);
|
||||||
|
|
||||||
bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev,
|
bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev,
|
||||||
struct amdgpu_vmid *id);
|
struct amdgpu_vmid *id);
|
||||||
|
|||||||
@@ -2898,6 +2898,7 @@ void amdgpu_vm_manager_fini(struct amdgpu_device *adev)
|
|||||||
xa_destroy(&adev->vm_manager.pasids);
|
xa_destroy(&adev->vm_manager.pasids);
|
||||||
|
|
||||||
amdgpu_vmid_mgr_fini(adev);
|
amdgpu_vmid_mgr_fini(adev);
|
||||||
|
amdgpu_pasid_mgr_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2973,14 +2974,14 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
|
|||||||
if (!root)
|
if (!root)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
addr /= AMDGPU_GPU_PAGE_SIZE;
|
|
||||||
|
|
||||||
if (is_compute_context && !svm_range_restore_pages(adev, pasid, vmid,
|
if (is_compute_context && !svm_range_restore_pages(adev, pasid, vmid,
|
||||||
node_id, addr, ts, write_fault)) {
|
node_id, addr >> PAGE_SHIFT, ts, write_fault)) {
|
||||||
amdgpu_bo_unref(&root);
|
amdgpu_bo_unref(&root);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addr /= AMDGPU_GPU_PAGE_SIZE;
|
||||||
|
|
||||||
r = amdgpu_bo_reserve(root, true);
|
r = amdgpu_bo_reserve(root, true);
|
||||||
if (r)
|
if (r)
|
||||||
goto error_unref;
|
goto error_unref;
|
||||||
|
|||||||
@@ -3170,11 +3170,11 @@ static int kfd_ioctl_create_process(struct file *filep, struct kfd_process *p, v
|
|||||||
struct kfd_process *process;
|
struct kfd_process *process;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Each FD owns only one kfd_process */
|
if (!filep->private_data || !p)
|
||||||
if (p->context_id != KFD_CONTEXT_ID_PRIMARY)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!filep->private_data || !p)
|
/* Each FD owns only one kfd_process */
|
||||||
|
if (p->context_id != KFD_CONTEXT_ID_PRIMARY)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&kfd_processes_mutex);
|
mutex_lock(&kfd_processes_mutex);
|
||||||
|
|||||||
@@ -3909,8 +3909,9 @@ void amdgpu_dm_update_connector_after_detect(
|
|||||||
|
|
||||||
aconnector->dc_sink = sink;
|
aconnector->dc_sink = sink;
|
||||||
dc_sink_retain(aconnector->dc_sink);
|
dc_sink_retain(aconnector->dc_sink);
|
||||||
|
drm_edid_free(aconnector->drm_edid);
|
||||||
|
aconnector->drm_edid = NULL;
|
||||||
if (sink->dc_edid.length == 0) {
|
if (sink->dc_edid.length == 0) {
|
||||||
aconnector->drm_edid = NULL;
|
|
||||||
hdmi_cec_unset_edid(aconnector);
|
hdmi_cec_unset_edid(aconnector);
|
||||||
if (aconnector->dc_link->aux_mode) {
|
if (aconnector->dc_link->aux_mode) {
|
||||||
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
|
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
|
||||||
@@ -5422,7 +5423,7 @@ static void setup_backlight_device(struct amdgpu_display_manager *dm,
|
|||||||
caps = &dm->backlight_caps[aconnector->bl_idx];
|
caps = &dm->backlight_caps[aconnector->bl_idx];
|
||||||
|
|
||||||
/* Only offer ABM property when non-OLED and user didn't turn off by module parameter */
|
/* Only offer ABM property when non-OLED and user didn't turn off by module parameter */
|
||||||
if (!caps->ext_caps->bits.oled && amdgpu_dm_abm_level < 0)
|
if (caps->ext_caps && !caps->ext_caps->bits.oled && amdgpu_dm_abm_level < 0)
|
||||||
drm_object_attach_property(&aconnector->base.base,
|
drm_object_attach_property(&aconnector->base.base,
|
||||||
dm->adev->mode_info.abm_level_property,
|
dm->adev->mode_info.abm_level_property,
|
||||||
ABM_SYSFS_CONTROL);
|
ABM_SYSFS_CONTROL);
|
||||||
@@ -12523,6 +12524,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dc_resource_is_dsc_encoding_supported(dc)) {
|
if (dc_resource_is_dsc_encoding_supported(dc)) {
|
||||||
|
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
|
||||||
|
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
|
||||||
|
dm_new_crtc_state->mode_changed_independent_from_dsc = new_crtc_state->mode_changed;
|
||||||
|
}
|
||||||
|
|
||||||
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
|
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
|
||||||
if (drm_atomic_crtc_needs_modeset(new_crtc_state)) {
|
if (drm_atomic_crtc_needs_modeset(new_crtc_state)) {
|
||||||
ret = add_affected_mst_dsc_crtcs(state, crtc);
|
ret = add_affected_mst_dsc_crtcs(state, crtc);
|
||||||
|
|||||||
@@ -984,6 +984,7 @@ struct dm_crtc_state {
|
|||||||
|
|
||||||
bool freesync_vrr_info_changed;
|
bool freesync_vrr_info_changed;
|
||||||
|
|
||||||
|
bool mode_changed_independent_from_dsc;
|
||||||
bool dsc_force_changed;
|
bool dsc_force_changed;
|
||||||
bool vrr_supported;
|
bool vrr_supported;
|
||||||
struct mod_freesync_config freesync_config;
|
struct mod_freesync_config freesync_config;
|
||||||
|
|||||||
@@ -1744,9 +1744,11 @@ int pre_validate_dsc(struct drm_atomic_state *state,
|
|||||||
int ind = find_crtc_index_in_state_by_stream(state, stream);
|
int ind = find_crtc_index_in_state_by_stream(state, stream);
|
||||||
|
|
||||||
if (ind >= 0) {
|
if (ind >= 0) {
|
||||||
|
struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(state->crtcs[ind].new_state);
|
||||||
|
|
||||||
DRM_INFO_ONCE("%s:%d MST_DSC no mode changed for stream 0x%p\n",
|
DRM_INFO_ONCE("%s:%d MST_DSC no mode changed for stream 0x%p\n",
|
||||||
__func__, __LINE__, stream);
|
__func__, __LINE__, stream);
|
||||||
state->crtcs[ind].new_state->mode_changed = 0;
|
dm_new_crtc_state->base.mode_changed = dm_new_crtc_state->mode_changed_independent_from_dsc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -650,9 +650,6 @@ static struct link_encoder *dce100_link_encoder_create(
|
|||||||
return &enc110->base;
|
return &enc110->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
link_regs_id =
|
link_regs_id =
|
||||||
map_transmitter_id_to_phy_instance(enc_init_data->transmitter);
|
map_transmitter_id_to_phy_instance(enc_init_data->transmitter);
|
||||||
|
|
||||||
@@ -661,7 +658,8 @@ static struct link_encoder *dce100_link_encoder_create(
|
|||||||
&link_enc_feature,
|
&link_enc_feature,
|
||||||
&link_enc_regs[link_regs_id],
|
&link_enc_regs[link_regs_id],
|
||||||
&link_enc_aux_regs[enc_init_data->channel - 1],
|
&link_enc_aux_regs[enc_init_data->channel - 1],
|
||||||
&link_enc_hpd_regs[enc_init_data->hpd_source]);
|
enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
|
||||||
|
NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
|
||||||
return &enc110->base;
|
return &enc110->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -671,7 +671,7 @@ static struct link_encoder *dce110_link_encoder_create(
|
|||||||
kzalloc_obj(struct dce110_link_encoder);
|
kzalloc_obj(struct dce110_link_encoder);
|
||||||
int link_regs_id;
|
int link_regs_id;
|
||||||
|
|
||||||
if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
|
if (!enc110)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
link_regs_id =
|
link_regs_id =
|
||||||
@@ -682,7 +682,8 @@ static struct link_encoder *dce110_link_encoder_create(
|
|||||||
&link_enc_feature,
|
&link_enc_feature,
|
||||||
&link_enc_regs[link_regs_id],
|
&link_enc_regs[link_regs_id],
|
||||||
&link_enc_aux_regs[enc_init_data->channel - 1],
|
&link_enc_aux_regs[enc_init_data->channel - 1],
|
||||||
&link_enc_hpd_regs[enc_init_data->hpd_source]);
|
enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
|
||||||
|
NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
|
||||||
return &enc110->base;
|
return &enc110->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -632,7 +632,7 @@ static struct link_encoder *dce112_link_encoder_create(
|
|||||||
kzalloc_obj(struct dce110_link_encoder);
|
kzalloc_obj(struct dce110_link_encoder);
|
||||||
int link_regs_id;
|
int link_regs_id;
|
||||||
|
|
||||||
if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
|
if (!enc110)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
link_regs_id =
|
link_regs_id =
|
||||||
@@ -643,7 +643,8 @@ static struct link_encoder *dce112_link_encoder_create(
|
|||||||
&link_enc_feature,
|
&link_enc_feature,
|
||||||
&link_enc_regs[link_regs_id],
|
&link_enc_regs[link_regs_id],
|
||||||
&link_enc_aux_regs[enc_init_data->channel - 1],
|
&link_enc_aux_regs[enc_init_data->channel - 1],
|
||||||
&link_enc_hpd_regs[enc_init_data->hpd_source]);
|
enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
|
||||||
|
NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
|
||||||
return &enc110->base;
|
return &enc110->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -716,7 +716,7 @@ static struct link_encoder *dce120_link_encoder_create(
|
|||||||
kzalloc_obj(struct dce110_link_encoder);
|
kzalloc_obj(struct dce110_link_encoder);
|
||||||
int link_regs_id;
|
int link_regs_id;
|
||||||
|
|
||||||
if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
|
if (!enc110)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
link_regs_id =
|
link_regs_id =
|
||||||
@@ -727,7 +727,8 @@ static struct link_encoder *dce120_link_encoder_create(
|
|||||||
&link_enc_feature,
|
&link_enc_feature,
|
||||||
&link_enc_regs[link_regs_id],
|
&link_enc_regs[link_regs_id],
|
||||||
&link_enc_aux_regs[enc_init_data->channel - 1],
|
&link_enc_aux_regs[enc_init_data->channel - 1],
|
||||||
&link_enc_hpd_regs[enc_init_data->hpd_source]);
|
enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
|
||||||
|
NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
|
||||||
|
|
||||||
return &enc110->base;
|
return &enc110->base;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -746,18 +746,16 @@ static struct link_encoder *dce60_link_encoder_create(
|
|||||||
return &enc110->base;
|
return &enc110->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
link_regs_id =
|
link_regs_id =
|
||||||
map_transmitter_id_to_phy_instance(enc_init_data->transmitter);
|
map_transmitter_id_to_phy_instance(enc_init_data->transmitter);
|
||||||
|
|
||||||
dce60_link_encoder_construct(enc110,
|
dce60_link_encoder_construct(enc110,
|
||||||
enc_init_data,
|
enc_init_data,
|
||||||
&link_enc_feature,
|
&link_enc_feature,
|
||||||
&link_enc_regs[link_regs_id],
|
&link_enc_regs[link_regs_id],
|
||||||
&link_enc_aux_regs[enc_init_data->channel - 1],
|
&link_enc_aux_regs[enc_init_data->channel - 1],
|
||||||
&link_enc_hpd_regs[enc_init_data->hpd_source]);
|
enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
|
||||||
|
NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
|
||||||
return &enc110->base;
|
return &enc110->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -752,9 +752,6 @@ static struct link_encoder *dce80_link_encoder_create(
|
|||||||
return &enc110->base;
|
return &enc110->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
link_regs_id =
|
link_regs_id =
|
||||||
map_transmitter_id_to_phy_instance(enc_init_data->transmitter);
|
map_transmitter_id_to_phy_instance(enc_init_data->transmitter);
|
||||||
|
|
||||||
@@ -763,7 +760,8 @@ static struct link_encoder *dce80_link_encoder_create(
|
|||||||
&link_enc_feature,
|
&link_enc_feature,
|
||||||
&link_enc_regs[link_regs_id],
|
&link_enc_regs[link_regs_id],
|
||||||
&link_enc_aux_regs[enc_init_data->channel - 1],
|
&link_enc_aux_regs[enc_init_data->channel - 1],
|
||||||
&link_enc_hpd_regs[enc_init_data->hpd_source]);
|
enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
|
||||||
|
NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
|
||||||
return &enc110->base;
|
return &enc110->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,10 @@
|
|||||||
|
|
||||||
#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
|
#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
|
||||||
|
|
||||||
|
static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
|
||||||
|
int od_feature_bit,
|
||||||
|
int32_t *min, int32_t *max);
|
||||||
|
|
||||||
static const struct smu_feature_bits smu_v13_0_0_dpm_features = {
|
static const struct smu_feature_bits smu_v13_0_0_dpm_features = {
|
||||||
.bits = {
|
.bits = {
|
||||||
SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
|
SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
|
||||||
@@ -1043,8 +1047,35 @@ static bool smu_v13_0_0_is_od_feature_supported(struct smu_context *smu,
|
|||||||
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
||||||
const OverDriveLimits_t * const overdrive_upperlimits =
|
const OverDriveLimits_t * const overdrive_upperlimits =
|
||||||
&pptable->SkuTable.OverDriveLimitsBasicMax;
|
&pptable->SkuTable.OverDriveLimitsBasicMax;
|
||||||
|
int32_t min_value, max_value;
|
||||||
|
bool feature_enabled;
|
||||||
|
|
||||||
return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit);
|
switch (od_feature_bit) {
|
||||||
|
case PP_OD_FEATURE_FAN_CURVE_BIT:
|
||||||
|
feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
|
||||||
|
if (feature_enabled) {
|
||||||
|
smu_v13_0_0_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP,
|
||||||
|
&min_value, &max_value);
|
||||||
|
if (!min_value && !max_value) {
|
||||||
|
feature_enabled = false;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
smu_v13_0_0_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM,
|
||||||
|
&min_value, &max_value);
|
||||||
|
if (!min_value && !max_value) {
|
||||||
|
feature_enabled = false;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return feature_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
|
static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
|
||||||
|
|||||||
@@ -1391,7 +1391,7 @@ static int smu_v13_0_6_emit_clk_levels(struct smu_context *smu,
|
|||||||
break;
|
break;
|
||||||
case SMU_OD_MCLK:
|
case SMU_OD_MCLK:
|
||||||
if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(SET_UCLK_MAX)))
|
if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(SET_UCLK_MAX)))
|
||||||
return 0;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK");
|
size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK");
|
||||||
size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n",
|
size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n",
|
||||||
@@ -2122,6 +2122,7 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu,
|
|||||||
{
|
{
|
||||||
struct smu_dpm_context *smu_dpm = &(smu->smu_dpm);
|
struct smu_dpm_context *smu_dpm = &(smu->smu_dpm);
|
||||||
struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context;
|
struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context;
|
||||||
|
struct smu_dpm_table *uclk_table = &dpm_context->dpm_tables.uclk_table;
|
||||||
struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
|
struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
|
||||||
uint32_t min_clk;
|
uint32_t min_clk;
|
||||||
uint32_t max_clk;
|
uint32_t max_clk;
|
||||||
@@ -2221,14 +2222,16 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu,
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
min_clk = SMU_DPM_TABLE_MIN(
|
if (SMU_DPM_TABLE_MAX(uclk_table) !=
|
||||||
&dpm_context->dpm_tables.uclk_table);
|
pstate_table->uclk_pstate.curr.max) {
|
||||||
max_clk = SMU_DPM_TABLE_MAX(
|
min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.uclk_table);
|
||||||
&dpm_context->dpm_tables.uclk_table);
|
max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table);
|
||||||
ret = smu_v13_0_6_set_soft_freq_limited_range(
|
ret = smu_v13_0_6_set_soft_freq_limited_range(smu,
|
||||||
smu, SMU_UCLK, min_clk, max_clk, false);
|
SMU_UCLK, min_clk,
|
||||||
if (ret)
|
max_clk, false);
|
||||||
return ret;
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
smu_v13_0_reset_custom_level(smu);
|
smu_v13_0_reset_custom_level(smu);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -59,6 +59,10 @@
|
|||||||
|
|
||||||
#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
|
#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
|
||||||
|
|
||||||
|
static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu,
|
||||||
|
int od_feature_bit,
|
||||||
|
int32_t *min, int32_t *max);
|
||||||
|
|
||||||
static const struct smu_feature_bits smu_v13_0_7_dpm_features = {
|
static const struct smu_feature_bits smu_v13_0_7_dpm_features = {
|
||||||
.bits = {
|
.bits = {
|
||||||
SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
|
SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
|
||||||
@@ -1053,8 +1057,35 @@ static bool smu_v13_0_7_is_od_feature_supported(struct smu_context *smu,
|
|||||||
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
||||||
const OverDriveLimits_t * const overdrive_upperlimits =
|
const OverDriveLimits_t * const overdrive_upperlimits =
|
||||||
&pptable->SkuTable.OverDriveLimitsBasicMax;
|
&pptable->SkuTable.OverDriveLimitsBasicMax;
|
||||||
|
int32_t min_value, max_value;
|
||||||
|
bool feature_enabled;
|
||||||
|
|
||||||
return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit);
|
switch (od_feature_bit) {
|
||||||
|
case PP_OD_FEATURE_FAN_CURVE_BIT:
|
||||||
|
feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
|
||||||
|
if (feature_enabled) {
|
||||||
|
smu_v13_0_7_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP,
|
||||||
|
&min_value, &max_value);
|
||||||
|
if (!min_value && !max_value) {
|
||||||
|
feature_enabled = false;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
smu_v13_0_7_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM,
|
||||||
|
&min_value, &max_value);
|
||||||
|
if (!min_value && !max_value) {
|
||||||
|
feature_enabled = false;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return feature_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu,
|
static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu,
|
||||||
|
|||||||
@@ -56,6 +56,10 @@
|
|||||||
|
|
||||||
#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
|
#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
|
||||||
|
|
||||||
|
static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
|
||||||
|
int od_feature_bit,
|
||||||
|
int32_t *min, int32_t *max);
|
||||||
|
|
||||||
static const struct smu_feature_bits smu_v14_0_2_dpm_features = {
|
static const struct smu_feature_bits smu_v14_0_2_dpm_features = {
|
||||||
.bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
|
.bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
|
||||||
SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT),
|
SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT),
|
||||||
@@ -922,8 +926,35 @@ static bool smu_v14_0_2_is_od_feature_supported(struct smu_context *smu,
|
|||||||
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
||||||
const OverDriveLimits_t * const overdrive_upperlimits =
|
const OverDriveLimits_t * const overdrive_upperlimits =
|
||||||
&pptable->SkuTable.OverDriveLimitsBasicMax;
|
&pptable->SkuTable.OverDriveLimitsBasicMax;
|
||||||
|
int32_t min_value, max_value;
|
||||||
|
bool feature_enabled;
|
||||||
|
|
||||||
return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit);
|
switch (od_feature_bit) {
|
||||||
|
case PP_OD_FEATURE_FAN_CURVE_BIT:
|
||||||
|
feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
|
||||||
|
if (feature_enabled) {
|
||||||
|
smu_v14_0_2_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP,
|
||||||
|
&min_value, &max_value);
|
||||||
|
if (!min_value && !max_value) {
|
||||||
|
feature_enabled = false;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
smu_v14_0_2_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM,
|
||||||
|
&min_value, &max_value);
|
||||||
|
if (!min_value && !max_value) {
|
||||||
|
feature_enabled = false;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return feature_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
|
static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
|
||||||
|
|||||||
@@ -550,27 +550,27 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);
|
EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);
|
||||||
|
|
||||||
static bool drm_gem_shmem_try_map_pmd(struct vm_fault *vmf, unsigned long addr,
|
static vm_fault_t try_insert_pfn(struct vm_fault *vmf, unsigned int order,
|
||||||
struct page *page)
|
unsigned long pfn)
|
||||||
{
|
{
|
||||||
|
if (!order) {
|
||||||
|
return vmf_insert_pfn(vmf->vma, vmf->address, pfn);
|
||||||
#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
|
#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
|
||||||
unsigned long pfn = page_to_pfn(page);
|
} else if (order == PMD_ORDER) {
|
||||||
unsigned long paddr = pfn << PAGE_SHIFT;
|
unsigned long paddr = pfn << PAGE_SHIFT;
|
||||||
bool aligned = (addr & ~PMD_MASK) == (paddr & ~PMD_MASK);
|
bool aligned = (vmf->address & ~PMD_MASK) == (paddr & ~PMD_MASK);
|
||||||
|
|
||||||
if (aligned &&
|
if (aligned &&
|
||||||
pmd_none(*vmf->pmd) &&
|
folio_test_pmd_mappable(page_folio(pfn_to_page(pfn)))) {
|
||||||
folio_test_pmd_mappable(page_folio(page))) {
|
pfn &= PMD_MASK >> PAGE_SHIFT;
|
||||||
pfn &= PMD_MASK >> PAGE_SHIFT;
|
return vmf_insert_pfn_pmd(vmf, pfn, false);
|
||||||
if (vmf_insert_pfn_pmd(vmf, pfn, false) == VM_FAULT_NOPAGE)
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
return false;
|
return VM_FAULT_FALLBACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
|
static vm_fault_t drm_gem_shmem_any_fault(struct vm_fault *vmf, unsigned int order)
|
||||||
{
|
{
|
||||||
struct vm_area_struct *vma = vmf->vma;
|
struct vm_area_struct *vma = vmf->vma;
|
||||||
struct drm_gem_object *obj = vma->vm_private_data;
|
struct drm_gem_object *obj = vma->vm_private_data;
|
||||||
@@ -581,6 +581,9 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
|
|||||||
pgoff_t page_offset;
|
pgoff_t page_offset;
|
||||||
unsigned long pfn;
|
unsigned long pfn;
|
||||||
|
|
||||||
|
if (order && order != PMD_ORDER)
|
||||||
|
return VM_FAULT_FALLBACK;
|
||||||
|
|
||||||
/* Offset to faulty address in the VMA. */
|
/* Offset to faulty address in the VMA. */
|
||||||
page_offset = vmf->pgoff - vma->vm_pgoff;
|
page_offset = vmf->pgoff - vma->vm_pgoff;
|
||||||
|
|
||||||
@@ -593,13 +596,8 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drm_gem_shmem_try_map_pmd(vmf, vmf->address, pages[page_offset])) {
|
|
||||||
ret = VM_FAULT_NOPAGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
pfn = page_to_pfn(pages[page_offset]);
|
pfn = page_to_pfn(pages[page_offset]);
|
||||||
ret = vmf_insert_pfn(vma, vmf->address, pfn);
|
ret = try_insert_pfn(vmf, order, pfn);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
dma_resv_unlock(shmem->base.resv);
|
dma_resv_unlock(shmem->base.resv);
|
||||||
@@ -607,6 +605,11 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
|
||||||
|
{
|
||||||
|
return drm_gem_shmem_any_fault(vmf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void drm_gem_shmem_vm_open(struct vm_area_struct *vma)
|
static void drm_gem_shmem_vm_open(struct vm_area_struct *vma)
|
||||||
{
|
{
|
||||||
struct drm_gem_object *obj = vma->vm_private_data;
|
struct drm_gem_object *obj = vma->vm_private_data;
|
||||||
@@ -643,6 +646,9 @@ static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
|
|||||||
|
|
||||||
const struct vm_operations_struct drm_gem_shmem_vm_ops = {
|
const struct vm_operations_struct drm_gem_shmem_vm_ops = {
|
||||||
.fault = drm_gem_shmem_fault,
|
.fault = drm_gem_shmem_fault,
|
||||||
|
#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
|
||||||
|
.huge_fault = drm_gem_shmem_any_fault,
|
||||||
|
#endif
|
||||||
.open = drm_gem_shmem_vm_open,
|
.open = drm_gem_shmem_vm_open,
|
||||||
.close = drm_gem_shmem_vm_close,
|
.close = drm_gem_shmem_vm_close,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -602,7 +602,7 @@ int drm_syncobj_get_handle(struct drm_file *file_private,
|
|||||||
drm_syncobj_get(syncobj);
|
drm_syncobj_get(syncobj);
|
||||||
|
|
||||||
ret = xa_alloc(&file_private->syncobj_xa, handle, syncobj, xa_limit_32b,
|
ret = xa_alloc(&file_private->syncobj_xa, handle, syncobj, xa_limit_32b,
|
||||||
GFP_NOWAIT);
|
GFP_KERNEL);
|
||||||
if (ret)
|
if (ret)
|
||||||
drm_syncobj_put(syncobj);
|
drm_syncobj_put(syncobj);
|
||||||
|
|
||||||
@@ -716,7 +716,7 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
|
|||||||
drm_syncobj_get(syncobj);
|
drm_syncobj_get(syncobj);
|
||||||
|
|
||||||
ret = xa_alloc(&file_private->syncobj_xa, handle, syncobj, xa_limit_32b,
|
ret = xa_alloc(&file_private->syncobj_xa, handle, syncobj, xa_limit_32b,
|
||||||
GFP_NOWAIT);
|
GFP_KERNEL);
|
||||||
if (ret)
|
if (ret)
|
||||||
drm_syncobj_put(syncobj);
|
drm_syncobj_put(syncobj);
|
||||||
|
|
||||||
|
|||||||
@@ -4602,6 +4602,7 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state,
|
|||||||
struct intel_crtc_state *crtc_state =
|
struct intel_crtc_state *crtc_state =
|
||||||
intel_atomic_get_new_crtc_state(state, crtc);
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
struct intel_crtc_state *saved_state;
|
struct intel_crtc_state *saved_state;
|
||||||
|
int err;
|
||||||
|
|
||||||
saved_state = intel_crtc_state_alloc(crtc);
|
saved_state = intel_crtc_state_alloc(crtc);
|
||||||
if (!saved_state)
|
if (!saved_state)
|
||||||
@@ -4610,7 +4611,12 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state,
|
|||||||
/* free the old crtc_state->hw members */
|
/* free the old crtc_state->hw members */
|
||||||
intel_crtc_free_hw_state(crtc_state);
|
intel_crtc_free_hw_state(crtc_state);
|
||||||
|
|
||||||
intel_dp_tunnel_atomic_clear_stream_bw(state, crtc_state);
|
err = intel_dp_tunnel_atomic_clear_stream_bw(state, crtc_state);
|
||||||
|
if (err) {
|
||||||
|
kfree(saved_state);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME: before the switch to atomic started, a new pipe_config was
|
/* FIXME: before the switch to atomic started, a new pipe_config was
|
||||||
* kzalloc'd. Code that depends on any field being zero should be
|
* kzalloc'd. Code that depends on any field being zero should be
|
||||||
|
|||||||
@@ -621,19 +621,27 @@ int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
|
|||||||
*
|
*
|
||||||
* Clear any DP tunnel stream BW requirement set by
|
* Clear any DP tunnel stream BW requirement set by
|
||||||
* intel_dp_tunnel_atomic_compute_stream_bw().
|
* intel_dp_tunnel_atomic_compute_stream_bw().
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success, a negative error code otherwise.
|
||||||
*/
|
*/
|
||||||
void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
|
int intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
|
||||||
struct intel_crtc_state *crtc_state)
|
struct intel_crtc_state *crtc_state)
|
||||||
{
|
{
|
||||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||||
|
int err;
|
||||||
|
|
||||||
if (!crtc_state->dp_tunnel_ref.tunnel)
|
if (!crtc_state->dp_tunnel_ref.tunnel)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
|
err = drm_dp_tunnel_atomic_set_stream_bw(&state->base,
|
||||||
|
crtc_state->dp_tunnel_ref.tunnel,
|
||||||
|
crtc->pipe, 0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
drm_dp_tunnel_atomic_set_stream_bw(&state->base,
|
|
||||||
crtc_state->dp_tunnel_ref.tunnel,
|
|
||||||
crtc->pipe, 0);
|
|
||||||
drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref);
|
drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
|
|||||||
struct intel_dp *intel_dp,
|
struct intel_dp *intel_dp,
|
||||||
const struct intel_connector *connector,
|
const struct intel_connector *connector,
|
||||||
struct intel_crtc_state *crtc_state);
|
struct intel_crtc_state *crtc_state);
|
||||||
void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
|
int intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
|
||||||
struct intel_crtc_state *crtc_state);
|
struct intel_crtc_state *crtc_state);
|
||||||
|
|
||||||
int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
|
int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc);
|
struct intel_crtc *crtc);
|
||||||
@@ -88,9 +88,12 @@ intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline int
|
||||||
intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
|
intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
|
||||||
struct intel_crtc_state *crtc_state) {}
|
struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
|
intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
|
||||||
|
|||||||
@@ -496,8 +496,10 @@ gmbus_xfer_read_chunk(struct intel_display *display,
|
|||||||
|
|
||||||
val = intel_de_read_fw(display, GMBUS3(display));
|
val = intel_de_read_fw(display, GMBUS3(display));
|
||||||
do {
|
do {
|
||||||
if (extra_byte_added && len == 1)
|
if (extra_byte_added && len == 1) {
|
||||||
|
len--;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
*buf++ = val & 0xff;
|
*buf++ = val & 0xff;
|
||||||
val >>= 8;
|
val >>= 8;
|
||||||
|
|||||||
@@ -436,11 +436,16 @@ void intel_plane_copy_hw_state(struct intel_plane_state *plane_state,
|
|||||||
drm_framebuffer_get(plane_state->hw.fb);
|
drm_framebuffer_get(plane_state->hw.fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void unlink_nv12_plane(struct intel_crtc_state *crtc_state,
|
||||||
|
struct intel_plane_state *plane_state);
|
||||||
|
|
||||||
void intel_plane_set_invisible(struct intel_crtc_state *crtc_state,
|
void intel_plane_set_invisible(struct intel_crtc_state *crtc_state,
|
||||||
struct intel_plane_state *plane_state)
|
struct intel_plane_state *plane_state)
|
||||||
{
|
{
|
||||||
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
|
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
|
||||||
|
|
||||||
|
unlink_nv12_plane(crtc_state, plane_state);
|
||||||
|
|
||||||
crtc_state->active_planes &= ~BIT(plane->id);
|
crtc_state->active_planes &= ~BIT(plane->id);
|
||||||
crtc_state->scaled_planes &= ~BIT(plane->id);
|
crtc_state->scaled_planes &= ~BIT(plane->id);
|
||||||
crtc_state->nv12_planes &= ~BIT(plane->id);
|
crtc_state->nv12_planes &= ~BIT(plane->id);
|
||||||
@@ -1513,6 +1518,9 @@ static void unlink_nv12_plane(struct intel_crtc_state *crtc_state,
|
|||||||
struct intel_display *display = to_intel_display(plane_state);
|
struct intel_display *display = to_intel_display(plane_state);
|
||||||
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
|
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
|
||||||
|
|
||||||
|
if (!plane_state->planar_linked_plane)
|
||||||
|
return;
|
||||||
|
|
||||||
plane_state->planar_linked_plane = NULL;
|
plane_state->planar_linked_plane = NULL;
|
||||||
|
|
||||||
if (!plane_state->is_y_plane)
|
if (!plane_state->is_y_plane)
|
||||||
@@ -1550,8 +1558,7 @@ static int icl_check_nv12_planes(struct intel_atomic_state *state,
|
|||||||
if (plane->pipe != crtc->pipe)
|
if (plane->pipe != crtc->pipe)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (plane_state->planar_linked_plane)
|
unlink_nv12_plane(crtc_state, plane_state);
|
||||||
unlink_nv12_plane(crtc_state, plane_state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!crtc_state->nv12_planes)
|
if (!crtc_state->nv12_planes)
|
||||||
|
|||||||
@@ -25,9 +25,9 @@
|
|||||||
might_sleep(); \
|
might_sleep(); \
|
||||||
for (;;) { \
|
for (;;) { \
|
||||||
const bool expired__ = ktime_after(ktime_get_raw(), end__); \
|
const bool expired__ = ktime_after(ktime_get_raw(), end__); \
|
||||||
OP; \
|
|
||||||
/* Guarantee COND check prior to timeout */ \
|
/* Guarantee COND check prior to timeout */ \
|
||||||
barrier(); \
|
barrier(); \
|
||||||
|
OP; \
|
||||||
if (COND) { \
|
if (COND) { \
|
||||||
ret__ = 0; \
|
ret__ = 0; \
|
||||||
break; \
|
break; \
|
||||||
|
|||||||
@@ -1236,6 +1236,11 @@ static int mtk_dsi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
dsi->host.ops = &mtk_dsi_ops;
|
dsi->host.ops = &mtk_dsi_ops;
|
||||||
dsi->host.dev = dev;
|
dsi->host.dev = dev;
|
||||||
|
|
||||||
|
init_waitqueue_head(&dsi->irq_wait_queue);
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, dsi);
|
||||||
|
|
||||||
ret = mipi_dsi_host_register(&dsi->host);
|
ret = mipi_dsi_host_register(&dsi->host);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return dev_err_probe(dev, ret, "Failed to register DSI host\n");
|
return dev_err_probe(dev, ret, "Failed to register DSI host\n");
|
||||||
@@ -1247,10 +1252,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
|
|||||||
return dev_err_probe(&pdev->dev, ret, "Failed to request DSI irq\n");
|
return dev_err_probe(&pdev->dev, ret, "Failed to request DSI irq\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
init_waitqueue_head(&dsi->irq_wait_queue);
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, dsi);
|
|
||||||
|
|
||||||
dsi->bridge.of_node = dev->of_node;
|
dsi->bridge.of_node = dev->of_node;
|
||||||
dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
|
dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
|
||||||
|
|
||||||
|
|||||||
@@ -553,6 +553,7 @@
|
|||||||
#define ENABLE_SMP_LD_RENDER_SURFACE_CONTROL REG_BIT(44 - 32)
|
#define ENABLE_SMP_LD_RENDER_SURFACE_CONTROL REG_BIT(44 - 32)
|
||||||
#define FORCE_SLM_FENCE_SCOPE_TO_TILE REG_BIT(42 - 32)
|
#define FORCE_SLM_FENCE_SCOPE_TO_TILE REG_BIT(42 - 32)
|
||||||
#define FORCE_UGM_FENCE_SCOPE_TO_TILE REG_BIT(41 - 32)
|
#define FORCE_UGM_FENCE_SCOPE_TO_TILE REG_BIT(41 - 32)
|
||||||
|
#define L3_128B_256B_WRT_DIS REG_BIT(40 - 32)
|
||||||
#define MAXREQS_PER_BANK REG_GENMASK(39 - 32, 37 - 32)
|
#define MAXREQS_PER_BANK REG_GENMASK(39 - 32, 37 - 32)
|
||||||
#define DISABLE_128B_EVICTION_COMMAND_UDW REG_BIT(36 - 32)
|
#define DISABLE_128B_EVICTION_COMMAND_UDW REG_BIT(36 - 32)
|
||||||
|
|
||||||
|
|||||||
@@ -1442,9 +1442,9 @@ static int op_check_svm_userptr(struct xe_vm *vm, struct xe_vma_op *op,
|
|||||||
err = vma_check_userptr(vm, op->map.vma, pt_update);
|
err = vma_check_userptr(vm, op->map.vma, pt_update);
|
||||||
break;
|
break;
|
||||||
case DRM_GPUVA_OP_REMAP:
|
case DRM_GPUVA_OP_REMAP:
|
||||||
if (op->remap.prev)
|
if (op->remap.prev && !op->remap.skip_prev)
|
||||||
err = vma_check_userptr(vm, op->remap.prev, pt_update);
|
err = vma_check_userptr(vm, op->remap.prev, pt_update);
|
||||||
if (!err && op->remap.next)
|
if (!err && op->remap.next && !op->remap.skip_next)
|
||||||
err = vma_check_userptr(vm, op->remap.next, pt_update);
|
err = vma_check_userptr(vm, op->remap.next, pt_update);
|
||||||
break;
|
break;
|
||||||
case DRM_GPUVA_OP_UNMAP:
|
case DRM_GPUVA_OP_UNMAP:
|
||||||
@@ -2198,12 +2198,12 @@ static int op_prepare(struct xe_vm *vm,
|
|||||||
|
|
||||||
err = unbind_op_prepare(tile, pt_update_ops, old);
|
err = unbind_op_prepare(tile, pt_update_ops, old);
|
||||||
|
|
||||||
if (!err && op->remap.prev) {
|
if (!err && op->remap.prev && !op->remap.skip_prev) {
|
||||||
err = bind_op_prepare(vm, tile, pt_update_ops,
|
err = bind_op_prepare(vm, tile, pt_update_ops,
|
||||||
op->remap.prev, false);
|
op->remap.prev, false);
|
||||||
pt_update_ops->wait_vm_bookkeep = true;
|
pt_update_ops->wait_vm_bookkeep = true;
|
||||||
}
|
}
|
||||||
if (!err && op->remap.next) {
|
if (!err && op->remap.next && !op->remap.skip_next) {
|
||||||
err = bind_op_prepare(vm, tile, pt_update_ops,
|
err = bind_op_prepare(vm, tile, pt_update_ops,
|
||||||
op->remap.next, false);
|
op->remap.next, false);
|
||||||
pt_update_ops->wait_vm_bookkeep = true;
|
pt_update_ops->wait_vm_bookkeep = true;
|
||||||
@@ -2428,10 +2428,10 @@ static void op_commit(struct xe_vm *vm,
|
|||||||
|
|
||||||
unbind_op_commit(vm, tile, pt_update_ops, old, fence, fence2);
|
unbind_op_commit(vm, tile, pt_update_ops, old, fence, fence2);
|
||||||
|
|
||||||
if (op->remap.prev)
|
if (op->remap.prev && !op->remap.skip_prev)
|
||||||
bind_op_commit(vm, tile, pt_update_ops, op->remap.prev,
|
bind_op_commit(vm, tile, pt_update_ops, op->remap.prev,
|
||||||
fence, fence2, false);
|
fence, fence2, false);
|
||||||
if (op->remap.next)
|
if (op->remap.next && !op->remap.skip_next)
|
||||||
bind_op_commit(vm, tile, pt_update_ops, op->remap.next,
|
bind_op_commit(vm, tile, pt_update_ops, op->remap.next,
|
||||||
fence, fence2, false);
|
fence, fence2, false);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -341,6 +341,8 @@ ssize_t xe_sriov_packet_write_single(struct xe_device *xe, unsigned int vfid,
|
|||||||
ret = xe_sriov_pf_migration_restore_produce(xe, vfid, *data);
|
ret = xe_sriov_pf_migration_restore_produce(xe, vfid, *data);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
xe_sriov_packet_free(*data);
|
xe_sriov_packet_free(*data);
|
||||||
|
*data = NULL;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2554,7 +2554,6 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op)
|
|||||||
if (!err && op->remap.skip_prev) {
|
if (!err && op->remap.skip_prev) {
|
||||||
op->remap.prev->tile_present =
|
op->remap.prev->tile_present =
|
||||||
tile_present;
|
tile_present;
|
||||||
op->remap.prev = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (op->remap.next) {
|
if (op->remap.next) {
|
||||||
@@ -2564,11 +2563,13 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op)
|
|||||||
if (!err && op->remap.skip_next) {
|
if (!err && op->remap.skip_next) {
|
||||||
op->remap.next->tile_present =
|
op->remap.next->tile_present =
|
||||||
tile_present;
|
tile_present;
|
||||||
op->remap.next = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adjust for partial unbind after removing VMA from VM */
|
/*
|
||||||
|
* Adjust for partial unbind after removing VMA from VM. In case
|
||||||
|
* of unwind we might need to undo this later.
|
||||||
|
*/
|
||||||
if (!err) {
|
if (!err) {
|
||||||
op->base.remap.unmap->va->va.addr = op->remap.start;
|
op->base.remap.unmap->va->va.addr = op->remap.start;
|
||||||
op->base.remap.unmap->va->va.range = op->remap.range;
|
op->base.remap.unmap->va->va.range = op->remap.range;
|
||||||
@@ -2687,6 +2688,8 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops,
|
|||||||
|
|
||||||
op->remap.start = xe_vma_start(old);
|
op->remap.start = xe_vma_start(old);
|
||||||
op->remap.range = xe_vma_size(old);
|
op->remap.range = xe_vma_size(old);
|
||||||
|
op->remap.old_start = op->remap.start;
|
||||||
|
op->remap.old_range = op->remap.range;
|
||||||
|
|
||||||
flags |= op->base.remap.unmap->va->flags & XE_VMA_CREATE_MASK;
|
flags |= op->base.remap.unmap->va->flags & XE_VMA_CREATE_MASK;
|
||||||
if (op->base.remap.prev) {
|
if (op->base.remap.prev) {
|
||||||
@@ -2835,8 +2838,19 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
|
|||||||
xe_svm_notifier_lock(vm);
|
xe_svm_notifier_lock(vm);
|
||||||
vma->gpuva.flags &= ~XE_VMA_DESTROYED;
|
vma->gpuva.flags &= ~XE_VMA_DESTROYED;
|
||||||
xe_svm_notifier_unlock(vm);
|
xe_svm_notifier_unlock(vm);
|
||||||
if (post_commit)
|
if (post_commit) {
|
||||||
|
/*
|
||||||
|
* Restore the old va range, in case of the
|
||||||
|
* prev/next skip optimisation. Otherwise what
|
||||||
|
* we re-insert here could be smaller than the
|
||||||
|
* original range.
|
||||||
|
*/
|
||||||
|
op->base.remap.unmap->va->va.addr =
|
||||||
|
op->remap.old_start;
|
||||||
|
op->base.remap.unmap->va->va.range =
|
||||||
|
op->remap.old_range;
|
||||||
xe_vm_insert_vma(vm, vma);
|
xe_vm_insert_vma(vm, vma);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -373,6 +373,10 @@ struct xe_vma_op_remap {
|
|||||||
u64 start;
|
u64 start;
|
||||||
/** @range: range of the VMA unmap */
|
/** @range: range of the VMA unmap */
|
||||||
u64 range;
|
u64 range;
|
||||||
|
/** @old_start: Original start of the VMA we unmap */
|
||||||
|
u64 old_start;
|
||||||
|
/** @old_range: Original range of the VMA we unmap */
|
||||||
|
u64 old_range;
|
||||||
/** @skip_prev: skip prev rebind */
|
/** @skip_prev: skip prev rebind */
|
||||||
bool skip_prev;
|
bool skip_prev;
|
||||||
/** @skip_next: skip next rebind */
|
/** @skip_next: skip next rebind */
|
||||||
|
|||||||
@@ -247,7 +247,8 @@ static const struct xe_rtp_entry_sr gt_was[] = {
|
|||||||
LSN_DIM_Z_WGT_MASK,
|
LSN_DIM_Z_WGT_MASK,
|
||||||
LSN_LNI_WGT(1) | LSN_LNE_WGT(1) |
|
LSN_LNI_WGT(1) | LSN_LNE_WGT(1) |
|
||||||
LSN_DIM_X_WGT(1) | LSN_DIM_Y_WGT(1) |
|
LSN_DIM_X_WGT(1) | LSN_DIM_Y_WGT(1) |
|
||||||
LSN_DIM_Z_WGT(1)))
|
LSN_DIM_Z_WGT(1)),
|
||||||
|
SET(LSC_CHICKEN_BIT_0_UDW, L3_128B_256B_WRT_DIS))
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Xe2_HPM */
|
/* Xe2_HPM */
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#include <linux/hwmon.h>
|
#include <linux/hwmon.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/math64.h>
|
||||||
|
#include <linux/minmax.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
|
||||||
@@ -33,7 +35,7 @@
|
|||||||
struct adm1177_state {
|
struct adm1177_state {
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
u32 r_sense_uohm;
|
u32 r_sense_uohm;
|
||||||
u32 alert_threshold_ua;
|
u64 alert_threshold_ua;
|
||||||
bool vrange_high;
|
bool vrange_high;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,7 +50,7 @@ static int adm1177_write_cmd(struct adm1177_state *st, u8 cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int adm1177_write_alert_thr(struct adm1177_state *st,
|
static int adm1177_write_alert_thr(struct adm1177_state *st,
|
||||||
u32 alert_threshold_ua)
|
u64 alert_threshold_ua)
|
||||||
{
|
{
|
||||||
u64 val;
|
u64 val;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -91,8 +93,8 @@ static int adm1177_read(struct device *dev, enum hwmon_sensor_types type,
|
|||||||
*val = div_u64((105840000ull * dummy),
|
*val = div_u64((105840000ull * dummy),
|
||||||
4096 * st->r_sense_uohm);
|
4096 * st->r_sense_uohm);
|
||||||
return 0;
|
return 0;
|
||||||
case hwmon_curr_max_alarm:
|
case hwmon_curr_max:
|
||||||
*val = st->alert_threshold_ua;
|
*val = div_u64(st->alert_threshold_ua, 1000);
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
@@ -126,9 +128,10 @@ static int adm1177_write(struct device *dev, enum hwmon_sensor_types type,
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case hwmon_curr:
|
case hwmon_curr:
|
||||||
switch (attr) {
|
switch (attr) {
|
||||||
case hwmon_curr_max_alarm:
|
case hwmon_curr_max:
|
||||||
adm1177_write_alert_thr(st, val);
|
val = clamp_val(val, 0,
|
||||||
return 0;
|
div_u64(105840000ULL, st->r_sense_uohm));
|
||||||
|
return adm1177_write_alert_thr(st, (u64)val * 1000);
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
@@ -156,7 +159,7 @@ static umode_t adm1177_is_visible(const void *data,
|
|||||||
if (st->r_sense_uohm)
|
if (st->r_sense_uohm)
|
||||||
return 0444;
|
return 0444;
|
||||||
return 0;
|
return 0;
|
||||||
case hwmon_curr_max_alarm:
|
case hwmon_curr_max:
|
||||||
if (st->r_sense_uohm)
|
if (st->r_sense_uohm)
|
||||||
return 0644;
|
return 0644;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -170,7 +173,7 @@ static umode_t adm1177_is_visible(const void *data,
|
|||||||
|
|
||||||
static const struct hwmon_channel_info * const adm1177_info[] = {
|
static const struct hwmon_channel_info * const adm1177_info[] = {
|
||||||
HWMON_CHANNEL_INFO(curr,
|
HWMON_CHANNEL_INFO(curr,
|
||||||
HWMON_C_INPUT | HWMON_C_MAX_ALARM),
|
HWMON_C_INPUT | HWMON_C_MAX),
|
||||||
HWMON_CHANNEL_INFO(in,
|
HWMON_CHANNEL_INFO(in,
|
||||||
HWMON_I_INPUT),
|
HWMON_I_INPUT),
|
||||||
NULL
|
NULL
|
||||||
@@ -192,7 +195,8 @@ static int adm1177_probe(struct i2c_client *client)
|
|||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct adm1177_state *st;
|
struct adm1177_state *st;
|
||||||
u32 alert_threshold_ua;
|
u64 alert_threshold_ua;
|
||||||
|
u32 prop;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
|
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
|
||||||
@@ -208,22 +212,26 @@ static int adm1177_probe(struct i2c_client *client)
|
|||||||
if (device_property_read_u32(dev, "shunt-resistor-micro-ohms",
|
if (device_property_read_u32(dev, "shunt-resistor-micro-ohms",
|
||||||
&st->r_sense_uohm))
|
&st->r_sense_uohm))
|
||||||
st->r_sense_uohm = 0;
|
st->r_sense_uohm = 0;
|
||||||
if (device_property_read_u32(dev, "adi,shutdown-threshold-microamp",
|
if (!device_property_read_u32(dev, "adi,shutdown-threshold-microamp",
|
||||||
&alert_threshold_ua)) {
|
&prop)) {
|
||||||
if (st->r_sense_uohm)
|
alert_threshold_ua = prop;
|
||||||
/*
|
} else if (st->r_sense_uohm) {
|
||||||
* set maximum default value from datasheet based on
|
/*
|
||||||
* shunt-resistor
|
* set maximum default value from datasheet based on
|
||||||
*/
|
* shunt-resistor
|
||||||
alert_threshold_ua = div_u64(105840000000,
|
*/
|
||||||
st->r_sense_uohm);
|
alert_threshold_ua = div_u64(105840000000ULL,
|
||||||
else
|
st->r_sense_uohm);
|
||||||
alert_threshold_ua = 0;
|
} else {
|
||||||
|
alert_threshold_ua = 0;
|
||||||
}
|
}
|
||||||
st->vrange_high = device_property_read_bool(dev,
|
st->vrange_high = device_property_read_bool(dev,
|
||||||
"adi,vrange-high-enable");
|
"adi,vrange-high-enable");
|
||||||
if (alert_threshold_ua && st->r_sense_uohm)
|
if (alert_threshold_ua && st->r_sense_uohm) {
|
||||||
adm1177_write_alert_thr(st, alert_threshold_ua);
|
ret = adm1177_write_alert_thr(st, alert_threshold_ua);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ret = adm1177_write_cmd(st, ADM1177_CMD_V_CONT |
|
ret = adm1177_write_cmd(st, ADM1177_CMD_V_CONT |
|
||||||
ADM1177_CMD_I_CONT |
|
ADM1177_CMD_I_CONT |
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ static int get_temp_target(struct peci_cputemp *priv, enum peci_temp_target_type
|
|||||||
*val = priv->temp.target.tjmax;
|
*val = priv->temp.target.tjmax;
|
||||||
break;
|
break;
|
||||||
case crit_hyst_type:
|
case crit_hyst_type:
|
||||||
*val = priv->temp.target.tjmax - priv->temp.target.tcontrol;
|
*val = priv->temp.target.tcontrol;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
@@ -319,7 +319,7 @@ static umode_t cputemp_is_visible(const void *data, enum hwmon_sensor_types type
|
|||||||
{
|
{
|
||||||
const struct peci_cputemp *priv = data;
|
const struct peci_cputemp *priv = data;
|
||||||
|
|
||||||
if (channel > CPUTEMP_CHANNEL_NUMS)
|
if (channel >= CPUTEMP_CHANNEL_NUMS)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (channel < channel_core)
|
if (channel < channel_core)
|
||||||
|
|||||||
@@ -72,7 +72,8 @@ static int ina233_read_word_data(struct i2c_client *client, int page,
|
|||||||
|
|
||||||
/* Adjust returned value to match VIN coefficients */
|
/* Adjust returned value to match VIN coefficients */
|
||||||
/* VIN: 1.25 mV VSHUNT: 2.5 uV LSB */
|
/* VIN: 1.25 mV VSHUNT: 2.5 uV LSB */
|
||||||
ret = DIV_ROUND_CLOSEST(ret * 25, 12500);
|
ret = clamp_val(DIV_ROUND_CLOSEST((s16)ret * 25, 12500),
|
||||||
|
S16_MIN, S16_MAX) & 0xffff;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -ENODATA;
|
ret = -ENODATA;
|
||||||
|
|||||||
@@ -96,7 +96,15 @@ static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client,
|
|||||||
int page,
|
int page,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
int val = pmbus_read_byte_data(client, page, PMBUS_OPERATION);
|
int val;
|
||||||
|
|
||||||
|
val = pmbus_lock_interruptible(client);
|
||||||
|
if (val)
|
||||||
|
return val;
|
||||||
|
|
||||||
|
val = pmbus_read_byte_data(client, page, PMBUS_OPERATION);
|
||||||
|
|
||||||
|
pmbus_unlock(client);
|
||||||
|
|
||||||
if (val < 0)
|
if (val < 0)
|
||||||
return val;
|
return val;
|
||||||
@@ -118,6 +126,10 @@ static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client,
|
|||||||
|
|
||||||
op_val = result ? ISL68137_VOUT_AVS : 0;
|
op_val = result ? ISL68137_VOUT_AVS : 0;
|
||||||
|
|
||||||
|
rc = pmbus_lock_interruptible(client);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Writes to VOUT setpoint over AVSBus will persist after the VRM is
|
* Writes to VOUT setpoint over AVSBus will persist after the VRM is
|
||||||
* switched to PMBus control. Switching back to AVSBus control
|
* switched to PMBus control. Switching back to AVSBus control
|
||||||
@@ -129,17 +141,20 @@ static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client,
|
|||||||
rc = pmbus_read_word_data(client, page, 0xff,
|
rc = pmbus_read_word_data(client, page, 0xff,
|
||||||
PMBUS_VOUT_COMMAND);
|
PMBUS_VOUT_COMMAND);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
goto unlock;
|
||||||
|
|
||||||
rc = pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND,
|
rc = pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND,
|
||||||
rc);
|
rc);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = pmbus_update_byte_data(client, page, PMBUS_OPERATION,
|
rc = pmbus_update_byte_data(client, page, PMBUS_OPERATION,
|
||||||
ISL68137_VOUT_AVS, op_val);
|
ISL68137_VOUT_AVS, op_val);
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
pmbus_unlock(client);
|
||||||
|
|
||||||
return (rc < 0) ? rc : count;
|
return (rc < 0) ? rc : count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user