mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Cross-merge networking fixes after downstream PR (net-7.1-rc8). Conflicts: drivers/net/ethernet/wangxun/txgbe/txgbe_aml.cf67aead16e("net: txgbe: rework service event handling")57d39faed4("net: txgbe: improve functions of AML 40G devices") net/rds/info.c512db8267b("rds: mark snapshot pages dirty in rds_info_getsockopt()")6e94eeb2a2("rds: convert to getsockopt_iter") Adjacent changes: include/net/sock.h1ee90b77b7("net: guard timestamp cmsgs to real error queue skbs")f0de88303d("net: make is_skb_wmem() available to modules") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
dad4d4b92a
1
.mailmap
1
.mailmap
|
|
@ -126,6 +126,7 @@ Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang@linaro.org>
|
|||
Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang@spreadtrum.com>
|
||||
Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang@unisoc.com>
|
||||
Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang7@gmail.com>
|
||||
Baoquan He <baoquan.he@linux.dev> <bhe@redhat.com>
|
||||
Barry Song <baohua@kernel.org> <21cnbao@gmail.com>
|
||||
Barry Song <baohua@kernel.org> <v-songbaohua@oppo.com>
|
||||
Barry Song <baohua@kernel.org> <song.bao.hua@hisilicon.com>
|
||||
|
|
|
|||
|
|
@ -13873,7 +13873,7 @@ F: scripts/Makefile.kcsan
|
|||
|
||||
KDUMP
|
||||
M: Andrew Morton <akpm@linux-foundation.org>
|
||||
M: Baoquan He <bhe@redhat.com>
|
||||
M: Baoquan He <baoquan.he@linux.dev>
|
||||
M: Mike Rapoport <rppt@kernel.org>
|
||||
M: Pasha Tatashin <pasha.tatashin@soleen.com>
|
||||
M: Pratyush Yadav <pratyush@kernel.org>
|
||||
|
|
@ -14192,7 +14192,7 @@ F: include/linux/kernfs.h
|
|||
|
||||
KEXEC
|
||||
M: Andrew Morton <akpm@linux-foundation.org>
|
||||
M: Baoquan He <bhe@redhat.com>
|
||||
M: Baoquan He <baoquan.he@linux.dev>
|
||||
M: Mike Rapoport <rppt@kernel.org>
|
||||
M: Pasha Tatashin <pasha.tatashin@soleen.com>
|
||||
M: Pratyush Yadav <pratyush@kernel.org>
|
||||
|
|
@ -17045,7 +17045,7 @@ M: Chris Li <chrisl@kernel.org>
|
|||
M: Kairui Song <kasong@tencent.com>
|
||||
R: Kemeng Shi <shikemeng@huaweicloud.com>
|
||||
R: Nhat Pham <nphamcs@gmail.com>
|
||||
R: Baoquan He <bhe@redhat.com>
|
||||
R: Baoquan He <baoquan.he@linux.dev>
|
||||
R: Barry Song <baohua@kernel.org>
|
||||
R: Youngjun Park <youngjun.park@lge.com>
|
||||
L: linux-mm@kvack.org
|
||||
|
|
|
|||
5
Makefile
5
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
VERSION = 7
|
||||
PATCHLEVEL = 1
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc6
|
||||
EXTRAVERSION = -rc7
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
@ -607,6 +607,7 @@ KBUILD_RUSTFLAGS := $(rust_common_flags) \
|
|||
-Crelocation-model=static \
|
||||
-Zfunction-sections=n \
|
||||
-Wclippy::float_arithmetic
|
||||
KBUILD_RUSTFLAGS_OPTION_CHKS :=
|
||||
|
||||
KBUILD_AFLAGS_KERNEL :=
|
||||
KBUILD_CFLAGS_KERNEL :=
|
||||
|
|
@ -643,7 +644,7 @@ export KBUILD_USERCFLAGS KBUILD_USERLDFLAGS
|
|||
|
||||
export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS KBUILD_LDFLAGS
|
||||
export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE
|
||||
export KBUILD_RUSTFLAGS RUSTFLAGS_KERNEL RUSTFLAGS_MODULE
|
||||
export KBUILD_RUSTFLAGS RUSTFLAGS_KERNEL RUSTFLAGS_MODULE KBUILD_RUSTFLAGS_OPTION_CHKS
|
||||
export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
|
||||
export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_RUSTFLAGS_MODULE KBUILD_LDFLAGS_MODULE
|
||||
export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL KBUILD_RUSTFLAGS_KERNEL
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ config ARM
|
|||
select MMU_GATHER_RCU_TABLE_FREE if SMP && ARM_LPAE
|
||||
select HAVE_REGS_AND_STACK_ACCESS_API
|
||||
select HAVE_RSEQ
|
||||
select HAVE_RUST if CPU_LITTLE_ENDIAN && CPU_32v7
|
||||
select HAVE_RUST if CPU_LITTLE_ENDIAN && CPU_32v7 && !KASAN
|
||||
select HAVE_STACKPROTECTOR
|
||||
select HAVE_SYSCALL_TRACEPOINTS
|
||||
select HAVE_UID16
|
||||
|
|
|
|||
|
|
@ -63,6 +63,9 @@ else
|
|||
KBUILD_CFLAGS += -fasynchronous-unwind-tables
|
||||
KBUILD_AFLAGS += -fasynchronous-unwind-tables
|
||||
KBUILD_RUSTFLAGS += -Cforce-unwind-tables=y -Zuse-sync-unwind=n
|
||||
# Work around rustc bug on compilers without
|
||||
# https://github.com/rust-lang/rust/pull/156973.
|
||||
KBUILD_RUSTFLAGS += $(if $(call rustc-min-version,109800),,-Zllvm_module_flag=uwtable:u32:2:max)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y)
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ static inline bool kvm_s2_trans_exec_el0(struct kvm *kvm, struct kvm_s2_trans *t
|
|||
u8 xn = FIELD_GET(KVM_PTE_LEAF_ATTR_HI_S2_XN, trans->desc);
|
||||
|
||||
if (!kvm_has_xnx(kvm))
|
||||
xn &= FIELD_PREP(KVM_PTE_LEAF_ATTR_HI_S2_XN, 0b10);
|
||||
xn &= 0b10;
|
||||
|
||||
switch (xn) {
|
||||
case 0b00:
|
||||
|
|
@ -148,7 +148,7 @@ static inline bool kvm_s2_trans_exec_el1(struct kvm *kvm, struct kvm_s2_trans *t
|
|||
u8 xn = FIELD_GET(KVM_PTE_LEAF_ATTR_HI_S2_XN, trans->desc);
|
||||
|
||||
if (!kvm_has_xnx(kvm))
|
||||
xn &= FIELD_PREP(KVM_PTE_LEAF_ATTR_HI_S2_XN, 0b10);
|
||||
xn &= 0b10;
|
||||
|
||||
switch (xn) {
|
||||
case 0b00:
|
||||
|
|
|
|||
|
|
@ -1569,7 +1569,8 @@ int __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
|||
/* Do the stage-2 translation */
|
||||
ipa = (par & GENMASK_ULL(47, 12)) | (vaddr & GENMASK_ULL(11, 0));
|
||||
out.esr = 0;
|
||||
ret = kvm_walk_nested_s2(vcpu, ipa, &out);
|
||||
scoped_guard(srcu, &vcpu->kvm->srcu)
|
||||
ret = kvm_walk_nested_s2(vcpu, ipa, &out);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -1665,7 +1666,8 @@ int __kvm_find_s1_desc_level(struct kvm_vcpu *vcpu, u64 va, u64 ipa, int *level)
|
|||
}
|
||||
|
||||
/* Walk the guest's PT, looking for a match along the way */
|
||||
ret = walk_s1(vcpu, &wi, &wr, va);
|
||||
scoped_guard(srcu, &vcpu->kvm->srcu)
|
||||
ret = walk_s1(vcpu, &wi, &wr, va);
|
||||
switch (ret) {
|
||||
case -EINTR:
|
||||
/* We interrupted the walk on a match, return the level */
|
||||
|
|
|
|||
|
|
@ -181,6 +181,8 @@ static inline void __deactivate_cptr_traps_vhe(struct kvm_vcpu *vcpu)
|
|||
val |= CPACR_EL1_ZEN;
|
||||
if (cpus_have_final_cap(ARM64_SME))
|
||||
val |= CPACR_EL1_SMEN;
|
||||
if (cpus_have_final_cap(ARM64_HAS_S1POE))
|
||||
val |= CPACR_EL1_E0POE;
|
||||
|
||||
write_sysreg(val, cpacr_el1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -925,7 +925,9 @@ static bool stage2_pte_cacheable(struct kvm_pgtable *pgt, kvm_pte_t pte)
|
|||
|
||||
static bool stage2_pte_executable(kvm_pte_t pte)
|
||||
{
|
||||
return kvm_pte_valid(pte) && !(pte & KVM_PTE_LEAF_ATTR_HI_S2_XN);
|
||||
enum kvm_pgtable_prot prot = kvm_pgtable_stage2_pte_prot(pte);
|
||||
|
||||
return prot & (KVM_PGTABLE_PROT_UX | KVM_PGTABLE_PROT_PX);
|
||||
}
|
||||
|
||||
static u64 stage2_map_walker_phys_addr(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
|
|
|
|||
|
|
@ -89,21 +89,28 @@ int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu)
|
|||
* again, and there is no reason to affect the whole VM for this.
|
||||
*/
|
||||
num_mmus = atomic_read(&kvm->online_vcpus) * S2_MMU_PER_VCPU;
|
||||
tmp = kvrealloc(kvm->arch.nested_mmus,
|
||||
size_mul(sizeof(*kvm->arch.nested_mmus), num_mmus),
|
||||
GFP_KERNEL_ACCOUNT | __GFP_ZERO);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
swap(kvm->arch.nested_mmus, tmp);
|
||||
if (num_mmus > kvm->arch.nested_mmus_size) {
|
||||
tmp = kvcalloc(num_mmus, sizeof(*tmp), GFP_KERNEL_ACCOUNT);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* If we went through a realocation, adjust the MMU back-pointers in
|
||||
* the previously initialised kvm_pgtable structures.
|
||||
*/
|
||||
if (kvm->arch.nested_mmus != tmp)
|
||||
for (int i = 0; i < kvm->arch.nested_mmus_size; i++)
|
||||
kvm->arch.nested_mmus[i].pgt->mmu = &kvm->arch.nested_mmus[i];
|
||||
write_lock(&kvm->mmu_lock);
|
||||
|
||||
if (kvm->arch.nested_mmus_size) {
|
||||
memcpy(tmp, kvm->arch.nested_mmus,
|
||||
size_mul(sizeof(*tmp), kvm->arch.nested_mmus_size));
|
||||
|
||||
for (int i = 0; i < kvm->arch.nested_mmus_size; i++)
|
||||
tmp[i].pgt->mmu = &tmp[i];
|
||||
}
|
||||
|
||||
swap(kvm->arch.nested_mmus, tmp);
|
||||
|
||||
write_unlock(&kvm->mmu_lock);
|
||||
|
||||
kvfree(tmp);
|
||||
}
|
||||
|
||||
for (int i = kvm->arch.nested_mmus_size; !ret && i < num_mmus; i++)
|
||||
ret = init_nested_s2_mmu(kvm, &kvm->arch.nested_mmus[i]);
|
||||
|
|
|
|||
|
|
@ -597,8 +597,10 @@ static void vgic_its_invalidate_cache(struct vgic_its *its)
|
|||
unsigned long idx;
|
||||
|
||||
xa_for_each(&its->translation_cache, idx, irq) {
|
||||
xa_erase(&its->translation_cache, idx);
|
||||
vgic_put_irq(kvm, irq);
|
||||
/* Only the context that erases the entry drops its cache ref. */
|
||||
irq = xa_erase(&its->translation_cache, idx);
|
||||
if (irq)
|
||||
vgic_put_irq(kvm, irq);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1441,6 +1441,7 @@ static void free_hotplug_page_range(struct page *page, size_t size,
|
|||
|
||||
static void free_hotplug_pgtable_page(struct page *page)
|
||||
{
|
||||
pagetable_dtor(page_ptdesc(page));
|
||||
free_hotplug_page_range(page, PAGE_SIZE, NULL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ void set_indir_lp_status(struct task_struct *task, bool enable);
|
|||
void set_indir_lp_lock(struct task_struct *task, bool lock);
|
||||
|
||||
#define PR_SHADOW_STACK_SUPPORTED_STATUS_MASK (PR_SHADOW_STACK_ENABLE)
|
||||
#define PR_CFI_SUPPORTED_STATUS_MASK (PR_CFI_ENABLE | PR_CFI_DISABLE | PR_CFI_LOCK)
|
||||
|
||||
#else
|
||||
|
||||
|
|
|
|||
|
|
@ -413,7 +413,7 @@ static struct user_regset riscv_user_regset[] __ro_after_init = {
|
|||
#endif
|
||||
#ifdef CONFIG_RISCV_USER_CFI
|
||||
[REGSET_CFI] = {
|
||||
.core_note_type = NT_RISCV_USER_CFI,
|
||||
USER_REGSET_NOTE_TYPE(RISCV_USER_CFI),
|
||||
.align = sizeof(__u64),
|
||||
.n = sizeof(struct user_cfi_state) / sizeof(__u64),
|
||||
.size = sizeof(__u64),
|
||||
|
|
|
|||
|
|
@ -235,17 +235,6 @@ static void set_unaligned_access_static_branches(void)
|
|||
modify_unaligned_access_branches(&fast_and_online, num_online_cpus());
|
||||
}
|
||||
|
||||
static int __init lock_and_set_unaligned_access_static_branch(void)
|
||||
{
|
||||
cpus_read_lock();
|
||||
set_unaligned_access_static_branches();
|
||||
cpus_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall_sync(lock_and_set_unaligned_access_static_branch);
|
||||
|
||||
static int riscv_online_cpu(unsigned int cpu)
|
||||
{
|
||||
int ret = cpu_online_unaligned_access_init(cpu);
|
||||
|
|
@ -440,6 +429,10 @@ static int __init check_unaligned_access_all_cpus(void)
|
|||
cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "riscv:online",
|
||||
riscv_online_cpu_vec, NULL);
|
||||
|
||||
cpus_read_lock();
|
||||
set_unaligned_access_static_branches();
|
||||
cpus_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -467,6 +467,9 @@ int arch_prctl_set_branch_landing_pad_state(struct task_struct *t, unsigned long
|
|||
if (!is_user_lpad_enabled())
|
||||
return -EINVAL;
|
||||
|
||||
if (state & ~PR_CFI_SUPPORTED_STATUS_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
/* indirect branch tracking is locked and further can't be modified by user */
|
||||
if (is_indir_lp_locked(t))
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ menu "Accelerated Cryptographic Algorithms for CPU (s390)"
|
|||
|
||||
config CRYPTO_AES_S390
|
||||
tristate "Ciphers: AES, modes: ECB, CBC, CTR, XTS, GCM"
|
||||
select CRYPTO_AEAD
|
||||
select CRYPTO_SKCIPHER
|
||||
help
|
||||
AEAD cipher: AES with GCM
|
||||
|
|
|
|||
|
|
@ -12,5 +12,6 @@ void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr);
|
|||
void gmap_helper_discard(struct mm_struct *mm, unsigned long vmaddr, unsigned long end);
|
||||
int gmap_helper_disable_cow_sharing(void);
|
||||
void gmap_helper_try_set_pte_unused(struct mm_struct *mm, unsigned long vmaddr);
|
||||
pte_t *try_get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl);
|
||||
|
||||
#endif /* _ASM_S390_GMAP_HELPERS_H */
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ int kvm_s390_faultin_gfn(struct kvm_vcpu *vcpu, struct kvm *kvm, struct guest_fa
|
|||
struct kvm_s390_mmu_cache *mc = NULL;
|
||||
struct kvm_memory_slot *slot;
|
||||
unsigned long inv_seq;
|
||||
int foll, rc = 0;
|
||||
int rc = -EAGAIN;
|
||||
int foll;
|
||||
|
||||
foll = f->write_attempt ? FOLL_WRITE : 0;
|
||||
foll |= f->attempt_pfault ? FOLL_NOWAIT : 0;
|
||||
|
|
@ -53,7 +54,14 @@ int kvm_s390_faultin_gfn(struct kvm_vcpu *vcpu, struct kvm *kvm, struct guest_fa
|
|||
return 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!mc) {
|
||||
local_mc = kvm_s390_new_mmu_cache();
|
||||
if (!local_mc)
|
||||
return -ENOMEM;
|
||||
mc = local_mc;
|
||||
}
|
||||
|
||||
while (rc == -EAGAIN) {
|
||||
f->valid = false;
|
||||
inv_seq = kvm->mmu_invalidate_seq;
|
||||
/* Pairs with the smp_wmb() in kvm_mmu_invalidate_end(). */
|
||||
|
|
@ -93,14 +101,7 @@ int kvm_s390_faultin_gfn(struct kvm_vcpu *vcpu, struct kvm *kvm, struct guest_fa
|
|||
if (is_error_pfn(f->pfn))
|
||||
return -EFAULT;
|
||||
|
||||
if (!mc) {
|
||||
local_mc = kvm_s390_new_mmu_cache();
|
||||
if (!local_mc)
|
||||
return -ENOMEM;
|
||||
mc = local_mc;
|
||||
}
|
||||
|
||||
/* Loop, will automatically release the faulted page. */
|
||||
/* Loop, release the faulted page. */
|
||||
if (mmu_invalidate_retry_gfn_unsafe(kvm, inv_seq, f->gfn)) {
|
||||
kvm_release_faultin_page(kvm, f->page, true, false);
|
||||
continue;
|
||||
|
|
@ -110,20 +111,19 @@ int kvm_s390_faultin_gfn(struct kvm_vcpu *vcpu, struct kvm *kvm, struct guest_fa
|
|||
if (!mmu_invalidate_retry_gfn(kvm, inv_seq, f->gfn)) {
|
||||
f->valid = true;
|
||||
rc = gmap_link(mc, kvm->arch.gmap, f, slot);
|
||||
kvm_release_faultin_page(kvm, f->page, !!rc, f->write_attempt);
|
||||
f->page = NULL;
|
||||
}
|
||||
kvm_release_faultin_page(kvm, f->page, !!rc, f->write_attempt);
|
||||
}
|
||||
kvm_release_faultin_page(kvm, f->page, true, false);
|
||||
|
||||
if (rc == -ENOMEM) {
|
||||
rc = kvm_s390_mmu_cache_topup(mc);
|
||||
if (rc)
|
||||
return rc;
|
||||
} else if (rc != -EAGAIN) {
|
||||
return rc;
|
||||
rc = -EAGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int kvm_s390_get_guest_page(struct kvm *kvm, struct guest_fault *f, gfn_t gfn, bool w)
|
||||
|
|
|
|||
|
|
@ -1466,15 +1466,17 @@ static int _do_shadow_crste(struct gmap *sg, gpa_t raddr, union crste *host, uni
|
|||
struct guest_fault *f, bool p)
|
||||
{
|
||||
union crste newcrste, oldcrste;
|
||||
gfn_t gfn;
|
||||
unsigned long mask;
|
||||
gfn_t r_gfn;
|
||||
int rc;
|
||||
|
||||
lockdep_assert_held(&sg->kvm->mmu_lock);
|
||||
lockdep_assert_held(&sg->parent->children_lock);
|
||||
|
||||
gfn = f->gfn & (is_pmd(*table) ? _SEGMENT_FR_MASK : _REGION3_FR_MASK);
|
||||
mask = is_pmd(*table) ? _SEGMENT_FR_MASK : _REGION3_FR_MASK;
|
||||
r_gfn = gpa_to_gfn(raddr) & mask;
|
||||
scoped_guard(spinlock, &sg->host_to_rmap_lock)
|
||||
rc = gmap_insert_rmap(sg, gfn, gpa_to_gfn(raddr), host->h.tt);
|
||||
rc = gmap_insert_rmap(sg, f->gfn & mask, r_gfn, host->h.tt);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -1497,8 +1499,7 @@ static int _do_shadow_crste(struct gmap *sg, gpa_t raddr, union crste *host, uni
|
|||
return -EAGAIN;
|
||||
|
||||
newcrste = _crste_fc1(f->pfn, oldcrste.h.tt, 0, !p);
|
||||
gfn = gpa_to_gfn(raddr);
|
||||
while (!dat_crstep_xchg_atomic(table, READ_ONCE(*table), newcrste, gfn, sg->asce))
|
||||
while (!dat_crstep_xchg_atomic(table, READ_ONCE(*table), newcrste, r_gfn, sg->asce))
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -395,15 +395,28 @@ static long _gmap_unmap_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct
|
|||
struct gmap_unmap_priv *priv = walk->priv;
|
||||
struct folio *folio = NULL;
|
||||
union crste old = *crstep;
|
||||
bool ok;
|
||||
|
||||
if (!old.h.fc)
|
||||
return 0;
|
||||
|
||||
if (old.s.fc1.pr && test_bit(GMAP_FLAG_EXPORT_ON_UNMAP, &priv->gmap->flags))
|
||||
folio = phys_to_folio(crste_origin_large(old));
|
||||
/* No races should happen because kvm->mmu_lock is held in write mode */
|
||||
KVM_BUG_ON(!gmap_crstep_xchg_atomic(priv->gmap, crstep, old, _CRSTE_EMPTY(old.h.tt), gfn),
|
||||
priv->gmap->kvm);
|
||||
/*
|
||||
* No races should happen because kvm->mmu_lock is held in write mode,
|
||||
* but the unmap operation could have triggered an unshadow, which
|
||||
* causes gmap_crstep_xchg_atomic() to return false and clear the
|
||||
* vsie_notif bit. Allow the operation to fail once, if the old crste
|
||||
* had the vsie_notif bit set. A second failure is not allowed, for
|
||||
* the reasons above.
|
||||
*/
|
||||
ok = gmap_crstep_xchg_atomic(priv->gmap, crstep, old, _CRSTE_EMPTY(old.h.tt), gfn);
|
||||
if (!ok) {
|
||||
KVM_BUG_ON(!old.s.fc1.vsie_notif, priv->gmap->kvm);
|
||||
old.s.fc1.vsie_notif = 0;
|
||||
ok = gmap_crstep_xchg_atomic(priv->gmap, crstep, old, _CRSTE_EMPTY(old.h.tt), gfn);
|
||||
KVM_BUG_ON(!ok, priv->gmap->kvm);
|
||||
}
|
||||
if (folio)
|
||||
uv_convert_from_secure_folio(folio);
|
||||
|
||||
|
|
|
|||
|
|
@ -273,11 +273,14 @@ static inline bool __must_check _gmap_crstep_xchg_atomic(struct gmap *gmap, unio
|
|||
gmap_unmap_prefix(gmap, gfn, gfn + align);
|
||||
}
|
||||
if (crste_leaf(oldcrste) && crste_needs_unshadow(oldcrste, newcrste)) {
|
||||
newcrste = oldcrste;
|
||||
newcrste.s.fc1.vsie_notif = 0;
|
||||
if (needs_lock)
|
||||
gmap_handle_vsie_unshadow_event(gmap, gfn);
|
||||
else
|
||||
_gmap_handle_vsie_unshadow_event(gmap, gfn);
|
||||
dat_crstep_xchg_atomic(crstep, oldcrste, newcrste, gfn, gmap->asce);
|
||||
return false;
|
||||
}
|
||||
if (!oldcrste.s.fc1.d && newcrste.s.fc1.d && !newcrste.s.fc1.s)
|
||||
SetPageDirty(phys_to_page(crste_origin_large(newcrste)));
|
||||
|
|
|
|||
|
|
@ -999,7 +999,10 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
|
|||
break;
|
||||
}
|
||||
case KVM_S390_VM_MEM_LIMIT_SIZE: {
|
||||
struct kvm_memslots *slots;
|
||||
struct kvm_memory_slot *ms;
|
||||
unsigned long new_limit;
|
||||
int bkt;
|
||||
|
||||
if (kvm_is_ucontrol(kvm))
|
||||
return -EINVAL;
|
||||
|
|
@ -1007,6 +1010,9 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
|
|||
if (get_user(new_limit, (u64 __user *)attr->addr))
|
||||
return -EFAULT;
|
||||
|
||||
guard(mutex)(&kvm->lock);
|
||||
|
||||
new_limit = ALIGN(new_limit, HPAGE_SIZE);
|
||||
if (kvm->arch.mem_limit != KVM_S390_NO_MEM_LIMIT &&
|
||||
new_limit > kvm->arch.mem_limit)
|
||||
return -E2BIG;
|
||||
|
|
@ -1014,12 +1020,27 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
|
|||
if (!new_limit)
|
||||
return -EINVAL;
|
||||
|
||||
ret = -EBUSY;
|
||||
if (!kvm->created_vcpus)
|
||||
ret = gmap_set_limit(kvm->arch.gmap, gpa_to_gfn(new_limit));
|
||||
if (kvm->created_vcpus)
|
||||
return -EBUSY;
|
||||
|
||||
ret = 0;
|
||||
scoped_guard(mutex, &kvm->slots_lock) {
|
||||
slots = kvm_memslots(kvm);
|
||||
if (slots && !kvm_memslots_empty(slots)) {
|
||||
kvm_for_each_memslot(ms, bkt, slots) {
|
||||
if (gpa_to_gfn(new_limit) < ms->base_gfn + ms->npages) {
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ret)
|
||||
ret = gmap_set_limit(kvm->arch.gmap, gpa_to_gfn(new_limit));
|
||||
}
|
||||
if (ret)
|
||||
break;
|
||||
VM_EVENT(kvm, 3, "SET: max guest address: %lu", new_limit);
|
||||
VM_EVENT(kvm, 3, "New guest asce: 0x%p",
|
||||
(void *)kvm->arch.gmap->asce.val);
|
||||
VM_EVENT(kvm, 3, "New guest asce: 0x%p", (void *)kvm->arch.gmap->asce.val);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -5672,6 +5693,8 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
|
|||
return -EINVAL;
|
||||
if ((new->base_gfn + new->npages) * PAGE_SIZE > kvm->arch.mem_limit)
|
||||
return -EINVAL;
|
||||
if (!asce_contains_gfn(kvm->arch.gmap->asce, new->base_gfn + new->npages - 1))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!kvm->arch.migration_mode)
|
||||
|
|
|
|||
|
|
@ -1188,6 +1188,7 @@ static void _essa_clear_cbrl(struct kvm_vcpu *vcpu, unsigned long *cbrl, int len
|
|||
union crste *crstep;
|
||||
union pgste pgste;
|
||||
union pte *ptep;
|
||||
hva_t hva;
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&vcpu->kvm->mmu_lock);
|
||||
|
|
@ -1199,8 +1200,11 @@ static void _essa_clear_cbrl(struct kvm_vcpu *vcpu, unsigned long *cbrl, int len
|
|||
if (!ptep || ptep->s.pr)
|
||||
continue;
|
||||
pgste = pgste_get_lock(ptep);
|
||||
if (pgste.usage == PGSTE_GPS_USAGE_UNUSED || pgste.zero)
|
||||
gmap_helper_zap_one_page(vcpu->kvm->mm, cbrl[i]);
|
||||
if (pgste.usage == PGSTE_GPS_USAGE_UNUSED || pgste.zero) {
|
||||
hva = gpa_to_hva(vcpu->kvm, cbrl[i]);
|
||||
if (!kvm_is_error_hva(hva))
|
||||
gmap_helper_zap_one_page(vcpu->kvm->mm, hva);
|
||||
}
|
||||
pgste_set_unlock(ptep, pgste);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/pagewalk.h>
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/mmu_notifier.h>
|
||||
#include <asm/gmap_helpers.h>
|
||||
#include "kvm-s390.h"
|
||||
#include "dat.h"
|
||||
#include "gaccess.h"
|
||||
|
|
@ -73,6 +74,7 @@ static bool should_export_before_import(struct uv_cb_header *uvcb, struct mm_str
|
|||
struct pv_make_secure {
|
||||
void *uvcb;
|
||||
struct folio *folio;
|
||||
struct kvm *kvm;
|
||||
int rc;
|
||||
bool needs_export;
|
||||
};
|
||||
|
|
@ -103,9 +105,21 @@ static void _kvm_s390_pv_make_secure(struct guest_fault *f)
|
|||
{
|
||||
struct pv_make_secure *priv = f->priv;
|
||||
struct folio *folio;
|
||||
spinlock_t *ptl; /* pte lock from try_get_locked_pte() */
|
||||
pte_t *ptep;
|
||||
|
||||
folio = pfn_folio(f->pfn);
|
||||
priv->rc = -EAGAIN;
|
||||
|
||||
if (!mmap_read_trylock(priv->kvm->mm))
|
||||
return;
|
||||
|
||||
ptep = try_get_locked_pte(priv->kvm->mm, gfn_to_hva(priv->kvm, f->gfn), &ptl);
|
||||
if (IS_ERR_VALUE(ptep)) {
|
||||
priv->rc = PTR_ERR(ptep);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (folio_trylock(folio)) {
|
||||
priv->rc = __kvm_s390_pv_make_secure(f, folio);
|
||||
if (priv->rc == -E2BIG || priv->rc == -EBUSY) {
|
||||
|
|
@ -114,6 +128,11 @@ static void _kvm_s390_pv_make_secure(struct guest_fault *f)
|
|||
}
|
||||
folio_unlock(folio);
|
||||
}
|
||||
|
||||
if (ptep)
|
||||
pte_unmap_unlock(ptep, ptl);
|
||||
out:
|
||||
mmap_read_unlock(priv->kvm->mm);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -127,7 +146,7 @@ static void _kvm_s390_pv_make_secure(struct guest_fault *f)
|
|||
*/
|
||||
int kvm_s390_pv_make_secure(struct kvm *kvm, unsigned long gaddr, void *uvcb)
|
||||
{
|
||||
struct pv_make_secure priv = { .uvcb = uvcb };
|
||||
struct pv_make_secure priv = { .uvcb = uvcb, .kvm = kvm, };
|
||||
struct guest_fault f = {
|
||||
.write_attempt = true,
|
||||
.gfn = gpa_to_gfn(gaddr),
|
||||
|
|
|
|||
|
|
@ -17,22 +17,68 @@
|
|||
#include <asm/gmap_helpers.h>
|
||||
|
||||
/**
|
||||
* ptep_zap_softleaf_entry() - discard a software leaf entry.
|
||||
* try_get_locked_pte() - like get_locked_pte(), but atomic and with trylock
|
||||
* @mm: the mm
|
||||
* @entry: the software leaf entry that needs to be zapped
|
||||
* @vmaddr: the userspace virtual address whose pte is to be found
|
||||
* @ptl: will be set to the pointer to the lock used to lock the pte in case
|
||||
* of success.
|
||||
*
|
||||
* Discards the given software leaf entry. If the leaf entry was an actual
|
||||
* swap entry (and not a migration entry, for example), the actual swapped
|
||||
* page is also discarded from swap.
|
||||
* This function returns the pointer to the pte corresponding to @addr in @mm,
|
||||
* similarly to get_locked_pte(). Unlike get_locked_pte(), no attempt is made
|
||||
* to allocate missing page tables. If a missing or large entry is found, the
|
||||
* function will return NULL. If the ptl lock is contended, %-EAGAIN is
|
||||
* returned.
|
||||
*
|
||||
* In case of success, *@ptl will point to the locked pte lock for the returned
|
||||
* pte, like get_locked_pte() does.
|
||||
*
|
||||
* Context: mmap_lock or vma lock for read or for write needs to be held.
|
||||
* Return:
|
||||
* * %NULL if the pte cannot be reached.
|
||||
* * %-EAGAIN if the pte can be reached, but cannot be locked.
|
||||
* * the pointer to the pte corresponding to @addr in @mm, if it can be reached
|
||||
* and locked.
|
||||
*/
|
||||
static void ptep_zap_softleaf_entry(struct mm_struct *mm, softleaf_t entry)
|
||||
pte_t *try_get_locked_pte(struct mm_struct *mm, unsigned long vmaddr, spinlock_t **ptl)
|
||||
{
|
||||
if (softleaf_is_swap(entry))
|
||||
dec_mm_counter(mm, MM_SWAPENTS);
|
||||
else if (softleaf_is_migration(entry))
|
||||
dec_mm_counter(mm, mm_counter(softleaf_to_folio(entry)));
|
||||
swap_put_entries_direct(entry, 1);
|
||||
pmd_t *pmdp, pmd, pmdval;
|
||||
pud_t *pudp, pud;
|
||||
p4d_t *p4dp, p4d;
|
||||
pgd_t *pgdp, pgd;
|
||||
pte_t *ptep;
|
||||
|
||||
pgdp = pgd_offset(mm, vmaddr);
|
||||
pgd = pgdp_get(pgdp);
|
||||
if (pgd_none(pgd) || !pgd_present(pgd))
|
||||
return NULL;
|
||||
p4dp = p4d_offset(pgdp, vmaddr);
|
||||
p4d = p4dp_get(p4dp);
|
||||
if (p4d_none(p4d) || !p4d_present(p4d))
|
||||
return NULL;
|
||||
pudp = pud_offset(p4dp, vmaddr);
|
||||
pud = pudp_get(pudp);
|
||||
if (pud_none(pud) || pud_leaf(pud) || !pud_present(pud))
|
||||
return NULL;
|
||||
pmdp = pmd_offset(pudp, vmaddr);
|
||||
pmd = pmdp_get_lockless(pmdp);
|
||||
if (pmd_none(pmd) || pmd_leaf(pmd) || !pmd_present(pmd))
|
||||
return NULL;
|
||||
ptep = pte_offset_map_rw_nolock(mm, pmdp, vmaddr, &pmdval, ptl);
|
||||
if (!ptep)
|
||||
return NULL;
|
||||
|
||||
if (spin_trylock(*ptl)) {
|
||||
if (unlikely(!pmd_same(pmdval, pmdp_get_lockless(pmdp)))) {
|
||||
pte_unmap_unlock(ptep, *ptl);
|
||||
return ERR_PTR(-EAGAIN);
|
||||
}
|
||||
return ptep;
|
||||
}
|
||||
|
||||
pte_unmap(ptep);
|
||||
return ERR_PTR(-EAGAIN);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(try_get_locked_pte);
|
||||
|
||||
/**
|
||||
* gmap_helper_zap_one_page() - discard a page if it was swapped.
|
||||
|
|
@ -46,7 +92,8 @@ static void ptep_zap_softleaf_entry(struct mm_struct *mm, softleaf_t entry)
|
|||
void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr)
|
||||
{
|
||||
struct vm_area_struct *vma;
|
||||
spinlock_t *ptl;
|
||||
spinlock_t *ptl; /* Lock for the host (userspace) page table */
|
||||
softleaf_t sl;
|
||||
pte_t *ptep;
|
||||
|
||||
mmap_assert_locked(mm);
|
||||
|
|
@ -57,11 +104,13 @@ void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr)
|
|||
return;
|
||||
|
||||
/* Get pointer to the page table entry */
|
||||
ptep = get_locked_pte(mm, vmaddr, &ptl);
|
||||
if (unlikely(!ptep))
|
||||
ptep = try_get_locked_pte(mm, vmaddr, &ptl);
|
||||
if (IS_ERR_OR_NULL(ptep))
|
||||
return;
|
||||
if (pte_swap(*ptep)) {
|
||||
ptep_zap_softleaf_entry(mm, softleaf_from_pte(*ptep));
|
||||
sl = softleaf_from_pte(*ptep);
|
||||
if (pte_swap(*ptep) && softleaf_is_swap(sl)) {
|
||||
dec_mm_counter(mm, MM_SWAPENTS);
|
||||
swap_put_entries_direct(sl, 1);
|
||||
pte_clear(mm, vmaddr, ptep);
|
||||
}
|
||||
pte_unmap_unlock(ptep, ptl);
|
||||
|
|
@ -113,37 +162,9 @@ EXPORT_SYMBOL_GPL(gmap_helper_discard);
|
|||
*/
|
||||
void gmap_helper_try_set_pte_unused(struct mm_struct *mm, unsigned long vmaddr)
|
||||
{
|
||||
pmd_t *pmdp, pmd, pmdval;
|
||||
pud_t *pudp, pud;
|
||||
p4d_t *p4dp, p4d;
|
||||
pgd_t *pgdp, pgd;
|
||||
spinlock_t *ptl; /* Lock for the host (userspace) page table */
|
||||
pte_t *ptep;
|
||||
|
||||
pgdp = pgd_offset(mm, vmaddr);
|
||||
pgd = pgdp_get(pgdp);
|
||||
if (pgd_none(pgd) || !pgd_present(pgd))
|
||||
return;
|
||||
|
||||
p4dp = p4d_offset(pgdp, vmaddr);
|
||||
p4d = p4dp_get(p4dp);
|
||||
if (p4d_none(p4d) || !p4d_present(p4d))
|
||||
return;
|
||||
|
||||
pudp = pud_offset(p4dp, vmaddr);
|
||||
pud = pudp_get(pudp);
|
||||
if (pud_none(pud) || pud_leaf(pud) || !pud_present(pud))
|
||||
return;
|
||||
|
||||
pmdp = pmd_offset(pudp, vmaddr);
|
||||
pmd = pmdp_get_lockless(pmdp);
|
||||
if (pmd_none(pmd) || pmd_leaf(pmd) || !pmd_present(pmd))
|
||||
return;
|
||||
|
||||
ptep = pte_offset_map_rw_nolock(mm, pmdp, vmaddr, &pmdval, &ptl);
|
||||
if (!ptep)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Several paths exists that takes the ptl lock and then call the
|
||||
* mmu_notifier, which takes the mmu_lock. The unmap path, instead,
|
||||
|
|
@ -156,21 +177,12 @@ void gmap_helper_try_set_pte_unused(struct mm_struct *mm, unsigned long vmaddr)
|
|||
* If the lock is contended the bit is not set and the deadlock is
|
||||
* avoided.
|
||||
*/
|
||||
if (spin_trylock(ptl)) {
|
||||
/*
|
||||
* Make sure the pte we are touching is still the correct
|
||||
* one. In theory this check should not be needed, but
|
||||
* better safe than sorry.
|
||||
* Disabling interrupts or holding the mmap lock is enough to
|
||||
* guarantee that no concurrent updates to the page tables
|
||||
* are possible.
|
||||
*/
|
||||
if (likely(pmd_same(pmdval, pmdp_get_lockless(pmdp))))
|
||||
__atomic64_or(_PAGE_UNUSED, (long *)ptep);
|
||||
spin_unlock(ptl);
|
||||
}
|
||||
ptep = try_get_locked_pte(mm, vmaddr, &ptl);
|
||||
if (IS_ERR_OR_NULL(ptep))
|
||||
return;
|
||||
|
||||
pte_unmap(ptep);
|
||||
__atomic64_or(_PAGE_UNUSED, (long *)ptep);
|
||||
pte_unmap_unlock(ptep, ptl);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gmap_helper_try_set_pte_unused);
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,10 @@ KBUILD_CFLAGS += -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -mno-sse4a
|
|||
KBUILD_RUSTFLAGS += --target=$(objtree)/scripts/target.json
|
||||
KBUILD_RUSTFLAGS += -Ctarget-feature=-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2
|
||||
|
||||
# The target.json file is not available when invoking rustc-option, so use the
|
||||
# built-in target when checking whether flags are supported instead.
|
||||
KBUILD_RUSTFLAGS_OPTION_CHKS += --target=x86_64-unknown-none
|
||||
|
||||
#
|
||||
# CFLAGS for compiling floating point code inside the kernel.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -14,6 +14,14 @@ endif
|
|||
|
||||
KBUILD_RUSTFLAGS += --target=$(objtree)/scripts/target.json
|
||||
|
||||
# The target.json file is not available when invoking rustc-option, so use the
|
||||
# built-in target when checking whether flags are supported instead.
|
||||
ifeq ($(CONFIG_X86_32),y)
|
||||
KBUILD_RUSTFLAGS_OPTION_CHKS += --target=i686-unknown-linux-gnu
|
||||
else
|
||||
KBUILD_RUSTFLAGS_OPTION_CHKS += --target=x86_64-unknown-linux-gnu
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_X86_32),y)
|
||||
START := 0x8048000
|
||||
|
||||
|
|
|
|||
|
|
@ -518,7 +518,7 @@ static void bsp_init_amd(struct cpuinfo_x86 *c)
|
|||
break;
|
||||
case 0x50 ... 0x5f:
|
||||
case 0x80 ... 0xaf:
|
||||
case 0xc0 ... 0xcf:
|
||||
case 0xc0 ... 0xef:
|
||||
setup_force_cpu_cap(X86_FEATURE_ZEN6);
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -377,7 +377,12 @@ static const struct x86_cpu_id snc_cpu_ids[] __initconst = {
|
|||
|
||||
static __init int snc_get_config(void)
|
||||
{
|
||||
int ret = topology_num_nodes_per_package();
|
||||
int ret;
|
||||
|
||||
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
|
||||
return 1;
|
||||
|
||||
ret = topology_num_nodes_per_package();
|
||||
|
||||
if (ret > 1 && !x86_match_cpu(snc_cpu_ids)) {
|
||||
pr_warn("CoD enabled system? Resctrl not supported\n");
|
||||
|
|
|
|||
|
|
@ -3313,37 +3313,6 @@ void sev_guest_memory_reclaimed(struct kvm *kvm)
|
|||
sev_writeback_caches(kvm);
|
||||
}
|
||||
|
||||
void sev_free_vcpu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm;
|
||||
|
||||
if (!is_sev_es_guest(vcpu))
|
||||
return;
|
||||
|
||||
svm = to_svm(vcpu);
|
||||
|
||||
/*
|
||||
* If it's an SNP guest, then the VMSA was marked in the RMP table as
|
||||
* a guest-owned page. Transition the page to hypervisor state before
|
||||
* releasing it back to the system.
|
||||
*/
|
||||
if (is_sev_snp_guest(vcpu)) {
|
||||
u64 pfn = __pa(svm->sev_es.vmsa) >> PAGE_SHIFT;
|
||||
|
||||
if (kvm_rmp_make_shared(vcpu->kvm, pfn, PG_LEVEL_4K))
|
||||
goto skip_vmsa_free;
|
||||
}
|
||||
|
||||
if (vcpu->arch.guest_state_protected)
|
||||
sev_flush_encrypted_page(vcpu, svm->sev_es.vmsa);
|
||||
|
||||
__free_page(virt_to_page(svm->sev_es.vmsa));
|
||||
|
||||
skip_vmsa_free:
|
||||
if (svm->sev_es.ghcb_sa_free)
|
||||
kvfree(svm->sev_es.ghcb_sa);
|
||||
}
|
||||
|
||||
static void dump_ghcb(struct vcpu_svm *svm)
|
||||
{
|
||||
struct vmcb_control_area *control = &svm->vmcb->control;
|
||||
|
|
@ -3583,6 +3552,20 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void __sev_es_unmap_ghcb(struct vcpu_svm *svm)
|
||||
{
|
||||
if (svm->sev_es.ghcb_sa_free) {
|
||||
kvfree(svm->sev_es.ghcb_sa);
|
||||
svm->sev_es.ghcb_sa = NULL;
|
||||
svm->sev_es.ghcb_sa_free = false;
|
||||
}
|
||||
|
||||
if (svm->sev_es.ghcb) {
|
||||
kvm_vcpu_unmap(&svm->vcpu, &svm->sev_es.ghcb_map);
|
||||
svm->sev_es.ghcb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void sev_es_unmap_ghcb(struct vcpu_svm *svm)
|
||||
{
|
||||
/* Clear any indication that the vCPU is in a type of AP Reset Hold */
|
||||
|
|
@ -3591,31 +3574,51 @@ void sev_es_unmap_ghcb(struct vcpu_svm *svm)
|
|||
if (!svm->sev_es.ghcb)
|
||||
return;
|
||||
|
||||
if (svm->sev_es.ghcb_sa_free) {
|
||||
/*
|
||||
* The scratch area lives outside the GHCB, so there is a
|
||||
* buffer that, depending on the operation performed, may
|
||||
* need to be synced, then freed.
|
||||
*/
|
||||
if (svm->sev_es.ghcb_sa_sync) {
|
||||
kvm_write_guest(svm->vcpu.kvm,
|
||||
svm->sev_es.sw_scratch,
|
||||
svm->sev_es.ghcb_sa,
|
||||
svm->sev_es.ghcb_sa_len);
|
||||
svm->sev_es.ghcb_sa_sync = false;
|
||||
}
|
||||
|
||||
kvfree(svm->sev_es.ghcb_sa);
|
||||
svm->sev_es.ghcb_sa = NULL;
|
||||
svm->sev_es.ghcb_sa_free = false;
|
||||
/*
|
||||
* If the scratch area lives outside the GHCB, there's a buffer that,
|
||||
* depending on the operation performed, may need to be synced.
|
||||
*/
|
||||
if (svm->sev_es.ghcb_sa_sync) {
|
||||
kvm_write_guest(svm->vcpu.kvm, svm->sev_es.sw_scratch,
|
||||
svm->sev_es.ghcb_sa, svm->sev_es.ghcb_sa_len);
|
||||
svm->sev_es.ghcb_sa_sync = false;
|
||||
}
|
||||
|
||||
trace_kvm_vmgexit_exit(svm->vcpu.vcpu_id, svm->sev_es.ghcb);
|
||||
|
||||
sev_es_sync_to_ghcb(svm);
|
||||
|
||||
kvm_vcpu_unmap(&svm->vcpu, &svm->sev_es.ghcb_map);
|
||||
svm->sev_es.ghcb = NULL;
|
||||
__sev_es_unmap_ghcb(svm);
|
||||
}
|
||||
|
||||
void sev_free_vcpu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm;
|
||||
|
||||
if (!is_sev_es_guest(vcpu))
|
||||
return;
|
||||
|
||||
svm = to_svm(vcpu);
|
||||
|
||||
/*
|
||||
* If it's an SNP guest, then the VMSA was marked in the RMP table as
|
||||
* a guest-owned page. Transition the page to hypervisor state before
|
||||
* releasing it back to the system.
|
||||
*/
|
||||
if (is_sev_snp_guest(vcpu)) {
|
||||
u64 pfn = __pa(svm->sev_es.vmsa) >> PAGE_SHIFT;
|
||||
|
||||
if (kvm_rmp_make_shared(vcpu->kvm, pfn, PG_LEVEL_4K))
|
||||
goto skip_vmsa_free;
|
||||
}
|
||||
|
||||
if (vcpu->arch.guest_state_protected)
|
||||
sev_flush_encrypted_page(vcpu, svm->sev_es.vmsa);
|
||||
|
||||
__free_page(virt_to_page(svm->sev_es.vmsa));
|
||||
|
||||
skip_vmsa_free:
|
||||
__sev_es_unmap_ghcb(svm);
|
||||
}
|
||||
|
||||
int pre_sev_run(struct vcpu_svm *svm, int cpu)
|
||||
|
|
@ -3685,6 +3688,8 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 min_len)
|
|||
goto e_scratch;
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(svm->sev_es.ghcb_sa_sync || svm->sev_es.ghcb_sa_free);
|
||||
|
||||
if ((scratch_gpa_beg & PAGE_MASK) == control->ghcb_gpa) {
|
||||
/* Scratch area begins within GHCB */
|
||||
ghcb_scratch_beg = control->ghcb_gpa +
|
||||
|
|
@ -3706,6 +3711,8 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 min_len)
|
|||
scratch_va = (void *)svm->sev_es.ghcb;
|
||||
scratch_va += (scratch_gpa_beg - control->ghcb_gpa);
|
||||
|
||||
svm->sev_es.ghcb_sa_sync = false;
|
||||
svm->sev_es.ghcb_sa_free = false;
|
||||
svm->sev_es.ghcb_sa_len = ghcb_scratch_end - scratch_gpa_beg;
|
||||
} else {
|
||||
/* GHCB v2 requires the scratch area to be within the GHCB. */
|
||||
|
|
@ -3841,13 +3848,11 @@ struct psc_buffer {
|
|||
struct psc_entry entries[];
|
||||
} __packed;
|
||||
|
||||
static int snp_begin_psc(struct vcpu_svm *svm);
|
||||
static int snp_do_psc(struct vcpu_svm *svm);
|
||||
|
||||
static void snp_complete_psc(struct vcpu_svm *svm, u64 psc_ret)
|
||||
{
|
||||
svm->sev_es.psc_inflight = 0;
|
||||
svm->sev_es.psc_idx = 0;
|
||||
svm->sev_es.psc_2m = false;
|
||||
memset(&svm->sev_es.psc, 0, sizeof(svm->sev_es.psc));
|
||||
|
||||
/*
|
||||
* PSC requests always get a "no action" response in SW_EXITINFO1, with
|
||||
|
|
@ -3860,9 +3865,8 @@ static void snp_complete_psc(struct vcpu_svm *svm, u64 psc_ret)
|
|||
|
||||
static void __snp_complete_one_psc(struct vcpu_svm *svm)
|
||||
{
|
||||
struct psc_buffer *psc = svm->sev_es.ghcb_sa;
|
||||
struct psc_entry *entries = psc->entries;
|
||||
struct psc_hdr *hdr = &psc->hdr;
|
||||
struct vcpu_sev_es_state *sev_es = &svm->sev_es;
|
||||
struct psc_buffer *guest_psc = sev_es->ghcb_sa;
|
||||
__u16 idx;
|
||||
|
||||
/*
|
||||
|
|
@ -3870,14 +3874,15 @@ static void __snp_complete_one_psc(struct vcpu_svm *svm)
|
|||
* corresponding entries in the guest's PSC buffer and zero out the
|
||||
* count of in-flight PSC entries.
|
||||
*/
|
||||
for (idx = svm->sev_es.psc_idx; svm->sev_es.psc_inflight;
|
||||
svm->sev_es.psc_inflight--, idx++) {
|
||||
struct psc_entry entry = READ_ONCE(entries[idx]);
|
||||
for (idx = sev_es->psc.cur_idx; sev_es->psc.batch_size;
|
||||
sev_es->psc.batch_size--, idx++) {
|
||||
struct psc_entry entry = READ_ONCE(guest_psc->entries[idx]);
|
||||
|
||||
entries[idx].cur_page = entry.pagesize ? 512 : 1;
|
||||
guest_psc->entries[idx].cur_page = entry.pagesize ? 512 : 1;
|
||||
}
|
||||
|
||||
hdr->cur_entry = idx;
|
||||
sev_es->psc.cur_idx = idx;
|
||||
guest_psc->hdr.cur_entry = idx;
|
||||
}
|
||||
|
||||
static int snp_complete_one_psc(struct kvm_vcpu *vcpu)
|
||||
|
|
@ -3892,63 +3897,30 @@ static int snp_complete_one_psc(struct kvm_vcpu *vcpu)
|
|||
__snp_complete_one_psc(svm);
|
||||
|
||||
/* Handle the next range (if any). */
|
||||
return snp_begin_psc(svm);
|
||||
return snp_do_psc(svm);
|
||||
}
|
||||
|
||||
static int snp_begin_psc(struct vcpu_svm *svm)
|
||||
static int snp_do_psc(struct vcpu_svm *svm)
|
||||
{
|
||||
struct vcpu_sev_es_state *sev_es = &svm->sev_es;
|
||||
struct psc_buffer *psc = sev_es->ghcb_sa;
|
||||
struct psc_entry *entries = psc->entries;
|
||||
struct psc_buffer *guest_psc = sev_es->ghcb_sa;
|
||||
struct kvm_vcpu *vcpu = &svm->vcpu;
|
||||
struct psc_hdr *hdr = &psc->hdr;
|
||||
struct psc_entry entry_start;
|
||||
u16 idx, idx_start, idx_end, max_nr_entries;
|
||||
int npages;
|
||||
bool huge;
|
||||
u64 gfn;
|
||||
|
||||
if (!user_exit_on_hypercall(vcpu->kvm, KVM_HC_MAP_GPA_RANGE)) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* GHCB v2 requires the scratch area to reside within the GHCB itself,
|
||||
* and PSC requests are only supported for GHCB v2+. Thus it should be
|
||||
* impossible to exceed the max PSC entry count (which is derived from
|
||||
* the size of the shared GHCB buffer).
|
||||
*/
|
||||
max_nr_entries = (sev_es->ghcb_sa_len - sizeof(struct psc_hdr)) /
|
||||
sizeof(struct psc_entry);
|
||||
if (WARN_ON_ONCE(max_nr_entries > VMGEXIT_PSC_MAX_COUNT)) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC);
|
||||
return 1;
|
||||
}
|
||||
u16 idx;
|
||||
|
||||
next_range:
|
||||
/* There should be no other PSCs in-flight at this point. */
|
||||
if (WARN_ON_ONCE(svm->sev_es.psc_inflight)) {
|
||||
if (WARN_ON_ONCE(svm->sev_es.psc.batch_size)) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The PSC descriptor buffer can be modified by a misbehaved guest after
|
||||
* validation, so take care to only use validated copies of values used
|
||||
* for things like array indexing.
|
||||
*/
|
||||
idx_start = READ_ONCE(hdr->cur_entry);
|
||||
idx_end = READ_ONCE(hdr->end_entry);
|
||||
|
||||
if (idx_end >= max_nr_entries) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_INVALID_HDR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Find the start of the next range which needs processing. */
|
||||
for (idx = idx_start; idx <= idx_end; idx++, hdr->cur_entry++) {
|
||||
entry_start = READ_ONCE(entries[idx]);
|
||||
for (idx = sev_es->psc.cur_idx; idx <= sev_es->psc.end_idx; idx++) {
|
||||
entry_start = READ_ONCE(guest_psc->entries[idx]);
|
||||
|
||||
gfn = entry_start.gfn;
|
||||
huge = entry_start.pagesize;
|
||||
|
|
@ -3974,32 +3946,40 @@ static int snp_begin_psc(struct vcpu_svm *svm)
|
|||
|
||||
if (npages)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Increment the guest-visible index to communicate the current
|
||||
* entry back to the guest, e.g. in case of failure. No need
|
||||
* for READ_ONCE() as KVM doesn't consume the field, i.e. a
|
||||
* misbehaving guest can only break itself.
|
||||
*/
|
||||
guest_psc->hdr.cur_entry++;
|
||||
}
|
||||
|
||||
if (idx > idx_end) {
|
||||
if (idx > sev_es->psc.end_idx) {
|
||||
/* Nothing more to process. */
|
||||
snp_complete_psc(svm, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
svm->sev_es.psc_2m = huge;
|
||||
svm->sev_es.psc_idx = idx;
|
||||
svm->sev_es.psc_inflight = 1;
|
||||
sev_es->psc.is_2m = huge;
|
||||
sev_es->psc.cur_idx = idx;
|
||||
sev_es->psc.batch_size = 1;
|
||||
|
||||
/*
|
||||
* Find all subsequent PSC entries that contain adjacent GPA
|
||||
* ranges/operations and can be combined into a single
|
||||
* KVM_HC_MAP_GPA_RANGE exit.
|
||||
*/
|
||||
while (++idx <= idx_end) {
|
||||
struct psc_entry entry = READ_ONCE(entries[idx]);
|
||||
while (++idx <= sev_es->psc.end_idx) {
|
||||
struct psc_entry entry = READ_ONCE(guest_psc->entries[idx]);
|
||||
|
||||
if (entry.operation != entry_start.operation ||
|
||||
entry.gfn != entry_start.gfn + npages ||
|
||||
entry.cur_page || !!entry.pagesize != huge)
|
||||
break;
|
||||
|
||||
svm->sev_es.psc_inflight++;
|
||||
sev_es->psc.batch_size++;
|
||||
npages += huge ? 512 : 1;
|
||||
}
|
||||
|
||||
|
|
@ -4041,6 +4021,46 @@ static int snp_begin_psc(struct vcpu_svm *svm)
|
|||
BUG();
|
||||
}
|
||||
|
||||
static int snp_begin_psc(struct vcpu_svm *svm)
|
||||
{
|
||||
struct vcpu_sev_es_state *sev_es = &svm->sev_es;
|
||||
struct psc_buffer *guest_psc = sev_es->ghcb_sa;
|
||||
u16 max_nr_entries;
|
||||
|
||||
if (!user_exit_on_hypercall(svm->vcpu.kvm, KVM_HC_MAP_GPA_RANGE)) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* GHCB v2 requires the scratch area to reside within the GHCB itself,
|
||||
* and PSC requests are only supported for GHCB v2+. Thus it should be
|
||||
* impossible to exceed the max PSC entry count (which is derived from
|
||||
* the size of the shared GHCB buffer).
|
||||
*/
|
||||
max_nr_entries = (sev_es->ghcb_sa_len - sizeof(struct psc_hdr)) /
|
||||
sizeof(struct psc_entry);
|
||||
if (WARN_ON_ONCE(max_nr_entries > VMGEXIT_PSC_MAX_COUNT)) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The PSC descriptor buffer can be modified by a misbehaved guest after
|
||||
* validation, so take care to only use validated copies of values used
|
||||
* for things like array indexing.
|
||||
*/
|
||||
sev_es->psc.cur_idx = READ_ONCE(guest_psc->hdr.cur_entry);
|
||||
sev_es->psc.end_idx = READ_ONCE(guest_psc->hdr.end_entry);
|
||||
|
||||
if (sev_es->psc.end_idx >= max_nr_entries) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_INVALID_HDR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return snp_do_psc(svm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoked as part of svm_vcpu_reset() processing of an init event.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -257,9 +257,12 @@ struct vcpu_sev_es_state {
|
|||
bool ghcb_sa_free;
|
||||
|
||||
/* SNP Page-State-Change buffer entries currently being processed */
|
||||
u16 psc_idx;
|
||||
u16 psc_inflight;
|
||||
bool psc_2m;
|
||||
struct {
|
||||
u16 cur_idx;
|
||||
u16 end_idx;
|
||||
u16 batch_size;
|
||||
bool is_2m;
|
||||
} psc;
|
||||
|
||||
u64 ghcb_registered_gpa;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
/* Copyright 2025 Arm, Ltd. */
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <drm/ethosu_accel.h>
|
||||
|
|
@ -163,17 +164,30 @@ static u64 dma_length(struct ethosu_validated_cmdstream_info *info,
|
|||
s8 mode = dma_st->mode;
|
||||
u64 len = dma->len;
|
||||
|
||||
if (len == U64_MAX)
|
||||
return U64_MAX;
|
||||
|
||||
if (mode >= 1) {
|
||||
if (dma->stride[0] < 0 && (u64)(-dma->stride[0]) > len)
|
||||
return U64_MAX;
|
||||
len += dma->stride[0];
|
||||
len *= dma_st->size0;
|
||||
if (check_mul_overflow(len, (u64)dma_st->size0, &len))
|
||||
return U64_MAX;
|
||||
}
|
||||
if (mode == 2) {
|
||||
if (dma->stride[1] < 0 && (u64)(-dma->stride[1]) > len)
|
||||
return U64_MAX;
|
||||
len += dma->stride[1];
|
||||
len *= dma_st->size1;
|
||||
if (check_mul_overflow(len, (u64)dma_st->size1, &len))
|
||||
return U64_MAX;
|
||||
}
|
||||
if (dma->region >= 0) {
|
||||
u64 end;
|
||||
|
||||
if (check_add_overflow(len, dma->offset, &end))
|
||||
return U64_MAX;
|
||||
info->region_size[dma->region] = max(info->region_size[dma->region], end);
|
||||
}
|
||||
if (dma->region >= 0)
|
||||
info->region_size[dma->region] = max(info->region_size[dma->region],
|
||||
len + dma->offset);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
|
@ -387,6 +401,8 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
return -EFAULT;
|
||||
|
||||
i++;
|
||||
if (i >= size / 4)
|
||||
return -EINVAL;
|
||||
bocmds[i] = cmds[1];
|
||||
addr = cmd_to_addr(cmds);
|
||||
}
|
||||
|
|
@ -395,6 +411,8 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
case NPU_OP_DMA_START:
|
||||
srclen = dma_length(info, &st.dma, &st.dma.src);
|
||||
dstlen = dma_length(info, &st.dma, &st.dma.dst);
|
||||
if (srclen == U64_MAX || dstlen == U64_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (st.dma.dst.region >= 0)
|
||||
info->output_region[st.dma.dst.region] = true;
|
||||
|
|
@ -431,8 +449,7 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
return ret;
|
||||
break;
|
||||
case NPU_OP_RESIZE: // U85 only
|
||||
WARN_ON(1); // TODO
|
||||
break;
|
||||
return -EINVAL;
|
||||
case NPU_SET_KERNEL_WIDTH_M1:
|
||||
st.ifm.width = param;
|
||||
break;
|
||||
|
|
@ -464,7 +481,7 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
st.ifm.broadcast = param;
|
||||
break;
|
||||
case NPU_SET_IFM_REGION:
|
||||
st.ifm.region = param & 0x7f;
|
||||
st.ifm.region = param & 0x7;
|
||||
break;
|
||||
case NPU_SET_IFM_WIDTH0_M1:
|
||||
st.ifm.width0 = param;
|
||||
|
|
@ -599,7 +616,7 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
if (ethosu_is_u65(edev))
|
||||
st.scale[1].length = cmds[1];
|
||||
else
|
||||
st.weight[1].length = cmds[1];
|
||||
st.weight[2].length = cmds[1];
|
||||
break;
|
||||
case NPU_SET_WEIGHT3_BASE:
|
||||
st.weight[3].base = addr;
|
||||
|
|
|
|||
|
|
@ -259,6 +259,22 @@ static int ivpu_fw_parse(struct ivpu_device *vdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!PAGE_ALIGNED(runtime_addr)) {
|
||||
ivpu_err(vdev, "Runtime address 0x%llx not page aligned\n", runtime_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!PAGE_ALIGNED(runtime_size)) {
|
||||
ivpu_err(vdev, "Runtime size %llu not page aligned\n", runtime_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (runtime_size < image_size) {
|
||||
ivpu_err(vdev, "Runtime size too small: %llu, image size: %llu\n",
|
||||
runtime_size, image_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!ivpu_is_within_range(image_load_addr, image_size, &vdev->hw->ranges.runtime)) {
|
||||
ivpu_err(vdev, "Invalid firmware load address: 0x%llx and size %llu\n",
|
||||
image_load_addr, image_size);
|
||||
|
|
|
|||
|
|
@ -98,6 +98,11 @@ static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const cha
|
|||
u32 log_start = only_new_msgs ? READ_ONCE(log->read_index) : 0;
|
||||
u32 log_end = READ_ONCE(log->write_index);
|
||||
|
||||
if (log_start >= data_size)
|
||||
log_start = 0;
|
||||
if (log_end > data_size)
|
||||
log_end = data_size;
|
||||
|
||||
if (log->wrap_count == log->read_wrap_count) {
|
||||
if (log_end <= log_start) {
|
||||
drm_printf(p, "==== %s \"%s\" log empty ====\n", prefix, log->name);
|
||||
|
|
|
|||
|
|
@ -291,6 +291,13 @@ int ivpu_ms_get_info_ioctl(struct drm_device *dev, void *data, struct drm_file *
|
|||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
if (info_size > ivpu_bo_size(bo)) {
|
||||
ivpu_warn_ratelimited(vdev, "MS info overflow: %#llx > %#zx\n",
|
||||
info_size, ivpu_bo_size(bo));
|
||||
ret = -EOVERFLOW;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (args->buffer_size < info_size) {
|
||||
ret = -ENOSPC;
|
||||
goto unlock;
|
||||
|
|
|
|||
|
|
@ -2337,7 +2337,7 @@ static int zram_bvec_write_partial(struct zram *zram, struct bio_vec *bvec,
|
|||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = zram_read_page(zram, page, index, bio);
|
||||
ret = zram_read_page(zram, page, index, NULL);
|
||||
if (!ret) {
|
||||
memcpy_from_bvec(page_address(page) + offset, bvec);
|
||||
ret = zram_write_page(zram, page, index);
|
||||
|
|
|
|||
|
|
@ -1428,7 +1428,7 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
|
|||
epp = cpudata->epp_default_dc;
|
||||
}
|
||||
|
||||
if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) {
|
||||
if (epp > 0 && cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) {
|
||||
pr_debug("EPP cannot be set under performance policy\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ struct amd_aperf_mperf {
|
|||
* @hw_prefcore: check whether HW supports preferred core featue.
|
||||
* Only when hw_prefcore and early prefcore param are true,
|
||||
* AMD P-State driver supports preferred core featue.
|
||||
* @epp_cached: Cached CPPC energy-performance preference value
|
||||
* @policy: Cpufreq policy value
|
||||
* @suspended: If CPU core if offlined
|
||||
* @epp_default_ac: Default EPP value for AC power source
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/irq_sim.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
@ -578,7 +579,7 @@ static int __init gpio_mockup_register_chip(int idx)
|
|||
|
||||
static int __init gpio_mockup_init(void)
|
||||
{
|
||||
int i, num_chips, err;
|
||||
int i, num_chips, err, base, ngpio;
|
||||
|
||||
if ((gpio_mockup_num_ranges % 2) ||
|
||||
(gpio_mockup_num_ranges > GPIO_MOCKUP_MAX_RANGES))
|
||||
|
|
@ -592,8 +593,19 @@ static int __init gpio_mockup_init(void)
|
|||
* always be greater than 0.
|
||||
*/
|
||||
for (i = 0; i < num_chips; i++) {
|
||||
if (gpio_mockup_range_ngpio(i) < 0)
|
||||
base = gpio_mockup_range_base(i);
|
||||
ngpio = gpio_mockup_range_ngpio(i);
|
||||
|
||||
if (ngpio <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (base < 0) {
|
||||
if (ngpio > U16_MAX)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (ngpio <= base || ngpio - base > U16_MAX)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup", NULL);
|
||||
|
|
|
|||
|
|
@ -996,7 +996,7 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
BUG();
|
||||
}
|
||||
|
||||
if (IS_REACHABLE(CONFIG_PWM))
|
||||
if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm)
|
||||
mvebu_pwm_suspend(mvchip);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1048,7 +1048,7 @@ static int mvebu_gpio_resume(struct platform_device *pdev)
|
|||
BUG();
|
||||
}
|
||||
|
||||
if (IS_REACHABLE(CONFIG_PWM))
|
||||
if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm)
|
||||
mvebu_pwm_resume(mvchip);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -802,8 +802,10 @@ static void rockchip_gpio_remove(struct platform_device *pdev)
|
|||
struct rockchip_pin_bank *bank = platform_get_drvdata(pdev);
|
||||
|
||||
irq_set_chained_handler_and_data(bank->irq, NULL, NULL);
|
||||
if (bank->domain)
|
||||
if (bank->domain) {
|
||||
irq_domain_remove_generic_chips(bank->domain);
|
||||
irq_domain_remove(bank->domain);
|
||||
}
|
||||
gpiochip_remove(&bank->gpio_chip);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1014,6 +1014,7 @@ static void zynq_gpio_remove(struct platform_device *pdev)
|
|||
gpiochip_remove(&gpio->chip);
|
||||
device_set_wakeup_capable(&pdev->dev, 0);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
}
|
||||
|
||||
static struct platform_driver zynq_gpio_driver = {
|
||||
|
|
|
|||
|
|
@ -1066,11 +1066,6 @@ int of_gpiochip_add(struct gpio_chip *chip)
|
|||
|
||||
of_node_get(np);
|
||||
|
||||
for_each_available_child_of_node_scoped(np, child) {
|
||||
if (of_property_read_bool(child, "gpio-hog"))
|
||||
of_node_set_flag(child, OF_POPULATED);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1031,9 +1031,17 @@ static int gpiochip_hog_lines(struct gpio_chip *gc)
|
|||
if (!fwnode_property_present(fwnode, "gpio-hog"))
|
||||
continue;
|
||||
|
||||
/* The hog may have been handled by another gpio_chip on the same fwnode */
|
||||
if (is_of_node(fwnode) &&
|
||||
of_node_check_flag(to_of_node(fwnode), OF_POPULATED))
|
||||
continue;
|
||||
|
||||
ret = gpiochip_add_hog(gc, fwnode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (is_of_node(fwnode))
|
||||
of_node_set_flag(to_of_node(fwnode), OF_POPULATED);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1291,7 +1299,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
|||
|
||||
ret = gpiochip_hog_lines(gc);
|
||||
if (ret)
|
||||
goto err_remove_of_chip;
|
||||
goto err_free_hogs;
|
||||
|
||||
ret = gpiochip_irqchip_init_valid_mask(gc);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -394,7 +394,8 @@ void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa,
|
|||
uint64_t start_page, uint64_t num_pages,
|
||||
uint64_t flags, void *dst)
|
||||
{
|
||||
u32 i, idx;
|
||||
u32 i, j, t, idx;
|
||||
u64 page_base;
|
||||
|
||||
/* The SYSTEM flag indicates the pages aren't in VRAM. */
|
||||
WARN_ON_ONCE(flags & AMDGPU_PTE_SYSTEM);
|
||||
|
|
@ -402,9 +403,12 @@ void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa,
|
|||
if (!drm_dev_enter(adev_to_drm(adev), &idx))
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_pages; ++i) {
|
||||
amdgpu_gmc_set_pte_pde(adev, dst,
|
||||
start_page + i, pa + AMDGPU_GPU_PAGE_SIZE * i, flags);
|
||||
page_base = pa;
|
||||
for (i = 0, t = 0; i < num_pages; i++) {
|
||||
for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) {
|
||||
amdgpu_gmc_set_pte_pde(adev, dst, start_page + t, page_base, flags);
|
||||
page_base += AMDGPU_GPU_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
drm_dev_exit(idx);
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr,
|
|||
/*
|
||||
* The following is for PTE only. GART does not have PDEs.
|
||||
*/
|
||||
value = addr & 0x0000FFFFFFFFF000ULL;
|
||||
value = addr & adev->gmc.pte_addr_mask;
|
||||
value |= flags;
|
||||
writeq(value, ptr + (gpu_page_idx * 8));
|
||||
|
||||
|
|
@ -1003,7 +1003,7 @@ void amdgpu_gmc_noretry_set(struct amdgpu_device *adev)
|
|||
gc_ver == IP_VERSION(9, 4, 3) ||
|
||||
gc_ver == IP_VERSION(9, 4, 4) ||
|
||||
gc_ver == IP_VERSION(9, 5, 0) ||
|
||||
gc_ver >= IP_VERSION(10, 3, 0));
|
||||
gc_ver >= IP_VERSION(10, 1, 0));
|
||||
|
||||
if (!amdgpu_sriov_xnack_support(adev))
|
||||
gmc->noretry = 1;
|
||||
|
|
|
|||
|
|
@ -280,6 +280,7 @@ struct amdgpu_gmc {
|
|||
u64 real_vram_size;
|
||||
int vram_mtrr;
|
||||
u64 mc_mask;
|
||||
uint64_t pte_addr_mask;
|
||||
const struct firmware *fw; /* MC firmware */
|
||||
uint32_t fw_version;
|
||||
struct amdgpu_irq_src vm_fault;
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ int amdgpu_gtt_mgr_alloc_entries(struct amdgpu_gtt_mgr *mgr,
|
|||
int r;
|
||||
|
||||
/* Align to TLB L2 cache entry size to work around "V bit HW bug" */
|
||||
if (adev->asic_type == CHIP_TAHITI) {
|
||||
if (adev->family == AMDGPU_FAMILY_SI) {
|
||||
alignment = 32 * 1024 / AMDGPU_GPU_PAGE_SIZE;
|
||||
num_pages = ALIGN(num_pages, alignment);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ static bool amdgpu_hmm_invalidate_gfx(struct mmu_interval_notifier *mni,
|
|||
{
|
||||
struct amdgpu_bo *bo = container_of(mni, struct amdgpu_bo, notifier);
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
|
||||
struct amdgpu_bo *vm_root = bo->vm_bo->vm->root.bo;
|
||||
long r;
|
||||
|
||||
if (!mmu_notifier_range_blockable(range))
|
||||
|
|
@ -77,8 +78,9 @@ static bool amdgpu_hmm_invalidate_gfx(struct mmu_interval_notifier *mni,
|
|||
mmu_interval_set_seq(mni, cur_seq);
|
||||
|
||||
amdgpu_vm_bo_invalidate(bo, false);
|
||||
r = dma_resv_wait_timeout(bo->tbo.base.resv, DMA_RESV_USAGE_BOOKKEEP,
|
||||
false, MAX_SCHEDULE_TIMEOUT);
|
||||
r = dma_resv_wait_timeout(vm_root->tbo.base.resv,
|
||||
DMA_RESV_USAGE_BOOKKEEP, false,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
mutex_unlock(&adev->notifier_lock);
|
||||
if (r <= 0)
|
||||
DRM_ERROR("(%ld) failed to wait for user bo\n", r);
|
||||
|
|
|
|||
|
|
@ -173,16 +173,17 @@ void amdgpu_seq64_unmap(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv)
|
|||
int amdgpu_seq64_alloc(struct amdgpu_device *adev, u64 *va,
|
||||
u64 *gpu_addr, u64 **cpu_addr)
|
||||
{
|
||||
unsigned long bit_pos;
|
||||
unsigned long bit_pos = 0;
|
||||
|
||||
for (;;) {
|
||||
bit_pos = find_first_zero_bit(adev->seq64.used, adev->seq64.num_sem);
|
||||
do {
|
||||
bit_pos = find_next_zero_bit(adev->seq64.used,
|
||||
adev->seq64.num_sem, bit_pos);
|
||||
if (bit_pos >= adev->seq64.num_sem)
|
||||
return -ENOSPC;
|
||||
|
||||
if (!test_and_set_bit(bit_pos, adev->seq64.used))
|
||||
break;
|
||||
}
|
||||
bit_pos++;
|
||||
} while (1);
|
||||
|
||||
*va = bit_pos * sizeof(u64) + amdgpu_seq64_get_va_base(adev);
|
||||
|
||||
|
|
|
|||
|
|
@ -532,10 +532,6 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
|
|||
amdgpu_bo_unreserve(queue->db_obj.obj);
|
||||
amdgpu_bo_unref(&queue->db_obj.obj);
|
||||
|
||||
amdgpu_bo_reserve(queue->wptr_obj.obj, true);
|
||||
amdgpu_bo_unpin(queue->wptr_obj.obj);
|
||||
amdgpu_bo_unreserve(queue->wptr_obj.obj);
|
||||
amdgpu_bo_unref(&queue->wptr_obj.obj);
|
||||
kfree(queue);
|
||||
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
|
|
@ -887,7 +883,7 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
|
|||
continue;
|
||||
}
|
||||
|
||||
r = amdgpu_userq_restore_helper(queue);
|
||||
r = amdgpu_userq_map_helper(queue);
|
||||
if (r)
|
||||
ret = r;
|
||||
|
||||
|
|
@ -1124,7 +1120,7 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
|
|||
|
||||
/* Try to unmap all the queues in this process ctx */
|
||||
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
|
||||
r = amdgpu_userq_preempt_helper(queue);
|
||||
r = amdgpu_userq_unmap_helper(queue);
|
||||
if (r)
|
||||
ret = r;
|
||||
}
|
||||
|
|
@ -1344,8 +1340,7 @@ int amdgpu_userq_start_sched_for_enforce_isolation(struct amdgpu_device *adev,
|
|||
}
|
||||
|
||||
void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_va_mapping *mapping,
|
||||
uint64_t saddr)
|
||||
struct amdgpu_bo_va_mapping *mapping)
|
||||
{
|
||||
u32 ip_mask = amdgpu_userq_get_supported_ip_mask(adev);
|
||||
struct amdgpu_bo_va *bo_va = mapping->bo_va;
|
||||
|
|
@ -1354,12 +1349,9 @@ void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
|
|||
if (!ip_mask)
|
||||
return;
|
||||
|
||||
dev_warn_once(adev->dev, "now unmapping a vital queue va:%llx\n", saddr);
|
||||
/**
|
||||
* The userq VA mapping reservation should include the eviction fence,
|
||||
* if the eviction fence can't signal successfully during unmapping,
|
||||
* then driver will warn to flag this improper unmap of the userq VA.
|
||||
* Note: The eviction fence may be attached to different BOs, and this
|
||||
* The userq VA mapping reservation should include the eviction fence.
|
||||
* Note: The eviction fence may be attached to different BOs and this
|
||||
* unmap is only for one kind of userq VAs, so at this point suppose
|
||||
* the eviction fence is always unsignaled.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -182,6 +182,5 @@ int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
|
|||
u64 addr, u64 expected_size, u64 *va_out);
|
||||
|
||||
void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_va_mapping *mapping,
|
||||
uint64_t saddr);
|
||||
struct amdgpu_bo_va_mapping *mapping);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2006,7 +2006,7 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
|
|||
* from user space.
|
||||
*/
|
||||
if (unlikely(bo_va->userq_va_mapped))
|
||||
amdgpu_userq_gem_va_unmap_validate(adev, mapping, saddr);
|
||||
amdgpu_userq_gem_va_unmap_validate(adev, mapping);
|
||||
|
||||
list_del(&mapping->list);
|
||||
amdgpu_vm_it_remove(mapping, &vm->va);
|
||||
|
|
|
|||
|
|
@ -449,12 +449,10 @@ static void gfxhub_v11_5_0_set_fault_enable_default(struct amdgpu_device *adev,
|
|||
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
if (!value) {
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, 1);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, 1);
|
||||
}
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, !value);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, !value);
|
||||
WREG32_SOC15(GC, 0, regGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -454,12 +454,10 @@ static void gfxhub_v12_0_set_fault_enable_default(struct amdgpu_device *adev,
|
|||
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
if (!value) {
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, 1);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, 1);
|
||||
}
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, !value);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, !value);
|
||||
WREG32_SOC15(GC, 0, regGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -633,19 +633,17 @@ static void gfxhub_v12_1_xcc_set_fault_enable_default(struct amdgpu_device *adev
|
|||
tmp = REG_SET_FIELD(tmp,
|
||||
GCVM_L2_PROTECTION_FAULT_CNTL_LO32,
|
||||
OTHER_CLIENT_ID_NO_RETRY_FAULT_INTERRUPT, value);
|
||||
if (!value)
|
||||
tmp = REG_SET_FIELD(tmp,
|
||||
GCVM_L2_PROTECTION_FAULT_CNTL_LO32,
|
||||
CRASH_ON_NO_RETRY_FAULT, 1);
|
||||
tmp = REG_SET_FIELD(tmp,
|
||||
GCVM_L2_PROTECTION_FAULT_CNTL_LO32,
|
||||
CRASH_ON_NO_RETRY_FAULT, !value);
|
||||
WREG32_SOC15(GC, GET_INST(GC, i),
|
||||
regGCVM_L2_PROTECTION_FAULT_CNTL_LO32, tmp);
|
||||
|
||||
tmp = RREG32_SOC15(GC, GET_INST(GC, i),
|
||||
regGCVM_L2_PROTECTION_FAULT_CNTL_HI32);
|
||||
if (!value)
|
||||
tmp = REG_SET_FIELD(tmp,
|
||||
GCVM_L2_PROTECTION_FAULT_CNTL_HI32,
|
||||
CRASH_ON_RETRY_FAULT, 1);
|
||||
tmp = REG_SET_FIELD(tmp,
|
||||
GCVM_L2_PROTECTION_FAULT_CNTL_HI32,
|
||||
CRASH_ON_RETRY_FAULT, !value);
|
||||
WREG32_SOC15(GC, GET_INST(GC, i),
|
||||
regGCVM_L2_PROTECTION_FAULT_CNTL_HI32, tmp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -403,12 +403,10 @@ static void gfxhub_v1_0_set_fault_enable_default(struct amdgpu_device *adev,
|
|||
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
|
||||
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
if (!value) {
|
||||
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, 1);
|
||||
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, 1);
|
||||
}
|
||||
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, !value);
|
||||
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, !value);
|
||||
WREG32_SOC15(GC, 0, mmVM_L2_PROTECTION_FAULT_CNTL, tmp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -516,12 +516,10 @@ static void gfxhub_v1_2_xcc_set_fault_enable_default(struct amdgpu_device *adev,
|
|||
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
|
||||
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
if (!value) {
|
||||
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, 1);
|
||||
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, 1);
|
||||
}
|
||||
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, !value);
|
||||
tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, !value);
|
||||
WREG32_SOC15(GC, GET_INST(GC, i), regVM_L2_PROTECTION_FAULT_CNTL, tmp);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -418,12 +418,10 @@ static void gfxhub_v2_0_set_fault_enable_default(struct amdgpu_device *adev,
|
|||
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
if (!value) {
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, 1);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, 1);
|
||||
}
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, !value);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, !value);
|
||||
WREG32_SOC15(GC, 0, mmGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -449,12 +449,10 @@ static void gfxhub_v2_1_set_fault_enable_default(struct amdgpu_device *adev,
|
|||
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
if (!value) {
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, 1);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, 1);
|
||||
}
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, !value);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, !value);
|
||||
WREG32_SOC15(GC, 0, mmGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -446,12 +446,10 @@ static void gfxhub_v3_0_set_fault_enable_default(struct amdgpu_device *adev,
|
|||
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
if (!value) {
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, 1);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, 1);
|
||||
}
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, !value);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, !value);
|
||||
WREG32_SOC15(GC, 0, regGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -434,12 +434,10 @@ static void gfxhub_v3_0_3_set_fault_enable_default(struct amdgpu_device *adev,
|
|||
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
|
||||
if (!value) {
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, 1);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, 1);
|
||||
}
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_NO_RETRY_FAULT, !value);
|
||||
tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
|
||||
CRASH_ON_RETRY_FAULT, !value);
|
||||
WREG32_SOC15(GC, 0, regGCVM_L2_PROTECTION_FAULT_CNTL, tmp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -847,6 +847,7 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
|
|||
* internal address space.
|
||||
*/
|
||||
adev->gmc.mc_mask = 0xffffffffffffULL; /* 48 bit MC */
|
||||
adev->gmc.pte_addr_mask = 0x0000FFFFFFFFF000ULL; /* 48 bit PA */
|
||||
|
||||
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(44));
|
||||
if (r) {
|
||||
|
|
|
|||
|
|
@ -821,6 +821,7 @@ static int gmc_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
|
|||
* internal address space.
|
||||
*/
|
||||
adev->gmc.mc_mask = 0xffffffffffffULL; /* 48 bit MC */
|
||||
adev->gmc.pte_addr_mask = 0x0000FFFFFFFFF000ULL; /* 48 bit PA */
|
||||
|
||||
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(44));
|
||||
if (r) {
|
||||
|
|
|
|||
|
|
@ -812,8 +812,9 @@ static int gmc_v12_0_gart_init(struct amdgpu_device *adev)
|
|||
|
||||
static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
{
|
||||
int r, vram_width = 0, vram_type = 0, vram_vendor = 0;
|
||||
int r, vram_width = 0, vram_type = 0, vram_vendor = 0, dma_addr_bits;
|
||||
struct amdgpu_device *adev = ip_block->adev;
|
||||
uint64_t pte_addr_mask = 0;
|
||||
int i;
|
||||
|
||||
adev->mmhub.funcs->init(adev);
|
||||
|
|
@ -843,6 +844,8 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
|
|||
* block size 512 (9bit)
|
||||
*/
|
||||
amdgpu_vm_adjust_size(adev, 256 * 1024, 9, 3, 48);
|
||||
pte_addr_mask = 0x0000FFFFFFFFF000ULL; /* 48 bit PA */
|
||||
dma_addr_bits = 44;
|
||||
break;
|
||||
case IP_VERSION(12, 1, 0):
|
||||
bitmap_set(adev->vmhubs_mask, AMDGPU_GFXHUB(0),
|
||||
|
|
@ -855,9 +858,13 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
|
|||
* block size 512 (9bit)
|
||||
*/
|
||||
amdgpu_vm_adjust_size(adev, 128 * 1024 * 1024, 9, 4, 57);
|
||||
pte_addr_mask = 0x000FFFFFFFFFF000ULL; /* 52 bit PA */
|
||||
dma_addr_bits = 52;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
dev_warn(adev->dev, "Unrecognized GC IP version: 0x%08x\n",
|
||||
amdgpu_ip_version(adev, GC_HWIP, 0));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* This interrupt is VMC page fault.*/
|
||||
|
|
@ -911,14 +918,15 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
|
|||
* internal address space.
|
||||
*/
|
||||
adev->gmc.mc_mask = AMDGPU_GMC_HOLE_MASK;
|
||||
adev->gmc.pte_addr_mask = pte_addr_mask;
|
||||
|
||||
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(44));
|
||||
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(dma_addr_bits));
|
||||
if (r) {
|
||||
drm_warn(adev_to_drm(adev), "No suitable DMA available.\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
adev->need_swiotlb = drm_need_swiotlb(44);
|
||||
adev->need_swiotlb = drm_need_swiotlb(dma_addr_bits);
|
||||
|
||||
r = gmc_v12_0_mc_init(adev);
|
||||
if (r)
|
||||
|
|
|
|||
|
|
@ -836,6 +836,7 @@ static int gmc_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
|
|||
amdgpu_vm_adjust_size(adev, 64, 9, 1, 40);
|
||||
|
||||
adev->gmc.mc_mask = 0xffffffffffULL;
|
||||
adev->gmc.pte_addr_mask = 0x000000FFFFFFF000ULL;
|
||||
|
||||
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(40));
|
||||
if (r) {
|
||||
|
|
|
|||
|
|
@ -1016,6 +1016,7 @@ static int gmc_v7_0_sw_init(struct amdgpu_ip_block *ip_block)
|
|||
* internal address space.
|
||||
*/
|
||||
adev->gmc.mc_mask = 0xffffffffffULL; /* 40 bit MC */
|
||||
adev->gmc.pte_addr_mask = 0x000000FFFFFFF000ULL; /* 40 bit PA */
|
||||
|
||||
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(40));
|
||||
if (r) {
|
||||
|
|
|
|||
|
|
@ -1131,6 +1131,7 @@ static int gmc_v8_0_sw_init(struct amdgpu_ip_block *ip_block)
|
|||
* internal address space.
|
||||
*/
|
||||
adev->gmc.mc_mask = 0xffffffffffULL; /* 40 bit MC */
|
||||
adev->gmc.pte_addr_mask = 0x000000FFFFFFF000ULL; /* 40 bit PA */
|
||||
|
||||
r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(40));
|
||||
if (r) {
|
||||
|
|
|
|||
|
|
@ -1994,6 +1994,7 @@ static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block)
|
|||
* internal address space.
|
||||
*/
|
||||
adev->gmc.mc_mask = 0xffffffffffffULL; /* 48 bit MC */
|
||||
adev->gmc.pte_addr_mask = 0x0000FFFFFFFFF000ULL; /* 48 bit PA */
|
||||
|
||||
dma_addr_bits = amdgpu_ip_version(adev, GC_HWIP, 0) >=
|
||||
IP_VERSION(9, 4, 2) ?
|
||||
|
|
|
|||
|
|
@ -467,6 +467,11 @@ static void mes_userq_mqd_destroy(struct amdgpu_usermode_queue *queue)
|
|||
kfree(queue->userq_prop);
|
||||
amdgpu_bo_free_kernel(&queue->mqd.obj, &queue->mqd.gpu_addr,
|
||||
&queue->mqd.cpu_ptr);
|
||||
|
||||
amdgpu_bo_reserve(queue->wptr_obj.obj, true);
|
||||
amdgpu_bo_unpin(queue->wptr_obj.obj);
|
||||
amdgpu_bo_unreserve(queue->wptr_obj.obj);
|
||||
amdgpu_bo_unref(&queue->wptr_obj.obj);
|
||||
}
|
||||
|
||||
static int mes_userq_preempt(struct amdgpu_usermode_queue *queue)
|
||||
|
|
|
|||
|
|
@ -1316,6 +1316,7 @@ static int sdma_v7_1_sw_init(struct amdgpu_ip_block *ip_block)
|
|||
ring->ring_obj = NULL;
|
||||
ring->use_doorbell = true;
|
||||
ring->me = i;
|
||||
ring->no_user_submission = adev->sdma.no_user_submission;
|
||||
|
||||
for (xcc_id = 0; xcc_id < fls(adev->gfx.xcc_mask); xcc_id++) {
|
||||
if (adev->sdma.instance[i].xcc_id == GET_INST(GC, xcc_id))
|
||||
|
|
|
|||
|
|
@ -2502,6 +2502,9 @@ static int wait_on_destroy_queue(struct device_queue_manager *dqm,
|
|||
if (pdd->qpd.is_debug)
|
||||
return ret;
|
||||
|
||||
if (q->properties.is_being_destroyed)
|
||||
return -EBUSY;
|
||||
|
||||
q->properties.is_being_destroyed = true;
|
||||
|
||||
if (pdd->process->debug_trap_enabled && q->properties.is_suspended) {
|
||||
|
|
@ -2514,6 +2517,9 @@ static int wait_on_destroy_queue(struct device_queue_manager *dqm,
|
|||
dqm_lock(dqm);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
q->properties.is_being_destroyed = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -2607,7 +2613,7 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm,
|
|||
return retval;
|
||||
|
||||
failed_try_destroy_debugged_queue:
|
||||
|
||||
q->properties.is_being_destroyed = false;
|
||||
dqm_unlock(dqm);
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -3309,7 +3315,7 @@ static void copy_context_work_handler(struct work_struct *work)
|
|||
static uint32_t *get_queue_ids(uint32_t num_queues, uint32_t *usr_queue_id_array)
|
||||
{
|
||||
if (!usr_queue_id_array)
|
||||
return NULL;
|
||||
return num_queues ? ERR_PTR(-EINVAL) : NULL;
|
||||
|
||||
if (num_queues > KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
|
|
|||
|
|
@ -320,8 +320,7 @@ static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, voi
|
|||
|
||||
static void restore_mqd(struct mqd_manager *mm, void **mqd,
|
||||
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
|
||||
struct queue_properties *qp,
|
||||
const void *mqd_src,
|
||||
struct queue_properties *qp, const void *mqd_src,
|
||||
const void *ctl_stack_src, const u32 ctl_stack_size)
|
||||
{
|
||||
uint64_t addr;
|
||||
|
|
@ -337,14 +336,48 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
|
|||
*gart_addr = addr;
|
||||
|
||||
m->cp_hqd_pq_doorbell_control =
|
||||
qp->doorbell_off <<
|
||||
CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
|
||||
pr_debug("cp_hqd_pq_doorbell_control 0x%x\n",
|
||||
m->cp_hqd_pq_doorbell_control);
|
||||
qp->doorbell_off << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
|
||||
pr_debug("cp_hqd_pq_doorbell_control 0x%x\n", m->cp_hqd_pq_doorbell_control);
|
||||
|
||||
qp->is_active = 0;
|
||||
}
|
||||
|
||||
static void checkpoint_mqd_sdma(struct mqd_manager *mm,
|
||||
void *mqd,
|
||||
void *mqd_dst,
|
||||
void *ctl_stack_dst)
|
||||
{
|
||||
struct v11_sdma_mqd *m;
|
||||
|
||||
m = get_sdma_mqd(mqd);
|
||||
|
||||
memcpy(mqd_dst, m, sizeof(struct v11_sdma_mqd));
|
||||
}
|
||||
|
||||
static void restore_mqd_sdma(struct mqd_manager *mm, void **mqd,
|
||||
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
|
||||
struct queue_properties *qp,
|
||||
const void *mqd_src,
|
||||
const void *ctl_stack_src,
|
||||
const u32 ctl_stack_size)
|
||||
{
|
||||
uint64_t addr;
|
||||
struct v11_sdma_mqd *m;
|
||||
|
||||
m = (struct v11_sdma_mqd *) mqd_mem_obj->cpu_ptr;
|
||||
addr = mqd_mem_obj->gpu_addr;
|
||||
|
||||
memcpy(m, mqd_src, sizeof(*m));
|
||||
|
||||
m->sdmax_rlcx_doorbell_offset =
|
||||
qp->doorbell_off << SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
|
||||
|
||||
*mqd = m;
|
||||
if (gart_addr)
|
||||
*gart_addr = addr;
|
||||
|
||||
qp->is_active = 0;
|
||||
}
|
||||
|
||||
static void init_mqd_hiq(struct mqd_manager *mm, void **mqd,
|
||||
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
|
||||
|
|
@ -529,8 +562,8 @@ struct mqd_manager *mqd_manager_init_v11(enum KFD_MQD_TYPE type,
|
|||
mqd->update_mqd = update_mqd_sdma;
|
||||
mqd->destroy_mqd = kfd_destroy_mqd_sdma;
|
||||
mqd->is_occupied = kfd_is_occupied_sdma;
|
||||
mqd->checkpoint_mqd = checkpoint_mqd;
|
||||
mqd->restore_mqd = restore_mqd;
|
||||
mqd->checkpoint_mqd = checkpoint_mqd_sdma;
|
||||
mqd->restore_mqd = restore_mqd_sdma;
|
||||
mqd->mqd_size = sizeof(struct v11_sdma_mqd);
|
||||
mqd->mqd_stride = kfd_mqd_stride;
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
|
|
|||
|
|
@ -1344,8 +1344,13 @@ static ssize_t dp_sdp_message_debugfs_write(struct file *f, const char __user *b
|
|||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
if (!connector->base.state || !connector->base.state->crtc)
|
||||
return -ENODEV;
|
||||
|
||||
acrtc_state = to_dm_crtc_state(connector->base.state->crtc->state);
|
||||
|
||||
write_size = min_t(size_t, size, sizeof(data));
|
||||
|
||||
r = copy_from_user(data, buf, write_size);
|
||||
|
||||
write_size -= r;
|
||||
|
|
|
|||
|
|
@ -289,8 +289,8 @@ bool dal_vector_reserve(struct vector *vector, uint32_t capacity)
|
|||
if (capacity <= vector->capacity)
|
||||
return true;
|
||||
|
||||
new_container = krealloc(vector->container,
|
||||
capacity * vector->struct_size, GFP_KERNEL);
|
||||
new_container = krealloc_array(vector->container,
|
||||
capacity, vector->struct_size, GFP_KERNEL);
|
||||
|
||||
if (new_container) {
|
||||
vector->container = new_container;
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
|
|||
ATOM_COMMON_RECORD_HEADER *header;
|
||||
ATOM_I2C_RECORD *record;
|
||||
struct bios_parser *bp = BP_FROM_DCB(dcb);
|
||||
int i;
|
||||
|
||||
if (!info)
|
||||
return BP_RESULT_BADINPUT;
|
||||
|
|
@ -234,7 +235,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
|
|||
offset = le16_to_cpu(object->usRecordOffset)
|
||||
+ bp->object_info_tbl_offset;
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
|
||||
header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
|
||||
|
||||
if (!header)
|
||||
|
|
@ -293,11 +294,12 @@ static enum bp_result bios_parser_get_device_tag_record(
|
|||
{
|
||||
ATOM_COMMON_RECORD_HEADER *header;
|
||||
uint32_t offset;
|
||||
int i;
|
||||
|
||||
offset = le16_to_cpu(object->usRecordOffset)
|
||||
+ bp->object_info_tbl_offset;
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
|
||||
header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
|
||||
|
||||
if (!header)
|
||||
|
|
@ -966,6 +968,7 @@ static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
|
|||
{
|
||||
ATOM_COMMON_RECORD_HEADER *header;
|
||||
uint32_t offset;
|
||||
int i;
|
||||
|
||||
if (!object) {
|
||||
BREAK_TO_DEBUGGER(); /* Invalid object */
|
||||
|
|
@ -975,7 +978,7 @@ static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
|
|||
offset = le16_to_cpu(object->usRecordOffset)
|
||||
+ bp->object_info_tbl_offset;
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
|
||||
header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
|
||||
|
||||
if (!header)
|
||||
|
|
@ -1670,6 +1673,7 @@ static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
|
|||
{
|
||||
ATOM_COMMON_RECORD_HEADER *header;
|
||||
uint32_t offset;
|
||||
int i;
|
||||
|
||||
if (!object) {
|
||||
BREAK_TO_DEBUGGER(); /* Invalid object */
|
||||
|
|
@ -1679,7 +1683,7 @@ static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
|
|||
offset = le16_to_cpu(object->usRecordOffset)
|
||||
+ bp->object_info_tbl_offset;
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
|
||||
header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
|
||||
|
||||
if (!header)
|
||||
|
|
@ -2769,6 +2773,7 @@ static enum bp_result update_slot_layout_info(struct dc_bios *dcb,
|
|||
{
|
||||
(void)i;
|
||||
unsigned int j;
|
||||
unsigned int n;
|
||||
struct bios_parser *bp;
|
||||
ATOM_BRACKET_LAYOUT_RECORD *record;
|
||||
ATOM_COMMON_RECORD_HEADER *record_header;
|
||||
|
|
@ -2778,7 +2783,7 @@ static enum bp_result update_slot_layout_info(struct dc_bios *dcb,
|
|||
record = NULL;
|
||||
record_header = NULL;
|
||||
|
||||
for (;;) {
|
||||
for (n = 0; n < BIOS_MAX_NUM_RECORD; n++) {
|
||||
|
||||
record_header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
|
||||
if (record_header == NULL) {
|
||||
|
|
|
|||
|
|
@ -396,6 +396,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
|
|||
struct atom_i2c_record *record;
|
||||
struct atom_i2c_record dummy_record = {0};
|
||||
struct bios_parser *bp = BP_FROM_DCB(dcb);
|
||||
int i;
|
||||
|
||||
if (!info)
|
||||
return BP_RESULT_BADINPUT;
|
||||
|
|
@ -429,7 +430,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
|
|||
break;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
|
||||
header = GET_IMAGE(struct atom_common_record_header, offset);
|
||||
|
||||
if (!header)
|
||||
|
|
@ -534,6 +535,7 @@ static struct atom_hpd_int_record *get_hpd_record_for_path_v3(struct bios_parser
|
|||
{
|
||||
struct atom_common_record_header *header;
|
||||
uint32_t offset;
|
||||
int i;
|
||||
|
||||
if (!object) {
|
||||
BREAK_TO_DEBUGGER(); /* Invalid object */
|
||||
|
|
@ -542,7 +544,7 @@ static struct atom_hpd_int_record *get_hpd_record_for_path_v3(struct bios_parser
|
|||
|
||||
offset = object->disp_recordoffset + bp->object_info_tbl_offset;
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
|
||||
header = GET_IMAGE(struct atom_common_record_header, offset);
|
||||
|
||||
if (!header)
|
||||
|
|
@ -611,6 +613,7 @@ static struct atom_hpd_int_record *get_hpd_record(
|
|||
{
|
||||
struct atom_common_record_header *header;
|
||||
uint32_t offset;
|
||||
int i;
|
||||
|
||||
if (!object) {
|
||||
BREAK_TO_DEBUGGER(); /* Invalid object */
|
||||
|
|
@ -620,7 +623,7 @@ static struct atom_hpd_int_record *get_hpd_record(
|
|||
offset = le16_to_cpu(object->disp_recordoffset)
|
||||
+ bp->object_info_tbl_offset;
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
|
||||
header = GET_IMAGE(struct atom_common_record_header, offset);
|
||||
|
||||
if (!header)
|
||||
|
|
@ -701,8 +704,10 @@ static enum bp_result bios_parser_get_gpio_pin_info(
|
|||
info->offset_en = info->offset + 1;
|
||||
info->offset_mask = info->offset - 1;
|
||||
|
||||
info->mask = (uint32_t) (1 <<
|
||||
header->gpio_pin[i].gpio_bitshift);
|
||||
if (header->gpio_pin[i].gpio_bitshift >= 32)
|
||||
return BP_RESULT_BADBIOSTABLE;
|
||||
|
||||
info->mask = 1u << header->gpio_pin[i].gpio_bitshift;
|
||||
info->mask_y = info->mask + 2;
|
||||
info->mask_en = info->mask + 1;
|
||||
info->mask_mask = info->mask - 1;
|
||||
|
|
@ -2193,6 +2198,7 @@ static struct atom_encoder_caps_record *get_encoder_cap_record(
|
|||
{
|
||||
struct atom_common_record_header *header;
|
||||
uint32_t offset;
|
||||
int i;
|
||||
|
||||
if (!object) {
|
||||
BREAK_TO_DEBUGGER(); /* Invalid object */
|
||||
|
|
@ -2201,7 +2207,7 @@ static struct atom_encoder_caps_record *get_encoder_cap_record(
|
|||
|
||||
offset = object->encoder_recordoffset + bp->object_info_tbl_offset;
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
|
||||
header = GET_IMAGE(struct atom_common_record_header, offset);
|
||||
|
||||
if (!header)
|
||||
|
|
@ -2230,6 +2236,7 @@ static struct atom_disp_connector_caps_record *get_disp_connector_caps_record(
|
|||
{
|
||||
struct atom_common_record_header *header;
|
||||
uint32_t offset;
|
||||
int i;
|
||||
|
||||
if (!object) {
|
||||
BREAK_TO_DEBUGGER(); /* Invalid object */
|
||||
|
|
@ -2238,7 +2245,7 @@ static struct atom_disp_connector_caps_record *get_disp_connector_caps_record(
|
|||
|
||||
offset = object->disp_recordoffset + bp->object_info_tbl_offset;
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
|
||||
header = GET_IMAGE(struct atom_common_record_header, offset);
|
||||
|
||||
if (!header)
|
||||
|
|
@ -2266,6 +2273,7 @@ static struct atom_connector_caps_record *get_connector_caps_record(struct bios_
|
|||
{
|
||||
struct atom_common_record_header *header;
|
||||
uint32_t offset;
|
||||
int i;
|
||||
|
||||
if (!object) {
|
||||
BREAK_TO_DEBUGGER(); /* Invalid object */
|
||||
|
|
@ -2274,7 +2282,7 @@ static struct atom_connector_caps_record *get_connector_caps_record(struct bios_
|
|||
|
||||
offset = object->disp_recordoffset + bp->object_info_tbl_offset;
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
|
||||
header = GET_IMAGE(struct atom_common_record_header, offset);
|
||||
|
||||
if (!header)
|
||||
|
|
@ -2352,6 +2360,7 @@ static struct atom_connector_speed_record *get_connector_speed_cap_record(struct
|
|||
{
|
||||
struct atom_common_record_header *header;
|
||||
uint32_t offset;
|
||||
int i;
|
||||
|
||||
if (!object) {
|
||||
BREAK_TO_DEBUGGER(); /* Invalid object */
|
||||
|
|
@ -2360,7 +2369,7 @@ static struct atom_connector_speed_record *get_connector_speed_cap_record(struct
|
|||
|
||||
offset = object->disp_recordoffset + bp->object_info_tbl_offset;
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) {
|
||||
header = GET_IMAGE(struct atom_common_record_header, offset);
|
||||
|
||||
if (!header)
|
||||
|
|
@ -2600,14 +2609,16 @@ static enum bp_result get_integrated_info_v11(
|
|||
info_v11->extdispconninfo.checksum;
|
||||
|
||||
info->dp0_ext_hdmi_slv_addr = info_v11->dp0_retimer_set.HdmiSlvAddr;
|
||||
info->dp0_ext_hdmi_reg_num = info_v11->dp0_retimer_set.HdmiRegNum;
|
||||
info->dp0_ext_hdmi_reg_num = min_t(u8, info_v11->dp0_retimer_set.HdmiRegNum,
|
||||
ARRAY_SIZE(info->dp0_ext_hdmi_reg_settings));
|
||||
for (i = 0; i < info->dp0_ext_hdmi_reg_num; i++) {
|
||||
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_index =
|
||||
info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
|
||||
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_val =
|
||||
info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
|
||||
}
|
||||
info->dp0_ext_hdmi_6g_reg_num = info_v11->dp0_retimer_set.Hdmi6GRegNum;
|
||||
info->dp0_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp0_retimer_set.Hdmi6GRegNum,
|
||||
ARRAY_SIZE(info->dp0_ext_hdmi_6g_reg_settings));
|
||||
for (i = 0; i < info->dp0_ext_hdmi_6g_reg_num; i++) {
|
||||
info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
|
||||
info_v11->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
|
||||
|
|
@ -2616,14 +2627,16 @@ static enum bp_result get_integrated_info_v11(
|
|||
}
|
||||
|
||||
info->dp1_ext_hdmi_slv_addr = info_v11->dp1_retimer_set.HdmiSlvAddr;
|
||||
info->dp1_ext_hdmi_reg_num = info_v11->dp1_retimer_set.HdmiRegNum;
|
||||
info->dp1_ext_hdmi_reg_num = min_t(u8, info_v11->dp1_retimer_set.HdmiRegNum,
|
||||
ARRAY_SIZE(info->dp1_ext_hdmi_reg_settings));
|
||||
for (i = 0; i < info->dp1_ext_hdmi_reg_num; i++) {
|
||||
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_index =
|
||||
info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
|
||||
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_val =
|
||||
info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
|
||||
}
|
||||
info->dp1_ext_hdmi_6g_reg_num = info_v11->dp1_retimer_set.Hdmi6GRegNum;
|
||||
info->dp1_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp1_retimer_set.Hdmi6GRegNum,
|
||||
ARRAY_SIZE(info->dp1_ext_hdmi_6g_reg_settings));
|
||||
for (i = 0; i < info->dp1_ext_hdmi_6g_reg_num; i++) {
|
||||
info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
|
||||
info_v11->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
|
||||
|
|
@ -2632,14 +2645,16 @@ static enum bp_result get_integrated_info_v11(
|
|||
}
|
||||
|
||||
info->dp2_ext_hdmi_slv_addr = info_v11->dp2_retimer_set.HdmiSlvAddr;
|
||||
info->dp2_ext_hdmi_reg_num = info_v11->dp2_retimer_set.HdmiRegNum;
|
||||
info->dp2_ext_hdmi_reg_num = min_t(u8, info_v11->dp2_retimer_set.HdmiRegNum,
|
||||
ARRAY_SIZE(info->dp2_ext_hdmi_reg_settings));
|
||||
for (i = 0; i < info->dp2_ext_hdmi_reg_num; i++) {
|
||||
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_index =
|
||||
info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
|
||||
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_val =
|
||||
info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
|
||||
}
|
||||
info->dp2_ext_hdmi_6g_reg_num = info_v11->dp2_retimer_set.Hdmi6GRegNum;
|
||||
info->dp2_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp2_retimer_set.Hdmi6GRegNum,
|
||||
ARRAY_SIZE(info->dp2_ext_hdmi_6g_reg_settings));
|
||||
for (i = 0; i < info->dp2_ext_hdmi_6g_reg_num; i++) {
|
||||
info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
|
||||
info_v11->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
|
||||
|
|
@ -2648,14 +2663,16 @@ static enum bp_result get_integrated_info_v11(
|
|||
}
|
||||
|
||||
info->dp3_ext_hdmi_slv_addr = info_v11->dp3_retimer_set.HdmiSlvAddr;
|
||||
info->dp3_ext_hdmi_reg_num = info_v11->dp3_retimer_set.HdmiRegNum;
|
||||
info->dp3_ext_hdmi_reg_num = min_t(u8, info_v11->dp3_retimer_set.HdmiRegNum,
|
||||
ARRAY_SIZE(info->dp3_ext_hdmi_reg_settings));
|
||||
for (i = 0; i < info->dp3_ext_hdmi_reg_num; i++) {
|
||||
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_index =
|
||||
info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
|
||||
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_val =
|
||||
info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
|
||||
}
|
||||
info->dp3_ext_hdmi_6g_reg_num = info_v11->dp3_retimer_set.Hdmi6GRegNum;
|
||||
info->dp3_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp3_retimer_set.Hdmi6GRegNum,
|
||||
ARRAY_SIZE(info->dp3_ext_hdmi_6g_reg_settings));
|
||||
for (i = 0; i < info->dp3_ext_hdmi_6g_reg_num; i++) {
|
||||
info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
|
||||
info_v11->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
|
||||
|
|
@ -2805,14 +2822,16 @@ static enum bp_result get_integrated_info_v2_1(
|
|||
info->ext_disp_conn_info.checksum =
|
||||
info_v2_1->extdispconninfo.checksum;
|
||||
info->dp0_ext_hdmi_slv_addr = info_v2_1->dp0_retimer_set.HdmiSlvAddr;
|
||||
info->dp0_ext_hdmi_reg_num = info_v2_1->dp0_retimer_set.HdmiRegNum;
|
||||
info->dp0_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp0_retimer_set.HdmiRegNum,
|
||||
ARRAY_SIZE(info->dp0_ext_hdmi_reg_settings));
|
||||
for (i = 0; i < info->dp0_ext_hdmi_reg_num; i++) {
|
||||
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_index =
|
||||
info_v2_1->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
|
||||
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_val =
|
||||
info_v2_1->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
|
||||
}
|
||||
info->dp0_ext_hdmi_6g_reg_num = info_v2_1->dp0_retimer_set.Hdmi6GRegNum;
|
||||
info->dp0_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp0_retimer_set.Hdmi6GRegNum,
|
||||
ARRAY_SIZE(info->dp0_ext_hdmi_6g_reg_settings));
|
||||
for (i = 0; i < info->dp0_ext_hdmi_6g_reg_num; i++) {
|
||||
info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
|
||||
info_v2_1->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
|
||||
|
|
@ -2820,14 +2839,16 @@ static enum bp_result get_integrated_info_v2_1(
|
|||
info_v2_1->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
|
||||
}
|
||||
info->dp1_ext_hdmi_slv_addr = info_v2_1->dp1_retimer_set.HdmiSlvAddr;
|
||||
info->dp1_ext_hdmi_reg_num = info_v2_1->dp1_retimer_set.HdmiRegNum;
|
||||
info->dp1_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp1_retimer_set.HdmiRegNum,
|
||||
ARRAY_SIZE(info->dp1_ext_hdmi_reg_settings));
|
||||
for (i = 0; i < info->dp1_ext_hdmi_reg_num; i++) {
|
||||
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_index =
|
||||
info_v2_1->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
|
||||
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_val =
|
||||
info_v2_1->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
|
||||
}
|
||||
info->dp1_ext_hdmi_6g_reg_num = info_v2_1->dp1_retimer_set.Hdmi6GRegNum;
|
||||
info->dp1_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp1_retimer_set.Hdmi6GRegNum,
|
||||
ARRAY_SIZE(info->dp1_ext_hdmi_6g_reg_settings));
|
||||
for (i = 0; i < info->dp1_ext_hdmi_6g_reg_num; i++) {
|
||||
info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
|
||||
info_v2_1->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
|
||||
|
|
@ -2835,14 +2856,16 @@ static enum bp_result get_integrated_info_v2_1(
|
|||
info_v2_1->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
|
||||
}
|
||||
info->dp2_ext_hdmi_slv_addr = info_v2_1->dp2_retimer_set.HdmiSlvAddr;
|
||||
info->dp2_ext_hdmi_reg_num = info_v2_1->dp2_retimer_set.HdmiRegNum;
|
||||
info->dp2_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp2_retimer_set.HdmiRegNum,
|
||||
ARRAY_SIZE(info->dp2_ext_hdmi_reg_settings));
|
||||
for (i = 0; i < info->dp2_ext_hdmi_reg_num; i++) {
|
||||
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_index =
|
||||
info_v2_1->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
|
||||
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_val =
|
||||
info_v2_1->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
|
||||
}
|
||||
info->dp2_ext_hdmi_6g_reg_num = info_v2_1->dp2_retimer_set.Hdmi6GRegNum;
|
||||
info->dp2_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp2_retimer_set.Hdmi6GRegNum,
|
||||
ARRAY_SIZE(info->dp2_ext_hdmi_6g_reg_settings));
|
||||
for (i = 0; i < info->dp2_ext_hdmi_6g_reg_num; i++) {
|
||||
info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
|
||||
info_v2_1->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
|
||||
|
|
@ -2850,14 +2873,16 @@ static enum bp_result get_integrated_info_v2_1(
|
|||
info_v2_1->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
|
||||
}
|
||||
info->dp3_ext_hdmi_slv_addr = info_v2_1->dp3_retimer_set.HdmiSlvAddr;
|
||||
info->dp3_ext_hdmi_reg_num = info_v2_1->dp3_retimer_set.HdmiRegNum;
|
||||
info->dp3_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp3_retimer_set.HdmiRegNum,
|
||||
ARRAY_SIZE(info->dp3_ext_hdmi_reg_settings));
|
||||
for (i = 0; i < info->dp3_ext_hdmi_reg_num; i++) {
|
||||
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_index =
|
||||
info_v2_1->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
|
||||
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_val =
|
||||
info_v2_1->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
|
||||
}
|
||||
info->dp3_ext_hdmi_6g_reg_num = info_v2_1->dp3_retimer_set.Hdmi6GRegNum;
|
||||
info->dp3_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp3_retimer_set.Hdmi6GRegNum,
|
||||
ARRAY_SIZE(info->dp3_ext_hdmi_6g_reg_settings));
|
||||
for (i = 0; i < info->dp3_ext_hdmi_6g_reg_num; i++) {
|
||||
info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
|
||||
info_v2_1->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
|
||||
|
|
@ -3245,6 +3270,7 @@ static enum bp_result update_slot_layout_info(
|
|||
{
|
||||
unsigned int record_offset;
|
||||
unsigned int j;
|
||||
unsigned int n;
|
||||
struct atom_display_object_path_v2 *object;
|
||||
struct atom_bracket_layout_record *record;
|
||||
struct atom_common_record_header *record_header;
|
||||
|
|
@ -3266,7 +3292,7 @@ static enum bp_result update_slot_layout_info(
|
|||
(object->disp_recordoffset) +
|
||||
(unsigned int)(bp->object_info_tbl_offset);
|
||||
|
||||
for (;;) {
|
||||
for (n = 0; n < BIOS_MAX_NUM_RECORD; n++) {
|
||||
|
||||
record_header = (struct atom_common_record_header *)
|
||||
GET_IMAGE(struct atom_common_record_header,
|
||||
|
|
@ -3360,6 +3386,7 @@ static enum bp_result update_slot_layout_info_v2(
|
|||
struct slot_layout_info *slot_layout_info)
|
||||
{
|
||||
unsigned int record_offset;
|
||||
unsigned int n;
|
||||
struct atom_display_object_path_v3 *object;
|
||||
struct atom_bracket_layout_record_v2 *record;
|
||||
struct atom_common_record_header *record_header;
|
||||
|
|
@ -3382,7 +3409,7 @@ static enum bp_result update_slot_layout_info_v2(
|
|||
(object->disp_recordoffset) +
|
||||
(unsigned int)(bp->object_info_tbl_offset);
|
||||
|
||||
for (;;) {
|
||||
for (n = 0; n < BIOS_MAX_NUM_RECORD; n++) {
|
||||
|
||||
record_header = (struct atom_common_record_header *)
|
||||
GET_IMAGE(struct atom_common_record_header,
|
||||
|
|
|
|||
|
|
@ -37,4 +37,9 @@ void bios_set_scratch_critical_state(struct dc_bios *bios, bool state);
|
|||
|
||||
#define GET_IMAGE(type, offset) ((type *) bios_get_image(&bp->base, offset, sizeof(type)))
|
||||
|
||||
/* Upper bound on the number of records in a VBIOS record chain. Prevents
|
||||
* unbounded looping if the VBIOS image is malformed and lacks a terminator.
|
||||
*/
|
||||
#define BIOS_MAX_NUM_RECORD 256
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1217,7 +1217,7 @@ struct dc_lttpr_caps {
|
|||
union dp_main_link_channel_coding_lttpr_cap main_link_channel_coding;
|
||||
union dp_128b_132b_supported_lttpr_link_rates supported_128b_132b_rates;
|
||||
union dp_alpm_lttpr_cap alpm;
|
||||
uint8_t aux_rd_interval[MAX_REPEATER_CNT - 1];
|
||||
uint8_t aux_rd_interval[MAX_REPEATER_CNT];
|
||||
uint8_t lttpr_ieee_oui[3]; // Always read from closest LTTPR to host
|
||||
uint8_t lttpr_device_id[6]; // Always read from closest LTTPR to host
|
||||
};
|
||||
|
|
|
|||
|
|
@ -110,7 +110,15 @@ static const struct out_csc_color_matrix global_color_matrix[] = {
|
|||
{ COLOR_SPACE_YCBCR601_LIMITED, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991,
|
||||
0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} },
|
||||
{ COLOR_SPACE_YCBCR709_LIMITED, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3,
|
||||
0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }
|
||||
0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },
|
||||
{ COLOR_SPACE_2020_RGB_FULLRANGE,
|
||||
{ 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
|
||||
{ COLOR_SPACE_2020_RGB_LIMITEDRANGE,
|
||||
{ 0x1B67, 0, 0, 0x201, 0, 0x1B67, 0, 0x201, 0, 0, 0x1B67, 0x201} },
|
||||
{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868,
|
||||
0x15B2, 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} },
|
||||
{ COLOR_SPACE_2020_YCBCR_FULL, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2,
|
||||
0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }
|
||||
};
|
||||
|
||||
static bool setup_scaling_configuration(
|
||||
|
|
|
|||
|
|
@ -88,7 +88,15 @@ static const struct out_csc_color_matrix global_color_matrix[] = {
|
|||
{ COLOR_SPACE_YCBCR601_LIMITED, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991,
|
||||
0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} },
|
||||
{ COLOR_SPACE_YCBCR709_LIMITED, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3,
|
||||
0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }
|
||||
0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },
|
||||
{ COLOR_SPACE_2020_RGB_FULLRANGE,
|
||||
{ 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
|
||||
{ COLOR_SPACE_2020_RGB_LIMITEDRANGE,
|
||||
{ 0x1B67, 0, 0, 0x201, 0, 0x1B67, 0, 0x201, 0, 0, 0x1B67, 0x201} },
|
||||
{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868,
|
||||
0x15B2, 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} },
|
||||
{ COLOR_SPACE_2020_YCBCR_FULL, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2,
|
||||
0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }
|
||||
};
|
||||
|
||||
enum csc_color_mode {
|
||||
|
|
|
|||
|
|
@ -529,7 +529,8 @@ enum mod_hdcp_status mod_hdcp_read_rx_id_list(struct mod_hdcp *hdcp)
|
|||
} else {
|
||||
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST,
|
||||
hdcp->auth.msg.hdcp2.rx_id_list,
|
||||
hdcp->auth.msg.hdcp2.rx_id_list_size);
|
||||
MIN(hdcp->auth.msg.hdcp2.rx_id_list_size,
|
||||
sizeof(hdcp->auth.msg.hdcp2.rx_id_list)));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2390,28 +2390,30 @@ static int smu_v13_0_0_enable_mgpu_fan_boost(struct smu_context *smu)
|
|||
}
|
||||
|
||||
static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
|
||||
uint32_t *current_power_limit,
|
||||
uint32_t *default_power_limit,
|
||||
uint32_t *max_power_limit,
|
||||
uint32_t *min_power_limit)
|
||||
uint32_t *current_power_limit,
|
||||
uint32_t *default_power_limit,
|
||||
uint32_t *max_power_limit,
|
||||
uint32_t *min_power_limit)
|
||||
{
|
||||
struct smu_table_context *table_context = &smu->smu_table;
|
||||
struct smu_13_0_0_powerplay_table *powerplay_table =
|
||||
(struct smu_13_0_0_powerplay_table *)table_context->power_play_table;
|
||||
PPTable_t *pptable = table_context->driver_pptable;
|
||||
SkuTable_t *skutable = &pptable->SkuTable;
|
||||
uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
|
||||
uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
|
||||
|
||||
if (smu_v13_0_get_current_power_limit(smu, &power_limit))
|
||||
power_limit = smu->adev->pm.ac_power ?
|
||||
uint32_t pp_limit = smu->adev->pm.ac_power ?
|
||||
skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
|
||||
skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
|
||||
uint32_t power_limit = 0, od_percent_upper = 0, od_percent_lower = 0;
|
||||
int ret;
|
||||
|
||||
if (current_power_limit) {
|
||||
ret = smu_v13_0_get_current_power_limit(smu, &power_limit);
|
||||
if (ret)
|
||||
*current_power_limit = pp_limit;
|
||||
}
|
||||
|
||||
if (current_power_limit)
|
||||
*current_power_limit = power_limit;
|
||||
if (default_power_limit)
|
||||
*default_power_limit = power_limit;
|
||||
*default_power_limit = pp_limit;
|
||||
|
||||
if (powerplay_table) {
|
||||
if (smu->od_enabled &&
|
||||
|
|
@ -2425,15 +2427,15 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
|
|||
}
|
||||
|
||||
dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
|
||||
od_percent_upper, od_percent_lower, power_limit);
|
||||
od_percent_upper, od_percent_lower, pp_limit);
|
||||
|
||||
if (max_power_limit) {
|
||||
*max_power_limit = msg_limit * (100 + od_percent_upper);
|
||||
*max_power_limit = pp_limit * (100 + od_percent_upper);
|
||||
*max_power_limit /= 100;
|
||||
}
|
||||
|
||||
if (min_power_limit) {
|
||||
*min_power_limit = power_limit * (100 - od_percent_lower);
|
||||
*min_power_limit = pp_limit * (100 - od_percent_lower);
|
||||
*min_power_limit /= 100;
|
||||
}
|
||||
|
||||
|
|
@ -2801,11 +2803,19 @@ static void smu_v13_0_0_i2c_control_fini(struct smu_context *smu)
|
|||
static int smu_v13_0_0_set_mp1_state(struct smu_context *smu,
|
||||
enum pp_mp1_state mp1_state)
|
||||
{
|
||||
uint32_t param;
|
||||
int ret;
|
||||
|
||||
switch (mp1_state) {
|
||||
case PP_MP1_STATE_UNLOAD:
|
||||
ret = smu_cmn_set_mp1_state(smu, mp1_state);
|
||||
/*
|
||||
* NOTE: Param 0x55 comes from PMFW 80.31.0, ignored in older versions.
|
||||
* No PMFW version check required.
|
||||
*/
|
||||
param = amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10) ?
|
||||
0x55 : 0x00;
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PrepareMp1ForUnload,
|
||||
param, NULL);
|
||||
break;
|
||||
default:
|
||||
/* Ignore others */
|
||||
|
|
|
|||
|
|
@ -2372,28 +2372,32 @@ static int smu_v13_0_7_enable_mgpu_fan_boost(struct smu_context *smu)
|
|||
}
|
||||
|
||||
static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
|
||||
uint32_t *current_power_limit,
|
||||
uint32_t *default_power_limit,
|
||||
uint32_t *max_power_limit,
|
||||
uint32_t *min_power_limit)
|
||||
uint32_t *current_power_limit,
|
||||
uint32_t *default_power_limit,
|
||||
uint32_t *max_power_limit,
|
||||
uint32_t *min_power_limit)
|
||||
{
|
||||
struct smu_table_context *table_context = &smu->smu_table;
|
||||
struct smu_13_0_7_powerplay_table *powerplay_table =
|
||||
(struct smu_13_0_7_powerplay_table *)table_context->power_play_table;
|
||||
PPTable_t *pptable = table_context->driver_pptable;
|
||||
SkuTable_t *skutable = &pptable->SkuTable;
|
||||
uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
|
||||
uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
|
||||
|
||||
if (smu_v13_0_get_current_power_limit(smu, &power_limit))
|
||||
power_limit = smu->adev->pm.ac_power ?
|
||||
uint32_t pp_limit = smu->adev->pm.ac_power ?
|
||||
skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
|
||||
skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
|
||||
uint32_t power_limit = 0, od_percent_upper = 0, od_percent_lower = 0;
|
||||
int ret;
|
||||
|
||||
if (current_power_limit) {
|
||||
ret = smu_v13_0_get_current_power_limit(smu, &power_limit);
|
||||
if (ret)
|
||||
power_limit = pp_limit;
|
||||
|
||||
if (current_power_limit)
|
||||
*current_power_limit = power_limit;
|
||||
}
|
||||
|
||||
if (default_power_limit)
|
||||
*default_power_limit = power_limit;
|
||||
*default_power_limit = pp_limit;
|
||||
|
||||
if (powerplay_table) {
|
||||
if (smu->od_enabled &&
|
||||
|
|
@ -2407,15 +2411,15 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
|
|||
}
|
||||
|
||||
dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
|
||||
od_percent_upper, od_percent_lower, power_limit);
|
||||
od_percent_upper, od_percent_lower, pp_limit);
|
||||
|
||||
if (max_power_limit) {
|
||||
*max_power_limit = msg_limit * (100 + od_percent_upper);
|
||||
*max_power_limit = pp_limit * (100 + od_percent_upper);
|
||||
*max_power_limit /= 100;
|
||||
}
|
||||
|
||||
if (min_power_limit) {
|
||||
*min_power_limit = power_limit * (100 - od_percent_lower);
|
||||
*min_power_limit = pp_limit * (100 - od_percent_lower);
|
||||
*min_power_limit /= 100;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1231,7 +1231,8 @@ static int smu_v14_0_0_set_soft_freq_limited_range(struct smu_context *smu,
|
|||
switch (clk_type) {
|
||||
case SMU_GFXCLK:
|
||||
case SMU_SCLK:
|
||||
msg_set_min = SMU_MSG_SetHardMinGfxClk;
|
||||
/* SoftMin lets PMFW throttle gfxclk; HardMin would override SoftMax. */
|
||||
msg_set_min = SMU_MSG_SetSoftMinGfxclk;
|
||||
msg_set_max = SMU_MSG_SetSoftMaxGfxClk;
|
||||
break;
|
||||
case SMU_FCLK:
|
||||
|
|
|
|||
|
|
@ -2152,7 +2152,6 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
|
|||
metrics->Vcn1ActivityPercentage);
|
||||
|
||||
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
|
||||
gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
|
||||
|
||||
if (metrics->AverageGfxActivity <= SMU_14_0_2_BUSY_THRESHOLD)
|
||||
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
|
||||
|
|
|
|||
|
|
@ -272,11 +272,15 @@ static void __smu_msg_v1_send(struct smu_msg_ctl *ctl, u16 index,
|
|||
{
|
||||
struct amdgpu_device *adev = ctl->smu->adev;
|
||||
struct smu_msg_config *cfg = &ctl->config;
|
||||
u32 arg;
|
||||
int i;
|
||||
|
||||
WREG32(cfg->resp_reg, 0);
|
||||
for (i = 0; i < args->num_args; i++)
|
||||
WREG32(cfg->arg_regs[i], args->args[i]);
|
||||
for (i = 0; i < cfg->num_arg_regs; i++) {
|
||||
/* NOTE: Clear unused argument registers to avoid stale values. */
|
||||
arg = i < args->num_args ? args->args[i] : 0;
|
||||
WREG32(cfg->arg_regs[i], arg);
|
||||
}
|
||||
WREG32(cfg->msg_reg, index);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -202,13 +202,6 @@ int drm_mode_create_dumb(struct drm_device *dev,
|
|||
if (!args->width || !args->height || !args->bpp)
|
||||
return -EINVAL;
|
||||
|
||||
/* Reject unreasonable inputs early. Dumb buffers are for software
|
||||
* rendering; nothing legitimate needs more than 8192x8192 at 32bpp.
|
||||
* This prevents overflows in downstream alignment helpers.
|
||||
*/
|
||||
if (args->width >= 8192 || args->height >= 8192 || args->bpp > 32)
|
||||
return -EINVAL;
|
||||
|
||||
/* overflow checks for 32bit size calculations */
|
||||
if (args->bpp > U32_MAX - 8)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -1015,12 +1015,25 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This ioctl is disabled for security reasons but also it failed
|
||||
* to follow process in terms of adding testing in igt and verifying
|
||||
* all the corner cases which made fixing security bugs in it even
|
||||
* harder than necessary.
|
||||
*
|
||||
* To re-enable this ioctl
|
||||
* 1. land working IGT tests in igt-gpu-tools that cover
|
||||
* all corner cases and race conditions.
|
||||
* 2. handle idr_preload
|
||||
* 3. handle == 0
|
||||
* 4. handle == new_handle semantics definition.
|
||||
*/
|
||||
int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_gem_change_handle *args = data;
|
||||
struct drm_gem_object *obj, *idrobj;
|
||||
int handle, ret;
|
||||
struct drm_gem_object *obj;
|
||||
int new_handle, ret;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_GEM))
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -1028,52 +1041,36 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
|
|||
/* idr_alloc() limitation. */
|
||||
if (args->new_handle > INT_MAX)
|
||||
return -EINVAL;
|
||||
handle = args->new_handle;
|
||||
new_handle = args->new_handle;
|
||||
|
||||
obj = drm_gem_object_lookup(file_priv, args->handle);
|
||||
if (!obj)
|
||||
return -ENOENT;
|
||||
|
||||
if (args->handle == handle) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
if (args->handle == new_handle)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&file_priv->prime.lock);
|
||||
|
||||
spin_lock(&file_priv->table_lock);
|
||||
|
||||
/* When create_tail allocs an obj idr, it needs to first alloc as NULL,
|
||||
* then later replace with the correct object. This is not necessary
|
||||
* here, because the only operations that could race are drm_prime
|
||||
* bookkeeping, and we hold the prime lock.
|
||||
*/
|
||||
ret = idr_alloc(&file_priv->object_idr, obj, handle, handle + 1,
|
||||
ret = idr_alloc(&file_priv->object_idr, NULL, new_handle, new_handle + 1,
|
||||
GFP_NOWAIT);
|
||||
|
||||
if (ret < 0) {
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
goto out_unlock;
|
||||
}
|
||||
if (ret < 0) {
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
idrobj = idr_replace(&file_priv->object_idr, NULL, handle);
|
||||
if (idrobj != obj) {
|
||||
idr_replace(&file_priv->object_idr, idrobj, handle);
|
||||
idr_remove(&file_priv->object_idr, args->new_handle);
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
ret = -ENOENT;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
idr_replace(&file_priv->object_idr, NULL, args->handle);
|
||||
obj = idr_replace(&file_priv->object_idr, NULL, args->handle);
|
||||
if (IS_ERR_OR_NULL(obj)) {
|
||||
idr_remove(&file_priv->object_idr, new_handle);
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
ret = -ENOENT;
|
||||
goto out_unlock;
|
||||
}
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
|
||||
if (obj->dma_buf) {
|
||||
ret = drm_prime_add_buf_handle(&file_priv->prime, obj->dma_buf,
|
||||
handle);
|
||||
new_handle);
|
||||
if (ret < 0) {
|
||||
spin_lock(&file_priv->table_lock);
|
||||
idr_remove(&file_priv->object_idr, handle);
|
||||
idr_remove(&file_priv->object_idr, new_handle);
|
||||
idr_replace(&file_priv->object_idr, obj, args->handle);
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
goto out_unlock;
|
||||
|
|
@ -1086,14 +1083,12 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
|
|||
|
||||
spin_lock(&file_priv->table_lock);
|
||||
idr_remove(&file_priv->object_idr, args->handle);
|
||||
idrobj = idr_replace(&file_priv->object_idr, obj, handle);
|
||||
obj = idr_replace(&file_priv->object_idr, obj, new_handle);
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
WARN_ON(idrobj != NULL);
|
||||
WARN_ON(obj != NULL);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&file_priv->prime.lock);
|
||||
out:
|
||||
drm_gem_object_put(obj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -660,7 +660,8 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
|
|||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_CHANGE_HANDLE, drm_gem_change_handle_ioctl, DRM_RENDER_ALLOW),
|
||||
/* see drm_gem.c:drm_gem_change_handle_ioctl for why this is invalid */
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_CHANGE_HANDLE, drm_invalid_op, DRM_RENDER_ALLOW),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, 0),
|
||||
|
||||
|
|
|
|||
|
|
@ -150,6 +150,10 @@ static int hyperv_vmbus_probe(struct hv_device *hdev,
|
|||
goto err_free_mmio;
|
||||
}
|
||||
|
||||
/* If DRM panic path is stubbed out VMBus code must do the unload */
|
||||
if (IS_ENABLED(CONFIG_DRM_PANIC))
|
||||
vmbus_set_skip_unload(true);
|
||||
|
||||
drm_client_setup(dev, NULL);
|
||||
|
||||
return 0;
|
||||
|
|
@ -169,6 +173,7 @@ static void hyperv_vmbus_remove(struct hv_device *hdev)
|
|||
struct drm_device *dev = hv_get_drvdata(hdev);
|
||||
struct hyperv_drm_device *hv = to_hv(dev);
|
||||
|
||||
vmbus_set_skip_unload(false);
|
||||
drm_dev_unplug(dev);
|
||||
drm_atomic_helper_shutdown(dev);
|
||||
vmbus_close(hdev->channel);
|
||||
|
|
|
|||
|
|
@ -212,15 +212,16 @@ static void hyperv_plane_panic_flush(struct drm_plane *plane)
|
|||
struct hyperv_drm_device *hv = to_hv(plane->dev);
|
||||
struct drm_rect rect;
|
||||
|
||||
if (!plane->state || !plane->state->fb)
|
||||
return;
|
||||
if (plane->state && plane->state->fb) {
|
||||
rect.x1 = 0;
|
||||
rect.y1 = 0;
|
||||
rect.x2 = plane->state->fb->width;
|
||||
rect.y2 = plane->state->fb->height;
|
||||
|
||||
rect.x1 = 0;
|
||||
rect.y1 = 0;
|
||||
rect.x2 = plane->state->fb->width;
|
||||
rect.y2 = plane->state->fb->height;
|
||||
hyperv_update_dirt(hv->hdev, &rect);
|
||||
}
|
||||
|
||||
hyperv_update_dirt(hv->hdev, &rect);
|
||||
vmbus_initiate_unload(true);
|
||||
}
|
||||
|
||||
static const struct drm_plane_helper_funcs hyperv_plane_helper_funcs = {
|
||||
|
|
|
|||
|
|
@ -691,10 +691,9 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
|
|||
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
||||
struct drm_device *dev = connector->base.dev;
|
||||
struct intel_panel *panel = &connector->panel;
|
||||
bool try_intel_interface = false;
|
||||
bool try_intel_interface = false, try_vesa_interface = false;
|
||||
|
||||
/*
|
||||
* Check the VBT and user's module parameters to figure out which
|
||||
/* Check the VBT and user's module parameters to figure out which
|
||||
* interfaces to probe
|
||||
*/
|
||||
switch (display->params.enable_dpcd_backlight) {
|
||||
|
|
@ -703,6 +702,7 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
|
|||
case INTEL_DP_AUX_BACKLIGHT_AUTO:
|
||||
switch (panel->vbt.backlight.type) {
|
||||
case INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE:
|
||||
try_vesa_interface = true;
|
||||
break;
|
||||
case INTEL_BACKLIGHT_DISPLAY_DDI:
|
||||
try_intel_interface = true;
|
||||
|
|
@ -715,12 +715,20 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
|
|||
if (panel->vbt.backlight.type != INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE)
|
||||
try_intel_interface = true;
|
||||
|
||||
try_vesa_interface = true;
|
||||
break;
|
||||
case INTEL_DP_AUX_BACKLIGHT_FORCE_VESA:
|
||||
try_vesa_interface = true;
|
||||
break;
|
||||
case INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL:
|
||||
try_intel_interface = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* For eDP 1.5 and above we are supposed to use VESA interface for brightness control */
|
||||
if (intel_dp->edp_dpcd[0] >= DP_EDP_15)
|
||||
try_vesa_interface = true;
|
||||
|
||||
/*
|
||||
* Since Intel has their own backlight control interface, the majority of machines out there
|
||||
* using DPCD backlight controls with Intel GPUs will be using this interface as opposed to
|
||||
|
|
@ -733,9 +741,6 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
|
|||
* panel with Intel's OUI - which is also required for us to be able to detect Intel's
|
||||
* backlight interface at all. This means that the only sensible way for us to detect both
|
||||
* interfaces is to probe for Intel's first, and VESA's second.
|
||||
*
|
||||
* Also there is a chance some VBTs may advertise false Intel backlight support even if the
|
||||
* TCON DPCD says otherwise. This means we keep VESA interface as fallback in that case.
|
||||
*/
|
||||
if (try_intel_interface && intel_dp->edp_dpcd[0] <= DP_EDP_14b &&
|
||||
intel_dp_aux_supports_hdr_backlight(connector)) {
|
||||
|
|
@ -745,7 +750,7 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (intel_dp_aux_supports_vesa_backlight(connector)) {
|
||||
if (try_vesa_interface && intel_dp_aux_supports_vesa_backlight(connector)) {
|
||||
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Using VESA eDP backlight controls\n",
|
||||
connector->base.base.id, connector->base.name);
|
||||
panel->backlight.funcs = &intel_dp_vesa_bl_funcs;
|
||||
|
|
|
|||
|
|
@ -144,6 +144,15 @@ intel_plane_duplicate_state(struct drm_plane *plane)
|
|||
if (intel_state->hw.fb)
|
||||
drm_framebuffer_get(intel_state->hw.fb);
|
||||
|
||||
if (intel_state->hw.degamma_lut)
|
||||
drm_property_blob_get(intel_state->hw.degamma_lut);
|
||||
if (intel_state->hw.gamma_lut)
|
||||
drm_property_blob_get(intel_state->hw.gamma_lut);
|
||||
if (intel_state->hw.ctm)
|
||||
drm_property_blob_get(intel_state->hw.ctm);
|
||||
if (intel_state->hw.lut_3d)
|
||||
drm_property_blob_get(intel_state->hw.lut_3d);
|
||||
|
||||
return &intel_state->uapi;
|
||||
}
|
||||
|
||||
|
|
@ -167,6 +176,16 @@ intel_plane_destroy_state(struct drm_plane *plane,
|
|||
__drm_atomic_helper_plane_destroy_state(&plane_state->uapi);
|
||||
if (plane_state->hw.fb)
|
||||
drm_framebuffer_put(plane_state->hw.fb);
|
||||
|
||||
if (plane_state->hw.degamma_lut)
|
||||
drm_property_blob_put(plane_state->hw.degamma_lut);
|
||||
if (plane_state->hw.gamma_lut)
|
||||
drm_property_blob_put(plane_state->hw.gamma_lut);
|
||||
if (plane_state->hw.ctm)
|
||||
drm_property_blob_put(plane_state->hw.ctm);
|
||||
if (plane_state->hw.lut_3d)
|
||||
drm_property_blob_put(plane_state->hw.lut_3d);
|
||||
|
||||
kfree(plane_state);
|
||||
}
|
||||
|
||||
|
|
@ -317,6 +336,14 @@ static void intel_plane_clear_hw_state(struct intel_plane_state *plane_state)
|
|||
{
|
||||
if (plane_state->hw.fb)
|
||||
drm_framebuffer_put(plane_state->hw.fb);
|
||||
if (plane_state->hw.degamma_lut)
|
||||
drm_property_blob_put(plane_state->hw.degamma_lut);
|
||||
if (plane_state->hw.gamma_lut)
|
||||
drm_property_blob_put(plane_state->hw.gamma_lut);
|
||||
if (plane_state->hw.ctm)
|
||||
drm_property_blob_put(plane_state->hw.ctm);
|
||||
if (plane_state->hw.lut_3d)
|
||||
drm_property_blob_put(plane_state->hw.lut_3d);
|
||||
|
||||
memset(&plane_state->hw, 0, sizeof(plane_state->hw));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ static int exp_approx_q(int x)
|
|||
* dcss_scaler_gaussian_filter() - Generate gaussian prototype filter.
|
||||
* @fc_q: fixed-point cutoff frequency normalized to range [0, 1]
|
||||
* @use_5_taps: indicates whether to use 5 taps or 7 taps
|
||||
* @phase0_identity: whether to override phase 0 coefficients with identity filter
|
||||
* @coef: output filter coefficients
|
||||
*/
|
||||
static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps,
|
||||
|
|
@ -262,7 +263,9 @@ static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps,
|
|||
* @src_length: length of input
|
||||
* @dst_length: length of output
|
||||
* @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps
|
||||
* @phase0_identity: whether to override phase 0 coefficients with identity filter
|
||||
* @coef: output coefficients
|
||||
* @nn_interpolation: whether to use nearest neighbor instead of gaussian filter
|
||||
*/
|
||||
static void dcss_scaler_filter_design(int src_length, int dst_length,
|
||||
bool use_5_taps, bool phase0_identity,
|
||||
|
|
|
|||
|
|
@ -213,6 +213,14 @@ v3d_clean_caches(struct v3d_dev *v3d)
|
|||
|
||||
trace_v3d_cache_clean_begin(dev);
|
||||
|
||||
/* GFXH-1897: Ensure pending flushes complete before writing L2TCACTL */
|
||||
if (v3d->ver < V3D_GEN_71) {
|
||||
if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
|
||||
V3D_L2TCACTL_L2TFLS), 100)) {
|
||||
drm_err(dev, "Timeout waiting for L2T clean\n");
|
||||
}
|
||||
}
|
||||
|
||||
V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, V3D_L2TCACTL_TMUWCF);
|
||||
if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
|
||||
V3D_L2TCACTL_TMUWCF), 100)) {
|
||||
|
|
|
|||
|
|
@ -309,8 +309,11 @@ static void v3d_perfmon_delete(struct v3d_file_priv *v3d_priv,
|
|||
if (perfmon == v3d->active_perfmon)
|
||||
v3d_perfmon_stop(v3d, perfmon, false);
|
||||
|
||||
/* If the global perfmon is being destroyed, set it to NULL */
|
||||
cmpxchg(&v3d->global_perfmon, perfmon, NULL);
|
||||
/* If the global perfmon is being destroyed, clean it and release
|
||||
* the reference stashed in v3d_perfmon_set_global_ioctl().
|
||||
*/
|
||||
if (cmpxchg(&v3d->global_perfmon, perfmon, NULL) == perfmon)
|
||||
v3d_perfmon_put(perfmon);
|
||||
|
||||
v3d_perfmon_put(perfmon);
|
||||
}
|
||||
|
|
@ -461,16 +464,27 @@ int v3d_perfmon_set_global_ioctl(struct drm_device *dev, void *data,
|
|||
|
||||
/* If the request is to clear the global performance monitor */
|
||||
if (req->flags & DRM_V3D_PERFMON_CLEAR_GLOBAL) {
|
||||
if (!v3d->global_perfmon)
|
||||
struct v3d_perfmon *old;
|
||||
|
||||
/* DRM_V3D_PERFMON_CLEAR_GLOBAL doesn't check if
|
||||
* v3d->global_perfmon == perfmon. Therefore, there
|
||||
* is no need to keep perfmon's reference.
|
||||
*/
|
||||
v3d_perfmon_put(perfmon);
|
||||
|
||||
old = xchg(&v3d->global_perfmon, NULL);
|
||||
if (!old)
|
||||
return -EINVAL;
|
||||
|
||||
xchg(&v3d->global_perfmon, NULL);
|
||||
v3d_perfmon_put(old);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmpxchg(&v3d->global_perfmon, NULL, perfmon))
|
||||
if (cmpxchg(&v3d->global_perfmon, NULL, perfmon)) {
|
||||
v3d_perfmon_put(perfmon);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -352,6 +352,16 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* The HW interprets a workgroup size of 0 as 65536; however, the
|
||||
* user-space driver exposes a maximum of 65535. Therefore, a 0 in
|
||||
* any dimension means that we have no workgroups and the compute
|
||||
* shader should not be dispatched.
|
||||
*/
|
||||
if (!V3D_GET_FIELD(job->args.cfg[0], V3D_CSD_QUEUED_CFG0_NUM_WGS_X) ||
|
||||
!V3D_GET_FIELD(job->args.cfg[1], V3D_CSD_QUEUED_CFG1_NUM_WGS_Y) ||
|
||||
!V3D_GET_FIELD(job->args.cfg[2], V3D_CSD_QUEUED_CFG2_NUM_WGS_Z))
|
||||
return NULL;
|
||||
|
||||
v3d->queue[V3D_CSD].active_job = &job->base;
|
||||
|
||||
v3d_invalidate_caches(v3d);
|
||||
|
|
@ -402,13 +412,13 @@ v3d_rewrite_csd_job_wg_counts_from_indirect(struct v3d_cpu_job *job)
|
|||
|
||||
wg_counts = (uint32_t *)(bo->vaddr + indirect_csd->offset);
|
||||
|
||||
if (wg_counts[0] == 0 || wg_counts[1] == 0 || wg_counts[2] == 0)
|
||||
return;
|
||||
|
||||
args->cfg[0] = wg_counts[0] << V3D_CSD_CFG012_WG_COUNT_SHIFT;
|
||||
args->cfg[1] = wg_counts[1] << V3D_CSD_CFG012_WG_COUNT_SHIFT;
|
||||
args->cfg[2] = wg_counts[2] << V3D_CSD_CFG012_WG_COUNT_SHIFT;
|
||||
|
||||
if (wg_counts[0] == 0 || wg_counts[1] == 0 || wg_counts[2] == 0)
|
||||
goto unmap_bo;
|
||||
|
||||
num_batches = DIV_ROUND_UP(indirect_csd->wg_size, 16) *
|
||||
(wg_counts[0] * wg_counts[1] * wg_counts[2]);
|
||||
|
||||
|
|
@ -428,6 +438,7 @@ v3d_rewrite_csd_job_wg_counts_from_indirect(struct v3d_cpu_job *job)
|
|||
}
|
||||
}
|
||||
|
||||
unmap_bo:
|
||||
v3d_put_bo_vaddr(indirect);
|
||||
v3d_put_bo_vaddr(bo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,21 +162,4 @@ int xe_exec_queue_contexts_hwsp_rebase(struct xe_exec_queue *q, void *scratch);
|
|||
struct xe_lrc *xe_exec_queue_lrc(struct xe_exec_queue *q);
|
||||
struct xe_lrc *xe_exec_queue_get_lrc(struct xe_exec_queue *q, u16 idx);
|
||||
|
||||
/**
|
||||
* xe_exec_queue_idle_skip_suspend() - Can exec queue skip suspend
|
||||
* @q: The exec_queue
|
||||
*
|
||||
* If an exec queue is not parallel and is idle, the suspend steps can be
|
||||
* skipped in the submission backend immediatley signaling the suspend fence.
|
||||
* Parallel queues cannot skip this step due to limitations in the submission
|
||||
* backend.
|
||||
*
|
||||
* Return: True if exec queue is idle and can skip suspend steps, False
|
||||
* otherwise
|
||||
*/
|
||||
static inline bool xe_exec_queue_idle_skip_suspend(struct xe_exec_queue *q)
|
||||
{
|
||||
return !xe_exec_queue_is_parallel(q) && xe_exec_queue_is_idle(q);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user