mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Cross-merge networking fixes after downstream PR (net-7.3-rc8). No conflicts. Adjacent changes: drivers/net/ethernet/microchip/lan865x/lan865x.c2a3f6d2a9a("microchip: lan865x: move setting of netops to fix crash")15358c2c3d("net: ethernet: oa_tc6: return ERR_PTR from oa_tc6_init()") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
f5e575a787
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -8172,7 +8172,6 @@ F: drivers/gpu/drm/tiny/hx8357d.c
|
|||
|
||||
DRM DRIVER FOR HYPERV SYNTHETIC VIDEO DEVICE
|
||||
M: Dexuan Cui <decui@microsoft.com>
|
||||
M: Long Li <longli@microsoft.com>
|
||||
M: Saurabh Sengar <ssengar@linux.microsoft.com>
|
||||
L: linux-hyperv@vger.kernel.org
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
|
|
@ -12163,11 +12162,9 @@ S: Maintained
|
|||
F: drivers/media/i2c/hi847.c
|
||||
|
||||
Hyper-V/Azure CORE AND DRIVERS
|
||||
M: "K. Y. Srinivasan" <kys@microsoft.com>
|
||||
M: Haiyang Zhang <haiyangz@microsoft.com>
|
||||
M: Wei Liu <wei.liu@kernel.org>
|
||||
M: Dexuan Cui <decui@microsoft.com>
|
||||
M: Long Li <longli@microsoft.com>
|
||||
L: linux-hyperv@vger.kernel.org
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
|
||||
|
|
@ -18831,6 +18828,7 @@ F: drivers/net/ethernet/nebula-matrix/
|
|||
|
||||
NETCONSOLE
|
||||
M: Breno Leitao <leitao@debian.org>
|
||||
R: Gustavo Luiz Duarte <gustavold@gmail.com>
|
||||
S: Maintained
|
||||
F: Documentation/networking/netconsole.rst
|
||||
F: drivers/net/netconsole.c
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
VERSION = 7
|
||||
PATCHLEVEL = 3
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc6
|
||||
EXTRAVERSION = -rc7
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ static inline __sum16 csum_fold(__wsum sum)
|
|||
"add %0, %0, r8\n"
|
||||
"nor %0, %0, %0\n"
|
||||
: "=r" (sum)
|
||||
: "r" (sum << 16), "0" (sum)
|
||||
: "r" ((__force u32)sum << 16), "0" (sum)
|
||||
: "r8");
|
||||
return (__force __sum16) sum;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -426,7 +426,7 @@ static void __init hv_stimer_setup_percpu_clockev(void)
|
|||
int ret;
|
||||
|
||||
/*
|
||||
* Continue afters errors in setting up stimer clockevents
|
||||
* Continue after errors in setting up stimer clockevents
|
||||
* as we can run with the LAPIC timer as a fallback.
|
||||
*/
|
||||
ret = hv_stimer_alloc(false);
|
||||
|
|
@ -434,7 +434,7 @@ static void __init hv_stimer_setup_percpu_clockev(void)
|
|||
pr_warn("stimer setup failed with error %d\n", ret);
|
||||
|
||||
/*
|
||||
* Still register the LAPIC timer to allows users
|
||||
* Still register the LAPIC timer to allow users
|
||||
* to switch to LAPIC timer via /sys, if they want to.
|
||||
*/
|
||||
if (old_setup_percpu_clockev)
|
||||
|
|
@ -727,7 +727,8 @@ int hv_apicid_to_vp_index(u32 apic_id)
|
|||
input->partition_id = HV_PARTITION_ID_SELF;
|
||||
input->apic_ids[0] = apic_id;
|
||||
|
||||
output = *this_cpu_ptr(hyperv_pcpu_output_arg);
|
||||
/* Treat input as having 2 APIC IDs so output is 64-bit aligned */
|
||||
output = (void *)input + struct_size(input, apic_ids, 2);
|
||||
|
||||
control = HV_HYPERCALL_REP_COMP_1 | HVCALL_GET_VP_INDEX_FROM_APIC_ID;
|
||||
status = hv_do_hypercall(control, input, output);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -265,11 +265,39 @@ noinstr u32 kvm_read_and_reset_apf_flags(void)
|
|||
}
|
||||
EXPORT_SYMBOL_FOR_KVM(kvm_read_and_reset_apf_flags);
|
||||
|
||||
static __always_inline bool kvm_apf_reason_pending(void)
|
||||
{
|
||||
return __this_cpu_read(async_pf_enabled) &&
|
||||
__this_cpu_read(apf_reason.flags);
|
||||
}
|
||||
|
||||
noinstr bool __kvm_handle_async_pf(struct pt_regs *regs, u32 token)
|
||||
{
|
||||
u32 flags = kvm_read_and_reset_apf_flags();
|
||||
irqentry_state_t state;
|
||||
u32 flags;
|
||||
|
||||
if (!kvm_apf_reason_pending())
|
||||
return false;
|
||||
|
||||
/*
|
||||
* The guest does not enable KVM_ASYNC_PF_SEND_ALWAYS, so the host
|
||||
* delivers async #PF only to user mode (or as a #PF VM-exit, which KVM
|
||||
* reads itself). A #PF from kernel mode can still arrive between that
|
||||
* delivery and the read of the reason flags, inside an NMI that
|
||||
* interrupted it, for instance perf reading user memory for a call
|
||||
* chain. Such a fault is not async, so leave the async PF flags
|
||||
* untouched for the outer handler. Outside NMI context, on the other
|
||||
* hand, async PF flags on a kernel-mode fault mean the host is broken.
|
||||
*/
|
||||
if (!user_mode(regs)) {
|
||||
if (likely(in_nmi()))
|
||||
return false;
|
||||
state = irqentry_enter(regs);
|
||||
instrumentation_begin();
|
||||
panic("Host injected async #PF in kernel mode\n");
|
||||
}
|
||||
|
||||
flags = kvm_read_and_reset_apf_flags();
|
||||
if (!flags)
|
||||
return false;
|
||||
|
||||
|
|
@ -285,8 +313,6 @@ noinstr bool __kvm_handle_async_pf(struct pt_regs *regs, u32 token)
|
|||
panic("Host injected async #PF in interrupt disabled region\n");
|
||||
|
||||
if (flags & KVM_PV_REASON_PAGE_NOT_PRESENT) {
|
||||
if (unlikely(!(user_mode(regs))))
|
||||
panic("Host injected async #PF in kernel mode\n");
|
||||
/* Page is swapped out by the host. */
|
||||
kvm_async_pf_task_wait_schedule(token);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -275,8 +275,18 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_pagewalk *w,
|
|||
unsigned pte_access, unsigned pte_pkey,
|
||||
u64 access)
|
||||
{
|
||||
/* strip nested paging fault error codes */
|
||||
unsigned int pfec = access;
|
||||
/*
|
||||
* Of the error codes that do not contribute to the index in
|
||||
* fmt->permissions, PK and SS are not supported by shadow paging
|
||||
* and also not provided to EPT violations, but SS *is* included
|
||||
* in the NPT exit code. RSVD faults are handled elsewhere.
|
||||
*/
|
||||
unsigned int pfec = access & ~PFERR_SS_MASK;
|
||||
if (WARN_ON_ONCE(pfec & ~(PFERR_PRESENT_MASK | PFERR_WRITE_MASK |
|
||||
PFERR_USER_MASK | PFERR_FETCH_MASK)))
|
||||
pfec &= (PFERR_PRESENT_MASK | PFERR_WRITE_MASK |
|
||||
PFERR_USER_MASK | PFERR_FETCH_MASK);
|
||||
|
||||
unsigned long rflags = kvm_x86_call(get_rflags)(vcpu);
|
||||
|
||||
/*
|
||||
|
|
@ -301,8 +311,6 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_pagewalk *w,
|
|||
kvm_mmu_refresh_passthrough_bits(vcpu, w);
|
||||
|
||||
fault = (fmt->permissions[index] >> pte_access) & 1;
|
||||
|
||||
WARN_ON_ONCE(pfec & (PFERR_PK_MASK | PFERR_SS_MASK | PFERR_RSVD_MASK));
|
||||
if (unlikely(fmt->pkru_mask)) {
|
||||
u32 pkru_bits, offset;
|
||||
|
||||
|
|
|
|||
|
|
@ -328,7 +328,6 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
|
|||
int offset;
|
||||
u64 walk_nx_mask = 0;
|
||||
const int write_fault = access & PFERR_WRITE_MASK;
|
||||
const int user_fault = access & PFERR_USER_MASK;
|
||||
const int fetch_fault = access & PFERR_FETCH_MASK;
|
||||
/*
|
||||
* Note! Track the error_code that's common to legacy shadow paging
|
||||
|
|
@ -486,7 +485,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
|
|||
return 1;
|
||||
|
||||
error:
|
||||
errcode |= write_fault | user_fault;
|
||||
errcode |= access & (PFERR_WRITE_MASK | PFERR_USER_MASK | PFERR_SS_MASK);
|
||||
if (fetch_fault && has_pferr_fetch(w))
|
||||
errcode |= PFERR_FETCH_MASK;
|
||||
|
||||
|
|
|
|||
|
|
@ -395,6 +395,11 @@ static phys_addr_t avic_get_backing_page_address(struct vcpu_svm *svm)
|
|||
return __sme_set(__pa(svm->vcpu.arch.apic->regs));
|
||||
}
|
||||
|
||||
static bool avic_is_addressable_vcpu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return vcpu->vcpu_id <= __avic_get_max_physical_id(vcpu->kvm, NULL);
|
||||
}
|
||||
|
||||
void avic_init_vmcb(struct vcpu_svm *svm, struct vmcb *vmcb)
|
||||
{
|
||||
struct kvm_svm *kvm_svm = to_kvm_svm(svm->vcpu.kvm);
|
||||
|
|
@ -412,7 +417,6 @@ void avic_init_vmcb(struct vcpu_svm *svm, struct vmcb *vmcb)
|
|||
|
||||
static int avic_init_backing_page(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u32 max_id = x2avic_enabled ? x2avic_max_physical_id : AVIC_MAX_PHYSICAL_ID;
|
||||
struct kvm_svm *kvm_svm = to_kvm_svm(vcpu->kvm);
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
u32 id = vcpu->vcpu_id;
|
||||
|
|
@ -425,7 +429,7 @@ static int avic_init_backing_page(struct kvm_vcpu *vcpu)
|
|||
* avic_vcpu_load() expects to be called if and only if the vCPU has
|
||||
* fully initialized AVIC.
|
||||
*/
|
||||
if (id > max_id) {
|
||||
if (!avic_is_addressable_vcpu(vcpu)) {
|
||||
kvm_set_apicv_inhibit(vcpu->kvm, APICV_INHIBIT_REASON_PHYSICAL_ID_TOO_BIG);
|
||||
vcpu->arch.apic->apicv_active = false;
|
||||
return 0;
|
||||
|
|
@ -885,6 +889,14 @@ int avic_init_vcpu(struct vcpu_svm *svm)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void avic_vcpu_free(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_svm *kvm_svm = to_kvm_svm(vcpu->kvm);
|
||||
|
||||
if (kvm_svm->avic_physical_id_table && avic_is_addressable_vcpu(vcpu))
|
||||
WRITE_ONCE(kvm_svm->avic_physical_id_table[vcpu->vcpu_id], 0);
|
||||
}
|
||||
|
||||
void avic_apicv_post_state_restore(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
avic_handle_dfr_update(vcpu);
|
||||
|
|
@ -1045,8 +1057,7 @@ static void __avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu,
|
|||
if (WARN_ON(h_physical_id & ~AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK))
|
||||
return;
|
||||
|
||||
if (WARN_ON_ONCE(vcpu->vcpu_id * sizeof(entry) >=
|
||||
PAGE_SIZE << avic_get_physical_id_table_order(vcpu->kvm)))
|
||||
if (WARN_ON_ONCE(!avic_is_addressable_vcpu(vcpu)))
|
||||
return;
|
||||
|
||||
/*
|
||||
|
|
@ -1108,8 +1119,7 @@ static void __avic_vcpu_put(struct kvm_vcpu *vcpu, enum avic_vcpu_action action)
|
|||
|
||||
lockdep_assert_preemption_disabled();
|
||||
|
||||
if (WARN_ON_ONCE(vcpu->vcpu_id * sizeof(entry) >=
|
||||
PAGE_SIZE << avic_get_physical_id_table_order(vcpu->kvm)))
|
||||
if (WARN_ON_ONCE(!avic_is_addressable_vcpu(vcpu)))
|
||||
return;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -2421,7 +2421,7 @@ static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
|
|||
void *dst_vaddr = kmap_local_pfn(pfn);
|
||||
|
||||
memcpy(src_vaddr, dst_vaddr, PAGE_SIZE);
|
||||
set_page_dirty(src_page);
|
||||
set_page_dirty_lock(src_page);
|
||||
|
||||
kunmap_local(dst_vaddr);
|
||||
kunmap_local(src_vaddr);
|
||||
|
|
|
|||
|
|
@ -1328,7 +1328,7 @@ static int svm_vcpu_create(struct kvm_vcpu *vcpu)
|
|||
svm->msrpm = svm_vcpu_alloc_msrpm();
|
||||
if (!svm->msrpm) {
|
||||
err = -ENOMEM;
|
||||
goto error_free_sev;
|
||||
goto error_free_avic;
|
||||
}
|
||||
|
||||
svm->x2avic_msrs_intercepted = true;
|
||||
|
|
@ -1342,6 +1342,8 @@ static int svm_vcpu_create(struct kvm_vcpu *vcpu)
|
|||
|
||||
return 0;
|
||||
|
||||
error_free_avic:
|
||||
avic_vcpu_free(vcpu);
|
||||
error_free_sev:
|
||||
sev_free_vcpu(vcpu);
|
||||
error_free_vmcb_page:
|
||||
|
|
@ -1356,6 +1358,8 @@ static void svm_vcpu_free(struct kvm_vcpu *vcpu)
|
|||
|
||||
WARN_ON_ONCE(!list_empty(&svm->ir_list));
|
||||
|
||||
avic_vcpu_free(vcpu);
|
||||
|
||||
svm_leave_nested(vcpu);
|
||||
svm_free_nested(svm);
|
||||
|
||||
|
|
|
|||
|
|
@ -955,6 +955,7 @@ void avic_init_vmcb(struct vcpu_svm *svm, struct vmcb *vmcb);
|
|||
int avic_incomplete_ipi_interception(struct kvm_vcpu *vcpu);
|
||||
int avic_unaccelerated_access_interception(struct kvm_vcpu *vcpu);
|
||||
int avic_init_vcpu(struct vcpu_svm *svm);
|
||||
void avic_vcpu_free(struct kvm_vcpu *vcpu);
|
||||
void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
|
||||
void avic_vcpu_put(struct kvm_vcpu *vcpu);
|
||||
void avic_apicv_post_state_restore(struct kvm_vcpu *vcpu);
|
||||
|
|
|
|||
|
|
@ -3770,8 +3770,10 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
|
|||
vmentry_fail_vmexit:
|
||||
vmx_switch_vmcs(vcpu, &vmx->vmcs01);
|
||||
|
||||
if (!from_vmentry)
|
||||
if (!from_vmentry) {
|
||||
nested_ept_uninit_mmu_context(vcpu);
|
||||
return NVMX_VMENTRY_VMEXIT;
|
||||
}
|
||||
|
||||
nested_put_vmcs12_pages(vcpu);
|
||||
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ static inline bool is_noncanonical_invlpg_address(u64 la, struct kvm_vcpu *vcpu)
|
|||
static inline void vcpu_cache_mmio_info(struct kvm_vcpu *vcpu,
|
||||
gva_t gva, gfn_t gfn, unsigned access)
|
||||
{
|
||||
u64 gen = kvm_memslots(vcpu->kvm)->generation;
|
||||
u64 gen = kvm_vcpu_memslots(vcpu)->generation;
|
||||
|
||||
if (unlikely(gen & KVM_MEMSLOT_GEN_UPDATE_IN_PROGRESS))
|
||||
return;
|
||||
|
|
@ -267,7 +267,7 @@ static inline void vcpu_cache_mmio_info(struct kvm_vcpu *vcpu,
|
|||
|
||||
static inline bool vcpu_match_mmio_gen(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return vcpu->arch.mmio_gen == kvm_memslots(vcpu->kvm)->generation;
|
||||
return vcpu->arch.mmio_gen == kvm_vcpu_memslots(vcpu)->generation;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ static inline u32 hv_ring_gpadl_send_hvpgoffset(u32 offset)
|
|||
* therefore leaving a (PAGE_SIZE - HV_HYP_PAGE_SIZE) gap.
|
||||
*
|
||||
* And to calculate the effective send offset in gpadl, we need to
|
||||
* substract this gap.
|
||||
* subtract this gap.
|
||||
*/
|
||||
return (offset - (PAGE_SIZE - HV_HYP_PAGE_SIZE)) >> HV_HYP_PAGE_SHIFT;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -752,13 +752,14 @@ static void init_vp_index(struct vmbus_channel *channel)
|
|||
u32 i, ncpu = num_online_cpus();
|
||||
cpumask_var_t available_mask;
|
||||
struct cpumask *allocated_mask;
|
||||
const struct cpumask *node_mask;
|
||||
const struct cpumask *hk_mask = housekeeping_cpumask(HK_TYPE_MANAGED_IRQ);
|
||||
u32 target_cpu;
|
||||
int numa_node;
|
||||
|
||||
if (!perf_chn ||
|
||||
!alloc_cpumask_var(&available_mask, GFP_KERNEL) ||
|
||||
cpumask_empty(hk_mask)) {
|
||||
!cpumask_intersects(hk_mask, cpu_online_mask)) {
|
||||
/*
|
||||
* If the channel is not a performance critical
|
||||
* channel, bind it to VMBUS_CONNECT_CPU.
|
||||
|
|
@ -780,14 +781,19 @@ static void init_vp_index(struct vmbus_channel *channel)
|
|||
next_numa_node_id = 0;
|
||||
continue;
|
||||
}
|
||||
if (cpumask_empty(cpumask_of_node(numa_node)))
|
||||
/*
|
||||
* Try next NUMA node if current NUMA node has no CPU
|
||||
* or doesn't contain any housekeeping CPU.
|
||||
*/
|
||||
node_mask = cpumask_of_node(numa_node);
|
||||
if (!cpumask_intersects(node_mask, hk_mask))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
allocated_mask = &hv_context.hv_numa_map[numa_node];
|
||||
|
||||
retry:
|
||||
cpumask_xor(available_mask, allocated_mask, cpumask_of_node(numa_node));
|
||||
cpumask_xor(available_mask, allocated_mask, node_mask);
|
||||
cpumask_and(available_mask, available_mask, hk_mask);
|
||||
|
||||
if (cpumask_empty(available_mask)) {
|
||||
|
|
|
|||
|
|
@ -346,7 +346,6 @@ int vmbus_connect(void)
|
|||
cleanup:
|
||||
pr_err("Unable to connect to host\n");
|
||||
|
||||
vmbus_connection.conn_state = DISCONNECTED;
|
||||
vmbus_disconnect();
|
||||
|
||||
kfree(msginfo);
|
||||
|
|
|
|||
|
|
@ -819,6 +819,9 @@ static vm_fault_t mshv_vtl_fault(struct vm_fault *vmf)
|
|||
return VM_FAULT_NOPAGE;
|
||||
}
|
||||
|
||||
if (!page)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
get_page(page);
|
||||
vmf->page = page;
|
||||
|
||||
|
|
|
|||
|
|
@ -2923,23 +2923,19 @@ static void hv_crash_handler(struct pt_regs *regs)
|
|||
static int hv_synic_suspend(void *data)
|
||||
{
|
||||
/*
|
||||
* When we reach here, all the non-boot CPUs have been offlined.
|
||||
* If we're in a legacy configuration where stimer Direct Mode is
|
||||
* not enabled, the stimers on the non-boot CPUs have been unbound
|
||||
* in hv_synic_cleanup() -> hv_stimer_legacy_cleanup() ->
|
||||
* hv_stimer_cleanup() -> clockevents_unbind_device().
|
||||
* When we reach here, all the non-boot CPUs have been offlined,
|
||||
* and their stimers have been cleaned up by the cpuhp teardown
|
||||
* callback hv_stimer_cleanup().
|
||||
*
|
||||
* hv_synic_suspend() only runs on CPU0 with interrupts disabled.
|
||||
* Here we do not call hv_stimer_legacy_cleanup() on CPU0 because:
|
||||
* 1) it's unnecessary as interrupts remain disabled between
|
||||
* syscore_suspend() and syscore_resume(): see create_image() and
|
||||
* The stimer on CPU0 is not explicitly cleaned up here because:
|
||||
* 1) it's harmless as interrupts remain disabled between
|
||||
* syscore_suspend() and syscore_resume(), so the stimer cannot
|
||||
* fire during this window: see create_image() and
|
||||
* resume_target_kernel()
|
||||
* 2) the stimer on CPU0 is automatically disabled later by
|
||||
* syscore_suspend() -> timekeeping_suspend() -> tick_suspend() -> ...
|
||||
* -> clockevents_shutdown() -> ... -> hv_ce_shutdown()
|
||||
* 3) a warning would be triggered if we call
|
||||
* clockevents_unbind_device(), which may sleep, in an
|
||||
* interrupts-disabled context.
|
||||
*/
|
||||
|
||||
hv_hyp_synic_disable_regs(0);
|
||||
|
|
@ -3043,7 +3039,6 @@ static void __exit vmbus_exit(void)
|
|||
|
||||
hv_remove_kexec_handler();
|
||||
hv_remove_crash_handler();
|
||||
vmbus_connection.conn_state = DISCONNECTED;
|
||||
hv_stimer_global_cleanup();
|
||||
vmbus_disconnect();
|
||||
if (vmbus_irq == -1)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -2416,7 +2416,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
|
|||
if (video_is_registered(&v4l2->radio_dev)) {
|
||||
dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n",
|
||||
video_device_node_name(&v4l2->radio_dev));
|
||||
vb2_video_unregister_device(&v4l2->radio_dev);
|
||||
video_unregister_device(&v4l2->radio_dev);
|
||||
}
|
||||
if (video_is_registered(&v4l2->vbi_dev)) {
|
||||
dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n",
|
||||
|
|
@ -3082,7 +3082,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
|
|||
dev_info(&dev->intf->dev,
|
||||
"V4L2 device %s deregistered\n",
|
||||
video_device_node_name(&v4l2->radio_dev));
|
||||
vb2_video_unregister_device(&v4l2->radio_dev);
|
||||
video_unregister_device(&v4l2->radio_dev);
|
||||
}
|
||||
if (video_is_registered(&v4l2->vbi_dev)) {
|
||||
dev_info(&dev->intf->dev,
|
||||
|
|
|
|||
|
|
@ -370,9 +370,7 @@ int memstick_set_rw_addr(struct memstick_dev *card)
|
|||
{
|
||||
card->next_request = h_memstick_set_rw_addr;
|
||||
memstick_new_req(card->host);
|
||||
if (!wait_for_completion_timeout(&card->mrq_complete,
|
||||
msecs_to_jiffies(500)))
|
||||
card->current_mrq.error = -ETIMEDOUT;
|
||||
wait_for_completion(&card->mrq_complete);
|
||||
|
||||
return card->current_mrq.error;
|
||||
}
|
||||
|
|
@ -405,9 +403,7 @@ static struct memstick_dev *memstick_alloc_card(struct memstick_host *host)
|
|||
|
||||
card->next_request = h_memstick_read_dev_id;
|
||||
memstick_new_req(host);
|
||||
if (!wait_for_completion_timeout(&card->mrq_complete,
|
||||
msecs_to_jiffies(500)))
|
||||
card->current_mrq.error = -ETIMEDOUT;
|
||||
wait_for_completion(&card->mrq_complete);
|
||||
|
||||
if (card->current_mrq.error)
|
||||
goto err_out;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ struct rtsx_usb_ms {
|
|||
struct memstick_host *msh;
|
||||
struct memstick_request *req;
|
||||
|
||||
struct mutex host_mutex;
|
||||
struct work_struct handle_req;
|
||||
struct delayed_work poll_card;
|
||||
|
||||
|
|
@ -514,6 +513,13 @@ static void rtsx_usb_ms_handle_req(struct work_struct *work)
|
|||
struct memstick_host *msh = host->msh;
|
||||
int rc;
|
||||
|
||||
/* Fail requests after eject so their waiters are released. */
|
||||
if (host->eject) {
|
||||
while (!memstick_next_req(msh, &host->req))
|
||||
host->req->error = -ENOMEDIUM;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!host->req) {
|
||||
pm_runtime_get_sync(ms_dev(host));
|
||||
do {
|
||||
|
|
@ -547,8 +553,7 @@ static void rtsx_usb_ms_request(struct memstick_host *msh)
|
|||
|
||||
dev_dbg(ms_dev(host), "--> %s\n", __func__);
|
||||
|
||||
if (!host->eject)
|
||||
schedule_work(&host->handle_req);
|
||||
schedule_work(&host->handle_req);
|
||||
}
|
||||
|
||||
static int rtsx_usb_ms_set_param(struct memstick_host *msh,
|
||||
|
|
@ -781,7 +786,6 @@ static int rtsx_usb_ms_drv_probe(struct platform_device *pdev)
|
|||
host->power_mode = MEMSTICK_POWER_OFF;
|
||||
platform_set_drvdata(pdev, host);
|
||||
|
||||
mutex_init(&host->host_mutex);
|
||||
INIT_WORK(&host->handle_req, rtsx_usb_ms_handle_req);
|
||||
|
||||
INIT_DELAYED_WORK(&host->poll_card, rtsx_usb_ms_poll_card);
|
||||
|
|
@ -812,27 +816,12 @@ static void rtsx_usb_ms_drv_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct rtsx_usb_ms *host = platform_get_drvdata(pdev);
|
||||
struct memstick_host *msh = host->msh;
|
||||
int err;
|
||||
|
||||
host->eject = true;
|
||||
msh->removing = true;
|
||||
cancel_work_sync(&host->handle_req);
|
||||
flush_work(&host->handle_req);
|
||||
cancel_delayed_work_sync(&host->poll_card);
|
||||
|
||||
mutex_lock(&host->host_mutex);
|
||||
if (host->req) {
|
||||
dev_dbg(ms_dev(host),
|
||||
"%s: Controller removed during transfer\n",
|
||||
dev_name(&msh->dev));
|
||||
host->req->error = -ENOMEDIUM;
|
||||
do {
|
||||
err = memstick_next_req(msh, &host->req);
|
||||
if (!err)
|
||||
host->req->error = -ENOMEDIUM;
|
||||
} while (!err);
|
||||
}
|
||||
mutex_unlock(&host->host_mutex);
|
||||
|
||||
/* Balance possible unbalanced usage count
|
||||
* e.g. unconditional module removal
|
||||
*/
|
||||
|
|
@ -841,6 +830,8 @@ static void rtsx_usb_ms_drv_remove(struct platform_device *pdev)
|
|||
|
||||
pm_runtime_disable(ms_dev(host));
|
||||
memstick_remove_host(msh);
|
||||
/* No card, no new requests; wait for the last failed one to finish. */
|
||||
cancel_work_sync(&host->handle_req);
|
||||
dev_dbg(ms_dev(host),
|
||||
": Realtek USB Memstick controller has been removed\n");
|
||||
memstick_free_host(msh);
|
||||
|
|
|
|||
|
|
@ -295,9 +295,12 @@ static void octeon_mmc_remove(struct platform_device *pdev)
|
|||
u64 dma_cfg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CAVIUM_MAX_MMC; i++)
|
||||
for (i = 0; i < CAVIUM_MAX_MMC; i++) {
|
||||
if (host->slot[i])
|
||||
cvm_mmc_of_slot_remove(host->slot[i]);
|
||||
if (host->slot_pdev[i])
|
||||
of_platform_device_destroy(&host->slot_pdev[i]->dev, NULL);
|
||||
}
|
||||
|
||||
dma_cfg = readq(host->dma_base + MIO_EMM_DMA_CFG(host));
|
||||
dma_cfg &= ~MIO_EMM_DMA_CFG_EN;
|
||||
|
|
|
|||
|
|
@ -173,9 +173,12 @@ static void thunder_mmc_remove(struct pci_dev *pdev)
|
|||
u64 dma_cfg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CAVIUM_MAX_MMC; i++)
|
||||
for (i = 0; i < CAVIUM_MAX_MMC; i++) {
|
||||
if (host->slot[i])
|
||||
cvm_mmc_of_slot_remove(host->slot[i]);
|
||||
if (host->slot_pdev[i])
|
||||
of_platform_device_destroy(&host->slot_pdev[i]->dev, NULL);
|
||||
}
|
||||
|
||||
dma_cfg = readq(host->dma_base + MIO_EMM_DMA_CFG(host));
|
||||
dma_cfg &= ~MIO_EMM_DMA_CFG_EN;
|
||||
|
|
|
|||
|
|
@ -3216,6 +3216,7 @@ static void msdc_drv_remove(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
mmc_remove_host(mmc);
|
||||
cancel_delayed_work_sync(&host->req_timeout);
|
||||
msdc_deinit_hw(host);
|
||||
msdc_gate_clock(host);
|
||||
|
||||
|
|
|
|||
|
|
@ -890,6 +890,10 @@ static void sdhci_sprd_remove(struct platform_device *pdev)
|
|||
struct sdhci_host *host = platform_get_drvdata(pdev);
|
||||
struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
sdhci_remove_host(host, 0);
|
||||
|
||||
clk_disable_unprepare(sprd_host->clk_sdio);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user