Merge branch 'sched/urgent' into sched/core, to resolve conflicts

The following fix in sched/urgent:

  e08d007f9d ("sched/debug: Fix avg_vruntime() usage")

is in conflict with this pending commit in sched/core:

  4823725d9d ("sched/fair: Increase weight bits for avg_vruntime")

Both modify the same variable definition and initialization blocks,
resolve it by merging the two.

 Conflicts:
	kernel/sched/debug.c

Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar
2026-04-02 15:03:51 +02:00
725 changed files with 8904 additions and 3620 deletions

View File

@@ -316,6 +316,7 @@ Hans Verkuil <hverkuil@kernel.org> <hverkuil-cisco@xs4all.nl>
Hans Verkuil <hverkuil@kernel.org> <hansverk@cisco.com>
Hao Ge <hao.ge@linux.dev> <gehao@kylinos.cn>
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> <heiko.carstens@de.ibm.com>
Heiko Stuebner <heiko@sntech.de> <heiko.stuebner@bqreaders.com>
@@ -327,6 +328,7 @@ Henrik Rydberg <rydberg@bitmath.org>
Herbert Xu <herbert@gondor.apana.org.au>
Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
Ignat Korchagin <ignat@linux.win> <ignat@cloudflare.com>
Ike Panhc <ikepanhc@gmail.com> <ike.pan@canonical.com>
J. Bruce Fields <bfields@fieldses.org> <bfields@redhat.com>
J. Bruce Fields <bfields@fieldses.org> <bfields@citi.umich.edu>
@@ -586,6 +588,7 @@ Morten Welinder <terra@gnome.org>
Morten Welinder <welinder@anemone.rentec.com>
Morten Welinder <welinder@darter.rentec.com>
Morten Welinder <welinder@troll.com>
Muhammad Usama Anjum <usama.anjum@arm.com> <usama.anjum@collabora.com>
Mukesh Ojha <quic_mojha@quicinc.com> <mojha@codeaurora.org>
Muna Sinada <quic_msinada@quicinc.com> <msinada@codeaurora.org>
Murali Nalajala <quic_mnalajal@quicinc.com> <mnalajal@codeaurora.org>

View File

@@ -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
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
--------------

View File

@@ -149,11 +149,33 @@ For architectures that require cache flushing for DMA coherence
DMA_ATTR_MMIO will not perform any cache flushing. The address
provided must never be mapped cacheable into the CPU.
DMA_ATTR_CPU_CACHE_CLEAN
------------------------
DMA_ATTR_DEBUGGING_IGNORE_CACHELINES
------------------------------------
This attribute indicates the CPU will not dirty any cacheline overlapping this
DMA_FROM_DEVICE/DMA_BIDIRECTIONAL buffer while it is mapped. This allows
multiple small buffers to safely share a cacheline without risk of data
corruption, suppressing DMA debug warnings about overlapping mappings.
All mappings sharing a cacheline should have this attribute.
This attribute indicates that CPU cache lines may overlap for buffers mapped
with DMA_FROM_DEVICE or DMA_BIDIRECTIONAL.
Such overlap may occur when callers map multiple small buffers that reside
within the same cache line. In this case, callers must guarantee that the CPU
will not dirty these cache lines after the mappings are established. When this
condition is met, multiple buffers can safely share a cache line without risking
data corruption.
All mappings that share a cache line must set this attribute to suppress DMA
debug warnings about overlapping mappings.
DMA_ATTR_REQUIRE_COHERENT
-------------------------
DMA mapping requests with the DMA_ATTR_REQUIRE_COHERENT fail on any
system where SWIOTLB or cache management is required. This should only
be used to support uAPI designs that require continuous HW DMA
coherence with userspace processes, for example RDMA and DRM. At a
minimum the memory being mapped must be userspace memory from
pin_user_pages() or similar.
Drivers should consider using dma_mmap_pages() instead of this
interface when building their uAPIs, when possible.
It must never be used in an in-kernel driver that only works with
kernel memory.

View File

@@ -336,6 +336,8 @@ command line arguments:
- ``--list_tests_attr``: If set, lists all tests that will be run and all of their
attributes.
- ``--list_suites``: If set, lists all suites that will be run.
Command-line completion
==============================

View File

@@ -19,9 +19,6 @@ description:
Flash sub nodes describe the memory range and optional per-flash
properties.
allOf:
- $ref: mtd.yaml#
properties:
compatible:
const: st,spear600-smi
@@ -42,14 +39,29 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32
description: Functional clock rate of the SMI controller in Hz.
st,smi-fast-mode:
type: boolean
description: Indicates that the attached flash supports fast read mode.
patternProperties:
"^flash@.*$":
$ref: /schemas/mtd/mtd.yaml#
properties:
reg:
maxItems: 1
st,smi-fast-mode:
type: boolean
description: Indicates that the attached flash supports fast read mode.
unevaluatedProperties: false
required:
- reg
required:
- compatible
- reg
- clock-rate
- "#address-cells"
- "#size-cells"
unevaluatedProperties: false
@@ -64,7 +76,7 @@ examples:
interrupts = <12>;
clock-rate = <50000000>; /* 50 MHz */
flash@f8000000 {
flash@fc000000 {
reg = <0xfc000000 0x1000>;
st,smi-fast-mode;
};

View File

@@ -168,7 +168,7 @@ properties:
offset from voltage set to regulator.
regulator-uv-protection-microvolt:
description: Set over under voltage protection limit. This is a limit where
description: Set under voltage protection limit. This is a limit where
hardware performs emergency shutdown. Zero can be passed to disable
protection and value '1' indicates that protection should be enabled but
limit setting can be omitted. Limit is given as microvolt offset from
@@ -182,7 +182,7 @@ properties:
is given as microvolt offset from voltage set to regulator.
regulator-uv-warn-microvolt:
description: Set over under voltage warning limit. This is a limit where
description: Set under voltage warning limit. This is a limit where
hardware is assumed still to be functional but approaching limit where
it gets damaged. Recovery actions should be initiated. Zero can be passed
to disable detection and value '1' indicates that detection should

View File

@@ -33,6 +33,7 @@ properties:
- const: rockchip,rk3066-spdif
- items:
- enum:
- rockchip,rk3576-spdif
- rockchip,rk3588-spdif
- const: rockchip,rk3568-spdif

View File

@@ -164,7 +164,7 @@ allOf:
properties:
compatible:
contains:
const: st,stm32mph7-sai
const: st,stm32h7-sai
then:
properties:
clocks:

View File

@@ -99,3 +99,51 @@ of the driver is decremented. All symlinks between the two are removed.
When a driver is removed, the list of devices that it supports is
iterated over, and the driver's remove callback is called for each
one. The device is removed from that list and the symlinks removed.
Driver Override
~~~~~~~~~~~~~~~
Userspace may override the standard matching by writing a driver name to
a device's ``driver_override`` sysfs attribute. When set, only a driver
whose name matches the override will be considered during binding. This
bypasses all bus-specific matching (OF, ACPI, ID tables, etc.).
The override may be cleared by writing an empty string, which returns
the device to standard matching rules. Writing to ``driver_override``
does not automatically unbind the device from its current driver or
make any attempt to load the specified driver.
Buses opt into this mechanism by setting the ``driver_override`` flag in
their ``struct bus_type``::
const struct bus_type example_bus_type = {
...
.driver_override = true,
};
When the flag is set, the driver core automatically creates the
``driver_override`` sysfs attribute for every device on that bus.
The bus's ``match()`` callback should check the override before performing
its own matching, using ``device_match_driver_override()``::
static int example_match(struct device *dev, const struct device_driver *drv)
{
int ret;
ret = device_match_driver_override(dev, drv);
if (ret >= 0)
return ret;
/* Fall through to bus-specific matching... */
}
``device_match_driver_override()`` returns > 0 if the override matches
the given driver, 0 if the override is set but does not match, or < 0 if
no override is set at all.
Additional helpers are available:
- ``device_set_driver_override()`` - set or clear the override from kernel code.
- ``device_has_driver_override()`` - check whether an override is set.

View File

@@ -783,6 +783,56 @@ controlled by the "uuid" mount option, which supports these values:
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
--------------

View File

@@ -27,10 +27,10 @@ for details.
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.
in0_input Measured voltage in microvolts.
in0_input Measured voltage in millivolts.
curr1_input Measured current in microamperes.
curr1_max_alarm Overcurrent alarm in microamperes.
curr1_input Measured current in milliamperes.
curr1_max Overcurrent shutdown threshold in milliamperes.

View File

@@ -51,8 +51,9 @@ temp1_max Provides thermal control temperature of the CPU package
temp1_crit Provides shutdown temperature of the CPU package which
is also known as the maximum processor junction
temperature, Tjmax or Tprochot.
temp1_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
the CPU package.
temp1_crit_hyst Provides the hysteresis temperature of the CPU
package. Returns Tcontrol, the temperature at which
the critical condition clears.
temp2_label "DTS"
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
is also known as the maximum processor junction
temperature, Tjmax or Tprochot.
temp2_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
the CPU package.
temp2_crit_hyst Provides the hysteresis temperature of the CPU
package. Returns Tcontrol, the temperature at which
the critical condition clears.
temp3_label "Tcontrol"
temp3_input Provides current Tcontrol temperature of the CPU

View File

@@ -247,8 +247,8 @@ operations:
flags: [admin-perm]
do:
pre: net-shaper-nl-pre-doit
post: net-shaper-nl-post-doit
pre: net-shaper-nl-pre-doit-write
post: net-shaper-nl-post-doit-write
request:
attributes:
- ifindex
@@ -278,8 +278,8 @@ operations:
flags: [admin-perm]
do:
pre: net-shaper-nl-pre-doit
post: net-shaper-nl-post-doit
pre: net-shaper-nl-pre-doit-write
post: net-shaper-nl-post-doit-write
request:
attributes: *ns-binding
@@ -309,8 +309,8 @@ operations:
flags: [admin-perm]
do:
pre: net-shaper-nl-pre-doit
post: net-shaper-nl-post-doit
pre: net-shaper-nl-pre-doit-write
post: net-shaper-nl-post-doit-write
request:
attributes:
- ifindex

View File

@@ -8,7 +8,7 @@ Landlock: unprivileged access control
=====================================
: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
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
__u32 restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON;
if (abi < 7) {
/* Clear logging flags unsupported before ABI 7. */
__u32 restrict_flags =
LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON |
LANDLOCK_RESTRICT_SELF_TSYNC;
switch (abi) {
case 1 ... 6:
/* Removes logging flags for ABI < 7 */
restrict_flags &= ~(LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF |
LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON |
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

View File

@@ -3986,7 +3986,7 @@ F: drivers/hwmon/asus-ec-sensors.c
ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS
M: Corentin Chary <corentin.chary@gmail.com>
M: Luke D. Jones <luke@ljones.dev>
M: Denis Benato <benato.denis96@gmail.com>
M: Denis Benato <denis.benato@linux.dev>
L: platform-driver-x86@vger.kernel.org
S: Maintained
W: https://asus-linux.org/
@@ -4022,7 +4022,7 @@ F: drivers/hwmon/asus_wmi_sensors.c
ASYMMETRIC KEYS
M: David Howells <dhowells@redhat.com>
M: Lukas Wunner <lukas@wunner.de>
M: Ignat Korchagin <ignat@cloudflare.com>
M: Ignat Korchagin <ignat@linux.win>
L: keyrings@vger.kernel.org
L: linux-crypto@vger.kernel.org
S: Maintained
@@ -4035,7 +4035,7 @@ F: include/linux/verification.h
ASYMMETRIC KEYS - ECDSA
M: Lukas Wunner <lukas@wunner.de>
M: Ignat Korchagin <ignat@cloudflare.com>
M: Ignat Korchagin <ignat@linux.win>
R: Stefan Berger <stefanb@linux.ibm.com>
L: linux-crypto@vger.kernel.org
S: Maintained
@@ -4045,14 +4045,14 @@ F: include/crypto/ecc*
ASYMMETRIC KEYS - GOST
M: Lukas Wunner <lukas@wunner.de>
M: Ignat Korchagin <ignat@cloudflare.com>
M: Ignat Korchagin <ignat@linux.win>
L: linux-crypto@vger.kernel.org
S: Odd fixes
F: crypto/ecrdsa*
ASYMMETRIC KEYS - RSA
M: Lukas Wunner <lukas@wunner.de>
M: Ignat Korchagin <ignat@cloudflare.com>
M: Ignat Korchagin <ignat@linux.win>
L: linux-crypto@vger.kernel.org
S: Maintained
F: crypto/rsa*
@@ -7998,7 +7998,9 @@ F: Documentation/devicetree/bindings/display/himax,hx8357.yaml
F: drivers/gpu/drm/tiny/hx8357d.c
DRM DRIVER FOR HYPERV SYNTHETIC VIDEO DEVICE
M: Deepak Rawat <drawat.floss@gmail.com>
M: Dexuan Cui <decui@microsoft.com>
M: Long Li <longli@microsoft.com>
M: Saurabh Sengar <ssengar@linux.microsoft.com>
L: linux-hyperv@vger.kernel.org
L: dri-devel@lists.freedesktop.org
S: Maintained
@@ -8626,8 +8628,14 @@ F: drivers/gpu/drm/lima/
F: include/uapi/drm/lima_drm.h
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
S: Orphan
S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: drivers/gpu/drm/loongson/
@@ -9611,7 +9619,12 @@ F: include/linux/ext2*
EXT4 FILE SYSTEM
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
S: Maintained
W: http://ext4.wiki.kernel.org
@@ -12007,7 +12020,6 @@ I2C SUBSYSTEM
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
L: linux-i2c@vger.kernel.org
S: Maintained
W: https://i2c.wiki.kernel.org/
Q: https://patchwork.ozlabs.org/project/linux-i2c/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
F: Documentation/i2c/
@@ -12033,7 +12045,6 @@ I2C SUBSYSTEM HOST DRIVERS
M: Andi Shyti <andi.shyti@kernel.org>
L: linux-i2c@vger.kernel.org
S: Maintained
W: https://i2c.wiki.kernel.org/
Q: https://patchwork.ozlabs.org/project/linux-i2c/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git
F: Documentation/devicetree/bindings/i2c/
@@ -16875,7 +16886,7 @@ M: Lorenzo Stoakes <ljs@kernel.org>
R: Rik van Riel <riel@surriel.com>
R: Liam R. Howlett <Liam.Howlett@oracle.com>
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>
L: linux-mm@kvack.org
S: Maintained
@@ -24342,7 +24353,7 @@ F: drivers/nvmem/layouts/sl28vpd.c
SLAB ALLOCATOR
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>
R: Hao Li <hao.li@linux.dev>
R: Christoph Lameter <cl@gentwo.org>
@@ -24901,9 +24912,9 @@ F: drivers/clk/spear/
F: drivers/pinctrl/spear/
SPI NOR SUBSYSTEM
M: Tudor Ambarus <tudor.ambarus@linaro.org>
M: Pratyush Yadav <pratyush@kernel.org>
M: Michael Walle <mwalle@kernel.org>
R: Takahiro Kuwano <takahiro.kuwano@infineon.com>
L: linux-mtd@lists.infradead.org
S: Maintained
W: http://www.linux-mtd.infradead.org/

View File

@@ -2,7 +2,7 @@
VERSION = 7
PATCHLEVEL = 0
SUBLEVEL = 0
EXTRAVERSION = -rc4
EXTRAVERSION = -rc6
NAME = Baby Opossum Posse
# *DOCUMENTATION*
@@ -1654,7 +1654,7 @@ CLEAN_FILES += vmlinux.symvers modules-only.symvers \
modules.builtin.ranges vmlinux.o.map vmlinux.unstripped \
compile_commands.json rust/test \
rust-project.json .vmlinux.objs .vmlinux.export.c \
.builtin-dtbs-list .builtin-dtb.S
.builtin-dtbs-list .builtin-dtbs.S
# Directories & files removed with 'make mrproper'
MRPROPER_FILES += include/config include/generated \

View File

@@ -279,7 +279,6 @@ CONFIG_TI_CPSW_SWITCHDEV=y
CONFIG_TI_CPTS=y
CONFIG_TI_KEYSTONE_NETCP=y
CONFIG_TI_KEYSTONE_NETCP_ETHSS=y
CONFIG_TI_PRUSS=m
CONFIG_TI_PRUETH=m
CONFIG_XILINX_EMACLITE=y
CONFIG_SFP=m

View File

@@ -698,7 +698,7 @@ scif0: serial@c0700000 {
compatible = "renesas,scif-r8a78000",
"renesas,rcar-gen5-scif", "renesas,scif";
reg = <0 0xc0700000 0 0x40>;
interrupts = <GIC_SPI 4074 IRQ_TYPE_LEVEL_HIGH>;
interrupts = <GIC_ESPI 10 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&dummy_clk_sgasyncd16>, <&dummy_clk_sgasyncd16>, <&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
status = "disabled";
@@ -708,7 +708,7 @@ scif1: serial@c0704000 {
compatible = "renesas,scif-r8a78000",
"renesas,rcar-gen5-scif", "renesas,scif";
reg = <0 0xc0704000 0 0x40>;
interrupts = <GIC_SPI 4075 IRQ_TYPE_LEVEL_HIGH>;
interrupts = <GIC_ESPI 11 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&dummy_clk_sgasyncd16>, <&dummy_clk_sgasyncd16>, <&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
status = "disabled";
@@ -718,7 +718,7 @@ scif3: serial@c0708000 {
compatible = "renesas,scif-r8a78000",
"renesas,rcar-gen5-scif", "renesas,scif";
reg = <0 0xc0708000 0 0x40>;
interrupts = <GIC_SPI 4076 IRQ_TYPE_LEVEL_HIGH>;
interrupts = <GIC_ESPI 12 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&dummy_clk_sgasyncd16>, <&dummy_clk_sgasyncd16>, <&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
status = "disabled";
@@ -728,7 +728,7 @@ scif4: serial@c070c000 {
compatible = "renesas,scif-r8a78000",
"renesas,rcar-gen5-scif", "renesas,scif";
reg = <0 0xc070c000 0 0x40>;
interrupts = <GIC_SPI 4077 IRQ_TYPE_LEVEL_HIGH>;
interrupts = <GIC_ESPI 13 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&dummy_clk_sgasyncd16>, <&dummy_clk_sgasyncd16>, <&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
status = "disabled";
@@ -738,7 +738,7 @@ hscif0: serial@c0710000 {
compatible = "renesas,hscif-r8a78000",
"renesas,rcar-gen5-hscif", "renesas,hscif";
reg = <0 0xc0710000 0 0x60>;
interrupts = <GIC_SPI 4078 IRQ_TYPE_LEVEL_HIGH>;
interrupts = <GIC_ESPI 14 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&dummy_clk_sgasyncd4>, <&dummy_clk_sgasyncd4>, <&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
status = "disabled";
@@ -748,7 +748,7 @@ hscif1: serial@c0714000 {
compatible = "renesas,hscif-r8a78000",
"renesas,rcar-gen5-hscif", "renesas,hscif";
reg = <0 0xc0714000 0 0x60>;
interrupts = <GIC_SPI 4079 IRQ_TYPE_LEVEL_HIGH>;
interrupts = <GIC_ESPI 15 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&dummy_clk_sgasyncd4>, <&dummy_clk_sgasyncd4>, <&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
status = "disabled";
@@ -758,7 +758,7 @@ hscif2: serial@c0718000 {
compatible = "renesas,hscif-r8a78000",
"renesas,rcar-gen5-hscif", "renesas,hscif";
reg = <0 0xc0718000 0 0x60>;
interrupts = <GIC_SPI 4080 IRQ_TYPE_LEVEL_HIGH>;
interrupts = <GIC_ESPI 16 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&dummy_clk_sgasyncd4>, <&dummy_clk_sgasyncd4>, <&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
status = "disabled";
@@ -768,7 +768,7 @@ hscif3: serial@c071c000 {
compatible = "renesas,hscif-r8a78000",
"renesas,rcar-gen5-hscif", "renesas,hscif";
reg = <0 0xc071c000 0 0x60>;
interrupts = <GIC_SPI 4081 IRQ_TYPE_LEVEL_HIGH>;
interrupts = <GIC_ESPI 17 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&dummy_clk_sgasyncd4>, <&dummy_clk_sgasyncd4>, <&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
status = "disabled";

View File

@@ -581,16 +581,6 @@ ostm7: timer@12c03000 {
status = "disabled";
};
wdt0: watchdog@11c00400 {
compatible = "renesas,r9a09g057-wdt";
reg = <0 0x11c00400 0 0x400>;
clocks = <&cpg CPG_MOD 0x4b>, <&cpg CPG_MOD 0x4c>;
clock-names = "pclk", "oscclk";
resets = <&cpg 0x75>;
power-domains = <&cpg>;
status = "disabled";
};
wdt1: watchdog@14400000 {
compatible = "renesas,r9a09g057-wdt";
reg = <0 0x14400000 0 0x400>;
@@ -601,26 +591,6 @@ wdt1: watchdog@14400000 {
status = "disabled";
};
wdt2: watchdog@13000000 {
compatible = "renesas,r9a09g057-wdt";
reg = <0 0x13000000 0 0x400>;
clocks = <&cpg CPG_MOD 0x4f>, <&cpg CPG_MOD 0x50>;
clock-names = "pclk", "oscclk";
resets = <&cpg 0x77>;
power-domains = <&cpg>;
status = "disabled";
};
wdt3: watchdog@13000400 {
compatible = "renesas,r9a09g057-wdt";
reg = <0 0x13000400 0 0x400>;
clocks = <&cpg CPG_MOD 0x51>, <&cpg CPG_MOD 0x52>;
clock-names = "pclk", "oscclk";
resets = <&cpg 0x78>;
power-domains = <&cpg>;
status = "disabled";
};
rtc: rtc@11c00800 {
compatible = "renesas,r9a09g057-rtca3", "renesas,rz-rtca3";
reg = <0 0x11c00800 0 0x400>;

View File

@@ -974,8 +974,8 @@ mii_conv3: mii-conv@3 {
cpg: clock-controller@80280000 {
compatible = "renesas,r9a09g077-cpg-mssr";
reg = <0 0x80280000 0 0x1000>,
<0 0x81280000 0 0x9000>;
reg = <0 0x80280000 0 0x10000>,
<0 0x81280000 0 0x10000>;
clocks = <&extal_clk>;
clock-names = "extal";
#clock-cells = <2>;

View File

@@ -977,8 +977,8 @@ mii_conv3: mii-conv@3 {
cpg: clock-controller@80280000 {
compatible = "renesas,r9a09g087-cpg-mssr";
reg = <0 0x80280000 0 0x1000>,
<0 0x81280000 0 0x9000>;
reg = <0 0x80280000 0 0x10000>,
<0 0x81280000 0 0x10000>;
clocks = <&extal_clk>;
clock-names = "extal";
#clock-cells = <2>;

View File

@@ -162,7 +162,7 @@ versa3: clock-generator@68 {
<100000000>;
renesas,settings = [
80 00 11 19 4c 42 dc 2f 06 7d 20 1a 5f 1e f2 27
00 40 00 00 00 00 00 00 06 0c 19 02 3f f0 90 86
00 40 00 00 00 00 00 00 06 0c 19 02 3b f0 90 86
a0 80 30 30 9c
];
};

View File

@@ -53,6 +53,7 @@ vqmmc_sdhi0: regulator-vqmmc-sdhi0 {
regulator-max-microvolt = <3300000>;
gpios-states = <0>;
states = <3300000 0>, <1800000 1>;
regulator-ramp-delay = <60>;
};
#endif

View File

@@ -25,6 +25,7 @@ vqmmc_sdhi0: regulator-vqmmc-sdhi0 {
regulator-max-microvolt = <3300000>;
gpios-states = <0>;
states = <3300000 0>, <1800000 1>;
regulator-ramp-delay = <60>;
};
};

View File

@@ -76,19 +76,24 @@ static int aesbs_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
unsigned int key_len)
{
struct aesbs_ctx *ctx = crypto_skcipher_ctx(tfm);
struct crypto_aes_ctx rk;
struct crypto_aes_ctx *rk;
int err;
err = aes_expandkey(&rk, in_key, key_len);
rk = kmalloc(sizeof(*rk), GFP_KERNEL);
if (!rk)
return -ENOMEM;
err = aes_expandkey(rk, in_key, key_len);
if (err)
return err;
goto out;
ctx->rounds = 6 + key_len / 4;
scoped_ksimd()
aesbs_convert_key(ctx->rk, rk.key_enc, ctx->rounds);
return 0;
aesbs_convert_key(ctx->rk, rk->key_enc, ctx->rounds);
out:
kfree_sensitive(rk);
return err;
}
static int __ecb_crypt(struct skcipher_request *req,
@@ -133,22 +138,26 @@ static int aesbs_cbc_ctr_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
unsigned int key_len)
{
struct aesbs_cbc_ctr_ctx *ctx = crypto_skcipher_ctx(tfm);
struct crypto_aes_ctx rk;
struct crypto_aes_ctx *rk;
int err;
err = aes_expandkey(&rk, in_key, key_len);
rk = kmalloc(sizeof(*rk), GFP_KERNEL);
if (!rk)
return -ENOMEM;
err = aes_expandkey(rk, in_key, key_len);
if (err)
return err;
goto out;
ctx->key.rounds = 6 + key_len / 4;
memcpy(ctx->enc, rk.key_enc, sizeof(ctx->enc));
memcpy(ctx->enc, rk->key_enc, sizeof(ctx->enc));
scoped_ksimd()
aesbs_convert_key(ctx->key.rk, rk.key_enc, ctx->key.rounds);
memzero_explicit(&rk, sizeof(rk));
return 0;
aesbs_convert_key(ctx->key.rk, rk->key_enc, ctx->key.rounds);
out:
kfree_sensitive(rk);
return err;
}
static int cbc_encrypt(struct skcipher_request *req)

View File

@@ -192,6 +192,14 @@ static int scs_handle_fde_frame(const struct eh_frame *frame,
size -= 2;
break;
case DW_CFA_advance_loc4:
loc += *opcode++ * code_alignment_factor;
loc += (*opcode++ << 8) * code_alignment_factor;
loc += (*opcode++ << 16) * code_alignment_factor;
loc += (*opcode++ << 24) * code_alignment_factor;
size -= 4;
break;
case DW_CFA_def_cfa:
case DW_CFA_offset_extended:
size = skip_xleb128(&opcode, size);

View File

@@ -12,6 +12,7 @@
#include <asm/io.h>
#include <asm/mem_encrypt.h>
#include <asm/pgtable.h>
#include <asm/rsi.h>
static struct realm_config config;
@@ -146,7 +147,7 @@ void __init arm64_rsi_init(void)
return;
if (WARN_ON(rsi_get_realm_config(&config)))
return;
prot_ns_shared = BIT(config.ipa_bits - 1);
prot_ns_shared = __phys_to_pte_val(BIT(config.ipa_bits - 1));
if (arm64_ioremap_prot_hook_register(realm_ioremap_hook))
return;

View File

@@ -1753,7 +1753,7 @@ int __kvm_at_swap_desc(struct kvm *kvm, gpa_t ipa, u64 old, u64 new)
if (!writable)
return -EPERM;
ptep = (u64 __user *)hva + offset;
ptep = (void __user *)hva + offset;
if (cpus_have_final_cap(ARM64_HAS_LSE_ATOMICS))
r = __lse_swap_desc(ptep, old, new);
else

View File

@@ -247,6 +247,20 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu)
kvm_vcpu_set_be(vcpu);
*vcpu_pc(vcpu) = target_pc;
/*
* We may come from a state where either a PC update was
* pending (SMC call resulting in PC being increpented to
* skip the SMC) or a pending exception. Make sure we get
* rid of all that, as this cannot be valid out of reset.
*
* Note that clearing the exception mask also clears PC
* updates, but that's an implementation detail, and we
* really want to make it explicit.
*/
vcpu_clear_flag(vcpu, PENDING_EXCEPTION);
vcpu_clear_flag(vcpu, EXCEPT_MASK);
vcpu_clear_flag(vcpu, INCREMENT_PC);
vcpu_set_reg(vcpu, 0, reset_state.r0);
}

View File

@@ -304,6 +304,9 @@ config AS_HAS_LBT_EXTENSION
config AS_HAS_LVZ_EXTENSION
def_bool $(as-instr,hvcl 0)
config AS_HAS_SCQ_EXTENSION
def_bool $(as-instr,sc.q \$t0$(comma)\$t1$(comma)\$t2)
config CC_HAS_ANNOTATE_TABLEJUMP
def_bool $(cc-option,-mannotate-tablejump)

View File

@@ -238,6 +238,8 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, unsigned int
arch_cmpxchg((ptr), (o), (n)); \
})
#ifdef CONFIG_AS_HAS_SCQ_EXTENSION
union __u128_halves {
u128 full;
struct {
@@ -290,6 +292,9 @@ union __u128_halves {
BUILD_BUG_ON(sizeof(*(ptr)) != 16); \
__arch_cmpxchg128(ptr, o, n, ""); \
})
#endif /* CONFIG_AS_HAS_SCQ_EXTENSION */
#else
#include <asm-generic/cmpxchg-local.h>
#define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))

View File

@@ -41,4 +41,40 @@
.cfi_endproc; \
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

View 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;
};

View File

@@ -253,8 +253,13 @@ do { \
\
__get_kernel_common(*((type *)(dst)), sizeof(type), \
(__force type *)(src)); \
if (unlikely(__gu_err)) \
if (unlikely(__gu_err)) { \
pr_info("%s: memory access failed, ecode 0x%x\n", \
__func__, read_csr_excode()); \
pr_info("%s: the caller is %pS\n", \
__func__, __builtin_return_address(0)); \
goto err_label; \
} \
} while (0)
#define __put_kernel_nofault(dst, src, type, err_label) \
@@ -264,8 +269,13 @@ do { \
\
__pu_val = *(__force type *)(src); \
__put_kernel_common(((type *)(dst)), sizeof(type)); \
if (unlikely(__pu_err)) \
if (unlikely(__pu_err)) { \
pr_info("%s: memory access failed, ecode 0x%x\n", \
__func__, read_csr_excode()); \
pr_info("%s: the caller is %pS\n", \
__func__, __builtin_return_address(0)); \
goto err_label; \
} \
} while (0)
extern unsigned long __copy_user(void *to, const void *from, __kernel_size_t n);

View File

@@ -16,6 +16,7 @@
#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/ftrace.h>
#include <asm/sigframe.h>
#include <vdso/datapage.h>
static void __used output_ptreg_defines(void)
@@ -220,6 +221,7 @@ static void __used output_sc_defines(void)
COMMENT("Linux sigcontext offsets.");
OFFSET(SC_REGS, sigcontext, sc_regs);
OFFSET(SC_PC, sigcontext, sc_pc);
OFFSET(RT_SIGFRAME_SC, rt_sigframe, rs_uctx.uc_mcontext);
BLANK();
}

View File

@@ -42,16 +42,15 @@ static int __init init_cpu_fullname(void)
int cpu, ret;
char *cpuname;
const char *model;
struct device_node *root;
/* Parsing cpuname from DTS model property */
root = of_find_node_by_path("/");
ret = of_property_read_string(root, "model", &model);
ret = of_property_read_string(of_root, "model", &model);
if (ret == 0) {
cpuname = kstrdup(model, GFP_KERNEL);
if (!cpuname)
return -ENOMEM;
loongson_sysconf.cpuname = strsep(&cpuname, " ");
}
of_node_put(root);
if (loongson_sysconf.cpuname && !strncmp(loongson_sysconf.cpuname, "Loongson", 8)) {
for (cpu = 0; cpu < NR_CPUS; cpu++)

View File

@@ -246,32 +246,51 @@ static int text_copy_cb(void *data)
if (smp_processor_id() == copy->cpu) {
ret = copy_to_kernel_nofault(copy->dst, copy->src, copy->len);
if (ret)
if (ret) {
pr_err("%s: operation failed\n", __func__);
return ret;
}
}
flush_icache_range((unsigned long)copy->dst, (unsigned long)copy->dst + copy->len);
return ret;
return 0;
}
int larch_insn_text_copy(void *dst, void *src, size_t len)
{
int ret = 0;
int err = 0;
size_t start, end;
struct insn_copy copy = {
.dst = dst,
.src = src,
.len = len,
.cpu = smp_processor_id(),
.cpu = raw_smp_processor_id(),
};
/*
* Ensure copy.cpu won't be hot removed before stop_machine.
* If it is removed nobody will really update the text.
*/
lockdep_assert_cpus_held();
start = round_down((size_t)dst, PAGE_SIZE);
end = round_up((size_t)dst + len, PAGE_SIZE);
set_memory_rw(start, (end - start) / PAGE_SIZE);
ret = stop_machine(text_copy_cb, &copy, cpu_online_mask);
set_memory_rox(start, (end - start) / PAGE_SIZE);
err = set_memory_rw(start, (end - start) / PAGE_SIZE);
if (err) {
pr_info("%s: set_memory_rw() failed\n", __func__);
return err;
}
ret = stop_machine_cpuslocked(text_copy_cb, &copy, cpu_online_mask);
err = set_memory_rox(start, (end - start) / PAGE_SIZE);
if (err) {
pr_info("%s: set_memory_rox() failed\n", __func__);
return err;
}
return ret;
}

View File

@@ -35,6 +35,7 @@
#include <asm/cpu-features.h>
#include <asm/fpu.h>
#include <asm/lbt.h>
#include <asm/sigframe.h>
#include <asm/ucontext.h>
#include <asm/vdso.h>
@@ -51,11 +52,6 @@
#define lock_lbt_owner() ({ preempt_disable(); pagefault_disable(); })
#define unlock_lbt_owner() ({ pagefault_enable(); preempt_enable(); })
struct rt_sigframe {
struct siginfo rs_info;
struct ucontext rs_uctx;
};
struct _ctx_layout {
struct sctx_info *addr;
unsigned int size;

View File

@@ -83,7 +83,7 @@ static inline void eiointc_update_sw_coremap(struct loongarch_eiointc *s,
if (!(s->status & BIT(EIOINTC_ENABLE_CPU_ENCODE))) {
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);
@@ -472,34 +472,34 @@ static int kvm_eiointc_regs_access(struct kvm_device *dev,
switch (addr) {
case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
offset = (addr - EIOINTC_NODETYPE_START) / 4;
p = s->nodetype + offset * 4;
p = (void *)s->nodetype + offset * 4;
break;
case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
offset = (addr - EIOINTC_IPMAP_START) / 4;
p = &s->ipmap + offset * 4;
p = (void *)&s->ipmap + offset * 4;
break;
case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
offset = (addr - EIOINTC_ENABLE_START) / 4;
p = s->enable + offset * 4;
p = (void *)s->enable + offset * 4;
break;
case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
offset = (addr - EIOINTC_BOUNCE_START) / 4;
p = s->bounce + offset * 4;
p = (void *)s->bounce + offset * 4;
break;
case EIOINTC_ISR_START ... EIOINTC_ISR_END:
offset = (addr - EIOINTC_ISR_START) / 4;
p = s->isr + offset * 4;
p = (void *)s->isr + offset * 4;
break;
case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
if (cpu >= s->num_cpu)
return -EINVAL;
offset = (addr - EIOINTC_COREISR_START) / 4;
p = s->coreisr[cpu] + offset * 4;
p = (void *)s->coreisr[cpu] + offset * 4;
break;
case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
offset = (addr - EIOINTC_COREMAP_START) / 4;
p = s->coremap + offset * 4;
p = (void *)s->coremap + offset * 4;
break;
default:
kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr);

View File

@@ -588,6 +588,9 @@ struct kvm_vcpu *kvm_get_vcpu_by_cpuid(struct kvm *kvm, int cpuid)
{
struct kvm_phyid_map *map;
if (cpuid < 0)
return NULL;
if (cpuid >= KVM_MAX_PHYID)
return NULL;

View File

@@ -49,8 +49,8 @@ static void kvm_vm_init_features(struct kvm *kvm)
kvm->arch.kvm_features |= BIT(KVM_LOONGARCH_VM_FEAT_PMU);
/* Enable all PV features by default */
kvm->arch.pv_features = BIT(KVM_FEATURE_IPI);
kvm->arch.kvm_features = BIT(KVM_LOONGARCH_VM_FEAT_PV_IPI);
kvm->arch.pv_features |= BIT(KVM_FEATURE_IPI);
kvm->arch.kvm_features |= BIT(KVM_LOONGARCH_VM_FEAT_PV_IPI);
if (kvm_pvtime_supported()) {
kvm->arch.pv_features |= BIT(KVM_FEATURE_PREEMPT);
kvm->arch.pv_features |= BIT(KVM_FEATURE_STEAL_TIME);

View File

@@ -1379,9 +1379,11 @@ void *bpf_arch_text_copy(void *dst, void *src, size_t len)
{
int ret;
cpus_read_lock();
mutex_lock(&text_mutex);
ret = larch_insn_text_copy(dst, src, len);
mutex_unlock(&text_mutex);
cpus_read_unlock();
return ret ? ERR_PTR(-EINVAL) : dst;
}
@@ -1429,10 +1431,12 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,
if (ret)
return ret;
cpus_read_lock();
mutex_lock(&text_mutex);
if (memcmp(ip, new_insns, LOONGARCH_LONG_JUMP_NBYTES))
ret = larch_insn_text_copy(ip, new_insns, LOONGARCH_LONG_JUMP_NBYTES);
mutex_unlock(&text_mutex);
cpus_read_unlock();
return ret;
}
@@ -1450,10 +1454,12 @@ int bpf_arch_text_invalidate(void *dst, size_t len)
for (i = 0; i < (len / sizeof(u32)); i++)
inst[i] = INSN_BREAK;
cpus_read_lock();
mutex_lock(&text_mutex);
if (larch_insn_text_copy(dst, inst, len))
ret = -EINVAL;
mutex_unlock(&text_mutex);
cpus_read_unlock();
kvfree(inst);
@@ -1568,6 +1574,11 @@ void arch_free_bpf_trampoline(void *image, unsigned int size)
bpf_prog_pack_free(image, size);
}
int arch_protect_bpf_trampoline(void *image, unsigned int size)
{
return 0;
}
/*
* Sign-extend the register if necessary
*/

View File

@@ -5,9 +5,11 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/vgaarb.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <asm/cacheflush.h>
#include <asm/loongson.h>
@@ -15,6 +17,9 @@
#define PCI_DEVICE_ID_LOONGSON_DC1 0x7a06
#define PCI_DEVICE_ID_LOONGSON_DC2 0x7a36
#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 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_DC2, 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);

View File

@@ -26,7 +26,7 @@ cflags-vdso := $(ccflags-vdso) \
$(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
-std=gnu11 -fms-extensions -O2 -g -fno-strict-aliasing -fno-common -fno-builtin \
-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)
aflags-vdso := $(ccflags-vdso) \
-D__ASSEMBLY__ -Wa,-gdwarf-2
@@ -41,7 +41,7 @@ endif
# VDSO linker flags.
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.

View File

@@ -12,13 +12,13 @@
#include <asm/regdef.h>
#include <asm/asm.h>
#include <asm/asm-offsets.h>
.section .text
.cfi_sections .debug_frame
SYM_FUNC_START(__vdso_rt_sigreturn)
SYM_SIGFUNC_START(__vdso_rt_sigreturn)
li.w a7, __NR_rt_sigreturn
syscall 0
SYM_FUNC_END(__vdso_rt_sigreturn)
SYM_SIGFUNC_END(__vdso_rt_sigreturn)

View File

@@ -953,7 +953,7 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes,
#else
"1: cmpb,<<,n %0,%2,1b\n"
#endif
" fic,m %3(%4,%0)\n"
" fdc,m %3(%4,%0)\n"
"2: sync\n"
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b, "%1")
: "+r" (start), "+r" (error)
@@ -968,7 +968,7 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes,
#else
"1: cmpb,<<,n %0,%2,1b\n"
#endif
" fdc,m %3(%4,%0)\n"
" fic,m %3(%4,%0)\n"
"2: sync\n"
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b, "%1")
: "+r" (start), "+r" (error)

View File

@@ -428,6 +428,7 @@ can0: can@2010c000 {
clocks = <&clkcfg CLK_CAN0>, <&clkcfg CLK_MSSPLL3>;
interrupt-parent = <&plic>;
interrupts = <56>;
resets = <&mss_top_sysreg CLK_CAN0>;
status = "disabled";
};
@@ -437,6 +438,7 @@ can1: can@2010d000 {
clocks = <&clkcfg CLK_CAN1>, <&clkcfg CLK_MSSPLL3>;
interrupt-parent = <&plic>;
interrupts = <57>;
resets = <&mss_top_sysreg CLK_CAN1>;
status = "disabled";
};

View File

@@ -62,8 +62,8 @@ do { \
* @size: number of elements in array
*/
#define array_index_mask_nospec array_index_mask_nospec
static inline unsigned long array_index_mask_nospec(unsigned long index,
unsigned long size)
static __always_inline unsigned long array_index_mask_nospec(unsigned long index,
unsigned long size)
{
unsigned long mask;

View File

@@ -710,6 +710,9 @@ void kvm_arch_crypto_clear_masks(struct kvm *kvm);
void kvm_arch_crypto_set_masks(struct kvm *kvm, unsigned long *apm,
unsigned long *aqm, unsigned long *adm);
#define SIE64_RETURN_NORMAL 0
#define SIE64_RETURN_MCCK 1
int __sie64a(phys_addr_t sie_block_phys, struct kvm_s390_sie_block *sie_block, u64 *rsa,
unsigned long gasce);

View File

@@ -62,7 +62,7 @@ struct stack_frame {
struct {
unsigned long sie_control_block;
unsigned long sie_savearea;
unsigned long sie_reason;
unsigned long sie_return;
unsigned long sie_flags;
unsigned long sie_control_block_phys;
unsigned long sie_guest_asce;

View File

@@ -63,7 +63,7 @@ int main(void)
OFFSET(__SF_EMPTY, stack_frame, empty[0]);
OFFSET(__SF_SIE_CONTROL, stack_frame, sie_control_block);
OFFSET(__SF_SIE_SAVEAREA, stack_frame, sie_savearea);
OFFSET(__SF_SIE_REASON, stack_frame, sie_reason);
OFFSET(__SF_SIE_RETURN, stack_frame, sie_return);
OFFSET(__SF_SIE_FLAGS, stack_frame, sie_flags);
OFFSET(__SF_SIE_CONTROL_PHYS, stack_frame, sie_control_block_phys);
OFFSET(__SF_SIE_GUEST_ASCE, stack_frame, sie_guest_asce);

View File

@@ -200,7 +200,7 @@ SYM_FUNC_START(__sie64a)
stg %r3,__SF_SIE_CONTROL(%r15) # ...and virtual addresses
stg %r4,__SF_SIE_SAVEAREA(%r15) # save guest register save area
stg %r5,__SF_SIE_GUEST_ASCE(%r15) # save guest asce
xc __SF_SIE_REASON(8,%r15),__SF_SIE_REASON(%r15) # reason code = 0
xc __SF_SIE_RETURN(8,%r15),__SF_SIE_RETURN(%r15) # return code = 0
mvc __SF_SIE_FLAGS(8,%r15),__TI_flags(%r14) # copy thread flags
lmg %r0,%r13,0(%r4) # load guest gprs 0-13
mvi __TI_sie(%r14),1
@@ -237,7 +237,7 @@ SYM_INNER_LABEL(sie_exit, SYM_L_GLOBAL)
xgr %r4,%r4
xgr %r5,%r5
lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
lg %r2,__SF_SIE_REASON(%r15) # return exit reason code
lg %r2,__SF_SIE_RETURN(%r15) # return sie return code
BR_EX %r14
SYM_FUNC_END(__sie64a)
EXPORT_SYMBOL(__sie64a)
@@ -271,6 +271,7 @@ SYM_CODE_START(system_call)
xgr %r9,%r9
xgr %r10,%r10
xgr %r11,%r11
xgr %r12,%r12
la %r2,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs
mvc __PT_R8(64,%r2),__LC_SAVE_AREA(%r13)
MBEAR %r2,%r13
@@ -407,6 +408,7 @@ SYM_CODE_START(\name)
xgr %r6,%r6
xgr %r7,%r7
xgr %r10,%r10
xgr %r12,%r12
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
mvc __PT_R8(64,%r11),__LC_SAVE_AREA(%r13)
MBEAR %r11,%r13
@@ -496,6 +498,7 @@ SYM_CODE_START(mcck_int_handler)
xgr %r6,%r6
xgr %r7,%r7
xgr %r10,%r10
xgr %r12,%r12
stmg %r8,%r9,__PT_PSW(%r11)
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)

View File

@@ -487,8 +487,8 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
mcck_dam_code = (mci.val & MCIC_SUBCLASS_MASK);
if (test_cpu_flag(CIF_MCCK_GUEST) &&
(mcck_dam_code & MCCK_CODE_NO_GUEST) != mcck_dam_code) {
/* Set exit reason code for host's later handling */
*((long *)(regs->gprs[15] + __SF_SIE_REASON)) = -EINTR;
/* Set sie return code for host's later handling */
((struct stack_frame *)regs->gprs[15])->sie_return = SIE64_RETURN_MCCK;
}
clear_cpu_flag(CIF_MCCK_GUEST);

View File

@@ -13,6 +13,7 @@
*/
#include <linux/cpufeature.h>
#include <linux/nospec.h>
#include <linux/errno.h>
#include <linux/sched.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)))
goto out;
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);
}
out:
syscall_exit_to_user_mode(regs);
}

View File

@@ -134,32 +134,6 @@ int dat_set_asce_limit(struct kvm_s390_mmu_cache *mc, union asce *asce, int newt
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.
* @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.
*/
bool dat_crstep_xchg_atomic(union crste *crstep, union crste old, union crste new, gfn_t gfn,
union asce asce)
bool __must_check dat_crstep_xchg_atomic(union crste *crstep, union crste old, union crste new,
gfn_t gfn, union asce asce)
{
if (old.h.i)
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;
/* No need to take locks as the page table is not installed yet. */
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;
dat_init_pgstes(pt, pgste_init.val);
} 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. */
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. */
if (!crste.h.fc && !crste.h.i) {
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;
}
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)
{
union crste crste = READ_ONCE(*crstep);
union crste newcrste, oldcrste;
int *n = walk->priv;
if (!crste.h.fc || crste.h.i || crste.h.p)
return 0;
do {
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;
if (crste.s.fc1.prefix_notif)
return 0;
crste.s.fc1.prefix_notif = 1;
dat_crstep_xchg(crstep, crste, gfn, walk->asce);
return 0;
}

View File

@@ -160,14 +160,14 @@ union pmd {
unsigned long :44; /* HW */
unsigned long : 3; /* Unused */
unsigned long : 1; /* HW */
unsigned long s : 1; /* Special */
unsigned long w : 1; /* Writable soft-bit */
unsigned long r : 1; /* Readable soft-bit */
unsigned long d : 1; /* Dirty */
unsigned long y : 1; /* Young */
unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
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 : 1; /* Unused */
unsigned long : 4; /* HW */
unsigned long sd : 1; /* Soft-Dirty */
unsigned long pr : 1; /* Present */
@@ -183,14 +183,14 @@ union pud {
unsigned long :33; /* HW */
unsigned long :14; /* Unused */
unsigned long : 1; /* HW */
unsigned long s : 1; /* Special */
unsigned long w : 1; /* Writable soft-bit */
unsigned long r : 1; /* Readable soft-bit */
unsigned long d : 1; /* Dirty */
unsigned long y : 1; /* Young */
unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
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 : 1; /* Unused */
unsigned long : 4; /* HW */
unsigned long sd : 1; /* Soft-Dirty */
unsigned long pr : 1; /* Present */
@@ -254,14 +254,14 @@ union crste {
struct {
unsigned long :47;
unsigned long : 1; /* HW (should be 0) */
unsigned long s : 1; /* Special */
unsigned long w : 1; /* Writable */
unsigned long r : 1; /* Readable */
unsigned long d : 1; /* Dirty */
unsigned long y : 1; /* Young */
unsigned long prefix_notif : 1; /* Guest prefix invalidation notification */
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 : 1;
unsigned long : 4; /* HW */
unsigned long sd : 1; /* Soft-Dirty */
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);
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);
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);
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);
}
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)

View File

@@ -1434,17 +1434,27 @@ static int _do_shadow_pte(struct gmap *sg, gpa_t raddr, union pte *ptep_h, union
if (rc)
return rc;
pgste = pgste_get_lock(ptep_h);
newpte = _pte(f->pfn, f->writable, !p, 0);
newpte.s.d |= ptep->s.d;
newpte.s.sd |= ptep->s.sd;
newpte.h.p &= ptep->h.p;
pgste = _gmap_ptep_xchg(sg->parent, ptep_h, newpte, pgste, f->gfn, false);
pgste.vsie_notif = 1;
if (!pgste_get_trylock(ptep_h, &pgste))
return -EAGAIN;
newpte = _pte(f->pfn, f->writable, !p, ptep_h->s.s);
newpte.s.d |= ptep_h->s.d;
newpte.s.sd |= ptep_h->s.sd;
newpte.h.p &= ptep_h->h.p;
if (!newpte.h.p && !f->writable) {
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);
if (rc)
return rc;
if (!sg->parent)
return -EAGAIN;
newpte = _pte(f->pfn, 0, !p, 0);
pgste = pgste_get_lock(ptep);
if (!pgste_get_trylock(ptep, &pgste))
return -EAGAIN;
pgste = __dat_ptep_xchg(ptep, pgste, newpte, gpa_to_gfn(raddr), sg->asce, uses_skeys(sg));
pgste_set_unlock(ptep, pgste);
@@ -1454,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,
struct guest_fault *f, bool p)
{
union crste newcrste;
union crste newcrste, oldcrste;
gfn_t gfn;
int rc;
@@ -1467,16 +1477,28 @@ static int _do_shadow_crste(struct gmap *sg, gpa_t raddr, union crste *host, uni
if (rc)
return rc;
newcrste = _crste_fc1(f->pfn, host->h.tt, f->writable, !p);
newcrste.s.fc1.d |= host->s.fc1.d;
newcrste.s.fc1.sd |= host->s.fc1.sd;
newcrste.h.p &= host->h.p;
newcrste.s.fc1.vsie_notif = 1;
newcrste.s.fc1.prefix_notif = host->s.fc1.prefix_notif;
_gmap_crstep_xchg(sg->parent, host, newcrste, f->gfn, false);
do {
/* _gmap_crstep_xchg_atomic() could have unshadowed this shadow gmap */
if (!sg->parent)
return -EAGAIN;
oldcrste = READ_ONCE(*host);
newcrste = _crste_fc1(f->pfn, oldcrste.h.tt, f->writable, !p);
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);
dat_crstep_xchg(table, newcrste, gpa_to_gfn(raddr), sg->asce);
newcrste = _crste_fc1(f->pfn, oldcrste.h.tt, 0, !p);
gfn = gpa_to_gfn(raddr);
while (!dat_crstep_xchg_atomic(table, READ_ONCE(*table), newcrste, gfn, sg->asce))
;
return 0;
}
@@ -1500,21 +1522,31 @@ static int _gaccess_do_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *sg,
if (rc)
return rc;
/* A race occourred. The shadow mapping is already valid, nothing to do */
if ((ptep && !ptep->h.i) || (!ptep && crste_leaf(*table)))
/* A race occurred. The shadow mapping is already valid, nothing to do */
if ((ptep && !ptep->h.i && ptep->h.p == w->p) ||
(!ptep && crste_leaf(*table) && !table->h.i && table->h.p == w->p))
return 0;
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
* only the page containing the entry, not the whole table.
*/
for (i = gl ; i >= w->level; i--) {
rc = gmap_protect_rmap(mc, sg, entries[i - 1].gfn, gpa_to_gfn(saddr),
entries[i - 1].pfn, i, entries[i - 1].writable);
rc = gmap_protect_rmap(mc, sg, entries[i].gfn, gpa_to_gfn(saddr),
entries[i].pfn, i + 1, entries[i].writable);
if (rc)
return rc;
if (!sg->parent)
return -EAGAIN;
}
rc = dat_entry_walk(NULL, entries[LEVEL_MEM].gfn, sg->parent->asce, DAT_WALK_LEAF,
@@ -1526,6 +1558,7 @@ static int _gaccess_do_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *sg,
/* Get the smallest granularity */
l = min3(gl, hl, w->level);
real_address_space:
flags = DAT_WALK_SPLIT_ALLOC | (uses_skeys(sg->parent) ? DAT_WALK_USES_SKEYS : 0);
/* If necessary, create the shadow mapping */
if (l < gl) {

View File

@@ -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;
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.h.i = 1;
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)));
new.s.fc1.d = 0;
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;
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 folio *folio = NULL;
union crste old = *crstep;
if (crstep->h.fc) {
if (crstep->s.fc1.pr && test_bit(GMAP_FLAG_EXPORT_ON_UNMAP, &priv->gmap->flags))
folio = phys_to_folio(crste_origin_large(*crstep));
gmap_crstep_xchg(priv->gmap, crstep, _CRSTE_EMPTY(crstep->h.tt), gfn);
if (folio)
uv_convert_from_secure_folio(folio);
}
if (!old.h.fc)
return 0;
if (old.s.fc1.pr && test_bit(GMAP_FLAG_EXPORT_ON_UNMAP, &priv->gmap->flags))
folio = phys_to_folio(crste_origin_large(old));
/* 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;
}
@@ -474,23 +481,24 @@ static long _crste_test_and_clear_softdirty(union crste *table, gfn_t gfn, gfn_t
if (fatal_signal_pending(current))
return 1;
crste = READ_ONCE(*table);
if (!crste.h.fc)
return 0;
if (crste.h.p && !crste.s.fc1.sd)
return 0;
do {
crste = READ_ONCE(*table);
if (!crste.h.fc)
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
* currently running, do not reset the protection, leave it marked as
* dirty.
*/
if (!crste.s.fc1.prefix_notif || gmap_mkold_prefix(gmap, gfn, end)) {
/*
* If this large page contains one or more prefixes of vCPUs that are
* currently running, do not reset the protection, leave it marked as
* dirty.
*/
if (crste.s.fc1.prefix_notif && !gmap_mkold_prefix(gmap, gfn, end))
break;
new = crste;
new.h.p = 1;
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++)
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);
}
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);
@@ -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.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. */
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. */
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.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);
return 0;
@@ -606,7 +610,7 @@ int gmap_try_fixup_minor(struct gmap *gmap, struct guest_fault *fault)
fault->callback(fault);
pgste_set_unlock(fault->ptep, pgste);
} else {
rc = gmap_handle_minor_crste_fault(gmap->asce, fault);
rc = gmap_handle_minor_crste_fault(gmap, fault);
if (!rc && fault->callback)
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);
}
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)
{
unsigned int order;
int rc, level;
int level;
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))
level = TABLE_TYPE_SEGMENT;
}
rc = dat_link(mc, gmap->asce, level, uses_skeys(gmap), f);
KVM_BUG_ON(rc == -EINVAL, gmap->kvm);
return rc;
return _gmap_link(mc, gmap, level, f);
}
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)
{
union crste newcrste, oldcrste;
struct page_table *pt;
union crste newcrste;
union crste *crstep;
union pte *ptep;
int rc;
@@ -673,7 +726,11 @@ static int gmap_ucas_map_one(struct kvm_s390_mmu_cache *mc, struct gmap *gmap,
&crstep, &ptep);
if (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;
}
@@ -777,8 +834,10 @@ static void gmap_ucas_unmap_one(struct gmap *gmap, gfn_t c_gfn)
int rc;
rc = dat_entry_walk(NULL, c_gfn, gmap->asce, 0, TABLE_TYPE_SEGMENT, &crstep, &ptep);
if (!rc)
dat_crstep_xchg(crstep, _PMD_EMPTY, c_gfn, gmap->asce);
if (rc)
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)
@@ -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));
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)
return;
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,
struct gmap_protect_asce_top_level *context)
{
struct gmap *parent;
int rc, i;
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))
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++) {
if (!context->f[i].valid)
continue;
@@ -1191,6 +1256,9 @@ struct gmap *gmap_create_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *pare
struct gmap *sg, *new;
int rc;
if (WARN_ON(!parent))
return ERR_PTR(-EINVAL);
scoped_guard(spinlock, &parent->children_lock) {
sg = gmap_find_shadow(parent, asce, edat_level);
if (sg) {

View File

@@ -185,6 +185,8 @@ static inline union pgste _gmap_ptep_xchg(struct gmap *gmap, union pte *ptep, un
else
_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));
}
@@ -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);
}
static inline void _gmap_crstep_xchg(struct gmap *gmap, union crste *crstep, union crste ne,
gfn_t gfn, bool needs_lock)
static inline bool __must_check _gmap_crstep_xchg_atomic(struct gmap *gmap, union crste *crstep,
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);
if (!needs_lock)
lockdep_assert_held(&gmap->children_lock);
gfn = ALIGN_DOWN(gfn, align);
if (crste_prefix(*crstep) && (ne.h.p || ne.h.i || !crste_prefix(ne))) {
ne.s.fc1.prefix_notif = 0;
if (crste_prefix(oldcrste) && (newcrste.h.p || newcrste.h.i || !crste_prefix(newcrste))) {
newcrste.s.fc1.prefix_notif = 0;
gmap_unmap_prefix(gmap, gfn, gfn + align);
}
if (crste_leaf(*crstep) && crstep->s.fc1.vsie_notif &&
(ne.h.p || ne.h.i || !ne.s.fc1.vsie_notif)) {
ne.s.fc1.vsie_notif = 0;
if (crste_leaf(oldcrste) && oldcrste.s.fc1.vsie_notif &&
(newcrste.h.p || newcrste.h.i || !newcrste.s.fc1.vsie_notif)) {
newcrste.s.fc1.vsie_notif = 0;
if (needs_lock)
gmap_handle_vsie_unshadow_event(gmap, gfn);
else
_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,
gfn_t gfn)
static inline bool __must_check gmap_crstep_xchg_atomic(struct gmap *gmap, union crste *crstep,
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);
}
/**

View File

@@ -2724,6 +2724,9 @@ static unsigned long get_ind_bit(__u64 addr, unsigned long bit_nr, bool swap)
bit = bit_nr + (addr % PAGE_SIZE) * 8;
/* kvm_set_routing_entry() should never allow this to happen */
WARN_ON_ONCE(bit > (PAGE_SIZE * BITS_PER_BYTE - 1));
return swap ? (bit ^ (BITS_PER_LONG - 1)) : bit;
}
@@ -2824,6 +2827,12 @@ void kvm_s390_reinject_machine_check(struct kvm_vcpu *vcpu,
int rc;
mci.val = mcck_info->mcic;
/* log machine checks being reinjected on all debugs */
VCPU_EVENT(vcpu, 2, "guest machine check %lx", mci.val);
KVM_EVENT(2, "guest machine check %lx", mci.val);
pr_info("guest machine check pid %d: %lx", current->pid, mci.val);
if (mci.sr)
cr14 |= CR14_RECOVERY_SUBMASK;
if (mci.dg)
@@ -2852,6 +2861,7 @@ int kvm_set_routing_entry(struct kvm *kvm,
struct kvm_kernel_irq_routing_entry *e,
const struct kvm_irq_routing_entry *ue)
{
const struct kvm_irq_routing_s390_adapter *adapter;
u64 uaddr_s, uaddr_i;
int idx;
@@ -2862,6 +2872,14 @@ int kvm_set_routing_entry(struct kvm *kvm,
return -EINVAL;
e->set = set_adapter_int;
adapter = &ue->u.adapter;
if (adapter->summary_addr + (adapter->summary_offset / 8) >=
(adapter->summary_addr & PAGE_MASK) + PAGE_SIZE)
return -EINVAL;
if (adapter->ind_addr + (adapter->ind_offset / 8) >=
(adapter->ind_addr & PAGE_MASK) + PAGE_SIZE)
return -EINVAL;
idx = srcu_read_lock(&kvm->srcu);
uaddr_s = gpa_to_hva(kvm, ue->u.adapter.summary_addr);
uaddr_i = gpa_to_hva(kvm, ue->u.adapter.ind_addr);

View File

@@ -4617,7 +4617,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
return 0;
}
static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
static int vcpu_post_run(struct kvm_vcpu *vcpu, int sie_return)
{
struct mcck_volatile_info *mcck_info;
struct sie_page *sie_page;
@@ -4633,14 +4633,14 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
vcpu->run->s.regs.gprs[14] = vcpu->arch.sie_block->gg14;
vcpu->run->s.regs.gprs[15] = vcpu->arch.sie_block->gg15;
if (exit_reason == -EINTR) {
VCPU_EVENT(vcpu, 3, "%s", "machine check");
if (sie_return == SIE64_RETURN_MCCK) {
sie_page = container_of(vcpu->arch.sie_block,
struct sie_page, sie_block);
mcck_info = &sie_page->mcck_info;
kvm_s390_reinject_machine_check(vcpu, mcck_info);
return 0;
}
WARN_ON_ONCE(sie_return != SIE64_RETURN_NORMAL);
if (vcpu->arch.sie_block->icptcode > 0) {
rc = kvm_handle_sie_intercept(vcpu);
@@ -4679,7 +4679,7 @@ int noinstr kvm_s390_enter_exit_sie(struct kvm_s390_sie_block *scb,
#define PSW_INT_MASK (PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_MCHECK)
static int __vcpu_run(struct kvm_vcpu *vcpu)
{
int rc, exit_reason;
int rc, sie_return;
struct sie_page *sie_page = (struct sie_page *)vcpu->arch.sie_block;
/*
@@ -4719,9 +4719,9 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
guest_timing_enter_irqoff();
__disable_cpu_timer_accounting(vcpu);
exit_reason = kvm_s390_enter_exit_sie(vcpu->arch.sie_block,
vcpu->run->s.regs.gprs,
vcpu->arch.gmap->asce.val);
sie_return = kvm_s390_enter_exit_sie(vcpu->arch.sie_block,
vcpu->run->s.regs.gprs,
vcpu->arch.gmap->asce.val);
__enable_cpu_timer_accounting(vcpu);
guest_timing_exit_irqoff();
@@ -4744,7 +4744,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
}
kvm_vcpu_srcu_read_lock(vcpu);
rc = vcpu_post_run(vcpu, exit_reason);
rc = vcpu_post_run(vcpu, sie_return);
if (rc || guestdbg_exit_pending(vcpu)) {
kvm_vcpu_srcu_read_unlock(vcpu);
break;
@@ -5520,9 +5520,21 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
}
#endif
case KVM_S390_VCPU_FAULT: {
idx = srcu_read_lock(&vcpu->kvm->srcu);
r = vcpu_dat_fault_handler(vcpu, arg, 0);
srcu_read_unlock(&vcpu->kvm->srcu, idx);
gpa_t gaddr = arg;
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;
}
case KVM_ENABLE_CAP:

View File

@@ -1122,6 +1122,7 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struc
{
struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
unsigned long sie_return = SIE64_RETURN_NORMAL;
int guest_bp_isolation;
int rc = 0;
@@ -1163,7 +1164,7 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struc
goto xfer_to_guest_mode_check;
}
guest_timing_enter_irqoff();
rc = kvm_s390_enter_exit_sie(scb_s, vcpu->run->s.regs.gprs, sg->asce.val);
sie_return = kvm_s390_enter_exit_sie(scb_s, vcpu->run->s.regs.gprs, sg->asce.val);
guest_timing_exit_irqoff();
local_irq_enable();
}
@@ -1178,12 +1179,13 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struc
kvm_vcpu_srcu_read_lock(vcpu);
if (rc == -EINTR) {
VCPU_EVENT(vcpu, 3, "%s", "machine check");
if (sie_return == SIE64_RETURN_MCCK) {
kvm_s390_reinject_machine_check(vcpu, &vsie_page->mcck_info);
return 0;
}
WARN_ON_ONCE(sie_return != SIE64_RETURN_NORMAL);
if (rc > 0)
rc = 0; /* we could still have an icpt */
else if (current->thread.gmap_int_code)
@@ -1326,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)
{
struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
struct gmap *sg;
struct gmap *sg = NULL;
int rc = 0;
while (1) {
@@ -1366,6 +1368,8 @@ static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
sg = gmap_put(sg);
cond_resched();
}
if (sg)
sg = gmap_put(sg);
if (rc == -EFAULT) {
/*

View File

@@ -441,10 +441,17 @@ void do_secure_storage_access(struct pt_regs *regs)
folio = phys_to_folio(addr);
if (unlikely(!folio_try_get(folio)))
return;
rc = arch_make_folio_accessible(folio);
rc = uv_convert_from_secure(folio_to_phys(folio));
if (!rc)
clear_bit(PG_arch_1, &folio->flags.f);
folio_put(folio);
/*
* There are some valid fixup types for kernel
* accesses to donated secure memory. zeropad is one
* of them.
*/
if (rc)
BUG();
return handle_fault_error_nolock(regs, 0);
} else {
if (faulthandler_disabled())
return handle_fault_error_nolock(regs, 0);

View File

@@ -26,10 +26,6 @@ static int platform_match(struct device *dev, struct device_driver *drv)
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* When driver_override is set, only bind to the matching driver */
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;

View File

@@ -121,6 +121,9 @@ noinstr struct ghcb *__sev_get_ghcb(struct ghcb_state *state)
WARN_ON(!irqs_disabled());
if (!sev_cfg.ghcbs_initialized)
return boot_ghcb;
data = this_cpu_read(runtime_data);
ghcb = &data->ghcb_page;
@@ -164,6 +167,9 @@ noinstr void __sev_put_ghcb(struct ghcb_state *state)
WARN_ON(!irqs_disabled());
if (!sev_cfg.ghcbs_initialized)
return;
data = this_cpu_read(runtime_data);
ghcb = &data->ghcb_page;

View File

@@ -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)
{
/* 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
case X86_TRAP_CP: return exc_control_protection(regs, error_code);
#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);
}

View File

@@ -13,7 +13,7 @@
#include <linux/types.h>
#include <vdso/gettime.h>
#include "../../../../lib/vdso/gettimeofday.c"
#include "lib/vdso/gettimeofday.c"
int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
{

View File

@@ -1372,14 +1372,17 @@ static void x86_pmu_enable(struct pmu *pmu)
else if (i < n_running)
continue;
if (hwc->state & PERF_HES_ARCH)
cpuc->events[hwc->idx] = event;
if (hwc->state & PERF_HES_ARCH) {
static_call(x86_pmu_set_period)(event);
continue;
}
/*
* if cpuc->enabled = 0, then no wrmsr as
* per x86_pmu_enable_event()
*/
cpuc->events[hwc->idx] = event;
x86_pmu_start(event, PERF_EF_RELOAD);
}
cpuc->n_added = 0;

View File

@@ -4628,6 +4628,19 @@ static inline void intel_pmu_set_acr_caused_constr(struct perf_event *event,
event->hw.dyn_constraint &= hybrid(event->pmu, acr_cause_mask64);
}
static inline int intel_set_branch_counter_constr(struct perf_event *event,
int *num)
{
if (branch_sample_call_stack(event))
return -EINVAL;
if (branch_sample_counters(event)) {
(*num)++;
event->hw.dyn_constraint &= x86_pmu.lbr_counters;
}
return 0;
}
static int intel_pmu_hw_config(struct perf_event *event)
{
int ret = x86_pmu_hw_config(event);
@@ -4698,21 +4711,19 @@ static int intel_pmu_hw_config(struct perf_event *event)
* group, which requires the extra space to store the counters.
*/
leader = event->group_leader;
if (branch_sample_call_stack(leader))
if (intel_set_branch_counter_constr(leader, &num))
return -EINVAL;
if (branch_sample_counters(leader)) {
num++;
leader->hw.dyn_constraint &= x86_pmu.lbr_counters;
}
leader->hw.flags |= PERF_X86_EVENT_BRANCH_COUNTERS;
for_each_sibling_event(sibling, leader) {
if (branch_sample_call_stack(sibling))
if (intel_set_branch_counter_constr(sibling, &num))
return -EINVAL;
}
/* event isn't installed as a sibling yet. */
if (event != leader) {
if (intel_set_branch_counter_constr(event, &num))
return -EINVAL;
if (branch_sample_counters(sibling)) {
num++;
sibling->hw.dyn_constraint &= x86_pmu.lbr_counters;
}
}
if (num > fls(x86_pmu.lbr_counters))

View File

@@ -345,12 +345,12 @@ static u64 parse_omr_data_source(u8 dse)
if (omr.omr_remote)
val |= REM;
val |= omr.omr_hitm ? P(SNOOP, HITM) : P(SNOOP, HIT);
if (omr.omr_source == 0x2) {
u8 snoop = omr.omr_snoop | omr.omr_promoted;
u8 snoop = omr.omr_snoop | (omr.omr_promoted << 1);
if (snoop == 0x0)
if (omr.omr_hitm)
val |= P(SNOOP, HITM);
else if (snoop == 0x0)
val |= P(SNOOP, NA);
else if (snoop == 0x1)
val |= P(SNOOP, MISS);
@@ -359,7 +359,10 @@ static u64 parse_omr_data_source(u8 dse)
else if (snoop == 0x3)
val |= P(SNOOP, NONE);
} else if (omr.omr_source > 0x2 && omr.omr_source < 0x7) {
val |= omr.omr_hitm ? P(SNOOP, HITM) : P(SNOOP, HIT);
val |= omr.omr_snoop ? P(SNOOPX, FWD) : 0;
} else {
val |= P(SNOOP, NONE);
}
return val;

View File

@@ -107,14 +107,12 @@ static void __noreturn hv_panic_timeout_reboot(void)
cpu_relax();
}
/* This cannot be inlined as it needs stack */
static noinline __noclone void hv_crash_restore_tss(void)
static void hv_crash_restore_tss(void)
{
load_TR_desc();
}
/* This cannot be inlined as it needs stack */
static noinline void hv_crash_clear_kernpt(void)
static void hv_crash_clear_kernpt(void)
{
pgd_t *pgd;
p4d_t *p4d;
@@ -125,50 +123,9 @@ static noinline void hv_crash_clear_kernpt(void)
native_p4d_clear(p4d);
}
/*
* This is the C entry point from the asm glue code after the disable hypercall.
* We enter here in IA32-e long mode, ie, full 64bit mode running on kernel
* page tables with our below 4G page identity mapped, but using a temporary
* GDT. ds/fs/gs/es are null. ss is not usable. bp is null. stack is not
* available. We restore kernel GDT, and rest of the context, and continue
* to kexec.
*/
static asmlinkage void __noreturn hv_crash_c_entry(void)
static void __noreturn hv_crash_handle(void)
{
struct hv_crash_ctxt *ctxt = &hv_crash_ctxt;
/* first thing, restore kernel gdt */
native_load_gdt(&ctxt->gdtr);
asm volatile("movw %%ax, %%ss" : : "a"(ctxt->ss));
asm volatile("movq %0, %%rsp" : : "m"(ctxt->rsp));
asm volatile("movw %%ax, %%ds" : : "a"(ctxt->ds));
asm volatile("movw %%ax, %%es" : : "a"(ctxt->es));
asm volatile("movw %%ax, %%fs" : : "a"(ctxt->fs));
asm volatile("movw %%ax, %%gs" : : "a"(ctxt->gs));
native_wrmsrq(MSR_IA32_CR_PAT, ctxt->pat);
asm volatile("movq %0, %%cr0" : : "r"(ctxt->cr0));
asm volatile("movq %0, %%cr8" : : "r"(ctxt->cr8));
asm volatile("movq %0, %%cr4" : : "r"(ctxt->cr4));
asm volatile("movq %0, %%cr2" : : "r"(ctxt->cr4));
native_load_idt(&ctxt->idtr);
native_wrmsrq(MSR_GS_BASE, ctxt->gsbase);
native_wrmsrq(MSR_EFER, ctxt->efer);
/* restore the original kernel CS now via far return */
asm volatile("movzwq %0, %%rax\n\t"
"pushq %%rax\n\t"
"pushq $1f\n\t"
"lretq\n\t"
"1:nop\n\t" : : "m"(ctxt->cs) : "rax");
/* We are in asmlinkage without stack frame, hence make C function
* calls which will buy stack frames.
*/
hv_crash_restore_tss();
hv_crash_clear_kernpt();
@@ -177,7 +134,54 @@ static asmlinkage void __noreturn hv_crash_c_entry(void)
hv_panic_timeout_reboot();
}
/* Tell gcc we are using lretq long jump in the above function intentionally */
/*
* __naked functions do not permit function calls, not even to __always_inline
* functions that only contain asm() blocks themselves. So use a macro instead.
*/
#define hv_wrmsr(msr, val) \
asm volatile("wrmsr" :: "c"(msr), "a"((u32)val), "d"((u32)(val >> 32)) : "memory")
/*
* This is the C entry point from the asm glue code after the disable hypercall.
* We enter here in IA32-e long mode, ie, full 64bit mode running on kernel
* page tables with our below 4G page identity mapped, but using a temporary
* GDT. ds/fs/gs/es are null. ss is not usable. bp is null. stack is not
* available. We restore kernel GDT, and rest of the context, and continue
* to kexec.
*/
static void __naked hv_crash_c_entry(void)
{
/* first thing, restore kernel gdt */
asm volatile("lgdt %0" : : "m" (hv_crash_ctxt.gdtr));
asm volatile("movw %0, %%ss\n\t"
"movq %1, %%rsp"
:: "m"(hv_crash_ctxt.ss), "m"(hv_crash_ctxt.rsp));
asm volatile("movw %0, %%ds" : : "m"(hv_crash_ctxt.ds));
asm volatile("movw %0, %%es" : : "m"(hv_crash_ctxt.es));
asm volatile("movw %0, %%fs" : : "m"(hv_crash_ctxt.fs));
asm volatile("movw %0, %%gs" : : "m"(hv_crash_ctxt.gs));
hv_wrmsr(MSR_IA32_CR_PAT, hv_crash_ctxt.pat);
asm volatile("movq %0, %%cr0" : : "r"(hv_crash_ctxt.cr0));
asm volatile("movq %0, %%cr8" : : "r"(hv_crash_ctxt.cr8));
asm volatile("movq %0, %%cr4" : : "r"(hv_crash_ctxt.cr4));
asm volatile("movq %0, %%cr2" : : "r"(hv_crash_ctxt.cr2));
asm volatile("lidt %0" : : "m" (hv_crash_ctxt.idtr));
hv_wrmsr(MSR_GS_BASE, hv_crash_ctxt.gsbase);
hv_wrmsr(MSR_EFER, hv_crash_ctxt.efer);
/* restore the original kernel CS now via far return */
asm volatile("pushq %q0\n\t"
"pushq %q1\n\t"
"lretq"
:: "r"(hv_crash_ctxt.cs), "r"(hv_crash_handle));
}
/* Tell objtool we are using lretq long jump in the above function intentionally */
STACK_FRAME_NON_STANDARD(hv_crash_c_entry);
static void hv_mark_tss_not_busy(void)
@@ -195,20 +199,20 @@ static void hv_hvcrash_ctxt_save(void)
{
struct hv_crash_ctxt *ctxt = &hv_crash_ctxt;
asm volatile("movq %%rsp,%0" : "=m"(ctxt->rsp));
ctxt->rsp = current_stack_pointer;
ctxt->cr0 = native_read_cr0();
ctxt->cr4 = native_read_cr4();
asm volatile("movq %%cr2, %0" : "=a"(ctxt->cr2));
asm volatile("movq %%cr8, %0" : "=a"(ctxt->cr8));
asm volatile("movq %%cr2, %0" : "=r"(ctxt->cr2));
asm volatile("movq %%cr8, %0" : "=r"(ctxt->cr8));
asm volatile("movl %%cs, %%eax" : "=a"(ctxt->cs));
asm volatile("movl %%ss, %%eax" : "=a"(ctxt->ss));
asm volatile("movl %%ds, %%eax" : "=a"(ctxt->ds));
asm volatile("movl %%es, %%eax" : "=a"(ctxt->es));
asm volatile("movl %%fs, %%eax" : "=a"(ctxt->fs));
asm volatile("movl %%gs, %%eax" : "=a"(ctxt->gs));
asm volatile("movw %%cs, %0" : "=m"(ctxt->cs));
asm volatile("movw %%ss, %0" : "=m"(ctxt->ss));
asm volatile("movw %%ds, %0" : "=m"(ctxt->ds));
asm volatile("movw %%es, %0" : "=m"(ctxt->es));
asm volatile("movw %%fs, %0" : "=m"(ctxt->fs));
asm volatile("movw %%gs, %0" : "=m"(ctxt->gs));
native_store_gdt(&ctxt->gdtr);
store_idt(&ctxt->idtr);

View File

@@ -1708,8 +1708,22 @@ static void __init uv_system_init_hub(void)
struct uv_hub_info_s *new_hub;
/* Allocate & fill new per hub info list */
new_hub = (bid == 0) ? &uv_hub_info_node0
: kzalloc_node(bytes, GFP_KERNEL, uv_blade_to_node(bid));
if (bid == 0) {
new_hub = &uv_hub_info_node0;
} else {
int nid;
/*
* Deconfigured sockets are mapped to SOCK_EMPTY. Use
* NUMA_NO_NODE to allocate on a valid node.
*/
nid = uv_blade_to_node(bid);
if (nid == SOCK_EMPTY)
nid = NUMA_NO_NODE;
new_hub = kzalloc_node(bytes, GFP_KERNEL, nid);
}
if (WARN_ON_ONCE(!new_hub)) {
/* do not kfree() bid 0, which is statically allocated */
while (--bid > 0)

View File

@@ -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. */
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 unsigned long cr4_pinned_bits __ro_after_init;
@@ -2050,12 +2063,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
setup_umip(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.
* 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. */
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)) {
/* The boot CPU has enabled FRED during early boot */
if (!boot_cpu)

View File

@@ -875,13 +875,18 @@ void amd_clear_bank(struct mce *m)
{
amd_reset_thr_limit(m->bank);
/* Clear MCA_DESTAT for all deferred errors even those logged in MCA_STATUS. */
if (m->status & MCI_STATUS_DEFERRED)
mce_wrmsrq(MSR_AMD64_SMCA_MCx_DESTAT(m->bank), 0);
if (mce_flags.smca) {
/*
* Clear MCA_DESTAT for all deferred errors even those
* logged in MCA_STATUS.
*/
if (m->status & MCI_STATUS_DEFERRED)
mce_wrmsrq(MSR_AMD64_SMCA_MCx_DESTAT(m->bank), 0);
/* Don't clear MCA_STATUS if MCA_DESTAT was used exclusively. */
if (m->kflags & MCE_CHECK_DFR_REGS)
return;
/* Don't clear MCA_STATUS if MCA_DESTAT was used exclusively. */
if (m->kflags & MCE_CHECK_DFR_REGS)
return;
}
mce_wrmsrq(mca_msr_reg(m->bank, MCA_STATUS), 0);
}

View File

@@ -496,8 +496,9 @@ static void hv_reserve_irq_vectors(void)
test_and_set_bit(HYPERV_DBG_FASTFAIL_VECTOR, system_vectors))
BUG();
pr_info("Hyper-V: reserve vectors: %d %d %d\n", HYPERV_DBG_ASSERT_VECTOR,
HYPERV_DBG_SERVICE_VECTOR, HYPERV_DBG_FASTFAIL_VECTOR);
pr_info("Hyper-V: reserve vectors: 0x%x 0x%x 0x%x\n",
HYPERV_DBG_ASSERT_VECTOR, HYPERV_DBG_SERVICE_VECTOR,
HYPERV_DBG_FASTFAIL_VECTOR);
}
static void __init ms_hyperv_init_platform(void)

View File

@@ -3044,12 +3044,6 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot,
bool prefetch = !fault || fault->prefetch;
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 (prefetch && is_last_spte(*sptep, level) &&
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);
drop_parent_pte(vcpu->kvm, child, sptep);
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);
flush = true;
} else
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,
false, host_writable, &spte);

View File

@@ -424,7 +424,7 @@ void __init efi_unmap_boot_services(void)
if (efi_enabled(EFI_DBG))
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);
if (!ranges_to_free) {
pr_err("Failed to allocate storage for freeable EFI regions\n");

View File

@@ -35,6 +35,7 @@
#define IVPU_HW_IP_60XX 60
#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_LNL 2

View File

@@ -70,8 +70,10 @@ static void wa_init(struct ivpu_device *vdev)
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);
if (ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL &&
ivpu_revision(vdev) < IVPU_HW_IP_REV_LNL_B0)
if ((ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL &&
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;
if (ivpu_test_mode & IVPU_TEST_MODE_CLK_RELINQ_ENABLE)

View File

@@ -113,6 +113,10 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
PCI_ANY_ID, PCI_ANY_ID, NULL);
if (ide_dev) {
errata.piix4.bmisx = pci_resource_start(ide_dev, 4);
if (errata.piix4.bmisx)
dev_dbg(&ide_dev->dev,
"Bus master activity detection (BM-IDE) erratum enabled\n");
pci_dev_put(ide_dev);
}
@@ -131,20 +135,17 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
if (isa_dev) {
pci_read_config_byte(isa_dev, 0x76, &value1);
pci_read_config_byte(isa_dev, 0x77, &value2);
if ((value1 & 0x80) || (value2 & 0x80))
if ((value1 & 0x80) || (value2 & 0x80)) {
errata.piix4.fdma = 1;
dev_dbg(&isa_dev->dev,
"Type-F DMA livelock erratum (C3 disabled)\n");
}
pci_dev_put(isa_dev);
}
break;
}
if (ide_dev)
dev_dbg(&ide_dev->dev, "Bus master activity detection (BM-IDE) erratum enabled\n");
if (isa_dev)
dev_dbg(&isa_dev->dev, "Type-F DMA livelock erratum (C3 disabled)\n");
return 0;
}

View File

@@ -451,7 +451,7 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_DSM",
METHOD_4ARGS(ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER,
ACPI_TYPE_ANY | ACPI_TYPE_PACKAGE) |
ACPI_TYPE_PACKAGE | ACPI_TYPE_ANY) |
ARG_COUNT_IS_MINIMUM,
METHOD_RETURNS(ACPI_RTYPE_ALL)}}, /* Must return a value, but it can be of any type */

View File

@@ -818,9 +818,6 @@ const struct acpi_device *acpi_companion_match(const struct device *dev)
if (list_empty(&adev->pnp.ids))
return NULL;
if (adev->pnp.type.backlight)
return adev;
return acpi_primary_dev_companion(adev, dev);
}

View File

@@ -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);
if (ret) {
ec_remove_handlers(ec);
if (ec == first_ec)
first_ec = NULL;

View File

@@ -4188,6 +4188,9 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
{ "ST3320[68]13AS", "SD1[5-9]", ATA_QUIRK_NONCQ |
ATA_QUIRK_FIRMWARE_WARN },
/* ADATA devices with LPM issues. */
{ "ADATA SU680", NULL, ATA_QUIRK_NOLPM },
/* Seagate disks with LPM issues */
{ "ST1000DM010-2EP102", NULL, ATA_QUIRK_NOLPM },
{ "ST2000DM008-2FR102", NULL, ATA_QUIRK_NOLPM },

View File

@@ -3600,7 +3600,7 @@ static unsigned int ata_scsiop_maint_in(struct ata_device *dev,
if (cdb[2] != 1 && cdb[2] != 3) {
ata_dev_warn(dev, "invalid command format %d\n", cdb[2]);
ata_scsi_set_invalid_field(dev, cmd, 1, 0xff);
ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
return 0;
}

View File

@@ -504,6 +504,36 @@ int bus_for_each_drv(const struct bus_type *bus, struct device_driver *start,
}
EXPORT_SYMBOL_GPL(bus_for_each_drv);
static ssize_t driver_override_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
ret = __device_set_driver_override(dev, buf, count);
if (ret)
return ret;
return count;
}
static ssize_t driver_override_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
guard(spinlock)(&dev->driver_override.lock);
return sysfs_emit(buf, "%s\n", dev->driver_override.name);
}
static DEVICE_ATTR_RW(driver_override);
static struct attribute *driver_override_dev_attrs[] = {
&dev_attr_driver_override.attr,
NULL,
};
static const struct attribute_group driver_override_dev_group = {
.attrs = driver_override_dev_attrs,
};
/**
* bus_add_device - add device to bus
* @dev: device being added
@@ -537,9 +567,15 @@ int bus_add_device(struct device *dev)
if (error)
goto out_put;
if (dev->bus->driver_override) {
error = device_add_group(dev, &driver_override_dev_group);
if (error)
goto out_groups;
}
error = sysfs_create_link(&sp->devices_kset->kobj, &dev->kobj, dev_name(dev));
if (error)
goto out_groups;
goto out_override;
error = sysfs_create_link(&dev->kobj, &sp->subsys.kobj, "subsystem");
if (error)
@@ -550,6 +586,9 @@ int bus_add_device(struct device *dev)
out_subsys:
sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev));
out_override:
if (dev->bus->driver_override)
device_remove_group(dev, &driver_override_dev_group);
out_groups:
device_remove_groups(dev, sp->bus->dev_groups);
out_put:
@@ -607,6 +646,8 @@ void bus_remove_device(struct device *dev)
sysfs_remove_link(&dev->kobj, "subsystem");
sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev));
if (dev->bus->driver_override)
device_remove_group(dev, &driver_override_dev_group);
device_remove_groups(dev, dev->bus->dev_groups);
if (klist_node_attached(&dev->p->knode_bus))
klist_del(&dev->p->knode_bus);

View File

@@ -2556,6 +2556,7 @@ static void device_release(struct kobject *kobj)
devres_release_all(dev);
kfree(dev->dma_range_map);
kfree(dev->driver_override.name);
if (dev->release)
dev->release(dev);
@@ -3159,6 +3160,7 @@ void device_initialize(struct device *dev)
kobject_init(&dev->kobj, &device_ktype);
INIT_LIST_HEAD(&dev->dma_pools);
mutex_init(&dev->mutex);
spin_lock_init(&dev->driver_override.lock);
lockdep_set_novalidate_class(&dev->mutex);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);

View File

@@ -381,6 +381,66 @@ static void __exit deferred_probe_exit(void)
}
__exitcall(deferred_probe_exit);
int __device_set_driver_override(struct device *dev, const char *s, size_t len)
{
const char *new, *old;
char *cp;
if (!s)
return -EINVAL;
/*
* The stored value will be used in sysfs show callback (sysfs_emit()),
* which has a length limit of PAGE_SIZE and adds a trailing newline.
* Thus we can store one character less to avoid truncation during sysfs
* show.
*/
if (len >= (PAGE_SIZE - 1))
return -EINVAL;
/*
* Compute the real length of the string in case userspace sends us a
* bunch of \0 characters like python likes to do.
*/
len = strlen(s);
if (!len) {
/* Empty string passed - clear override */
spin_lock(&dev->driver_override.lock);
old = dev->driver_override.name;
dev->driver_override.name = NULL;
spin_unlock(&dev->driver_override.lock);
kfree(old);
return 0;
}
cp = strnchr(s, len, '\n');
if (cp)
len = cp - s;
new = kstrndup(s, len, GFP_KERNEL);
if (!new)
return -ENOMEM;
spin_lock(&dev->driver_override.lock);
old = dev->driver_override.name;
if (cp != s) {
dev->driver_override.name = new;
spin_unlock(&dev->driver_override.lock);
} else {
/* "\n" passed - clear override */
dev->driver_override.name = NULL;
spin_unlock(&dev->driver_override.lock);
kfree(new);
}
kfree(old);
return 0;
}
EXPORT_SYMBOL_GPL(__device_set_driver_override);
/**
* device_is_bound() - Check if device is bound to a driver
* @dev: device to check

View File

@@ -603,7 +603,6 @@ static void platform_device_release(struct device *dev)
kfree(pa->pdev.dev.platform_data);
kfree(pa->pdev.mfd_cell);
kfree(pa->pdev.resource);
kfree(pa->pdev.driver_override);
kfree(pa);
}
@@ -1306,38 +1305,9 @@ static ssize_t numa_node_show(struct device *dev,
}
static DEVICE_ATTR_RO(numa_node);
static ssize_t driver_override_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
ssize_t len;
device_lock(dev);
len = sysfs_emit(buf, "%s\n", pdev->driver_override);
device_unlock(dev);
return len;
}
static ssize_t driver_override_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct platform_device *pdev = to_platform_device(dev);
int ret;
ret = driver_set_override(dev, &pdev->driver_override, buf, count);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR_RW(driver_override);
static struct attribute *platform_dev_attrs[] = {
&dev_attr_modalias.attr,
&dev_attr_numa_node.attr,
&dev_attr_driver_override.attr,
NULL,
};
@@ -1377,10 +1347,12 @@ static int platform_match(struct device *dev, const struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
int ret;
/* When driver_override is set, only bind to the matching driver */
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
ret = device_match_driver_override(dev, drv);
if (ret >= 0)
return ret;
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
@@ -1516,6 +1488,7 @@ static const struct dev_pm_ops platform_dev_pm_ops = {
const struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.driver_override = true,
.match = platform_match,
.uevent = platform_uevent,
.probe = platform_probe,

View File

@@ -1895,6 +1895,7 @@ void pm_runtime_reinit(struct device *dev)
void pm_runtime_remove(struct device *dev)
{
__pm_runtime_disable(dev, false);
flush_work(&dev->power.work);
pm_runtime_reinit(dev);
}

View File

@@ -1545,6 +1545,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
unsigned int val_num)
{
void *orig_work_buf;
unsigned int selector_reg;
unsigned int win_offset;
unsigned int win_page;
bool page_chg;
@@ -1563,10 +1564,31 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
return -EINVAL;
}
/* 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. */
/*
* Calculate the address of the selector register in the corresponding
* 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 ||
(page_chg && selector_reg != range->selector_reg) ||
range->window_start + win_offset != range->selector_reg) {
/* Use separate work_buf during page switching */
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,
range->selector_mask,
win_page << range->selector_shift,
&page_chg, false);
NULL, false);
map->work_buf = orig_work_buf;

View File

@@ -917,9 +917,8 @@ static void zram_account_writeback_submit(struct zram *zram)
static int zram_writeback_complete(struct zram *zram, struct zram_wb_req *req)
{
u32 size, index = req->pps->index;
int err, prio;
bool huge;
u32 index = req->pps->index;
int err;
err = blk_status_to_errno(req->bio.bi_status);
if (err) {
@@ -946,28 +945,13 @@ static int zram_writeback_complete(struct zram *zram, struct zram_wb_req *req)
goto out;
}
if (zram->compressed_wb) {
/*
* ZRAM_WB slots get freed, we need to preserve data required
* for read decompression.
*/
size = get_slot_size(zram, index);
prio = get_slot_comp_priority(zram, index);
huge = test_slot_flag(zram, index, ZRAM_HUGE);
}
slot_free(zram, index);
set_slot_flag(zram, index, ZRAM_WB);
clear_slot_flag(zram, index, ZRAM_IDLE);
if (test_slot_flag(zram, index, ZRAM_HUGE))
atomic64_dec(&zram->stats.huge_pages);
atomic64_sub(get_slot_size(zram, index), &zram->stats.compr_data_size);
zs_free(zram->mem_pool, get_slot_handle(zram, index));
set_slot_handle(zram, index, req->blk_idx);
if (zram->compressed_wb) {
if (huge)
set_slot_flag(zram, index, ZRAM_HUGE);
set_slot_size(zram, index, size);
set_slot_comp_priority(zram, index, prio);
}
atomic64_inc(&zram->stats.pages_stored);
set_slot_flag(zram, index, ZRAM_WB);
out:
slot_unlock(zram, index);
@@ -2010,8 +1994,13 @@ static void slot_free(struct zram *zram, u32 index)
set_slot_comp_priority(zram, index, 0);
if (test_slot_flag(zram, index, ZRAM_HUGE)) {
/*
* Writeback completion decrements ->huge_pages but keeps
* ZRAM_HUGE flag for deferred decompression path.
*/
if (!test_slot_flag(zram, index, ZRAM_WB))
atomic64_dec(&zram->stats.huge_pages);
clear_slot_flag(zram, index, ZRAM_HUGE);
atomic64_dec(&zram->stats.huge_pages);
}
if (test_slot_flag(zram, index, ZRAM_WB)) {

View File

@@ -251,11 +251,13 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code)
bt_dev_err(hdev, "Hardware error 0x%2.2x", code);
hci_req_sync_lock(hdev);
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Reset after hardware error failed (%ld)",
PTR_ERR(skb));
return;
goto unlock;
}
kfree_skb(skb);
@@ -263,18 +265,21 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code)
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Retrieving Intel exception info failed (%ld)",
PTR_ERR(skb));
return;
goto unlock;
}
if (skb->len != 13) {
bt_dev_err(hdev, "Exception info size mismatch");
kfree_skb(skb);
return;
goto unlock;
}
bt_dev_err(hdev, "Exception info %s", (char *)(skb->data + 1));
kfree_skb(skb);
unlock:
hci_req_sync_unlock(hdev);
}
EXPORT_SYMBOL_GPL(btintel_hw_error);

View File

@@ -787,6 +787,8 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
*/
if (soc_type == QCA_WCN3988)
rom_ver = ((soc_ver & 0x00000f00) >> 0x05) | (soc_ver & 0x0000000f);
else if (soc_type == QCA_WCN3998)
rom_ver = ((soc_ver & 0x0000f000) >> 0x07) | (soc_ver & 0x0000000f);
else
rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);

View File

@@ -2376,8 +2376,11 @@ static void btusb_work(struct work_struct *work)
if (data->air_mode == HCI_NOTIFY_ENABLE_SCO_CVSD) {
if (hdev->voice_setting & 0x0020) {
static const int alts[3] = { 2, 4, 5 };
unsigned int sco_idx;
new_alts = alts[data->sco_num - 1];
sco_idx = min_t(unsigned int, data->sco_num - 1,
ARRAY_SIZE(alts) - 1);
new_alts = alts[sco_idx];
} else {
new_alts = data->sco_num;
}

View File

@@ -541,6 +541,8 @@ static int download_firmware(struct ll_device *lldev)
if (err || !fw->data || !fw->size) {
bt_dev_err(lldev->hu.hdev, "request_firmware failed(errno %d) for %s",
err, bts_scr_name);
if (!err)
release_firmware(fw);
return -EINVAL;
}
ptr = (void *)fw->data;

View File

@@ -36,7 +36,7 @@ static int simple_pm_bus_probe(struct platform_device *pdev)
* that's not listed in simple_pm_bus_of_match. We don't want to do any
* of the simple-pm-bus tasks for these devices, so return early.
*/
if (pdev->driver_override)
if (device_has_driver_override(&pdev->dev))
return 0;
match = of_match_device(dev->driver->of_match_table, dev);
@@ -78,7 +78,7 @@ static void simple_pm_bus_remove(struct platform_device *pdev)
{
const void *data = of_device_get_match_data(&pdev->dev);
if (pdev->driver_override || data)
if (device_has_driver_override(&pdev->dev) || data)
return;
dev_dbg(&pdev->dev, "%s\n", __func__);

View File

@@ -178,11 +178,11 @@ static const struct of_device_id ax45mp_cache_ids[] = {
static int __init ax45mp_cache_init(void)
{
struct device_node *np;
struct resource res;
int ret;
np = of_find_matching_node(NULL, ax45mp_cache_ids);
struct device_node *np __free(device_node) =
of_find_matching_node(NULL, ax45mp_cache_ids);
if (!of_device_is_available(np))
return -ENODEV;

View File

@@ -102,11 +102,11 @@ static const struct of_device_id starlink_cache_ids[] = {
static int __init starlink_cache_init(void)
{
struct device_node *np;
u32 block_size;
int ret;
np = of_find_matching_node(NULL, starlink_cache_ids);
struct device_node *np __free(device_node) =
of_find_matching_node(NULL, starlink_cache_ids);
if (!of_device_is_available(np))
return -ENODEV;

View File

@@ -706,8 +706,7 @@ struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
if (ret)
goto put_device;
ret = driver_set_override(&pdev->dev, &pdev->driver_override,
"imx-scu-clk", strlen("imx-scu-clk"));
ret = device_set_driver_override(&pdev->dev, "imx-scu-clk");
if (ret)
goto put_device;

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