Merge 5.7-rc5 into staging-next

We need the staging fixes in here as well.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Greg Kroah-Hartman 2020-05-11 08:57:22 +02:00
commit ae73e77848
461 changed files with 4390 additions and 2041 deletions

View File

@ -182,12 +182,15 @@ fix_padding
space-efficient. If this option is not present, large padding is space-efficient. If this option is not present, large padding is
used - that is for compatibility with older kernels. used - that is for compatibility with older kernels.
allow_discards
Allow block discard requests (a.k.a. TRIM) for the integrity device.
Discards are only allowed to devices using internal hash.
The journal mode (D/J), buffer_sectors, journal_watermark, commit_time can The journal mode (D/J), buffer_sectors, journal_watermark, commit_time and
be changed when reloading the target (load an inactive table and swap the allow_discards can be changed when reloading the target (load an inactive
tables with suspend and resume). The other arguments should not be changed table and swap the tables with suspend and resume). The other arguments
when reloading the target because the layout of disk data depend on them should not be changed when reloading the target because the layout of disk
and the reloaded target would be non-functional. data depend on them and the reloaded target would be non-functional.
The layout of the formatted block device: The layout of the formatted block device:

View File

@ -22,9 +22,7 @@ properties:
const: socionext,uniphier-xdmac const: socionext,uniphier-xdmac
reg: reg:
items: maxItems: 1
- description: XDMAC base register region (offset and length)
- description: XDMAC extension register region (offset and length)
interrupts: interrupts:
maxItems: 1 maxItems: 1
@ -49,12 +47,13 @@ required:
- reg - reg
- interrupts - interrupts
- "#dma-cells" - "#dma-cells"
- dma-channels
examples: examples:
- | - |
xdmac: dma-controller@5fc10000 { xdmac: dma-controller@5fc10000 {
compatible = "socionext,uniphier-xdmac"; compatible = "socionext,uniphier-xdmac";
reg = <0x5fc10000 0x1000>, <0x5fc20000 0x800>; reg = <0x5fc10000 0x5300>;
interrupts = <0 188 4>; interrupts = <0 188 4>;
#dma-cells = <2>; #dma-cells = <2>;
dma-channels = <16>; dma-channels = <16>;

View File

@ -61,8 +61,8 @@ The ``ice`` driver reports the following versions
- running - running
- ICE OS Default Package - ICE OS Default Package
- The name of the DDP package that is active in the device. The DDP - The name of the DDP package that is active in the device. The DDP
package is loaded by the driver during initialization. Each varation package is loaded by the driver during initialization. Each
of DDP package shall have a unique name. variation of the DDP package has a unique name.
* - ``fw.app`` * - ``fw.app``
- running - running
- 1.3.1.0 - 1.3.1.0

View File

@ -28,3 +28,5 @@ KVM
arm/index arm/index
devices/index devices/index
running-nested-guests

View File

@ -0,0 +1,276 @@
==============================
Running nested guests with KVM
==============================
A nested guest is the ability to run a guest inside another guest (it
can be KVM-based or a different hypervisor). The straightforward
example is a KVM guest that in turn runs on a KVM guest (the rest of
this document is built on this example)::
.----------------. .----------------.
| | | |
| L2 | | L2 |
| (Nested Guest) | | (Nested Guest) |
| | | |
|----------------'--'----------------|
| |
| L1 (Guest Hypervisor) |
| KVM (/dev/kvm) |
| |
.------------------------------------------------------.
| L0 (Host Hypervisor) |
| KVM (/dev/kvm) |
|------------------------------------------------------|
| Hardware (with virtualization extensions) |
'------------------------------------------------------'
Terminology:
- L0 level-0; the bare metal host, running KVM
- L1 level-1 guest; a VM running on L0; also called the "guest
hypervisor", as it itself is capable of running KVM.
- L2 level-2 guest; a VM running on L1, this is the "nested guest"
.. note:: The above diagram is modelled after the x86 architecture;
s390x, ppc64 and other architectures are likely to have
a different design for nesting.
For example, s390x always has an LPAR (LogicalPARtition)
hypervisor running on bare metal, adding another layer and
resulting in at least four levels in a nested setup — L0 (bare
metal, running the LPAR hypervisor), L1 (host hypervisor), L2
(guest hypervisor), L3 (nested guest).
This document will stick with the three-level terminology (L0,
L1, and L2) for all architectures; and will largely focus on
x86.
Use Cases
---------
There are several scenarios where nested KVM can be useful, to name a
few:
- As a developer, you want to test your software on different operating
systems (OSes). Instead of renting multiple VMs from a Cloud
Provider, using nested KVM lets you rent a large enough "guest
hypervisor" (level-1 guest). This in turn allows you to create
multiple nested guests (level-2 guests), running different OSes, on
which you can develop and test your software.
- Live migration of "guest hypervisors" and their nested guests, for
load balancing, disaster recovery, etc.
- VM image creation tools (e.g. ``virt-install``, etc) often run
their own VM, and users expect these to work inside a VM.
- Some OSes use virtualization internally for security (e.g. to let
applications run safely in isolation).
Enabling "nested" (x86)
-----------------------
From Linux kernel v4.19 onwards, the ``nested`` KVM parameter is enabled
by default for Intel and AMD. (Though your Linux distribution might
override this default.)
In case you are running a Linux kernel older than v4.19, to enable
nesting, set the ``nested`` KVM module parameter to ``Y`` or ``1``. To
persist this setting across reboots, you can add it in a config file, as
shown below:
1. On the bare metal host (L0), list the kernel modules and ensure that
the KVM modules::
$ lsmod | grep -i kvm
kvm_intel 133627 0
kvm 435079 1 kvm_intel
2. Show information for ``kvm_intel`` module::
$ modinfo kvm_intel | grep -i nested
parm: nested:bool
3. For the nested KVM configuration to persist across reboots, place the
below in ``/etc/modprobed/kvm_intel.conf`` (create the file if it
doesn't exist)::
$ cat /etc/modprobe.d/kvm_intel.conf
options kvm-intel nested=y
4. Unload and re-load the KVM Intel module::
$ sudo rmmod kvm-intel
$ sudo modprobe kvm-intel
5. Verify if the ``nested`` parameter for KVM is enabled::
$ cat /sys/module/kvm_intel/parameters/nested
Y
For AMD hosts, the process is the same as above, except that the module
name is ``kvm-amd``.
Additional nested-related kernel parameters (x86)
-------------------------------------------------
If your hardware is sufficiently advanced (Intel Haswell processor or
higher, which has newer hardware virt extensions), the following
additional features will also be enabled by default: "Shadow VMCS
(Virtual Machine Control Structure)", APIC Virtualization on your bare
metal host (L0). Parameters for Intel hosts::
$ cat /sys/module/kvm_intel/parameters/enable_shadow_vmcs
Y
$ cat /sys/module/kvm_intel/parameters/enable_apicv
Y
$ cat /sys/module/kvm_intel/parameters/ept
Y
.. note:: If you suspect your L2 (i.e. nested guest) is running slower,
ensure the above are enabled (particularly
``enable_shadow_vmcs`` and ``ept``).
Starting a nested guest (x86)
-----------------------------
Once your bare metal host (L0) is configured for nesting, you should be
able to start an L1 guest with::
$ qemu-kvm -cpu host [...]
The above will pass through the host CPU's capabilities as-is to the
gues); or for better live migration compatibility, use a named CPU
model supported by QEMU. e.g.::
$ qemu-kvm -cpu Haswell-noTSX-IBRS,vmx=on
then the guest hypervisor will subsequently be capable of running a
nested guest with accelerated KVM.
Enabling "nested" (s390x)
-------------------------
1. On the host hypervisor (L0), enable the ``nested`` parameter on
s390x::
$ rmmod kvm
$ modprobe kvm nested=1
.. note:: On s390x, the kernel parameter ``hpage`` is mutually exclusive
with the ``nested`` paramter — i.e. to be able to enable
``nested``, the ``hpage`` parameter *must* be disabled.
2. The guest hypervisor (L1) must be provided with the ``sie`` CPU
feature — with QEMU, this can be done by using "host passthrough"
(via the command-line ``-cpu host``).
3. Now the KVM module can be loaded in the L1 (guest hypervisor)::
$ modprobe kvm
Live migration with nested KVM
------------------------------
Migrating an L1 guest, with a *live* nested guest in it, to another
bare metal host, works as of Linux kernel 5.3 and QEMU 4.2.0 for
Intel x86 systems, and even on older versions for s390x.
On AMD systems, once an L1 guest has started an L2 guest, the L1 guest
should no longer be migrated or saved (refer to QEMU documentation on
"savevm"/"loadvm") until the L2 guest shuts down. Attempting to migrate
or save-and-load an L1 guest while an L2 guest is running will result in
undefined behavior. You might see a ``kernel BUG!`` entry in ``dmesg``, a
kernel 'oops', or an outright kernel panic. Such a migrated or loaded L1
guest can no longer be considered stable or secure, and must be restarted.
Migrating an L1 guest merely configured to support nesting, while not
actually running L2 guests, is expected to function normally even on AMD
systems but may fail once guests are started.
Migrating an L2 guest is always expected to succeed, so all the following
scenarios should work even on AMD systems:
- Migrating a nested guest (L2) to another L1 guest on the *same* bare
metal host.
- Migrating a nested guest (L2) to another L1 guest on a *different*
bare metal host.
- Migrating a nested guest (L2) to a bare metal host.
Reporting bugs from nested setups
-----------------------------------
Debugging "nested" problems can involve sifting through log files across
L0, L1 and L2; this can result in tedious back-n-forth between the bug
reporter and the bug fixer.
- Mention that you are in a "nested" setup. If you are running any kind
of "nesting" at all, say so. Unfortunately, this needs to be called
out because when reporting bugs, people tend to forget to even
*mention* that they're using nested virtualization.
- Ensure you are actually running KVM on KVM. Sometimes people do not
have KVM enabled for their guest hypervisor (L1), which results in
them running with pure emulation or what QEMU calls it as "TCG", but
they think they're running nested KVM. Thus confusing "nested Virt"
(which could also mean, QEMU on KVM) with "nested KVM" (KVM on KVM).
Information to collect (generic)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The following is not an exhaustive list, but a very good starting point:
- Kernel, libvirt, and QEMU version from L0
- Kernel, libvirt and QEMU version from L1
- QEMU command-line of L1 -- when using libvirt, you'll find it here:
``/var/log/libvirt/qemu/instance.log``
- QEMU command-line of L2 -- as above, when using libvirt, get the
complete libvirt-generated QEMU command-line
- ``cat /sys/cpuinfo`` from L0
- ``cat /sys/cpuinfo`` from L1
- ``lscpu`` from L0
- ``lscpu`` from L1
- Full ``dmesg`` output from L0
- Full ``dmesg`` output from L1
x86-specific info to collect
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Both the below commands, ``x86info`` and ``dmidecode``, should be
available on most Linux distributions with the same name:
- Output of: ``x86info -a`` from L0
- Output of: ``x86info -a`` from L1
- Output of: ``dmidecode`` from L0
- Output of: ``dmidecode`` from L1
s390x-specific info to collect
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Along with the earlier mentioned generic details, the below is
also recommended:
- ``/proc/sysinfo`` from L1; this will also include the info from L0

View File

@ -3658,7 +3658,7 @@ L: linux-btrfs@vger.kernel.org
S: Maintained S: Maintained
W: http://btrfs.wiki.kernel.org/ W: http://btrfs.wiki.kernel.org/
Q: http://patchwork.kernel.org/project/linux-btrfs/list/ Q: http://patchwork.kernel.org/project/linux-btrfs/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git
F: Documentation/filesystems/btrfs.rst F: Documentation/filesystems/btrfs.rst
F: fs/btrfs/ F: fs/btrfs/
F: include/linux/btrfs* F: include/linux/btrfs*
@ -3937,11 +3937,9 @@ F: arch/powerpc/platforms/cell/
CEPH COMMON CODE (LIBCEPH) CEPH COMMON CODE (LIBCEPH)
M: Ilya Dryomov <idryomov@gmail.com> M: Ilya Dryomov <idryomov@gmail.com>
M: Jeff Layton <jlayton@kernel.org> M: Jeff Layton <jlayton@kernel.org>
M: Sage Weil <sage@redhat.com>
L: ceph-devel@vger.kernel.org L: ceph-devel@vger.kernel.org
S: Supported S: Supported
W: http://ceph.com/ W: http://ceph.com/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
T: git git://github.com/ceph/ceph-client.git T: git git://github.com/ceph/ceph-client.git
F: include/linux/ceph/ F: include/linux/ceph/
F: include/linux/crush/ F: include/linux/crush/
@ -3949,12 +3947,10 @@ F: net/ceph/
CEPH DISTRIBUTED FILE SYSTEM CLIENT (CEPH) CEPH DISTRIBUTED FILE SYSTEM CLIENT (CEPH)
M: Jeff Layton <jlayton@kernel.org> M: Jeff Layton <jlayton@kernel.org>
M: Sage Weil <sage@redhat.com>
M: Ilya Dryomov <idryomov@gmail.com> M: Ilya Dryomov <idryomov@gmail.com>
L: ceph-devel@vger.kernel.org L: ceph-devel@vger.kernel.org
S: Supported S: Supported
W: http://ceph.com/ W: http://ceph.com/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
T: git git://github.com/ceph/ceph-client.git T: git git://github.com/ceph/ceph-client.git
F: Documentation/filesystems/ceph.rst F: Documentation/filesystems/ceph.rst
F: fs/ceph/ F: fs/ceph/
@ -5936,9 +5932,9 @@ F: lib/dynamic_debug.c
DYNAMIC INTERRUPT MODERATION DYNAMIC INTERRUPT MODERATION
M: Tal Gilboa <talgi@mellanox.com> M: Tal Gilboa <talgi@mellanox.com>
S: Maintained S: Maintained
F: Documentation/networking/net_dim.rst
F: include/linux/dim.h F: include/linux/dim.h
F: lib/dim/ F: lib/dim/
F: Documentation/networking/net_dim.rst
DZ DECSTATION DZ11 SERIAL DRIVER DZ DECSTATION DZ11 SERIAL DRIVER
M: "Maciej W. Rozycki" <macro@linux-mips.org> M: "Maciej W. Rozycki" <macro@linux-mips.org>
@ -7121,9 +7117,10 @@ F: include/uapi/asm-generic/
GENERIC PHY FRAMEWORK GENERIC PHY FRAMEWORK
M: Kishon Vijay Abraham I <kishon@ti.com> M: Kishon Vijay Abraham I <kishon@ti.com>
M: Vinod Koul <vkoul@kernel.org>
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
S: Supported S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy.git
F: Documentation/devicetree/bindings/phy/ F: Documentation/devicetree/bindings/phy/
F: drivers/phy/ F: drivers/phy/
F: include/linux/phy/ F: include/linux/phy/
@ -7748,11 +7745,6 @@ L: platform-driver-x86@vger.kernel.org
S: Orphan S: Orphan
F: drivers/platform/x86/tc1100-wmi.c F: drivers/platform/x86/tc1100-wmi.c
HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
M: Jaroslav Kysela <perex@perex.cz>
S: Obsolete
F: drivers/staging/hp/hp100.*
HPET: High Precision Event Timers driver HPET: High Precision Event Timers driver
M: Clemens Ladisch <clemens@ladisch.de> M: Clemens Ladisch <clemens@ladisch.de>
S: Maintained S: Maintained
@ -14104,12 +14096,10 @@ F: drivers/media/radio/radio-tea5777.c
RADOS BLOCK DEVICE (RBD) RADOS BLOCK DEVICE (RBD)
M: Ilya Dryomov <idryomov@gmail.com> M: Ilya Dryomov <idryomov@gmail.com>
M: Sage Weil <sage@redhat.com>
R: Dongsheng Yang <dongsheng.yang@easystack.cn> R: Dongsheng Yang <dongsheng.yang@easystack.cn>
L: ceph-devel@vger.kernel.org L: ceph-devel@vger.kernel.org
S: Supported S: Supported
W: http://ceph.com/ W: http://ceph.com/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
T: git git://github.com/ceph/ceph-client.git T: git git://github.com/ceph/ceph-client.git
F: Documentation/ABI/testing/sysfs-bus-rbd F: Documentation/ABI/testing/sysfs-bus-rbd
F: drivers/block/rbd.c F: drivers/block/rbd.c

View File

@ -2,7 +2,7 @@
VERSION = 5 VERSION = 5
PATCHLEVEL = 7 PATCHLEVEL = 7
SUBLEVEL = 0 SUBLEVEL = 0
EXTRAVERSION = -rc3 EXTRAVERSION = -rc5
NAME = Kleptomaniac Octopus NAME = Kleptomaniac Octopus
# *DOCUMENTATION* # *DOCUMENTATION*
@ -729,10 +729,6 @@ else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS += -Os KBUILD_CFLAGS += -Os
endif endif
ifdef CONFIG_CC_DISABLE_WARN_MAYBE_UNINITIALIZED
KBUILD_CFLAGS += -Wno-maybe-uninitialized
endif
# Tell gcc to never replace conditional load with a non-conditional one # Tell gcc to never replace conditional load with a non-conditional one
KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0) KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0)
KBUILD_CFLAGS += $(call cc-option,-fno-allow-store-data-races) KBUILD_CFLAGS += $(call cc-option,-fno-allow-store-data-races)
@ -881,6 +877,17 @@ KBUILD_CFLAGS += -Wno-pointer-sign
# disable stringop warnings in gcc 8+ # disable stringop warnings in gcc 8+
KBUILD_CFLAGS += $(call cc-disable-warning, stringop-truncation) KBUILD_CFLAGS += $(call cc-disable-warning, stringop-truncation)
# We'll want to enable this eventually, but it's not going away for 5.7 at least
KBUILD_CFLAGS += $(call cc-disable-warning, zero-length-bounds)
KBUILD_CFLAGS += $(call cc-disable-warning, array-bounds)
KBUILD_CFLAGS += $(call cc-disable-warning, stringop-overflow)
# Another good warning that we'll want to enable eventually
KBUILD_CFLAGS += $(call cc-disable-warning, restrict)
# Enabled with W=2, disabled by default as noisy
KBUILD_CFLAGS += $(call cc-disable-warning, maybe-uninitialized)
# disable invalid "can't wrap" optimizations for signed / pointers # disable invalid "can't wrap" optimizations for signed / pointers
KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow) KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow)

View File

@ -91,9 +91,17 @@ void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes,
return; return;
} }
kernel_neon_begin(); do {
chacha_doneon(state, dst, src, bytes, nrounds); unsigned int todo = min_t(unsigned int, bytes, SZ_4K);
kernel_neon_end();
kernel_neon_begin();
chacha_doneon(state, dst, src, todo, nrounds);
kernel_neon_end();
bytes -= todo;
src += todo;
dst += todo;
} while (bytes);
} }
EXPORT_SYMBOL(chacha_crypt_arch); EXPORT_SYMBOL(chacha_crypt_arch);

View File

@ -30,7 +30,7 @@ static int nhpoly1305_neon_update(struct shash_desc *desc,
return crypto_nhpoly1305_update(desc, src, srclen); return crypto_nhpoly1305_update(desc, src, srclen);
do { do {
unsigned int n = min_t(unsigned int, srclen, PAGE_SIZE); unsigned int n = min_t(unsigned int, srclen, SZ_4K);
kernel_neon_begin(); kernel_neon_begin();
crypto_nhpoly1305_update_helper(desc, src, n, _nh_neon); crypto_nhpoly1305_update_helper(desc, src, n, _nh_neon);

View File

@ -160,13 +160,20 @@ void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src,
unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE); unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE);
if (static_branch_likely(&have_neon) && do_neon) { if (static_branch_likely(&have_neon) && do_neon) {
kernel_neon_begin(); do {
poly1305_blocks_neon(&dctx->h, src, len, 1); unsigned int todo = min_t(unsigned int, len, SZ_4K);
kernel_neon_end();
kernel_neon_begin();
poly1305_blocks_neon(&dctx->h, src, todo, 1);
kernel_neon_end();
len -= todo;
src += todo;
} while (len);
} else { } else {
poly1305_blocks_arm(&dctx->h, src, len, 1); poly1305_blocks_arm(&dctx->h, src, len, 1);
src += len;
} }
src += len;
nbytes %= POLY1305_BLOCK_SIZE; nbytes %= POLY1305_BLOCK_SIZE;
} }

View File

@ -165,8 +165,13 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
preempt_enable(); preempt_enable();
#endif #endif
if (!ret) /*
*oval = oldval; * Store unconditionally. If ret != 0 the extra store is the least
* of the worries but GCC cannot figure out that __futex_atomic_op()
* is either setting ret to -EFAULT or storing the old value in
* oldval which results in a uninitialized warning at the call site.
*/
*oval = oldval;
return ret; return ret;
} }

View File

@ -87,9 +87,17 @@ void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes,
!crypto_simd_usable()) !crypto_simd_usable())
return chacha_crypt_generic(state, dst, src, bytes, nrounds); return chacha_crypt_generic(state, dst, src, bytes, nrounds);
kernel_neon_begin(); do {
chacha_doneon(state, dst, src, bytes, nrounds); unsigned int todo = min_t(unsigned int, bytes, SZ_4K);
kernel_neon_end();
kernel_neon_begin();
chacha_doneon(state, dst, src, todo, nrounds);
kernel_neon_end();
bytes -= todo;
src += todo;
dst += todo;
} while (bytes);
} }
EXPORT_SYMBOL(chacha_crypt_arch); EXPORT_SYMBOL(chacha_crypt_arch);

View File

@ -30,7 +30,7 @@ static int nhpoly1305_neon_update(struct shash_desc *desc,
return crypto_nhpoly1305_update(desc, src, srclen); return crypto_nhpoly1305_update(desc, src, srclen);
do { do {
unsigned int n = min_t(unsigned int, srclen, PAGE_SIZE); unsigned int n = min_t(unsigned int, srclen, SZ_4K);
kernel_neon_begin(); kernel_neon_begin();
crypto_nhpoly1305_update_helper(desc, src, n, _nh_neon); crypto_nhpoly1305_update_helper(desc, src, n, _nh_neon);

View File

@ -143,13 +143,20 @@ void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src,
unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE); unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE);
if (static_branch_likely(&have_neon) && crypto_simd_usable()) { if (static_branch_likely(&have_neon) && crypto_simd_usable()) {
kernel_neon_begin(); do {
poly1305_blocks_neon(&dctx->h, src, len, 1); unsigned int todo = min_t(unsigned int, len, SZ_4K);
kernel_neon_end();
kernel_neon_begin();
poly1305_blocks_neon(&dctx->h, src, todo, 1);
kernel_neon_end();
len -= todo;
src += todo;
} while (len);
} else { } else {
poly1305_blocks(&dctx->h, src, len, 1); poly1305_blocks(&dctx->h, src, len, 1);
src += len;
} }
src += len;
nbytes %= POLY1305_BLOCK_SIZE; nbytes %= POLY1305_BLOCK_SIZE;
} }

View File

@ -32,7 +32,7 @@ UBSAN_SANITIZE := n
OBJECT_FILES_NON_STANDARD := y OBJECT_FILES_NON_STANDARD := y
KCOV_INSTRUMENT := n KCOV_INSTRUMENT := n
CFLAGS_vgettimeofday.o = -O2 -mcmodel=tiny CFLAGS_vgettimeofday.o = -O2 -mcmodel=tiny -fasynchronous-unwind-tables
ifneq ($(c-gettimeofday-y),) ifneq ($(c-gettimeofday-y),)
CFLAGS_vgettimeofday.o += -include $(c-gettimeofday-y) CFLAGS_vgettimeofday.o += -include $(c-gettimeofday-y)

View File

@ -200,6 +200,13 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
} }
memcpy((u32 *)regs + off, valp, KVM_REG_SIZE(reg->id)); memcpy((u32 *)regs + off, valp, KVM_REG_SIZE(reg->id));
if (*vcpu_cpsr(vcpu) & PSR_MODE32_BIT) {
int i;
for (i = 0; i < 16; i++)
*vcpu_reg32(vcpu, i) = (u32)*vcpu_reg32(vcpu, i);
}
out: out:
return err; return err;
} }

View File

@ -18,6 +18,7 @@
#define CPU_GP_REG_OFFSET(x) (CPU_GP_REGS + x) #define CPU_GP_REG_OFFSET(x) (CPU_GP_REGS + x)
#define CPU_XREG_OFFSET(x) CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x) #define CPU_XREG_OFFSET(x) CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
#define CPU_SP_EL0_OFFSET (CPU_XREG_OFFSET(30) + 8)
.text .text
.pushsection .hyp.text, "ax" .pushsection .hyp.text, "ax"
@ -47,6 +48,16 @@
ldp x29, lr, [\ctxt, #CPU_XREG_OFFSET(29)] ldp x29, lr, [\ctxt, #CPU_XREG_OFFSET(29)]
.endm .endm
.macro save_sp_el0 ctxt, tmp
mrs \tmp, sp_el0
str \tmp, [\ctxt, #CPU_SP_EL0_OFFSET]
.endm
.macro restore_sp_el0 ctxt, tmp
ldr \tmp, [\ctxt, #CPU_SP_EL0_OFFSET]
msr sp_el0, \tmp
.endm
/* /*
* u64 __guest_enter(struct kvm_vcpu *vcpu, * u64 __guest_enter(struct kvm_vcpu *vcpu,
* struct kvm_cpu_context *host_ctxt); * struct kvm_cpu_context *host_ctxt);
@ -60,6 +71,9 @@ SYM_FUNC_START(__guest_enter)
// Store the host regs // Store the host regs
save_callee_saved_regs x1 save_callee_saved_regs x1
// Save the host's sp_el0
save_sp_el0 x1, x2
// Now the host state is stored if we have a pending RAS SError it must // Now the host state is stored if we have a pending RAS SError it must
// affect the host. If any asynchronous exception is pending we defer // affect the host. If any asynchronous exception is pending we defer
// the guest entry. The DSB isn't necessary before v8.2 as any SError // the guest entry. The DSB isn't necessary before v8.2 as any SError
@ -83,6 +97,9 @@ alternative_else_nop_endif
// when this feature is enabled for kernel code. // when this feature is enabled for kernel code.
ptrauth_switch_to_guest x29, x0, x1, x2 ptrauth_switch_to_guest x29, x0, x1, x2
// Restore the guest's sp_el0
restore_sp_el0 x29, x0
// Restore guest regs x0-x17 // Restore guest regs x0-x17
ldp x0, x1, [x29, #CPU_XREG_OFFSET(0)] ldp x0, x1, [x29, #CPU_XREG_OFFSET(0)]
ldp x2, x3, [x29, #CPU_XREG_OFFSET(2)] ldp x2, x3, [x29, #CPU_XREG_OFFSET(2)]
@ -130,6 +147,9 @@ SYM_INNER_LABEL(__guest_exit, SYM_L_GLOBAL)
// Store the guest regs x18-x29, lr // Store the guest regs x18-x29, lr
save_callee_saved_regs x1 save_callee_saved_regs x1
// Store the guest's sp_el0
save_sp_el0 x1, x2
get_host_ctxt x2, x3 get_host_ctxt x2, x3
// Macro ptrauth_switch_to_guest format: // Macro ptrauth_switch_to_guest format:
@ -139,6 +159,9 @@ SYM_INNER_LABEL(__guest_exit, SYM_L_GLOBAL)
// when this feature is enabled for kernel code. // when this feature is enabled for kernel code.
ptrauth_switch_to_host x1, x2, x3, x4, x5 ptrauth_switch_to_host x1, x2, x3, x4, x5
// Restore the hosts's sp_el0
restore_sp_el0 x2, x3
// Now restore the host regs // Now restore the host regs
restore_callee_saved_regs x2 restore_callee_saved_regs x2

View File

@ -198,7 +198,6 @@ SYM_CODE_END(__hyp_panic)
.macro invalid_vector label, target = __hyp_panic .macro invalid_vector label, target = __hyp_panic
.align 2 .align 2
SYM_CODE_START(\label) SYM_CODE_START(\label)
\label:
b \target b \target
SYM_CODE_END(\label) SYM_CODE_END(\label)
.endm .endm

View File

@ -15,8 +15,9 @@
/* /*
* Non-VHE: Both host and guest must save everything. * Non-VHE: Both host and guest must save everything.
* *
* VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and pstate, * VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and
* which are handled as part of the el2 return state) on every switch. * pstate, which are handled as part of the el2 return state) on every
* switch (sp_el0 is being dealt with in the assembly code).
* tpidr_el0 and tpidrro_el0 only need to be switched when going * tpidr_el0 and tpidrro_el0 only need to be switched when going
* to host userspace or a different VCPU. EL1 registers only need to be * to host userspace or a different VCPU. EL1 registers only need to be
* switched when potentially going to run a different VCPU. The latter two * switched when potentially going to run a different VCPU. The latter two
@ -26,12 +27,6 @@
static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt) static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
{ {
ctxt->sys_regs[MDSCR_EL1] = read_sysreg(mdscr_el1); ctxt->sys_regs[MDSCR_EL1] = read_sysreg(mdscr_el1);
/*
* The host arm64 Linux uses sp_el0 to point to 'current' and it must
* therefore be saved/restored on every entry/exit to/from the guest.
*/
ctxt->gp_regs.regs.sp = read_sysreg(sp_el0);
} }
static void __hyp_text __sysreg_save_user_state(struct kvm_cpu_context *ctxt) static void __hyp_text __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
@ -99,12 +94,6 @@ NOKPROBE_SYMBOL(sysreg_save_guest_state_vhe);
static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctxt) static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctxt)
{ {
write_sysreg(ctxt->sys_regs[MDSCR_EL1], mdscr_el1); write_sysreg(ctxt->sys_regs[MDSCR_EL1], mdscr_el1);
/*
* The host arm64 Linux uses sp_el0 to point to 'current' and it must
* therefore be saved/restored on every entry/exit to/from the guest.
*/
write_sysreg(ctxt->gp_regs.regs.sp, sp_el0);
} }
static void __hyp_text __sysreg_restore_user_state(struct kvm_cpu_context *ctxt) static void __hyp_text __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)

View File

@ -230,6 +230,8 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
ptep = (pte_t *)pudp; ptep = (pte_t *)pudp;
} else if (sz == (CONT_PTE_SIZE)) { } else if (sz == (CONT_PTE_SIZE)) {
pmdp = pmd_alloc(mm, pudp, addr); pmdp = pmd_alloc(mm, pudp, addr);
if (!pmdp)
return NULL;
WARN_ON(addr & (sz - 1)); WARN_ON(addr & (sz - 1));
/* /*

View File

@ -521,6 +521,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_IOEVENTFD: case KVM_CAP_IOEVENTFD:
case KVM_CAP_DEVICE_CTRL: case KVM_CAP_DEVICE_CTRL:
case KVM_CAP_IMMEDIATE_EXIT: case KVM_CAP_IMMEDIATE_EXIT:
case KVM_CAP_SET_GUEST_DEBUG:
r = 1; r = 1;
break; break;
case KVM_CAP_PPC_GUEST_DEBUG_SSTEP: case KVM_CAP_PPC_GUEST_DEBUG_SSTEP:

View File

@ -60,7 +60,7 @@ config RISCV
select ARCH_HAS_GIGANTIC_PAGE select ARCH_HAS_GIGANTIC_PAGE
select ARCH_HAS_SET_DIRECT_MAP select ARCH_HAS_SET_DIRECT_MAP
select ARCH_HAS_SET_MEMORY select ARCH_HAS_SET_MEMORY
select ARCH_HAS_STRICT_KERNEL_RWX select ARCH_HAS_STRICT_KERNEL_RWX if MMU
select ARCH_WANT_HUGE_PMD_SHARE if 64BIT select ARCH_WANT_HUGE_PMD_SHARE if 64BIT
select SPARSEMEM_STATIC if 32BIT select SPARSEMEM_STATIC if 32BIT
select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU

View File

@ -51,13 +51,10 @@
#define CAUSE_IRQ_FLAG (_AC(1, UL) << (__riscv_xlen - 1)) #define CAUSE_IRQ_FLAG (_AC(1, UL) << (__riscv_xlen - 1))
/* Interrupt causes (minus the high bit) */ /* Interrupt causes (minus the high bit) */
#define IRQ_U_SOFT 0
#define IRQ_S_SOFT 1 #define IRQ_S_SOFT 1
#define IRQ_M_SOFT 3 #define IRQ_M_SOFT 3
#define IRQ_U_TIMER 4
#define IRQ_S_TIMER 5 #define IRQ_S_TIMER 5
#define IRQ_M_TIMER 7 #define IRQ_M_TIMER 7
#define IRQ_U_EXT 8
#define IRQ_S_EXT 9 #define IRQ_S_EXT 9
#define IRQ_M_EXT 11 #define IRQ_M_EXT 11

View File

@ -8,6 +8,7 @@
#ifndef _ASM_RISCV_HWCAP_H #ifndef _ASM_RISCV_HWCAP_H
#define _ASM_RISCV_HWCAP_H #define _ASM_RISCV_HWCAP_H
#include <linux/bits.h>
#include <uapi/asm/hwcap.h> #include <uapi/asm/hwcap.h>
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
@ -22,6 +23,27 @@ enum {
}; };
extern unsigned long elf_hwcap; extern unsigned long elf_hwcap;
#define RISCV_ISA_EXT_a ('a' - 'a')
#define RISCV_ISA_EXT_c ('c' - 'a')
#define RISCV_ISA_EXT_d ('d' - 'a')
#define RISCV_ISA_EXT_f ('f' - 'a')
#define RISCV_ISA_EXT_h ('h' - 'a')
#define RISCV_ISA_EXT_i ('i' - 'a')
#define RISCV_ISA_EXT_m ('m' - 'a')
#define RISCV_ISA_EXT_s ('s' - 'a')
#define RISCV_ISA_EXT_u ('u' - 'a')
#define RISCV_ISA_EXT_MAX 64
unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap);
#define riscv_isa_extension_mask(ext) BIT_MASK(RISCV_ISA_EXT_##ext)
bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit);
#define riscv_isa_extension_available(isa_bitmap, ext) \
__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext)
#endif #endif
#endif /* _ASM_RISCV_HWCAP_H */ #endif /* _ASM_RISCV_HWCAP_H */

View File

@ -22,14 +22,6 @@ static inline int set_memory_x(unsigned long addr, int numpages) { return 0; }
static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; } static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; }
#endif #endif
#ifdef CONFIG_STRICT_KERNEL_RWX
void set_kernel_text_ro(void);
void set_kernel_text_rw(void);
#else
static inline void set_kernel_text_ro(void) { }
static inline void set_kernel_text_rw(void) { }
#endif
int set_direct_map_invalid_noflush(struct page *page); int set_direct_map_invalid_noflush(struct page *page);
int set_direct_map_default_noflush(struct page *page); int set_direct_map_default_noflush(struct page *page);

View File

@ -15,8 +15,8 @@
const struct cpu_operations *cpu_ops[NR_CPUS] __ro_after_init; const struct cpu_operations *cpu_ops[NR_CPUS] __ro_after_init;
void *__cpu_up_stack_pointer[NR_CPUS]; void *__cpu_up_stack_pointer[NR_CPUS] __section(.data);
void *__cpu_up_task_pointer[NR_CPUS]; void *__cpu_up_task_pointer[NR_CPUS] __section(.data);
extern const struct cpu_operations cpu_ops_sbi; extern const struct cpu_operations cpu_ops_sbi;
extern const struct cpu_operations cpu_ops_spinwait; extern const struct cpu_operations cpu_ops_spinwait;

View File

@ -6,6 +6,7 @@
* Copyright (C) 2017 SiFive * Copyright (C) 2017 SiFive
*/ */
#include <linux/bitmap.h>
#include <linux/of.h> #include <linux/of.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/hwcap.h> #include <asm/hwcap.h>
@ -13,15 +14,57 @@
#include <asm/switch_to.h> #include <asm/switch_to.h>
unsigned long elf_hwcap __read_mostly; unsigned long elf_hwcap __read_mostly;
/* Host ISA bitmap */
static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
#ifdef CONFIG_FPU #ifdef CONFIG_FPU
bool has_fpu __read_mostly; bool has_fpu __read_mostly;
#endif #endif
/**
* riscv_isa_extension_base() - Get base extension word
*
* @isa_bitmap: ISA bitmap to use
* Return: base extension word as unsigned long value
*
* NOTE: If isa_bitmap is NULL then Host ISA bitmap will be used.
*/
unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap)
{
if (!isa_bitmap)
return riscv_isa[0];
return isa_bitmap[0];
}
EXPORT_SYMBOL_GPL(riscv_isa_extension_base);
/**
* __riscv_isa_extension_available() - Check whether given extension
* is available or not
*
* @isa_bitmap: ISA bitmap to use
* @bit: bit position of the desired extension
* Return: true or false
*
* NOTE: If isa_bitmap is NULL then Host ISA bitmap will be used.
*/
bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
{
const unsigned long *bmap = (isa_bitmap) ? isa_bitmap : riscv_isa;
if (bit >= RISCV_ISA_EXT_MAX)
return false;
return test_bit(bit, bmap) ? true : false;
}
EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
void riscv_fill_hwcap(void) void riscv_fill_hwcap(void)
{ {
struct device_node *node; struct device_node *node;
const char *isa; const char *isa;
size_t i; char print_str[BITS_PER_LONG + 1];
size_t i, j, isa_len;
static unsigned long isa2hwcap[256] = {0}; static unsigned long isa2hwcap[256] = {0};
isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I; isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I;
@ -33,8 +76,11 @@ void riscv_fill_hwcap(void)
elf_hwcap = 0; elf_hwcap = 0;
bitmap_zero(riscv_isa, RISCV_ISA_EXT_MAX);
for_each_of_cpu_node(node) { for_each_of_cpu_node(node) {
unsigned long this_hwcap = 0; unsigned long this_hwcap = 0;
unsigned long this_isa = 0;
if (riscv_of_processor_hartid(node) < 0) if (riscv_of_processor_hartid(node) < 0)
continue; continue;
@ -44,8 +90,24 @@ void riscv_fill_hwcap(void)
continue; continue;
} }
for (i = 0; i < strlen(isa); ++i) i = 0;
isa_len = strlen(isa);
#if IS_ENABLED(CONFIG_32BIT)
if (!strncmp(isa, "rv32", 4))
i += 4;
#elif IS_ENABLED(CONFIG_64BIT)
if (!strncmp(isa, "rv64", 4))
i += 4;
#endif
for (; i < isa_len; ++i) {
this_hwcap |= isa2hwcap[(unsigned char)(isa[i])]; this_hwcap |= isa2hwcap[(unsigned char)(isa[i])];
/*
* TODO: X, Y and Z extension parsing for Host ISA
* bitmap will be added in-future.
*/
if ('a' <= isa[i] && isa[i] < 'x')
this_isa |= (1UL << (isa[i] - 'a'));
}
/* /*
* All "okay" hart should have same isa. Set HWCAP based on * All "okay" hart should have same isa. Set HWCAP based on
@ -56,6 +118,11 @@ void riscv_fill_hwcap(void)
elf_hwcap &= this_hwcap; elf_hwcap &= this_hwcap;
else else
elf_hwcap = this_hwcap; elf_hwcap = this_hwcap;
if (riscv_isa[0])
riscv_isa[0] &= this_isa;
else
riscv_isa[0] = this_isa;
} }
/* We don't support systems with F but without D, so mask those out /* We don't support systems with F but without D, so mask those out
@ -65,7 +132,17 @@ void riscv_fill_hwcap(void)
elf_hwcap &= ~COMPAT_HWCAP_ISA_F; elf_hwcap &= ~COMPAT_HWCAP_ISA_F;
} }
pr_info("elf_hwcap is 0x%lx\n", elf_hwcap); memset(print_str, 0, sizeof(print_str));
for (i = 0, j = 0; i < BITS_PER_LONG; i++)
if (riscv_isa[0] & BIT_MASK(i))
print_str[j++] = (char)('a' + i);
pr_info("riscv: ISA extensions %s\n", print_str);
memset(print_str, 0, sizeof(print_str));
for (i = 0, j = 0; i < BITS_PER_LONG; i++)
if (elf_hwcap & BIT_MASK(i))
print_str[j++] = (char)('a' + i);
pr_info("riscv: ELF capabilities %s\n", print_str);
#ifdef CONFIG_FPU #ifdef CONFIG_FPU
if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)) if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))

View File

@ -102,7 +102,7 @@ void sbi_shutdown(void)
{ {
sbi_ecall(SBI_EXT_0_1_SHUTDOWN, 0, 0, 0, 0, 0, 0, 0); sbi_ecall(SBI_EXT_0_1_SHUTDOWN, 0, 0, 0, 0, 0, 0, 0);
} }
EXPORT_SYMBOL(sbi_set_timer); EXPORT_SYMBOL(sbi_shutdown);
/** /**
* sbi_clear_ipi() - Clear any pending IPIs for the calling hart. * sbi_clear_ipi() - Clear any pending IPIs for the calling hart.
@ -113,7 +113,7 @@ void sbi_clear_ipi(void)
{ {
sbi_ecall(SBI_EXT_0_1_CLEAR_IPI, 0, 0, 0, 0, 0, 0, 0); sbi_ecall(SBI_EXT_0_1_CLEAR_IPI, 0, 0, 0, 0, 0, 0, 0);
} }
EXPORT_SYMBOL(sbi_shutdown); EXPORT_SYMBOL(sbi_clear_ipi);
/** /**
* sbi_set_timer_v01() - Program the timer for next timer event. * sbi_set_timer_v01() - Program the timer for next timer event.
@ -167,6 +167,11 @@ static int __sbi_rfence_v01(int fid, const unsigned long *hart_mask,
return result; return result;
} }
static void sbi_set_power_off(void)
{
pm_power_off = sbi_shutdown;
}
#else #else
static void __sbi_set_timer_v01(uint64_t stime_value) static void __sbi_set_timer_v01(uint64_t stime_value)
{ {
@ -191,6 +196,8 @@ static int __sbi_rfence_v01(int fid, const unsigned long *hart_mask,
return 0; return 0;
} }
static void sbi_set_power_off(void) {}
#endif /* CONFIG_RISCV_SBI_V01 */ #endif /* CONFIG_RISCV_SBI_V01 */
static void __sbi_set_timer_v02(uint64_t stime_value) static void __sbi_set_timer_v02(uint64_t stime_value)
@ -540,16 +547,12 @@ static inline long sbi_get_firmware_version(void)
return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_VERSION); return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_VERSION);
} }
static void sbi_power_off(void)
{
sbi_shutdown();
}
int __init sbi_init(void) int __init sbi_init(void)
{ {
int ret; int ret;
pm_power_off = sbi_power_off; sbi_set_power_off();
ret = sbi_get_spec_version(); ret = sbi_get_spec_version();
if (ret > 0) if (ret > 0)
sbi_spec_version = ret; sbi_spec_version = ret;

View File

@ -10,6 +10,7 @@
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/profile.h> #include <linux/profile.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/sched.h> #include <linux/sched.h>
@ -63,6 +64,7 @@ void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out)
for_each_cpu(cpu, in) for_each_cpu(cpu, in)
cpumask_set_cpu(cpuid_to_hartid_map(cpu), out); cpumask_set_cpu(cpuid_to_hartid_map(cpu), out);
} }
EXPORT_SYMBOL_GPL(riscv_cpuid_to_hartid_mask);
bool arch_match_cpu_phys_id(int cpu, u64 phys_id) bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
{ {

View File

@ -12,6 +12,8 @@
#include <linux/stacktrace.h> #include <linux/stacktrace.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
register unsigned long sp_in_global __asm__("sp");
#ifdef CONFIG_FRAME_POINTER #ifdef CONFIG_FRAME_POINTER
struct stackframe { struct stackframe {
@ -19,8 +21,6 @@ struct stackframe {
unsigned long ra; unsigned long ra;
}; };
register unsigned long sp_in_global __asm__("sp");
void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
bool (*fn)(unsigned long, void *), void *arg) bool (*fn)(unsigned long, void *), void *arg)
{ {

View File

@ -12,7 +12,7 @@ vdso-syms += getcpu
vdso-syms += flush_icache vdso-syms += flush_icache
# Files to link into the vdso # Files to link into the vdso
obj-vdso = $(patsubst %, %.o, $(vdso-syms)) obj-vdso = $(patsubst %, %.o, $(vdso-syms)) note.o
# Build rules # Build rules
targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds vdso-dummy.o targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds vdso-dummy.o
@ -33,15 +33,15 @@ $(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) FORCE
$(call if_changed,vdsold) $(call if_changed,vdsold)
# We also create a special relocatable object that should mirror the symbol # We also create a special relocatable object that should mirror the symbol
# table and layout of the linked DSO. With ld -R we can then refer to # table and layout of the linked DSO. With ld --just-symbols we can then
# these symbols in the kernel code rather than hand-coded addresses. # refer to these symbols in the kernel code rather than hand-coded addresses.
SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \ SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \
-Wl,--build-id -Wl,--hash-style=both -Wl,--build-id -Wl,--hash-style=both
$(obj)/vdso-dummy.o: $(src)/vdso.lds $(obj)/rt_sigreturn.o FORCE $(obj)/vdso-dummy.o: $(src)/vdso.lds $(obj)/rt_sigreturn.o FORCE
$(call if_changed,vdsold) $(call if_changed,vdsold)
LDFLAGS_vdso-syms.o := -r -R LDFLAGS_vdso-syms.o := -r --just-symbols
$(obj)/vdso-syms.o: $(obj)/vdso-dummy.o FORCE $(obj)/vdso-syms.o: $(obj)/vdso-dummy.o FORCE
$(call if_changed,ld) $(call if_changed,ld)

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
* Here we can supply some information useful to userland.
*/
#include <linux/elfnote.h>
#include <linux/version.h>
ELFNOTE_START(Linux, 0, "a")
.long LINUX_VERSION_CODE
ELFNOTE_END

View File

@ -150,7 +150,8 @@ void __init setup_bootmem(void)
memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start); memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start);
set_max_mapnr(PFN_DOWN(mem_size)); set_max_mapnr(PFN_DOWN(mem_size));
max_low_pfn = PFN_DOWN(memblock_end_of_DRAM()); max_pfn = PFN_DOWN(memblock_end_of_DRAM());
max_low_pfn = max_pfn;
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
setup_initrd(); setup_initrd();
@ -501,22 +502,6 @@ static inline void setup_vm_final(void)
#endif /* CONFIG_MMU */ #endif /* CONFIG_MMU */
#ifdef CONFIG_STRICT_KERNEL_RWX #ifdef CONFIG_STRICT_KERNEL_RWX
void set_kernel_text_rw(void)
{
unsigned long text_start = (unsigned long)_text;
unsigned long text_end = (unsigned long)_etext;
set_memory_rw(text_start, (text_end - text_start) >> PAGE_SHIFT);
}
void set_kernel_text_ro(void)
{
unsigned long text_start = (unsigned long)_text;
unsigned long text_end = (unsigned long)_etext;
set_memory_ro(text_start, (text_end - text_start) >> PAGE_SHIFT);
}
void mark_rodata_ro(void) void mark_rodata_ro(void)
{ {
unsigned long text_start = (unsigned long)_text; unsigned long text_start = (unsigned long)_text;

View File

@ -545,6 +545,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_S390_AIS: case KVM_CAP_S390_AIS:
case KVM_CAP_S390_AIS_MIGRATION: case KVM_CAP_S390_AIS_MIGRATION:
case KVM_CAP_S390_VCPU_RESETS: case KVM_CAP_S390_VCPU_RESETS:
case KVM_CAP_SET_GUEST_DEBUG:
r = 1; r = 1;
break; break;
case KVM_CAP_S390_HPAGE_1M: case KVM_CAP_S390_HPAGE_1M:

View File

@ -626,10 +626,12 @@ static int handle_pqap(struct kvm_vcpu *vcpu)
* available for the guest are AQIC and TAPQ with the t bit set * available for the guest are AQIC and TAPQ with the t bit set
* since we do not set IC.3 (FIII) we currently will only intercept * since we do not set IC.3 (FIII) we currently will only intercept
* the AQIC function code. * the AQIC function code.
* Note: running nested under z/VM can result in intercepts for other
* function codes, e.g. PQAP(QCI). We do not support this and bail out.
*/ */
reg0 = vcpu->run->s.regs.gprs[0]; reg0 = vcpu->run->s.regs.gprs[0];
fc = (reg0 >> 24) & 0xff; fc = (reg0 >> 24) & 0xff;
if (WARN_ON_ONCE(fc != 0x03)) if (fc != 0x03)
return -EOPNOTSUPP; return -EOPNOTSUPP;
/* PQAP instruction is allowed for guest kernel only */ /* PQAP instruction is allowed for guest kernel only */

View File

@ -64,10 +64,13 @@ mm_segment_t enable_sacf_uaccess(void)
{ {
mm_segment_t old_fs; mm_segment_t old_fs;
unsigned long asce, cr; unsigned long asce, cr;
unsigned long flags;
old_fs = current->thread.mm_segment; old_fs = current->thread.mm_segment;
if (old_fs & 1) if (old_fs & 1)
return old_fs; return old_fs;
/* protect against a concurrent page table upgrade */
local_irq_save(flags);
current->thread.mm_segment |= 1; current->thread.mm_segment |= 1;
asce = S390_lowcore.kernel_asce; asce = S390_lowcore.kernel_asce;
if (likely(old_fs == USER_DS)) { if (likely(old_fs == USER_DS)) {
@ -83,6 +86,7 @@ mm_segment_t enable_sacf_uaccess(void)
__ctl_load(asce, 7, 7); __ctl_load(asce, 7, 7);
set_cpu_flag(CIF_ASCE_SECONDARY); set_cpu_flag(CIF_ASCE_SECONDARY);
} }
local_irq_restore(flags);
return old_fs; return old_fs;
} }
EXPORT_SYMBOL(enable_sacf_uaccess); EXPORT_SYMBOL(enable_sacf_uaccess);

View File

@ -70,8 +70,20 @@ static void __crst_table_upgrade(void *arg)
{ {
struct mm_struct *mm = arg; struct mm_struct *mm = arg;
if (current->active_mm == mm) /* we must change all active ASCEs to avoid the creation of new TLBs */
set_user_asce(mm); if (current->active_mm == mm) {
S390_lowcore.user_asce = mm->context.asce;
if (current->thread.mm_segment == USER_DS) {
__ctl_load(S390_lowcore.user_asce, 1, 1);
/* Mark user-ASCE present in CR1 */
clear_cpu_flag(CIF_ASCE_PRIMARY);
}
if (current->thread.mm_segment == USER_DS_SACF) {
__ctl_load(S390_lowcore.user_asce, 7, 7);
/* enable_sacf_uaccess does all or nothing */
WARN_ON(!test_cpu_flag(CIF_ASCE_SECONDARY));
}
}
__tlb_flush_local(); __tlb_flush_local();
} }

View File

@ -32,16 +32,16 @@ void blake2s_compress_arch(struct blake2s_state *state,
const u32 inc) const u32 inc)
{ {
/* SIMD disables preemption, so relax after processing each page. */ /* SIMD disables preemption, so relax after processing each page. */
BUILD_BUG_ON(PAGE_SIZE / BLAKE2S_BLOCK_SIZE < 8); BUILD_BUG_ON(SZ_4K / BLAKE2S_BLOCK_SIZE < 8);
if (!static_branch_likely(&blake2s_use_ssse3) || !crypto_simd_usable()) { if (!static_branch_likely(&blake2s_use_ssse3) || !crypto_simd_usable()) {
blake2s_compress_generic(state, block, nblocks, inc); blake2s_compress_generic(state, block, nblocks, inc);
return; return;
} }
for (;;) { do {
const size_t blocks = min_t(size_t, nblocks, const size_t blocks = min_t(size_t, nblocks,
PAGE_SIZE / BLAKE2S_BLOCK_SIZE); SZ_4K / BLAKE2S_BLOCK_SIZE);
kernel_fpu_begin(); kernel_fpu_begin();
if (IS_ENABLED(CONFIG_AS_AVX512) && if (IS_ENABLED(CONFIG_AS_AVX512) &&
@ -52,10 +52,8 @@ void blake2s_compress_arch(struct blake2s_state *state,
kernel_fpu_end(); kernel_fpu_end();
nblocks -= blocks; nblocks -= blocks;
if (!nblocks)
break;
block += blocks * BLAKE2S_BLOCK_SIZE; block += blocks * BLAKE2S_BLOCK_SIZE;
} } while (nblocks);
} }
EXPORT_SYMBOL(blake2s_compress_arch); EXPORT_SYMBOL(blake2s_compress_arch);

View File

@ -153,9 +153,17 @@ void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes,
bytes <= CHACHA_BLOCK_SIZE) bytes <= CHACHA_BLOCK_SIZE)
return chacha_crypt_generic(state, dst, src, bytes, nrounds); return chacha_crypt_generic(state, dst, src, bytes, nrounds);
kernel_fpu_begin(); do {
chacha_dosimd(state, dst, src, bytes, nrounds); unsigned int todo = min_t(unsigned int, bytes, SZ_4K);
kernel_fpu_end();
kernel_fpu_begin();
chacha_dosimd(state, dst, src, todo, nrounds);
kernel_fpu_end();
bytes -= todo;
src += todo;
dst += todo;
} while (bytes);
} }
EXPORT_SYMBOL(chacha_crypt_arch); EXPORT_SYMBOL(chacha_crypt_arch);

View File

@ -29,7 +29,7 @@ static int nhpoly1305_avx2_update(struct shash_desc *desc,
return crypto_nhpoly1305_update(desc, src, srclen); return crypto_nhpoly1305_update(desc, src, srclen);
do { do {
unsigned int n = min_t(unsigned int, srclen, PAGE_SIZE); unsigned int n = min_t(unsigned int, srclen, SZ_4K);
kernel_fpu_begin(); kernel_fpu_begin();
crypto_nhpoly1305_update_helper(desc, src, n, _nh_avx2); crypto_nhpoly1305_update_helper(desc, src, n, _nh_avx2);

View File

@ -29,7 +29,7 @@ static int nhpoly1305_sse2_update(struct shash_desc *desc,
return crypto_nhpoly1305_update(desc, src, srclen); return crypto_nhpoly1305_update(desc, src, srclen);
do { do {
unsigned int n = min_t(unsigned int, srclen, PAGE_SIZE); unsigned int n = min_t(unsigned int, srclen, SZ_4K);
kernel_fpu_begin(); kernel_fpu_begin();
crypto_nhpoly1305_update_helper(desc, src, n, _nh_sse2); crypto_nhpoly1305_update_helper(desc, src, n, _nh_sse2);

View File

@ -91,8 +91,8 @@ static void poly1305_simd_blocks(void *ctx, const u8 *inp, size_t len,
struct poly1305_arch_internal *state = ctx; struct poly1305_arch_internal *state = ctx;
/* SIMD disables preemption, so relax after processing each page. */ /* SIMD disables preemption, so relax after processing each page. */
BUILD_BUG_ON(PAGE_SIZE < POLY1305_BLOCK_SIZE || BUILD_BUG_ON(SZ_4K < POLY1305_BLOCK_SIZE ||
PAGE_SIZE % POLY1305_BLOCK_SIZE); SZ_4K % POLY1305_BLOCK_SIZE);
if (!static_branch_likely(&poly1305_use_avx) || if (!static_branch_likely(&poly1305_use_avx) ||
(len < (POLY1305_BLOCK_SIZE * 18) && !state->is_base2_26) || (len < (POLY1305_BLOCK_SIZE * 18) && !state->is_base2_26) ||
@ -102,8 +102,8 @@ static void poly1305_simd_blocks(void *ctx, const u8 *inp, size_t len,
return; return;
} }
for (;;) { do {
const size_t bytes = min_t(size_t, len, PAGE_SIZE); const size_t bytes = min_t(size_t, len, SZ_4K);
kernel_fpu_begin(); kernel_fpu_begin();
if (IS_ENABLED(CONFIG_AS_AVX512) && static_branch_likely(&poly1305_use_avx512)) if (IS_ENABLED(CONFIG_AS_AVX512) && static_branch_likely(&poly1305_use_avx512))
@ -113,11 +113,10 @@ static void poly1305_simd_blocks(void *ctx, const u8 *inp, size_t len,
else else
poly1305_blocks_avx(ctx, inp, bytes, padbit); poly1305_blocks_avx(ctx, inp, bytes, padbit);
kernel_fpu_end(); kernel_fpu_end();
len -= bytes; len -= bytes;
if (!len)
break;
inp += bytes; inp += bytes;
} } while (len);
} }
static void poly1305_simd_emit(void *ctx, u8 mac[POLY1305_DIGEST_SIZE], static void poly1305_simd_emit(void *ctx, u8 mac[POLY1305_DIGEST_SIZE],

View File

@ -98,13 +98,6 @@ For 32-bit we have the following conventions - kernel is built with
#define SIZEOF_PTREGS 21*8 #define SIZEOF_PTREGS 21*8
.macro PUSH_AND_CLEAR_REGS rdx=%rdx rax=%rax save_ret=0 .macro PUSH_AND_CLEAR_REGS rdx=%rdx rax=%rax save_ret=0
/*
* Push registers and sanitize registers of values that a
* speculation attack might otherwise want to exploit. The
* lower registers are likely clobbered well before they
* could be put to use in a speculative execution gadget.
* Interleave XOR with PUSH for better uop scheduling:
*/
.if \save_ret .if \save_ret
pushq %rsi /* pt_regs->si */ pushq %rsi /* pt_regs->si */
movq 8(%rsp), %rsi /* temporarily store the return address in %rsi */ movq 8(%rsp), %rsi /* temporarily store the return address in %rsi */
@ -114,34 +107,43 @@ For 32-bit we have the following conventions - kernel is built with
pushq %rsi /* pt_regs->si */ pushq %rsi /* pt_regs->si */
.endif .endif
pushq \rdx /* pt_regs->dx */ pushq \rdx /* pt_regs->dx */
xorl %edx, %edx /* nospec dx */
pushq %rcx /* pt_regs->cx */ pushq %rcx /* pt_regs->cx */
xorl %ecx, %ecx /* nospec cx */
pushq \rax /* pt_regs->ax */ pushq \rax /* pt_regs->ax */
pushq %r8 /* pt_regs->r8 */ pushq %r8 /* pt_regs->r8 */
xorl %r8d, %r8d /* nospec r8 */
pushq %r9 /* pt_regs->r9 */ pushq %r9 /* pt_regs->r9 */
xorl %r9d, %r9d /* nospec r9 */
pushq %r10 /* pt_regs->r10 */ pushq %r10 /* pt_regs->r10 */
xorl %r10d, %r10d /* nospec r10 */
pushq %r11 /* pt_regs->r11 */ pushq %r11 /* pt_regs->r11 */
xorl %r11d, %r11d /* nospec r11*/
pushq %rbx /* pt_regs->rbx */ pushq %rbx /* pt_regs->rbx */
xorl %ebx, %ebx /* nospec rbx*/
pushq %rbp /* pt_regs->rbp */ pushq %rbp /* pt_regs->rbp */
xorl %ebp, %ebp /* nospec rbp*/
pushq %r12 /* pt_regs->r12 */ pushq %r12 /* pt_regs->r12 */
xorl %r12d, %r12d /* nospec r12*/
pushq %r13 /* pt_regs->r13 */ pushq %r13 /* pt_regs->r13 */
xorl %r13d, %r13d /* nospec r13*/
pushq %r14 /* pt_regs->r14 */ pushq %r14 /* pt_regs->r14 */
xorl %r14d, %r14d /* nospec r14*/
pushq %r15 /* pt_regs->r15 */ pushq %r15 /* pt_regs->r15 */
xorl %r15d, %r15d /* nospec r15*/
UNWIND_HINT_REGS UNWIND_HINT_REGS
.if \save_ret .if \save_ret
pushq %rsi /* return address on top of stack */ pushq %rsi /* return address on top of stack */
.endif .endif
/*
* Sanitize registers of values that a speculation attack might
* otherwise want to exploit. The lower registers are likely clobbered
* well before they could be put to use in a speculative execution
* gadget.
*/
xorl %edx, %edx /* nospec dx */
xorl %ecx, %ecx /* nospec cx */
xorl %r8d, %r8d /* nospec r8 */
xorl %r9d, %r9d /* nospec r9 */
xorl %r10d, %r10d /* nospec r10 */
xorl %r11d, %r11d /* nospec r11 */
xorl %ebx, %ebx /* nospec rbx */
xorl %ebp, %ebp /* nospec rbp */
xorl %r12d, %r12d /* nospec r12 */
xorl %r13d, %r13d /* nospec r13 */
xorl %r14d, %r14d /* nospec r14 */
xorl %r15d, %r15d /* nospec r15 */
.endm .endm
.macro POP_REGS pop_rdi=1 skip_r11rcx=0 .macro POP_REGS pop_rdi=1 skip_r11rcx=0

View File

@ -249,7 +249,6 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
*/ */
syscall_return_via_sysret: syscall_return_via_sysret:
/* rcx and r11 are already restored (see code above) */ /* rcx and r11 are already restored (see code above) */
UNWIND_HINT_EMPTY
POP_REGS pop_rdi=0 skip_r11rcx=1 POP_REGS pop_rdi=0 skip_r11rcx=1
/* /*
@ -258,6 +257,7 @@ syscall_return_via_sysret:
*/ */
movq %rsp, %rdi movq %rsp, %rdi
movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp
UNWIND_HINT_EMPTY
pushq RSP-RDI(%rdi) /* RSP */ pushq RSP-RDI(%rdi) /* RSP */
pushq (%rdi) /* RDI */ pushq (%rdi) /* RDI */
@ -279,8 +279,7 @@ SYM_CODE_END(entry_SYSCALL_64)
* %rdi: prev task * %rdi: prev task
* %rsi: next task * %rsi: next task
*/ */
SYM_CODE_START(__switch_to_asm) SYM_FUNC_START(__switch_to_asm)
UNWIND_HINT_FUNC
/* /*
* Save callee-saved registers * Save callee-saved registers
* This must match the order in inactive_task_frame * This must match the order in inactive_task_frame
@ -321,7 +320,7 @@ SYM_CODE_START(__switch_to_asm)
popq %rbp popq %rbp
jmp __switch_to jmp __switch_to
SYM_CODE_END(__switch_to_asm) SYM_FUNC_END(__switch_to_asm)
/* /*
* A newly forked process directly context switches into this address. * A newly forked process directly context switches into this address.
@ -512,7 +511,7 @@ SYM_CODE_END(spurious_entries_start)
* +----------------------------------------------------+ * +----------------------------------------------------+
*/ */
SYM_CODE_START(interrupt_entry) SYM_CODE_START(interrupt_entry)
UNWIND_HINT_FUNC UNWIND_HINT_IRET_REGS offset=16
ASM_CLAC ASM_CLAC
cld cld
@ -544,9 +543,9 @@ SYM_CODE_START(interrupt_entry)
pushq 5*8(%rdi) /* regs->eflags */ pushq 5*8(%rdi) /* regs->eflags */
pushq 4*8(%rdi) /* regs->cs */ pushq 4*8(%rdi) /* regs->cs */
pushq 3*8(%rdi) /* regs->ip */ pushq 3*8(%rdi) /* regs->ip */
UNWIND_HINT_IRET_REGS
pushq 2*8(%rdi) /* regs->orig_ax */ pushq 2*8(%rdi) /* regs->orig_ax */
pushq 8(%rdi) /* return address */ pushq 8(%rdi) /* return address */
UNWIND_HINT_FUNC
movq (%rdi), %rdi movq (%rdi), %rdi
jmp 2f jmp 2f
@ -637,6 +636,7 @@ SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
*/ */
movq %rsp, %rdi movq %rsp, %rdi
movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp
UNWIND_HINT_EMPTY
/* Copy the IRET frame to the trampoline stack. */ /* Copy the IRET frame to the trampoline stack. */
pushq 6*8(%rdi) /* SS */ pushq 6*8(%rdi) /* SS */
@ -1739,7 +1739,7 @@ SYM_CODE_START(rewind_stack_do_exit)
movq PER_CPU_VAR(cpu_current_top_of_stack), %rax movq PER_CPU_VAR(cpu_current_top_of_stack), %rax
leaq -PTREGS_SIZE(%rax), %rsp leaq -PTREGS_SIZE(%rax), %rsp
UNWIND_HINT_FUNC sp_offset=PTREGS_SIZE UNWIND_HINT_REGS
call do_exit call do_exit
SYM_CODE_END(rewind_stack_do_exit) SYM_CODE_END(rewind_stack_do_exit)

View File

@ -73,7 +73,8 @@ static int hv_cpu_init(unsigned int cpu)
struct page *pg; struct page *pg;
input_arg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg); input_arg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
pg = alloc_page(GFP_KERNEL); /* hv_cpu_init() can be called with IRQs disabled from hv_resume() */
pg = alloc_page(irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
if (unlikely(!pg)) if (unlikely(!pg))
return -ENOMEM; return -ENOMEM;
*input_arg = page_address(pg); *input_arg = page_address(pg);
@ -254,6 +255,7 @@ static int __init hv_pci_init(void)
static int hv_suspend(void) static int hv_suspend(void)
{ {
union hv_x64_msr_hypercall_contents hypercall_msr; union hv_x64_msr_hypercall_contents hypercall_msr;
int ret;
/* /*
* Reset the hypercall page as it is going to be invalidated * Reset the hypercall page as it is going to be invalidated
@ -270,12 +272,17 @@ static int hv_suspend(void)
hypercall_msr.enable = 0; hypercall_msr.enable = 0;
wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
return 0; ret = hv_cpu_die(0);
return ret;
} }
static void hv_resume(void) static void hv_resume(void)
{ {
union hv_x64_msr_hypercall_contents hypercall_msr; union hv_x64_msr_hypercall_contents hypercall_msr;
int ret;
ret = hv_cpu_init(0);
WARN_ON(ret);
/* Re-enable the hypercall page */ /* Re-enable the hypercall page */
rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
@ -288,6 +295,7 @@ static void hv_resume(void)
hv_hypercall_pg_saved = NULL; hv_hypercall_pg_saved = NULL;
} }
/* Note: when the ops are called, only CPU0 is online and IRQs are disabled. */
static struct syscore_ops hv_syscore_ops = { static struct syscore_ops hv_syscore_ops = {
.suspend = hv_suspend, .suspend = hv_suspend,
.resume = hv_resume, .resume = hv_resume,

View File

@ -61,11 +61,12 @@ static inline bool arch_syscall_match_sym_name(const char *sym, const char *name
{ {
/* /*
* Compare the symbol name with the system call name. Skip the * Compare the symbol name with the system call name. Skip the
* "__x64_sys", "__ia32_sys" or simple "sys" prefix. * "__x64_sys", "__ia32_sys", "__do_sys" or simple "sys" prefix.
*/ */
return !strcmp(sym + 3, name + 3) || return !strcmp(sym + 3, name + 3) ||
(!strncmp(sym, "__x64_", 6) && !strcmp(sym + 9, name + 3)) || (!strncmp(sym, "__x64_", 6) && !strcmp(sym + 9, name + 3)) ||
(!strncmp(sym, "__ia32_", 7) && !strcmp(sym + 10, name + 3)); (!strncmp(sym, "__ia32_", 7) && !strcmp(sym + 10, name + 3)) ||
(!strncmp(sym, "__do_sys", 8) && !strcmp(sym + 8, name + 3));
} }
#ifndef COMPILE_OFFSETS #ifndef COMPILE_OFFSETS

View File

@ -1663,8 +1663,8 @@ void kvm_set_msi_irq(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e,
static inline bool kvm_irq_is_postable(struct kvm_lapic_irq *irq) static inline bool kvm_irq_is_postable(struct kvm_lapic_irq *irq)
{ {
/* We can only post Fixed and LowPrio IRQs */ /* We can only post Fixed and LowPrio IRQs */
return (irq->delivery_mode == dest_Fixed || return (irq->delivery_mode == APIC_DM_FIXED ||
irq->delivery_mode == dest_LowestPrio); irq->delivery_mode == APIC_DM_LOWEST);
} }
static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)

View File

@ -35,6 +35,8 @@ typedef int (*hyperv_fill_flush_list_func)(
rdmsrl(HV_X64_MSR_SINT0 + int_num, val) rdmsrl(HV_X64_MSR_SINT0 + int_num, val)
#define hv_set_synint_state(int_num, val) \ #define hv_set_synint_state(int_num, val) \
wrmsrl(HV_X64_MSR_SINT0 + int_num, val) wrmsrl(HV_X64_MSR_SINT0 + int_num, val)
#define hv_recommend_using_aeoi() \
(!(ms_hyperv.hints & HV_DEPRECATING_AEOI_RECOMMENDED))
#define hv_get_crash_ctl(val) \ #define hv_get_crash_ctl(val) \
rdmsrl(HV_X64_MSR_CRASH_CTL, val) rdmsrl(HV_X64_MSR_CRASH_CTL, val)

View File

@ -19,7 +19,7 @@ struct unwind_state {
#if defined(CONFIG_UNWINDER_ORC) #if defined(CONFIG_UNWINDER_ORC)
bool signal, full_regs; bool signal, full_regs;
unsigned long sp, bp, ip; unsigned long sp, bp, ip;
struct pt_regs *regs; struct pt_regs *regs, *prev_regs;
#elif defined(CONFIG_UNWINDER_FRAME_POINTER) #elif defined(CONFIG_UNWINDER_FRAME_POINTER)
bool got_irq; bool got_irq;
unsigned long *bp, *orig_sp, ip; unsigned long *bp, *orig_sp, ip;

View File

@ -352,8 +352,6 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
* According to Intel, MFENCE can do the serialization here. * According to Intel, MFENCE can do the serialization here.
*/ */
asm volatile("mfence" : : : "memory"); asm volatile("mfence" : : : "memory");
printk_once(KERN_DEBUG "TSC deadline timer enabled\n");
return; return;
} }
@ -546,7 +544,7 @@ static struct clock_event_device lapic_clockevent = {
}; };
static DEFINE_PER_CPU(struct clock_event_device, lapic_events); static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
static u32 hsx_deadline_rev(void) static __init u32 hsx_deadline_rev(void)
{ {
switch (boot_cpu_data.x86_stepping) { switch (boot_cpu_data.x86_stepping) {
case 0x02: return 0x3a; /* EP */ case 0x02: return 0x3a; /* EP */
@ -556,7 +554,7 @@ static u32 hsx_deadline_rev(void)
return ~0U; return ~0U;
} }
static u32 bdx_deadline_rev(void) static __init u32 bdx_deadline_rev(void)
{ {
switch (boot_cpu_data.x86_stepping) { switch (boot_cpu_data.x86_stepping) {
case 0x02: return 0x00000011; case 0x02: return 0x00000011;
@ -568,7 +566,7 @@ static u32 bdx_deadline_rev(void)
return ~0U; return ~0U;
} }
static u32 skx_deadline_rev(void) static __init u32 skx_deadline_rev(void)
{ {
switch (boot_cpu_data.x86_stepping) { switch (boot_cpu_data.x86_stepping) {
case 0x03: return 0x01000136; case 0x03: return 0x01000136;
@ -581,7 +579,7 @@ static u32 skx_deadline_rev(void)
return ~0U; return ~0U;
} }
static const struct x86_cpu_id deadline_match[] = { static const struct x86_cpu_id deadline_match[] __initconst = {
X86_MATCH_INTEL_FAM6_MODEL( HASWELL_X, &hsx_deadline_rev), X86_MATCH_INTEL_FAM6_MODEL( HASWELL_X, &hsx_deadline_rev),
X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_X, 0x0b000020), X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_X, 0x0b000020),
X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_D, &bdx_deadline_rev), X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_D, &bdx_deadline_rev),
@ -603,18 +601,19 @@ static const struct x86_cpu_id deadline_match[] = {
{}, {},
}; };
static void apic_check_deadline_errata(void) static __init bool apic_validate_deadline_timer(void)
{ {
const struct x86_cpu_id *m; const struct x86_cpu_id *m;
u32 rev; u32 rev;
if (!boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER) || if (!boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER))
boot_cpu_has(X86_FEATURE_HYPERVISOR)) return false;
return; if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
return true;
m = x86_match_cpu(deadline_match); m = x86_match_cpu(deadline_match);
if (!m) if (!m)
return; return true;
/* /*
* Function pointers will have the MSB set due to address layout, * Function pointers will have the MSB set due to address layout,
@ -626,11 +625,12 @@ static void apic_check_deadline_errata(void)
rev = (u32)m->driver_data; rev = (u32)m->driver_data;
if (boot_cpu_data.microcode >= rev) if (boot_cpu_data.microcode >= rev)
return; return true;
setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER); setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER);
pr_err(FW_BUG "TSC_DEADLINE disabled due to Errata; " pr_err(FW_BUG "TSC_DEADLINE disabled due to Errata; "
"please update microcode to version: 0x%x (or later)\n", rev); "please update microcode to version: 0x%x (or later)\n", rev);
return false;
} }
/* /*
@ -2092,7 +2092,8 @@ void __init init_apic_mappings(void)
{ {
unsigned int new_apicid; unsigned int new_apicid;
apic_check_deadline_errata(); if (apic_validate_deadline_timer())
pr_debug("TSC deadline timer available\n");
if (x2apic_mode) { if (x2apic_mode) {
boot_cpu_physical_apicid = read_apic_id(); boot_cpu_physical_apicid = read_apic_id();

View File

@ -183,7 +183,8 @@ recursion_check:
*/ */
if (visit_mask) { if (visit_mask) {
if (*visit_mask & (1UL << info->type)) { if (*visit_mask & (1UL << info->type)) {
printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type); if (task == current)
printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
goto unknown; goto unknown;
} }
*visit_mask |= 1UL << info->type; *visit_mask |= 1UL << info->type;

View File

@ -344,6 +344,9 @@ bad_address:
if (IS_ENABLED(CONFIG_X86_32)) if (IS_ENABLED(CONFIG_X86_32))
goto the_end; goto the_end;
if (state->task != current)
goto the_end;
if (state->regs) { if (state->regs) {
printk_deferred_once(KERN_WARNING printk_deferred_once(KERN_WARNING
"WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n", "WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n",

View File

@ -8,19 +8,21 @@
#include <asm/orc_lookup.h> #include <asm/orc_lookup.h>
#define orc_warn(fmt, ...) \ #define orc_warn(fmt, ...) \
printk_deferred_once(KERN_WARNING pr_fmt("WARNING: " fmt), ##__VA_ARGS__) printk_deferred_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__)
#define orc_warn_current(args...) \
({ \
if (state->task == current) \
orc_warn(args); \
})
extern int __start_orc_unwind_ip[]; extern int __start_orc_unwind_ip[];
extern int __stop_orc_unwind_ip[]; extern int __stop_orc_unwind_ip[];
extern struct orc_entry __start_orc_unwind[]; extern struct orc_entry __start_orc_unwind[];
extern struct orc_entry __stop_orc_unwind[]; extern struct orc_entry __stop_orc_unwind[];
static DEFINE_MUTEX(sort_mutex); static bool orc_init __ro_after_init;
int *cur_orc_ip_table = __start_orc_unwind_ip; static unsigned int lookup_num_blocks __ro_after_init;
struct orc_entry *cur_orc_table = __start_orc_unwind;
unsigned int lookup_num_blocks;
bool orc_init;
static inline unsigned long orc_ip(const int *ip) static inline unsigned long orc_ip(const int *ip)
{ {
@ -142,9 +144,6 @@ static struct orc_entry *orc_find(unsigned long ip)
{ {
static struct orc_entry *orc; static struct orc_entry *orc;
if (!orc_init)
return NULL;
if (ip == 0) if (ip == 0)
return &null_orc_entry; return &null_orc_entry;
@ -189,6 +188,10 @@ static struct orc_entry *orc_find(unsigned long ip)
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
static DEFINE_MUTEX(sort_mutex);
static int *cur_orc_ip_table = __start_orc_unwind_ip;
static struct orc_entry *cur_orc_table = __start_orc_unwind;
static void orc_sort_swap(void *_a, void *_b, int size) static void orc_sort_swap(void *_a, void *_b, int size)
{ {
struct orc_entry *orc_a, *orc_b; struct orc_entry *orc_a, *orc_b;
@ -381,9 +384,38 @@ static bool deref_stack_iret_regs(struct unwind_state *state, unsigned long addr
return true; return true;
} }
/*
* If state->regs is non-NULL, and points to a full pt_regs, just get the reg
* value from state->regs.
*
* Otherwise, if state->regs just points to IRET regs, and the previous frame
* had full regs, it's safe to get the value from the previous regs. This can
* happen when early/late IRQ entry code gets interrupted by an NMI.
*/
static bool get_reg(struct unwind_state *state, unsigned int reg_off,
unsigned long *val)
{
unsigned int reg = reg_off/8;
if (!state->regs)
return false;
if (state->full_regs) {
*val = ((unsigned long *)state->regs)[reg];
return true;
}
if (state->prev_regs) {
*val = ((unsigned long *)state->prev_regs)[reg];
return true;
}
return false;
}
bool unwind_next_frame(struct unwind_state *state) bool unwind_next_frame(struct unwind_state *state)
{ {
unsigned long ip_p, sp, orig_ip = state->ip, prev_sp = state->sp; unsigned long ip_p, sp, tmp, orig_ip = state->ip, prev_sp = state->sp;
enum stack_type prev_type = state->stack_info.type; enum stack_type prev_type = state->stack_info.type;
struct orc_entry *orc; struct orc_entry *orc;
bool indirect = false; bool indirect = false;
@ -445,43 +477,39 @@ bool unwind_next_frame(struct unwind_state *state)
break; break;
case ORC_REG_R10: case ORC_REG_R10:
if (!state->regs || !state->full_regs) { if (!get_reg(state, offsetof(struct pt_regs, r10), &sp)) {
orc_warn("missing regs for base reg R10 at ip %pB\n", orc_warn_current("missing R10 value at %pB\n",
(void *)state->ip); (void *)state->ip);
goto err; goto err;
} }
sp = state->regs->r10;
break; break;
case ORC_REG_R13: case ORC_REG_R13:
if (!state->regs || !state->full_regs) { if (!get_reg(state, offsetof(struct pt_regs, r13), &sp)) {
orc_warn("missing regs for base reg R13 at ip %pB\n", orc_warn_current("missing R13 value at %pB\n",
(void *)state->ip); (void *)state->ip);
goto err; goto err;
} }
sp = state->regs->r13;
break; break;
case ORC_REG_DI: case ORC_REG_DI:
if (!state->regs || !state->full_regs) { if (!get_reg(state, offsetof(struct pt_regs, di), &sp)) {
orc_warn("missing regs for base reg DI at ip %pB\n", orc_warn_current("missing RDI value at %pB\n",
(void *)state->ip); (void *)state->ip);
goto err; goto err;
} }
sp = state->regs->di;
break; break;
case ORC_REG_DX: case ORC_REG_DX:
if (!state->regs || !state->full_regs) { if (!get_reg(state, offsetof(struct pt_regs, dx), &sp)) {
orc_warn("missing regs for base reg DX at ip %pB\n", orc_warn_current("missing DX value at %pB\n",
(void *)state->ip); (void *)state->ip);
goto err; goto err;
} }
sp = state->regs->dx;
break; break;
default: default:
orc_warn("unknown SP base reg %d for ip %pB\n", orc_warn("unknown SP base reg %d at %pB\n",
orc->sp_reg, (void *)state->ip); orc->sp_reg, (void *)state->ip);
goto err; goto err;
} }
@ -504,44 +532,48 @@ bool unwind_next_frame(struct unwind_state *state)
state->sp = sp; state->sp = sp;
state->regs = NULL; state->regs = NULL;
state->prev_regs = NULL;
state->signal = false; state->signal = false;
break; break;
case ORC_TYPE_REGS: case ORC_TYPE_REGS:
if (!deref_stack_regs(state, sp, &state->ip, &state->sp)) { if (!deref_stack_regs(state, sp, &state->ip, &state->sp)) {
orc_warn("can't dereference registers at %p for ip %pB\n", orc_warn_current("can't access registers at %pB\n",
(void *)sp, (void *)orig_ip); (void *)orig_ip);
goto err; goto err;
} }
state->regs = (struct pt_regs *)sp; state->regs = (struct pt_regs *)sp;
state->prev_regs = NULL;
state->full_regs = true; state->full_regs = true;
state->signal = true; state->signal = true;
break; break;
case ORC_TYPE_REGS_IRET: case ORC_TYPE_REGS_IRET:
if (!deref_stack_iret_regs(state, sp, &state->ip, &state->sp)) { if (!deref_stack_iret_regs(state, sp, &state->ip, &state->sp)) {
orc_warn("can't dereference iret registers at %p for ip %pB\n", orc_warn_current("can't access iret registers at %pB\n",
(void *)sp, (void *)orig_ip); (void *)orig_ip);
goto err; goto err;
} }
if (state->full_regs)
state->prev_regs = state->regs;
state->regs = (void *)sp - IRET_FRAME_OFFSET; state->regs = (void *)sp - IRET_FRAME_OFFSET;
state->full_regs = false; state->full_regs = false;
state->signal = true; state->signal = true;
break; break;
default: default:
orc_warn("unknown .orc_unwind entry type %d for ip %pB\n", orc_warn("unknown .orc_unwind entry type %d at %pB\n",
orc->type, (void *)orig_ip); orc->type, (void *)orig_ip);
break; goto err;
} }
/* Find BP: */ /* Find BP: */
switch (orc->bp_reg) { switch (orc->bp_reg) {
case ORC_REG_UNDEFINED: case ORC_REG_UNDEFINED:
if (state->regs && state->full_regs) if (get_reg(state, offsetof(struct pt_regs, bp), &tmp))
state->bp = state->regs->bp; state->bp = tmp;
break; break;
case ORC_REG_PREV_SP: case ORC_REG_PREV_SP:
@ -564,8 +596,8 @@ bool unwind_next_frame(struct unwind_state *state)
if (state->stack_info.type == prev_type && if (state->stack_info.type == prev_type &&
on_stack(&state->stack_info, (void *)state->sp, sizeof(long)) && on_stack(&state->stack_info, (void *)state->sp, sizeof(long)) &&
state->sp <= prev_sp) { state->sp <= prev_sp) {
orc_warn("stack going in the wrong direction? ip=%pB\n", orc_warn_current("stack going in the wrong direction? at %pB\n",
(void *)orig_ip); (void *)orig_ip);
goto err; goto err;
} }
@ -585,6 +617,9 @@ EXPORT_SYMBOL_GPL(unwind_next_frame);
void __unwind_start(struct unwind_state *state, struct task_struct *task, void __unwind_start(struct unwind_state *state, struct task_struct *task,
struct pt_regs *regs, unsigned long *first_frame) struct pt_regs *regs, unsigned long *first_frame)
{ {
if (!orc_init)
goto done;
memset(state, 0, sizeof(*state)); memset(state, 0, sizeof(*state));
state->task = task; state->task = task;
@ -651,7 +686,7 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
/* Otherwise, skip ahead to the user-specified starting frame: */ /* Otherwise, skip ahead to the user-specified starting frame: */
while (!unwind_done(state) && while (!unwind_done(state) &&
(!on_stack(&state->stack_info, first_frame, sizeof(long)) || (!on_stack(&state->stack_info, first_frame, sizeof(long)) ||
state->sp <= (unsigned long)first_frame)) state->sp < (unsigned long)first_frame))
unwind_next_frame(state); unwind_next_frame(state);
return; return;

View File

@ -225,12 +225,12 @@ static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
} }
/* /*
* AMD SVM AVIC accelerate EOI write and do not trap, * AMD SVM AVIC accelerate EOI write iff the interrupt is edge
* in-kernel IOAPIC will not be able to receive the EOI. * triggered, in which case the in-kernel IOAPIC will not be able
* In this case, we do lazy update of the pending EOI when * to receive the EOI. In this case, we do a lazy update of the
* trying to set IOAPIC irq. * pending EOI when trying to set IOAPIC irq.
*/ */
if (kvm_apicv_activated(ioapic->kvm)) if (edge && kvm_apicv_activated(ioapic->kvm))
ioapic_lazy_update_eoi(ioapic, irq); ioapic_lazy_update_eoi(ioapic, irq);
/* /*

View File

@ -345,7 +345,7 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
return NULL; return NULL;
/* Pin the user virtual address. */ /* Pin the user virtual address. */
npinned = get_user_pages_fast(uaddr, npages, FOLL_WRITE, pages); npinned = get_user_pages_fast(uaddr, npages, write ? FOLL_WRITE : 0, pages);
if (npinned != npages) { if (npinned != npages) {
pr_err("SEV: Failure locking %lu pages.\n", npages); pr_err("SEV: Failure locking %lu pages.\n", npages);
goto err; goto err;

View File

@ -1752,6 +1752,8 @@ static int db_interception(struct vcpu_svm *svm)
if (svm->vcpu.guest_debug & if (svm->vcpu.guest_debug &
(KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) { (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) {
kvm_run->exit_reason = KVM_EXIT_DEBUG; kvm_run->exit_reason = KVM_EXIT_DEBUG;
kvm_run->debug.arch.dr6 = svm->vmcb->save.dr6;
kvm_run->debug.arch.dr7 = svm->vmcb->save.dr7;
kvm_run->debug.arch.pc = kvm_run->debug.arch.pc =
svm->vmcb->save.cs.base + svm->vmcb->save.rip; svm->vmcb->save.cs.base + svm->vmcb->save.rip;
kvm_run->debug.arch.exception = DB_VECTOR; kvm_run->debug.arch.exception = DB_VECTOR;

View File

@ -5165,7 +5165,7 @@ static int handle_invept(struct kvm_vcpu *vcpu)
*/ */
break; break;
default: default:
BUG_ON(1); BUG();
break; break;
} }

View File

@ -82,6 +82,9 @@ SYM_FUNC_START(vmx_vmexit)
/* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */ /* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */
FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
/* Clear RFLAGS.CF and RFLAGS.ZF to preserve VM-Exit, i.e. !VM-Fail. */
or $1, %_ASM_AX
pop %_ASM_AX pop %_ASM_AX
.Lvmexit_skip_rsb: .Lvmexit_skip_rsb:
#endif #endif

View File

@ -926,19 +926,6 @@ EXPORT_SYMBOL_GPL(kvm_set_xcr);
__reserved_bits; \ __reserved_bits; \
}) })
static u64 kvm_host_cr4_reserved_bits(struct cpuinfo_x86 *c)
{
u64 reserved_bits = __cr4_reserved_bits(cpu_has, c);
if (kvm_cpu_cap_has(X86_FEATURE_LA57))
reserved_bits &= ~X86_CR4_LA57;
if (kvm_cpu_cap_has(X86_FEATURE_UMIP))
reserved_bits &= ~X86_CR4_UMIP;
return reserved_bits;
}
static int kvm_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) static int kvm_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
{ {
if (cr4 & cr4_reserved_bits) if (cr4 & cr4_reserved_bits)
@ -3385,6 +3372,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_GET_MSR_FEATURES: case KVM_CAP_GET_MSR_FEATURES:
case KVM_CAP_MSR_PLATFORM_INFO: case KVM_CAP_MSR_PLATFORM_INFO:
case KVM_CAP_EXCEPTION_PAYLOAD: case KVM_CAP_EXCEPTION_PAYLOAD:
case KVM_CAP_SET_GUEST_DEBUG:
r = 1; r = 1;
break; break;
case KVM_CAP_SYNC_REGS: case KVM_CAP_SYNC_REGS:
@ -9675,7 +9663,9 @@ int kvm_arch_hardware_setup(void *opaque)
if (!kvm_cpu_cap_has(X86_FEATURE_XSAVES)) if (!kvm_cpu_cap_has(X86_FEATURE_XSAVES))
supported_xss = 0; supported_xss = 0;
cr4_reserved_bits = kvm_host_cr4_reserved_bits(&boot_cpu_data); #define __kvm_cpu_cap_has(UNUSED_, f) kvm_cpu_cap_has(f)
cr4_reserved_bits = __cr4_reserved_bits(__kvm_cpu_cap_has, UNUSED_);
#undef __kvm_cpu_cap_has
if (kvm_has_tsc_control) { if (kvm_has_tsc_control) {
/* /*
@ -9707,7 +9697,8 @@ int kvm_arch_check_processor_compat(void *opaque)
WARN_ON(!irqs_disabled()); WARN_ON(!irqs_disabled());
if (kvm_host_cr4_reserved_bits(c) != cr4_reserved_bits) if (__cr4_reserved_bits(cpu_has, c) !=
__cr4_reserved_bits(cpu_has, &boot_cpu_data))
return -EIO; return -EIO;
return ops->check_processor_compatibility(); return ops->check_processor_compatibility();

View File

@ -43,7 +43,8 @@ struct cpa_data {
unsigned long pfn; unsigned long pfn;
unsigned int flags; unsigned int flags;
unsigned int force_split : 1, unsigned int force_split : 1,
force_static_prot : 1; force_static_prot : 1,
force_flush_all : 1;
struct page **pages; struct page **pages;
}; };
@ -355,10 +356,10 @@ static void cpa_flush(struct cpa_data *data, int cache)
return; return;
} }
if (cpa->numpages <= tlb_single_page_flush_ceiling) if (cpa->force_flush_all || cpa->numpages > tlb_single_page_flush_ceiling)
on_each_cpu(__cpa_flush_tlb, cpa, 1);
else
flush_tlb_all(); flush_tlb_all();
else
on_each_cpu(__cpa_flush_tlb, cpa, 1);
if (!cache) if (!cache)
return; return;
@ -1598,6 +1599,8 @@ static int cpa_process_alias(struct cpa_data *cpa)
alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY); alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
alias_cpa.curpage = 0; alias_cpa.curpage = 0;
cpa->force_flush_all = 1;
ret = __change_page_attr_set_clr(&alias_cpa, 0); ret = __change_page_attr_set_clr(&alias_cpa, 0);
if (ret) if (ret)
return ret; return ret;
@ -1618,6 +1621,7 @@ static int cpa_process_alias(struct cpa_data *cpa)
alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY); alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
alias_cpa.curpage = 0; alias_cpa.curpage = 0;
cpa->force_flush_all = 1;
/* /*
* The high mapping range is imprecise, so ignore the * The high mapping range is imprecise, so ignore the
* return value. * return value.

View File

@ -123,6 +123,7 @@
#include <linux/ioprio.h> #include <linux/ioprio.h>
#include <linux/sbitmap.h> #include <linux/sbitmap.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/backing-dev.h>
#include "blk.h" #include "blk.h"
#include "blk-mq.h" #include "blk-mq.h"
@ -4976,8 +4977,9 @@ bfq_set_next_ioprio_data(struct bfq_queue *bfqq, struct bfq_io_cq *bic)
ioprio_class = IOPRIO_PRIO_CLASS(bic->ioprio); ioprio_class = IOPRIO_PRIO_CLASS(bic->ioprio);
switch (ioprio_class) { switch (ioprio_class) {
default: default:
dev_err(bfqq->bfqd->queue->backing_dev_info->dev, pr_err("bdi %s: bfq: bad prio class %d\n",
"bfq: bad prio class %d\n", ioprio_class); bdi_dev_name(bfqq->bfqd->queue->backing_dev_info),
ioprio_class);
/* fall through */ /* fall through */
case IOPRIO_CLASS_NONE: case IOPRIO_CLASS_NONE:
/* /*

View File

@ -496,7 +496,7 @@ const char *blkg_dev_name(struct blkcg_gq *blkg)
{ {
/* some drivers (floppy) instantiate a queue w/o disk registered */ /* some drivers (floppy) instantiate a queue w/o disk registered */
if (blkg->q->backing_dev_info->dev) if (blkg->q->backing_dev_info->dev)
return dev_name(blkg->q->backing_dev_info->dev); return bdi_dev_name(blkg->q->backing_dev_info);
return NULL; return NULL;
} }

View File

@ -466,7 +466,7 @@ struct ioc_gq {
*/ */
atomic64_t vtime; atomic64_t vtime;
atomic64_t done_vtime; atomic64_t done_vtime;
atomic64_t abs_vdebt; u64 abs_vdebt;
u64 last_vtime; u64 last_vtime;
/* /*
@ -1142,7 +1142,7 @@ static void iocg_kick_waitq(struct ioc_gq *iocg, struct ioc_now *now)
struct iocg_wake_ctx ctx = { .iocg = iocg }; struct iocg_wake_ctx ctx = { .iocg = iocg };
u64 margin_ns = (u64)(ioc->period_us * u64 margin_ns = (u64)(ioc->period_us *
WAITQ_TIMER_MARGIN_PCT / 100) * NSEC_PER_USEC; WAITQ_TIMER_MARGIN_PCT / 100) * NSEC_PER_USEC;
u64 abs_vdebt, vdebt, vshortage, expires, oexpires; u64 vdebt, vshortage, expires, oexpires;
s64 vbudget; s64 vbudget;
u32 hw_inuse; u32 hw_inuse;
@ -1152,18 +1152,15 @@ static void iocg_kick_waitq(struct ioc_gq *iocg, struct ioc_now *now)
vbudget = now->vnow - atomic64_read(&iocg->vtime); vbudget = now->vnow - atomic64_read(&iocg->vtime);
/* pay off debt */ /* pay off debt */
abs_vdebt = atomic64_read(&iocg->abs_vdebt); vdebt = abs_cost_to_cost(iocg->abs_vdebt, hw_inuse);
vdebt = abs_cost_to_cost(abs_vdebt, hw_inuse);
if (vdebt && vbudget > 0) { if (vdebt && vbudget > 0) {
u64 delta = min_t(u64, vbudget, vdebt); u64 delta = min_t(u64, vbudget, vdebt);
u64 abs_delta = min(cost_to_abs_cost(delta, hw_inuse), u64 abs_delta = min(cost_to_abs_cost(delta, hw_inuse),
abs_vdebt); iocg->abs_vdebt);
atomic64_add(delta, &iocg->vtime); atomic64_add(delta, &iocg->vtime);
atomic64_add(delta, &iocg->done_vtime); atomic64_add(delta, &iocg->done_vtime);
atomic64_sub(abs_delta, &iocg->abs_vdebt); iocg->abs_vdebt -= abs_delta;
if (WARN_ON_ONCE(atomic64_read(&iocg->abs_vdebt) < 0))
atomic64_set(&iocg->abs_vdebt, 0);
} }
/* /*
@ -1219,12 +1216,18 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now, u64 cost)
u64 expires, oexpires; u64 expires, oexpires;
u32 hw_inuse; u32 hw_inuse;
lockdep_assert_held(&iocg->waitq.lock);
/* debt-adjust vtime */ /* debt-adjust vtime */
current_hweight(iocg, NULL, &hw_inuse); current_hweight(iocg, NULL, &hw_inuse);
vtime += abs_cost_to_cost(atomic64_read(&iocg->abs_vdebt), hw_inuse); vtime += abs_cost_to_cost(iocg->abs_vdebt, hw_inuse);
/* clear or maintain depending on the overage */ /*
if (time_before_eq64(vtime, now->vnow)) { * Clear or maintain depending on the overage. Non-zero vdebt is what
* guarantees that @iocg is online and future iocg_kick_delay() will
* clear use_delay. Don't leave it on when there's no vdebt.
*/
if (!iocg->abs_vdebt || time_before_eq64(vtime, now->vnow)) {
blkcg_clear_delay(blkg); blkcg_clear_delay(blkg);
return false; return false;
} }
@ -1258,9 +1261,12 @@ static enum hrtimer_restart iocg_delay_timer_fn(struct hrtimer *timer)
{ {
struct ioc_gq *iocg = container_of(timer, struct ioc_gq, delay_timer); struct ioc_gq *iocg = container_of(timer, struct ioc_gq, delay_timer);
struct ioc_now now; struct ioc_now now;
unsigned long flags;
spin_lock_irqsave(&iocg->waitq.lock, flags);
ioc_now(iocg->ioc, &now); ioc_now(iocg->ioc, &now);
iocg_kick_delay(iocg, &now, 0); iocg_kick_delay(iocg, &now, 0);
spin_unlock_irqrestore(&iocg->waitq.lock, flags);
return HRTIMER_NORESTART; return HRTIMER_NORESTART;
} }
@ -1368,14 +1374,13 @@ static void ioc_timer_fn(struct timer_list *timer)
* should have woken up in the last period and expire idle iocgs. * should have woken up in the last period and expire idle iocgs.
*/ */
list_for_each_entry_safe(iocg, tiocg, &ioc->active_iocgs, active_list) { list_for_each_entry_safe(iocg, tiocg, &ioc->active_iocgs, active_list) {
if (!waitqueue_active(&iocg->waitq) && if (!waitqueue_active(&iocg->waitq) && iocg->abs_vdebt &&
!atomic64_read(&iocg->abs_vdebt) && !iocg_is_idle(iocg)) !iocg_is_idle(iocg))
continue; continue;
spin_lock(&iocg->waitq.lock); spin_lock(&iocg->waitq.lock);
if (waitqueue_active(&iocg->waitq) || if (waitqueue_active(&iocg->waitq) || iocg->abs_vdebt) {
atomic64_read(&iocg->abs_vdebt)) {
/* might be oversleeping vtime / hweight changes, kick */ /* might be oversleeping vtime / hweight changes, kick */
iocg_kick_waitq(iocg, &now); iocg_kick_waitq(iocg, &now);
iocg_kick_delay(iocg, &now, 0); iocg_kick_delay(iocg, &now, 0);
@ -1718,28 +1723,49 @@ static void ioc_rqos_throttle(struct rq_qos *rqos, struct bio *bio)
* tests are racy but the races aren't systemic - we only miss once * tests are racy but the races aren't systemic - we only miss once
* in a while which is fine. * in a while which is fine.
*/ */
if (!waitqueue_active(&iocg->waitq) && if (!waitqueue_active(&iocg->waitq) && !iocg->abs_vdebt &&
!atomic64_read(&iocg->abs_vdebt) &&
time_before_eq64(vtime + cost, now.vnow)) { time_before_eq64(vtime + cost, now.vnow)) {
iocg_commit_bio(iocg, bio, cost); iocg_commit_bio(iocg, bio, cost);
return; return;
} }
/* /*
* We're over budget. If @bio has to be issued regardless, * We activated above but w/o any synchronization. Deactivation is
* remember the abs_cost instead of advancing vtime. * synchronized with waitq.lock and we won't get deactivated as long
* iocg_kick_waitq() will pay off the debt before waking more IOs. * as we're waiting or has debt, so we're good if we're activated
* here. In the unlikely case that we aren't, just issue the IO.
*/
spin_lock_irq(&iocg->waitq.lock);
if (unlikely(list_empty(&iocg->active_list))) {
spin_unlock_irq(&iocg->waitq.lock);
iocg_commit_bio(iocg, bio, cost);
return;
}
/*
* We're over budget. If @bio has to be issued regardless, remember
* the abs_cost instead of advancing vtime. iocg_kick_waitq() will pay
* off the debt before waking more IOs.
*
* This way, the debt is continuously paid off each period with the * This way, the debt is continuously paid off each period with the
* actual budget available to the cgroup. If we just wound vtime, * actual budget available to the cgroup. If we just wound vtime, we
* we would incorrectly use the current hw_inuse for the entire * would incorrectly use the current hw_inuse for the entire amount
* amount which, for example, can lead to the cgroup staying * which, for example, can lead to the cgroup staying blocked for a
* blocked for a long time even with substantially raised hw_inuse. * long time even with substantially raised hw_inuse.
*
* An iocg with vdebt should stay online so that the timer can keep
* deducting its vdebt and [de]activate use_delay mechanism
* accordingly. We don't want to race against the timer trying to
* clear them and leave @iocg inactive w/ dangling use_delay heavily
* penalizing the cgroup and its descendants.
*/ */
if (bio_issue_as_root_blkg(bio) || fatal_signal_pending(current)) { if (bio_issue_as_root_blkg(bio) || fatal_signal_pending(current)) {
atomic64_add(abs_cost, &iocg->abs_vdebt); iocg->abs_vdebt += abs_cost;
if (iocg_kick_delay(iocg, &now, cost)) if (iocg_kick_delay(iocg, &now, cost))
blkcg_schedule_throttle(rqos->q, blkcg_schedule_throttle(rqos->q,
(bio->bi_opf & REQ_SWAP) == REQ_SWAP); (bio->bi_opf & REQ_SWAP) == REQ_SWAP);
spin_unlock_irq(&iocg->waitq.lock);
return; return;
} }
@ -1756,20 +1782,6 @@ static void ioc_rqos_throttle(struct rq_qos *rqos, struct bio *bio)
* All waiters are on iocg->waitq and the wait states are * All waiters are on iocg->waitq and the wait states are
* synchronized using waitq.lock. * synchronized using waitq.lock.
*/ */
spin_lock_irq(&iocg->waitq.lock);
/*
* We activated above but w/o any synchronization. Deactivation is
* synchronized with waitq.lock and we won't get deactivated as
* long as we're waiting, so we're good if we're activated here.
* In the unlikely case that we are deactivated, just issue the IO.
*/
if (unlikely(list_empty(&iocg->active_list))) {
spin_unlock_irq(&iocg->waitq.lock);
iocg_commit_bio(iocg, bio, cost);
return;
}
init_waitqueue_func_entry(&wait.wait, iocg_wake_fn); init_waitqueue_func_entry(&wait.wait, iocg_wake_fn);
wait.wait.private = current; wait.wait.private = current;
wait.bio = bio; wait.bio = bio;
@ -1801,6 +1813,7 @@ static void ioc_rqos_merge(struct rq_qos *rqos, struct request *rq,
struct ioc_now now; struct ioc_now now;
u32 hw_inuse; u32 hw_inuse;
u64 abs_cost, cost; u64 abs_cost, cost;
unsigned long flags;
/* bypass if disabled or for root cgroup */ /* bypass if disabled or for root cgroup */
if (!ioc->enabled || !iocg->level) if (!ioc->enabled || !iocg->level)
@ -1820,15 +1833,28 @@ static void ioc_rqos_merge(struct rq_qos *rqos, struct request *rq,
iocg->cursor = bio_end; iocg->cursor = bio_end;
/* /*
* Charge if there's enough vtime budget and the existing request * Charge if there's enough vtime budget and the existing request has
* has cost assigned. Otherwise, account it as debt. See debt * cost assigned.
* handling in ioc_rqos_throttle() for details.
*/ */
if (rq->bio && rq->bio->bi_iocost_cost && if (rq->bio && rq->bio->bi_iocost_cost &&
time_before_eq64(atomic64_read(&iocg->vtime) + cost, now.vnow)) time_before_eq64(atomic64_read(&iocg->vtime) + cost, now.vnow)) {
iocg_commit_bio(iocg, bio, cost); iocg_commit_bio(iocg, bio, cost);
else return;
atomic64_add(abs_cost, &iocg->abs_vdebt); }
/*
* Otherwise, account it as debt if @iocg is online, which it should
* be for the vast majority of cases. See debt handling in
* ioc_rqos_throttle() for details.
*/
spin_lock_irqsave(&iocg->waitq.lock, flags);
if (likely(!list_empty(&iocg->active_list))) {
iocg->abs_vdebt += abs_cost;
iocg_kick_delay(iocg, &now, cost);
} else {
iocg_commit_bio(iocg, bio, cost);
}
spin_unlock_irqrestore(&iocg->waitq.lock, flags);
} }
static void ioc_rqos_done_bio(struct rq_qos *rqos, struct bio *bio) static void ioc_rqos_done_bio(struct rq_qos *rqos, struct bio *bio)
@ -1998,7 +2024,6 @@ static void ioc_pd_init(struct blkg_policy_data *pd)
iocg->ioc = ioc; iocg->ioc = ioc;
atomic64_set(&iocg->vtime, now.vnow); atomic64_set(&iocg->vtime, now.vnow);
atomic64_set(&iocg->done_vtime, now.vnow); atomic64_set(&iocg->done_vtime, now.vnow);
atomic64_set(&iocg->abs_vdebt, 0);
atomic64_set(&iocg->active_period, atomic64_read(&ioc->cur_period)); atomic64_set(&iocg->active_period, atomic64_read(&ioc->cur_period));
INIT_LIST_HEAD(&iocg->active_list); INIT_LIST_HEAD(&iocg->active_list);
iocg->hweight_active = HWEIGHT_WHOLE; iocg->hweight_active = HWEIGHT_WHOLE;

View File

@ -496,7 +496,7 @@ int blk_drop_partitions(struct gendisk *disk, struct block_device *bdev)
if (!disk_part_scan_enabled(disk)) if (!disk_part_scan_enabled(disk))
return 0; return 0;
if (bdev->bd_part_count || bdev->bd_openers > 1) if (bdev->bd_part_count)
return -EBUSY; return -EBUSY;
res = invalidate_partition(disk, 0); res = invalidate_partition(disk, 0);
if (res) if (res)

View File

@ -287,7 +287,7 @@ static void exit_tfm(struct crypto_skcipher *tfm)
crypto_free_skcipher(ctx->child); crypto_free_skcipher(ctx->child);
} }
static void free(struct skcipher_instance *inst) static void free_inst(struct skcipher_instance *inst)
{ {
crypto_drop_skcipher(skcipher_instance_ctx(inst)); crypto_drop_skcipher(skcipher_instance_ctx(inst));
kfree(inst); kfree(inst);
@ -400,12 +400,12 @@ static int create(struct crypto_template *tmpl, struct rtattr **tb)
inst->alg.encrypt = encrypt; inst->alg.encrypt = encrypt;
inst->alg.decrypt = decrypt; inst->alg.decrypt = decrypt;
inst->free = free; inst->free = free_inst;
err = skcipher_register_instance(tmpl, inst); err = skcipher_register_instance(tmpl, inst);
if (err) { if (err) {
err_free_inst: err_free_inst:
free(inst); free_inst(inst);
} }
return err; return err;
} }

View File

@ -322,7 +322,7 @@ static void exit_tfm(struct crypto_skcipher *tfm)
crypto_free_cipher(ctx->tweak); crypto_free_cipher(ctx->tweak);
} }
static void free(struct skcipher_instance *inst) static void free_inst(struct skcipher_instance *inst)
{ {
crypto_drop_skcipher(skcipher_instance_ctx(inst)); crypto_drop_skcipher(skcipher_instance_ctx(inst));
kfree(inst); kfree(inst);
@ -434,12 +434,12 @@ static int create(struct crypto_template *tmpl, struct rtattr **tb)
inst->alg.encrypt = encrypt; inst->alg.encrypt = encrypt;
inst->alg.decrypt = decrypt; inst->alg.decrypt = decrypt;
inst->free = free; inst->free = free_inst;
err = skcipher_register_instance(tmpl, inst); err = skcipher_register_instance(tmpl, inst);
if (err) { if (err) {
err_free_inst: err_free_inst:
free(inst); free_inst(inst);
} }
return err; return err;
} }

View File

@ -273,13 +273,13 @@ int acpi_device_set_power(struct acpi_device *device, int state)
end: end:
if (result) { if (result) {
dev_warn(&device->dev, "Failed to change power state to %s\n", dev_warn(&device->dev, "Failed to change power state to %s\n",
acpi_power_state_string(state)); acpi_power_state_string(target_state));
} else { } else {
device->power.state = target_state; device->power.state = target_state;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device [%s] transitioned to %s\n", "Device [%s] transitioned to %s\n",
device->pnp.bus_id, device->pnp.bus_id,
acpi_power_state_string(state))); acpi_power_state_string(target_state)));
} }
return result; return result;

View File

@ -645,6 +645,7 @@ static void amba_device_initialize(struct amba_device *dev, const char *name)
dev->dev.release = amba_device_release; dev->dev.release = amba_device_release;
dev->dev.bus = &amba_bustype; dev->dev.bus = &amba_bustype;
dev->dev.dma_mask = &dev->dev.coherent_dma_mask; dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
dev->dev.dma_parms = &dev->dma_parms;
dev->res.name = dev_name(&dev->dev); dev->res.name = dev_name(&dev->dev);
} }

View File

@ -256,7 +256,8 @@ static int try_to_bring_up_master(struct master *master,
ret = master->ops->bind(master->dev); ret = master->ops->bind(master->dev);
if (ret < 0) { if (ret < 0) {
devres_release_group(master->dev, NULL); devres_release_group(master->dev, NULL);
dev_info(master->dev, "master bind failed: %d\n", ret); if (ret != -EPROBE_DEFER)
dev_info(master->dev, "master bind failed: %d\n", ret);
return ret; return ret;
} }
@ -611,8 +612,9 @@ static int component_bind(struct component *component, struct master *master,
devres_release_group(component->dev, NULL); devres_release_group(component->dev, NULL);
devres_release_group(master->dev, NULL); devres_release_group(master->dev, NULL);
dev_err(master->dev, "failed to bind %s (ops %ps): %d\n", if (ret != -EPROBE_DEFER)
dev_name(component->dev), component->ops, ret); dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
dev_name(component->dev), component->ops, ret);
} }
return ret; return ret;

View File

@ -2370,6 +2370,11 @@ u32 fw_devlink_get_flags(void)
return fw_devlink_flags; return fw_devlink_flags;
} }
static bool fw_devlink_is_permissive(void)
{
return fw_devlink_flags == DL_FLAG_SYNC_STATE_ONLY;
}
/** /**
* device_add - add device to device hierarchy. * device_add - add device to device hierarchy.
* @dev: device. * @dev: device.
@ -2524,7 +2529,7 @@ int device_add(struct device *dev)
if (fw_devlink_flags && is_fwnode_dev && if (fw_devlink_flags && is_fwnode_dev &&
fwnode_has_op(dev->fwnode, add_links)) { fwnode_has_op(dev->fwnode, add_links)) {
fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev); fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
if (fw_ret == -ENODEV) if (fw_ret == -ENODEV && !fw_devlink_is_permissive())
device_link_wait_for_mandatory_supplier(dev); device_link_wait_for_mandatory_supplier(dev);
else if (fw_ret) else if (fw_ret)
device_link_wait_for_optional_supplier(dev); device_link_wait_for_optional_supplier(dev);

View File

@ -224,17 +224,9 @@ static int deferred_devs_show(struct seq_file *s, void *data)
} }
DEFINE_SHOW_ATTRIBUTE(deferred_devs); DEFINE_SHOW_ATTRIBUTE(deferred_devs);
#ifdef CONFIG_MODULES int driver_deferred_probe_timeout;
/*
* In the case of modules, set the default probe timeout to
* 30 seconds to give userland some time to load needed modules
*/
int driver_deferred_probe_timeout = 30;
#else
/* In the case of !modules, no probe timeout needed */
int driver_deferred_probe_timeout = -1;
#endif
EXPORT_SYMBOL_GPL(driver_deferred_probe_timeout); EXPORT_SYMBOL_GPL(driver_deferred_probe_timeout);
static DECLARE_WAIT_QUEUE_HEAD(probe_timeout_waitqueue);
static int __init deferred_probe_timeout_setup(char *str) static int __init deferred_probe_timeout_setup(char *str)
{ {
@ -266,8 +258,8 @@ int driver_deferred_probe_check_state(struct device *dev)
return -ENODEV; return -ENODEV;
} }
if (!driver_deferred_probe_timeout) { if (!driver_deferred_probe_timeout && initcalls_done) {
dev_WARN(dev, "deferred probe timeout, ignoring dependency"); dev_warn(dev, "deferred probe timeout, ignoring dependency");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
@ -284,6 +276,7 @@ static void deferred_probe_timeout_work_func(struct work_struct *work)
list_for_each_entry_safe(private, p, &deferred_probe_pending_list, deferred_probe) list_for_each_entry_safe(private, p, &deferred_probe_pending_list, deferred_probe)
dev_info(private->device, "deferred probe pending"); dev_info(private->device, "deferred probe pending");
wake_up(&probe_timeout_waitqueue);
} }
static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func); static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func);
@ -658,6 +651,9 @@ int driver_probe_done(void)
*/ */
void wait_for_device_probe(void) void wait_for_device_probe(void)
{ {
/* wait for probe timeout */
wait_event(probe_timeout_waitqueue, !driver_deferred_probe_timeout);
/* wait for the deferred probe workqueue to finish */ /* wait for the deferred probe workqueue to finish */
flush_work(&deferred_probe_work); flush_work(&deferred_probe_work);

View File

@ -380,6 +380,8 @@ struct platform_object {
*/ */
static void setup_pdev_dma_masks(struct platform_device *pdev) static void setup_pdev_dma_masks(struct platform_device *pdev)
{ {
pdev->dev.dma_parms = &pdev->dma_parms;
if (!pdev->dev.coherent_dma_mask) if (!pdev->dev.coherent_dma_mask)
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
if (!pdev->dev.dma_mask) { if (!pdev->dev.dma_mask) {

View File

@ -33,6 +33,15 @@ struct virtio_blk_vq {
} ____cacheline_aligned_in_smp; } ____cacheline_aligned_in_smp;
struct virtio_blk { struct virtio_blk {
/*
* This mutex must be held by anything that may run after
* virtblk_remove() sets vblk->vdev to NULL.
*
* blk-mq, virtqueue processing, and sysfs attribute code paths are
* shut down before vblk->vdev is set to NULL and therefore do not need
* to hold this mutex.
*/
struct mutex vdev_mutex;
struct virtio_device *vdev; struct virtio_device *vdev;
/* The disk structure for the kernel. */ /* The disk structure for the kernel. */
@ -44,6 +53,13 @@ struct virtio_blk {
/* Process context for config space updates */ /* Process context for config space updates */
struct work_struct config_work; struct work_struct config_work;
/*
* Tracks references from block_device_operations open/release and
* virtio_driver probe/remove so this object can be freed once no
* longer in use.
*/
refcount_t refs;
/* What host tells us, plus 2 for header & tailer. */ /* What host tells us, plus 2 for header & tailer. */
unsigned int sg_elems; unsigned int sg_elems;
@ -295,10 +311,55 @@ out:
return err; return err;
} }
static void virtblk_get(struct virtio_blk *vblk)
{
refcount_inc(&vblk->refs);
}
static void virtblk_put(struct virtio_blk *vblk)
{
if (refcount_dec_and_test(&vblk->refs)) {
ida_simple_remove(&vd_index_ida, vblk->index);
mutex_destroy(&vblk->vdev_mutex);
kfree(vblk);
}
}
static int virtblk_open(struct block_device *bd, fmode_t mode)
{
struct virtio_blk *vblk = bd->bd_disk->private_data;
int ret = 0;
mutex_lock(&vblk->vdev_mutex);
if (vblk->vdev)
virtblk_get(vblk);
else
ret = -ENXIO;
mutex_unlock(&vblk->vdev_mutex);
return ret;
}
static void virtblk_release(struct gendisk *disk, fmode_t mode)
{
struct virtio_blk *vblk = disk->private_data;
virtblk_put(vblk);
}
/* We provide getgeo only to please some old bootloader/partitioning tools */ /* We provide getgeo only to please some old bootloader/partitioning tools */
static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
{ {
struct virtio_blk *vblk = bd->bd_disk->private_data; struct virtio_blk *vblk = bd->bd_disk->private_data;
int ret = 0;
mutex_lock(&vblk->vdev_mutex);
if (!vblk->vdev) {
ret = -ENXIO;
goto out;
}
/* see if the host passed in geometry config */ /* see if the host passed in geometry config */
if (virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_GEOMETRY)) { if (virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_GEOMETRY)) {
@ -314,11 +375,15 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
geo->sectors = 1 << 5; geo->sectors = 1 << 5;
geo->cylinders = get_capacity(bd->bd_disk) >> 11; geo->cylinders = get_capacity(bd->bd_disk) >> 11;
} }
return 0; out:
mutex_unlock(&vblk->vdev_mutex);
return ret;
} }
static const struct block_device_operations virtblk_fops = { static const struct block_device_operations virtblk_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = virtblk_open,
.release = virtblk_release,
.getgeo = virtblk_getgeo, .getgeo = virtblk_getgeo,
}; };
@ -655,6 +720,10 @@ static int virtblk_probe(struct virtio_device *vdev)
goto out_free_index; goto out_free_index;
} }
/* This reference is dropped in virtblk_remove(). */
refcount_set(&vblk->refs, 1);
mutex_init(&vblk->vdev_mutex);
vblk->vdev = vdev; vblk->vdev = vdev;
vblk->sg_elems = sg_elems; vblk->sg_elems = sg_elems;
@ -820,8 +889,6 @@ out:
static void virtblk_remove(struct virtio_device *vdev) static void virtblk_remove(struct virtio_device *vdev)
{ {
struct virtio_blk *vblk = vdev->priv; struct virtio_blk *vblk = vdev->priv;
int index = vblk->index;
int refc;
/* Make sure no work handler is accessing the device. */ /* Make sure no work handler is accessing the device. */
flush_work(&vblk->config_work); flush_work(&vblk->config_work);
@ -831,18 +898,21 @@ static void virtblk_remove(struct virtio_device *vdev)
blk_mq_free_tag_set(&vblk->tag_set); blk_mq_free_tag_set(&vblk->tag_set);
mutex_lock(&vblk->vdev_mutex);
/* Stop all the virtqueues. */ /* Stop all the virtqueues. */
vdev->config->reset(vdev); vdev->config->reset(vdev);
refc = kref_read(&disk_to_dev(vblk->disk)->kobj.kref); /* Virtqueues are stopped, nothing can use vblk->vdev anymore. */
vblk->vdev = NULL;
put_disk(vblk->disk); put_disk(vblk->disk);
vdev->config->del_vqs(vdev); vdev->config->del_vqs(vdev);
kfree(vblk->vqs); kfree(vblk->vqs);
kfree(vblk);
/* Only free device id if we don't have any users */ mutex_unlock(&vblk->vdev_mutex);
if (refc == 1)
ida_simple_remove(&vd_index_ida, index); virtblk_put(vblk);
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP

View File

@ -812,10 +812,9 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
if (!mhi_cntrl) if (!mhi_cntrl)
return -EINVAL; return -EINVAL;
if (!mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put) if (!mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put ||
return -EINVAL; !mhi_cntrl->status_cb || !mhi_cntrl->read_reg ||
!mhi_cntrl->write_reg)
if (!mhi_cntrl->status_cb || !mhi_cntrl->link_status)
return -EINVAL; return -EINVAL;
ret = parse_config(mhi_cntrl, config); ret = parse_config(mhi_cntrl, config);

View File

@ -11,9 +11,6 @@
extern struct bus_type mhi_bus_type; extern struct bus_type mhi_bus_type;
/* MHI MMIO register mapping */
#define PCI_INVALID_READ(val) (val == U32_MAX)
#define MHIREGLEN (0x0) #define MHIREGLEN (0x0)
#define MHIREGLEN_MHIREGLEN_MASK (0xFFFFFFFF) #define MHIREGLEN_MHIREGLEN_MASK (0xFFFFFFFF)
#define MHIREGLEN_MHIREGLEN_SHIFT (0) #define MHIREGLEN_MHIREGLEN_SHIFT (0)

View File

@ -18,16 +18,7 @@
int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl, int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl,
void __iomem *base, u32 offset, u32 *out) void __iomem *base, u32 offset, u32 *out)
{ {
u32 tmp = readl(base + offset); return mhi_cntrl->read_reg(mhi_cntrl, base + offset, out);
/* If there is any unexpected value, query the link status */
if (PCI_INVALID_READ(tmp) &&
mhi_cntrl->link_status(mhi_cntrl))
return -EIO;
*out = tmp;
return 0;
} }
int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl, int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl,
@ -49,7 +40,7 @@ int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl,
void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base, void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base,
u32 offset, u32 val) u32 offset, u32 val)
{ {
writel(val, base + offset); mhi_cntrl->write_reg(mhi_cntrl, base + offset, val);
} }
void mhi_write_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base, void mhi_write_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base,
@ -294,7 +285,7 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl)
!(mhi_chan->ee_mask & BIT(mhi_cntrl->ee))) !(mhi_chan->ee_mask & BIT(mhi_cntrl->ee)))
continue; continue;
mhi_dev = mhi_alloc_device(mhi_cntrl); mhi_dev = mhi_alloc_device(mhi_cntrl);
if (!mhi_dev) if (IS_ERR(mhi_dev))
return; return;
mhi_dev->dev_type = MHI_DEVICE_XFER; mhi_dev->dev_type = MHI_DEVICE_XFER;
@ -336,7 +327,8 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl)
/* Channel name is same for both UL and DL */ /* Channel name is same for both UL and DL */
mhi_dev->chan_name = mhi_chan->name; mhi_dev->chan_name = mhi_chan->name;
dev_set_name(&mhi_dev->dev, "%04x_%s", mhi_chan->chan, dev_set_name(&mhi_dev->dev, "%s_%s",
dev_name(mhi_cntrl->cntrl_dev),
mhi_dev->chan_name); mhi_dev->chan_name);
/* Init wakeup source if available */ /* Init wakeup source if available */

View File

@ -902,7 +902,11 @@ int mhi_sync_power_up(struct mhi_controller *mhi_cntrl)
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
msecs_to_jiffies(mhi_cntrl->timeout_ms)); msecs_to_jiffies(mhi_cntrl->timeout_ms));
return (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -EIO; ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -ETIMEDOUT;
if (ret)
mhi_power_down(mhi_cntrl, false);
return ret;
} }
EXPORT_SYMBOL(mhi_sync_power_up); EXPORT_SYMBOL(mhi_sync_power_up);

View File

@ -1059,7 +1059,7 @@ static ssize_t store_no_turbo(struct kobject *a, struct kobj_attribute *b,
update_turbo_state(); update_turbo_state();
if (global.turbo_disabled) { if (global.turbo_disabled) {
pr_warn("Turbo disabled by BIOS or unavailable on processor\n"); pr_notice_once("Turbo disabled by BIOS or unavailable on processor\n");
mutex_unlock(&intel_pstate_limits_lock); mutex_unlock(&intel_pstate_limits_lock);
mutex_unlock(&intel_pstate_driver_lock); mutex_unlock(&intel_pstate_driver_lock);
return -EPERM; return -EPERM;

View File

@ -963,10 +963,12 @@ static void aead_crypt_done(struct device *jrdev, u32 *desc, u32 err,
struct caam_drv_private_jr *jrp = dev_get_drvdata(jrdev); struct caam_drv_private_jr *jrp = dev_get_drvdata(jrdev);
struct aead_edesc *edesc; struct aead_edesc *edesc;
int ecode = 0; int ecode = 0;
bool has_bklog;
dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
edesc = rctx->edesc; edesc = rctx->edesc;
has_bklog = edesc->bklog;
if (err) if (err)
ecode = caam_jr_strstatus(jrdev, err); ecode = caam_jr_strstatus(jrdev, err);
@ -979,7 +981,7 @@ static void aead_crypt_done(struct device *jrdev, u32 *desc, u32 err,
* If no backlog flag, the completion of the request is done * If no backlog flag, the completion of the request is done
* by CAAM, not crypto engine. * by CAAM, not crypto engine.
*/ */
if (!edesc->bklog) if (!has_bklog)
aead_request_complete(req, ecode); aead_request_complete(req, ecode);
else else
crypto_finalize_aead_request(jrp->engine, req, ecode); crypto_finalize_aead_request(jrp->engine, req, ecode);
@ -995,10 +997,12 @@ static void skcipher_crypt_done(struct device *jrdev, u32 *desc, u32 err,
struct caam_drv_private_jr *jrp = dev_get_drvdata(jrdev); struct caam_drv_private_jr *jrp = dev_get_drvdata(jrdev);
int ivsize = crypto_skcipher_ivsize(skcipher); int ivsize = crypto_skcipher_ivsize(skcipher);
int ecode = 0; int ecode = 0;
bool has_bklog;
dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
edesc = rctx->edesc; edesc = rctx->edesc;
has_bklog = edesc->bklog;
if (err) if (err)
ecode = caam_jr_strstatus(jrdev, err); ecode = caam_jr_strstatus(jrdev, err);
@ -1028,7 +1032,7 @@ static void skcipher_crypt_done(struct device *jrdev, u32 *desc, u32 err,
* If no backlog flag, the completion of the request is done * If no backlog flag, the completion of the request is done
* by CAAM, not crypto engine. * by CAAM, not crypto engine.
*/ */
if (!edesc->bklog) if (!has_bklog)
skcipher_request_complete(req, ecode); skcipher_request_complete(req, ecode);
else else
crypto_finalize_skcipher_request(jrp->engine, req, ecode); crypto_finalize_skcipher_request(jrp->engine, req, ecode);
@ -1711,7 +1715,7 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req,
if (ivsize || mapped_dst_nents > 1) if (ivsize || mapped_dst_nents > 1)
sg_to_sec4_set_last(edesc->sec4_sg + dst_sg_idx + sg_to_sec4_set_last(edesc->sec4_sg + dst_sg_idx +
mapped_dst_nents); mapped_dst_nents - 1 + !!ivsize);
if (sec4_sg_bytes) { if (sec4_sg_bytes) {
edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,

View File

@ -583,10 +583,12 @@ static inline void ahash_done_cpy(struct device *jrdev, u32 *desc, u32 err,
struct caam_hash_state *state = ahash_request_ctx(req); struct caam_hash_state *state = ahash_request_ctx(req);
struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
int ecode = 0; int ecode = 0;
bool has_bklog;
dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
edesc = state->edesc; edesc = state->edesc;
has_bklog = edesc->bklog;
if (err) if (err)
ecode = caam_jr_strstatus(jrdev, err); ecode = caam_jr_strstatus(jrdev, err);
@ -603,7 +605,7 @@ static inline void ahash_done_cpy(struct device *jrdev, u32 *desc, u32 err,
* If no backlog flag, the completion of the request is done * If no backlog flag, the completion of the request is done
* by CAAM, not crypto engine. * by CAAM, not crypto engine.
*/ */
if (!edesc->bklog) if (!has_bklog)
req->base.complete(&req->base, ecode); req->base.complete(&req->base, ecode);
else else
crypto_finalize_hash_request(jrp->engine, req, ecode); crypto_finalize_hash_request(jrp->engine, req, ecode);
@ -632,10 +634,12 @@ static inline void ahash_done_switch(struct device *jrdev, u32 *desc, u32 err,
struct caam_hash_state *state = ahash_request_ctx(req); struct caam_hash_state *state = ahash_request_ctx(req);
int digestsize = crypto_ahash_digestsize(ahash); int digestsize = crypto_ahash_digestsize(ahash);
int ecode = 0; int ecode = 0;
bool has_bklog;
dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
edesc = state->edesc; edesc = state->edesc;
has_bklog = edesc->bklog;
if (err) if (err)
ecode = caam_jr_strstatus(jrdev, err); ecode = caam_jr_strstatus(jrdev, err);
@ -663,7 +667,7 @@ static inline void ahash_done_switch(struct device *jrdev, u32 *desc, u32 err,
* If no backlog flag, the completion of the request is done * If no backlog flag, the completion of the request is done
* by CAAM, not crypto engine. * by CAAM, not crypto engine.
*/ */
if (!edesc->bklog) if (!has_bklog)
req->base.complete(&req->base, ecode); req->base.complete(&req->base, ecode);
else else
crypto_finalize_hash_request(jrp->engine, req, ecode); crypto_finalize_hash_request(jrp->engine, req, ecode);

View File

@ -121,11 +121,13 @@ static void rsa_pub_done(struct device *dev, u32 *desc, u32 err, void *context)
struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
struct rsa_edesc *edesc; struct rsa_edesc *edesc;
int ecode = 0; int ecode = 0;
bool has_bklog;
if (err) if (err)
ecode = caam_jr_strstatus(dev, err); ecode = caam_jr_strstatus(dev, err);
edesc = req_ctx->edesc; edesc = req_ctx->edesc;
has_bklog = edesc->bklog;
rsa_pub_unmap(dev, edesc, req); rsa_pub_unmap(dev, edesc, req);
rsa_io_unmap(dev, edesc, req); rsa_io_unmap(dev, edesc, req);
@ -135,7 +137,7 @@ static void rsa_pub_done(struct device *dev, u32 *desc, u32 err, void *context)
* If no backlog flag, the completion of the request is done * If no backlog flag, the completion of the request is done
* by CAAM, not crypto engine. * by CAAM, not crypto engine.
*/ */
if (!edesc->bklog) if (!has_bklog)
akcipher_request_complete(req, ecode); akcipher_request_complete(req, ecode);
else else
crypto_finalize_akcipher_request(jrp->engine, req, ecode); crypto_finalize_akcipher_request(jrp->engine, req, ecode);
@ -152,11 +154,13 @@ static void rsa_priv_f_done(struct device *dev, u32 *desc, u32 err,
struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req); struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req);
struct rsa_edesc *edesc; struct rsa_edesc *edesc;
int ecode = 0; int ecode = 0;
bool has_bklog;
if (err) if (err)
ecode = caam_jr_strstatus(dev, err); ecode = caam_jr_strstatus(dev, err);
edesc = req_ctx->edesc; edesc = req_ctx->edesc;
has_bklog = edesc->bklog;
switch (key->priv_form) { switch (key->priv_form) {
case FORM1: case FORM1:
@ -176,7 +180,7 @@ static void rsa_priv_f_done(struct device *dev, u32 *desc, u32 err,
* If no backlog flag, the completion of the request is done * If no backlog flag, the completion of the request is done
* by CAAM, not crypto engine. * by CAAM, not crypto engine.
*/ */
if (!edesc->bklog) if (!has_bklog)
akcipher_request_complete(req, ecode); akcipher_request_complete(req, ecode);
else else
crypto_finalize_akcipher_request(jrp->engine, req, ecode); crypto_finalize_akcipher_request(jrp->engine, req, ecode);

View File

@ -673,41 +673,14 @@ int chcr_ktls_cpl_set_tcb_rpl(struct adapter *adap, unsigned char *input)
return 0; return 0;
} }
/* static void *__chcr_write_cpl_set_tcb_ulp(struct chcr_ktls_info *tx_info,
* chcr_write_cpl_set_tcb_ulp: update tcb values. u32 tid, void *pos, u16 word, u64 mask,
* TCB is responsible to create tcp headers, so all the related values
* should be correctly updated.
* @tx_info - driver specific tls info.
* @q - tx queue on which packet is going out.
* @tid - TCB identifier.
* @pos - current index where should we start writing.
* @word - TCB word.
* @mask - TCB word related mask.
* @val - TCB word related value.
* @reply - set 1 if looking for TP response.
* return - next position to write.
*/
static void *chcr_write_cpl_set_tcb_ulp(struct chcr_ktls_info *tx_info,
struct sge_eth_txq *q, u32 tid,
void *pos, u16 word, u64 mask,
u64 val, u32 reply) u64 val, u32 reply)
{ {
struct cpl_set_tcb_field_core *cpl; struct cpl_set_tcb_field_core *cpl;
struct ulptx_idata *idata; struct ulptx_idata *idata;
struct ulp_txpkt *txpkt; struct ulp_txpkt *txpkt;
void *save_pos = NULL;
u8 buf[48] = {0};
int left;
left = (void *)q->q.stat - pos;
if (unlikely(left < CHCR_SET_TCB_FIELD_LEN)) {
if (!left) {
pos = q->q.desc;
} else {
save_pos = pos;
pos = buf;
}
}
/* ULP_TXPKT */ /* ULP_TXPKT */
txpkt = pos; txpkt = pos;
txpkt->cmd_dest = htonl(ULPTX_CMD_V(ULP_TX_PKT) | ULP_TXPKT_DEST_V(0)); txpkt->cmd_dest = htonl(ULPTX_CMD_V(ULP_TX_PKT) | ULP_TXPKT_DEST_V(0));
@ -732,18 +705,54 @@ static void *chcr_write_cpl_set_tcb_ulp(struct chcr_ktls_info *tx_info,
idata = (struct ulptx_idata *)(cpl + 1); idata = (struct ulptx_idata *)(cpl + 1);
idata->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_NOOP)); idata->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_NOOP));
idata->len = htonl(0); idata->len = htonl(0);
pos = idata + 1;
if (save_pos) { return pos;
pos = chcr_copy_to_txd(buf, &q->q, save_pos, }
CHCR_SET_TCB_FIELD_LEN);
} else {
/* check again if we are at the end of the queue */ /*
if (left == CHCR_SET_TCB_FIELD_LEN) * chcr_write_cpl_set_tcb_ulp: update tcb values.
* TCB is responsible to create tcp headers, so all the related values
* should be correctly updated.
* @tx_info - driver specific tls info.
* @q - tx queue on which packet is going out.
* @tid - TCB identifier.
* @pos - current index where should we start writing.
* @word - TCB word.
* @mask - TCB word related mask.
* @val - TCB word related value.
* @reply - set 1 if looking for TP response.
* return - next position to write.
*/
static void *chcr_write_cpl_set_tcb_ulp(struct chcr_ktls_info *tx_info,
struct sge_eth_txq *q, u32 tid,
void *pos, u16 word, u64 mask,
u64 val, u32 reply)
{
int left = (void *)q->q.stat - pos;
if (unlikely(left < CHCR_SET_TCB_FIELD_LEN)) {
if (!left) {
pos = q->q.desc; pos = q->q.desc;
else } else {
pos = idata + 1; u8 buf[48] = {0};
__chcr_write_cpl_set_tcb_ulp(tx_info, tid, buf, word,
mask, val, reply);
return chcr_copy_to_txd(buf, &q->q, pos,
CHCR_SET_TCB_FIELD_LEN);
}
} }
pos = __chcr_write_cpl_set_tcb_ulp(tx_info, tid, pos, word,
mask, val, reply);
/* check again if we are at the end of the queue */
if (left == CHCR_SET_TCB_FIELD_LEN)
pos = q->q.desc;
return pos; return pos;
} }

View File

@ -388,7 +388,8 @@ static long dma_buf_ioctl(struct file *file,
return ret; return ret;
case DMA_BUF_SET_NAME: case DMA_BUF_SET_NAME_A:
case DMA_BUF_SET_NAME_B:
return dma_buf_set_name(dmabuf, (const char __user *)arg); return dma_buf_set_name(dmabuf, (const char __user *)arg);
default: default:
@ -655,8 +656,8 @@ EXPORT_SYMBOL_GPL(dma_buf_put);
* calls attach() of dma_buf_ops to allow device-specific attach functionality * calls attach() of dma_buf_ops to allow device-specific attach functionality
* @dmabuf: [in] buffer to attach device to. * @dmabuf: [in] buffer to attach device to.
* @dev: [in] device to be attached. * @dev: [in] device to be attached.
* @importer_ops [in] importer operations for the attachment * @importer_ops: [in] importer operations for the attachment
* @importer_priv [in] importer private pointer for the attachment * @importer_priv: [in] importer private pointer for the attachment
* *
* Returns struct dma_buf_attachment pointer for this attachment. Attachments * Returns struct dma_buf_attachment pointer for this attachment. Attachments
* must be cleaned up by calling dma_buf_detach(). * must be cleaned up by calling dma_buf_detach().

View File

@ -241,7 +241,8 @@ config FSL_RAID
config HISI_DMA config HISI_DMA
tristate "HiSilicon DMA Engine support" tristate "HiSilicon DMA Engine support"
depends on ARM64 || (COMPILE_TEST && PCI_MSI) depends on ARM64 || COMPILE_TEST
depends on PCI_MSI
select DMA_ENGINE select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS select DMA_VIRTUAL_CHANNELS
help help

View File

@ -232,10 +232,6 @@ static void chan_dev_release(struct device *dev)
struct dma_chan_dev *chan_dev; struct dma_chan_dev *chan_dev;
chan_dev = container_of(dev, typeof(*chan_dev), device); chan_dev = container_of(dev, typeof(*chan_dev), device);
if (atomic_dec_and_test(chan_dev->idr_ref)) {
ida_free(&dma_ida, chan_dev->dev_id);
kfree(chan_dev->idr_ref);
}
kfree(chan_dev); kfree(chan_dev);
} }
@ -1043,27 +1039,9 @@ static int get_dma_id(struct dma_device *device)
} }
static int __dma_async_device_channel_register(struct dma_device *device, static int __dma_async_device_channel_register(struct dma_device *device,
struct dma_chan *chan, struct dma_chan *chan)
int chan_id)
{ {
int rc = 0; int rc = 0;
int chancnt = device->chancnt;
atomic_t *idr_ref;
struct dma_chan *tchan;
tchan = list_first_entry_or_null(&device->channels,
struct dma_chan, device_node);
if (!tchan)
return -ENODEV;
if (tchan->dev) {
idr_ref = tchan->dev->idr_ref;
} else {
idr_ref = kmalloc(sizeof(*idr_ref), GFP_KERNEL);
if (!idr_ref)
return -ENOMEM;
atomic_set(idr_ref, 0);
}
chan->local = alloc_percpu(typeof(*chan->local)); chan->local = alloc_percpu(typeof(*chan->local));
if (!chan->local) if (!chan->local)
@ -1079,29 +1057,36 @@ static int __dma_async_device_channel_register(struct dma_device *device,
* When the chan_id is a negative value, we are dynamically adding * When the chan_id is a negative value, we are dynamically adding
* the channel. Otherwise we are static enumerating. * the channel. Otherwise we are static enumerating.
*/ */
chan->chan_id = chan_id < 0 ? chancnt : chan_id; mutex_lock(&device->chan_mutex);
chan->chan_id = ida_alloc(&device->chan_ida, GFP_KERNEL);
mutex_unlock(&device->chan_mutex);
if (chan->chan_id < 0) {
pr_err("%s: unable to alloc ida for chan: %d\n",
__func__, chan->chan_id);
goto err_out;
}
chan->dev->device.class = &dma_devclass; chan->dev->device.class = &dma_devclass;
chan->dev->device.parent = device->dev; chan->dev->device.parent = device->dev;
chan->dev->chan = chan; chan->dev->chan = chan;
chan->dev->idr_ref = idr_ref;
chan->dev->dev_id = device->dev_id; chan->dev->dev_id = device->dev_id;
atomic_inc(idr_ref);
dev_set_name(&chan->dev->device, "dma%dchan%d", dev_set_name(&chan->dev->device, "dma%dchan%d",
device->dev_id, chan->chan_id); device->dev_id, chan->chan_id);
rc = device_register(&chan->dev->device); rc = device_register(&chan->dev->device);
if (rc) if (rc)
goto err_out; goto err_out_ida;
chan->client_count = 0; chan->client_count = 0;
device->chancnt = chan->chan_id + 1; device->chancnt++;
return 0; return 0;
err_out_ida:
mutex_lock(&device->chan_mutex);
ida_free(&device->chan_ida, chan->chan_id);
mutex_unlock(&device->chan_mutex);
err_out: err_out:
free_percpu(chan->local); free_percpu(chan->local);
kfree(chan->dev); kfree(chan->dev);
if (atomic_dec_return(idr_ref) == 0)
kfree(idr_ref);
return rc; return rc;
} }
@ -1110,7 +1095,7 @@ int dma_async_device_channel_register(struct dma_device *device,
{ {
int rc; int rc;
rc = __dma_async_device_channel_register(device, chan, -1); rc = __dma_async_device_channel_register(device, chan);
if (rc < 0) if (rc < 0)
return rc; return rc;
@ -1130,6 +1115,9 @@ static void __dma_async_device_channel_unregister(struct dma_device *device,
device->chancnt--; device->chancnt--;
chan->dev->chan = NULL; chan->dev->chan = NULL;
mutex_unlock(&dma_list_mutex); mutex_unlock(&dma_list_mutex);
mutex_lock(&device->chan_mutex);
ida_free(&device->chan_ida, chan->chan_id);
mutex_unlock(&device->chan_mutex);
device_unregister(&chan->dev->device); device_unregister(&chan->dev->device);
free_percpu(chan->local); free_percpu(chan->local);
} }
@ -1152,7 +1140,7 @@ EXPORT_SYMBOL_GPL(dma_async_device_channel_unregister);
*/ */
int dma_async_device_register(struct dma_device *device) int dma_async_device_register(struct dma_device *device)
{ {
int rc, i = 0; int rc;
struct dma_chan* chan; struct dma_chan* chan;
if (!device) if (!device)
@ -1257,9 +1245,12 @@ int dma_async_device_register(struct dma_device *device)
if (rc != 0) if (rc != 0)
return rc; return rc;
mutex_init(&device->chan_mutex);
ida_init(&device->chan_ida);
/* represent channels in sysfs. Probably want devs too */ /* represent channels in sysfs. Probably want devs too */
list_for_each_entry(chan, &device->channels, device_node) { list_for_each_entry(chan, &device->channels, device_node) {
rc = __dma_async_device_channel_register(device, chan, i++); rc = __dma_async_device_channel_register(device, chan);
if (rc < 0) if (rc < 0)
goto err_out; goto err_out;
} }
@ -1334,6 +1325,7 @@ void dma_async_device_unregister(struct dma_device *device)
*/ */
dma_cap_set(DMA_PRIVATE, device->cap_mask); dma_cap_set(DMA_PRIVATE, device->cap_mask);
dma_channel_rebalance(); dma_channel_rebalance();
ida_free(&dma_ida, device->dev_id);
dma_device_put(device); dma_device_put(device);
mutex_unlock(&dma_list_mutex); mutex_unlock(&dma_list_mutex);
} }

View File

@ -240,7 +240,7 @@ static bool is_threaded_test_run(struct dmatest_info *info)
struct dmatest_thread *thread; struct dmatest_thread *thread;
list_for_each_entry(thread, &dtc->threads, node) { list_for_each_entry(thread, &dtc->threads, node) {
if (!thread->done) if (!thread->done && !thread->pending)
return true; return true;
} }
} }
@ -662,8 +662,8 @@ static int dmatest_func(void *data)
flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
ktime = ktime_get(); ktime = ktime_get();
while (!kthread_should_stop() while (!(kthread_should_stop() ||
&& !(params->iterations && total_tests >= params->iterations)) { (params->iterations && total_tests >= params->iterations))) {
struct dma_async_tx_descriptor *tx = NULL; struct dma_async_tx_descriptor *tx = NULL;
struct dmaengine_unmap_data *um; struct dmaengine_unmap_data *um;
dma_addr_t *dsts; dma_addr_t *dsts;

View File

@ -363,6 +363,8 @@ static void mmp_tdma_free_descriptor(struct mmp_tdma_chan *tdmac)
gen_pool_free(gpool, (unsigned long)tdmac->desc_arr, gen_pool_free(gpool, (unsigned long)tdmac->desc_arr,
size); size);
tdmac->desc_arr = NULL; tdmac->desc_arr = NULL;
if (tdmac->status == DMA_ERROR)
tdmac->status = DMA_COMPLETE;
return; return;
} }
@ -443,7 +445,8 @@ static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic(
if (!desc) if (!desc)
goto err_out; goto err_out;
mmp_tdma_config_write(chan, direction, &tdmac->slave_config); if (mmp_tdma_config_write(chan, direction, &tdmac->slave_config))
goto err_out;
while (buf < buf_len) { while (buf < buf_len) {
desc = &tdmac->desc_arr[i]; desc = &tdmac->desc_arr[i];

View File

@ -865,6 +865,7 @@ static int pch_dma_probe(struct pci_dev *pdev,
} }
pci_set_master(pdev); pci_set_master(pdev);
pd->dma.dev = &pdev->dev;
err = request_irq(pdev->irq, pd_irq, IRQF_SHARED, DRV_NAME, pd); err = request_irq(pdev->irq, pd_irq, IRQF_SHARED, DRV_NAME, pd);
if (err) { if (err) {
@ -880,7 +881,6 @@ static int pch_dma_probe(struct pci_dev *pdev,
goto err_free_irq; goto err_free_irq;
} }
pd->dma.dev = &pdev->dev;
INIT_LIST_HEAD(&pd->dma.channels); INIT_LIST_HEAD(&pd->dma.channels);

View File

@ -816,6 +816,13 @@ static bool tegra_dma_eoc_interrupt_deasserted(struct tegra_dma_channel *tdc)
static void tegra_dma_synchronize(struct dma_chan *dc) static void tegra_dma_synchronize(struct dma_chan *dc)
{ {
struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
int err;
err = pm_runtime_get_sync(tdc->tdma->dev);
if (err < 0) {
dev_err(tdc2dev(tdc), "Failed to synchronize DMA: %d\n", err);
return;
}
/* /*
* CPU, which handles interrupt, could be busy in * CPU, which handles interrupt, could be busy in
@ -825,6 +832,8 @@ static void tegra_dma_synchronize(struct dma_chan *dc)
wait_event(tdc->wq, tegra_dma_eoc_interrupt_deasserted(tdc)); wait_event(tdc->wq, tegra_dma_eoc_interrupt_deasserted(tdc));
tasklet_kill(&tdc->tasklet); tasklet_kill(&tdc->tasklet);
pm_runtime_put(tdc->tdma->dev);
} }
static unsigned int tegra_dma_sg_bytes_xferred(struct tegra_dma_channel *tdc, static unsigned int tegra_dma_sg_bytes_xferred(struct tegra_dma_channel *tdc,

View File

@ -27,6 +27,7 @@ struct psil_endpoint_config *psil_get_ep_config(u32 thread_id)
soc_ep_map = &j721e_ep_map; soc_ep_map = &j721e_ep_map;
} else { } else {
pr_err("PSIL: No compatible machine found for map\n"); pr_err("PSIL: No compatible machine found for map\n");
mutex_unlock(&ep_map_mutex);
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-ENOTSUPP);
} }
pr_debug("%s: Using map for %s\n", __func__, soc_ep_map->name); pr_debug("%s: Using map for %s\n", __func__, soc_ep_map->name);

View File

@ -1230,16 +1230,16 @@ static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan,
return ret; return ret;
spin_lock_irqsave(&chan->lock, flags); spin_lock_irqsave(&chan->lock, flags);
if (!list_empty(&chan->active_list)) {
desc = list_last_entry(&chan->active_list, desc = list_last_entry(&chan->active_list,
struct xilinx_dma_tx_descriptor, node); struct xilinx_dma_tx_descriptor, node);
/* /*
* VDMA and simple mode do not support residue reporting, so the * VDMA and simple mode do not support residue reporting, so the
* residue field will always be 0. * residue field will always be 0.
*/ */
if (chan->has_sg && chan->xdev->dma_config->dmatype != XDMA_TYPE_VDMA) if (chan->has_sg && chan->xdev->dma_config->dmatype != XDMA_TYPE_VDMA)
residue = xilinx_dma_get_residue(chan, desc); residue = xilinx_dma_get_residue(chan, desc);
}
spin_unlock_irqrestore(&chan->lock, flags); spin_unlock_irqrestore(&chan->lock, flags);
dma_set_residue(txstate, residue); dma_set_residue(txstate, residue);

View File

@ -16,7 +16,7 @@
int efi_tpm_final_log_size; int efi_tpm_final_log_size;
EXPORT_SYMBOL(efi_tpm_final_log_size); EXPORT_SYMBOL(efi_tpm_final_log_size);
static int tpm2_calc_event_log_size(void *data, int count, void *size_info) static int __init tpm2_calc_event_log_size(void *data, int count, void *size_info)
{ {
struct tcg_pcr_event2_head *header; struct tcg_pcr_event2_head *header;
int event_size, size = 0; int event_size, size = 0;

View File

@ -3372,15 +3372,12 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon)
} }
} }
amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
amdgpu_amdkfd_suspend(adev, !fbcon);
amdgpu_ras_suspend(adev); amdgpu_ras_suspend(adev);
r = amdgpu_device_ip_suspend_phase1(adev); r = amdgpu_device_ip_suspend_phase1(adev);
amdgpu_amdkfd_suspend(adev, !fbcon);
/* evict vram memory */ /* evict vram memory */
amdgpu_bo_evict_vram(adev); amdgpu_bo_evict_vram(adev);

View File

@ -85,9 +85,10 @@
* - 3.34.0 - Non-DC can flip correctly between buffers with different pitches * - 3.34.0 - Non-DC can flip correctly between buffers with different pitches
* - 3.35.0 - Add drm_amdgpu_info_device::tcc_disabled_mask * - 3.35.0 - Add drm_amdgpu_info_device::tcc_disabled_mask
* - 3.36.0 - Allow reading more status registers on si/cik * - 3.36.0 - Allow reading more status registers on si/cik
* - 3.37.0 - L2 is invalidated before SDMA IBs, needed for correctness
*/ */
#define KMS_DRIVER_MAJOR 3 #define KMS_DRIVER_MAJOR 3
#define KMS_DRIVER_MINOR 36 #define KMS_DRIVER_MINOR 37
#define KMS_DRIVER_PATCHLEVEL 0 #define KMS_DRIVER_PATCHLEVEL 0
int amdgpu_vram_limit = 0; int amdgpu_vram_limit = 0;

View File

@ -73,6 +73,22 @@
#define SDMA_OP_AQL_COPY 0 #define SDMA_OP_AQL_COPY 0
#define SDMA_OP_AQL_BARRIER_OR 0 #define SDMA_OP_AQL_BARRIER_OR 0
#define SDMA_GCR_RANGE_IS_PA (1 << 18)
#define SDMA_GCR_SEQ(x) (((x) & 0x3) << 16)
#define SDMA_GCR_GL2_WB (1 << 15)
#define SDMA_GCR_GL2_INV (1 << 14)
#define SDMA_GCR_GL2_DISCARD (1 << 13)
#define SDMA_GCR_GL2_RANGE(x) (((x) & 0x3) << 11)
#define SDMA_GCR_GL2_US (1 << 10)
#define SDMA_GCR_GL1_INV (1 << 9)
#define SDMA_GCR_GLV_INV (1 << 8)
#define SDMA_GCR_GLK_INV (1 << 7)
#define SDMA_GCR_GLK_WB (1 << 6)
#define SDMA_GCR_GLM_INV (1 << 5)
#define SDMA_GCR_GLM_WB (1 << 4)
#define SDMA_GCR_GL1_RANGE(x) (((x) & 0x3) << 2)
#define SDMA_GCR_GLI_INV(x) (((x) & 0x3) << 0)
/*define for op field*/ /*define for op field*/
#define SDMA_PKT_HEADER_op_offset 0 #define SDMA_PKT_HEADER_op_offset 0
#define SDMA_PKT_HEADER_op_mask 0x000000FF #define SDMA_PKT_HEADER_op_mask 0x000000FF

View File

@ -382,6 +382,18 @@ static void sdma_v5_0_ring_emit_ib(struct amdgpu_ring *ring,
unsigned vmid = AMDGPU_JOB_GET_VMID(job); unsigned vmid = AMDGPU_JOB_GET_VMID(job);
uint64_t csa_mc_addr = amdgpu_sdma_get_csa_mc_addr(ring, vmid); uint64_t csa_mc_addr = amdgpu_sdma_get_csa_mc_addr(ring, vmid);
/* Invalidate L2, because if we don't do it, we might get stale cache
* lines from previous IBs.
*/
amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_GCR_REQ));
amdgpu_ring_write(ring, 0);
amdgpu_ring_write(ring, (SDMA_GCR_GL2_INV |
SDMA_GCR_GL2_WB |
SDMA_GCR_GLM_INV |
SDMA_GCR_GLM_WB) << 16);
amdgpu_ring_write(ring, 0xffffff80);
amdgpu_ring_write(ring, 0xffff);
/* An IB packet must end on a 8 DW boundary--the next dword /* An IB packet must end on a 8 DW boundary--the next dword
* must be on a 8-dword boundary. Our IB packet below is 6 * must be on a 8-dword boundary. Our IB packet below is 6
* dwords long, thus add x number of NOPs, such that, in * dwords long, thus add x number of NOPs, such that, in
@ -1595,7 +1607,7 @@ static const struct amdgpu_ring_funcs sdma_v5_0_ring_funcs = {
SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 + SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 +
SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 6 * 2 + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 6 * 2 +
10 + 10 + 10, /* sdma_v5_0_ring_emit_fence x3 for user fence, vm fence */ 10 + 10 + 10, /* sdma_v5_0_ring_emit_fence x3 for user fence, vm fence */
.emit_ib_size = 7 + 6, /* sdma_v5_0_ring_emit_ib */ .emit_ib_size = 5 + 7 + 6, /* sdma_v5_0_ring_emit_ib */
.emit_ib = sdma_v5_0_ring_emit_ib, .emit_ib = sdma_v5_0_ring_emit_ib,
.emit_fence = sdma_v5_0_ring_emit_fence, .emit_fence = sdma_v5_0_ring_emit_fence,
.emit_pipeline_sync = sdma_v5_0_ring_emit_pipeline_sync, .emit_pipeline_sync = sdma_v5_0_ring_emit_pipeline_sync,

View File

@ -2008,17 +2008,22 @@ void amdgpu_dm_update_connector_after_detect(
dc_sink_retain(aconnector->dc_sink); dc_sink_retain(aconnector->dc_sink);
if (sink->dc_edid.length == 0) { if (sink->dc_edid.length == 0) {
aconnector->edid = NULL; aconnector->edid = NULL;
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); if (aconnector->dc_link->aux_mode) {
drm_dp_cec_unset_edid(
&aconnector->dm_dp_aux.aux);
}
} else { } else {
aconnector->edid = aconnector->edid =
(struct edid *) sink->dc_edid.raw_edid; (struct edid *)sink->dc_edid.raw_edid;
drm_connector_update_edid_property(connector, drm_connector_update_edid_property(connector,
aconnector->edid); aconnector->edid);
drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
aconnector->edid); if (aconnector->dc_link->aux_mode)
drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
aconnector->edid);
} }
amdgpu_dm_update_freesync_caps(connector, aconnector->edid); amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
update_connector_ext_caps(aconnector); update_connector_ext_caps(aconnector);
} else { } else {
@ -3340,7 +3345,8 @@ fill_plane_dcc_attributes(struct amdgpu_device *adev,
const union dc_tiling_info *tiling_info, const union dc_tiling_info *tiling_info,
const uint64_t info, const uint64_t info,
struct dc_plane_dcc_param *dcc, struct dc_plane_dcc_param *dcc,
struct dc_plane_address *address) struct dc_plane_address *address,
bool force_disable_dcc)
{ {
struct dc *dc = adev->dm.dc; struct dc *dc = adev->dm.dc;
struct dc_dcc_surface_param input; struct dc_dcc_surface_param input;
@ -3352,6 +3358,9 @@ fill_plane_dcc_attributes(struct amdgpu_device *adev,
memset(&input, 0, sizeof(input)); memset(&input, 0, sizeof(input));
memset(&output, 0, sizeof(output)); memset(&output, 0, sizeof(output));
if (force_disable_dcc)
return 0;
if (!offset) if (!offset)
return 0; return 0;
@ -3401,7 +3410,8 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev,
union dc_tiling_info *tiling_info, union dc_tiling_info *tiling_info,
struct plane_size *plane_size, struct plane_size *plane_size,
struct dc_plane_dcc_param *dcc, struct dc_plane_dcc_param *dcc,
struct dc_plane_address *address) struct dc_plane_address *address,
bool force_disable_dcc)
{ {
const struct drm_framebuffer *fb = &afb->base; const struct drm_framebuffer *fb = &afb->base;
int ret; int ret;
@ -3507,7 +3517,8 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev,
ret = fill_plane_dcc_attributes(adev, afb, format, rotation, ret = fill_plane_dcc_attributes(adev, afb, format, rotation,
plane_size, tiling_info, plane_size, tiling_info,
tiling_flags, dcc, address); tiling_flags, dcc, address,
force_disable_dcc);
if (ret) if (ret)
return ret; return ret;
} }
@ -3599,7 +3610,8 @@ fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
const struct drm_plane_state *plane_state, const struct drm_plane_state *plane_state,
const uint64_t tiling_flags, const uint64_t tiling_flags,
struct dc_plane_info *plane_info, struct dc_plane_info *plane_info,
struct dc_plane_address *address) struct dc_plane_address *address,
bool force_disable_dcc)
{ {
const struct drm_framebuffer *fb = plane_state->fb; const struct drm_framebuffer *fb = plane_state->fb;
const struct amdgpu_framebuffer *afb = const struct amdgpu_framebuffer *afb =
@ -3681,7 +3693,8 @@ fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
plane_info->rotation, tiling_flags, plane_info->rotation, tiling_flags,
&plane_info->tiling_info, &plane_info->tiling_info,
&plane_info->plane_size, &plane_info->plane_size,
&plane_info->dcc, address); &plane_info->dcc, address,
force_disable_dcc);
if (ret) if (ret)
return ret; return ret;
@ -3704,6 +3717,7 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,
struct dc_plane_info plane_info; struct dc_plane_info plane_info;
uint64_t tiling_flags; uint64_t tiling_flags;
int ret; int ret;
bool force_disable_dcc = false;
ret = fill_dc_scaling_info(plane_state, &scaling_info); ret = fill_dc_scaling_info(plane_state, &scaling_info);
if (ret) if (ret)
@ -3718,9 +3732,11 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,
if (ret) if (ret)
return ret; return ret;
force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;
ret = fill_dc_plane_info_and_addr(adev, plane_state, tiling_flags, ret = fill_dc_plane_info_and_addr(adev, plane_state, tiling_flags,
&plane_info, &plane_info,
&dc_plane_state->address); &dc_plane_state->address,
force_disable_dcc);
if (ret) if (ret)
return ret; return ret;
@ -5342,6 +5358,7 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
uint64_t tiling_flags; uint64_t tiling_flags;
uint32_t domain; uint32_t domain;
int r; int r;
bool force_disable_dcc = false;
dm_plane_state_old = to_dm_plane_state(plane->state); dm_plane_state_old = to_dm_plane_state(plane->state);
dm_plane_state_new = to_dm_plane_state(new_state); dm_plane_state_new = to_dm_plane_state(new_state);
@ -5400,11 +5417,13 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) { dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) {
struct dc_plane_state *plane_state = dm_plane_state_new->dc_state; struct dc_plane_state *plane_state = dm_plane_state_new->dc_state;
force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;
fill_plane_buffer_attributes( fill_plane_buffer_attributes(
adev, afb, plane_state->format, plane_state->rotation, adev, afb, plane_state->format, plane_state->rotation,
tiling_flags, &plane_state->tiling_info, tiling_flags, &plane_state->tiling_info,
&plane_state->plane_size, &plane_state->dcc, &plane_state->plane_size, &plane_state->dcc,
&plane_state->address); &plane_state->address,
force_disable_dcc);
} }
return 0; return 0;
@ -6676,7 +6695,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
fill_dc_plane_info_and_addr( fill_dc_plane_info_and_addr(
dm->adev, new_plane_state, tiling_flags, dm->adev, new_plane_state, tiling_flags,
&bundle->plane_infos[planes_count], &bundle->plane_infos[planes_count],
&bundle->flip_addrs[planes_count].address); &bundle->flip_addrs[planes_count].address,
false);
DRM_DEBUG_DRIVER("plane: id=%d dcc_en=%d\n",
new_plane_state->plane->index,
bundle->plane_infos[planes_count].dcc.enable);
bundle->surface_updates[planes_count].plane_info = bundle->surface_updates[planes_count].plane_info =
&bundle->plane_infos[planes_count]; &bundle->plane_infos[planes_count];
@ -8096,7 +8120,8 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm,
ret = fill_dc_plane_info_and_addr( ret = fill_dc_plane_info_and_addr(
dm->adev, new_plane_state, tiling_flags, dm->adev, new_plane_state, tiling_flags,
plane_info, plane_info,
&flip_addr->address); &flip_addr->address,
false);
if (ret) if (ret)
goto cleanup; goto cleanup;

View File

@ -834,11 +834,10 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
static void wait_for_no_pipes_pending(struct dc *dc, struct dc_state *context) static void wait_for_no_pipes_pending(struct dc *dc, struct dc_state *context)
{ {
int i; int i;
int count = 0;
struct pipe_ctx *pipe;
PERF_TRACE(); PERF_TRACE();
for (i = 0; i < MAX_PIPES; i++) { for (i = 0; i < MAX_PIPES; i++) {
pipe = &context->res_ctx.pipe_ctx[i]; int count = 0;
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
if (!pipe->plane_state) if (!pipe->plane_state)
continue; continue;

View File

@ -2908,6 +2908,12 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd
sizeof(hpd_irq_dpcd_data), sizeof(hpd_irq_dpcd_data),
"Status: "); "Status: ");
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link)
link->dc->hwss.blank_stream(pipe_ctx);
}
for (i = 0; i < MAX_PIPES; i++) { for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link) if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link)
@ -2927,6 +2933,12 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
dc_link_reallocate_mst_payload(link); dc_link_reallocate_mst_payload(link);
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link)
link->dc->hwss.unblank_stream(pipe_ctx, &previous_link_settings);
}
status = false; status = false;
if (out_link_loss) if (out_link_loss)
*out_link_loss = true; *out_link_loss = true;
@ -4227,6 +4239,21 @@ void dp_set_fec_enable(struct dc_link *link, bool enable)
void dpcd_set_source_specific_data(struct dc_link *link) void dpcd_set_source_specific_data(struct dc_link *link)
{ {
const uint32_t post_oui_delay = 30; // 30ms const uint32_t post_oui_delay = 30; // 30ms
uint8_t dspc = 0;
enum dc_status ret = DC_ERROR_UNEXPECTED;
ret = core_link_read_dpcd(link, DP_DOWN_STREAM_PORT_COUNT, &dspc,
sizeof(dspc));
if (ret != DC_OK) {
DC_LOG_ERROR("Error in DP aux read transaction,"
" not writing source specific data\n");
return;
}
/* Return if OUI unsupported */
if (!(dspc & DP_OUI_SUPPORT))
return;
if (!link->dc->vendor_signature.is_valid) { if (!link->dc->vendor_signature.is_valid) {
struct dpcd_amd_signature amd_signature; struct dpcd_amd_signature amd_signature;

View File

@ -231,34 +231,6 @@ struct dc_stream_status *dc_stream_get_status(
return dc_stream_get_status_from_state(dc->current_state, stream); return dc_stream_get_status_from_state(dc->current_state, stream);
} }
static void delay_cursor_until_vupdate(struct pipe_ctx *pipe_ctx, struct dc *dc)
{
#if defined(CONFIG_DRM_AMD_DC_DCN)
unsigned int vupdate_line;
unsigned int lines_to_vupdate, us_to_vupdate, vpos, nvpos;
struct dc_stream_state *stream = pipe_ctx->stream;
unsigned int us_per_line;
if (stream->ctx->asic_id.chip_family == FAMILY_RV &&
ASICREV_IS_RAVEN(stream->ctx->asic_id.hw_internal_rev)) {
vupdate_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx);
if (!dc_stream_get_crtc_position(dc, &stream, 1, &vpos, &nvpos))
return;
if (vpos >= vupdate_line)
return;
us_per_line = stream->timing.h_total * 10000 / stream->timing.pix_clk_100hz;
lines_to_vupdate = vupdate_line - vpos;
us_to_vupdate = lines_to_vupdate * us_per_line;
/* 70 us is a conservative estimate of cursor update time*/
if (us_to_vupdate < 70)
udelay(us_to_vupdate);
}
#endif
}
/** /**
* dc_stream_set_cursor_attributes() - Update cursor attributes and set cursor surface address * dc_stream_set_cursor_attributes() - Update cursor attributes and set cursor surface address
@ -298,9 +270,7 @@ bool dc_stream_set_cursor_attributes(
if (!pipe_to_program) { if (!pipe_to_program) {
pipe_to_program = pipe_ctx; pipe_to_program = pipe_ctx;
dc->hwss.cursor_lock(dc, pipe_to_program, true);
delay_cursor_until_vupdate(pipe_ctx, dc);
dc->hwss.pipe_control_lock(dc, pipe_to_program, true);
} }
dc->hwss.set_cursor_attribute(pipe_ctx); dc->hwss.set_cursor_attribute(pipe_ctx);
@ -309,7 +279,7 @@ bool dc_stream_set_cursor_attributes(
} }
if (pipe_to_program) if (pipe_to_program)
dc->hwss.pipe_control_lock(dc, pipe_to_program, false); dc->hwss.cursor_lock(dc, pipe_to_program, false);
return true; return true;
} }
@ -349,16 +319,14 @@ bool dc_stream_set_cursor_position(
if (!pipe_to_program) { if (!pipe_to_program) {
pipe_to_program = pipe_ctx; pipe_to_program = pipe_ctx;
dc->hwss.cursor_lock(dc, pipe_to_program, true);
delay_cursor_until_vupdate(pipe_ctx, dc);
dc->hwss.pipe_control_lock(dc, pipe_to_program, true);
} }
dc->hwss.set_cursor_position(pipe_ctx); dc->hwss.set_cursor_position(pipe_ctx);
} }
if (pipe_to_program) if (pipe_to_program)
dc->hwss.pipe_control_lock(dc, pipe_to_program, false); dc->hwss.cursor_lock(dc, pipe_to_program, false);
return true; return true;
} }

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