mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
ASoC: tegra: Support auxiliary devices
Svyatoslav Ryhel <clamor95@gmail.com> says: Add support for auxiliary devices, such as amplifiers, sound-muxes or dsp, to be added to the sound card. Link: https://patch.msgid.link/20261013180253.477605-1-clamor95@gmail.com
This commit is contained in:
commit
bce34abda5
5
.mailmap
5
.mailmap
|
|
@ -101,6 +101,7 @@ Andy Chiu <andybnac@gmail.com> <andy.chiu@sifive.com>
|
|||
Andy Chiu <andybnac@gmail.com> <taochiu@synology.com>
|
||||
Andy Shevchenko <andy@kernel.org> <andy@smile.org.ua>
|
||||
Andy Shevchenko <andy@kernel.org> <ext-andriy.shevchenko@nokia.com>
|
||||
Andy Yan <andyshrk@163.com> <andy.yan@rock-chips.com>
|
||||
Anilkumar Kolli <quic_akolli@quicinc.com> <akolli@codeaurora.org>
|
||||
Anirudh Ghayal <quic_aghayal@quicinc.com> <aghayal@codeaurora.org>
|
||||
Antoine Tenart <atenart@kernel.org> <antoine.tenart@bootlin.com>
|
||||
|
|
@ -461,7 +462,8 @@ Johan Hovold <johan@kernel.org> <jhovold@gmail.com>
|
|||
Johan Hovold <johan@kernel.org> <johan@hovoldconsulting.com>
|
||||
John Crispin <john@phrozen.org> <blogic@openwrt.org>
|
||||
John Fastabend <john.fastabend@gmail.com> <john.r.fastabend@intel.com>
|
||||
John Garry <john.g.garry@oracle.com> <john.garry@huawei.com>
|
||||
John Garry <john.garry@linux.dev> <john.garry@huawei.com>
|
||||
John Garry <john.garry@linux.dev> <john.g.garry@oracle.com>
|
||||
John Keeping <john@keeping.me.uk> <john@metanate.com>
|
||||
John Moon <john@jmoon.dev> <quic_johmoo@quicinc.com>
|
||||
John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
|
||||
|
|
@ -486,6 +488,7 @@ Juha Yrjola <juha.yrjola@nokia.com>
|
|||
Juha Yrjola <juha.yrjola@solidboot.com>
|
||||
Julien Thierry <julien.thierry.kdev@gmail.com> <julien.thierry@arm.com>
|
||||
Justin Iurman <justin.iurman@gmail.com> <justin.iurman@uliege.be>
|
||||
Imre Kaloz <kaloz@kernel.org> <kaloz@openwrt.org>
|
||||
Ira Weiny <iweiny@kernel.org> <ira.weiny@intel.com>
|
||||
Iskren Chernev <me@iskren.info> <iskren.chernev@gmail.com>
|
||||
Kalle Valo <kvalo@kernel.org> <kvalo@codeaurora.org>
|
||||
|
|
|
|||
|
|
@ -172,7 +172,8 @@ When mounting an ext4 filesystem, the following option are accepted:
|
|||
data=journal
|
||||
All data are committed into the journal prior to being written into the
|
||||
main file system. Enabling this mode will disable delayed allocation
|
||||
and O_DIRECT support.
|
||||
and O_DIRECT support. This feature is deprecated and support
|
||||
will be removed in January 2028.
|
||||
|
||||
data=ordered (*)
|
||||
All data are forced directly out to the main file system prior to its
|
||||
|
|
@ -418,7 +419,8 @@ There are 3 different data modes:
|
|||
consistent state. This mode is the slowest except when data needs to be read
|
||||
from and written to disk at the same time where it outperforms all others
|
||||
modes. Enabling this mode will disable delayed allocation and O_DIRECT
|
||||
support.
|
||||
support. The data=journal feature is deprecated and support will be
|
||||
removed in January 2028.
|
||||
|
||||
/proc entries
|
||||
=============
|
||||
|
|
|
|||
|
|
@ -48,6 +48,11 @@ properties:
|
|||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: The phandle of audio codec
|
||||
|
||||
nvidia,aux-devs:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: List of phandles pointing to auxiliary devices,
|
||||
such as amplifiers or dsp, to be added to the sound card.
|
||||
|
||||
nvidia,spkr-en-gpios:
|
||||
maxItems: 1
|
||||
description: The GPIO that enables the speakers
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ properties:
|
|||
- mscc,ocelot-spi
|
||||
- mscc,jaguar2-spi
|
||||
- sophgo,sg2042-spi
|
||||
- syna,sl2610-spi
|
||||
- thead,th1520-spi
|
||||
- ultrarisc,dp1000-spi
|
||||
- const: snps,dw-apb-ssi
|
||||
|
|
|
|||
|
|
@ -32,12 +32,12 @@ of set. They can be reparented to the place where the bottom of
|
|||
stack is attached to a mount that will survive. NOTE: doing that
|
||||
will violate a constraint on having no more than one mount with
|
||||
the same parent/mountpoint pair; however, the caller (umount_tree())
|
||||
will immediately remedy that - it may keep unmounted element attached
|
||||
to parent, but only if the parent itself is unmounted. Since all
|
||||
conflicts created by reparenting have common parent *not* in the
|
||||
set and one side of the conflict (bottom of the stack of overmounts)
|
||||
is in the set, it will be resolved. However, we rely upon umount_tree()
|
||||
doing that pretty much immediately after the call of propagate_umount().
|
||||
will immediately remedy that - it detaches every element of the set
|
||||
from its parent. Since all conflicts created by reparenting have
|
||||
common parent *not* in the set and one side of the conflict (bottom
|
||||
of the stack of overmounts) is in the set, it will be resolved.
|
||||
However, we rely upon umount_tree() doing that pretty much immediately
|
||||
after the call of propagate_umount().
|
||||
|
||||
Algorithm is based on two statements:
|
||||
1) for any set S, there is a maximal non-shifting subset of S
|
||||
|
|
|
|||
|
|
@ -564,8 +564,8 @@ f) Unmount semantics
|
|||
where 'A' is a mount mounted on mount 'B' at dentry 'b'.
|
||||
|
||||
If mount 'B' is shared, then all most-recently-mounted mounts at dentry
|
||||
'b' on mounts that receive propagation from mount 'B' and does not have
|
||||
sub-mounts within them are unmounted.
|
||||
'b' on mounts that receive propagation from mount 'B' are unmounted as
|
||||
well, if every mount below them is also unmounted.
|
||||
|
||||
Example: Let's say 'B1', 'B2', 'B3' are shared mounts that propagate to
|
||||
each other.
|
||||
|
|
@ -584,10 +584,18 @@ f) Unmount semantics
|
|||
|
||||
So all 'C1', 'C2' and 'C3' should be unmounted.
|
||||
|
||||
If any of 'C2' or 'C3' has some child mounts, then that mount is not
|
||||
unmounted, but all other mounts are unmounted. However if 'C1' is told
|
||||
to be unmounted and 'C1' has some sub-mounts, the umount operation is
|
||||
failed entirely.
|
||||
If any of 'C2' or 'C3' has a child mount that cannot be unmounted
|
||||
then that mount is not unmounted. But all other mounts are unmounted.
|
||||
A child mount that is itself unmounted by the same unmount
|
||||
propagation does not keep its parent mounted. However if 'C1' is
|
||||
supposed to be unmounted and 'C1' has some sub-mounts, the unmount
|
||||
fails.
|
||||
|
||||
A lazy umount (MNT_DETACH) takes a whole tree. Every mount of the
|
||||
tree then propagates its unmount from its own parent as described
|
||||
above, so the mounts that receive propagation lose the corresponding
|
||||
trees as well. Documentation/filesystems/propagate_umount.txt has the
|
||||
precise rules, including the ones for locked mounts.
|
||||
|
||||
g) Clone Namespace
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ Functions
|
|||
|
||||
strp_done is called to release any resources held by the stream
|
||||
parser instance. This must be called after the stream processor
|
||||
has been stopped.
|
||||
has been stopped. The socket lock must not be held.
|
||||
|
||||
::
|
||||
|
||||
|
|
|
|||
|
|
@ -3020,7 +3020,7 @@ F: arch/arm/boot/dts/ti/omap/omap3-igep*
|
|||
|
||||
ARM/INTEL IXP4XX ARM ARCHITECTURE
|
||||
M: Linus Walleij <linusw@kernel.org>
|
||||
M: Imre Kaloz <kaloz@openwrt.org>
|
||||
M: Imre Kaloz <kaloz@kernel.org>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml
|
||||
|
|
@ -9876,7 +9876,7 @@ L: linux-ext4@vger.kernel.org
|
|||
S: Maintained
|
||||
W: http://ext4.wiki.kernel.org
|
||||
Q: http://patchwork.ozlabs.org/project/linux-ext4/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git dev
|
||||
F: Documentation/filesystems/ext4/
|
||||
F: fs/ext4/
|
||||
F: include/trace/events/ext4.h
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
VERSION = 7
|
||||
PATCHLEVEL = 3
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc6
|
||||
EXTRAVERSION = -rc7
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
|||
|
|
@ -1602,7 +1602,7 @@ esdhc0_clksync_pins: iic5-sdhc-clk-pins {
|
|||
};
|
||||
|
||||
dspi2_miso_mosi_pins: iic5-spi3-pins {
|
||||
pinctrl-single,bits = <0x3 (0x2 << 9) (0x7 << 9)>;
|
||||
pinctrl-single,bits = <0x0 (0x3 << 9) (0x7 << 9)>;
|
||||
};
|
||||
|
||||
i2c5_pins: iic6-i2c-pins {
|
||||
|
|
@ -1622,7 +1622,7 @@ fspi_data74_pins: xspi1-data74-pins {
|
|||
};
|
||||
|
||||
gpio1_31_28_pins: xspi1-data74-gpio-pins {
|
||||
pinctrl-single,bits = <0x0 0x1 (0x7 << 15)>;
|
||||
pinctrl-single,bits = <0x0 (0x1 << 15) (0x7 << 15)>;
|
||||
};
|
||||
|
||||
fspi_data30_pins: xspi1-data30-pins {
|
||||
|
|
@ -1630,7 +1630,7 @@ fspi_data30_pins: xspi1-data30-pins {
|
|||
};
|
||||
|
||||
gpio1_27_24_pins: xspi1-data30-gpio-pins {
|
||||
pinctrl-single,bits = <0x0 0x1 (0x7 << 18)>;
|
||||
pinctrl-single,bits = <0x0 (0x1 << 18) (0x7 << 18)>;
|
||||
};
|
||||
|
||||
fspi_dqs_sck_cs10_pins: xspi1-base-pins {
|
||||
|
|
@ -1638,7 +1638,7 @@ fspi_dqs_sck_cs10_pins: xspi1-base-pins {
|
|||
};
|
||||
|
||||
gpio1_23_20_pins: xspi1-base-gpio-pins {
|
||||
pinctrl-single,bits = <0x0 0x1 (0x7 << 21)>;
|
||||
pinctrl-single,bits = <0x0 (0x1 << 21) (0x7 << 21)>;
|
||||
};
|
||||
|
||||
esdhc0_cmd_data30_clk_vsel_pins: sdhc1-base-sdhc-vsel-pins {
|
||||
|
|
@ -1687,12 +1687,19 @@ i2c6_i2c7_pins: iic8-iic7-i2c-pins {
|
|||
};
|
||||
|
||||
/* RCWSR14 */
|
||||
/*
|
||||
* IIC1_PMUX is a single bit at RCWSR14[10], but bit-per-mux
|
||||
* uses the mask for the field to clear before applying the
|
||||
* value.
|
||||
* So bits 11 and 12, which are reserved, are written as 0
|
||||
* on every mux switch, it is harmless.
|
||||
*/
|
||||
i2c0_pins: iic1-i2c-pins {
|
||||
pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>;
|
||||
pinctrl-single,bits = <0x8 0x0 (0x7 << 10)>;
|
||||
};
|
||||
|
||||
gpio0_3_2_pins: iic1-gpio-pins {
|
||||
pinctrl-single,bits = <0x8 (0x1 << 10) (0x1 << 10)>;
|
||||
pinctrl-single,bits = <0x8 (0x1 << 10) (0x7 << 10)>;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -511,6 +511,7 @@ &usdhc2 {
|
|||
pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
|
||||
cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
|
||||
vmmc-supply = <®_usdhc2_vmmc>;
|
||||
vqmmc-supply = <&ldo5>;
|
||||
bus-width = <4>;
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -863,11 +863,11 @@ spkr_01_sd_n_active: spkr-01-sd-n-active-state {
|
|||
};
|
||||
|
||||
&lpass_vamacro {
|
||||
pinctrl-0 = <&dmic01_default>, <&dmic23_default>;
|
||||
pinctrl-0 = <&dmic01_default>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
vdd-micb-supply = <&vreg_l1b_1p8>;
|
||||
qcom,dmic-sample-rate = <4800000>;
|
||||
qcom,dmic-sample-rate = <2400000>;
|
||||
};
|
||||
|
||||
&mdss {
|
||||
|
|
|
|||
|
|
@ -421,8 +421,9 @@
|
|||
mov x2, xzr
|
||||
mrs x1, id_aa64dfr0_el1
|
||||
ubfx x1, x1, #ID_AA64DFR0_EL1_PMUVer_SHIFT, #4
|
||||
cmp x1, #ID_AA64DFR0_EL1_PMUVer_V3P9
|
||||
b.lt .Lskip_pmuv3p9_\@
|
||||
cmp x1, #ID_AA64DFR0_EL1_PMUVer_IMP_DEF
|
||||
ccmp x1, #ID_AA64DFR0_EL1_PMUVer_V3P9, #8, ne
|
||||
b.lt .Lskip_pmuv3p9_\@ // Skip if < PMUv3p9 or IMP_DEF
|
||||
|
||||
orr x0, x0, #HDFGRTR2_EL2_nPMICNTR_EL0
|
||||
orr x0, x0, #HDFGRTR2_EL2_nPMICFILTR_EL0
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ KASAN_SANITIZE_stacktrace.o := n
|
|||
KCOV_INSTRUMENT_entry-common.o := n
|
||||
KCOV_INSTRUMENT_idle.o := n
|
||||
|
||||
# Softirq stack switching can run outside interrupt context.
|
||||
KCOV_INSTRUMENT_irq.o := n
|
||||
|
||||
# Object file lists.
|
||||
obj-y := debug-monitors.o entry.o irq.o fpsimd.o \
|
||||
entry-common.o process.o ptrace.o \
|
||||
|
|
|
|||
|
|
@ -453,9 +453,10 @@ config SMP
|
|||
config NR_CPUS
|
||||
int "Maximum number of CPUs (2-512)"
|
||||
depends on SMP
|
||||
range 2 512 if !RISCV_SBI_V01
|
||||
range 2 32 if RISCV_SBI_V01 && 32BIT
|
||||
range 2 512 if !RISCV_SBI_V01 && 64BIT
|
||||
range 2 128 if !RISCV_SBI_V01 && 32BIT
|
||||
range 2 64 if RISCV_SBI_V01 && 64BIT
|
||||
range 2 32 if RISCV_SBI_V01 && 32BIT
|
||||
default "32" if 32BIT
|
||||
default "64" if RISCV_SBI_V01 && 64BIT
|
||||
default "256" if !RISCV_SBI_V01 && 64BIT
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ config ERRATA_MIPS_P8700_PAUSE_OPCODE
|
|||
|
||||
config ERRATA_SIFIVE
|
||||
bool "SiFive errata"
|
||||
depends on RISCV_ALTERNATIVE
|
||||
depends on RISCV_ALTERNATIVE && 64BIT
|
||||
help
|
||||
All SiFive errata Kconfig depend on this Kconfig. Disabling
|
||||
this Kconfig will disable all SiFive errata. Please say "Y"
|
||||
|
|
@ -96,6 +96,20 @@ config ERRATA_STARFIVE_JH7100
|
|||
Say "Y" if you want to support the BeagleV Starlight and/or
|
||||
StarFive VisionFive V1 boards.
|
||||
|
||||
config ERRATA_SIFIVE_MAL_9092
|
||||
bool "Apply SiFive HLV/HLVX/HSV fence errata"
|
||||
depends on ERRATA_SIFIVE && 64BIT
|
||||
default y
|
||||
help
|
||||
This will apply the SiFive MAL-9092 errata to add fence.rw
|
||||
instructions around all HLV/HLVX/HSV instructions.
|
||||
|
||||
Note: HSTATUS.HU is cleared during KVM initialization. If future
|
||||
changes enable HSTATUS.HU to allow hypervisor instructions in
|
||||
U-mode, additional errata handling may be required.
|
||||
|
||||
If you don't know what to do here, say "Y".
|
||||
|
||||
config ERRATA_THEAD
|
||||
bool "T-HEAD errata"
|
||||
depends on RISCV_ALTERNATIVE
|
||||
|
|
@ -146,6 +160,7 @@ config ERRATA_THEAD_PMU
|
|||
config ERRATA_THEAD_GHOSTWRITE
|
||||
bool "Apply T-Head Ghostwrite errata"
|
||||
depends on ERRATA_THEAD && RISCV_ISA_XTHEADVECTOR
|
||||
select RISCV_ALTERNATIVE_EARLY
|
||||
default y
|
||||
help
|
||||
The T-Head C9xx cores have a vulnerability in the xtheadvector
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ config ARCH_RENESAS
|
|||
config ARCH_SIFIVE
|
||||
bool "SiFive SoCs"
|
||||
select ERRATA_SIFIVE
|
||||
depends on 64BIT
|
||||
help
|
||||
This enables support for SiFive SoC platform hardware.
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,22 @@ static bool errata_cip_1200_check_func(unsigned long arch_id, unsigned long imp
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool errata_mal_9092_check_func(unsigned long arch_id, unsigned long impid)
|
||||
{
|
||||
/*
|
||||
* Affected cores:
|
||||
* Architecture ID: 0x8000000000000109
|
||||
* Implementation ID: 0x19251031, 0x19251217, 0x19260320
|
||||
*/
|
||||
|
||||
if (arch_id != 0x8000000000000109)
|
||||
return false;
|
||||
if (impid != 0x19251031 && impid != 0x19251217 && impid != 0x19260320)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
|
||||
{
|
||||
.name = "cip-453",
|
||||
|
|
@ -60,6 +76,10 @@ static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
|
|||
.name = "cip-1200",
|
||||
.check_func = errata_cip_1200_check_func
|
||||
},
|
||||
{
|
||||
.name = "mal-9092",
|
||||
.check_func = errata_mal_9092_check_func
|
||||
},
|
||||
};
|
||||
|
||||
static u32 __init_or_module sifive_errata_probe(unsigned long archid,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ extern u32 thead_vlenb_of;
|
|||
|
||||
void __init riscv_user_isa_enable(void);
|
||||
|
||||
void riscv_clear_hypervisor_csr(void);
|
||||
|
||||
#define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size, _validate) { \
|
||||
.name = #_name, \
|
||||
.property = #_name, \
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@
|
|||
#ifdef CONFIG_ERRATA_SIFIVE
|
||||
#define ERRATA_SIFIVE_CIP_453 0
|
||||
#define ERRATA_SIFIVE_CIP_1200 1
|
||||
#define ERRATA_SIFIVE_NUMBER 2
|
||||
#define ERRATA_SIFIVE_MAL_9092 2
|
||||
#define ERRATA_SIFIVE_NUMBER 3
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ERRATA_THEAD
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
|
|||
|
||||
if (!access_ok(uaddr, sizeof(u32)))
|
||||
return -EFAULT;
|
||||
uaddr = untagged_addr(uaddr);
|
||||
|
||||
switch (op) {
|
||||
case FUTEX_OP_SET:
|
||||
|
|
@ -82,6 +83,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
|
|||
|
||||
if (!access_ok(uaddr, sizeof(u32)))
|
||||
return -EFAULT;
|
||||
uaddr = untagged_addr(uaddr);
|
||||
|
||||
__enable_user_access();
|
||||
__asm__ __volatile__ (
|
||||
|
|
|
|||
|
|
@ -192,18 +192,28 @@
|
|||
INSN_R(OPCODE_SYSTEM, FUNC3(0), FUNC7(49), \
|
||||
__RD(0), RS1(gaddr), RS2(vmid))
|
||||
|
||||
#define ALT_SIFIVE_MAL_9092_FENCE \
|
||||
ALTERNATIVE("nop", "fence rw, rw", SIFIVE_VENDOR_ID, \
|
||||
ERRATA_SIFIVE_MAL_9092, CONFIG_ERRATA_SIFIVE_MAL_9092)
|
||||
|
||||
#define HLVX_HU(dest, addr) \
|
||||
ALT_SIFIVE_MAL_9092_FENCE "\n" \
|
||||
INSN_R(OPCODE_SYSTEM, FUNC3(4), FUNC7(50), \
|
||||
RD(dest), RS1(addr), __RS2(3))
|
||||
RD(dest), RS1(addr), __RS2(3)) "\n" \
|
||||
ALT_SIFIVE_MAL_9092_FENCE
|
||||
|
||||
#define HLV_W(dest, addr) \
|
||||
ALT_SIFIVE_MAL_9092_FENCE "\n" \
|
||||
INSN_R(OPCODE_SYSTEM, FUNC3(4), FUNC7(52), \
|
||||
RD(dest), RS1(addr), __RS2(0))
|
||||
RD(dest), RS1(addr), __RS2(0)) "\n" \
|
||||
ALT_SIFIVE_MAL_9092_FENCE
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
#define HLV_D(dest, addr) \
|
||||
ALT_SIFIVE_MAL_9092_FENCE "\n" \
|
||||
INSN_R(OPCODE_SYSTEM, FUNC3(4), FUNC7(54), \
|
||||
RD(dest), RS1(addr), __RS2(0))
|
||||
RD(dest), RS1(addr), __RS2(0)) "\n" \
|
||||
ALT_SIFIVE_MAL_9092_FENCE
|
||||
#else
|
||||
#define HLV_D(dest, addr) \
|
||||
__ASM_STR(.error "hlv.d requires 64-bit support")
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#ifdef __ASSEMBLER__
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/csr.h>
|
||||
|
||||
#ifdef CONFIG_SHADOW_CALL_STACK
|
||||
|
||||
|
|
@ -22,9 +23,17 @@
|
|||
REG_L gp, TASK_TI_SCS_SP(tp)
|
||||
.endm
|
||||
|
||||
/* Load task_scs_sp(current) to gp, but only if tp has changed. */
|
||||
.macro scs_load_current_if_task_changed prev
|
||||
beq \prev, tp, _skip_scs
|
||||
/*
|
||||
* Load task_scs_sp(current) to gp, but only when the trap came from U-mode.
|
||||
* The source privilege level is taken from the saved sstatus.SPP bit (written
|
||||
* by hardware on trap entry), not by comparing tp. tp is a user-writable
|
||||
* register, so gating the shadow call stack reload on it let a user task that
|
||||
* set tp == ¤t skip the reload and run the kernel with an attacker
|
||||
* controlled gp (the shadow call stack pointer).
|
||||
*/
|
||||
.macro scs_load_current_if_from_user status, tmp
|
||||
andi \tmp, \status, SR_SPP
|
||||
bnez \tmp, _skip_scs
|
||||
scs_load_current
|
||||
_skip_scs:
|
||||
.endm
|
||||
|
|
@ -42,7 +51,7 @@
|
|||
.endm
|
||||
.macro scs_load_current
|
||||
.endm
|
||||
.macro scs_load_current_if_task_changed prev
|
||||
.macro scs_load_current_if_from_user status, tmp
|
||||
.endm
|
||||
.macro scs_save_current
|
||||
.endm
|
||||
|
|
|
|||
|
|
@ -137,8 +137,8 @@ static __always_inline void __vstate_csr_save(struct __riscv_v_ext_state *dest)
|
|||
"csrr %0, " __stringify(CSR_VSTART) "\n\t"
|
||||
"csrr %1, " __stringify(CSR_VTYPE) "\n\t"
|
||||
"csrr %2, " __stringify(CSR_VL) "\n\t"
|
||||
: "=r" (dest->vstart), "=r" (dest->vtype), "=r" (dest->vl),
|
||||
"=r" (dest->vcsr) : :);
|
||||
: "=r" (dest->vstart), "=r" (dest->vtype), "=r" (dest->vl)
|
||||
: :);
|
||||
|
||||
if (has_xtheadvector()) {
|
||||
unsigned long status;
|
||||
|
|
@ -230,7 +230,7 @@ static inline void __riscv_v_vstate_save(struct __riscv_v_ext_state *save_to,
|
|||
"add %1, %1, %0\n\t"
|
||||
"vse8.v v24, (%1)\n\t"
|
||||
".option pop\n\t"
|
||||
: "=&r" (vl) : "r" (datap) : "memory");
|
||||
: "=&r" (vl), "+r" (datap) : : "memory");
|
||||
}
|
||||
riscv_v_disable();
|
||||
}
|
||||
|
|
@ -266,7 +266,7 @@ static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_
|
|||
"add %1, %1, %0\n\t"
|
||||
"vle8.v v24, (%1)\n\t"
|
||||
".option pop\n\t"
|
||||
: "=&r" (vl) : "r" (datap) : "memory");
|
||||
: "=&r" (vl), "+r" (datap) : : "memory");
|
||||
}
|
||||
__vstate_csr_restore(restore_from);
|
||||
riscv_v_disable();
|
||||
|
|
|
|||
4
arch/riscv/include/uapi/asm/vendor/mips.h
vendored
4
arch/riscv/include/uapi/asm/vendor/mips.h
vendored
|
|
@ -1,3 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
|
||||
#define RISCV_HWPROBE_VENDOR_EXT_XMIPSEXECTL BIT(0)
|
||||
#include <linux/const.h>
|
||||
|
||||
#define RISCV_HWPROBE_VENDOR_EXT_XMIPSEXECTL _BITULL(0)
|
||||
|
|
|
|||
|
|
@ -1233,6 +1233,18 @@ void __init riscv_user_isa_enable(void)
|
|||
pr_warn("Zicbop disabled as it is unavailable on some harts\n");
|
||||
}
|
||||
|
||||
void riscv_clear_hypervisor_csr(void)
|
||||
{
|
||||
if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_H))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Clear HSTATUS.HU to restrict hypervisor instructions to HS-mode.
|
||||
* This prevents user-mode from executing HLV/HSV instructions.
|
||||
*/
|
||||
csr_clear(CSR_HSTATUS, HSTATUS_HU);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RISCV_ALTERNATIVE
|
||||
/*
|
||||
* Alternative patch sites consider 48 bits when determining when to patch
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ SYM_CODE_START(handle_exception)
|
|||
load_global_pointer
|
||||
|
||||
/* Load the kernel shadow call stack pointer if coming from userspace */
|
||||
scs_load_current_if_task_changed s5
|
||||
scs_load_current_if_from_user s1, s5
|
||||
|
||||
#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE
|
||||
move a0, sp
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ static __always_inline void *patch_map(void *addr, const unsigned int fixmap)
|
|||
if (!IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
|
||||
return addr;
|
||||
phys = __pa_symbol(addr);
|
||||
} else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) {
|
||||
} else if (IS_ENABLED(CONFIG_EXECMEM)) {
|
||||
struct page *page = vmalloc_to_page(addr);
|
||||
|
||||
BUG_ON(!page);
|
||||
|
|
|
|||
|
|
@ -230,6 +230,7 @@ static int riscv_vr_set(struct task_struct *target,
|
|||
return -ENODATA;
|
||||
|
||||
/* Copy rest of the vstate except datap */
|
||||
memset(&ptrace_vstate, 0, sizeof(ptrace_vstate));
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ptrace_vstate, 0,
|
||||
sizeof(struct __riscv_v_regset_state));
|
||||
if (unlikely(ret))
|
||||
|
|
@ -299,6 +300,9 @@ static int riscv_cfi_get(struct task_struct *target,
|
|||
struct user_cfi_state user_cfi;
|
||||
struct pt_regs *regs;
|
||||
|
||||
if (!is_user_lpad_enabled() && !is_user_shstk_enabled())
|
||||
return -EINVAL;
|
||||
|
||||
memset(&user_cfi, 0, sizeof(user_cfi));
|
||||
regs = task_pt_regs(target);
|
||||
|
||||
|
|
@ -337,8 +341,12 @@ static int riscv_cfi_set(struct task_struct *target,
|
|||
struct user_cfi_state user_cfi;
|
||||
struct pt_regs *regs;
|
||||
|
||||
if (!is_user_lpad_enabled() && !is_user_shstk_enabled())
|
||||
return -EINVAL;
|
||||
|
||||
regs = task_pt_regs(target);
|
||||
|
||||
memset(&user_cfi, 0, sizeof(user_cfi));
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &user_cfi, 0, -1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -366,6 +366,8 @@ void __init setup_arch(char **cmdline_p)
|
|||
|
||||
if (!IS_ENABLED(CONFIG_RISCV_ISA_ZBB) || !riscv_isa_extension_available(NULL, ZBB))
|
||||
static_branch_disable(&efficient_ffs_key);
|
||||
|
||||
riscv_clear_hypervisor_csr();
|
||||
}
|
||||
|
||||
bool arch_cpu_is_hotpluggable(int cpu)
|
||||
|
|
|
|||
|
|
@ -244,6 +244,8 @@ asmlinkage __visible void smp_callin(void)
|
|||
|
||||
numa_add_cpu(curr_cpuid);
|
||||
|
||||
riscv_clear_hypervisor_csr();
|
||||
|
||||
pr_debug("CPU%u: Booted secondary hartid %lu\n", curr_cpuid,
|
||||
cpuid_to_hartid_map(curr_cpuid));
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ void suspend_save_csrs(struct suspend_context *context)
|
|||
|
||||
void suspend_restore_csrs(struct suspend_context *context)
|
||||
{
|
||||
riscv_clear_hypervisor_csr();
|
||||
|
||||
csr_write(CSR_SCRATCH, 0);
|
||||
if (riscv_has_extension_unlikely(RISCV_ISA_EXT_XLINUXENVCFG))
|
||||
csr_write(CSR_ENVCFG, context->envcfg);
|
||||
|
|
|
|||
|
|
@ -87,9 +87,25 @@ strnlen_zbb:
|
|||
* Aligned boundary. Use the address of the last valid byte
|
||||
* (s + count - 1) to avoid loading a word past the count
|
||||
* boundary in the loop below. count == 0 is handled above.
|
||||
*
|
||||
* Saturate the boundary when s + count would wrap around (very
|
||||
* large counts, e.g. SIZE_MAX passed by FORTIFY strcat/strlcat
|
||||
* with a destination whose size is unknown at compile time).
|
||||
* Without this, the wrapped boundary lands before s and the
|
||||
* pre-loop guard below always exits, returning a truncated
|
||||
* length.
|
||||
*
|
||||
* Clamping the increment to ~s (== SIZE_MAX - s) keeps the
|
||||
* computation branchless and wrap-free:
|
||||
*
|
||||
* s + min(count - 1, ~s) == saturating_add(s, count - 1)
|
||||
*
|
||||
* Saturating makes the scan equivalent to strlen().
|
||||
*/
|
||||
add t4, a0, a1
|
||||
addi t4, t4, -1
|
||||
addi t4, a1, -1 /* count - 1 */
|
||||
not t1, a0 /* SIZE_MAX - s */
|
||||
minu t4, t4, t1 /* clamp, so s + t4 can never wrap */
|
||||
add t4, a0, t4 /* saturated s + count - 1 */
|
||||
andi t4, t4, -SZREG
|
||||
|
||||
/* Get the first word. */
|
||||
|
|
|
|||
|
|
@ -68,8 +68,8 @@ ex_handler_load_unaligned_zeropad(const struct exception_table_entry *ex,
|
|||
|
||||
addr = regs_get_gpr(regs, reg_addr * sizeof(unsigned long));
|
||||
|
||||
offset = addr & 0x7UL;
|
||||
addr &= ~0x7UL;
|
||||
offset = addr & (sizeof(data) - 1);
|
||||
addr &= ~(sizeof(data) - 1);
|
||||
|
||||
data = *(unsigned long *)addr >> (offset * 8);
|
||||
|
||||
|
|
|
|||
|
|
@ -209,6 +209,7 @@ static int raw_verify_header(
|
|||
if ((vheader->flags & VIRTIO_NET_HDR_F_DATA_VALID) > 0)
|
||||
return 1;
|
||||
|
||||
skb_set_network_header(skb, ETH_HLEN);
|
||||
virtio_net_hdr_to_skb(skb, vheader, virtio_legacy_is_little_endian());
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -477,6 +477,8 @@
|
|||
#define X86_FEATURE_NO_NESTED_DATA_BP (20*32+ 0) /* No Nested Data Breakpoints */
|
||||
#define X86_FEATURE_WRMSR_XX_BASE_NS (20*32+ 1) /* WRMSR to {FS,GS,KERNEL_GS}_BASE is non-serializing */
|
||||
#define X86_FEATURE_LFENCE_RDTSC (20*32+ 2) /* LFENCE always serializing / synchronizes RDTSC */
|
||||
|
||||
#define X86_FEATURE_TLBSYNC_SFW_NO (20*32+ 4) /* TLBI Erratum #1718 fixed in microcode */
|
||||
#define X86_FEATURE_VERW_CLEAR (20*32+ 5) /* The memory form of VERW mitigates TSA */
|
||||
#define X86_FEATURE_NULL_SEL_CLR_BASE (20*32+ 6) /* Null Selector Clears Base */
|
||||
|
||||
|
|
@ -587,4 +589,5 @@
|
|||
#define X86_BUG_TSA X86_BUG( 1*32+ 9) /* "tsa" CPU is affected by Transient Scheduler Attacks */
|
||||
#define X86_BUG_VMSCAPE X86_BUG( 1*32+10) /* "vmscape" CPU is affected by VMSCAPE attacks from guests */
|
||||
#define X86_BUG_SEAMRET_INVD_VMCS X86_BUG( 1*32+11) /* "seamret_invd_vmcs" SEAMRET from P-SEAMLDR clears the current VMCS */
|
||||
#define X86_BUG_TLBI X86_BUG( 1*32+12) /* "tlbi" AMD TLBI Erratum #1718 */
|
||||
#endif /* _ASM_X86_CPUFEATURES_H */
|
||||
|
|
|
|||
|
|
@ -110,6 +110,12 @@ static inline void __tlbsync(void)
|
|||
|
||||
/* TLBSYNC: supported in binutils >= 0.36. */
|
||||
asm volatile(".byte 0x0f, 0x01, 0xff" ::: "memory");
|
||||
|
||||
if (!static_cpu_has_bug(X86_BUG_TLBI))
|
||||
return;
|
||||
|
||||
/* TLBSYNC: supported in binutils >= 0.36. */
|
||||
asm volatile(".byte 0x0f, 0x01, 0xff" ::: "memory");
|
||||
}
|
||||
#else
|
||||
/* Some compilers (I'm looking at you clang!) simply can't do DCE */
|
||||
|
|
|
|||
|
|
@ -1049,6 +1049,10 @@ static void init_amd_zen5(struct cpuinfo_x86 *c)
|
|||
msr_clear_bit(MSR_AMD64_CPUID_FN_7, 18);
|
||||
pr_emerg_once("RDSEED32 is broken. Disabling the corresponding CPUID bit.\n");
|
||||
}
|
||||
|
||||
if (cpu_has(c, X86_FEATURE_INVLPGB) &&
|
||||
!cpu_has(c, X86_FEATURE_TLBSYNC_SFW_NO))
|
||||
set_cpu_bug(c, X86_BUG_TLBI);
|
||||
}
|
||||
|
||||
static void init_amd(struct cpuinfo_x86 *c)
|
||||
|
|
|
|||
|
|
@ -62,14 +62,50 @@ static void braille_write(u16 *buf)
|
|||
{
|
||||
static u16 lastwrite[WIDTH];
|
||||
unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c;
|
||||
struct nbcon_write_context wctxt = { };
|
||||
unsigned long flags;
|
||||
u16 out;
|
||||
int i;
|
||||
|
||||
if (!braille_co)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Braille console is not registered in console_list. Instead, it
|
||||
* is integrated with VT and shows what appears on the graphical
|
||||
* console under console_lock(). From this POV it is a legacy
|
||||
* console. But it calls serial console driver which might be
|
||||
* converted to the NBCON API. It is similar to
|
||||
* nbcon_legacy_emit_next_record() except that we should try
|
||||
* harder to get the lock. Otherwise, the Braille device won't show
|
||||
* everything what is displayed on the terminal.
|
||||
*
|
||||
* In short, simulate the original locking using NBCON API.
|
||||
*/
|
||||
if (braille_co->flags & CON_NBCON) {
|
||||
if (panic_on_this_cpu()) {
|
||||
/*
|
||||
* This should be good enough in practice. Most/all
|
||||
* serial console drivers have the atomic callback.
|
||||
*/
|
||||
if (!braille_co->write_atomic)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
/* NBCON API strictly requires the ownership. */
|
||||
if (!nbcon_braille_try_acquire(braille_co, &wctxt)) {
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
braille_co->device_lock(braille_co, &flags);
|
||||
while (!nbcon_braille_try_acquire(braille_co, &wctxt))
|
||||
cpu_relax();
|
||||
}
|
||||
}
|
||||
|
||||
if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf)))
|
||||
return;
|
||||
goto unlock_nbcon;
|
||||
memcpy(lastwrite, buf, WIDTH * sizeof(*buf));
|
||||
|
||||
#define SOH 1
|
||||
|
|
@ -102,7 +138,24 @@ static void braille_write(u16 *buf)
|
|||
*c++ = csum;
|
||||
*c++ = ETX;
|
||||
|
||||
braille_co->write(braille_co, data, c - data);
|
||||
if (braille_co->flags & CON_NBCON) {
|
||||
nbcon_write_context_set_buf(&wctxt, (char *)data, c - data);
|
||||
if (panic_on_this_cpu())
|
||||
braille_co->write_atomic(braille_co, &wctxt);
|
||||
else
|
||||
braille_co->write_thread(braille_co, &wctxt);
|
||||
} else {
|
||||
braille_co->write(braille_co, data, c - data);
|
||||
}
|
||||
|
||||
unlock_nbcon:
|
||||
if (braille_co->flags & CON_NBCON) {
|
||||
nbcon_braille_release(&wctxt);
|
||||
if (panic_on_this_cpu())
|
||||
local_irq_restore(flags);
|
||||
else
|
||||
braille_co->device_unlock(braille_co, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/* Follow the VC cursor*/
|
||||
|
|
|
|||
|
|
@ -3059,10 +3059,15 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
|
|||
if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL && qc->dev->sdev)
|
||||
qc->dev->sdev->locked = 0;
|
||||
|
||||
if (cmd->result)
|
||||
ata_scsi_qc_done(qc, false, 0);
|
||||
else
|
||||
ata_scsi_qc_done(qc, true, SAM_STAT_CHECK_CONDITION);
|
||||
/*
|
||||
* Report CHECK CONDITION unless the command was terminated
|
||||
* with a host byte set. Only set the status byte, so that the
|
||||
* SCSI midlayer internal byte, which scsi_check_sense() may
|
||||
* have set from the sense data, is preserved.
|
||||
*/
|
||||
if (get_host_byte(cmd) == DID_OK)
|
||||
set_status_byte(cmd, SAM_STAT_CHECK_CONDITION);
|
||||
ata_scsi_qc_done(qc, false, 0);
|
||||
goto schedule_deferred;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -800,6 +800,27 @@ static void zloop_cmd_workfn(struct work_struct *work)
|
|||
current->flags = orig_flags;
|
||||
}
|
||||
|
||||
static void zloop_fill_zero_rq(struct request *rq, unsigned int zero_from)
|
||||
{
|
||||
struct req_iterator iter;
|
||||
struct bio_vec bv;
|
||||
unsigned int pos = 0;
|
||||
unsigned int end, off;
|
||||
|
||||
rq_for_each_segment(bv, rq, iter) {
|
||||
end = pos + bv.bv_len;
|
||||
if (end > zero_from) {
|
||||
if (pos < zero_from)
|
||||
off = zero_from - pos;
|
||||
else
|
||||
off = 0;
|
||||
memzero_page(bv.bv_page, bv.bv_offset + off,
|
||||
bv.bv_len - off);
|
||||
}
|
||||
pos = end;
|
||||
}
|
||||
}
|
||||
|
||||
static void zloop_complete_rq(struct request *rq)
|
||||
{
|
||||
struct zloop_cmd *cmd = blk_mq_rq_to_pdu(rq);
|
||||
|
|
@ -814,13 +835,9 @@ static void zloop_complete_rq(struct request *rq)
|
|||
pr_err("Zone %u: failed read sector %llu, %llu sectors\n",
|
||||
zone_no, cmd->sector, cmd->nr_sectors);
|
||||
|
||||
if (cmd->ret >= 0 && cmd->ret != blk_rq_bytes(rq)) {
|
||||
/* short read */
|
||||
struct bio *bio;
|
||||
|
||||
__rq_for_each_bio(bio, rq)
|
||||
zero_fill_bio(bio);
|
||||
}
|
||||
/* Short read. Zero out the unread tail beyond cmd->ret. */
|
||||
if (cmd->ret >= 0 && cmd->ret != blk_rq_bytes(rq))
|
||||
zloop_fill_zero_rq(rq, cmd->ret);
|
||||
break;
|
||||
case REQ_OP_WRITE:
|
||||
case REQ_OP_ZONE_APPEND:
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data,
|
|||
|
||||
tfd_index = data->ia.tr_hia[BTINTEL_PCIE_TXQ_NUM];
|
||||
|
||||
if (tfd_index > txq->count)
|
||||
if (tfd_index >= txq->count)
|
||||
return -ERANGE;
|
||||
|
||||
if (skb->len > BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN) {
|
||||
|
|
@ -1777,7 +1777,7 @@ static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id)
|
|||
static int btintel_pcie_setup_irq(struct btintel_pcie_data *data)
|
||||
{
|
||||
int err;
|
||||
int num_irqs, i;
|
||||
int num_irqs, i, j;
|
||||
|
||||
for (i = 0; i < BTINTEL_PCIE_MSIX_VEC_MAX; i++)
|
||||
data->msix_entries[i].entry = i;
|
||||
|
|
@ -1806,6 +1806,10 @@ static int btintel_pcie_setup_irq(struct btintel_pcie_data *data)
|
|||
KBUILD_MODNAME,
|
||||
msix_entry);
|
||||
if (err) {
|
||||
for (j = 0; j < i; j++)
|
||||
devm_free_irq(&data->pdev->dev,
|
||||
data->msix_entries[j].vector,
|
||||
&data->msix_entries[j]);
|
||||
pci_free_irq_vectors(data->pdev);
|
||||
data->alloc_vecs = 0;
|
||||
return err;
|
||||
|
|
@ -1877,6 +1881,13 @@ static int btintel_pcie_config_pcie(struct pci_dev *pdev,
|
|||
if (IS_ERR(data->base_addr))
|
||||
return PTR_ERR(data->base_addr);
|
||||
|
||||
/* Do shared hardware reset to ensure a clean start before
|
||||
* configuring interrupts.
|
||||
*/
|
||||
err = btintel_pcie_reset_bt(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = btintel_pcie_setup_irq(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
@ -3138,7 +3149,7 @@ static void btintel_pcie_remove(struct pci_dev *pdev)
|
|||
struct msix_entry *msix_entry;
|
||||
|
||||
msix_entry = &data->msix_entries[i];
|
||||
free_irq(msix_entry->vector, msix_entry);
|
||||
devm_free_irq(&pdev->dev, msix_entry->vector, msix_entry);
|
||||
}
|
||||
|
||||
pci_free_irq_vectors(pdev);
|
||||
|
|
|
|||
|
|
@ -503,7 +503,7 @@ static int mmap_zero_prepare(struct vm_area_desc *desc)
|
|||
#ifndef CONFIG_MMU
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
if (vma_desc_test(desc, VMA_SHARED_BIT))
|
||||
if (vma_desc_test(desc, VMA_MAYSHARE_BIT))
|
||||
return shmem_zero_setup_desc(desc);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -3010,8 +3010,6 @@ static const u32 gcc_eliza_critical_cbcrs[] = {
|
|||
0x26034, /* GCC_CAMERA_XO_CLK */
|
||||
0x27004, /* GCC_DISP_AHB_CLK */
|
||||
0x71004, /* GCC_GPU_CFG_AHB_CLK */
|
||||
0x52010, /* GCC_PCIE_RSCC_CFG_AHB_CLK */
|
||||
0x52010, /* GCC_PCIE_RSCC_XO_CLK */
|
||||
0x32004, /* GCC_VIDEO_AHB_CLK */
|
||||
0x32038, /* GCC_VIDEO_XO_CLK */
|
||||
};
|
||||
|
|
@ -3045,6 +3043,10 @@ static const struct regmap_config gcc_eliza_regmap_config = {
|
|||
|
||||
static void clk_eliza_regs_configure(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
/* Keep clocks always enabled */
|
||||
regmap_update_bits(regmap, 0x52010, BIT(20), BIT(20)); /* GCC_PCIE_RSCC_CFG_AHB_CLK */
|
||||
regmap_update_bits(regmap, 0x52010, BIT(21), BIT(21)); /* GCC_PCIE_RSCC_XO_CLK */
|
||||
|
||||
/* FORCE_MEM_CORE_ON for ufs phy ice core and gcc ufs phy axi clocks */
|
||||
qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true);
|
||||
qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_axi_clk, true);
|
||||
|
|
|
|||
|
|
@ -3692,8 +3692,6 @@ static const u32 gcc_hawi_critical_cbcrs[] = {
|
|||
0x67084, /* GCC_PCIE_1_RSC_CORE_CLK */
|
||||
0x43014, /* GCC_PCIE_LINK_XO_CLK */
|
||||
0x6b088, /* GCC_PCIE_RSC_CORE_CLK */
|
||||
0x52010, /* GCC_PCIE_RSCC_CFG_AHB_CLK */
|
||||
0x52010, /* GCC_PCIE_RSCC_XO_CLK */
|
||||
0x32004, /* GCC_VIDEO_AHB_CLK */
|
||||
0x32028, /* GCC_VIDEO_XO_CLK */
|
||||
};
|
||||
|
|
@ -3763,6 +3761,10 @@ static const struct regmap_config gcc_hawi_regmap_config = {
|
|||
|
||||
static void clk_hawi_regs_configure(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
/* Keep clocks always enabled */
|
||||
regmap_update_bits(regmap, 0x52010, BIT(20), BIT(20)); /* GCC_PCIE_RSCC_CFG_AHB_CLK */
|
||||
regmap_update_bits(regmap, 0x52010, BIT(21), BIT(21)); /* GCC_PCIE_RSCC_XO_CLK */
|
||||
|
||||
/* FORCE_MEM_CORE_ON for ufs phy ice core clocks */
|
||||
qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3464,8 +3464,6 @@ static const u32 gcc_kaanapali_critical_cbcrs[] = {
|
|||
0x9f004, /* GCC_EVA_AHB_CLK */
|
||||
0x9f024, /* GCC_EVA_XO_CLK */
|
||||
0x71004, /* GCC_GPU_CFG_AHB_CLK */
|
||||
0x52010, /* GCC_PCIE_RSCC_CFG_AHB_CLK */
|
||||
0x52010, /* GCC_PCIE_RSCC_XO_CLK */
|
||||
0x32004, /* GCC_VIDEO_AHB_CLK */
|
||||
0x32040, /* GCC_VIDEO_XO_CLK */
|
||||
};
|
||||
|
|
@ -3480,6 +3478,10 @@ static const struct regmap_config gcc_kaanapali_regmap_config = {
|
|||
|
||||
static void clk_kaanapali_regs_configure(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
/* Keep clocks always enabled */
|
||||
regmap_update_bits(regmap, 0x52010, BIT(20), BIT(20)); /* GCC_PCIE_RSCC_CFG_AHB_CLK */
|
||||
regmap_update_bits(regmap, 0x52010, BIT(21), BIT(21)); /* GCC_PCIE_RSCC_XO_CLK */
|
||||
|
||||
/* FORCE_MEM_CORE_ON for ufs phy ice core clocks */
|
||||
qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -510,7 +510,7 @@ static struct gdsc gpu_cc_cx_gdsc = {
|
|||
.name = "gpu_cc_cx_gdsc",
|
||||
},
|
||||
.pwrsts = PWRSTS_OFF_ON,
|
||||
.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
|
||||
.flags = RETAIN_FF_ENABLE | VOTABLE,
|
||||
};
|
||||
|
||||
static struct clk_regmap *gpu_cc_glymur_clocks[] = {
|
||||
|
|
|
|||
|
|
@ -380,7 +380,7 @@ static struct gdsc gpu_cc_cx_gdsc = {
|
|||
.name = "gpu_cc_cx_gdsc",
|
||||
},
|
||||
.pwrsts = PWRSTS_OFF_ON,
|
||||
.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
|
||||
.flags = RETAIN_FF_ENABLE | VOTABLE,
|
||||
};
|
||||
|
||||
static struct clk_regmap *gpu_cc_kaanapali_clocks[] = {
|
||||
|
|
|
|||
|
|
@ -2796,13 +2796,13 @@ static inline void decode_bus_error(int node_id, struct mce *m)
|
|||
* the instance_id. For example, instance_id=0xYXXXXX where Y is the channel
|
||||
* number.
|
||||
*
|
||||
* For DRAM ECC errors, the Chip Select number is given in bits [2:0] of
|
||||
* For DRAM ECC errors, the Chip Select number is given in bits [1:0] of
|
||||
* the MCA_SYND[ErrorInformation] field.
|
||||
*/
|
||||
static void umc_get_err_info(struct mce *m, struct err_info *err)
|
||||
{
|
||||
err->channel = (m->ipid & GENMASK(31, 0)) >> 20;
|
||||
err->csrow = m->synd & 0x7;
|
||||
err->csrow = m->synd & 0x3;
|
||||
}
|
||||
|
||||
static void decode_umc_error(int node_id, struct mce *m)
|
||||
|
|
|
|||
|
|
@ -199,6 +199,7 @@ static int gpio_exar_probe(struct platform_device *pdev)
|
|||
index = ida_alloc(&ida_index, GFP_KERNEL);
|
||||
if (index < 0)
|
||||
return index;
|
||||
exar_gpio->index = index;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, exar_devm_ida_free, exar_gpio);
|
||||
if (ret)
|
||||
|
|
@ -214,7 +215,6 @@ static int gpio_exar_probe(struct platform_device *pdev)
|
|||
exar_gpio->gpio_chip.set = exar_set_value;
|
||||
exar_gpio->gpio_chip.base = -1;
|
||||
exar_gpio->gpio_chip.ngpio = ngpios;
|
||||
exar_gpio->index = index;
|
||||
exar_gpio->first_pin = first_pin;
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/cleanup.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
|
|
@ -24,6 +25,7 @@ struct mpsse_priv {
|
|||
raw_spinlock_t irq_spin; /* protects worker list */
|
||||
atomic_t irq_type[16]; /* pin -> edge detection type */
|
||||
atomic_t irq_enabled;
|
||||
atomic_t dying; /* no new workers after disconnect */
|
||||
int id;
|
||||
|
||||
u8 gpio_outputs[2]; /* Output states for GPIOs [L, H] */
|
||||
|
|
@ -46,6 +48,7 @@ struct mpsse_worker {
|
|||
atomic_t cancelled;
|
||||
struct list_head list; /* linked list */
|
||||
struct list_head destroy; /* teardown linked list */
|
||||
struct rcu_head rcu; /* deferred free for dying path */
|
||||
};
|
||||
|
||||
struct bulk_desc {
|
||||
|
|
@ -525,10 +528,24 @@ static void gpio_mpsse_irq_enable(struct irq_data *irqd)
|
|||
worker->priv = priv;
|
||||
INIT_LIST_HEAD(&worker->list);
|
||||
INIT_WORK(&worker->work, gpio_mpsse_poll);
|
||||
schedule_work(&worker->work);
|
||||
|
||||
scoped_guard(raw_spinlock_irqsave, &priv->irq_spin)
|
||||
scoped_guard(raw_spinlock_irqsave, &priv->irq_spin) {
|
||||
if (atomic_read(&priv->dying)) {
|
||||
/*
|
||||
* Cannot kfree() here: this callback
|
||||
* runs with the IRQ descriptor's raw
|
||||
* spinlock held and kfree() may sleep
|
||||
* on PREEMPT_RT. The worker is not
|
||||
* yet published, so the deferred free
|
||||
* is unobservable.
|
||||
*/
|
||||
kfree_rcu(worker, rcu);
|
||||
return;
|
||||
}
|
||||
|
||||
list_add(&worker->list, &priv->workers);
|
||||
schedule_work(&worker->work);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -704,6 +721,9 @@ static void gpio_mpsse_disconnect(struct usb_interface *intf)
|
|||
{
|
||||
struct mpsse_priv *priv = usb_get_intfdata(intf);
|
||||
|
||||
scoped_guard(raw_spinlock_irqsave, &priv->irq_spin)
|
||||
atomic_set(&priv->dying, 1);
|
||||
|
||||
/*
|
||||
* Lock prevents double-free of worker from here and the teardown
|
||||
* step at the beginning of gpio_mpsse_poll
|
||||
|
|
|
|||
|
|
@ -271,14 +271,7 @@ static void xgpio_save_regs(struct xgpio_instance *chip)
|
|||
|
||||
static int xgpio_request(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(chip->parent);
|
||||
/*
|
||||
* If the device is already active pm_runtime_get() will return 1 on
|
||||
* success, but gpio_request still needs to return 0.
|
||||
*/
|
||||
return ret < 0 ? ret : 0;
|
||||
return pm_runtime_resume_and_get(chip->parent);
|
||||
}
|
||||
|
||||
static void xgpio_free(struct gpio_chip *chip, unsigned int offset)
|
||||
|
|
|
|||
|
|
@ -598,14 +598,18 @@ int amdgpu_amdkfd_get_dmabuf_info(struct amdgpu_device *adev, int dma_buf_fd,
|
|||
/* first get metadata_size by buffer = NULL */
|
||||
r = amdgpu_bo_get_metadata(bo, NULL, 0,
|
||||
metadata_size, NULL);
|
||||
if (r)
|
||||
goto out_put;
|
||||
|
||||
/* user buf_size is bigger than bo metadata_size
|
||||
* allocate a buf at kernel space and copy */
|
||||
if (*metadata_size <= buffer_size) {
|
||||
*metadata_buffer = kzalloc(*metadata_size, GFP_KERNEL);
|
||||
|
||||
if (!*metadata_buffer)
|
||||
return -ENOMEM;
|
||||
if (!*metadata_buffer) {
|
||||
r = -ENOMEM;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
r = amdgpu_bo_get_metadata(bo, *metadata_buffer, *metadata_size,
|
||||
NULL, &metadata_flags);
|
||||
|
|
|
|||
|
|
@ -121,6 +121,20 @@ static int amdgpu_debugfs_process_reg_op(bool read, struct file *f,
|
|||
|
||||
*pos &= (1UL << 22) - 1;
|
||||
|
||||
if (size > PAGE_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Access the user buffer only while none of the locks below are held:
|
||||
* a fault takes mmap_lock, and grbm_idx_mutex and srbm_mutex nest
|
||||
* inside it.
|
||||
*/
|
||||
u32 *data __free(kfree) = kmalloc(size, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
if (!read && copy_from_user(data, buf, size))
|
||||
return -EFAULT;
|
||||
|
||||
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
|
||||
if (r < 0) {
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
|
|
@ -152,28 +166,16 @@ static int amdgpu_debugfs_process_reg_op(bool read, struct file *f,
|
|||
mutex_lock(&adev->pm.mutex);
|
||||
|
||||
while (size) {
|
||||
uint32_t value;
|
||||
|
||||
if (read) {
|
||||
value = RREG32(*pos >> 2);
|
||||
r = put_user(value, (uint32_t *)buf);
|
||||
} else {
|
||||
r = get_user(value, (uint32_t *)buf);
|
||||
if (!r)
|
||||
amdgpu_mm_wreg_mmio_rlc(adev, *pos >> 2, value, 0);
|
||||
}
|
||||
if (r) {
|
||||
result = r;
|
||||
goto end;
|
||||
}
|
||||
if (read)
|
||||
data[result >> 2] = RREG32(*pos >> 2);
|
||||
else
|
||||
amdgpu_mm_wreg_mmio_rlc(adev, *pos >> 2, data[result >> 2], 0);
|
||||
|
||||
result += 4;
|
||||
buf += 4;
|
||||
*pos += 4;
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
end:
|
||||
if (use_bank) {
|
||||
amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, 0);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
|
@ -188,6 +190,10 @@ static int amdgpu_debugfs_process_reg_op(bool read, struct file *f,
|
|||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
|
||||
amdgpu_virt_disable_access_debugfs(adev);
|
||||
|
||||
if (read && copy_to_user(buf, data, result))
|
||||
return -EFAULT;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -238,11 +244,24 @@ static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 off
|
|||
struct amdgpu_device *adev = rd->adev;
|
||||
ssize_t result = 0;
|
||||
int r;
|
||||
uint32_t value;
|
||||
|
||||
if (size & 0x3 || offset & 0x3)
|
||||
return -EINVAL;
|
||||
|
||||
if (size > PAGE_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Access the user buffer only while none of the locks below are held:
|
||||
* a fault takes mmap_lock, and grbm_idx_mutex and srbm_mutex nest
|
||||
* inside it.
|
||||
*/
|
||||
u32 *data __free(kfree) = kmalloc(size, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
if (write_en && copy_from_user(data, buf, size))
|
||||
return -EFAULT;
|
||||
|
||||
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
|
||||
if (r < 0) {
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
|
|
@ -281,24 +300,16 @@ static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 off
|
|||
mutex_lock(&adev->pm.mutex);
|
||||
|
||||
while (size) {
|
||||
if (!write_en) {
|
||||
value = RREG32(offset >> 2);
|
||||
r = put_user(value, (uint32_t *)buf);
|
||||
} else {
|
||||
r = get_user(value, (uint32_t *)buf);
|
||||
if (!r)
|
||||
amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, value, rd->id.xcc_id);
|
||||
}
|
||||
if (r) {
|
||||
result = r;
|
||||
goto end;
|
||||
}
|
||||
if (!write_en)
|
||||
data[result >> 2] = RREG32(offset >> 2);
|
||||
else
|
||||
amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, data[result >> 2],
|
||||
rd->id.xcc_id);
|
||||
offset += 4;
|
||||
size -= 4;
|
||||
result += 4;
|
||||
buf += 4;
|
||||
}
|
||||
end:
|
||||
|
||||
if (rd->id.use_grbm) {
|
||||
amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, rd->id.xcc_id);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
|
@ -317,6 +328,10 @@ static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 off
|
|||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
|
||||
amdgpu_virt_disable_access_debugfs(adev);
|
||||
|
||||
if (!write_en && copy_to_user(buf, data, result))
|
||||
return -EFAULT;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1080,20 +1080,17 @@ void amdgpu_gmc_init_vga_resv_regions(struct amdgpu_device *adev)
|
|||
case CHIP_RENOIR:
|
||||
adev->mman.keep_stolen_vga_memory = true;
|
||||
break;
|
||||
case CHIP_POLARIS10:
|
||||
case CHIP_POLARIS11:
|
||||
case CHIP_POLARIS12:
|
||||
/* MacBookPros with switchable graphics put VRAM at 0 when
|
||||
* the iGPU is enabled which results in cursor issues if
|
||||
* the cursor ends up at 0. Reserve vram at 0 in that case.
|
||||
*/
|
||||
if (adev->gmc.vram_start == 0)
|
||||
adev->mman.keep_stolen_vga_memory = true;
|
||||
break;
|
||||
default:
|
||||
adev->mman.keep_stolen_vga_memory = false;
|
||||
break;
|
||||
}
|
||||
/* MacBookPros with switchable graphics put VRAM at 0 when
|
||||
* the iGPU is enabled which results in cursor issues if
|
||||
* the cursor ends up at 0. Reserve vram at 0 in that case.
|
||||
*/
|
||||
if ((adev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
|
||||
(adev->gmc.vram_start == 0))
|
||||
adev->mman.keep_stolen_vga_memory = true;
|
||||
|
||||
if (amdgpu_sriov_vf(adev) ||
|
||||
!amdgpu_device_has_display_hardware(adev)) {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <drm/amdgpu_drm.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include "amdgpu_uvd.h"
|
||||
#include "amdgpu_vce.h"
|
||||
#include "atom.h"
|
||||
|
|
@ -1660,6 +1661,9 @@ u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc)
|
|||
DRM_ERROR("Invalid crtc %u\n", pipe);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!down_read_trylock(&adev->reset_domain->sem))
|
||||
return drm_crtc_vblank_count(crtc);
|
||||
|
||||
|
||||
/* The hw increments its frame counter at start of vsync, not at start
|
||||
* of vblank, as is required by DRM core vblank counter handling.
|
||||
|
|
@ -1705,6 +1709,7 @@ u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc)
|
|||
DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
|
||||
}
|
||||
|
||||
up_read(&adev->reset_domain->sem);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -472,6 +472,7 @@ amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
|
|||
u64 doorbell_index;
|
||||
struct drm_gem_object *gobj;
|
||||
struct amdgpu_userq_obj *db_obj = db_info->db_obj;
|
||||
struct amdgpu_bo *abo;
|
||||
int r, db_size;
|
||||
|
||||
gobj = drm_gem_object_lookup(filp, db_info->doorbell_handle);
|
||||
|
|
@ -480,7 +481,17 @@ amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
db_obj->obj = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj));
|
||||
/*
|
||||
* Pinning a regular BO into the doorbell domain would discard its
|
||||
* contents, possibly those of a buffer shared by another client.
|
||||
*/
|
||||
abo = gem_to_amdgpu_bo(gobj);
|
||||
if (!(abo->preferred_domains & AMDGPU_GEM_DOMAIN_DOORBELL)) {
|
||||
drm_gem_object_put(gobj);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
db_obj->obj = amdgpu_bo_ref(abo);
|
||||
drm_gem_object_put(gobj);
|
||||
|
||||
r = amdgpu_bo_reserve(db_obj->obj, true);
|
||||
|
|
|
|||
|
|
@ -361,8 +361,7 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
|
||||
compute_mqd = memdup_user(u64_to_user_ptr(mqd_user->mqd), mqd_user->mqd_size);
|
||||
if (IS_ERR(compute_mqd)) {
|
||||
DRM_ERROR("Failed to read user MQD\n");
|
||||
r = -ENOMEM;
|
||||
r = PTR_ERR(compute_mqd);
|
||||
goto free_mqd;
|
||||
}
|
||||
|
||||
|
|
@ -406,8 +405,7 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
|
||||
mqd_gfx_v11 = memdup_user(u64_to_user_ptr(mqd_user->mqd), mqd_user->mqd_size);
|
||||
if (IS_ERR(mqd_gfx_v11)) {
|
||||
DRM_ERROR("Failed to read user MQD\n");
|
||||
r = -ENOMEM;
|
||||
r = PTR_ERR(mqd_gfx_v11);
|
||||
goto free_mqd;
|
||||
}
|
||||
|
||||
|
|
@ -451,8 +449,7 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
|
||||
mqd_sdma_v11 = memdup_user(u64_to_user_ptr(mqd_user->mqd), mqd_user->mqd_size);
|
||||
if (IS_ERR(mqd_sdma_v11)) {
|
||||
DRM_ERROR("Failed to read sdma user MQD\n");
|
||||
r = -ENOMEM;
|
||||
r = PTR_ERR(mqd_sdma_v11);
|
||||
goto free_mqd;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -572,12 +572,32 @@ static int allocate_doorbell(struct qcm_process_device *qpd,
|
|||
* we need the physical sdma engine id in order to get the
|
||||
* correct doorbell offset.
|
||||
*/
|
||||
uint32_t valid_id = idx_offset[qpd->dqm->dev->node_id *
|
||||
get_num_all_sdma_engines(qpd->dqm) +
|
||||
q->properties.sdma_engine_id]
|
||||
+ (q->properties.sdma_queue_id & 1)
|
||||
* KFD_QUEUE_DOORBELL_MIRROR_OFFSET
|
||||
+ (q->properties.sdma_queue_id >> 1);
|
||||
u32 engine_base = idx_offset[dev->node_id *
|
||||
get_num_all_sdma_engines(qpd->dqm) +
|
||||
q->properties.sdma_engine_id];
|
||||
u32 valid_id;
|
||||
|
||||
/*
|
||||
* With the aqua_vanjaram doorbell layout, a shader doorbell
|
||||
* write whose 32-byte block starts in the previous engine's
|
||||
* range rings that engine instead. Engine ranges are 10
|
||||
* indices apart (sdma_doorbell_range = 20 dwords, halved for
|
||||
* 8-byte doorbells, in aqua_vanjaram_doorbell_index_init()),
|
||||
* which puts odd engines 2 indices into a shared block.
|
||||
* Aligning costs at most 2 indices, and 8 queues per engine use
|
||||
* only 4 of the 10, so the aligned base stays in range. The
|
||||
* 512-index mirror offset keeps the alignment.
|
||||
*/
|
||||
if (KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 3) ||
|
||||
KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 4) ||
|
||||
KFD_GC_VERSION(dev) == IP_VERSION(9, 5, 0))
|
||||
engine_base = ALIGN(engine_base,
|
||||
KFD_SDMA_SHADER_DOORBELL_GRANULARITY);
|
||||
|
||||
valid_id = engine_base +
|
||||
(q->properties.sdma_queue_id & 1) *
|
||||
KFD_QUEUE_DOORBELL_MIRROR_OFFSET +
|
||||
(q->properties.sdma_queue_id >> 1);
|
||||
|
||||
if (restore_id && *restore_id != valid_id)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -133,6 +133,13 @@
|
|||
*/
|
||||
#define KFD_QUEUE_DOORBELL_MIRROR_OFFSET 512
|
||||
|
||||
/*
|
||||
* On GC 9.4.3, 9.4.4 and 9.5.0, doorbell writes issued from shaders are
|
||||
* routed to an SDMA engine at 32-byte granularity, i.e. 4 indices with the
|
||||
* 8-byte SDMA doorbells used on SOC15.
|
||||
*/
|
||||
#define KFD_SDMA_SHADER_DOORBELL_GRANULARITY 4
|
||||
|
||||
/**
|
||||
* enum kfd_ioctl_flags - KFD ioctl flags
|
||||
* Various flags that can be set in &amdkfd_ioctl_desc.flags to control how
|
||||
|
|
|
|||
|
|
@ -3708,6 +3708,13 @@ static void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm,
|
|||
struct amdgpu_dm_connector *aconn =
|
||||
(struct amdgpu_dm_connector *)acrtc_state->stream->dm_stream_context;
|
||||
|
||||
if (!acrtc_state->base.async_flip) {
|
||||
amdgpu_dm_psr_set_event(dm, acrtc_state->stream, false,
|
||||
psr_event_immediate_flip, false);
|
||||
amdgpu_dm_replay_set_event(dm, acrtc_state->stream, false,
|
||||
replay_event_immediate_flip, false);
|
||||
}
|
||||
|
||||
/* Decrement skip count when SR is enabled and we're doing fast updates. */
|
||||
if (acrtc_state->update_type == UPDATE_TYPE_FAST &&
|
||||
(psr->psr_feature_enabled || pr->replay_feature_enabled)) {
|
||||
|
|
@ -4118,6 +4125,18 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
|
|||
spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
|
||||
}
|
||||
mutex_lock(&dm->dc_lock);
|
||||
/*
|
||||
* Tearing (immediate) flips cannot work with panel self-refresh
|
||||
* features. The event is cleared by
|
||||
* amdgpu_dm_enable_self_refresh() once async flips stop.
|
||||
*/
|
||||
if (immediate_flip) {
|
||||
dc_exit_ips_for_hw_access(dm->dc);
|
||||
amdgpu_dm_psr_set_event(dm, acrtc_state->stream, true,
|
||||
psr_event_immediate_flip, true);
|
||||
amdgpu_dm_replay_set_event(dm, acrtc_state->stream, true,
|
||||
replay_event_immediate_flip, true);
|
||||
}
|
||||
update_planes_and_stream_adapter(dm->dc,
|
||||
acrtc_state->update_type,
|
||||
planes_count,
|
||||
|
|
|
|||
|
|
@ -1012,10 +1012,15 @@ decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode,
|
|||
const struct drm_display_mode *native_mode,
|
||||
bool scale_enabled)
|
||||
{
|
||||
/* Inserted modes copy the native sync; a sink mode with equal totals may not */
|
||||
if (scale_enabled || (
|
||||
native_mode->clock == drm_mode->clock &&
|
||||
native_mode->htotal == drm_mode->htotal &&
|
||||
native_mode->vtotal == drm_mode->vtotal)) {
|
||||
native_mode->vtotal == drm_mode->vtotal &&
|
||||
native_mode->hsync_start == drm_mode->hsync_start &&
|
||||
native_mode->hsync_end == drm_mode->hsync_end &&
|
||||
native_mode->vsync_start == drm_mode->vsync_start &&
|
||||
native_mode->vsync_end == drm_mode->vsync_end)) {
|
||||
if (native_mode->crtc_clock)
|
||||
copy_crtc_timing_for_drm_display_mode(native_mode, drm_mode);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -112,25 +112,7 @@ void amdgpu_dm_plane_fill_blending_from_plane_state(const struct drm_plane_state
|
|||
|
||||
if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
|
||||
plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) {
|
||||
static const uint32_t alpha_formats[] = {
|
||||
DRM_FORMAT_ARGB8888,
|
||||
DRM_FORMAT_RGBA8888,
|
||||
DRM_FORMAT_ABGR8888,
|
||||
DRM_FORMAT_ARGB2101010,
|
||||
DRM_FORMAT_ABGR2101010,
|
||||
DRM_FORMAT_ARGB16161616,
|
||||
DRM_FORMAT_ABGR16161616,
|
||||
DRM_FORMAT_ARGB16161616F,
|
||||
};
|
||||
uint32_t format = plane_state->fb->format->format;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(alpha_formats); ++i) {
|
||||
if (format == alpha_formats[i]) {
|
||||
*per_pixel_alpha = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*per_pixel_alpha = plane_state->fb->format->has_alpha;
|
||||
|
||||
if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
|
||||
*pre_multiplied_alpha = false;
|
||||
|
|
|
|||
|
|
@ -1572,6 +1572,46 @@ static void dm_test_decide_crtc_timing_no_crtc_clock(struct kunit *test)
|
|||
KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 0);
|
||||
}
|
||||
|
||||
static void dm_test_decide_crtc_timing_sink_mode_same_totals(struct kunit *test)
|
||||
{
|
||||
struct drm_display_mode native_mode = {
|
||||
DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016, 4104,
|
||||
4400, 0, 2160, 2168, 2178, 2250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) };
|
||||
struct drm_display_mode drm_mode = {
|
||||
DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 4184, 4272,
|
||||
4400, 0, 2160, 2168, 2178, 2250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) };
|
||||
|
||||
drm_mode_set_crtcinfo(&native_mode, 0);
|
||||
drm_mode_set_crtcinfo(&drm_mode, 0);
|
||||
|
||||
decide_crtc_timing_for_drm_display_mode(&drm_mode, &native_mode, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 4096);
|
||||
KUNIT_EXPECT_EQ(test, drm_mode.crtc_hsync_start, 4184);
|
||||
}
|
||||
|
||||
static void dm_test_decide_crtc_timing_inserted_mode(struct kunit *test)
|
||||
{
|
||||
struct drm_display_mode native_mode = {
|
||||
DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016, 4104,
|
||||
4400, 0, 2160, 2168, 2178, 2250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) };
|
||||
struct drm_display_mode drm_mode;
|
||||
|
||||
drm_mode_set_crtcinfo(&native_mode, 0);
|
||||
drm_mode = native_mode;
|
||||
drm_mode.hdisplay = 1920;
|
||||
drm_mode.vdisplay = 1080;
|
||||
drm_mode_set_crtcinfo(&drm_mode, 0);
|
||||
|
||||
decide_crtc_timing_for_drm_display_mode(&drm_mode, &native_mode, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 3840);
|
||||
KUNIT_EXPECT_EQ(test, drm_mode.crtc_vdisplay, 2160);
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_connector_funcs_reset() */
|
||||
|
||||
static const struct drm_connector_funcs dm_test_connector_funcs = {
|
||||
|
|
@ -5635,6 +5675,8 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
|
|||
KUNIT_CASE(dm_test_decide_crtc_timing_matching_mode),
|
||||
KUNIT_CASE(dm_test_decide_crtc_timing_no_copy),
|
||||
KUNIT_CASE(dm_test_decide_crtc_timing_no_crtc_clock),
|
||||
KUNIT_CASE(dm_test_decide_crtc_timing_sink_mode_same_totals),
|
||||
KUNIT_CASE(dm_test_decide_crtc_timing_inserted_mode),
|
||||
/* amdgpu_dm_connector_funcs_reset */
|
||||
KUNIT_CASE(dm_test_funcs_reset_sets_defaults),
|
||||
KUNIT_CASE(dm_test_funcs_reset_edp_abm_level),
|
||||
|
|
|
|||
|
|
@ -189,13 +189,12 @@ static int aspeed_gfx_load(struct drm_device *drm)
|
|||
}
|
||||
reset_control_deassert(priv->rst);
|
||||
|
||||
priv->clk = devm_clk_get(drm->dev, NULL);
|
||||
priv->clk = devm_clk_get_enabled(drm->dev, NULL);
|
||||
if (IS_ERR(priv->clk)) {
|
||||
dev_err(&pdev->dev,
|
||||
"missing or invalid clk device tree entry");
|
||||
"failed to get and enable clock\n");
|
||||
return PTR_ERR(priv->clk);
|
||||
}
|
||||
clk_prepare_enable(priv->clk);
|
||||
|
||||
/* Sanitize control registers */
|
||||
writel(0, priv->base + CRT_CTRL1);
|
||||
|
|
|
|||
|
|
@ -135,8 +135,8 @@ static int th1520_dw_hdmi_probe(struct platform_device *pdev)
|
|||
plat_data->priv_data = hdmi;
|
||||
|
||||
hdmi->dw_hdmi = dw_hdmi_probe(pdev, plat_data);
|
||||
if (IS_ERR(hdmi))
|
||||
return PTR_ERR(hdmi);
|
||||
if (IS_ERR(hdmi->dw_hdmi))
|
||||
return PTR_ERR(hdmi->dw_hdmi);
|
||||
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
|
|
@ -145,9 +145,9 @@ static int th1520_dw_hdmi_probe(struct platform_device *pdev)
|
|||
|
||||
static void th1520_dw_hdmi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
|
||||
struct th1520_hdmi *hdmi = platform_get_drvdata(pdev);
|
||||
|
||||
dw_hdmi_remove(hdmi);
|
||||
dw_hdmi_remove(hdmi->dw_hdmi);
|
||||
}
|
||||
|
||||
static const struct of_device_id th1520_dw_hdmi_of_table[] = {
|
||||
|
|
|
|||
|
|
@ -4634,7 +4634,9 @@ static int dp_aux_backlight_update_status(struct backlight_device *bd)
|
|||
|
||||
if (!backlight_is_blank(bd)) {
|
||||
if (!bl->enabled) {
|
||||
drm_edp_backlight_enable(bl->aux, &bl->info, brightness);
|
||||
ret = drm_edp_backlight_enable(bl->aux, &bl->info, brightness);
|
||||
if (ret)
|
||||
return ret;
|
||||
bl->enabled = true;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -454,8 +454,10 @@ void drm_bridge_add(struct drm_bridge *bridge)
|
|||
* in bridge_lingering_list. Remove it or bridge_lingering_list will be
|
||||
* corrupted when adding this bridge to bridge_list below.
|
||||
*/
|
||||
mutex_lock(&bridge_lock);
|
||||
if (!list_empty(&bridge->list))
|
||||
list_del_init(&bridge->list);
|
||||
mutex_unlock(&bridge_lock);
|
||||
|
||||
mutex_init(&bridge->hpd_state_mutex);
|
||||
mutex_init(&bridge->hpd_mutex);
|
||||
|
|
@ -593,8 +595,10 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
|
|||
if (!bridge->container)
|
||||
DRM_WARN("DRM bridge corrupted or not allocated by devm_drm_bridge_alloc()\n");
|
||||
|
||||
if (list_empty(&bridge->list))
|
||||
DRM_WARN("Missing drm_bridge_add() before attach\n");
|
||||
scoped_guard(mutex, &bridge_lock) {
|
||||
if (list_empty(&bridge->list))
|
||||
DRM_WARN("Missing drm_bridge_add() before attach\n");
|
||||
}
|
||||
|
||||
drm_bridge_get(bridge);
|
||||
|
||||
|
|
|
|||
|
|
@ -1724,10 +1724,10 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper)
|
|||
|
||||
ret = drm_fb_helper_single_fb_probe(fb_helper);
|
||||
if (ret < 0) {
|
||||
if (ret == -EAGAIN) {
|
||||
fb_helper->deferred_setup = true;
|
||||
/* modesets are probed but fb_helper->fb isn't; defer restore too */
|
||||
fb_helper->deferred_setup = true;
|
||||
if (ret == -EAGAIN)
|
||||
ret = 0;
|
||||
}
|
||||
mutex_unlock(&fb_helper->lock);
|
||||
|
||||
goto err_drm_fb_helper_release_info;
|
||||
|
|
|
|||
|
|
@ -507,6 +507,7 @@ int gud_plane_atomic_check(struct drm_plane *plane,
|
|||
for_each_new_connector_in_state(state, connector, connector_state, i) {
|
||||
if (connector_state->crtc)
|
||||
break;
|
||||
connector_state = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1766,6 +1766,7 @@ static int eb_reinit_userptr(struct i915_execbuffer *eb)
|
|||
|
||||
static noinline int eb_relocate_parse_slow(struct i915_execbuffer *eb)
|
||||
{
|
||||
const unsigned int count = eb->buffer_count;
|
||||
bool have_copy = false;
|
||||
struct eb_vma *ev;
|
||||
int err = 0;
|
||||
|
|
@ -1868,7 +1869,6 @@ static noinline int eb_relocate_parse_slow(struct i915_execbuffer *eb)
|
|||
|
||||
out:
|
||||
if (have_copy) {
|
||||
const unsigned int count = eb->buffer_count;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
|
|
|
|||
|
|
@ -1904,7 +1904,8 @@ static void rps_work(struct work_struct *work)
|
|||
|
||||
out:
|
||||
spin_lock_irq(gt->irq_lock);
|
||||
gen6_gt_pm_unmask_irq(gt, rps->pm_events);
|
||||
if (intel_rps_is_active(rps))
|
||||
gen6_gt_pm_unmask_irq(gt, rps->pm_events);
|
||||
spin_unlock_irq(gt->irq_lock);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2337,7 +2337,7 @@ void pvr_mmu_op_context_destroy(struct pvr_mmu_op_context *op_ctx)
|
|||
* @ctx: MMU context associated with owning VM context.
|
||||
* @sgt: Scatter gather table containing pages pinned for use by this context.
|
||||
* @device_addr: Virtual device address at the start of the requested mapping.
|
||||
* @sgt_offset: Start offset of the requested device-virtual memory mapping.
|
||||
* @sgt_offset: Offset into @sgt of the start of the requested mapping.
|
||||
* @size: Size in bytes of the requested device-virtual memory mapping. For an
|
||||
* unmapping, this should be zero so that no page tables are allocated.
|
||||
*
|
||||
|
|
@ -2350,7 +2350,6 @@ struct pvr_mmu_op_context *
|
|||
pvr_mmu_op_context_create(struct pvr_mmu_context *ctx, struct sg_table *sgt,
|
||||
u64 device_addr, u64 sgt_offset, u64 size)
|
||||
{
|
||||
u64 start_addr = device_addr + sgt_offset;
|
||||
int err;
|
||||
|
||||
struct pvr_mmu_op_context *op_ctx = kzalloc_obj(*op_ctx);
|
||||
|
|
@ -2365,18 +2364,18 @@ pvr_mmu_op_context_create(struct pvr_mmu_context *ctx, struct sg_table *sgt,
|
|||
|
||||
if (size) {
|
||||
/*
|
||||
* The number of page table objects we need to prealloc is
|
||||
* indicated by the mapping size, start address and the sizes
|
||||
* of the areas mapped per PT or PD. The range calculation is
|
||||
* identical to that for the index into a table for a device
|
||||
* address, so we reuse those functions here.
|
||||
* The page tables needed are set by the device-virtual range
|
||||
* being mapped: one level 1 table per 1GiB region and one
|
||||
* level 0 table per 2MiB region the range touches. Tables that
|
||||
* already exist are not consumed, so this is an upper bound.
|
||||
*/
|
||||
const u32 l1_start_idx = pvr_page_table_l2_idx(start_addr);
|
||||
const u32 l1_end_idx = pvr_page_table_l2_idx(start_addr + size);
|
||||
const u32 l1_count = l1_end_idx - l1_start_idx + 1;
|
||||
const u32 l0_start_idx = pvr_page_table_l1_idx(start_addr);
|
||||
const u32 l0_end_idx = pvr_page_table_l1_idx(start_addr + size);
|
||||
const u32 l0_count = l0_end_idx - l0_start_idx + 1;
|
||||
const u64 last_addr = device_addr + size - 1;
|
||||
const u64 l1_count =
|
||||
(last_addr >> ROGUE_MMUCTRL_VADDR_PC_INDEX_SHIFT) -
|
||||
(device_addr >> ROGUE_MMUCTRL_VADDR_PC_INDEX_SHIFT) + 1;
|
||||
const u64 l0_count =
|
||||
(last_addr >> ROGUE_MMUCTRL_VADDR_PD_INDEX_SHIFT) -
|
||||
(device_addr >> ROGUE_MMUCTRL_VADDR_PD_INDEX_SHIFT) + 1;
|
||||
|
||||
/*
|
||||
* Alloc and push page table entries until we have enough of
|
||||
|
|
|
|||
|
|
@ -418,6 +418,8 @@ pvr_vm_gpuva_unmap(struct drm_gpuva_op *op, void *op_ctx)
|
|||
static int
|
||||
pvr_vm_gpuva_remap(struct drm_gpuva_op *op, void *op_ctx)
|
||||
{
|
||||
/* The split parts belong to the object of the mapping being split. */
|
||||
struct drm_gpuvm_bo *vm_bo = op->remap.unmap->va->vm_bo;
|
||||
struct pvr_vm_bind_op *ctx = op_ctx;
|
||||
u64 va_start = 0, va_range = 0;
|
||||
int err;
|
||||
|
|
@ -433,14 +435,12 @@ pvr_vm_gpuva_remap(struct drm_gpuva_op *op, void *op_ctx)
|
|||
drm_gpuva_remap(&ctx->prev_va->base, &ctx->next_va->base, &op->remap);
|
||||
|
||||
if (op->remap.prev) {
|
||||
pvr_gem_object_get(gem_to_pvr_gem(ctx->prev_va->base.gem.obj));
|
||||
drm_gpuva_link(&ctx->prev_va->base, ctx->gpuvm_bo);
|
||||
drm_gpuva_link(&ctx->prev_va->base, vm_bo);
|
||||
ctx->prev_va = NULL;
|
||||
}
|
||||
|
||||
if (op->remap.next) {
|
||||
pvr_gem_object_get(gem_to_pvr_gem(ctx->next_va->base.gem.obj));
|
||||
drm_gpuva_link(&ctx->next_va->base, ctx->gpuvm_bo);
|
||||
drm_gpuva_link(&ctx->next_va->base, vm_bo);
|
||||
ctx->next_va = NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -488,7 +488,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
|
|||
goto done;
|
||||
break;
|
||||
case NV_DEVICE_INFO_V0_TURING:
|
||||
if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_NVDEC) {
|
||||
if (engine == NV_DEVICE_HOST_RUNLIST_ENGINES_GR) {
|
||||
ret = nvif_object_ctor(&chan->chan->user, "abi16CeWar",
|
||||
0, TURING_DMA_COPY_A, NULL, 0,
|
||||
&chan->ce);
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ nvkm_udevice_gcx_ready(struct nvkm_udevice *udev, void *data, u32 size)
|
|||
} *args = data;
|
||||
int ret = -ENOSYS;
|
||||
|
||||
if (!gsp) {
|
||||
if (!gsp || !gsp->rm) {
|
||||
args->v0.ready = NV_DEVICE_GC6_READY | NV_DEVICE_GCOFF_READY;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3674,6 +3674,9 @@ int panthor_group_create(struct panthor_file *pfile,
|
|||
hweight64(group_args->tiler_core_mask) < group_args->max_tiler_cores)
|
||||
return -EINVAL;
|
||||
|
||||
if (group_args->queues.count > sched->cs_slot_count)
|
||||
return -EINVAL;
|
||||
|
||||
group = kzalloc_obj(*group);
|
||||
if (!group)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ static struct list_head *vc4_get_cache_list_for_size(struct drm_device *dev,
|
|||
struct list_head *new_list;
|
||||
uint32_t i;
|
||||
|
||||
new_list = kmalloc_objs(struct list_head, new_size);
|
||||
new_list = kvmalloc_objs(struct list_head, new_size);
|
||||
if (!new_list)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -224,7 +224,7 @@ static struct list_head *vc4_get_cache_list_for_size(struct drm_device *dev,
|
|||
for (i = vc4->bo_cache.size_list_size; i < new_size; i++)
|
||||
INIT_LIST_HEAD(&new_list[i]);
|
||||
|
||||
kfree(vc4->bo_cache.size_list);
|
||||
kvfree(vc4->bo_cache.size_list);
|
||||
vc4->bo_cache.size_list = new_list;
|
||||
vc4->bo_cache.size_list_size = new_size;
|
||||
}
|
||||
|
|
@ -1052,6 +1052,7 @@ static void vc4_bo_cache_destroy(struct drm_device *dev, void *unused)
|
|||
cancel_work_sync(&vc4->bo_cache.time_work);
|
||||
|
||||
vc4_bo_cache_purge(dev);
|
||||
kvfree(vc4->bo_cache.size_list);
|
||||
|
||||
for (i = 0; i < vc4->num_labels; i++) {
|
||||
if (vc4->bo_labels[i].num_allocated) {
|
||||
|
|
|
|||
|
|
@ -360,8 +360,11 @@ static int vc4_drm_bind(struct device *dev)
|
|||
}
|
||||
|
||||
ret = aperture_remove_all_conflicting_devices(driver->name);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
if (firmware)
|
||||
rpi_firmware_put(firmware);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (firmware) {
|
||||
ret = rpi_firmware_property(firmware,
|
||||
|
|
|
|||
|
|
@ -1051,7 +1051,7 @@ void vc4_plane_async_set_fb(struct drm_plane *plane,
|
|||
/* vc4_v3d.c */
|
||||
extern struct platform_driver vc4_v3d_driver;
|
||||
extern const struct of_device_id vc4_v3d_dt_match[];
|
||||
int vc4_v3d_get_bin_slot(struct vc4_dev *vc4);
|
||||
int vc4_v3d_get_bin_slot(struct vc4_dev *vc4, long timeout);
|
||||
int vc4_v3d_bin_bo_get(struct vc4_dev *vc4, bool *used);
|
||||
void vc4_v3d_bin_bo_put(struct vc4_dev *vc4);
|
||||
int vc4_v3d_pm_get(struct vc4_dev *vc4);
|
||||
|
|
|
|||
|
|
@ -877,11 +877,17 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
|
|||
drm_gem_object_put(&bo->base.base);
|
||||
}
|
||||
|
||||
/* Free up the allocation of any bin slots we used. */
|
||||
/* Free up the allocation of any bin slots we used. Jobs that ran to
|
||||
* completion had their slots released in vc4_irq_finish_render_job().
|
||||
* Only jobs that never completed still have slots to be released here.
|
||||
*/
|
||||
spin_lock_irqsave(&vc4->job_lock, irqflags);
|
||||
vc4->bin_alloc_used &= ~exec->bin_slots;
|
||||
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
|
||||
|
||||
/* Let anyone waiting on the binner pool retry. */
|
||||
wake_up_all(&vc4->job_wait_queue);
|
||||
|
||||
/* Release the reference on the binner BO if needed. */
|
||||
if (exec->bin_bo_used)
|
||||
vc4_v3d_bin_bo_put(vc4);
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ vc4_overflow_mem_work(struct work_struct *work)
|
|||
|
||||
bo = vc4->bin_bo;
|
||||
|
||||
bin_bo_slot = vc4_v3d_get_bin_slot(vc4);
|
||||
bin_bo_slot = vc4_v3d_get_bin_slot(vc4, msecs_to_jiffies(500));
|
||||
if (bin_bo_slot < 0) {
|
||||
drm_err(&vc4->base, "Couldn't allocate binner overflow mem\n");
|
||||
goto complete;
|
||||
|
|
@ -165,6 +165,10 @@ vc4_irq_finish_render_job(struct drm_device *dev)
|
|||
trace_vc4_rcl_end_irq(dev, exec->seqno);
|
||||
|
||||
vc4->finished_seqno++;
|
||||
|
||||
vc4->bin_alloc_used &= ~exec->bin_slots;
|
||||
exec->bin_slots = 0;
|
||||
|
||||
list_move_tail(&exec->head, &vc4->job_done_list);
|
||||
|
||||
nextbin = vc4_first_bin_job(vc4);
|
||||
|
|
@ -276,7 +280,7 @@ vc4_irq_disable(struct drm_device *dev)
|
|||
V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
|
||||
|
||||
/* Finish any interrupt handler still in flight. */
|
||||
synchronize_irq(vc4->irq);
|
||||
disable_irq(vc4->irq);
|
||||
|
||||
cancel_work_sync(&vc4->overflow_mem_work);
|
||||
}
|
||||
|
|
@ -284,7 +288,6 @@ vc4_irq_disable(struct drm_device *dev)
|
|||
int vc4_irq_install(struct drm_device *dev, int irq)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
int ret;
|
||||
|
||||
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
|
||||
return -ENODEV;
|
||||
|
|
@ -298,19 +301,8 @@ int vc4_irq_install(struct drm_device *dev, int irq)
|
|||
init_waitqueue_head(&vc4->job_wait_queue);
|
||||
INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work);
|
||||
|
||||
/* Clear any pending interrupts someone might have left around
|
||||
* for us.
|
||||
*/
|
||||
V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
|
||||
|
||||
ret = devm_request_irq(dev->dev, irq, vc4_irq, 0,
|
||||
dev_name(dev->dev), dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vc4_irq_enable(dev);
|
||||
|
||||
return 0;
|
||||
return devm_request_irq(dev->dev, irq, vc4_irq, IRQF_NO_AUTOEN,
|
||||
dev_name(dev->dev), dev);
|
||||
}
|
||||
|
||||
void vc4_irq_uninstall(struct drm_device *dev)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/component.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
|
|
@ -172,46 +173,42 @@ static void vc4_v3d_init_hw(struct drm_device *dev)
|
|||
V3D_WRITE(V3D_VPMBASE, 0);
|
||||
}
|
||||
|
||||
int vc4_v3d_get_bin_slot(struct vc4_dev *vc4)
|
||||
static int bin_slot_try_alloc(struct vc4_dev *vc4)
|
||||
{
|
||||
struct drm_device *dev = &vc4->base;
|
||||
unsigned long irqflags;
|
||||
int slot;
|
||||
uint64_t seqno = 0;
|
||||
struct vc4_exec_info *exec;
|
||||
|
||||
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
|
||||
return -ENODEV;
|
||||
guard(spinlock_irqsave)(&vc4->job_lock);
|
||||
|
||||
try_again:
|
||||
spin_lock_irqsave(&vc4->job_lock, irqflags);
|
||||
slot = ffs(~vc4->bin_alloc_used);
|
||||
if (slot != 0) {
|
||||
/* Switch from ffs() bit index to a 0-based index. */
|
||||
slot--;
|
||||
vc4->bin_alloc_used |= BIT(slot);
|
||||
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
|
||||
return slot;
|
||||
} else {
|
||||
slot = -ENOMEM;
|
||||
}
|
||||
|
||||
/* Couldn't find an open slot. Wait for render to complete
|
||||
* and try again.
|
||||
*/
|
||||
exec = vc4_last_render_job(vc4);
|
||||
if (exec)
|
||||
seqno = exec->seqno;
|
||||
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
|
||||
return slot;
|
||||
}
|
||||
|
||||
if (seqno) {
|
||||
int ret = vc4_wait_for_seqno(dev, seqno, ~0ull, true);
|
||||
int vc4_v3d_get_bin_slot(struct vc4_dev *vc4, long timeout)
|
||||
{
|
||||
int slot;
|
||||
long ret;
|
||||
|
||||
if (ret == 0)
|
||||
goto try_again;
|
||||
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
|
||||
return -ENODEV;
|
||||
|
||||
/* If the pool is full, wait for a job to release its slots. */
|
||||
ret = wait_event_interruptible_timeout(vc4->job_wait_queue,
|
||||
(slot = bin_slot_try_alloc(vc4)) >= 0,
|
||||
timeout);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (ret == 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return -ENOMEM;
|
||||
return slot;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -396,6 +393,7 @@ static int vc4_v3d_runtime_resume(struct device *dev)
|
|||
vc4_v3d_init_hw(&vc4->base);
|
||||
|
||||
vc4_irq_enable(&vc4->base);
|
||||
enable_irq(vc4->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -452,6 +450,12 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
|
|||
return ret;
|
||||
vc4->irq = ret;
|
||||
|
||||
ret = vc4_irq_install(drm, vc4->irq);
|
||||
if (ret) {
|
||||
drm_err(drm, "Failed to install IRQ handler\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -473,12 +477,6 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
|
|||
V3D_WRITE(V3D_BPOA, 0);
|
||||
V3D_WRITE(V3D_BPOS, 0);
|
||||
|
||||
ret = vc4_irq_install(drm, vc4->irq);
|
||||
if (ret) {
|
||||
drm_err(drm, "Failed to install IRQ handler\n");
|
||||
goto err_put_runtime_pm;
|
||||
}
|
||||
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_set_autosuspend_delay(dev, 40); /* a little over 2 frames. */
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
|
@ -497,8 +495,15 @@ static void vc4_v3d_unbind(struct device *dev, struct device *master,
|
|||
struct drm_device *drm = data;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(drm);
|
||||
|
||||
/* A straggler vc4_reset() re-enables the interrupt. */
|
||||
timer_shutdown_sync(&vc4->hangcheck.timer);
|
||||
cancel_work_sync(&vc4->hangcheck.reset_work);
|
||||
|
||||
vc4_irq_uninstall(drm);
|
||||
|
||||
/* Flush rather than cancel, so queued completions release their jobs. */
|
||||
flush_work(&vc4->job_done_work);
|
||||
|
||||
/* Disable the binner's overflow memory address, so the next
|
||||
* driver probe (if any) doesn't try to reuse our old
|
||||
* allocation.
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ validate_tile_binning_config(VALIDATE_ARGS)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
bin_slot = vc4_v3d_get_bin_slot(vc4);
|
||||
bin_slot = vc4_v3d_get_bin_slot(vc4, MAX_SCHEDULE_TIMEOUT);
|
||||
if (bin_slot < 0) {
|
||||
if (bin_slot != -EINTR && bin_slot != -ERESTARTSYS) {
|
||||
drm_err(dev, "Failed to allocate binner memory: %d\n",
|
||||
|
|
|
|||
|
|
@ -324,6 +324,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
|
|||
unsigned long kmap_num;
|
||||
SVGA3dCopyBox *box;
|
||||
u32 box_count;
|
||||
u64 src_extent;
|
||||
void *virtual;
|
||||
bool is_iomem;
|
||||
struct vmw_dma_cmd {
|
||||
|
|
@ -335,6 +336,8 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
|
|||
vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT);
|
||||
const u32 image_pitch = VMW_CURSOR_SNOOP_WIDTH * desc->pitchBytesPerBlock;
|
||||
|
||||
BUILD_BUG_ON(sizeof(*srf->snooper.image) != desc->pitchBytesPerBlock);
|
||||
|
||||
cmd = container_of(header, struct vmw_dma_cmd, header);
|
||||
|
||||
/* No snooper installed, nothing to copy */
|
||||
|
|
@ -372,8 +375,19 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
|
|||
return;
|
||||
}
|
||||
|
||||
if (box->w == 0 || box->h == 0)
|
||||
return;
|
||||
|
||||
src_extent = (u64)(box->h - 1) * cmd->dma.guest.pitch +
|
||||
(u64)box->w * desc->pitchBytesPerBlock;
|
||||
if (src_extent > bo->base.size) {
|
||||
DRM_ERROR("Cursor snoop source of %llu bytes exceeds the %zu byte buffer\n",
|
||||
src_extent, bo->base.size);
|
||||
return;
|
||||
}
|
||||
|
||||
kmap_offset = cmd->dma.guest.ptr.offset >> PAGE_SHIFT;
|
||||
kmap_num = (VMW_CURSOR_SNOOP_HEIGHT * image_pitch) >> PAGE_SHIFT;
|
||||
kmap_num = PFN_UP(src_extent);
|
||||
|
||||
ret = ttm_bo_reserve(bo, true, false, NULL);
|
||||
if (unlikely(ret != 0)) {
|
||||
|
|
@ -387,14 +401,16 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
|
|||
|
||||
virtual = ttm_kmap_obj_virtual(&map, &is_iomem);
|
||||
|
||||
if (box->w == VMW_CURSOR_SNOOP_WIDTH && cmd->dma.guest.pitch == image_pitch) {
|
||||
if (box->w == VMW_CURSOR_SNOOP_WIDTH &&
|
||||
box->h == VMW_CURSOR_SNOOP_HEIGHT &&
|
||||
cmd->dma.guest.pitch == image_pitch) {
|
||||
memcpy(srf->snooper.image, virtual,
|
||||
VMW_CURSOR_SNOOP_HEIGHT * image_pitch);
|
||||
} else {
|
||||
/* Image is unsigned pointer. */
|
||||
/* The destination stride is in pixels. */
|
||||
for (i = 0; i < box->h; i++)
|
||||
memcpy(srf->snooper.image + i * image_pitch,
|
||||
virtual + i * cmd->dma.guest.pitch,
|
||||
memcpy(srf->snooper.image + i * VMW_CURSOR_SNOOP_WIDTH,
|
||||
virtual + (size_t)i * cmd->dma.guest.pitch,
|
||||
box->w * desc->pitchBytesPerBlock);
|
||||
}
|
||||
srf->snooper.id++;
|
||||
|
|
|
|||
|
|
@ -20,10 +20,18 @@
|
|||
#include <drm/drm_rect.h>
|
||||
#include <drm/drm_sysfs.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_blend.h>
|
||||
|
||||
void vmw_du_init(struct vmw_display_unit *du)
|
||||
{
|
||||
vmw_vkms_crtc_init(&du->crtc);
|
||||
drm_plane_create_blend_mode_property(&du->primary,
|
||||
BIT(DRM_MODE_BLEND_PIXEL_NONE) |
|
||||
BIT(DRM_MODE_BLEND_PREMULTI));
|
||||
// Check that the cursor plane was actually initialized
|
||||
if (du->crtc.cursor == &du->cursor.base)
|
||||
drm_plane_create_blend_mode_property(&du->cursor.base,
|
||||
BIT(DRM_MODE_BLEND_PREMULTI));
|
||||
}
|
||||
|
||||
void vmw_du_cleanup(struct vmw_display_unit *du)
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ static struct i915_vma *__xe_pin_fb_vma(struct drm_gem_object *obj, bool is_dpt,
|
|||
drm_exec_retry_on_contention(&exec);
|
||||
xe_validation_retry_on_oom(&ctx, &ret);
|
||||
if (!ret)
|
||||
ttm_bo_pin(&bo->ttm);
|
||||
xe_bo_pin_account(bo);
|
||||
}
|
||||
if (ret)
|
||||
goto err;
|
||||
|
|
@ -373,7 +373,7 @@ static struct i915_vma *__xe_pin_fb_vma(struct drm_gem_object *obj, bool is_dpt,
|
|||
|
||||
err_unpin:
|
||||
ttm_bo_reserve(&bo->ttm, false, false, NULL);
|
||||
ttm_bo_unpin(&bo->ttm);
|
||||
xe_bo_unpin_account(bo);
|
||||
ttm_bo_unreserve(&bo->ttm);
|
||||
err:
|
||||
kfree(vma);
|
||||
|
|
@ -393,7 +393,7 @@ static void __xe_unpin_fb_vma(struct i915_vma *vma)
|
|||
xe_ggtt_node_remove(vma->node, false);
|
||||
|
||||
ttm_bo_reserve(&vma->bo->ttm, false, false, NULL);
|
||||
ttm_bo_unpin(&vma->bo->ttm);
|
||||
xe_bo_unpin_account(vma->bo);
|
||||
ttm_bo_unreserve(&vma->bo->ttm);
|
||||
kfree(vma);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -455,6 +455,100 @@ static void xe_ttm_tt_account_subtract(struct xe_device *xe, struct ttm_tt *tt)
|
|||
xe_shrinker_mod_pages(xe->mem.shrinker, -(long)tt->num_pages, 0);
|
||||
}
|
||||
|
||||
static bool xe_ttm_bo_is_imported(struct ttm_buffer_object *tbo)
|
||||
{
|
||||
dma_resv_assert_held(tbo->base.resv);
|
||||
|
||||
return tbo->ttm &&
|
||||
(tbo->ttm->page_flags & (TTM_TT_FLAG_EXTERNAL | TTM_TT_FLAG_EXTERNAL_MAPPABLE)) ==
|
||||
TTM_TT_FLAG_EXTERNAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Account @bo's pages as pinned for the shrinker. Removes @bo's pages
|
||||
* from the shrinker's shrinkable / purgeable counts on the transition
|
||||
* from unpinned to pinned. Must be called with @bo's dma-resv held,
|
||||
* after &ttm_buffer_object.pin_count has been incremented by
|
||||
* ttm_bo_pin(). Safe to call unconditionally regardless of which pin
|
||||
* path (kernel, external, framebuffer, backup object, ...) is pinning
|
||||
* @bo, since it only acts on the true 0->1 pin_count transition.
|
||||
*
|
||||
* Imported bos (xe_ttm_bo_is_imported()) are excluded: for those,
|
||||
* xe_ttm_tt_populate() never actually populates the tt or calls
|
||||
* xe_ttm_tt_account_add(), but TTM core's ttm_tt_populate() still
|
||||
* unconditionally marks the tt as populated on driver-hook success.
|
||||
* Relying on ttm_tt_is_populated() for these would subtract pages that
|
||||
* were never added, underflowing the shrinker's counts.
|
||||
*/
|
||||
static void xe_bo_account_pin(struct xe_bo *bo)
|
||||
{
|
||||
struct xe_device *xe = xe_bo_device(bo);
|
||||
|
||||
if (bo->ttm.pin_count == 1 && bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm) &&
|
||||
!xe_ttm_bo_is_imported(&bo->ttm))
|
||||
xe_ttm_tt_account_subtract(xe, bo->ttm.ttm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Counterpart to xe_bo_account_pin(). Must be called with @bo's dma-resv
|
||||
* held, before &ttm_buffer_object.pin_count is decremented by
|
||||
* ttm_bo_unpin(), so that the check against the true 1->0 transition sees
|
||||
* the pin count that is about to be released. See xe_bo_account_pin() for
|
||||
* why imported bos are excluded.
|
||||
*
|
||||
* On the true last unpin, also removes @bo from whichever pinned-bo list
|
||||
* (external or kernel_bo_present) it may currently be linked on, since a
|
||||
* bo's final unpin can happen through a pin path (e.g. framebuffer,
|
||||
* backup object) that has no notion of, or ownership over, that list.
|
||||
* This is safe and list-agnostic: list_del_init() only needs the node
|
||||
* itself, not knowledge of which list it is threaded through, and is a
|
||||
* no-op if @bo is not linked.
|
||||
*/
|
||||
static void xe_bo_account_unpin(struct xe_bo *bo)
|
||||
{
|
||||
struct xe_device *xe = xe_bo_device(bo);
|
||||
bool last_unpin = bo->ttm.pin_count == 1;
|
||||
|
||||
if (last_unpin && !list_empty(&bo->pinned_link)) {
|
||||
spin_lock(&xe->pinned.lock);
|
||||
list_del_init(&bo->pinned_link);
|
||||
spin_unlock(&xe->pinned.lock);
|
||||
}
|
||||
|
||||
if (last_unpin && bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm) &&
|
||||
!xe_ttm_bo_is_imported(&bo->ttm))
|
||||
xe_ttm_tt_account_add(xe, bo->ttm.ttm);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_bo_pin_account() - Pin a bo and account its pages for the shrinker
|
||||
* @bo: The buffer object to pin.
|
||||
*
|
||||
* Pins @bo via ttm_bo_pin() and updates the shrinker's shrinkable /
|
||||
* purgeable page accounting to match. Must be called with @bo's dma-resv
|
||||
* held. Safe to call regardless of which pin path (kernel, external,
|
||||
* framebuffer, backup object, ...) is pinning @bo.
|
||||
*/
|
||||
void xe_bo_pin_account(struct xe_bo *bo)
|
||||
{
|
||||
ttm_bo_pin(&bo->ttm);
|
||||
xe_bo_account_pin(bo);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_bo_unpin_account() - Unpin a bo and account its pages for the shrinker
|
||||
* @bo: The buffer object to unpin.
|
||||
*
|
||||
* Counterpart to xe_bo_pin_account(). Updates the shrinker's shrinkable /
|
||||
* purgeable page accounting to match, then unpins @bo via ttm_bo_unpin().
|
||||
* Must be called with @bo's dma-resv held.
|
||||
*/
|
||||
void xe_bo_unpin_account(struct xe_bo *bo)
|
||||
{
|
||||
xe_bo_account_unpin(bo);
|
||||
ttm_bo_unpin(&bo->ttm);
|
||||
}
|
||||
|
||||
static void update_global_total_pages(struct ttm_device *ttm_dev,
|
||||
long num_pages)
|
||||
{
|
||||
|
|
@ -1389,7 +1483,8 @@ int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
|
|||
}
|
||||
|
||||
backup->parent_obj = xe_bo_get(bo); /* Released by bo_destroy */
|
||||
ttm_bo_pin(&backup->ttm);
|
||||
/* Note: XE_BO_FLAG_SYSTEM resolves to XE_PL_TT so already populated. */
|
||||
xe_bo_pin_account(backup);
|
||||
bo->backup_obj = backup;
|
||||
}
|
||||
|
||||
|
|
@ -1409,7 +1504,7 @@ int xe_bo_notifier_unprepare_pinned(struct xe_bo *bo)
|
|||
{
|
||||
xe_bo_lock(bo, false);
|
||||
if (bo->backup_obj) {
|
||||
ttm_bo_unpin(&bo->backup_obj->ttm);
|
||||
xe_bo_unpin_account(bo->backup_obj);
|
||||
xe_bo_put(bo->backup_obj);
|
||||
bo->backup_obj = NULL;
|
||||
}
|
||||
|
|
@ -1620,7 +1715,7 @@ int xe_bo_restore_pinned(struct xe_bo *bo)
|
|||
xe_bo_vunmap(backup);
|
||||
if (!bo->backup_obj) {
|
||||
if (xe_bo_is_pinned(backup))
|
||||
ttm_bo_unpin(&backup->ttm);
|
||||
xe_bo_unpin_account(backup);
|
||||
xe_bo_put(backup);
|
||||
}
|
||||
out_unlock_bo:
|
||||
|
|
@ -2012,15 +2107,6 @@ static vm_fault_t xe_err_to_fault_t(int err)
|
|||
return VM_FAULT_SIGBUS;
|
||||
}
|
||||
|
||||
static bool xe_ttm_bo_is_imported(struct ttm_buffer_object *tbo)
|
||||
{
|
||||
dma_resv_assert_held(tbo->base.resv);
|
||||
|
||||
return tbo->ttm &&
|
||||
(tbo->ttm->page_flags & (TTM_TT_FLAG_EXTERNAL | TTM_TT_FLAG_EXTERNAL_MAPPABLE)) ==
|
||||
TTM_TT_FLAG_EXTERNAL;
|
||||
}
|
||||
|
||||
static vm_fault_t xe_bo_cpu_fault_fastpath(struct vm_fault *vmf, struct xe_device *xe,
|
||||
struct xe_bo *bo, bool needs_rpm)
|
||||
{
|
||||
|
|
@ -3141,12 +3227,13 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res)
|
|||
int xe_bo_pin_external(struct xe_bo *bo, bool in_place, struct drm_exec *exec)
|
||||
{
|
||||
struct xe_device *xe = xe_bo_device(bo);
|
||||
bool first_pin = !xe_bo_is_pinned(bo);
|
||||
int err;
|
||||
|
||||
xe_assert(xe, !bo->vm);
|
||||
xe_assert(xe, xe_bo_is_user(bo));
|
||||
|
||||
if (!xe_bo_is_pinned(bo)) {
|
||||
if (first_pin) {
|
||||
if (!in_place) {
|
||||
err = xe_bo_validate(bo, NULL, false, exec);
|
||||
if (err)
|
||||
|
|
@ -3158,9 +3245,7 @@ int xe_bo_pin_external(struct xe_bo *bo, bool in_place, struct drm_exec *exec)
|
|||
spin_unlock(&xe->pinned.lock);
|
||||
}
|
||||
|
||||
ttm_bo_pin(&bo->ttm);
|
||||
if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
|
||||
xe_ttm_tt_account_subtract(xe, bo->ttm.ttm);
|
||||
xe_bo_pin_account(bo);
|
||||
|
||||
/*
|
||||
* FIXME: If we always use the reserve / unreserve functions for locking
|
||||
|
|
@ -3216,9 +3301,7 @@ int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec)
|
|||
spin_unlock(&xe->pinned.lock);
|
||||
}
|
||||
|
||||
ttm_bo_pin(&bo->ttm);
|
||||
if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
|
||||
xe_ttm_tt_account_subtract(xe, bo->ttm.ttm);
|
||||
xe_bo_pin_account(bo);
|
||||
|
||||
/*
|
||||
* FIXME: If we always use the reserve / unreserve functions for locking
|
||||
|
|
@ -3247,14 +3330,7 @@ void xe_bo_unpin_external(struct xe_bo *bo)
|
|||
xe_assert(xe, xe_bo_is_pinned(bo));
|
||||
xe_assert(xe, xe_bo_is_user(bo));
|
||||
|
||||
spin_lock(&xe->pinned.lock);
|
||||
if (bo->ttm.pin_count == 1 && !list_empty(&bo->pinned_link))
|
||||
list_del_init(&bo->pinned_link);
|
||||
spin_unlock(&xe->pinned.lock);
|
||||
|
||||
ttm_bo_unpin(&bo->ttm);
|
||||
if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
|
||||
xe_ttm_tt_account_add(xe, bo->ttm.ttm);
|
||||
xe_bo_unpin_account(bo);
|
||||
|
||||
/*
|
||||
* FIXME: If we always use the reserve / unreserve functions for locking
|
||||
|
|
@ -3272,21 +3348,16 @@ void xe_bo_unpin(struct xe_bo *bo)
|
|||
xe_assert(xe, xe_bo_is_pinned(bo));
|
||||
|
||||
if (mem_type_is_vram(place->mem_type) || bo->flags & XE_BO_FLAG_GGTT) {
|
||||
spin_lock(&xe->pinned.lock);
|
||||
xe_assert(xe, !list_empty(&bo->pinned_link));
|
||||
list_del_init(&bo->pinned_link);
|
||||
spin_unlock(&xe->pinned.lock);
|
||||
|
||||
if (bo->backup_obj) {
|
||||
if (xe_bo_is_pinned(bo->backup_obj))
|
||||
ttm_bo_unpin(&bo->backup_obj->ttm);
|
||||
xe_bo_unpin_account(bo->backup_obj);
|
||||
xe_bo_put(bo->backup_obj);
|
||||
bo->backup_obj = NULL;
|
||||
}
|
||||
}
|
||||
ttm_bo_unpin(&bo->ttm);
|
||||
if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
|
||||
xe_ttm_tt_account_add(xe, bo->ttm.ttm);
|
||||
xe_bo_unpin_account(bo);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -229,6 +229,8 @@ int xe_bo_pin_external(struct xe_bo *bo, bool in_place, struct drm_exec *exec);
|
|||
int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec);
|
||||
void xe_bo_unpin_external(struct xe_bo *bo);
|
||||
void xe_bo_unpin(struct xe_bo *bo);
|
||||
void xe_bo_pin_account(struct xe_bo *bo);
|
||||
void xe_bo_unpin_account(struct xe_bo *bo);
|
||||
int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict,
|
||||
struct drm_exec *exec);
|
||||
|
||||
|
|
|
|||
|
|
@ -324,12 +324,15 @@ static void xe_i2c_remove(void *data)
|
|||
xe_i2c_irq_reset(xe);
|
||||
xe_amc_exit(i2c);
|
||||
|
||||
/* Stop the notifier from arming the client work before teardown. */
|
||||
bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier);
|
||||
cancel_work_sync(&i2c->work);
|
||||
|
||||
for (i = 0; i < XE_I2C_MAX_CLIENTS; i++) {
|
||||
i2c_unregister_device(i2c->client[i]);
|
||||
i2c->client[i] = NULL;
|
||||
}
|
||||
|
||||
bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier);
|
||||
xe_i2c_unregister_adapter(i2c);
|
||||
xe->i2c = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1099,8 +1099,7 @@ static void xe_lrc_finish(struct xe_lrc *lrc)
|
|||
#define CONTEXT_ACTIVE XE_LRC_CTX_TIMESTAMP_ACTIVE
|
||||
static ssize_t setup_utilization_wa(struct xe_lrc *lrc,
|
||||
struct xe_hw_engine *hwe,
|
||||
u32 *batch,
|
||||
size_t max_len)
|
||||
u32 *batch, size_t max_len, bool indirect)
|
||||
{
|
||||
u32 *cmd = batch;
|
||||
|
||||
|
|
@ -1131,19 +1130,25 @@ static ssize_t setup_utilization_wa(struct xe_lrc *lrc,
|
|||
}
|
||||
|
||||
static ssize_t setup_timestamp_wa(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
|
||||
u32 *batch, size_t max_len)
|
||||
u32 *batch, size_t max_len, bool indirect)
|
||||
{
|
||||
const u32 ts_addr = __xe_lrc_ctx_timestamp_ggtt_addr(lrc);
|
||||
u32 *cmd = batch;
|
||||
|
||||
if (!XE_GT_WA(lrc->gt, 16010904313) ||
|
||||
!(hwe->class == XE_ENGINE_CLASS_RENDER ||
|
||||
hwe->class == XE_ENGINE_CLASS_COMPUTE ||
|
||||
hwe->class == XE_ENGINE_CLASS_COPY ||
|
||||
if (!XE_GT_WA(lrc->gt, 16010904313))
|
||||
return 0;
|
||||
|
||||
if (!indirect &&
|
||||
!(hwe->class == XE_ENGINE_CLASS_COPY ||
|
||||
hwe->class == XE_ENGINE_CLASS_VIDEO_DECODE ||
|
||||
hwe->class == XE_ENGINE_CLASS_VIDEO_ENHANCE))
|
||||
return 0;
|
||||
|
||||
if (indirect &&
|
||||
!(hwe->class == XE_ENGINE_CLASS_RENDER ||
|
||||
hwe->class == XE_ENGINE_CLASS_COMPUTE))
|
||||
return 0;
|
||||
|
||||
if (xe_gt_WARN_ON(lrc->gt, max_len < 12))
|
||||
return -ENOSPC;
|
||||
|
||||
|
|
@ -1169,7 +1174,8 @@ static ssize_t setup_timestamp_wa(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
|
|||
|
||||
static ssize_t setup_configfs_post_ctx_restore_bb(struct xe_lrc *lrc,
|
||||
struct xe_hw_engine *hwe,
|
||||
u32 *batch, size_t max_len)
|
||||
u32 *batch, size_t max_len,
|
||||
bool indirect)
|
||||
{
|
||||
struct xe_device *xe = gt_to_xe(lrc->gt);
|
||||
const u32 *user_batch;
|
||||
|
|
@ -1198,7 +1204,8 @@ static ssize_t setup_configfs_post_ctx_restore_bb(struct xe_lrc *lrc,
|
|||
|
||||
static ssize_t setup_configfs_mid_ctx_restore_bb(struct xe_lrc *lrc,
|
||||
struct xe_hw_engine *hwe,
|
||||
u32 *batch, size_t max_len)
|
||||
u32 *batch, size_t max_len,
|
||||
bool indirect)
|
||||
{
|
||||
struct xe_device *xe = gt_to_xe(lrc->gt);
|
||||
const u32 *user_batch;
|
||||
|
|
@ -1227,7 +1234,8 @@ static ssize_t setup_configfs_mid_ctx_restore_bb(struct xe_lrc *lrc,
|
|||
|
||||
static ssize_t setup_invalidate_state_cache_wa(struct xe_lrc *lrc,
|
||||
struct xe_hw_engine *hwe,
|
||||
u32 *batch, size_t max_len)
|
||||
u32 *batch, size_t max_len,
|
||||
bool indirect)
|
||||
{
|
||||
u32 *cmd = batch;
|
||||
|
||||
|
|
@ -1247,7 +1255,8 @@ static ssize_t setup_invalidate_state_cache_wa(struct xe_lrc *lrc,
|
|||
|
||||
static ssize_t setup_invalidate_auxccs_wa(struct xe_lrc *lrc,
|
||||
struct xe_hw_engine *hwe,
|
||||
u32 *batch, size_t max_len)
|
||||
u32 *batch, size_t max_len,
|
||||
bool indirect)
|
||||
{
|
||||
struct xe_gt *gt = lrc->gt;
|
||||
u32 *(*emit)(struct xe_gt *gt, u32 *cmd) =
|
||||
|
|
@ -1264,7 +1273,7 @@ static ssize_t setup_invalidate_auxccs_wa(struct xe_lrc *lrc,
|
|||
|
||||
struct bo_setup {
|
||||
ssize_t (*setup)(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
|
||||
u32 *batch, size_t max_size);
|
||||
u32 *batch, size_t max_size, bool indirect);
|
||||
};
|
||||
|
||||
struct bo_setup_state {
|
||||
|
|
@ -1273,6 +1282,7 @@ struct bo_setup_state {
|
|||
struct xe_hw_engine *hwe;
|
||||
size_t max_size;
|
||||
size_t reserve_dw;
|
||||
bool indirect;
|
||||
unsigned int offset;
|
||||
const struct bo_setup *funcs;
|
||||
unsigned int num_funcs;
|
||||
|
|
@ -1298,7 +1308,8 @@ static int setup_bo(struct bo_setup_state *state)
|
|||
|
||||
for (size_t i = 0; i < state->num_funcs; i++) {
|
||||
ssize_t len = state->funcs[i].setup(state->lrc, state->hwe,
|
||||
state->ptr, remain);
|
||||
state->ptr, remain,
|
||||
state->indirect);
|
||||
|
||||
remain -= len;
|
||||
|
||||
|
|
@ -1404,6 +1415,7 @@ setup_indirect_ctx(struct xe_lrc *lrc, struct xe_hw_engine *hwe)
|
|||
struct bo_setup_state state = {
|
||||
.lrc = lrc,
|
||||
.hwe = hwe,
|
||||
.indirect = true,
|
||||
.max_size = (63 * 64) /* max 63 cachelines */,
|
||||
.buffer = NULL,
|
||||
.offset = __xe_lrc_indirect_ctx_offset(lrc),
|
||||
|
|
|
|||
|
|
@ -320,6 +320,7 @@ u64 xe_mmio_read64_2x32(struct xe_mmio *mmio, struct xe_reg reg)
|
|||
return (u64)udw << 32 | ldw;
|
||||
}
|
||||
|
||||
#define __XE_MMIO_WAIT_MAX_BACKOFF_100MS (100 * USEC_PER_MSEC)
|
||||
static int __xe_mmio_wait32(struct xe_mmio *mmio, struct xe_reg reg, u32 mask, u32 val,
|
||||
u32 timeout_us, u32 *out_val, bool atomic, bool expect_match)
|
||||
{
|
||||
|
|
@ -350,10 +351,10 @@ static int __xe_mmio_wait32(struct xe_mmio *mmio, struct xe_reg reg, u32 mask, u
|
|||
wait = ktime_us_delta(end, cur);
|
||||
|
||||
if (atomic)
|
||||
udelay(wait);
|
||||
udelay(min_t(s64, wait, (MAX_UDELAY_MS * 1000)));
|
||||
else
|
||||
usleep_range(wait, wait << 1);
|
||||
wait <<= 1;
|
||||
wait = min_t(s64, wait << 1, __XE_MMIO_WAIT_MAX_BACKOFF_100MS);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
|
|
|
|||
|
|
@ -19,20 +19,20 @@
|
|||
#include "xe_sysctrl_mailbox_types.h"
|
||||
|
||||
struct xe_sysctrl_mailbox_msg_hdr {
|
||||
__le32 data;
|
||||
} __packed;
|
||||
u32 data;
|
||||
};
|
||||
|
||||
#define XE_SYSCTRL_HDR_GROUP_ID(hdr) \
|
||||
FIELD_GET(SYSCTRL_HDR_GROUP_ID_MASK, le32_to_cpu((hdr)->data))
|
||||
FIELD_GET(SYSCTRL_HDR_GROUP_ID_MASK, (hdr)->data)
|
||||
|
||||
#define XE_SYSCTRL_HDR_COMMAND(hdr) \
|
||||
FIELD_GET(SYSCTRL_HDR_COMMAND_MASK, le32_to_cpu((hdr)->data))
|
||||
FIELD_GET(SYSCTRL_HDR_COMMAND_MASK, (hdr)->data)
|
||||
|
||||
#define XE_SYSCTRL_HDR_IS_RESPONSE(hdr) \
|
||||
FIELD_GET(SYSCTRL_HDR_IS_RESPONSE, le32_to_cpu((hdr)->data))
|
||||
FIELD_GET(SYSCTRL_HDR_IS_RESPONSE, (hdr)->data)
|
||||
|
||||
#define XE_SYSCTRL_HDR_RESULT(hdr) \
|
||||
FIELD_GET(SYSCTRL_HDR_RESULT_MASK, le32_to_cpu((hdr)->data))
|
||||
FIELD_GET(SYSCTRL_HDR_RESULT_MASK, (hdr)->data)
|
||||
|
||||
static bool sysctrl_wait_bit_clear(struct xe_sysctrl *sc, u32 bit_mask,
|
||||
unsigned int timeout_ms)
|
||||
|
|
@ -126,8 +126,8 @@ static int sysctrl_prepare_command(struct xe_device *xe,
|
|||
return -ENOMEM;
|
||||
|
||||
hdr = (struct xe_sysctrl_mailbox_msg_hdr *)buffer;
|
||||
hdr->data = cpu_to_le32(FIELD_PREP(SYSCTRL_HDR_GROUP_ID_MASK, group_id) |
|
||||
FIELD_PREP(SYSCTRL_HDR_COMMAND_MASK, command));
|
||||
hdr->data = FIELD_PREP(SYSCTRL_HDR_GROUP_ID_MASK, group_id) |
|
||||
FIELD_PREP(SYSCTRL_HDR_COMMAND_MASK, command);
|
||||
|
||||
if (data_in && data_in_len)
|
||||
memcpy(buffer + sizeof(*hdr), data_in, data_in_len);
|
||||
|
|
|
|||
|
|
@ -1003,13 +1003,14 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
|
|||
|
||||
ret = gi2c->dev_data->set_rate(&gi2c->se, gi2c->clk_freq_out);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out_pm;
|
||||
|
||||
if (gi2c->gpi_mode)
|
||||
ret = geni_i2c_gpi_xfer(gi2c, msgs, num);
|
||||
else
|
||||
ret = geni_i2c_fifo_xfer(gi2c, msgs, num);
|
||||
|
||||
out_pm:
|
||||
pm_runtime_put_autosuspend(gi2c->se.dev);
|
||||
gi2c->cur = NULL;
|
||||
gi2c->err = 0;
|
||||
|
|
|
|||
|
|
@ -302,6 +302,8 @@ static const struct xpad_device {
|
|||
{ 0x17ef, 0x6182, "Lenovo Legion Controller for Windows", 0, XTYPE_XBOX360 },
|
||||
{ 0x1949, 0x041a, "Amazon Game Controller", 0, XTYPE_XBOX360 },
|
||||
{ 0x1a86, 0xe310, "Legion Go S", 0, XTYPE_XBOX360 },
|
||||
{ 0x1b1c, 0x2b1f, "Corsair Novablade Pro (Wired)", 0, XTYPE_XBOX360 },
|
||||
{ 0x1b1c, 0x2b2b, "Corsair Novablade Pro (2.4 GHz Receiver)", 0, XTYPE_XBOX360 },
|
||||
{ 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
|
||||
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0x1bad, 0x0130, "Ion Drum Rocker", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
|
|
@ -379,6 +381,7 @@ static const struct xpad_device {
|
|||
{ 0x2993, 0x2001, "TECNO Pocket Go", 0, XTYPE_XBOX360 },
|
||||
{ 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE },
|
||||
{ 0x2dc8, 0x200f, "8BitDo Ultimate 3-mode Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
|
||||
{ 0x2dc8, 0x201e, "8BitDo Pro 2 Wired Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
|
||||
{ 0x2dc8, 0x3106, "8BitDo Ultimate Wireless / Pro 2 Wired Controller", 0, XTYPE_XBOX360 },
|
||||
{ 0x2dc8, 0x3109, "8BitDo Ultimate Wireless Bluetooth", 0, XTYPE_XBOX360 },
|
||||
{ 0x2dc8, 0x310a, "8BitDo Ultimate 2C Wireless Controller", 0, XTYPE_XBOX360 },
|
||||
|
|
@ -545,6 +548,7 @@ static const struct usb_device_id xpad_table[] = {
|
|||
XPAD_XBOX360_VENDOR(0x17ef), /* Lenovo */
|
||||
XPAD_XBOX360_VENDOR(0x1949), /* Amazon controllers */
|
||||
XPAD_XBOX360_VENDOR(0x1a86), /* Nanjing Qinheng Microelectronics (WCH) */
|
||||
XPAD_XBOX360_VENDOR(0x1b1c), /* Corsair controllers */
|
||||
XPAD_XBOX360_VENDOR(0x1bad), /* Harmonix Rock Band guitar and drums */
|
||||
XPAD_XBOX360_VENDOR(0x1ee9), /* ZOTAC Technology Limited */
|
||||
XPAD_XBOX360_VENDOR(0x20bc), /* BETOP wireless dongles */
|
||||
|
|
|
|||
|
|
@ -672,8 +672,7 @@ static ssize_t ati_remote2_show_channel_mask(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
|
||||
|
||||
return sprintf(buf, "0x%04x\n", ar2->channel_mask);
|
||||
|
|
@ -683,8 +682,7 @@ static ssize_t ati_remote2_store_channel_mask(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
|
||||
unsigned int mask;
|
||||
int r;
|
||||
|
|
@ -720,8 +718,7 @@ static ssize_t ati_remote2_show_mode_mask(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
|
||||
|
||||
return sprintf(buf, "0x%02x\n", ar2->mode_mask);
|
||||
|
|
@ -731,8 +728,7 @@ static ssize_t ati_remote2_store_mode_mask(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
|
||||
unsigned int mask;
|
||||
int err;
|
||||
|
|
|
|||
|
|
@ -1228,9 +1228,9 @@ dma_addr_t iommu_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
|
|||
* If both the physical buffer start address and size are page aligned,
|
||||
* we don't need to use a bounce page.
|
||||
*/
|
||||
if (dev_use_swiotlb(dev, size, dir) &&
|
||||
if (!(attrs & DMA_ATTR_MMIO) && dev_use_swiotlb(dev, size, dir) &&
|
||||
iova_unaligned(iovad, phys, size)) {
|
||||
if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))
|
||||
if (attrs & DMA_ATTR_REQUIRE_COHERENT)
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
phys = iommu_dma_map_swiotlb(dev, phys, size, dir, attrs);
|
||||
|
|
|
|||
|
|
@ -2894,8 +2894,13 @@ static int crypt_ctr_cipher_new(struct dm_target *ti, char *cipher_in, char *key
|
|||
}
|
||||
}
|
||||
|
||||
if (*ivmode && !strcmp(*ivmode, "lmk"))
|
||||
if (*ivmode && !strcmp(*ivmode, "lmk")) {
|
||||
if (crypt_integrity_aead(cc)) {
|
||||
ti->error = "AEAD transforms not supported for LMK";
|
||||
return -EINVAL;
|
||||
}
|
||||
cc->tfms_count = 64;
|
||||
}
|
||||
|
||||
if (*ivmode && !strcmp(*ivmode, "essiv")) {
|
||||
if (!*ivopts) {
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ struct dm_integrity_c {
|
|||
struct dm_bufio_client *bufio;
|
||||
struct workqueue_struct *metadata_wq;
|
||||
struct superblock *sb;
|
||||
struct superblock *sb_copy;
|
||||
unsigned int journal_pages;
|
||||
unsigned int n_bitmap_blocks;
|
||||
|
||||
|
|
@ -2721,7 +2722,7 @@ static void dm_integrity_inline_recheck(struct work_struct *w)
|
|||
outgoing_data = dio->integrity_payload + PAGE_SIZE;
|
||||
|
||||
while (dio->bio_details.bi_iter.bi_size) {
|
||||
char digest[HASH_MAX_DIGESTSIZE];
|
||||
char digest[MAX_T(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
|
||||
int r;
|
||||
struct bio_integrity_payload *bip;
|
||||
struct bio_vec bv;
|
||||
|
|
@ -2788,7 +2789,7 @@ static inline bool dm_integrity_check(struct dm_integrity_c *ic, struct dm_integ
|
|||
unsigned pos = 0;
|
||||
|
||||
while (dio->bio_details.bi_iter.bi_size) {
|
||||
char digest[HASH_MAX_DIGESTSIZE];
|
||||
char digest[MAX_T(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
|
||||
struct bio_vec bv = bio_iter_iovec(bio, dio->bio_details.bi_iter);
|
||||
char *mem = integrity_kmap(ic, bv.bv_page);
|
||||
integrity_sector_checksum(ic, &dio->ahash_req, dio->bio_details.bi_iter.bi_sector, mem, bv.bv_offset, digest);
|
||||
|
|
@ -3858,6 +3859,35 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
|
|||
ic->journal_uptodate = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The superblock is re-read from the device on every resume, so that we pick
|
||||
* up the flags and the recalculate position. The geometry described by the
|
||||
* superblock must not change though - the in-memory structures (and the
|
||||
* journal in particular) were sized according to the superblock that was
|
||||
* validated in the constructor. Reject a superblock that was modified behind
|
||||
* our back.
|
||||
*
|
||||
* Only the fields that the driver never rewrites may be tested here. In
|
||||
* particular, "version" is recalculated by sb_set_version on every superblock
|
||||
* write and it depends on SB_FLAG_RECALCULATING and SB_FLAG_DIRTY_BITMAP, and
|
||||
* SB_FLAG_DISCARD_KEYED may be set by dm_integrity_resume itself.
|
||||
*/
|
||||
static bool superblock_changed(struct dm_integrity_c *ic)
|
||||
{
|
||||
const __le32 immutable_flags = cpu_to_le32(SB_FLAG_HAVE_JOURNAL_MAC |
|
||||
SB_FLAG_FIXED_PADDING |
|
||||
SB_FLAG_FIXED_HMAC |
|
||||
SB_FLAG_INLINE);
|
||||
|
||||
return memcmp(ic->sb->magic, ic->sb_copy->magic, sizeof(ic->sb->magic)) != 0 ||
|
||||
ic->sb->log2_interleave_sectors != ic->sb_copy->log2_interleave_sectors ||
|
||||
ic->sb->integrity_tag_size != ic->sb_copy->integrity_tag_size ||
|
||||
ic->sb->journal_sections != ic->sb_copy->journal_sections ||
|
||||
ic->sb->log2_sectors_per_block != ic->sb_copy->log2_sectors_per_block ||
|
||||
((ic->sb->flags ^ ic->sb_copy->flags) & immutable_flags) != 0 ||
|
||||
memcmp(ic->sb->salt, ic->sb_copy->salt, SALT_SIZE) != 0;
|
||||
}
|
||||
|
||||
static void dm_integrity_resume(struct dm_target *ti)
|
||||
{
|
||||
struct dm_integrity_c *ic = ti->private;
|
||||
|
|
@ -3876,6 +3906,18 @@ static void dm_integrity_resume(struct dm_target *ti)
|
|||
if (r)
|
||||
dm_integrity_io_error(ic, "reading superblock", r);
|
||||
|
||||
if (unlikely(superblock_changed(ic))) {
|
||||
/*
|
||||
* Restore the superblock that we validated in the constructor,
|
||||
* so that the rest of the driver doesn't operate on values
|
||||
* that don't match the in-memory structures.
|
||||
*/
|
||||
memcpy(ic->sb, ic->sb_copy, sizeof(struct superblock));
|
||||
DMERR("The superblock was changed while the device was suspended");
|
||||
dm_integrity_io_error(ic, "superblock check", -EINVAL);
|
||||
goto skip_writes;
|
||||
}
|
||||
|
||||
if (ic->mode == 'R')
|
||||
goto skip_writes;
|
||||
|
||||
|
|
@ -5427,6 +5469,13 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
|
|||
ic->just_formatted = true;
|
||||
}
|
||||
|
||||
ic->sb_copy = kmemdup(ic->sb, sizeof(struct superblock), GFP_KERNEL);
|
||||
if (!ic->sb_copy) {
|
||||
ti->error = "Cannot allocate superblock copy";
|
||||
r = -ENOMEM;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!ic->meta_dev && ic->mode != 'I') {
|
||||
r = dm_set_target_max_io_len(ti, 1U << ic->sb->log2_interleave_sectors);
|
||||
if (r)
|
||||
|
|
@ -5525,6 +5574,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
|
|||
kvfree(ic->journal_tree);
|
||||
if (ic->sb)
|
||||
free_pages_exact(ic->sb, SB_SECTORS << SECTOR_SHIFT);
|
||||
kfree(ic->sb_copy);
|
||||
|
||||
if (ic->internal_shash)
|
||||
crypto_free_shash(ic->internal_shash);
|
||||
|
|
|
|||
|
|
@ -656,10 +656,16 @@ static void *get_result_buffer(struct dm_ioctl *param, size_t param_size,
|
|||
{
|
||||
param->data_start = align_ptr(param + 1) - (void *) param;
|
||||
|
||||
if (param->data_start < param_size)
|
||||
if (param->data_start < param_size) {
|
||||
*len = param_size - param->data_start;
|
||||
else
|
||||
} else {
|
||||
/*
|
||||
* The buffer can be as small as offsetof(*param, data), which
|
||||
* is less than sizeof(*param), so don't run off the end of it.
|
||||
*/
|
||||
*len = 0;
|
||||
param->data_start = param_size;
|
||||
}
|
||||
|
||||
return ((void *) param) + param->data_start;
|
||||
}
|
||||
|
|
@ -1267,6 +1273,7 @@ static int do_resume(struct dm_ioctl *param)
|
|||
/* Do we need to load a new map ? */
|
||||
if (new_map) {
|
||||
sector_t old_size, new_size;
|
||||
blk_mode_t new_map_mode;
|
||||
|
||||
dm_ima_context_table_op(md, ima_context, DM_IMA_TABLE_SAVE);
|
||||
/* Suspend if it isn't already suspended */
|
||||
|
|
@ -1299,6 +1306,7 @@ static int do_resume(struct dm_ioctl *param)
|
|||
}
|
||||
}
|
||||
|
||||
new_map_mode = dm_table_get_mode(new_map);
|
||||
old_size = dm_get_size(md);
|
||||
old_map = dm_swap_table(md, new_map);
|
||||
if (IS_ERR(old_map)) {
|
||||
|
|
@ -1314,7 +1322,7 @@ static int do_resume(struct dm_ioctl *param)
|
|||
if (old_size && new_size && old_size != new_size)
|
||||
need_resize_uevent = true;
|
||||
|
||||
if (dm_table_get_mode(new_map) & BLK_OPEN_WRITE)
|
||||
if (new_map_mode & BLK_OPEN_WRITE)
|
||||
set_disk_ro(dm_disk(md), 0);
|
||||
else
|
||||
set_disk_ro(dm_disk(md), 1);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user