Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Move the bpf verifier trace check into the new switch statement in HEAD. Resolve the overlapping changes in hinic, where bug fixes overlap the addition of VF support. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
da07f52d3c
|
@ -112,6 +112,20 @@ used when printing stack backtraces. The specifier takes into
|
|||
consideration the effect of compiler optimisations which may occur
|
||||
when tail-calls are used and marked with the noreturn GCC attribute.
|
||||
|
||||
Probed Pointers from BPF / tracing
|
||||
----------------------------------
|
||||
|
||||
::
|
||||
|
||||
%pks kernel string
|
||||
%pus user string
|
||||
|
||||
The ``k`` and ``u`` specifiers are used for printing prior probed memory from
|
||||
either kernel memory (k) or user memory (u). The subsequent ``s`` specifier
|
||||
results in printing a string. For direct use in regular vsnprintf() the (k)
|
||||
and (u) annotation is ignored, however, when used out of BPF's bpf_trace_printk(),
|
||||
for example, it reads the memory it is pointing to without faulting.
|
||||
|
||||
Kernel Pointers
|
||||
---------------
|
||||
|
||||
|
|
|
@ -28,3 +28,5 @@ KVM
|
|||
arm/index
|
||||
|
||||
devices/index
|
||||
|
||||
running-nested-guests
|
||||
|
|
|
@ -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
|
19
MAINTAINERS
19
MAINTAINERS
|
@ -3936,11 +3936,9 @@ F: arch/powerpc/platforms/cell/
|
|||
CEPH COMMON CODE (LIBCEPH)
|
||||
M: Ilya Dryomov <idryomov@gmail.com>
|
||||
M: Jeff Layton <jlayton@kernel.org>
|
||||
M: Sage Weil <sage@redhat.com>
|
||||
L: ceph-devel@vger.kernel.org
|
||||
S: Supported
|
||||
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
|
||||
F: include/linux/ceph/
|
||||
F: include/linux/crush/
|
||||
|
@ -3948,12 +3946,10 @@ F: net/ceph/
|
|||
|
||||
CEPH DISTRIBUTED FILE SYSTEM CLIENT (CEPH)
|
||||
M: Jeff Layton <jlayton@kernel.org>
|
||||
M: Sage Weil <sage@redhat.com>
|
||||
M: Ilya Dryomov <idryomov@gmail.com>
|
||||
L: ceph-devel@vger.kernel.org
|
||||
S: Supported
|
||||
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
|
||||
F: Documentation/filesystems/ceph.rst
|
||||
F: fs/ceph/
|
||||
|
@ -7119,9 +7115,10 @@ F: include/uapi/asm-generic/
|
|||
|
||||
GENERIC PHY FRAMEWORK
|
||||
M: Kishon Vijay Abraham I <kishon@ti.com>
|
||||
M: Vinod Koul <vkoul@kernel.org>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
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: drivers/phy/
|
||||
F: include/linux/phy/
|
||||
|
@ -7746,11 +7743,6 @@ L: platform-driver-x86@vger.kernel.org
|
|||
S: Orphan
|
||||
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
|
||||
M: Clemens Ladisch <clemens@ladisch.de>
|
||||
S: Maintained
|
||||
|
@ -11718,8 +11710,9 @@ F: net/core/drop_monitor.c
|
|||
|
||||
NETWORKING DRIVERS
|
||||
M: "David S. Miller" <davem@davemloft.net>
|
||||
M: Jakub Kicinski <kuba@kernel.org>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Odd Fixes
|
||||
S: Maintained
|
||||
W: http://www.linuxfoundation.org/en/Net
|
||||
Q: http://patchwork.ozlabs.org/project/netdev/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
|
||||
|
@ -14102,12 +14095,10 @@ F: drivers/media/radio/radio-tea5777.c
|
|||
|
||||
RADOS BLOCK DEVICE (RBD)
|
||||
M: Ilya Dryomov <idryomov@gmail.com>
|
||||
M: Sage Weil <sage@redhat.com>
|
||||
R: Dongsheng Yang <dongsheng.yang@easystack.cn>
|
||||
L: ceph-devel@vger.kernel.org
|
||||
S: Supported
|
||||
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
|
||||
F: Documentation/ABI/testing/sysfs-bus-rbd
|
||||
F: drivers/block/rbd.c
|
||||
|
@ -14644,6 +14635,7 @@ F: drivers/iommu/s390-iommu.c
|
|||
|
||||
S390 IUCV NETWORK LAYER
|
||||
M: Julian Wiedmann <jwi@linux.ibm.com>
|
||||
M: Karsten Graul <kgraul@linux.ibm.com>
|
||||
M: Ursula Braun <ubraun@linux.ibm.com>
|
||||
L: linux-s390@vger.kernel.org
|
||||
S: Supported
|
||||
|
@ -14654,6 +14646,7 @@ F: net/iucv/
|
|||
|
||||
S390 NETWORK DRIVERS
|
||||
M: Julian Wiedmann <jwi@linux.ibm.com>
|
||||
M: Karsten Graul <kgraul@linux.ibm.com>
|
||||
M: Ursula Braun <ubraun@linux.ibm.com>
|
||||
L: linux-s390@vger.kernel.org
|
||||
S: Supported
|
||||
|
|
17
Makefile
17
Makefile
|
@ -2,7 +2,7 @@
|
|||
VERSION = 5
|
||||
PATCHLEVEL = 7
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc4
|
||||
EXTRAVERSION = -rc5
|
||||
NAME = Kleptomaniac Octopus
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
@ -729,10 +729,6 @@ else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
|
|||
KBUILD_CFLAGS += -Os
|
||||
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
|
||||
KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0)
|
||||
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+
|
||||
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
|
||||
KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow)
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ config ARM
|
|||
select ARCH_HAS_KEEPINITRD
|
||||
select ARCH_HAS_KCOV
|
||||
select ARCH_HAS_MEMBARRIER_SYNC_CORE
|
||||
select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
|
||||
select ARCH_HAS_PTE_SPECIAL if ARM_LPAE
|
||||
select ARCH_HAS_PHYS_TO_DMA
|
||||
select ARCH_HAS_SETUP_DMA_OPS
|
||||
|
|
|
@ -147,6 +147,7 @@ CONFIG_I2C_DAVINCI=y
|
|||
CONFIG_SPI=y
|
||||
CONFIG_SPI_DAVINCI=y
|
||||
CONFIG_SPI_SPIDEV=y
|
||||
CONFIG_PTP_1588_CLOCK=y
|
||||
CONFIG_PINCTRL_SINGLE=y
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
|
|
|
@ -274,6 +274,7 @@ CONFIG_SPI_TI_QSPI=m
|
|||
CONFIG_HSI=m
|
||||
CONFIG_OMAP_SSI=m
|
||||
CONFIG_SSI_PROTOCOL=m
|
||||
CONFIG_PTP_1588_CLOCK=y
|
||||
CONFIG_PINCTRL_SINGLE=y
|
||||
CONFIG_DEBUG_GPIO=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
|
|
|
@ -165,7 +165,12 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
|
|||
preempt_enable();
|
||||
#endif
|
||||
|
||||
if (!ret)
|
||||
/*
|
||||
* 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;
|
||||
|
|
|
@ -20,6 +20,7 @@ config ARM64
|
|||
select ARCH_HAS_KCOV
|
||||
select ARCH_HAS_KEEPINITRD
|
||||
select ARCH_HAS_MEMBARRIER_SYNC_CORE
|
||||
select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
|
||||
select ARCH_HAS_PTE_DEVMAP
|
||||
select ARCH_HAS_PTE_SPECIAL
|
||||
select ARCH_HAS_SETUP_DMA_OPS
|
||||
|
|
|
@ -177,6 +177,7 @@ void machine_kexec(struct kimage *kimage)
|
|||
* the offline CPUs. Therefore, we must use the __* variant here.
|
||||
*/
|
||||
__flush_icache_range((uintptr_t)reboot_code_buffer,
|
||||
(uintptr_t)reboot_code_buffer +
|
||||
arm64_relocate_new_kernel_size);
|
||||
|
||||
/* Flush the kimage list and its buffers. */
|
||||
|
|
|
@ -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));
|
||||
|
||||
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:
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#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_SP_EL0_OFFSET (CPU_XREG_OFFSET(30) + 8)
|
||||
|
||||
.text
|
||||
.pushsection .hyp.text, "ax"
|
||||
|
@ -47,6 +48,16 @@
|
|||
ldp x29, lr, [\ctxt, #CPU_XREG_OFFSET(29)]
|
||||
.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,
|
||||
* struct kvm_cpu_context *host_ctxt);
|
||||
|
@ -60,6 +71,9 @@ SYM_FUNC_START(__guest_enter)
|
|||
// Store the host regs
|
||||
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
|
||||
// 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
|
||||
|
@ -83,6 +97,9 @@ alternative_else_nop_endif
|
|||
// when this feature is enabled for kernel code.
|
||||
ptrauth_switch_to_guest x29, x0, x1, x2
|
||||
|
||||
// Restore the guest's sp_el0
|
||||
restore_sp_el0 x29, x0
|
||||
|
||||
// Restore guest regs x0-x17
|
||||
ldp x0, x1, [x29, #CPU_XREG_OFFSET(0)]
|
||||
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
|
||||
save_callee_saved_regs x1
|
||||
|
||||
// Store the guest's sp_el0
|
||||
save_sp_el0 x1, x2
|
||||
|
||||
get_host_ctxt x2, x3
|
||||
|
||||
// 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.
|
||||
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
|
||||
restore_callee_saved_regs x2
|
||||
|
||||
|
|
|
@ -198,7 +198,6 @@ SYM_CODE_END(__hyp_panic)
|
|||
.macro invalid_vector label, target = __hyp_panic
|
||||
.align 2
|
||||
SYM_CODE_START(\label)
|
||||
\label:
|
||||
b \target
|
||||
SYM_CODE_END(\label)
|
||||
.endm
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
/*
|
||||
* 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,
|
||||
* which are handled as part of the el2 return state) on every switch.
|
||||
* VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and
|
||||
* 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
|
||||
* 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
|
||||
|
@ -26,12 +27,6 @@
|
|||
static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
|
||||
{
|
||||
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)
|
||||
|
@ -99,12 +94,6 @@ NOKPROBE_SYMBOL(sysreg_save_guest_state_vhe);
|
|||
static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctxt)
|
||||
{
|
||||
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)
|
||||
|
|
|
@ -230,6 +230,8 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
|
|||
ptep = (pte_t *)pudp;
|
||||
} else if (sz == (CONT_PTE_SIZE)) {
|
||||
pmdp = pmd_alloc(mm, pudp, addr);
|
||||
if (!pmdp)
|
||||
return NULL;
|
||||
|
||||
WARN_ON(addr & (sz - 1));
|
||||
/*
|
||||
|
|
|
@ -521,6 +521,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||
case KVM_CAP_IOEVENTFD:
|
||||
case KVM_CAP_DEVICE_CTRL:
|
||||
case KVM_CAP_IMMEDIATE_EXIT:
|
||||
case KVM_CAP_SET_GUEST_DEBUG:
|
||||
r = 1;
|
||||
break;
|
||||
case KVM_CAP_PPC_GUEST_DEBUG_SSTEP:
|
||||
|
|
|
@ -54,7 +54,7 @@ config RISCV
|
|||
select GENERIC_ARCH_TOPOLOGY if SMP
|
||||
select ARCH_HAS_PTE_SPECIAL
|
||||
select ARCH_HAS_MMIOWB
|
||||
select ARCH_HAS_DEBUG_VIRTUAL
|
||||
select ARCH_HAS_DEBUG_VIRTUAL if MMU
|
||||
select HAVE_EBPF_JIT if MMU
|
||||
select EDAC_SUPPORT
|
||||
select ARCH_HAS_GIGANTIC_PAGE
|
||||
|
@ -136,6 +136,7 @@ config ARCH_SUPPORTS_DEBUG_PAGEALLOC
|
|||
def_bool y
|
||||
|
||||
config SYS_SUPPORTS_HUGETLBFS
|
||||
depends on MMU
|
||||
def_bool y
|
||||
|
||||
config STACKTRACE_SUPPORT
|
||||
|
|
|
@ -12,10 +12,11 @@ config SOC_SIFIVE
|
|||
|
||||
config SOC_VIRT
|
||||
bool "QEMU Virt Machine"
|
||||
select POWER_RESET
|
||||
select POWER_RESET_SYSCON
|
||||
select POWER_RESET_SYSCON_POWEROFF
|
||||
select GOLDFISH
|
||||
select RTC_DRV_GOLDFISH
|
||||
select RTC_DRV_GOLDFISH if RTC_CLASS
|
||||
select SIFIVE_PLIC
|
||||
help
|
||||
This enables support for QEMU Virt Machine.
|
||||
|
|
|
@ -51,13 +51,10 @@
|
|||
#define CAUSE_IRQ_FLAG (_AC(1, UL) << (__riscv_xlen - 1))
|
||||
|
||||
/* Interrupt causes (minus the high bit) */
|
||||
#define IRQ_U_SOFT 0
|
||||
#define IRQ_S_SOFT 1
|
||||
#define IRQ_M_SOFT 3
|
||||
#define IRQ_U_TIMER 4
|
||||
#define IRQ_S_TIMER 5
|
||||
#define IRQ_M_TIMER 7
|
||||
#define IRQ_U_EXT 8
|
||||
#define IRQ_S_EXT 9
|
||||
#define IRQ_M_EXT 11
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#ifndef _ASM_RISCV_HWCAP_H
|
||||
#define _ASM_RISCV_HWCAP_H
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <uapi/asm/hwcap.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
@ -22,6 +23,27 @@ enum {
|
|||
};
|
||||
|
||||
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 /* _ASM_RISCV_HWCAP_H */
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#ifndef CONFIG_MMU
|
||||
#define pgprot_noncached(x) (x)
|
||||
#define pgprot_writecombine(x) (x)
|
||||
#define pgprot_device(x) (x)
|
||||
#endif /* CONFIG_MMU */
|
||||
|
||||
/* Generic IO read/write. These perform native-endian accesses. */
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
#define mmiowb() __asm__ __volatile__ ("fence o,w" : : : "memory");
|
||||
|
||||
#include <linux/smp.h>
|
||||
#include <asm-generic/mmiowb.h>
|
||||
|
||||
#endif /* _ASM_RISCV_MMIOWB_H */
|
||||
|
|
|
@ -12,19 +12,14 @@
|
|||
#include <linux/ptrace.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#ifdef CONFIG_RISCV_BASE_PMU
|
||||
#define RISCV_BASE_COUNTERS 2
|
||||
|
||||
/*
|
||||
* The RISCV_MAX_COUNTERS parameter should be specified.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_RISCV_BASE_PMU
|
||||
#define RISCV_MAX_COUNTERS 2
|
||||
#endif
|
||||
|
||||
#ifndef RISCV_MAX_COUNTERS
|
||||
#error "Please provide a valid RISCV_MAX_COUNTERS for the PMU."
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These are the indexes of bits in counteren register *minus* 1,
|
||||
|
@ -82,6 +77,7 @@ struct riscv_pmu {
|
|||
int irq;
|
||||
};
|
||||
|
||||
#endif
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
#define perf_arch_bpf_user_pt_regs(regs) (struct user_regs_struct *)regs
|
||||
#endif
|
||||
|
|
|
@ -470,12 +470,15 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
|
|||
|
||||
#else /* CONFIG_MMU */
|
||||
|
||||
#define PAGE_SHARED __pgprot(0)
|
||||
#define PAGE_KERNEL __pgprot(0)
|
||||
#define swapper_pg_dir NULL
|
||||
#define VMALLOC_START 0
|
||||
|
||||
#define TASK_SIZE 0xffffffffUL
|
||||
|
||||
static inline void __kernel_map_pages(struct page *page, int numpages, int enable) {}
|
||||
|
||||
#endif /* !CONFIG_MMU */
|
||||
|
||||
#define kern_addr_valid(addr) (1) /* FIXME */
|
||||
|
|
|
@ -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; }
|
||||
#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_default_noflush(struct page *page);
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o
|
|||
obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o
|
||||
obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o
|
||||
|
||||
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
|
||||
obj-$(CONFIG_RISCV_BASE_PMU) += perf_event.o
|
||||
obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o
|
||||
obj-$(CONFIG_HAVE_PERF_REGS) += perf_regs.o
|
||||
obj-$(CONFIG_RISCV_SBI) += sbi.o
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
|
||||
const struct cpu_operations *cpu_ops[NR_CPUS] __ro_after_init;
|
||||
|
||||
void *__cpu_up_stack_pointer[NR_CPUS];
|
||||
void *__cpu_up_task_pointer[NR_CPUS];
|
||||
void *__cpu_up_stack_pointer[NR_CPUS] __section(.data);
|
||||
void *__cpu_up_task_pointer[NR_CPUS] __section(.data);
|
||||
|
||||
extern const struct cpu_operations cpu_ops_sbi;
|
||||
extern const struct cpu_operations cpu_ops_spinwait;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Copyright (C) 2017 SiFive
|
||||
*/
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/of.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/hwcap.h>
|
||||
|
@ -13,15 +14,57 @@
|
|||
#include <asm/switch_to.h>
|
||||
|
||||
unsigned long elf_hwcap __read_mostly;
|
||||
|
||||
/* Host ISA bitmap */
|
||||
static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
|
||||
|
||||
#ifdef CONFIG_FPU
|
||||
bool has_fpu __read_mostly;
|
||||
#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)
|
||||
{
|
||||
struct device_node *node;
|
||||
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};
|
||||
|
||||
isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I;
|
||||
|
@ -33,8 +76,11 @@ void riscv_fill_hwcap(void)
|
|||
|
||||
elf_hwcap = 0;
|
||||
|
||||
bitmap_zero(riscv_isa, RISCV_ISA_EXT_MAX);
|
||||
|
||||
for_each_of_cpu_node(node) {
|
||||
unsigned long this_hwcap = 0;
|
||||
unsigned long this_isa = 0;
|
||||
|
||||
if (riscv_of_processor_hartid(node) < 0)
|
||||
continue;
|
||||
|
@ -44,8 +90,24 @@ void riscv_fill_hwcap(void)
|
|||
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])];
|
||||
/*
|
||||
* 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
|
||||
|
@ -56,6 +118,11 @@ void riscv_fill_hwcap(void)
|
|||
elf_hwcap &= this_hwcap;
|
||||
else
|
||||
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
|
||||
|
@ -65,7 +132,17 @@ void riscv_fill_hwcap(void)
|
|||
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
|
||||
if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
|
||||
|
|
|
@ -147,7 +147,7 @@ static int riscv_map_hw_event(u64 config)
|
|||
return riscv_pmu->hw_events[config];
|
||||
}
|
||||
|
||||
int riscv_map_cache_decode(u64 config, unsigned int *type,
|
||||
static int riscv_map_cache_decode(u64 config, unsigned int *type,
|
||||
unsigned int *op, unsigned int *result)
|
||||
{
|
||||
return -ENOENT;
|
||||
|
@ -342,7 +342,7 @@ static void riscv_pmu_del(struct perf_event *event, int flags)
|
|||
|
||||
static DEFINE_MUTEX(pmc_reserve_mutex);
|
||||
|
||||
irqreturn_t riscv_base_pmu_handle_irq(int irq_num, void *dev)
|
||||
static irqreturn_t riscv_base_pmu_handle_irq(int irq_num, void *dev)
|
||||
{
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
@ -361,7 +361,7 @@ static int reserve_pmc_hardware(void)
|
|||
return err;
|
||||
}
|
||||
|
||||
void release_pmc_hardware(void)
|
||||
static void release_pmc_hardware(void)
|
||||
{
|
||||
mutex_lock(&pmc_reserve_mutex);
|
||||
if (riscv_pmu->irq >= 0)
|
||||
|
@ -464,7 +464,7 @@ static const struct of_device_id riscv_pmu_of_ids[] = {
|
|||
{ /* sentinel value */ }
|
||||
};
|
||||
|
||||
int __init init_hw_perf_events(void)
|
||||
static int __init init_hw_perf_events(void)
|
||||
{
|
||||
struct device_node *node = of_find_node_by_type(NULL, "pmu");
|
||||
const struct of_device_id *of_id;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/smp.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)
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -65,7 +65,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
|
|||
|
||||
#else /* !CONFIG_FRAME_POINTER */
|
||||
|
||||
static void notrace walk_stackframe(struct task_struct *task,
|
||||
void notrace walk_stackframe(struct task_struct *task,
|
||||
struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg)
|
||||
{
|
||||
unsigned long sp, pc;
|
||||
|
|
|
@ -12,7 +12,7 @@ vdso-syms += getcpu
|
|||
vdso-syms += flush_icache
|
||||
|
||||
# Files to link into the vdso
|
||||
obj-vdso = $(patsubst %, %.o, $(vdso-syms))
|
||||
obj-vdso = $(patsubst %, %.o, $(vdso-syms)) note.o
|
||||
|
||||
# Build rules
|
||||
targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds vdso-dummy.o
|
||||
|
|
|
@ -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
|
|
@ -150,7 +150,8 @@ void __init setup_bootmem(void)
|
|||
memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start);
|
||||
|
||||
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
|
||||
setup_initrd();
|
||||
|
@ -501,22 +502,6 @@ static inline void setup_vm_final(void)
|
|||
#endif /* CONFIG_MMU */
|
||||
|
||||
#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)
|
||||
{
|
||||
unsigned long text_start = (unsigned long)_text;
|
||||
|
|
|
@ -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_MIGRATION:
|
||||
case KVM_CAP_S390_VCPU_RESETS:
|
||||
case KVM_CAP_SET_GUEST_DEBUG:
|
||||
r = 1;
|
||||
break;
|
||||
case KVM_CAP_S390_HPAGE_1M:
|
||||
|
|
|
@ -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
|
||||
* since we do not set IC.3 (FIII) we currently will only intercept
|
||||
* 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];
|
||||
fc = (reg0 >> 24) & 0xff;
|
||||
if (WARN_ON_ONCE(fc != 0x03))
|
||||
if (fc != 0x03)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* PQAP instruction is allowed for guest kernel only */
|
||||
|
|
|
@ -68,6 +68,7 @@ config X86
|
|||
select ARCH_HAS_KCOV if X86_64
|
||||
select ARCH_HAS_MEM_ENCRYPT
|
||||
select ARCH_HAS_MEMBARRIER_SYNC_CORE
|
||||
select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
|
||||
select ARCH_HAS_PMEM_API if X86_64
|
||||
select ARCH_HAS_PTE_DEVMAP if X86_64
|
||||
select ARCH_HAS_PTE_SPECIAL
|
||||
|
|
|
@ -98,13 +98,6 @@ For 32-bit we have the following conventions - kernel is built with
|
|||
#define SIZEOF_PTREGS 21*8
|
||||
|
||||
.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
|
||||
pushq %rsi /* pt_regs->si */
|
||||
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 */
|
||||
.endif
|
||||
pushq \rdx /* pt_regs->dx */
|
||||
xorl %edx, %edx /* nospec dx */
|
||||
pushq %rcx /* pt_regs->cx */
|
||||
xorl %ecx, %ecx /* nospec cx */
|
||||
pushq \rax /* pt_regs->ax */
|
||||
pushq %r8 /* pt_regs->r8 */
|
||||
xorl %r8d, %r8d /* nospec r8 */
|
||||
pushq %r9 /* pt_regs->r9 */
|
||||
xorl %r9d, %r9d /* nospec r9 */
|
||||
pushq %r10 /* pt_regs->r10 */
|
||||
xorl %r10d, %r10d /* nospec r10 */
|
||||
pushq %r11 /* pt_regs->r11 */
|
||||
xorl %r11d, %r11d /* nospec r11*/
|
||||
pushq %rbx /* pt_regs->rbx */
|
||||
xorl %ebx, %ebx /* nospec rbx*/
|
||||
pushq %rbp /* pt_regs->rbp */
|
||||
xorl %ebp, %ebp /* nospec rbp*/
|
||||
pushq %r12 /* pt_regs->r12 */
|
||||
xorl %r12d, %r12d /* nospec r12*/
|
||||
pushq %r13 /* pt_regs->r13 */
|
||||
xorl %r13d, %r13d /* nospec r13*/
|
||||
pushq %r14 /* pt_regs->r14 */
|
||||
xorl %r14d, %r14d /* nospec r14*/
|
||||
pushq %r15 /* pt_regs->r15 */
|
||||
xorl %r15d, %r15d /* nospec r15*/
|
||||
UNWIND_HINT_REGS
|
||||
|
||||
.if \save_ret
|
||||
pushq %rsi /* return address on top of stack */
|
||||
.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
|
||||
|
||||
.macro POP_REGS pop_rdi=1 skip_r11rcx=0
|
||||
|
|
|
@ -249,7 +249,6 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
|
|||
*/
|
||||
syscall_return_via_sysret:
|
||||
/* rcx and r11 are already restored (see code above) */
|
||||
UNWIND_HINT_EMPTY
|
||||
POP_REGS pop_rdi=0 skip_r11rcx=1
|
||||
|
||||
/*
|
||||
|
@ -258,6 +257,7 @@ syscall_return_via_sysret:
|
|||
*/
|
||||
movq %rsp, %rdi
|
||||
movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp
|
||||
UNWIND_HINT_EMPTY
|
||||
|
||||
pushq RSP-RDI(%rdi) /* RSP */
|
||||
pushq (%rdi) /* RDI */
|
||||
|
@ -279,8 +279,7 @@ SYM_CODE_END(entry_SYSCALL_64)
|
|||
* %rdi: prev task
|
||||
* %rsi: next task
|
||||
*/
|
||||
SYM_CODE_START(__switch_to_asm)
|
||||
UNWIND_HINT_FUNC
|
||||
SYM_FUNC_START(__switch_to_asm)
|
||||
/*
|
||||
* Save callee-saved registers
|
||||
* This must match the order in inactive_task_frame
|
||||
|
@ -321,7 +320,7 @@ SYM_CODE_START(__switch_to_asm)
|
|||
popq %rbp
|
||||
|
||||
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.
|
||||
|
@ -512,7 +511,7 @@ SYM_CODE_END(spurious_entries_start)
|
|||
* +----------------------------------------------------+
|
||||
*/
|
||||
SYM_CODE_START(interrupt_entry)
|
||||
UNWIND_HINT_FUNC
|
||||
UNWIND_HINT_IRET_REGS offset=16
|
||||
ASM_CLAC
|
||||
cld
|
||||
|
||||
|
@ -544,9 +543,9 @@ SYM_CODE_START(interrupt_entry)
|
|||
pushq 5*8(%rdi) /* regs->eflags */
|
||||
pushq 4*8(%rdi) /* regs->cs */
|
||||
pushq 3*8(%rdi) /* regs->ip */
|
||||
UNWIND_HINT_IRET_REGS
|
||||
pushq 2*8(%rdi) /* regs->orig_ax */
|
||||
pushq 8(%rdi) /* return address */
|
||||
UNWIND_HINT_FUNC
|
||||
|
||||
movq (%rdi), %rdi
|
||||
jmp 2f
|
||||
|
@ -637,6 +636,7 @@ SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
|
|||
*/
|
||||
movq %rsp, %rdi
|
||||
movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp
|
||||
UNWIND_HINT_EMPTY
|
||||
|
||||
/* Copy the IRET frame to the trampoline stack. */
|
||||
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
|
||||
leaq -PTREGS_SIZE(%rax), %rsp
|
||||
UNWIND_HINT_FUNC sp_offset=PTREGS_SIZE
|
||||
UNWIND_HINT_REGS
|
||||
|
||||
call do_exit
|
||||
SYM_CODE_END(rewind_stack_do_exit)
|
||||
|
|
|
@ -56,16 +56,23 @@ struct dyn_arch_ftrace {
|
|||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_DYNAMIC_FTRACE)
|
||||
extern void set_ftrace_ops_ro(void);
|
||||
#else
|
||||
static inline void set_ftrace_ops_ro(void) { }
|
||||
#endif
|
||||
|
||||
#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
|
||||
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
|
||||
* "__x64_sys", "__ia32_sys" or simple "sys" prefix.
|
||||
* "__x64_sys", "__ia32_sys", "__do_sys" or simple "sys" prefix.
|
||||
*/
|
||||
return !strcmp(sym + 3, 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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
/* We can only post Fixed and LowPrio IRQs */
|
||||
return (irq->delivery_mode == dest_Fixed ||
|
||||
irq->delivery_mode == dest_LowestPrio);
|
||||
return (irq->delivery_mode == APIC_DM_FIXED ||
|
||||
irq->delivery_mode == APIC_DM_LOWEST);
|
||||
}
|
||||
|
||||
static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
|
||||
|
|
|
@ -19,7 +19,7 @@ struct unwind_state {
|
|||
#if defined(CONFIG_UNWINDER_ORC)
|
||||
bool signal, full_regs;
|
||||
unsigned long sp, bp, ip;
|
||||
struct pt_regs *regs;
|
||||
struct pt_regs *regs, *prev_regs;
|
||||
#elif defined(CONFIG_UNWINDER_FRAME_POINTER)
|
||||
bool got_irq;
|
||||
unsigned long *bp, *orig_sp, ip;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
asm volatile("mfence" : : : "memory");
|
||||
|
||||
printk_once(KERN_DEBUG "TSC deadline timer enabled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -546,7 +544,7 @@ static struct clock_event_device lapic_clockevent = {
|
|||
};
|
||||
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) {
|
||||
case 0x02: return 0x3a; /* EP */
|
||||
|
@ -556,7 +554,7 @@ static u32 hsx_deadline_rev(void)
|
|||
return ~0U;
|
||||
}
|
||||
|
||||
static u32 bdx_deadline_rev(void)
|
||||
static __init u32 bdx_deadline_rev(void)
|
||||
{
|
||||
switch (boot_cpu_data.x86_stepping) {
|
||||
case 0x02: return 0x00000011;
|
||||
|
@ -568,7 +566,7 @@ static u32 bdx_deadline_rev(void)
|
|||
return ~0U;
|
||||
}
|
||||
|
||||
static u32 skx_deadline_rev(void)
|
||||
static __init u32 skx_deadline_rev(void)
|
||||
{
|
||||
switch (boot_cpu_data.x86_stepping) {
|
||||
case 0x03: return 0x01000136;
|
||||
|
@ -581,7 +579,7 @@ static u32 skx_deadline_rev(void)
|
|||
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( BROADWELL_X, 0x0b000020),
|
||||
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;
|
||||
u32 rev;
|
||||
|
||||
if (!boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER) ||
|
||||
boot_cpu_has(X86_FEATURE_HYPERVISOR))
|
||||
return;
|
||||
if (!boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER))
|
||||
return false;
|
||||
if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
|
||||
return true;
|
||||
|
||||
m = x86_match_cpu(deadline_match);
|
||||
if (!m)
|
||||
return;
|
||||
return true;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
if (boot_cpu_data.microcode >= rev)
|
||||
return;
|
||||
return true;
|
||||
|
||||
setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER);
|
||||
pr_err(FW_BUG "TSC_DEADLINE disabled due to Errata; "
|
||||
"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;
|
||||
|
||||
apic_check_deadline_errata();
|
||||
if (apic_validate_deadline_timer())
|
||||
pr_debug("TSC deadline timer available\n");
|
||||
|
||||
if (x2apic_mode) {
|
||||
boot_cpu_physical_apicid = read_apic_id();
|
||||
|
|
|
@ -183,6 +183,7 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
|
|||
*/
|
||||
if (visit_mask) {
|
||||
if (*visit_mask & (1UL << info->type)) {
|
||||
if (task == current)
|
||||
printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
|
||||
goto unknown;
|
||||
}
|
||||
|
|
|
@ -407,6 +407,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
|
|||
|
||||
set_vm_flush_reset_perms(trampoline);
|
||||
|
||||
if (likely(system_state != SYSTEM_BOOTING))
|
||||
set_memory_ro((unsigned long)trampoline, npages);
|
||||
set_memory_x((unsigned long)trampoline, npages);
|
||||
return (unsigned long)trampoline;
|
||||
|
@ -415,6 +416,32 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void set_ftrace_ops_ro(void)
|
||||
{
|
||||
struct ftrace_ops *ops;
|
||||
unsigned long start_offset;
|
||||
unsigned long end_offset;
|
||||
unsigned long npages;
|
||||
unsigned long size;
|
||||
|
||||
do_for_each_ftrace_op(ops, ftrace_ops_list) {
|
||||
if (!(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP))
|
||||
continue;
|
||||
|
||||
if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) {
|
||||
start_offset = (unsigned long)ftrace_regs_caller;
|
||||
end_offset = (unsigned long)ftrace_regs_caller_end;
|
||||
} else {
|
||||
start_offset = (unsigned long)ftrace_caller;
|
||||
end_offset = (unsigned long)ftrace_epilogue;
|
||||
}
|
||||
size = end_offset - start_offset;
|
||||
size = size + RET_SIZE + sizeof(void *);
|
||||
npages = DIV_ROUND_UP(size, PAGE_SIZE);
|
||||
set_memory_ro((unsigned long)ops->trampoline, npages);
|
||||
} while_for_each_ftrace_op(ops);
|
||||
}
|
||||
|
||||
static unsigned long calc_trampoline_call_offset(bool save_regs)
|
||||
{
|
||||
unsigned long start_offset;
|
||||
|
|
|
@ -344,6 +344,9 @@ bool unwind_next_frame(struct unwind_state *state)
|
|||
if (IS_ENABLED(CONFIG_X86_32))
|
||||
goto the_end;
|
||||
|
||||
if (state->task != current)
|
||||
goto the_end;
|
||||
|
||||
if (state->regs) {
|
||||
printk_deferred_once(KERN_WARNING
|
||||
"WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n",
|
||||
|
|
|
@ -8,19 +8,21 @@
|
|||
#include <asm/orc_lookup.h>
|
||||
|
||||
#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 __stop_orc_unwind_ip[];
|
||||
extern struct orc_entry __start_orc_unwind[];
|
||||
extern struct orc_entry __stop_orc_unwind[];
|
||||
|
||||
static DEFINE_MUTEX(sort_mutex);
|
||||
int *cur_orc_ip_table = __start_orc_unwind_ip;
|
||||
struct orc_entry *cur_orc_table = __start_orc_unwind;
|
||||
|
||||
unsigned int lookup_num_blocks;
|
||||
bool orc_init;
|
||||
static bool orc_init __ro_after_init;
|
||||
static unsigned int lookup_num_blocks __ro_after_init;
|
||||
|
||||
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;
|
||||
|
||||
if (!orc_init)
|
||||
return NULL;
|
||||
|
||||
if (ip == 0)
|
||||
return &null_orc_entry;
|
||||
|
||||
|
@ -189,6 +188,10 @@ static struct orc_entry *orc_find(unsigned long ip)
|
|||
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
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;
|
||||
struct orc_entry *orc;
|
||||
bool indirect = false;
|
||||
|
@ -445,43 +477,39 @@ bool unwind_next_frame(struct unwind_state *state)
|
|||
break;
|
||||
|
||||
case ORC_REG_R10:
|
||||
if (!state->regs || !state->full_regs) {
|
||||
orc_warn("missing regs for base reg R10 at ip %pB\n",
|
||||
if (!get_reg(state, offsetof(struct pt_regs, r10), &sp)) {
|
||||
orc_warn_current("missing R10 value at %pB\n",
|
||||
(void *)state->ip);
|
||||
goto err;
|
||||
}
|
||||
sp = state->regs->r10;
|
||||
break;
|
||||
|
||||
case ORC_REG_R13:
|
||||
if (!state->regs || !state->full_regs) {
|
||||
orc_warn("missing regs for base reg R13 at ip %pB\n",
|
||||
if (!get_reg(state, offsetof(struct pt_regs, r13), &sp)) {
|
||||
orc_warn_current("missing R13 value at %pB\n",
|
||||
(void *)state->ip);
|
||||
goto err;
|
||||
}
|
||||
sp = state->regs->r13;
|
||||
break;
|
||||
|
||||
case ORC_REG_DI:
|
||||
if (!state->regs || !state->full_regs) {
|
||||
orc_warn("missing regs for base reg DI at ip %pB\n",
|
||||
if (!get_reg(state, offsetof(struct pt_regs, di), &sp)) {
|
||||
orc_warn_current("missing RDI value at %pB\n",
|
||||
(void *)state->ip);
|
||||
goto err;
|
||||
}
|
||||
sp = state->regs->di;
|
||||
break;
|
||||
|
||||
case ORC_REG_DX:
|
||||
if (!state->regs || !state->full_regs) {
|
||||
orc_warn("missing regs for base reg DX at ip %pB\n",
|
||||
if (!get_reg(state, offsetof(struct pt_regs, dx), &sp)) {
|
||||
orc_warn_current("missing DX value at %pB\n",
|
||||
(void *)state->ip);
|
||||
goto err;
|
||||
}
|
||||
sp = state->regs->dx;
|
||||
break;
|
||||
|
||||
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);
|
||||
goto err;
|
||||
}
|
||||
|
@ -504,44 +532,48 @@ bool unwind_next_frame(struct unwind_state *state)
|
|||
|
||||
state->sp = sp;
|
||||
state->regs = NULL;
|
||||
state->prev_regs = NULL;
|
||||
state->signal = false;
|
||||
break;
|
||||
|
||||
case ORC_TYPE_REGS:
|
||||
if (!deref_stack_regs(state, sp, &state->ip, &state->sp)) {
|
||||
orc_warn("can't dereference registers at %p for ip %pB\n",
|
||||
(void *)sp, (void *)orig_ip);
|
||||
orc_warn_current("can't access registers at %pB\n",
|
||||
(void *)orig_ip);
|
||||
goto err;
|
||||
}
|
||||
|
||||
state->regs = (struct pt_regs *)sp;
|
||||
state->prev_regs = NULL;
|
||||
state->full_regs = true;
|
||||
state->signal = true;
|
||||
break;
|
||||
|
||||
case ORC_TYPE_REGS_IRET:
|
||||
if (!deref_stack_iret_regs(state, sp, &state->ip, &state->sp)) {
|
||||
orc_warn("can't dereference iret registers at %p for ip %pB\n",
|
||||
(void *)sp, (void *)orig_ip);
|
||||
orc_warn_current("can't access iret registers at %pB\n",
|
||||
(void *)orig_ip);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (state->full_regs)
|
||||
state->prev_regs = state->regs;
|
||||
state->regs = (void *)sp - IRET_FRAME_OFFSET;
|
||||
state->full_regs = false;
|
||||
state->signal = true;
|
||||
break;
|
||||
|
||||
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);
|
||||
break;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Find BP: */
|
||||
switch (orc->bp_reg) {
|
||||
case ORC_REG_UNDEFINED:
|
||||
if (state->regs && state->full_regs)
|
||||
state->bp = state->regs->bp;
|
||||
if (get_reg(state, offsetof(struct pt_regs, bp), &tmp))
|
||||
state->bp = tmp;
|
||||
break;
|
||||
|
||||
case ORC_REG_PREV_SP:
|
||||
|
@ -564,7 +596,7 @@ bool unwind_next_frame(struct unwind_state *state)
|
|||
if (state->stack_info.type == prev_type &&
|
||||
on_stack(&state->stack_info, (void *)state->sp, sizeof(long)) &&
|
||||
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);
|
||||
goto err;
|
||||
}
|
||||
|
@ -585,6 +617,9 @@ EXPORT_SYMBOL_GPL(unwind_next_frame);
|
|||
void __unwind_start(struct unwind_state *state, struct task_struct *task,
|
||||
struct pt_regs *regs, unsigned long *first_frame)
|
||||
{
|
||||
if (!orc_init)
|
||||
goto done;
|
||||
|
||||
memset(state, 0, sizeof(*state));
|
||||
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: */
|
||||
while (!unwind_done(state) &&
|
||||
(!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);
|
||||
|
||||
return;
|
||||
|
|
|
@ -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,
|
||||
* in-kernel IOAPIC will not be able to receive the EOI.
|
||||
* In this case, we do lazy update of the pending EOI when
|
||||
* trying to set IOAPIC irq.
|
||||
* AMD SVM AVIC accelerate EOI write iff the interrupt is edge
|
||||
* triggered, in which case the in-kernel IOAPIC will not be able
|
||||
* to receive the EOI. In this case, we do a lazy update of the
|
||||
* 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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -345,7 +345,7 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
|
|||
return NULL;
|
||||
|
||||
/* 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) {
|
||||
pr_err("SEV: Failure locking %lu pages.\n", npages);
|
||||
goto err;
|
||||
|
|
|
@ -1752,6 +1752,8 @@ static int db_interception(struct vcpu_svm *svm)
|
|||
if (svm->vcpu.guest_debug &
|
||||
(KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) {
|
||||
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 =
|
||||
svm->vmcb->save.cs.base + svm->vmcb->save.rip;
|
||||
kvm_run->debug.arch.exception = DB_VECTOR;
|
||||
|
|
|
@ -5165,7 +5165,7 @@ static int handle_invept(struct kvm_vcpu *vcpu)
|
|||
*/
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -82,6 +82,9 @@ SYM_FUNC_START(vmx_vmexit)
|
|||
/* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */
|
||||
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
|
||||
.Lvmexit_skip_rsb:
|
||||
#endif
|
||||
|
|
|
@ -926,19 +926,6 @@ EXPORT_SYMBOL_GPL(kvm_set_xcr);
|
|||
__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)
|
||||
{
|
||||
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_MSR_PLATFORM_INFO:
|
||||
case KVM_CAP_EXCEPTION_PAYLOAD:
|
||||
case KVM_CAP_SET_GUEST_DEBUG:
|
||||
r = 1;
|
||||
break;
|
||||
case KVM_CAP_SYNC_REGS:
|
||||
|
@ -9675,7 +9663,9 @@ int kvm_arch_hardware_setup(void *opaque)
|
|||
if (!kvm_cpu_cap_has(X86_FEATURE_XSAVES))
|
||||
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) {
|
||||
/*
|
||||
|
@ -9707,7 +9697,8 @@ int kvm_arch_check_processor_compat(void *opaque)
|
|||
|
||||
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 ops->check_processor_compatibility();
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include <asm/init.h>
|
||||
#include <asm/uv/uv.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/ftrace.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
|
||||
|
@ -1291,6 +1292,8 @@ void mark_rodata_ro(void)
|
|||
all_end = roundup((unsigned long)_brk_end, PMD_SIZE);
|
||||
set_memory_nx(text_end, (all_end - text_end) >> PAGE_SHIFT);
|
||||
|
||||
set_ftrace_ops_ro();
|
||||
|
||||
#ifdef CONFIG_CPA_DEBUG
|
||||
printk(KERN_INFO "Testing CPA: undo %lx-%lx\n", start, end);
|
||||
set_memory_rw(start, (end-start) >> PAGE_SHIFT);
|
||||
|
|
|
@ -43,7 +43,8 @@ struct cpa_data {
|
|||
unsigned long pfn;
|
||||
unsigned int flags;
|
||||
unsigned int force_split : 1,
|
||||
force_static_prot : 1;
|
||||
force_static_prot : 1,
|
||||
force_flush_all : 1;
|
||||
struct page **pages;
|
||||
};
|
||||
|
||||
|
@ -355,10 +356,10 @@ static void cpa_flush(struct cpa_data *data, int cache)
|
|||
return;
|
||||
}
|
||||
|
||||
if (cpa->numpages <= tlb_single_page_flush_ceiling)
|
||||
on_each_cpu(__cpa_flush_tlb, cpa, 1);
|
||||
else
|
||||
if (cpa->force_flush_all || cpa->numpages > tlb_single_page_flush_ceiling)
|
||||
flush_tlb_all();
|
||||
else
|
||||
on_each_cpu(__cpa_flush_tlb, cpa, 1);
|
||||
|
||||
if (!cache)
|
||||
return;
|
||||
|
@ -1598,6 +1599,8 @@ static int cpa_process_alias(struct cpa_data *cpa)
|
|||
alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
|
||||
alias_cpa.curpage = 0;
|
||||
|
||||
cpa->force_flush_all = 1;
|
||||
|
||||
ret = __change_page_attr_set_clr(&alias_cpa, 0);
|
||||
if (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.curpage = 0;
|
||||
|
||||
cpa->force_flush_all = 1;
|
||||
/*
|
||||
* The high mapping range is imprecise, so ignore the
|
||||
* return value.
|
||||
|
|
|
@ -123,6 +123,7 @@
|
|||
#include <linux/ioprio.h>
|
||||
#include <linux/sbitmap.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/backing-dev.h>
|
||||
|
||||
#include "blk.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);
|
||||
switch (ioprio_class) {
|
||||
default:
|
||||
dev_err(bfqq->bfqd->queue->backing_dev_info->dev,
|
||||
"bfq: bad prio class %d\n", ioprio_class);
|
||||
pr_err("bdi %s: bfq: bad prio class %d\n",
|
||||
bdi_dev_name(bfqq->bfqd->queue->backing_dev_info),
|
||||
ioprio_class);
|
||||
/* fall through */
|
||||
case IOPRIO_CLASS_NONE:
|
||||
/*
|
||||
|
|
|
@ -496,7 +496,7 @@ const char *blkg_dev_name(struct blkcg_gq *blkg)
|
|||
{
|
||||
/* some drivers (floppy) instantiate a queue w/o disk registered */
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -466,7 +466,7 @@ struct ioc_gq {
|
|||
*/
|
||||
atomic64_t vtime;
|
||||
atomic64_t done_vtime;
|
||||
atomic64_t abs_vdebt;
|
||||
u64 abs_vdebt;
|
||||
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 };
|
||||
u64 margin_ns = (u64)(ioc->period_us *
|
||||
WAITQ_TIMER_MARGIN_PCT / 100) * NSEC_PER_USEC;
|
||||
u64 abs_vdebt, vdebt, vshortage, expires, oexpires;
|
||||
u64 vdebt, vshortage, expires, oexpires;
|
||||
s64 vbudget;
|
||||
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);
|
||||
|
||||
/* pay off debt */
|
||||
abs_vdebt = atomic64_read(&iocg->abs_vdebt);
|
||||
vdebt = abs_cost_to_cost(abs_vdebt, hw_inuse);
|
||||
vdebt = abs_cost_to_cost(iocg->abs_vdebt, hw_inuse);
|
||||
if (vdebt && vbudget > 0) {
|
||||
u64 delta = min_t(u64, vbudget, vdebt);
|
||||
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->done_vtime);
|
||||
atomic64_sub(abs_delta, &iocg->abs_vdebt);
|
||||
if (WARN_ON_ONCE(atomic64_read(&iocg->abs_vdebt) < 0))
|
||||
atomic64_set(&iocg->abs_vdebt, 0);
|
||||
iocg->abs_vdebt -= abs_delta;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1219,12 +1216,18 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now, u64 cost)
|
|||
u64 expires, oexpires;
|
||||
u32 hw_inuse;
|
||||
|
||||
lockdep_assert_held(&iocg->waitq.lock);
|
||||
|
||||
/* debt-adjust vtime */
|
||||
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);
|
||||
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_now now;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&iocg->waitq.lock, flags);
|
||||
ioc_now(iocg->ioc, &now);
|
||||
iocg_kick_delay(iocg, &now, 0);
|
||||
spin_unlock_irqrestore(&iocg->waitq.lock, flags);
|
||||
|
||||
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.
|
||||
*/
|
||||
list_for_each_entry_safe(iocg, tiocg, &ioc->active_iocgs, active_list) {
|
||||
if (!waitqueue_active(&iocg->waitq) &&
|
||||
!atomic64_read(&iocg->abs_vdebt) && !iocg_is_idle(iocg))
|
||||
if (!waitqueue_active(&iocg->waitq) && iocg->abs_vdebt &&
|
||||
!iocg_is_idle(iocg))
|
||||
continue;
|
||||
|
||||
spin_lock(&iocg->waitq.lock);
|
||||
|
||||
if (waitqueue_active(&iocg->waitq) ||
|
||||
atomic64_read(&iocg->abs_vdebt)) {
|
||||
if (waitqueue_active(&iocg->waitq) || iocg->abs_vdebt) {
|
||||
/* might be oversleeping vtime / hweight changes, kick */
|
||||
iocg_kick_waitq(iocg, &now);
|
||||
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
|
||||
* in a while which is fine.
|
||||
*/
|
||||
if (!waitqueue_active(&iocg->waitq) &&
|
||||
!atomic64_read(&iocg->abs_vdebt) &&
|
||||
if (!waitqueue_active(&iocg->waitq) && !iocg->abs_vdebt &&
|
||||
time_before_eq64(vtime + cost, now.vnow)) {
|
||||
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.
|
||||
* 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 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
|
||||
* actual budget available to the cgroup. If we just wound vtime,
|
||||
* we would incorrectly use the current hw_inuse for the entire
|
||||
* amount which, for example, can lead to the cgroup staying
|
||||
* blocked for a long time even with substantially raised hw_inuse.
|
||||
* actual budget available to the cgroup. If we just wound vtime, we
|
||||
* would incorrectly use the current hw_inuse for the entire amount
|
||||
* which, for example, can lead to the cgroup staying blocked for a
|
||||
* 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)) {
|
||||
atomic64_add(abs_cost, &iocg->abs_vdebt);
|
||||
iocg->abs_vdebt += abs_cost;
|
||||
if (iocg_kick_delay(iocg, &now, cost))
|
||||
blkcg_schedule_throttle(rqos->q,
|
||||
(bio->bi_opf & REQ_SWAP) == REQ_SWAP);
|
||||
spin_unlock_irq(&iocg->waitq.lock);
|
||||
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
|
||||
* 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);
|
||||
wait.wait.private = current;
|
||||
wait.bio = bio;
|
||||
|
@ -1801,6 +1813,7 @@ static void ioc_rqos_merge(struct rq_qos *rqos, struct request *rq,
|
|||
struct ioc_now now;
|
||||
u32 hw_inuse;
|
||||
u64 abs_cost, cost;
|
||||
unsigned long flags;
|
||||
|
||||
/* bypass if disabled or for root cgroup */
|
||||
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;
|
||||
|
||||
/*
|
||||
* Charge if there's enough vtime budget and the existing request
|
||||
* has cost assigned. Otherwise, account it as debt. See debt
|
||||
* handling in ioc_rqos_throttle() for details.
|
||||
* Charge if there's enough vtime budget and the existing request has
|
||||
* cost assigned.
|
||||
*/
|
||||
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);
|
||||
else
|
||||
atomic64_add(abs_cost, &iocg->abs_vdebt);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
@ -1998,7 +2024,6 @@ static void ioc_pd_init(struct blkg_policy_data *pd)
|
|||
iocg->ioc = ioc;
|
||||
atomic64_set(&iocg->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));
|
||||
INIT_LIST_HEAD(&iocg->active_list);
|
||||
iocg->hweight_active = HWEIGHT_WHOLE;
|
||||
|
|
|
@ -287,7 +287,7 @@ static void exit_tfm(struct crypto_skcipher *tfm)
|
|||
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));
|
||||
kfree(inst);
|
||||
|
@ -400,12 +400,12 @@ static int create(struct crypto_template *tmpl, struct rtattr **tb)
|
|||
inst->alg.encrypt = encrypt;
|
||||
inst->alg.decrypt = decrypt;
|
||||
|
||||
inst->free = free;
|
||||
inst->free = free_inst;
|
||||
|
||||
err = skcipher_register_instance(tmpl, inst);
|
||||
if (err) {
|
||||
err_free_inst:
|
||||
free(inst);
|
||||
free_inst(inst);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -322,7 +322,7 @@ static void exit_tfm(struct crypto_skcipher *tfm)
|
|||
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));
|
||||
kfree(inst);
|
||||
|
@ -434,12 +434,12 @@ static int create(struct crypto_template *tmpl, struct rtattr **tb)
|
|||
inst->alg.encrypt = encrypt;
|
||||
inst->alg.decrypt = decrypt;
|
||||
|
||||
inst->free = free;
|
||||
inst->free = free_inst;
|
||||
|
||||
err = skcipher_register_instance(tmpl, inst);
|
||||
if (err) {
|
||||
err_free_inst:
|
||||
free(inst);
|
||||
free_inst(inst);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -1994,23 +1994,31 @@ void acpi_ec_set_gpe_wake_mask(u8 action)
|
|||
acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action);
|
||||
}
|
||||
|
||||
bool acpi_ec_other_gpes_active(void)
|
||||
{
|
||||
return acpi_any_gpe_status_set(first_ec ? first_ec->gpe : U32_MAX);
|
||||
}
|
||||
|
||||
bool acpi_ec_dispatch_gpe(void)
|
||||
{
|
||||
u32 ret;
|
||||
|
||||
if (!first_ec)
|
||||
return acpi_any_gpe_status_set(U32_MAX);
|
||||
|
||||
/*
|
||||
* Report wakeup if the status bit is set for any enabled GPE other
|
||||
* than the EC one.
|
||||
*/
|
||||
if (acpi_any_gpe_status_set(first_ec->gpe))
|
||||
return true;
|
||||
|
||||
if (ec_no_wakeup)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Dispatch the EC GPE in-band, but do not report wakeup in any case
|
||||
* to allow the caller to process events properly after that.
|
||||
*/
|
||||
ret = acpi_dispatch_gpe(NULL, first_ec->gpe);
|
||||
if (ret == ACPI_INTERRUPT_HANDLED) {
|
||||
if (ret == ACPI_INTERRUPT_HANDLED)
|
||||
pm_pr_dbg("EC GPE dispatched\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
|
|
@ -202,7 +202,6 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
|
|||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
void acpi_ec_flush_work(void);
|
||||
bool acpi_ec_other_gpes_active(void);
|
||||
bool acpi_ec_dispatch_gpe(void);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1013,20 +1013,10 @@ static bool acpi_s2idle_wake(void)
|
|||
if (acpi_check_wakeup_handlers())
|
||||
return true;
|
||||
|
||||
/*
|
||||
* If the status bit is set for any enabled GPE other than the
|
||||
* EC one, the wakeup is regarded as a genuine one.
|
||||
*/
|
||||
if (acpi_ec_other_gpes_active())
|
||||
/* Check non-EC GPE wakeups and dispatch the EC GPE. */
|
||||
if (acpi_ec_dispatch_gpe())
|
||||
return true;
|
||||
|
||||
/*
|
||||
* If the EC GPE status bit has not been set, the wakeup is
|
||||
* regarded as a spurious one.
|
||||
*/
|
||||
if (!acpi_ec_dispatch_gpe())
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Cancel the wakeup and process all pending events in case
|
||||
* there are any wakeup ones in there.
|
||||
|
|
|
@ -645,6 +645,7 @@ static void amba_device_initialize(struct amba_device *dev, const char *name)
|
|||
dev->dev.release = amba_device_release;
|
||||
dev->dev.bus = &amba_bustype;
|
||||
dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
|
||||
dev->dev.dma_parms = &dev->dma_parms;
|
||||
dev->res.name = dev_name(&dev->dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -256,6 +256,7 @@ static int try_to_bring_up_master(struct master *master,
|
|||
ret = master->ops->bind(master->dev);
|
||||
if (ret < 0) {
|
||||
devres_release_group(master->dev, NULL);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_info(master->dev, "master bind failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -611,6 +612,7 @@ static int component_bind(struct component *component, struct master *master,
|
|||
devres_release_group(component->dev, NULL);
|
||||
devres_release_group(master->dev, NULL);
|
||||
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
|
||||
dev_name(component->dev), component->ops, ret);
|
||||
}
|
||||
|
|
|
@ -2370,6 +2370,11 @@ u32 fw_devlink_get_flags(void)
|
|||
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.
|
||||
* @dev: device.
|
||||
|
@ -2524,7 +2529,7 @@ int device_add(struct device *dev)
|
|||
if (fw_devlink_flags && is_fwnode_dev &&
|
||||
fwnode_has_op(dev->fwnode, add_links)) {
|
||||
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);
|
||||
else if (fw_ret)
|
||||
device_link_wait_for_optional_supplier(dev);
|
||||
|
|
|
@ -224,17 +224,9 @@ static int deferred_devs_show(struct seq_file *s, void *data)
|
|||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(deferred_devs);
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
/*
|
||||
* 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
|
||||
int 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)
|
||||
{
|
||||
|
@ -266,8 +258,8 @@ int driver_deferred_probe_check_state(struct device *dev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!driver_deferred_probe_timeout) {
|
||||
dev_WARN(dev, "deferred probe timeout, ignoring dependency");
|
||||
if (!driver_deferred_probe_timeout && initcalls_done) {
|
||||
dev_warn(dev, "deferred probe timeout, ignoring dependency");
|
||||
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)
|
||||
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);
|
||||
|
||||
|
@ -658,6 +651,9 @@ int driver_probe_done(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 */
|
||||
flush_work(&deferred_probe_work);
|
||||
|
||||
|
|
|
@ -380,6 +380,8 @@ struct platform_object {
|
|||
*/
|
||||
static void setup_pdev_dma_masks(struct platform_device *pdev)
|
||||
{
|
||||
pdev->dev.dma_parms = &pdev->dma_parms;
|
||||
|
||||
if (!pdev->dev.coherent_dma_mask)
|
||||
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
if (!pdev->dev.dma_mask) {
|
||||
|
|
|
@ -812,10 +812,9 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
|
|||
if (!mhi_cntrl)
|
||||
return -EINVAL;
|
||||
|
||||
if (!mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put)
|
||||
return -EINVAL;
|
||||
|
||||
if (!mhi_cntrl->status_cb || !mhi_cntrl->link_status)
|
||||
if (!mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put ||
|
||||
!mhi_cntrl->status_cb || !mhi_cntrl->read_reg ||
|
||||
!mhi_cntrl->write_reg)
|
||||
return -EINVAL;
|
||||
|
||||
ret = parse_config(mhi_cntrl, config);
|
||||
|
|
|
@ -11,9 +11,6 @@
|
|||
|
||||
extern struct bus_type mhi_bus_type;
|
||||
|
||||
/* MHI MMIO register mapping */
|
||||
#define PCI_INVALID_READ(val) (val == U32_MAX)
|
||||
|
||||
#define MHIREGLEN (0x0)
|
||||
#define MHIREGLEN_MHIREGLEN_MASK (0xFFFFFFFF)
|
||||
#define MHIREGLEN_MHIREGLEN_SHIFT (0)
|
||||
|
|
|
@ -18,16 +18,7 @@
|
|||
int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl,
|
||||
void __iomem *base, u32 offset, u32 *out)
|
||||
{
|
||||
u32 tmp = readl(base + offset);
|
||||
|
||||
/* 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;
|
||||
return mhi_cntrl->read_reg(mhi_cntrl, base + offset, out);
|
||||
}
|
||||
|
||||
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,
|
||||
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,
|
||||
|
@ -294,7 +285,7 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl)
|
|||
!(mhi_chan->ee_mask & BIT(mhi_cntrl->ee)))
|
||||
continue;
|
||||
mhi_dev = mhi_alloc_device(mhi_cntrl);
|
||||
if (!mhi_dev)
|
||||
if (IS_ERR(mhi_dev))
|
||||
return;
|
||||
|
||||
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 */
|
||||
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);
|
||||
|
||||
/* Init wakeup source if available */
|
||||
|
|
|
@ -902,7 +902,11 @@ int mhi_sync_power_up(struct mhi_controller *mhi_cntrl)
|
|||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
|
||||
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);
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
int 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;
|
||||
int event_size, size = 0;
|
||||
|
|
|
@ -531,7 +531,7 @@ static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
|
|||
{
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
|
||||
switch (config) {
|
||||
switch (pinconf_to_config_param(config)) {
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
return pca953x_gpio_set_pull_up_down(chip, offset, config);
|
||||
|
|
|
@ -368,6 +368,7 @@ static void tegra_gpio_irq_shutdown(struct irq_data *d)
|
|||
struct tegra_gpio_info *tgi = bank->tgi;
|
||||
unsigned int gpio = d->hwirq;
|
||||
|
||||
tegra_gpio_irq_mask(d);
|
||||
gpiochip_unlock_as_irq(&tgi->gc, gpio);
|
||||
}
|
||||
|
||||
|
|
|
@ -1158,8 +1158,19 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
|
|||
struct gpioline_info *info)
|
||||
{
|
||||
struct gpio_chip *gc = desc->gdev->chip;
|
||||
bool ok_for_pinctrl;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* This function takes a mutex so we must check this before taking
|
||||
* the spinlock.
|
||||
*
|
||||
* FIXME: find a non-racy way to retrieve this information. Maybe a
|
||||
* lock common to both frameworks?
|
||||
*/
|
||||
ok_for_pinctrl =
|
||||
pinctrl_gpio_can_use_line(gc->base + info->line_offset);
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
if (desc->name) {
|
||||
|
@ -1186,7 +1197,7 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
|
|||
test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
|
||||
test_bit(FLAG_EXPORT, &desc->flags) ||
|
||||
test_bit(FLAG_SYSFS, &desc->flags) ||
|
||||
!pinctrl_gpio_can_use_line(gc->base + info->line_offset))
|
||||
!ok_for_pinctrl)
|
||||
info->flags |= GPIOLINE_FLAG_KERNEL;
|
||||
if (test_bit(FLAG_IS_OUT, &desc->flags))
|
||||
info->flags |= GPIOLINE_FLAG_IS_OUT;
|
||||
|
@ -1227,6 +1238,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
void __user *ip = (void __user *)arg;
|
||||
struct gpio_desc *desc;
|
||||
__u32 offset;
|
||||
int hwgpio;
|
||||
|
||||
/* We fail any subsequent ioctl():s when the chip is gone */
|
||||
if (!gc)
|
||||
|
@ -1259,13 +1271,19 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
if (IS_ERR(desc))
|
||||
return PTR_ERR(desc);
|
||||
|
||||
hwgpio = gpio_chip_hwgpio(desc);
|
||||
|
||||
if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL &&
|
||||
test_bit(hwgpio, priv->watched_lines))
|
||||
return -EBUSY;
|
||||
|
||||
gpio_desc_to_lineinfo(desc, &lineinfo);
|
||||
|
||||
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
|
||||
return -EFAULT;
|
||||
|
||||
if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL)
|
||||
set_bit(gpio_chip_hwgpio(desc), priv->watched_lines);
|
||||
set_bit(hwgpio, priv->watched_lines);
|
||||
|
||||
return 0;
|
||||
} else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) {
|
||||
|
@ -1280,7 +1298,12 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
if (IS_ERR(desc))
|
||||
return PTR_ERR(desc);
|
||||
|
||||
clear_bit(gpio_chip_hwgpio(desc), priv->watched_lines);
|
||||
hwgpio = gpio_chip_hwgpio(desc);
|
||||
|
||||
if (!test_bit(hwgpio, priv->watched_lines))
|
||||
return -EBUSY;
|
||||
|
||||
clear_bit(hwgpio, priv->watched_lines);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
|
@ -5289,8 +5312,9 @@ static int __init gpiolib_dev_init(void)
|
|||
gpiolib_initialized = true;
|
||||
gpiochip_setup_devs();
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF_DYNAMIC))
|
||||
#if IS_ENABLED(CONFIG_OF_DYNAMIC) && IS_ENABLED(CONFIG_OF_GPIO)
|
||||
WARN_ON(of_reconfig_notifier_register(&gpio_of_notifier));
|
||||
#endif /* CONFIG_OF_DYNAMIC && CONFIG_OF_GPIO */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -945,6 +945,7 @@ struct amdgpu_device {
|
|||
|
||||
/* s3/s4 mask */
|
||||
bool in_suspend;
|
||||
bool in_hibernate;
|
||||
|
||||
/* record last mm index being written through WREG32*/
|
||||
unsigned long last_mm_index;
|
||||
|
|
|
@ -1343,7 +1343,7 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(
|
|||
}
|
||||
|
||||
/* Free the BO*/
|
||||
amdgpu_bo_unref(&mem->bo);
|
||||
drm_gem_object_put_unlocked(&mem->bo->tbo.base);
|
||||
mutex_destroy(&mem->lock);
|
||||
kfree(mem);
|
||||
|
||||
|
@ -1688,7 +1688,8 @@ int amdgpu_amdkfd_gpuvm_import_dmabuf(struct kgd_dev *kgd,
|
|||
| KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE
|
||||
| KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE;
|
||||
|
||||
(*mem)->bo = amdgpu_bo_ref(bo);
|
||||
drm_gem_object_get(&bo->tbo.base);
|
||||
(*mem)->bo = bo;
|
||||
(*mem)->va = va;
|
||||
(*mem)->domain = (bo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM) ?
|
||||
AMDGPU_GEM_DOMAIN_VRAM : AMDGPU_GEM_DOMAIN_GTT;
|
||||
|
|
|
@ -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);
|
||||
|
||||
r = amdgpu_device_ip_suspend_phase1(adev);
|
||||
|
||||
amdgpu_amdkfd_suspend(adev, !fbcon);
|
||||
|
||||
/* evict vram memory */
|
||||
amdgpu_bo_evict_vram(adev);
|
||||
|
||||
|
|
|
@ -1181,7 +1181,9 @@ static int amdgpu_pmops_freeze(struct device *dev)
|
|||
struct amdgpu_device *adev = drm_dev->dev_private;
|
||||
int r;
|
||||
|
||||
adev->in_hibernate = true;
|
||||
r = amdgpu_device_suspend(drm_dev, true);
|
||||
adev->in_hibernate = false;
|
||||
if (r)
|
||||
return r;
|
||||
return amdgpu_asic_reset(adev);
|
||||
|
|
|
@ -133,8 +133,7 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev,
|
|||
u32 cpp;
|
||||
u64 flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED |
|
||||
AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
|
||||
AMDGPU_GEM_CREATE_VRAM_CLEARED |
|
||||
AMDGPU_GEM_CREATE_CPU_GTT_USWC;
|
||||
AMDGPU_GEM_CREATE_VRAM_CLEARED;
|
||||
|
||||
info = drm_get_format_info(adev->ddev, mode_cmd);
|
||||
cpp = info->cpp[0];
|
||||
|
|
|
@ -4273,7 +4273,7 @@ static int gfx_v10_0_update_gfx_clock_gating(struct amdgpu_device *adev,
|
|||
/* === CGCG /CGLS for GFX 3D Only === */
|
||||
gfx_v10_0_update_3d_clock_gating(adev, enable);
|
||||
/* === MGCG + MGLS === */
|
||||
/* gfx_v10_0_update_medium_grain_clock_gating(adev, enable); */
|
||||
gfx_v10_0_update_medium_grain_clock_gating(adev, enable);
|
||||
}
|
||||
|
||||
if (adev->cg_flags &
|
||||
|
@ -4353,11 +4353,7 @@ static int gfx_v10_0_set_powergating_state(void *handle,
|
|||
switch (adev->asic_type) {
|
||||
case CHIP_NAVI10:
|
||||
case CHIP_NAVI14:
|
||||
if (!enable) {
|
||||
amdgpu_gfx_off_ctrl(adev, false);
|
||||
cancel_delayed_work_sync(&adev->gfx.gfx_off_delay_work);
|
||||
} else
|
||||
amdgpu_gfx_off_ctrl(adev, true);
|
||||
amdgpu_gfx_off_ctrl(adev, enable);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -4918,6 +4914,19 @@ static void gfx_v10_0_ring_emit_reg_write_reg_wait(struct amdgpu_ring *ring,
|
|||
ref, mask);
|
||||
}
|
||||
|
||||
static void gfx_v10_0_ring_soft_recovery(struct amdgpu_ring *ring,
|
||||
unsigned vmid)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
uint32_t value = 0;
|
||||
|
||||
value = REG_SET_FIELD(value, SQ_CMD, CMD, 0x03);
|
||||
value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01);
|
||||
value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1);
|
||||
value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid);
|
||||
WREG32_SOC15(GC, 0, mmSQ_CMD, value);
|
||||
}
|
||||
|
||||
static void
|
||||
gfx_v10_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev,
|
||||
uint32_t me, uint32_t pipe,
|
||||
|
@ -5309,6 +5318,7 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_gfx = {
|
|||
.emit_wreg = gfx_v10_0_ring_emit_wreg,
|
||||
.emit_reg_wait = gfx_v10_0_ring_emit_reg_wait,
|
||||
.emit_reg_write_reg_wait = gfx_v10_0_ring_emit_reg_write_reg_wait,
|
||||
.soft_recovery = gfx_v10_0_ring_soft_recovery,
|
||||
};
|
||||
|
||||
static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_compute = {
|
||||
|
|
|
@ -1236,6 +1236,8 @@ static const struct amdgpu_gfxoff_quirk amdgpu_gfxoff_quirk_list[] = {
|
|||
{ 0x1002, 0x15dd, 0x1002, 0x15dd, 0xc8 },
|
||||
/* https://bugzilla.kernel.org/show_bug.cgi?id=207171 */
|
||||
{ 0x1002, 0x15dd, 0x103c, 0x83e7, 0xd3 },
|
||||
/* GFXOFF is unstable on C6 parts with a VBIOS 113-RAVEN-114 */
|
||||
{ 0x1002, 0x15dd, 0x1002, 0x15dd, 0xc6 },
|
||||
{ 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
|
@ -5025,10 +5027,9 @@ static int gfx_v9_0_set_powergating_state(void *handle,
|
|||
switch (adev->asic_type) {
|
||||
case CHIP_RAVEN:
|
||||
case CHIP_RENOIR:
|
||||
if (!enable) {
|
||||
if (!enable)
|
||||
amdgpu_gfx_off_ctrl(adev, false);
|
||||
cancel_delayed_work_sync(&adev->gfx.gfx_off_delay_work);
|
||||
}
|
||||
|
||||
if (adev->pg_flags & AMD_PG_SUPPORT_RLC_SMU_HS) {
|
||||
gfx_v9_0_enable_sck_slow_down_on_power_up(adev, true);
|
||||
gfx_v9_0_enable_sck_slow_down_on_power_down(adev, true);
|
||||
|
@ -5052,12 +5053,7 @@ static int gfx_v9_0_set_powergating_state(void *handle,
|
|||
amdgpu_gfx_off_ctrl(adev, true);
|
||||
break;
|
||||
case CHIP_VEGA12:
|
||||
if (!enable) {
|
||||
amdgpu_gfx_off_ctrl(adev, false);
|
||||
cancel_delayed_work_sync(&adev->gfx.gfx_off_delay_work);
|
||||
} else {
|
||||
amdgpu_gfx_off_ctrl(adev, true);
|
||||
}
|
||||
amdgpu_gfx_off_ctrl(adev, enable);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -441,7 +441,7 @@ static void dm_vupdate_high_irq(void *interrupt_params)
|
|||
|
||||
/**
|
||||
* dm_crtc_high_irq() - Handles CRTC interrupt
|
||||
* @interrupt_params: ignored
|
||||
* @interrupt_params: used for determining the CRTC instance
|
||||
*
|
||||
* Handles the CRTC/VSYNC interrupt by notfying DRM's VBLANK
|
||||
* event handler.
|
||||
|
@ -455,70 +455,6 @@ static void dm_crtc_high_irq(void *interrupt_params)
|
|||
unsigned long flags;
|
||||
|
||||
acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);
|
||||
|
||||
if (acrtc) {
|
||||
acrtc_state = to_dm_crtc_state(acrtc->base.state);
|
||||
|
||||
DRM_DEBUG_VBL("crtc:%d, vupdate-vrr:%d\n",
|
||||
acrtc->crtc_id,
|
||||
amdgpu_dm_vrr_active(acrtc_state));
|
||||
|
||||
/* Core vblank handling at start of front-porch is only possible
|
||||
* in non-vrr mode, as only there vblank timestamping will give
|
||||
* valid results while done in front-porch. Otherwise defer it
|
||||
* to dm_vupdate_high_irq after end of front-porch.
|
||||
*/
|
||||
if (!amdgpu_dm_vrr_active(acrtc_state))
|
||||
drm_crtc_handle_vblank(&acrtc->base);
|
||||
|
||||
/* Following stuff must happen at start of vblank, for crc
|
||||
* computation and below-the-range btr support in vrr mode.
|
||||
*/
|
||||
amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
|
||||
|
||||
if (acrtc_state->stream && adev->family >= AMDGPU_FAMILY_AI &&
|
||||
acrtc_state->vrr_params.supported &&
|
||||
acrtc_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE) {
|
||||
spin_lock_irqsave(&adev->ddev->event_lock, flags);
|
||||
mod_freesync_handle_v_update(
|
||||
adev->dm.freesync_module,
|
||||
acrtc_state->stream,
|
||||
&acrtc_state->vrr_params);
|
||||
|
||||
dc_stream_adjust_vmin_vmax(
|
||||
adev->dm.dc,
|
||||
acrtc_state->stream,
|
||||
&acrtc_state->vrr_params.adjust);
|
||||
spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN)
|
||||
/**
|
||||
* dm_dcn_crtc_high_irq() - Handles VStartup interrupt for DCN generation ASICs
|
||||
* @interrupt params - interrupt parameters
|
||||
*
|
||||
* Notify DRM's vblank event handler at VSTARTUP
|
||||
*
|
||||
* Unlike DCE hardware, we trigger the handler at VSTARTUP. at which:
|
||||
* * We are close enough to VUPDATE - the point of no return for hw
|
||||
* * We are in the fixed portion of variable front porch when vrr is enabled
|
||||
* * We are before VUPDATE, where double-buffered vrr registers are swapped
|
||||
*
|
||||
* It is therefore the correct place to signal vblank, send user flip events,
|
||||
* and update VRR.
|
||||
*/
|
||||
static void dm_dcn_crtc_high_irq(void *interrupt_params)
|
||||
{
|
||||
struct common_irq_params *irq_params = interrupt_params;
|
||||
struct amdgpu_device *adev = irq_params->adev;
|
||||
struct amdgpu_crtc *acrtc;
|
||||
struct dm_crtc_state *acrtc_state;
|
||||
unsigned long flags;
|
||||
|
||||
acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);
|
||||
|
||||
if (!acrtc)
|
||||
return;
|
||||
|
||||
|
@ -528,21 +464,34 @@ static void dm_dcn_crtc_high_irq(void *interrupt_params)
|
|||
amdgpu_dm_vrr_active(acrtc_state),
|
||||
acrtc_state->active_planes);
|
||||
|
||||
amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
|
||||
/**
|
||||
* Core vblank handling at start of front-porch is only possible
|
||||
* in non-vrr mode, as only there vblank timestamping will give
|
||||
* valid results while done in front-porch. Otherwise defer it
|
||||
* to dm_vupdate_high_irq after end of front-porch.
|
||||
*/
|
||||
if (!amdgpu_dm_vrr_active(acrtc_state))
|
||||
drm_crtc_handle_vblank(&acrtc->base);
|
||||
|
||||
/**
|
||||
* Following stuff must happen at start of vblank, for crc
|
||||
* computation and below-the-range btr support in vrr mode.
|
||||
*/
|
||||
amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
|
||||
|
||||
/* BTR updates need to happen before VUPDATE on Vega and above. */
|
||||
if (adev->family < AMDGPU_FAMILY_AI)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&adev->ddev->event_lock, flags);
|
||||
|
||||
if (acrtc_state->vrr_params.supported &&
|
||||
if (acrtc_state->stream && acrtc_state->vrr_params.supported &&
|
||||
acrtc_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE) {
|
||||
mod_freesync_handle_v_update(
|
||||
adev->dm.freesync_module,
|
||||
mod_freesync_handle_v_update(adev->dm.freesync_module,
|
||||
acrtc_state->stream,
|
||||
&acrtc_state->vrr_params);
|
||||
|
||||
dc_stream_adjust_vmin_vmax(
|
||||
adev->dm.dc,
|
||||
acrtc_state->stream,
|
||||
dc_stream_adjust_vmin_vmax(adev->dm.dc, acrtc_state->stream,
|
||||
&acrtc_state->vrr_params.adjust);
|
||||
}
|
||||
|
||||
|
@ -556,7 +505,8 @@ static void dm_dcn_crtc_high_irq(void *interrupt_params)
|
|||
* avoid race conditions between flip programming and completion,
|
||||
* which could cause too early flip completion events.
|
||||
*/
|
||||
if (acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&
|
||||
if (adev->family >= AMDGPU_FAMILY_RV &&
|
||||
acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&
|
||||
acrtc_state->active_planes == 0) {
|
||||
if (acrtc->event) {
|
||||
drm_crtc_send_vblank_event(&acrtc->base, acrtc->event);
|
||||
|
@ -568,7 +518,6 @@ static void dm_dcn_crtc_high_irq(void *interrupt_params)
|
|||
|
||||
spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dm_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
|
@ -2008,17 +1957,22 @@ void amdgpu_dm_update_connector_after_detect(
|
|||
dc_sink_retain(aconnector->dc_sink);
|
||||
if (sink->dc_edid.length == 0) {
|
||||
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 {
|
||||
aconnector->edid =
|
||||
(struct edid *) sink->dc_edid.raw_edid;
|
||||
|
||||
(struct edid *)sink->dc_edid.raw_edid;
|
||||
|
||||
drm_connector_update_edid_property(connector,
|
||||
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);
|
||||
update_connector_ext_caps(aconnector);
|
||||
} else {
|
||||
|
@ -2440,8 +2394,36 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
|
|||
c_irq_params->adev = adev;
|
||||
c_irq_params->irq_src = int_params.irq_source;
|
||||
|
||||
amdgpu_dm_irq_register_interrupt(
|
||||
adev, &int_params, dm_crtc_high_irq, c_irq_params);
|
||||
}
|
||||
|
||||
/* Use VUPDATE_NO_LOCK interrupt on DCN, which seems to correspond to
|
||||
* the regular VUPDATE interrupt on DCE. We want DC_IRQ_SOURCE_VUPDATEx
|
||||
* to trigger at end of each vblank, regardless of state of the lock,
|
||||
* matching DCE behaviour.
|
||||
*/
|
||||
for (i = DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT;
|
||||
i <= DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT + adev->mode_info.num_crtc - 1;
|
||||
i++) {
|
||||
r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->vupdate_irq);
|
||||
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to add vupdate irq id!\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
|
||||
int_params.irq_source =
|
||||
dc_interrupt_to_irq_source(dc, i, 0);
|
||||
|
||||
c_irq_params = &adev->dm.vupdate_params[int_params.irq_source - DC_IRQ_SOURCE_VUPDATE1];
|
||||
|
||||
c_irq_params->adev = adev;
|
||||
c_irq_params->irq_src = int_params.irq_source;
|
||||
|
||||
amdgpu_dm_irq_register_interrupt(adev, &int_params,
|
||||
dm_dcn_crtc_high_irq, c_irq_params);
|
||||
dm_vupdate_high_irq, c_irq_params);
|
||||
}
|
||||
|
||||
/* Use GRPH_PFLIP interrupt */
|
||||
|
@ -4448,10 +4430,6 @@ static inline int dm_set_vupdate_irq(struct drm_crtc *crtc, bool enable)
|
|||
struct amdgpu_device *adev = crtc->dev->dev_private;
|
||||
int rc;
|
||||
|
||||
/* Do not set vupdate for DCN hardware */
|
||||
if (adev->family > AMDGPU_FAMILY_AI)
|
||||
return 0;
|
||||
|
||||
irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst;
|
||||
|
||||
rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
|
||||
|
@ -7877,6 +7855,7 @@ static int dm_update_plane_state(struct dc *dc,
|
|||
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
|
||||
struct dm_crtc_state *dm_new_crtc_state, *dm_old_crtc_state;
|
||||
struct dm_plane_state *dm_new_plane_state, *dm_old_plane_state;
|
||||
struct amdgpu_crtc *new_acrtc;
|
||||
bool needs_reset;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -7886,10 +7865,31 @@ static int dm_update_plane_state(struct dc *dc,
|
|||
dm_new_plane_state = to_dm_plane_state(new_plane_state);
|
||||
dm_old_plane_state = to_dm_plane_state(old_plane_state);
|
||||
|
||||
/*TODO Implement atomic check for cursor plane */
|
||||
if (plane->type == DRM_PLANE_TYPE_CURSOR)
|
||||
/*TODO Implement better atomic check for cursor plane */
|
||||
if (plane->type == DRM_PLANE_TYPE_CURSOR) {
|
||||
if (!enable || !new_plane_crtc ||
|
||||
drm_atomic_plane_disabling(plane->state, new_plane_state))
|
||||
return 0;
|
||||
|
||||
new_acrtc = to_amdgpu_crtc(new_plane_crtc);
|
||||
|
||||
if ((new_plane_state->crtc_w > new_acrtc->max_cursor_width) ||
|
||||
(new_plane_state->crtc_h > new_acrtc->max_cursor_height)) {
|
||||
DRM_DEBUG_ATOMIC("Bad cursor size %d x %d\n",
|
||||
new_plane_state->crtc_w, new_plane_state->crtc_h);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (new_plane_state->crtc_x <= -new_acrtc->max_cursor_width ||
|
||||
new_plane_state->crtc_y <= -new_acrtc->max_cursor_height) {
|
||||
DRM_DEBUG_ATOMIC("Bad cursor position %d, %d\n",
|
||||
new_plane_state->crtc_x, new_plane_state->crtc_y);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
needs_reset = should_reset_plane(state, plane, old_plane_state,
|
||||
new_plane_state);
|
||||
|
||||
|
|
|
@ -398,15 +398,15 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
|
|||
struct mod_hdcp_display *display = &hdcp_work[link_index].display;
|
||||
struct mod_hdcp_link *link = &hdcp_work[link_index].link;
|
||||
|
||||
memset(display, 0, sizeof(*display));
|
||||
memset(link, 0, sizeof(*link));
|
||||
|
||||
display->index = aconnector->base.index;
|
||||
|
||||
if (config->dpms_off) {
|
||||
hdcp_remove_display(hdcp_work, link_index, aconnector);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(display, 0, sizeof(*display));
|
||||
memset(link, 0, sizeof(*link));
|
||||
|
||||
display->index = aconnector->base.index;
|
||||
display->state = MOD_HDCP_DISPLAY_ACTIVE;
|
||||
|
||||
if (aconnector->dc_sink != NULL)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
int i;
|
||||
int count = 0;
|
||||
struct pipe_ctx *pipe;
|
||||
PERF_TRACE();
|
||||
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)
|
||||
continue;
|
||||
|
|
|
@ -3068,25 +3068,32 @@ static bool dcn20_validate_bandwidth_internal(struct dc *dc, struct dc_state *co
|
|||
return out;
|
||||
}
|
||||
|
||||
|
||||
bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context,
|
||||
bool fast_validate)
|
||||
/*
|
||||
* This must be noinline to ensure anything that deals with FP registers
|
||||
* is contained within this call; previously our compiling with hard-float
|
||||
* would result in fp instructions being emitted outside of the boundaries
|
||||
* of the DC_FP_START/END macros, which makes sense as the compiler has no
|
||||
* idea about what is wrapped and what is not
|
||||
*
|
||||
* This is largely just a workaround to avoid breakage introduced with 5.6,
|
||||
* ideally all fp-using code should be moved into its own file, only that
|
||||
* should be compiled with hard-float, and all code exported from there
|
||||
* should be strictly wrapped with DC_FP_START/END
|
||||
*/
|
||||
static noinline bool dcn20_validate_bandwidth_fp(struct dc *dc,
|
||||
struct dc_state *context, bool fast_validate)
|
||||
{
|
||||
bool voltage_supported = false;
|
||||
bool full_pstate_supported = false;
|
||||
bool dummy_pstate_supported = false;
|
||||
double p_state_latency_us;
|
||||
|
||||
DC_FP_START();
|
||||
p_state_latency_us = context->bw_ctx.dml.soc.dram_clock_change_latency_us;
|
||||
context->bw_ctx.dml.soc.disable_dram_clock_change_vactive_support =
|
||||
dc->debug.disable_dram_clock_change_vactive_support;
|
||||
|
||||
if (fast_validate) {
|
||||
voltage_supported = dcn20_validate_bandwidth_internal(dc, context, true);
|
||||
|
||||
DC_FP_END();
|
||||
return voltage_supported;
|
||||
return dcn20_validate_bandwidth_internal(dc, context, true);
|
||||
}
|
||||
|
||||
// Best case, we support full UCLK switch latency
|
||||
|
@ -3115,7 +3122,15 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context,
|
|||
|
||||
restore_dml_state:
|
||||
context->bw_ctx.dml.soc.dram_clock_change_latency_us = p_state_latency_us;
|
||||
return voltage_supported;
|
||||
}
|
||||
|
||||
bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context,
|
||||
bool fast_validate)
|
||||
{
|
||||
bool voltage_supported = false;
|
||||
DC_FP_START();
|
||||
voltage_supported = dcn20_validate_bandwidth_fp(dc, context, fast_validate);
|
||||
DC_FP_END();
|
||||
return voltage_supported;
|
||||
}
|
||||
|
|
|
@ -1200,7 +1200,7 @@ static void dml_rq_dlg_get_dlg_params(
|
|||
min_hratio_fact_l = 1.0;
|
||||
min_hratio_fact_c = 1.0;
|
||||
|
||||
if (htaps_l <= 1)
|
||||
if (hratio_l <= 1)
|
||||
min_hratio_fact_l = 2.0;
|
||||
else if (htaps_l <= 6) {
|
||||
if ((hratio_l * 2.0) > 4.0)
|
||||
|
@ -1216,7 +1216,7 @@ static void dml_rq_dlg_get_dlg_params(
|
|||
|
||||
hscale_pixel_rate_l = min_hratio_fact_l * dppclk_freq_in_mhz;
|
||||
|
||||
if (htaps_c <= 1)
|
||||
if (hratio_c <= 1)
|
||||
min_hratio_fact_c = 2.0;
|
||||
else if (htaps_c <= 6) {
|
||||
if ((hratio_c * 2.0) > 4.0)
|
||||
|
@ -1522,8 +1522,8 @@ static void dml_rq_dlg_get_dlg_params(
|
|||
|
||||
disp_dlg_regs->refcyc_per_vm_group_vblank = get_refcyc_per_vm_group_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz;
|
||||
disp_dlg_regs->refcyc_per_vm_group_flip = get_refcyc_per_vm_group_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz;
|
||||
disp_dlg_regs->refcyc_per_vm_req_vblank = get_refcyc_per_vm_req_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz;
|
||||
disp_dlg_regs->refcyc_per_vm_req_flip = get_refcyc_per_vm_req_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz;
|
||||
disp_dlg_regs->refcyc_per_vm_req_vblank = get_refcyc_per_vm_req_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz * dml_pow(2, 10);
|
||||
disp_dlg_regs->refcyc_per_vm_req_flip = get_refcyc_per_vm_req_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz * dml_pow(2, 10);
|
||||
|
||||
// Clamp to max for now
|
||||
if (disp_dlg_regs->refcyc_per_vm_group_vblank >= (unsigned int)dml_pow(2, 23))
|
||||
|
|
|
@ -108,7 +108,7 @@
|
|||
#define ASSERT(expr) ASSERT_CRITICAL(expr)
|
||||
|
||||
#else
|
||||
#define ASSERT(expr) WARN_ON(!(expr))
|
||||
#define ASSERT(expr) WARN_ON_ONCE(!(expr))
|
||||
#endif
|
||||
|
||||
#define BREAK_TO_DEBUGGER() ASSERT(0)
|
||||
|
|
|
@ -319,12 +319,12 @@ static void pp_dpm_en_umd_pstate(struct pp_hwmgr *hwmgr,
|
|||
if (*level & profile_mode_mask) {
|
||||
hwmgr->saved_dpm_level = hwmgr->dpm_level;
|
||||
hwmgr->en_umd_pstate = true;
|
||||
amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
|
||||
AMD_IP_BLOCK_TYPE_GFX,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
amdgpu_device_ip_set_powergating_state(hwmgr->adev,
|
||||
AMD_IP_BLOCK_TYPE_GFX,
|
||||
AMD_PG_STATE_UNGATE);
|
||||
amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
|
||||
AMD_IP_BLOCK_TYPE_GFX,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
}
|
||||
} else {
|
||||
/* exit umd pstate, restore level, enable gfx cg*/
|
||||
|
|
|
@ -1476,7 +1476,7 @@ static int smu_disable_dpm(struct smu_context *smu)
|
|||
bool use_baco = !smu->is_apu &&
|
||||
((adev->in_gpu_reset &&
|
||||
(amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO)) ||
|
||||
(adev->in_runpm && amdgpu_asic_supports_baco(adev)));
|
||||
((adev->in_runpm || adev->in_hibernate) && amdgpu_asic_supports_baco(adev)));
|
||||
|
||||
ret = smu_get_smc_version(smu, NULL, &smu_version);
|
||||
if (ret) {
|
||||
|
@ -1744,12 +1744,12 @@ static int smu_enable_umd_pstate(void *handle,
|
|||
if (*level & profile_mode_mask) {
|
||||
smu_dpm_ctx->saved_dpm_level = smu_dpm_ctx->dpm_level;
|
||||
smu_dpm_ctx->enable_umd_pstate = true;
|
||||
amdgpu_device_ip_set_clockgating_state(smu->adev,
|
||||
AMD_IP_BLOCK_TYPE_GFX,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
amdgpu_device_ip_set_powergating_state(smu->adev,
|
||||
AMD_IP_BLOCK_TYPE_GFX,
|
||||
AMD_PG_STATE_UNGATE);
|
||||
amdgpu_device_ip_set_clockgating_state(smu->adev,
|
||||
AMD_IP_BLOCK_TYPE_GFX,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
}
|
||||
} else {
|
||||
/* exit umd pstate, restore level, enable gfx cg*/
|
||||
|
|
|
@ -241,8 +241,12 @@ static int drm_hdcp_request_srm(struct drm_device *drm_dev,
|
|||
|
||||
ret = request_firmware_direct(&fw, (const char *)fw_name,
|
||||
drm_dev->dev);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
*revoked_ksv_cnt = 0;
|
||||
*revoked_ksv_list = NULL;
|
||||
ret = 0;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (fw->size && fw->data)
|
||||
ret = drm_hdcp_srm_update(fw->data, fw->size, revoked_ksv_list,
|
||||
|
@ -287,6 +291,8 @@ int drm_hdcp_check_ksvs_revoked(struct drm_device *drm_dev, u8 *ksvs,
|
|||
|
||||
ret = drm_hdcp_request_srm(drm_dev, &revoked_ksv_list,
|
||||
&revoked_ksv_cnt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* revoked_ksv_cnt will be zero when above function failed */
|
||||
for (i = 0; i < revoked_ksv_cnt; i++)
|
||||
|
|
|
@ -485,8 +485,7 @@ static int intel_fbc_alloc_cfb(struct drm_i915_private *dev_priv,
|
|||
if (!ret)
|
||||
goto err_llb;
|
||||
else if (ret > 1) {
|
||||
DRM_INFO("Reducing the compressed framebuffer size. This may lead to less power savings than a non-reduced-size. Try to increase stolen memory size if available in BIOS.\n");
|
||||
|
||||
DRM_INFO_ONCE("Reducing the compressed framebuffer size. This may lead to less power savings than a non-reduced-size. Try to increase stolen memory size if available in BIOS.\n");
|
||||
}
|
||||
|
||||
fbc->threshold = ret;
|
||||
|
|
|
@ -368,7 +368,6 @@ static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj)
|
|||
struct drm_i915_private *i915 = to_i915(obj->base.dev);
|
||||
struct i915_vma *vma;
|
||||
|
||||
GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
|
||||
if (!atomic_read(&obj->bind_count))
|
||||
return;
|
||||
|
||||
|
@ -400,12 +399,8 @@ static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj)
|
|||
void
|
||||
i915_gem_object_unpin_from_display_plane(struct i915_vma *vma)
|
||||
{
|
||||
struct drm_i915_gem_object *obj = vma->obj;
|
||||
|
||||
assert_object_held(obj);
|
||||
|
||||
/* Bump the LRU to try and avoid premature eviction whilst flipping */
|
||||
i915_gem_object_bump_inactive_ggtt(obj);
|
||||
i915_gem_object_bump_inactive_ggtt(vma->obj);
|
||||
|
||||
i915_vma_unpin(vma);
|
||||
}
|
||||
|
|
|
@ -69,7 +69,13 @@ struct intel_context {
|
|||
#define CONTEXT_NOPREEMPT 7
|
||||
|
||||
u32 *lrc_reg_state;
|
||||
u64 lrc_desc;
|
||||
union {
|
||||
struct {
|
||||
u32 lrca;
|
||||
u32 ccid;
|
||||
};
|
||||
u64 desc;
|
||||
} lrc;
|
||||
u32 tag; /* cookie passed to HW to track this context on submission */
|
||||
|
||||
/* Time on GPU as tracked by the hw. */
|
||||
|
|
|
@ -333,13 +333,4 @@ intel_engine_has_preempt_reset(const struct intel_engine_cs *engine)
|
|||
return intel_engine_has_preemption(engine);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
intel_engine_has_timeslices(const struct intel_engine_cs *engine)
|
||||
{
|
||||
if (!IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION))
|
||||
return false;
|
||||
|
||||
return intel_engine_has_semaphores(engine);
|
||||
}
|
||||
|
||||
#endif /* _INTEL_RINGBUFFER_H_ */
|
||||
|
|
|
@ -1295,6 +1295,12 @@ static void intel_engine_print_registers(struct intel_engine_cs *engine,
|
|||
|
||||
if (engine->id == RENDER_CLASS && IS_GEN_RANGE(dev_priv, 4, 7))
|
||||
drm_printf(m, "\tCCID: 0x%08x\n", ENGINE_READ(engine, CCID));
|
||||
if (HAS_EXECLISTS(dev_priv)) {
|
||||
drm_printf(m, "\tEL_STAT_HI: 0x%08x\n",
|
||||
ENGINE_READ(engine, RING_EXECLIST_STATUS_HI));
|
||||
drm_printf(m, "\tEL_STAT_LO: 0x%08x\n",
|
||||
ENGINE_READ(engine, RING_EXECLIST_STATUS_LO));
|
||||
}
|
||||
drm_printf(m, "\tRING_START: 0x%08x\n",
|
||||
ENGINE_READ(engine, RING_START));
|
||||
drm_printf(m, "\tRING_HEAD: 0x%08x\n",
|
||||
|
|
|
@ -156,6 +156,20 @@ struct intel_engine_execlists {
|
|||
*/
|
||||
struct i915_priolist default_priolist;
|
||||
|
||||
/**
|
||||
* @ccid: identifier for contexts submitted to this engine
|
||||
*/
|
||||
u32 ccid;
|
||||
|
||||
/**
|
||||
* @yield: CCID at the time of the last semaphore-wait interrupt.
|
||||
*
|
||||
* Instead of leaving a semaphore busy-spinning on an engine, we would
|
||||
* like to switch to another ready context, i.e. yielding the semaphore
|
||||
* timeslice.
|
||||
*/
|
||||
u32 yield;
|
||||
|
||||
/**
|
||||
* @error_interrupt: CS Master EIR
|
||||
*
|
||||
|
@ -295,8 +309,7 @@ struct intel_engine_cs {
|
|||
u32 context_size;
|
||||
u32 mmio_base;
|
||||
|
||||
unsigned int context_tag;
|
||||
#define NUM_CONTEXT_TAG roundup_pow_of_two(2 * EXECLIST_MAX_PORTS)
|
||||
unsigned long context_tag;
|
||||
|
||||
struct rb_node uabi_node;
|
||||
|
||||
|
@ -483,10 +496,11 @@ struct intel_engine_cs {
|
|||
#define I915_ENGINE_SUPPORTS_STATS BIT(1)
|
||||
#define I915_ENGINE_HAS_PREEMPTION BIT(2)
|
||||
#define I915_ENGINE_HAS_SEMAPHORES BIT(3)
|
||||
#define I915_ENGINE_NEEDS_BREADCRUMB_TASKLET BIT(4)
|
||||
#define I915_ENGINE_IS_VIRTUAL BIT(5)
|
||||
#define I915_ENGINE_HAS_RELATIVE_MMIO BIT(6)
|
||||
#define I915_ENGINE_REQUIRES_CMD_PARSER BIT(7)
|
||||
#define I915_ENGINE_HAS_TIMESLICES BIT(4)
|
||||
#define I915_ENGINE_NEEDS_BREADCRUMB_TASKLET BIT(5)
|
||||
#define I915_ENGINE_IS_VIRTUAL BIT(6)
|
||||
#define I915_ENGINE_HAS_RELATIVE_MMIO BIT(7)
|
||||
#define I915_ENGINE_REQUIRES_CMD_PARSER BIT(8)
|
||||
unsigned int flags;
|
||||
|
||||
/*
|
||||
|
@ -584,6 +598,15 @@ intel_engine_has_semaphores(const struct intel_engine_cs *engine)
|
|||
return engine->flags & I915_ENGINE_HAS_SEMAPHORES;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
intel_engine_has_timeslices(const struct intel_engine_cs *engine)
|
||||
{
|
||||
if (!IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION))
|
||||
return false;
|
||||
|
||||
return engine->flags & I915_ENGINE_HAS_TIMESLICES;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
intel_engine_needs_breadcrumb_tasklet(const struct intel_engine_cs *engine)
|
||||
{
|
||||
|
|
|
@ -39,6 +39,15 @@ cs_irq_handler(struct intel_engine_cs *engine, u32 iir)
|
|||
}
|
||||
}
|
||||
|
||||
if (iir & GT_WAIT_SEMAPHORE_INTERRUPT) {
|
||||
WRITE_ONCE(engine->execlists.yield,
|
||||
ENGINE_READ_FW(engine, RING_EXECLIST_STATUS_HI));
|
||||
ENGINE_TRACE(engine, "semaphore yield: %08x\n",
|
||||
engine->execlists.yield);
|
||||
if (del_timer(&engine->execlists.timer))
|
||||
tasklet = true;
|
||||
}
|
||||
|
||||
if (iir & GT_CONTEXT_SWITCH_INTERRUPT)
|
||||
tasklet = true;
|
||||
|
||||
|
@ -228,7 +237,8 @@ void gen11_gt_irq_postinstall(struct intel_gt *gt)
|
|||
const u32 irqs =
|
||||
GT_CS_MASTER_ERROR_INTERRUPT |
|
||||
GT_RENDER_USER_INTERRUPT |
|
||||
GT_CONTEXT_SWITCH_INTERRUPT;
|
||||
GT_CONTEXT_SWITCH_INTERRUPT |
|
||||
GT_WAIT_SEMAPHORE_INTERRUPT;
|
||||
struct intel_uncore *uncore = gt->uncore;
|
||||
const u32 dmask = irqs << 16 | irqs;
|
||||
const u32 smask = irqs << 16;
|
||||
|
@ -366,7 +376,8 @@ void gen8_gt_irq_postinstall(struct intel_gt *gt)
|
|||
const u32 irqs =
|
||||
GT_CS_MASTER_ERROR_INTERRUPT |
|
||||
GT_RENDER_USER_INTERRUPT |
|
||||
GT_CONTEXT_SWITCH_INTERRUPT;
|
||||
GT_CONTEXT_SWITCH_INTERRUPT |
|
||||
GT_WAIT_SEMAPHORE_INTERRUPT;
|
||||
const u32 gt_interrupts[] = {
|
||||
irqs << GEN8_RCS_IRQ_SHIFT | irqs << GEN8_BCS_IRQ_SHIFT,
|
||||
irqs << GEN8_VCS0_IRQ_SHIFT | irqs << GEN8_VCS1_IRQ_SHIFT,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue