Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Cross-merge networking fixes after downstream PR (net-7.1-rc3).

Conflicts:

net/ipv4/igmp.c
  726fa7da2d ("ipv4: igmp: get rid of IGMPV3_{QQIC,MRC} and simplify calculation")
  c6bebaa744 ("ipv4: igmp: annotate data-races in igmp_heard_query()")
https://lore.kernel.org/a7365e4873340f7a5e30411207de3bf9@kernel.org

Adjacent changes:

net/psp/psp_main.c
  30cb24f97d ("psp: strip variable-length PSP header in psp_dev_rcv()")
  c2b22277ad ("psp: validate IPv4 header fields in psp_dev_rcv()")

net/sched/sch_fq_codel.c
  f83e07b292 ("net/sched: sch_fq_codel: annotate data-races from fq_codel_dump_class_stats()")
  3f3aa77ff1 ("net/sched: add qstats_cpu_drop_inc() helper")

net/wireless/pmsr.c
  0f3c0a1973 ("wifi: nl80211: fix NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST usage")
  410aa47fd9 ("wifi: cfg80211: allow suppressing FTM result reporting for PD requests")

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-04-30 12:49:56 -07:00
commit 6a4c4656b0
544 changed files with 7658 additions and 3331 deletions

View File

@ -19,6 +19,7 @@ Abhinav Kumar <quic_abhinavk@quicinc.com> <abhinavk@codeaurora.org>
Ahmad Masri <quic_amasri@quicinc.com> <amasri@codeaurora.org>
Adam Oldham <oldhamca@gmail.com>
Adam Radford <aradford@gmail.com>
Aditya Garg <gargaditya08@proton.me> <gargaditya08@live.com>
Adriana Reus <adi.reus@gmail.com> <adriana.reus@intel.com>
Adrian Bunk <bunk@stusta.de>
Ajay Kaher <ajay.kaher@broadcom.com> <akaher@vmware.com>
@ -207,6 +208,7 @@ Claudiu Beznea <claudiu.beznea@tuxon.dev> <claudiu.beznea@microchip.com>
Colin Ian King <colin.i.king@gmail.com> <colin.king@canonical.com>
Corey Minyard <minyard@acm.org>
Damian Hobson-Garcia <dhobsong@igel.co.jp>
Dan Carpenter <error27@gmail.com> <dan.carpenter@linaro.org>
Dan Carpenter <error27@gmail.com> <dan.carpenter@oracle.com>
Dan Williams <djbw@kernel.org> <dan.j.williams@intel.com>
Daniel Borkmann <daniel@iogearbox.net> <danborkmann@googlemail.com>
@ -495,6 +497,7 @@ Leon Romanovsky <leon@kernel.org> <leon@leon.nu>
Leon Romanovsky <leon@kernel.org> <leonro@mellanox.com>
Leon Romanovsky <leon@kernel.org> <leonro@nvidia.com>
Leo Yan <leo.yan@linux.dev> <leo.yan@linaro.org>
Liam R. Howlett <liam@infradead.org> <Liam.Howlett@oracle.com>
Liam Mark <quic_lmark@quicinc.com> <lmark@codeaurora.org>
Linas Vepstas <linas@austin.ibm.com>
Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@ascom.ch>
@ -505,6 +508,8 @@ Linus Walleij <linusw@kernel.org> <linus.walleij@stericsson.com>
Linus Walleij <linusw@kernel.org> <linus.walleij@linaro.org>
Linus Walleij <linusw@kernel.org> <triad@df.lth.se>
<linux-hardening@vger.kernel.org> <kernel-hardening@lists.openwall.com>
Li Wang <li.wang@linux.dev> <liwang@redhat.com>
Li Wang <li.wang@linux.dev> <wangli.ahau@gmail.com>
Li Yang <leoyang.li@nxp.com> <leoli@freescale.com>
Li Yang <leoyang.li@nxp.com> <leo@zh-kernel.org>
Lior David <quic_liord@quicinc.com> <liord@codeaurora.org>
@ -687,6 +692,7 @@ Punit Agrawal <punitagrawal@gmail.com> <punit.agrawal@arm.com>
Puranjay Mohan <puranjay@kernel.org> <puranjay12@gmail.com>
Qais Yousef <qyousef@layalina.io> <qais.yousef@imgtec.com>
Qais Yousef <qyousef@layalina.io> <qais.yousef@arm.com>
Qi Zheng <qi.zheng@linux.dev> <zhengqi.arch@bytedance.com>
Quentin Monnet <qmo@kernel.org> <quentin.monnet@netronome.com>
Quentin Monnet <qmo@kernel.org> <quentin@isovalent.com>
Quentin Perret <qperret@qperret.net> <quentin.perret@arm.com>

View File

@ -47,21 +47,19 @@ Please note that implementation details can be changed.
Called when swp_entry's refcnt goes down to 0. A charge against swap
disappears.
3. charge-commit-cancel
3. charge-commit
=======================
Memcg pages are charged in two steps:
- mem_cgroup_try_charge()
- mem_cgroup_commit_charge() or mem_cgroup_cancel_charge()
- commit_charge()
At try_charge(), there are no flags to say "this page is charged".
at this point, usage += PAGE_SIZE.
At commit(), the page is associated with the memcg.
At cancel(), simply usage -= PAGE_SIZE.
Under below explanation, we assume CONFIG_SWAP=y.
4. Anonymous

View File

@ -7077,6 +7077,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core/debugobjec
F: include/linux/debugobjects.h
F: lib/debugobjects.c
DEC LANCE NETWORK DRIVER
M: "Maciej W. Rozycki" <macro@orcam.me.uk>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/amd/declance.c
DECSTATION PLATFORM SUPPORT
M: "Maciej W. Rozycki" <macro@orcam.me.uk>
L: linux-mips@vger.kernel.org
@ -7873,7 +7879,7 @@ F: drivers/gpu/drm/sun4i/sun8i*
DRM DRIVER FOR APPLE TOUCH BARS
M: Aun-Ali Zaidi <admin@kodeit.net>
M: Aditya Garg <gargaditya08@live.com>
M: Aditya Garg <gargaditya08@proton.me>
L: dri-devel@lists.freedesktop.org
S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
@ -13860,7 +13866,6 @@ M: Pratyush Yadav <pratyush@kernel.org>
R: Dave Young <ruirui.yang@linux.dev>
L: kexec@lists.infradead.org
S: Maintained
W: http://lse.sourceforge.net/kdump/
F: Documentation/admin-guide/kdump/
F: fs/proc/vmcore.c
F: include/linux/crash_core.h
@ -15252,7 +15257,7 @@ M: Andrea Cervesato <andrea.cervesato@suse.com>
M: Cyril Hrubis <chrubis@suse.cz>
M: Jan Stancek <jstancek@redhat.com>
M: Petr Vorel <pvorel@suse.cz>
M: Li Wang <liwang@redhat.com>
M: Li Wang <li.wang@linux.dev>
M: Yang Xu <xuyang2018.jy@fujitsu.com>
M: Xiao Yang <yangx.jy@fujitsu.com>
L: ltp@lists.linux.it (subscribers-only)
@ -15399,7 +15404,7 @@ F: include/net/netns/mctp.h
F: net/mctp/
MAPLE TREE
M: Liam R. Howlett <Liam.Howlett@oracle.com>
M: Liam R. Howlett <liam@infradead.org>
R: Alice Ryhl <aliceryhl@google.com>
R: Andrew Ballance <andrewjballance@gmail.com>
L: maple-tree@lists.infradead.org
@ -16759,7 +16764,7 @@ MEMORY MANAGEMENT - CORE
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
R: Lorenzo Stoakes <ljs@kernel.org>
R: Liam R. Howlett <Liam.Howlett@oracle.com>
R: Liam R. Howlett <liam@infradead.org>
R: Vlastimil Babka <vbabka@kernel.org>
R: Mike Rapoport <rppt@kernel.org>
R: Suren Baghdasaryan <surenb@google.com>
@ -16805,7 +16810,7 @@ F: mm/sparse.c
F: mm/util.c
F: mm/vmpressure.c
F: mm/vmstat.c
N: include/linux/page[-_]*
N: include\/linux\/page[-_][a-zA-Z]*
MEMORY MANAGEMENT - EXECMEM
M: Andrew Morton <akpm@linux-foundation.org>
@ -16895,7 +16900,7 @@ MEMORY MANAGEMENT - MISC
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
R: Lorenzo Stoakes <ljs@kernel.org>
R: Liam R. Howlett <Liam.Howlett@oracle.com>
R: Liam R. Howlett <liam@infradead.org>
R: Vlastimil Babka <vbabka@kernel.org>
R: Mike Rapoport <rppt@kernel.org>
R: Suren Baghdasaryan <surenb@google.com>
@ -16962,6 +16967,7 @@ S: Maintained
F: include/linux/compaction.h
F: include/linux/gfp.h
F: include/linux/page-isolation.h
F: include/linux/pageblock-flags.h
F: mm/compaction.c
F: mm/debug_page_alloc.c
F: mm/debug_page_ref.c
@ -16983,7 +16989,7 @@ M: Andrew Morton <akpm@linux-foundation.org>
M: Johannes Weiner <hannes@cmpxchg.org>
R: David Hildenbrand <david@kernel.org>
R: Michal Hocko <mhocko@kernel.org>
R: Qi Zheng <zhengqi.arch@bytedance.com>
R: Qi Zheng <qi.zheng@linux.dev>
R: Shakeel Butt <shakeel.butt@linux.dev>
R: Lorenzo Stoakes <ljs@kernel.org>
L: linux-mm@kvack.org
@ -16996,7 +17002,7 @@ M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
M: Lorenzo Stoakes <ljs@kernel.org>
R: Rik van Riel <riel@surriel.com>
R: Liam R. Howlett <Liam.Howlett@oracle.com>
R: Liam R. Howlett <liam@infradead.org>
R: Vlastimil Babka <vbabka@kernel.org>
R: Harry Yoo <harry@kernel.org>
R: Jann Horn <jannh@google.com>
@ -17043,7 +17049,7 @@ M: David Hildenbrand <david@kernel.org>
M: Lorenzo Stoakes <ljs@kernel.org>
R: Zi Yan <ziy@nvidia.com>
R: Baolin Wang <baolin.wang@linux.alibaba.com>
R: Liam R. Howlett <Liam.Howlett@oracle.com>
R: Liam R. Howlett <liam@infradead.org>
R: Nico Pache <npache@redhat.com>
R: Ryan Roberts <ryan.roberts@arm.com>
R: Dev Jain <dev.jain@arm.com>
@ -17081,7 +17087,7 @@ F: tools/testing/selftests/mm/uffd-*.[ch]
MEMORY MANAGEMENT - RUST
M: Alice Ryhl <aliceryhl@google.com>
R: Lorenzo Stoakes <ljs@kernel.org>
R: Liam R. Howlett <Liam.Howlett@oracle.com>
R: Liam R. Howlett <liam@infradead.org>
L: linux-mm@kvack.org
L: rust-for-linux@vger.kernel.org
S: Maintained
@ -17095,7 +17101,7 @@ F: rust/kernel/page.rs
MEMORY MAPPING
M: Andrew Morton <akpm@linux-foundation.org>
M: Liam R. Howlett <Liam.Howlett@oracle.com>
M: Liam R. Howlett <liam@infradead.org>
M: Lorenzo Stoakes <ljs@kernel.org>
R: Vlastimil Babka <vbabka@kernel.org>
R: Jann Horn <jannh@google.com>
@ -17127,7 +17133,7 @@ F: tools/testing/vma/
MEMORY MAPPING - LOCKING
M: Andrew Morton <akpm@linux-foundation.org>
M: Suren Baghdasaryan <surenb@google.com>
M: Liam R. Howlett <Liam.Howlett@oracle.com>
M: Liam R. Howlett <liam@infradead.org>
M: Lorenzo Stoakes <ljs@kernel.org>
R: Vlastimil Babka <vbabka@kernel.org>
R: Shakeel Butt <shakeel.butt@linux.dev>
@ -17142,7 +17148,7 @@ F: mm/mmap_lock.c
MEMORY MAPPING - MADVISE (MEMORY ADVICE)
M: Andrew Morton <akpm@linux-foundation.org>
M: Liam R. Howlett <Liam.Howlett@oracle.com>
M: Liam R. Howlett <liam@infradead.org>
M: Lorenzo Stoakes <ljs@kernel.org>
M: David Hildenbrand <david@kernel.org>
R: Vlastimil Babka <vbabka@kernel.org>
@ -23403,7 +23409,7 @@ RUST [ALLOC]
M: Danilo Krummrich <dakr@kernel.org>
R: Lorenzo Stoakes <ljs@kernel.org>
R: Vlastimil Babka <vbabka@kernel.org>
R: Liam R. Howlett <Liam.Howlett@oracle.com>
R: Liam R. Howlett <liam@infradead.org>
R: Uladzislau Rezki <urezki@gmail.com>
L: rust-for-linux@vger.kernel.org
S: Maintained
@ -23555,7 +23561,7 @@ F: drivers/s390/net/
S390 PCI SUBSYSTEM
M: Niklas Schnelle <schnelle@linux.ibm.com>
M: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
M: Gerd Bayer <gbayer@linux.ibm.com>
L: linux-s390@vger.kernel.org
S: Supported
F: Documentation/arch/s390/pci.rst
@ -24348,7 +24354,7 @@ F: include/media/i2c/rj54n1cb0c.h
SHRINKER
M: Andrew Morton <akpm@linux-foundation.org>
M: Dave Chinner <david@fromorbit.com>
R: Qi Zheng <zhengqi.arch@bytedance.com>
R: Qi Zheng <qi.zheng@linux.dev>
R: Roman Gushchin <roman.gushchin@linux.dev>
R: Muchun Song <muchun.song@linux.dev>
L: linux-mm@kvack.org
@ -24650,6 +24656,7 @@ S: Maintained
F: fs/smb/client/smbdirect.*
F: fs/smb/smbdirect/
F: fs/smb/server/transport_rdma.*
F: include/linux/smbdirect.h
SMC91x ETHERNET DRIVER
M: Nicolas Pitre <nico@fluxnic.net>
@ -24798,6 +24805,7 @@ SOFTWARE RAID (Multiple Disks) SUPPORT
M: Song Liu <song@kernel.org>
M: Yu Kuai <yukuai@fnnas.com>
R: Li Nan <linan122@huawei.com>
R: Xiao Ni <xiao@kernel.org>
L: linux-raid@vger.kernel.org
S: Supported
Q: https://patchwork.kernel.org/project/linux-raid/list/

View File

@ -2,7 +2,7 @@
VERSION = 7
PATCHLEVEL = 1
SUBLEVEL = 0
EXTRAVERSION = -rc1
EXTRAVERSION = -rc2
NAME = Baby Opossum Posse
# *DOCUMENTATION*

View File

@ -40,7 +40,7 @@ static __always_inline void __pmr_local_irq_enable(void)
barrier();
}
static inline void arch_local_irq_enable(void)
static __always_inline void arch_local_irq_enable(void)
{
if (system_uses_irq_prio_masking()) {
__pmr_local_irq_enable();
@ -68,7 +68,7 @@ static __always_inline void __pmr_local_irq_disable(void)
barrier();
}
static inline void arch_local_irq_disable(void)
static __always_inline void arch_local_irq_disable(void)
{
if (system_uses_irq_prio_masking()) {
__pmr_local_irq_disable();
@ -90,7 +90,7 @@ static __always_inline unsigned long __pmr_local_save_flags(void)
/*
* Save the current interrupt enable state.
*/
static inline unsigned long arch_local_save_flags(void)
static __always_inline unsigned long arch_local_save_flags(void)
{
if (system_uses_irq_prio_masking()) {
return __pmr_local_save_flags();
@ -109,7 +109,7 @@ static __always_inline bool __pmr_irqs_disabled_flags(unsigned long flags)
return flags != GIC_PRIO_IRQON;
}
static inline bool arch_irqs_disabled_flags(unsigned long flags)
static __always_inline bool arch_irqs_disabled_flags(unsigned long flags)
{
if (system_uses_irq_prio_masking()) {
return __pmr_irqs_disabled_flags(flags);
@ -128,7 +128,7 @@ static __always_inline bool __pmr_irqs_disabled(void)
return __pmr_irqs_disabled_flags(__pmr_local_save_flags());
}
static inline bool arch_irqs_disabled(void)
static __always_inline bool arch_irqs_disabled(void)
{
if (system_uses_irq_prio_masking()) {
return __pmr_irqs_disabled();
@ -160,7 +160,7 @@ static __always_inline unsigned long __pmr_local_irq_save(void)
return flags;
}
static inline unsigned long arch_local_irq_save(void)
static __always_inline unsigned long arch_local_irq_save(void)
{
if (system_uses_irq_prio_masking()) {
return __pmr_local_irq_save();
@ -187,7 +187,7 @@ static __always_inline void __pmr_local_irq_restore(unsigned long flags)
/*
* restore saved IRQ state
*/
static inline void arch_local_irq_restore(unsigned long flags)
static __always_inline void arch_local_irq_restore(unsigned long flags)
{
if (system_uses_irq_prio_masking()) {
__pmr_local_irq_restore(flags);

View File

@ -68,7 +68,12 @@
#define KERNEL_SEGMENT_COUNT 5
#if SWAPPER_BLOCK_SIZE > SEGMENT_ALIGN
#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 1)
/*
* KERNEL_SEGMENT_COUNT counts the permanent kernel VMAs. The early mapping
* has one additional split, [_text, _stext). Reserve one more page for the
* SWAPPER_BLOCK_SIZE-unaligned boundaries.
*/
#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 2)
/*
* The initial ID map consists of the kernel image, mapped as two separate
* segments, and may appear misaligned wrt the swapper block size. This means

View File

@ -196,9 +196,9 @@ static int scs_handle_fde_frame(const struct eh_frame *frame,
loc += *opcode++ * code_alignment_factor;
loc += (*opcode++ << 8) * code_alignment_factor;
loc += (*opcode++ << 16) * code_alignment_factor;
loc += (*opcode++ << 24) * code_alignment_factor;
loc += ((u64)*opcode++ << 24) * code_alignment_factor;
size -= 4;
break;
break;
case DW_CFA_def_cfa:
case DW_CFA_offset_extended:

View File

@ -67,6 +67,9 @@ struct rt_sigframe_user_layout {
unsigned long end_offset;
};
#define TERMINATOR_SIZE round_up(sizeof(struct _aarch64_ctx), 16)
#define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16)
/*
* Holds any EL0-controlled state that influences unprivileged memory accesses.
* This includes both accesses done in userspace and uaccess done in the kernel.
@ -74,13 +77,35 @@ struct rt_sigframe_user_layout {
* This state needs to be carefully managed to ensure that it doesn't cause
* uaccess to fail when setting up the signal frame, and the signal handler
* itself also expects a well-defined state when entered.
*
* The struct should be zero-initialised. Its members should only be accessed
* via the accessors below. __valid_fields tracks which of the fields are valid
* (have been set to some value).
*/
struct user_access_state {
u64 por_el0;
unsigned int __valid_fields;
u64 __por_el0;
};
#define TERMINATOR_SIZE round_up(sizeof(struct _aarch64_ctx), 16)
#define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16)
#define UA_STATE_HAS_POR_EL0 BIT(0)
static void set_ua_state_por_el0(struct user_access_state *ua_state,
u64 por_el0)
{
ua_state->__por_el0 = por_el0;
ua_state->__valid_fields |= UA_STATE_HAS_POR_EL0;
}
static int get_ua_state_por_el0(const struct user_access_state *ua_state,
u64 *por_el0)
{
if (ua_state->__valid_fields & UA_STATE_HAS_POR_EL0) {
*por_el0 = ua_state->__por_el0;
return 0;
}
return -ENOENT;
}
/*
* Save the user access state into ua_state and reset it to disable any
@ -94,7 +119,7 @@ static void save_reset_user_access_state(struct user_access_state *ua_state)
for (int pkey = 0; pkey < arch_max_pkey(); pkey++)
por_enable_all |= POR_ELx_PERM_PREP(pkey, POE_RWX);
ua_state->por_el0 = read_sysreg_s(SYS_POR_EL0);
set_ua_state_por_el0(ua_state, read_sysreg_s(SYS_POR_EL0));
write_sysreg_s(por_enable_all, SYS_POR_EL0);
/*
* No ISB required as we can tolerate spurious Overlay faults -
@ -122,8 +147,10 @@ static void set_handler_user_access_state(void)
*/
static void restore_user_access_state(const struct user_access_state *ua_state)
{
if (system_supports_poe())
write_sysreg_s(ua_state->por_el0, SYS_POR_EL0);
u64 por_el0;
if (get_ua_state_por_el0(ua_state, &por_el0) == 0)
write_sysreg_s(por_el0, SYS_POR_EL0);
}
static void init_user_layout(struct rt_sigframe_user_layout *user)
@ -333,11 +360,16 @@ static int restore_fpmr_context(struct user_ctxs *user)
static int preserve_poe_context(struct poe_context __user *ctx,
const struct user_access_state *ua_state)
{
int err = 0;
int err;
u64 por_el0;
err = get_ua_state_por_el0(ua_state, &por_el0);
if (WARN_ON_ONCE(err))
return err;
__put_user_error(POE_MAGIC, &ctx->head.magic, err);
__put_user_error(sizeof(*ctx), &ctx->head.size, err);
__put_user_error(ua_state->por_el0, &ctx->por_el0, err);
__put_user_error(por_el0, &ctx->por_el0, err);
return err;
}
@ -353,7 +385,7 @@ static int restore_poe_context(struct user_ctxs *user,
__get_user_error(por_el0, &(user->poe->por_el0), err);
if (!err)
ua_state->por_el0 = por_el0;
set_ua_state_por_el0(ua_state, por_el0);
return err;
}
@ -1095,7 +1127,7 @@ SYSCALL_DEFINE0(rt_sigreturn)
{
struct pt_regs *regs = current_pt_regs();
struct rt_sigframe __user *frame;
struct user_access_state ua_state;
struct user_access_state ua_state = {};
/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;
@ -1507,7 +1539,7 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
{
struct rt_sigframe_user_layout user;
struct rt_sigframe __user *frame;
struct user_access_state ua_state;
struct user_access_state ua_state = {};
int err = 0;
fpsimd_save_and_flush_current_state();

View File

@ -3,7 +3,7 @@ obj-y += mm/
obj-y += net/
obj-y += vdso/
obj-$(CONFIG_KVM) += kvm/
obj-$(subst m,y,$(CONFIG_KVM)) += kvm/
# for cleaning
subdir- += boot

View File

@ -220,6 +220,7 @@ menu "Kernel type and options"
choice
prompt "Kernel type"
default 64BIT # Keep existing behavior
config 32BIT
bool "32-bit kernel"

View File

@ -55,9 +55,11 @@ endif
ifdef CONFIG_32BIT
tool-archpref = $(32bit-tool-archpref)
UTS_MACHINE := loongarch32
cflags-y += $(call cc-option,-m32)
else
tool-archpref = $(64bit-tool-archpref)
UTS_MACHINE := loongarch64
cflags-y += $(call cc-option,-m64)
endif
ifneq ($(SUBARCH),$(ARCH))

View File

@ -20,3 +20,23 @@ asmlinkage void noinstr __no_stack_protector ret_from_kernel_thread(struct task_
struct pt_regs *regs,
int (*fn)(void *),
void *fn_arg);
struct kvm_run;
struct kvm_vcpu;
struct loongarch_fpu;
void kvm_exc_entry(void);
int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
void kvm_save_fpu(struct loongarch_fpu *fpu);
void kvm_restore_fpu(struct loongarch_fpu *fpu);
#ifdef CONFIG_CPU_HAS_LSX
void kvm_save_lsx(struct loongarch_fpu *fpu);
void kvm_restore_lsx(struct loongarch_fpu *fpu);
#endif
#ifdef CONFIG_CPU_HAS_LASX
void kvm_save_lasx(struct loongarch_fpu *fpu);
void kvm_restore_lasx(struct loongarch_fpu *fpu);
#endif

View File

@ -87,7 +87,6 @@ struct kvm_context {
struct kvm_world_switch {
int (*exc_entry)(void);
int (*enter_guest)(struct kvm_run *run, struct kvm_vcpu *vcpu);
unsigned long page_order;
};
#define MAX_PGTABLE_LEVELS 4
@ -359,8 +358,6 @@ void kvm_exc_entry(void);
int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
extern unsigned long vpid_mask;
extern const unsigned long kvm_exception_size;
extern const unsigned long kvm_enter_guest_size;
extern struct kvm_world_switch *kvm_loongarch_ops;
#define SW_GCSR (1 << 0)

View File

@ -69,7 +69,7 @@
9, 10, 11, 12, 13, 14, 15, 16, \
17, 18, 19, 20, 21, 22, 23, 24, \
25, 26, 27, 28, 29, 30, 31; \
.cfi_offset \num, SC_REGS + \num * SZREG; \
.cfi_offset \num, SC_REGS + \num * 8; \
.endr; \
\
nop; \

View File

@ -85,12 +85,6 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
return count;
}
static inline bool loongarch_vdso_hres_capable(void)
{
return true;
}
#define __arch_vdso_hres_capable loongarch_vdso_hres_capable
#endif /* CONFIG_GENERIC_GETTIMEOFDAY */
#endif /* !__ASSEMBLER__ */

View File

@ -7,11 +7,12 @@ include $(srctree)/virt/kvm/Makefile.kvm
obj-$(CONFIG_KVM) += kvm.o
obj-y += switch.o
kvm-y += exit.o
kvm-y += interrupt.o
kvm-y += main.o
kvm-y += mmu.o
kvm-y += switch.o
kvm-y += timer.o
kvm-y += tlb.o
kvm-y += vcpu.o

View File

@ -390,6 +390,7 @@ int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst)
run->mmio.len = 8;
break;
default:
ret = EMULATE_FAIL;
break;
}
break;

View File

@ -28,23 +28,29 @@ static unsigned int priority_to_irq[EXCCODE_INT_NUM] = {
static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
{
unsigned int irq = 0;
unsigned long old, new;
clear_bit(priority, &vcpu->arch.irq_pending);
if (priority < EXCCODE_INT_NUM)
irq = priority_to_irq[priority];
if (kvm_guest_has_msgint(&vcpu->arch) && (priority == INT_AVEC)) {
dmsintc_inject_irq(vcpu);
set_gcsr_estat(irq);
return 1;
}
switch (priority) {
case INT_AVEC:
if (!kvm_guest_has_msgint(&vcpu->arch))
break;
dmsintc_inject_irq(vcpu);
fallthrough;
case INT_TI:
case INT_IPI:
case INT_SWI0:
case INT_SWI1:
old = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
set_gcsr_estat(irq);
new = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
/* Inject TI if TVAL inverted */
if (new > old)
set_gcsr_estat(CPU_TIMER);
break;
case INT_HWI0 ... INT_HWI7:
@ -61,22 +67,28 @@ static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
{
unsigned int irq = 0;
unsigned long old, new;
clear_bit(priority, &vcpu->arch.irq_clear);
if (priority < EXCCODE_INT_NUM)
irq = priority_to_irq[priority];
if (kvm_guest_has_msgint(&vcpu->arch) && (priority == INT_AVEC)) {
clear_gcsr_estat(irq);
return 1;
}
switch (priority) {
case INT_AVEC:
if (!kvm_guest_has_msgint(&vcpu->arch))
break;
fallthrough;
case INT_TI:
case INT_IPI:
case INT_SWI0:
case INT_SWI1:
old = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
clear_gcsr_estat(irq);
new = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
/* Inject TI if TVAL inverted */
if (new > old)
set_gcsr_estat(CPU_TIMER);
break;
case INT_HWI0 ... INT_HWI7:

View File

@ -348,8 +348,7 @@ void kvm_arch_disable_virtualization_cpu(void)
static int kvm_loongarch_env_init(void)
{
int cpu, order, ret;
void *addr;
int cpu, ret;
struct kvm_context *context;
vmcs = alloc_percpu(struct kvm_context);
@ -365,30 +364,8 @@ static int kvm_loongarch_env_init(void)
return -ENOMEM;
}
/*
* PGD register is shared between root kernel and kvm hypervisor.
* So world switch entry should be in DMW area rather than TLB area
* to avoid page fault reenter.
*
* In future if hardware pagetable walking is supported, we won't
* need to copy world switch code to DMW area.
*/
order = get_order(kvm_exception_size + kvm_enter_guest_size);
addr = (void *)__get_free_pages(GFP_KERNEL, order);
if (!addr) {
free_percpu(vmcs);
vmcs = NULL;
kfree(kvm_loongarch_ops);
kvm_loongarch_ops = NULL;
return -ENOMEM;
}
memcpy(addr, kvm_exc_entry, kvm_exception_size);
memcpy(addr + kvm_exception_size, kvm_enter_guest, kvm_enter_guest_size);
flush_icache_range((unsigned long)addr, (unsigned long)addr + kvm_exception_size + kvm_enter_guest_size);
kvm_loongarch_ops->exc_entry = addr;
kvm_loongarch_ops->enter_guest = addr + kvm_exception_size;
kvm_loongarch_ops->page_order = order;
kvm_loongarch_ops->exc_entry = (void *)kvm_exc_entry;
kvm_loongarch_ops->enter_guest = (void *)kvm_enter_guest;
vpid_mask = read_csr_gstat();
vpid_mask = (vpid_mask & CSR_GSTAT_GIDBIT) >> CSR_GSTAT_GIDBIT_SHIFT;
@ -428,16 +405,10 @@ static int kvm_loongarch_env_init(void)
static void kvm_loongarch_env_exit(void)
{
unsigned long addr;
if (vmcs)
free_percpu(vmcs);
if (kvm_loongarch_ops) {
if (kvm_loongarch_ops->exc_entry) {
addr = (unsigned long)kvm_loongarch_ops->exc_entry;
free_pages(addr, kvm_loongarch_ops->page_order);
}
kfree(kvm_loongarch_ops);
}

View File

@ -95,7 +95,7 @@ static int kvm_flush_pte(kvm_pte_t *pte, phys_addr_t addr, kvm_ptw_ctx *ctx)
else
kvm->stat.pages--;
*pte = ctx->invalid_entry;
kvm_set_pte(pte, ctx->invalid_entry);
return 1;
}

View File

@ -4,9 +4,11 @@
*/
#include <linux/linkage.h>
#include <linux/kvm_types.h>
#include <asm/asm.h>
#include <asm/asmmacro.h>
#include <asm/loongarch.h>
#include <asm/page.h>
#include <asm/regdef.h>
#include <asm/unwind_hints.h>
@ -100,11 +102,16 @@
* - is still in guest mode, such as pgd table/vmid registers etc,
* - will fix with hw page walk enabled in future
* load kvm_vcpu from reserved CSR KVM_VCPU_KS, and save a2 to KVM_TEMP_KS
*
* PGD register is shared between root kernel and kvm hypervisor.
* So world switch entry should be in DMW area rather than TLB area
* to avoid page fault re-enter.
*/
.text
.p2align PAGE_SHIFT
.cfi_sections .debug_frame
SYM_CODE_START(kvm_exc_entry)
UNWIND_HINT_UNDEFINED
UNWIND_HINT_END_OF_STACK
csrwr a2, KVM_TEMP_KS
csrrd a2, KVM_VCPU_KS
addi.d a2, a2, KVM_VCPU_ARCH
@ -190,8 +197,8 @@ ret_to_host:
kvm_restore_host_gpr a2
jr ra
SYM_INNER_LABEL(kvm_exc_entry_end, SYM_L_LOCAL)
SYM_CODE_END(kvm_exc_entry)
EXPORT_SYMBOL_FOR_KVM(kvm_exc_entry)
/*
* int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu)
@ -215,8 +222,8 @@ SYM_FUNC_START(kvm_enter_guest)
/* Save kvm_vcpu to kscratch */
csrwr a1, KVM_VCPU_KS
kvm_switch_to_guest
SYM_INNER_LABEL(kvm_enter_guest_end, SYM_L_LOCAL)
SYM_FUNC_END(kvm_enter_guest)
EXPORT_SYMBOL_FOR_KVM(kvm_enter_guest)
SYM_FUNC_START(kvm_save_fpu)
fpu_save_csr a0 t1
@ -224,6 +231,7 @@ SYM_FUNC_START(kvm_save_fpu)
fpu_save_cc a0 t1 t2
jr ra
SYM_FUNC_END(kvm_save_fpu)
EXPORT_SYMBOL_FOR_KVM(kvm_save_fpu)
SYM_FUNC_START(kvm_restore_fpu)
fpu_restore_double a0 t1
@ -231,6 +239,7 @@ SYM_FUNC_START(kvm_restore_fpu)
fpu_restore_cc a0 t1 t2
jr ra
SYM_FUNC_END(kvm_restore_fpu)
EXPORT_SYMBOL_FOR_KVM(kvm_restore_fpu)
#ifdef CONFIG_CPU_HAS_LSX
SYM_FUNC_START(kvm_save_lsx)
@ -239,6 +248,7 @@ SYM_FUNC_START(kvm_save_lsx)
lsx_save_data a0 t1
jr ra
SYM_FUNC_END(kvm_save_lsx)
EXPORT_SYMBOL_FOR_KVM(kvm_save_lsx)
SYM_FUNC_START(kvm_restore_lsx)
lsx_restore_data a0 t1
@ -246,6 +256,7 @@ SYM_FUNC_START(kvm_restore_lsx)
fpu_restore_csr a0 t1 t2
jr ra
SYM_FUNC_END(kvm_restore_lsx)
EXPORT_SYMBOL_FOR_KVM(kvm_restore_lsx)
#endif
#ifdef CONFIG_CPU_HAS_LASX
@ -255,6 +266,7 @@ SYM_FUNC_START(kvm_save_lasx)
lasx_save_data a0 t1
jr ra
SYM_FUNC_END(kvm_save_lasx)
EXPORT_SYMBOL_FOR_KVM(kvm_save_lasx)
SYM_FUNC_START(kvm_restore_lasx)
lasx_restore_data a0 t1
@ -262,10 +274,8 @@ SYM_FUNC_START(kvm_restore_lasx)
fpu_restore_csr a0 t1 t2
jr ra
SYM_FUNC_END(kvm_restore_lasx)
EXPORT_SYMBOL_FOR_KVM(kvm_restore_lasx)
#endif
.section ".rodata"
SYM_DATA(kvm_exception_size, .quad kvm_exc_entry_end - kvm_exc_entry)
SYM_DATA(kvm_enter_guest_size, .quad kvm_enter_guest_end - kvm_enter_guest)
#ifdef CONFIG_CPU_HAS_LBT
STACK_FRAME_NON_STANDARD kvm_restore_fpu

View File

@ -96,15 +96,21 @@ void kvm_restore_timer(struct kvm_vcpu *vcpu)
* and set CSR TVAL with -1
*/
write_gcsr_timertick(0);
__delay(2); /* Wait cycles until timer interrupt injected */
/*
* Writing CSR_TINTCLR_TI to LOONGARCH_CSR_TINTCLR will clear
* timer interrupt, and CSR TVAL keeps unchanged with -1, it
* avoids spurious timer interrupt
*/
if (!(estat & CPU_TIMER))
if (!(estat & CPU_TIMER)) {
__delay(2); /* Wait cycles until timer interrupt injected */
/* Write TVAL with max value if no TI shot */
estat = kvm_read_hw_gcsr(LOONGARCH_CSR_ESTAT);
if (!(estat & CPU_TIMER))
write_gcsr_timertick(CSR_TCFG_VAL);
gcsr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR);
}
return;
}

View File

@ -125,7 +125,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
r = 1;
break;
case KVM_CAP_NR_VCPUS:
r = num_online_cpus();
r = min_t(unsigned int, num_online_cpus(), KVM_MAX_VCPUS);
break;
case KVM_CAP_MAX_VCPUS:
r = KVM_MAX_VCPUS;

View File

@ -61,11 +61,16 @@ static void acpi_release_root_info(struct acpi_pci_root_info *ci)
static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci)
{
int status;
unsigned long long pci_h = 0;
struct resource_entry *entry, *tmp;
struct acpi_device *device = ci->bridge;
status = acpi_pci_probe_root_resources(ci);
if (status > 0) {
acpi_evaluate_integer(device->handle, "PCIH", NULL, &pci_h);
if (pci_h)
return status;
resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
if (entry->res->flags & IORESOURCE_MEM) {
entry->offset = ci->root->mcfg_addr & GENMASK_ULL(63, 40);

View File

@ -132,6 +132,9 @@ static void loongson_gpu_fixup_dma_hang(struct pci_dev *pdev, bool on)
crtc_reg = regbase;
crtc_offset = 0x400;
break;
default:
iounmap(regbase);
return;
}
for (i = 0; i < CRTC_NUM_MAX; i++, crtc_reg += crtc_offset) {

View File

@ -12,6 +12,8 @@ obj-vdso-$(CONFIG_GENERIC_GETTIMEOFDAY) += vgettimeofday.o
ccflags-vdso := \
$(filter -I%,$(KBUILD_CFLAGS)) \
$(filter -E%,$(KBUILD_CFLAGS)) \
$(filter -m32,$(KBUILD_CFLAGS)) \
$(filter -m64,$(KBUILD_CFLAGS)) \
$(filter -march=%,$(KBUILD_CFLAGS)) \
$(filter -m%-float,$(KBUILD_CFLAGS)) \
$(CLANG_FLAGS) \

View File

@ -174,15 +174,21 @@ ifeq ($(KBUILD_EXTMOD),)
# this hack.
prepare: vdso_prepare
vdso_prepare: prepare0
$(if $(CONFIG_64BIT),$(Q)$(MAKE) \
$(build)=arch/parisc/kernel/vdso64 include/generated/vdso64-offsets.h)
$(if $(CONFIG_PA11)$(CONFIG_COMPAT),$(Q)$(MAKE) \
ifdef CONFIG_64BIT
$(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso64 include/generated/vdso64-offsets.h
$(if $(CONFIG_COMPAT),$(Q)$(MAKE) \
$(build)=arch/parisc/kernel/vdso32 include/generated/vdso32-offsets.h)
else
$(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso32 include/generated/vdso32-offsets.h
endif
endif
vdso-install-$(CONFIG_PA11) += arch/parisc/kernel/vdso32/vdso32.so
ifdef CONFIG_64BIT
vdso-install-y += arch/parisc/kernel/vdso64/vdso64.so
vdso-install-$(CONFIG_COMPAT) += arch/parisc/kernel/vdso32/vdso32.so
vdso-install-$(CONFIG_64BIT) += arch/parisc/kernel/vdso64/vdso64.so
else
vdso-install-y += arch/parisc/kernel/vdso32/vdso32.so
endif
install: KBUILD_IMAGE := vmlinux
zinstall: KBUILD_IMAGE := vmlinuz

View File

@ -6,13 +6,14 @@
#ifdef CONFIG_64BIT
#include <generated/vdso64-offsets.h>
#define VDSO64_SYMBOL(tsk, name) ((tsk)->mm->context.vdso_base + (vdso64_offset_##name))
#endif
#if !defined(CONFIG_64BIT) || defined(CONFIG_COMPAT)
#include <generated/vdso32-offsets.h>
#endif
#define VDSO64_SYMBOL(tsk, name) ((tsk)->mm->context.vdso_base + (vdso64_offset_##name))
#define VDSO32_SYMBOL(tsk, name) ((tsk)->mm->context.vdso_base + (vdso32_offset_##name))
#else
#define VDSO32_SYMBOL(tsk, name) 0UL
#endif
#endif /* __ASSEMBLER__ */

View File

@ -46,6 +46,9 @@ obj-$(CONFIG_KEXEC_FILE) += kexec_file.o
# vdso
obj-y += vdso.o
obj-$(CONFIG_64BIT) += vdso64/
obj-$(CONFIG_PA11) += vdso32/
ifdef CONFIG_64BIT
obj-y += vdso64/
obj-$(CONFIG_COMPAT) += vdso32/
else
obj-y += vdso32/
endif

View File

@ -41,9 +41,7 @@
const struct dma_map_ops *hppa_dma_ops __ro_after_init;
EXPORT_SYMBOL(hppa_dma_ops);
static struct device root = {
.init_name = "parisc",
};
static struct device *root;
static inline int check_dev(struct device *dev)
{
@ -89,7 +87,7 @@ static int for_each_padev(int (*fn)(struct device *, void *), void * data)
.obj = data,
.fn = fn,
};
return device_for_each_child(&root, &recurse_data, descend_children);
return device_for_each_child(root, &recurse_data, descend_children);
}
/**
@ -290,7 +288,7 @@ const struct parisc_device *
find_pa_parent_type(const struct parisc_device *padev, int type)
{
const struct device *dev = &padev->dev;
while (dev != &root) {
while (dev != root) {
struct parisc_device *candidate = to_parisc_device(dev);
if (candidate->id.hw_type == type)
return candidate;
@ -319,7 +317,7 @@ static void get_node_path(struct device *dev, struct hardware_path *path)
dev = dev->parent;
}
while (dev != &root) {
while (dev != root) {
if (dev_is_pci(dev)) {
unsigned int devfn = to_pci_dev(dev)->devfn;
path->bc[i--] = PCI_SLOT(devfn) | (PCI_FUNC(devfn)<< 5);
@ -482,7 +480,7 @@ static struct parisc_device * __init alloc_tree_node(
static struct parisc_device *create_parisc_device(struct hardware_path *modpath)
{
int i;
struct device *parent = &root;
struct device *parent = root;
for (i = 0; i < 6; i++) {
if (modpath->bc[i] == -1)
continue;
@ -755,7 +753,7 @@ parse_tree_node(struct device *parent, int index, struct hardware_path *modpath)
struct device *hwpath_to_device(struct hardware_path *modpath)
{
int i;
struct device *parent = &root;
struct device *parent = root;
for (i = 0; i < 6; i++) {
if (modpath->bc[i] == -1)
continue;
@ -880,7 +878,7 @@ void __init walk_central_bus(void)
{
walk_native_bus(CENTRAL_BUS_ADDR,
CENTRAL_BUS_ADDR + (MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET),
&root);
root);
}
static __init void print_parisc_device(struct parisc_device *dev)
@ -907,9 +905,10 @@ void __init init_parisc_bus(void)
{
if (bus_register(&parisc_bus_type))
panic("Could not register PA-RISC bus type\n");
if (device_register(&root))
root = root_device_register("parisc");
if (IS_ERR(root))
panic("Could not register PA-RISC root device\n");
get_device(&root);
}
static __init void qemu_header(void)

View File

@ -1414,6 +1414,9 @@ static inline char *debug_get_user_string(const char __user *user_buf,
{
char *buffer;
if (!user_len)
return ERR_PTR(-EINVAL);
buffer = memdup_user_nul(user_buf, user_len);
if (IS_ERR(buffer))
return buffer;
@ -1584,6 +1587,11 @@ static int debug_input_flush_fn(debug_info_t *id, struct debug_view *view,
char input_buf[1];
int rc = user_len;
if (!user_len) {
rc = -EINVAL;
goto out;
}
if (user_len > 0x10000)
user_len = 0x10000;
if (*offset != 0) {

View File

@ -438,7 +438,7 @@ void do_secure_storage_access(struct pt_regs *regs)
panic("Unexpected PGM 0x3d with TEID bit 61=0");
}
if (is_kernel_fault(regs)) {
folio = phys_to_folio(addr);
folio = virt_to_folio((void *)addr);
if (unlikely(!folio_try_get(folio)))
return;
rc = uv_convert_from_secure(folio_to_phys(folio));

View File

@ -7,7 +7,7 @@
/*
* This is set up by the setup-routine at boot-time
*/
extern unsigned char *boot_params_page;
extern unsigned char boot_params_page[];
#define PARAM boot_params_page
#define MOUNT_ROOT_RDONLY (*(unsigned long *) (PARAM+0x000))

View File

@ -137,7 +137,8 @@ extern void __init efi_dump_pagetable(void);
extern void __init efi_apply_memmap_quirks(void);
extern int __init efi_reuse_config(u64 tables, int nr_tables);
extern void efi_delete_dummy_variable(void);
extern void efi_crash_gracefully_on_page_fault(unsigned long phys_addr);
extern void efi_crash_gracefully_on_page_fault(unsigned long phys_addr,
const struct pt_regs *regs);
extern void efi_unmap_boot_services(void);
void arch_efi_call_virt_setup(void);

View File

@ -2040,7 +2040,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
* flush). Translate the address here so the memory can be uniformly
* read with kvm_read_guest().
*/
if (!hc->fast && is_guest_mode(vcpu)) {
if (!hc->fast && mmu_is_nested(vcpu)) {
hc->ingpa = translate_nested_gpa(vcpu, hc->ingpa, 0, NULL);
if (unlikely(hc->ingpa == INVALID_GPA))
return HV_STATUS_INVALID_HYPERCALL_INPUT;

View File

@ -667,13 +667,15 @@ bool __kvm_apic_update_irr(unsigned long *pir, void *regs, int *max_irr)
u32 *__pir = (void *)pir_vals;
u32 i, vec;
u32 irr_val, prev_irr_val;
int max_updated_irr;
int max_new_irr;
max_updated_irr = -1;
*max_irr = -1;
if (!pi_harvest_pir(pir, pir_vals))
if (!pi_harvest_pir(pir, pir_vals)) {
*max_irr = apic_find_highest_vector(regs + APIC_IRR);
return false;
}
max_new_irr = -1;
*max_irr = -1;
for (i = vec = 0; i <= 7; i++, vec += 32) {
u32 *p_irr = (u32 *)(regs + APIC_IRR + i * 0x10);
@ -688,25 +690,25 @@ bool __kvm_apic_update_irr(unsigned long *pir, void *regs, int *max_irr)
!try_cmpxchg(p_irr, &prev_irr_val, irr_val));
if (prev_irr_val != irr_val)
max_updated_irr = __fls(irr_val ^ prev_irr_val) + vec;
max_new_irr = __fls(irr_val ^ prev_irr_val) + vec;
}
if (irr_val)
*max_irr = __fls(irr_val) + vec;
}
return ((max_updated_irr != -1) &&
(max_updated_irr == *max_irr));
return max_new_irr != -1 && max_new_irr == *max_irr;
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(__kvm_apic_update_irr);
bool kvm_apic_update_irr(struct kvm_vcpu *vcpu, unsigned long *pir, int *max_irr)
{
struct kvm_lapic *apic = vcpu->arch.apic;
bool irr_updated = __kvm_apic_update_irr(pir, apic->regs, max_irr);
bool max_irr_is_from_pir;
if (unlikely(!apic->apicv_active && irr_updated))
max_irr_is_from_pir = __kvm_apic_update_irr(pir, apic->regs, max_irr);
if (unlikely(!apic->apicv_active && max_irr_is_from_pir))
apic->irr_pending = true;
return irr_updated;
return max_irr_is_from_pir;
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_update_irr);

View File

@ -182,6 +182,8 @@ static struct kmem_cache *pte_list_desc_cache;
struct kmem_cache *mmu_page_header_cache;
static void mmu_spte_set(u64 *sptep, u64 spte);
static int mmu_page_zap_pte(struct kvm *kvm, struct kvm_mmu_page *sp,
u64 *spte, struct list_head *invalid_list);
struct kvm_mmu_role_regs {
const unsigned long cr0;
@ -1287,19 +1289,6 @@ static void drop_spte(struct kvm *kvm, u64 *sptep)
rmap_remove(kvm, sptep);
}
static void drop_large_spte(struct kvm *kvm, u64 *sptep, bool flush)
{
struct kvm_mmu_page *sp;
sp = sptep_to_sp(sptep);
WARN_ON_ONCE(sp->role.level == PG_LEVEL_4K);
drop_spte(kvm, sptep);
if (flush)
kvm_flush_remote_tlbs_sptep(kvm, sptep);
}
/*
* Write-protect on the specified @sptep, @pt_protect indicates whether
* spte write-protection is caused by protecting shadow page table.
@ -2466,7 +2455,8 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu,
{
union kvm_mmu_page_role role;
if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep))
if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep) &&
spte_to_child_sp(*sptep) && spte_to_child_sp(*sptep)->gfn == gfn)
return ERR_PTR(-EEXIST);
role = kvm_mmu_child_role(sptep, direct, access);
@ -2544,13 +2534,16 @@ static void __link_shadow_page(struct kvm *kvm,
BUILD_BUG_ON(VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK);
/*
* If an SPTE is present already, it must be a leaf and therefore
* a large one. Drop it, and flush the TLB if needed, before
* installing sp.
*/
if (is_shadow_present_pte(*sptep))
drop_large_spte(kvm, sptep, flush);
if (is_shadow_present_pte(*sptep)) {
struct kvm_mmu_page *parent_sp;
LIST_HEAD(invalid_list);
parent_sp = sptep_to_sp(sptep);
WARN_ON_ONCE(parent_sp->role.level == PG_LEVEL_4K);
mmu_page_zap_pte(kvm, parent_sp, sptep, &invalid_list);
kvm_mmu_remote_flush_or_zap(kvm, &invalid_list, true);
}
spte = make_nonleaf_spte(sp->spt, sp_ad_disabled(sp));

View File

@ -7029,8 +7029,8 @@ static void vmx_set_rvi(int vector)
int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
{
struct vcpu_vt *vt = to_vt(vcpu);
bool max_irr_is_from_pir;
int max_irr;
bool got_posted_interrupt;
if (KVM_BUG_ON(!enable_apicv, vcpu->kvm))
return -EIO;
@ -7042,17 +7042,22 @@ int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
* But on x86 this is just a compiler barrier anyway.
*/
smp_mb__after_atomic();
got_posted_interrupt =
kvm_apic_update_irr(vcpu, vt->pi_desc.pir, &max_irr);
max_irr_is_from_pir = kvm_apic_update_irr(vcpu, vt->pi_desc.pir,
&max_irr);
} else {
max_irr = kvm_lapic_find_highest_irr(vcpu);
got_posted_interrupt = false;
max_irr_is_from_pir = false;
}
/*
* Newly recognized interrupts are injected via either virtual interrupt
* delivery (RVI) or KVM_REQ_EVENT. Virtual interrupt delivery is
* disabled in two cases:
* If APICv is enabled and L2 is not active, then update the Requesting
* Virtual Interrupt (RVI) portion of vmcs01.GUEST_INTR_STATUS with the
* highest priority IRR to deliver the IRQ via Virtual Interrupt
* Delivery. Note, this is required even if the highest priority IRQ
* was already pending in the IRR, as RVI isn't updated in lockstep with
* the IRR (unlike apic->irr_pending).
*
* For the cases where Virtual Interrupt Delivery can't be used:
*
* 1) If L2 is running and the vCPU has a new pending interrupt. If L1
* wants to exit on interrupts, KVM_REQ_EVENT is needed to synthesize a
@ -7063,10 +7068,29 @@ int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
* 2) If APICv is disabled for this vCPU, assigned devices may still
* attempt to post interrupts. The posted interrupt vector will cause
* a VM-Exit and the subsequent entry will call sync_pir_to_irr.
*
* In both cases, set KVM_REQ_EVENT if and only if the highest priority
* pending IRQ came from the PIR, as setting KVM_REQ_EVENT if any IRQ
* is pending may put the vCPU into an infinite loop, e.g. if the IRQ
* is blocked, then it will stay pending until an IRQ window is opened.
*
* Note! It's possible that one or more IRQs were moved from the PIR
* to the IRR _without_ max_irr_is_from_pir being true! I.e. if there
* was a higher priority IRQ already pending in the IRR. Not setting
* KVM_REQ_EVENT in this case is intentional and safe. If APICv is
* inactive, or L2 is running with exit-on-interrupt off (in vmcs12),
* i.e. without nested virtual interrupt delivery, then there's no need
* to request an IRQ window as the lower priority IRQ only needs to be
* delivered when the higher priority IRQ is dismissed from the ISR,
* i.e. on the next EOI, and EOIs are always intercepted if APICv is
* disabled or if L2 is running without nested VID. If L2 is running
* exit-on-interrupt on (in vmcs12), then the higher priority IRQ will
* trigger a nested VM-Exit, at which point KVM will re-evaluate L1's
* pending IRQs.
*/
if (!is_guest_mode(vcpu) && kvm_vcpu_apicv_active(vcpu))
vmx_set_rvi(max_irr);
else if (got_posted_interrupt)
else if (max_irr_is_from_pir)
kvm_make_request(KVM_REQ_EVENT, vcpu);
return max_irr;

View File

@ -686,7 +686,7 @@ page_fault_oops(struct pt_regs *regs, unsigned long error_code,
* avoid hanging the system.
*/
if (IS_ENABLED(CONFIG_EFI))
efi_crash_gracefully_on_page_fault(address);
efi_crash_gracefully_on_page_fault(address, regs);
/* Only not-present faults should be handled by KFENCE. */
if (!(error_code & X86_PF_PROT) &&

View File

@ -761,7 +761,8 @@ int efi_capsule_setup_info(struct capsule_info *cap_info, void *kbuff,
* @return: Returns, if the page fault is not handled. This function
* will never return if the page fault is handled successfully.
*/
void efi_crash_gracefully_on_page_fault(unsigned long phys_addr)
void efi_crash_gracefully_on_page_fault(unsigned long phys_addr,
const struct pt_regs *regs)
{
if (!IS_ENABLED(CONFIG_X86_64))
return;
@ -770,7 +771,7 @@ void efi_crash_gracefully_on_page_fault(unsigned long phys_addr)
* If we get an interrupt/NMI while processing an EFI runtime service
* then this is a regular OOPS, not an EFI failure.
*/
if (in_interrupt())
if (!in_task())
return;
/*
@ -810,6 +811,14 @@ void efi_crash_gracefully_on_page_fault(unsigned long phys_addr)
return;
}
/*
* The API does not permit entering a kernel mode FPU section with
* interrupts enabled and leaving it with interrupts disabled. So
* re-enable interrupts now if they were enabled when the page fault
* occurred.
*/
local_irq_restore(regs->flags);
/*
* Before calling EFI Runtime Service, the kernel has switched the
* calling process to efi_mm. Hence, switch back to task_mm.

View File

@ -390,6 +390,11 @@ static int crypto_authenc_esn_create(struct crypto_template *tmpl,
auth = crypto_spawn_ahash_alg(&ctx->auth);
auth_base = &auth->base;
if (auth->digestsize > 0 && auth->digestsize < 4) {
err = -EINVAL;
goto err_free_inst;
}
err = crypto_grab_skcipher(&ctx->enc, aead_crypto_instance(inst),
crypto_attr_alg_name(tb[2]), 0, mask);
if (err)

View File

@ -605,15 +605,12 @@ static umode_t acpi_tad_attr_is_visible(struct kobject *kobj,
return 0;
}
static const struct attribute_group acpi_tad_attr_group = {
static const struct attribute_group acpi_tad_group = {
.attrs = acpi_tad_attrs,
.is_visible = acpi_tad_attr_is_visible,
};
static const struct attribute_group *acpi_tad_attr_groups[] = {
&acpi_tad_attr_group,
NULL,
};
__ATTRIBUTE_GROUPS(acpi_tad);
#ifdef CONFIG_RTC_CLASS
/* RTC class device interface */
@ -683,9 +680,8 @@ static int acpi_tad_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
acpi_tad_rt_to_tm(&rt, &tm_now);
value = ktime_divns(ktime_sub(rtc_tm_to_ktime(t->time),
rtc_tm_to_ktime(tm_now)), NSEC_PER_SEC);
if (value <= 0 || value > U32_MAX)
value = rtc_tm_to_time64(&t->time) - rtc_tm_to_time64(&tm_now);
if (value <= 0 || value >= U32_MAX)
return -EINVAL;
}
@ -748,8 +744,7 @@ static int acpi_tad_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t)
if (retval != ACPI_TAD_WAKE_DISABLED) {
t->enabled = 1;
t->time = rtc_ktime_to_tm(ktime_add_ns(rtc_tm_to_ktime(tm_now),
(u64)retval * NSEC_PER_SEC));
rtc_time64_to_tm(rtc_tm_to_time64(&tm_now) + retval, &t->time);
} else {
t->enabled = 0;
t->time = tm_now;
@ -795,9 +790,9 @@ static int acpi_tad_disable_timer(struct device *dev, u32 timer_id)
return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED);
}
static void acpi_tad_remove(struct platform_device *pdev)
static void acpi_tad_remove(void *data)
{
struct device *dev = &pdev->dev;
struct device *dev = data;
struct acpi_tad_driver_data *dd = dev_get_drvdata(dev);
device_init_wakeup(dev, false);
@ -824,6 +819,7 @@ static int acpi_tad_probe(struct platform_device *pdev)
struct acpi_tad_driver_data *dd;
acpi_status status;
unsigned long long caps;
int ret;
/*
* Initialization failure messages are mostly about firmware issues, so
@ -863,13 +859,21 @@ static int acpi_tad_probe(struct platform_device *pdev)
}
/*
* The platform bus type layer tells the ACPI PM domain powers up the
* device, so set the runtime PM status of it to "active".
* The platform bus type probe callback tells the ACPI PM domain to
* power up the device, so set the runtime PM status of it to "active".
*/
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
pm_runtime_suspend(dev);
/*
* acpi_tad_remove() needs to run after unregistering the RTC class
* device to avoid racing with the latter's callbacks.
*/
ret = devm_add_action_or_reset(&pdev->dev, acpi_tad_remove, &pdev->dev);
if (ret)
return ret;
if (caps & ACPI_TAD_RT)
acpi_tad_register_rtc(dev, caps);
@ -885,10 +889,9 @@ static struct platform_driver acpi_tad_driver = {
.driver = {
.name = "acpi-tad",
.acpi_match_table = acpi_tad_ids,
.dev_groups = acpi_tad_attr_groups,
.dev_groups = acpi_tad_groups,
},
.probe = acpi_tad_probe,
.remove = acpi_tad_remove,
};
MODULE_DEVICE_TABLE(acpi, acpi_tad_ids);

View File

@ -401,8 +401,18 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region(
return NULL;
}
static bool is_memory_injection(u32 type, u32 flags)
{
if (flags & SETWA_FLAGS_EINJV2)
return !!(type & ACPI_EINJV2_MEMORY);
if (type & ACPI5_VENDOR_BIT)
return !!(vendor_flags & SETWA_FLAGS_MEM);
return !!(type & MEM_ERROR_MASK) || !!(flags & SETWA_FLAGS_MEM);
}
/* Execute instructions in trigger error action table */
static int __einj_error_trigger(u64 trigger_paddr, u32 type,
static int __einj_error_trigger(u64 trigger_paddr, u32 type, u32 flags,
u64 param1, u64 param2)
{
struct acpi_einj_trigger trigger_tab;
@ -480,7 +490,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
* This will cause resource conflict with regular memory. So
* remove it from trigger table resources.
*/
if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) {
if ((param_extension || acpi5) && is_memory_injection(type, flags)) {
struct apei_resources addr_resources;
apei_resources_init(&addr_resources);
@ -660,7 +670,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
return rc;
trigger_paddr = apei_exec_ctx_get_output(&ctx);
if (notrigger == 0) {
rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
rc = __einj_error_trigger(trigger_paddr, type, flags, param1, param2);
if (rc)
return rc;
}
@ -718,28 +728,6 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,
SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2)))
return -EINVAL;
/* check if type is a valid EINJv2 error type */
if (is_v2) {
if (!(type & available_error_type_v2))
return -EINVAL;
}
/*
* We need extra sanity checks for memory errors.
* Other types leap directly to injection.
*/
/* ensure param1/param2 existed */
if (!(param_extension || acpi5))
goto inject;
/* ensure injection is memory related */
if (type & ACPI5_VENDOR_BIT) {
if (vendor_flags != SETWA_FLAGS_MEM)
goto inject;
} else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) {
goto inject;
}
/*
* Injections targeting a CXL 1.0/1.1 port have to be injected
* via the einj_cxl_rch_error_inject() path as that does the proper
@ -748,6 +736,23 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,
if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))
return -EINVAL;
/* check if type is a valid EINJv2 error type */
if (is_v2) {
if (!(type & available_error_type_v2))
return -EINVAL;
}
/* ensure param1/param2 existed */
if (!(param_extension || acpi5))
goto inject;
/*
* We need extra sanity checks for memory errors.
* Other types leap directly to injection.
*/
if (!is_memory_injection(type, flags))
goto inject;
/*
* Disallow crazy address masks that give BIOS leeway to pick
* injection address almost anywhere. Insist on page or

View File

@ -16,7 +16,7 @@
static int psci_acpi_cpu_init_idle(unsigned int cpu)
{
int i, count;
int i;
struct acpi_lpi_state *lpi;
struct acpi_processor *pr = per_cpu(processors, cpu);
@ -30,14 +30,10 @@ static int psci_acpi_cpu_init_idle(unsigned int cpu)
if (!psci_ops.cpu_suspend)
return -EOPNOTSUPP;
count = pr->power.count - 1;
if (count <= 0)
return -ENODEV;
for (i = 0; i < count; i++) {
for (i = 1; i < pr->power.count; i++) {
u32 state;
lpi = &pr->power.lpi_states[i + 1];
lpi = &pr->power.lpi_states[i];
/*
* Only bits[31:0] represent a PSCI power_state while
* bits[63:32] must be 0x0 as per ARM ACPI FFH Specification

View File

@ -362,7 +362,7 @@ static int send_pcc_cmd(int pcc_ss_id, u16 cmd)
end:
if (cmd == CMD_WRITE) {
if (unlikely(ret)) {
for_each_online_cpu(i) {
for_each_possible_cpu(i) {
struct cpc_desc *desc = per_cpu(cpc_desc_ptr, i);
if (!desc)
@ -524,13 +524,13 @@ int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data)
else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
cpu_data->shared_type = CPUFREQ_SHARED_TYPE_ANY;
for_each_online_cpu(i) {
for_each_possible_cpu(i) {
if (i == cpu)
continue;
match_cpc_ptr = per_cpu(cpc_desc_ptr, i);
if (!match_cpc_ptr)
goto err_fault;
continue;
match_pdomain = &(match_cpc_ptr->domain_info);
if (match_pdomain->domain != pdomain->domain)

View File

@ -916,6 +916,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "82K8"),
},
},
{
.callback = video_detect_force_native,
/* HP OMEN Gaming Laptop 16-n0xxx */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-n0xxx"),
},
},
/*
* x86 android tablets which directly control the backlight through

View File

@ -172,7 +172,7 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va
ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size);
if (ret == -ENODATA) {
if (!deferrable)
dev_warn(dev, "Defer on undeferable control: %x\n", reg);
dev_warn(dev, "Defer on undeferrable control: %x\n", reg);
ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx);
if (ret)

View File

@ -289,6 +289,9 @@ static inline void btintel_pcie_dump_debug_registers(struct hci_dev *hdev)
skb_put_data(skb, buf, strlen(buf));
data->boot_stage_cache = reg;
if (reg & BTINTEL_PCIE_CSR_BOOT_STAGE_DEVICE_WARNING)
bt_dev_warn(hdev, "Controller device warning (boot_stage: 0x%8.8x)", reg);
reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IPC_STATUS_REG);
snprintf(buf, sizeof(buf), "ipc status: 0x%8.8x", reg);
skb_put_data(skb, buf, strlen(buf));
@ -880,8 +883,11 @@ static inline bool btintel_pcie_in_lockdown(struct btintel_pcie_data *data)
static inline bool btintel_pcie_in_error(struct btintel_pcie_data *data)
{
return (data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_DEVICE_ERR) ||
(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_ABORT_HANDLER);
if (data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_DEVICE_WARNING)
bt_dev_warn(data->hdev, "Controller device warning (boot_stage: 0x%8.8x)",
data->boot_stage_cache);
return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_ABORT_HANDLER;
}
static void btintel_pcie_msix_gp1_handler(struct btintel_pcie_data *data)
@ -914,7 +920,8 @@ static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data)
data->img_resp_cache = reg;
if (btintel_pcie_in_error(data)) {
bt_dev_err(data->hdev, "Controller in error state");
bt_dev_err(data->hdev, "Controller in error state (boot_stage: 0x%8.8x)",
data->boot_stage_cache);
btintel_pcie_dump_debug_registers(data->hdev);
return;
}

View File

@ -48,7 +48,7 @@
#define BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW (BIT(2))
#define BTINTEL_PCIE_CSR_BOOT_STAGE_ROM_LOCKDOWN (BIT(10))
#define BTINTEL_PCIE_CSR_BOOT_STAGE_IML_LOCKDOWN (BIT(11))
#define BTINTEL_PCIE_CSR_BOOT_STAGE_DEVICE_ERR (BIT(12))
#define BTINTEL_PCIE_CSR_BOOT_STAGE_DEVICE_WARNING (BIT(12))
#define BTINTEL_PCIE_CSR_BOOT_STAGE_ABORT_HANDLER (BIT(13))
#define BTINTEL_PCIE_CSR_BOOT_STAGE_DEVICE_HALTED (BIT(14))
#define BTINTEL_PCIE_CSR_BOOT_STAGE_MAC_ACCESS_ON (BIT(16))

View File

@ -695,8 +695,13 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
if (data->evt_skb == NULL)
goto err_free_wc;
/* Parse and handle the return WMT event */
wmt_evt = (struct btmtk_hci_wmt_evt *)data->evt_skb->data;
wmt_evt = skb_pull_data(data->evt_skb, sizeof(*wmt_evt));
if (!wmt_evt) {
bt_dev_err(hdev, "WMT event too short (%u bytes)",
data->evt_skb->len);
err = -EINVAL;
goto err_free_skb;
}
if (wmt_evt->whdr.op != hdr->op) {
bt_dev_err(hdev, "Wrong op received %d expected %d",
wmt_evt->whdr.op, hdr->op);
@ -712,6 +717,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
status = BTMTK_WMT_PATCH_DONE;
break;
case BTMTK_WMT_FUNC_CTRL:
if (!skb_pull_data(data->evt_skb,
sizeof(wmt_evt_funcc->status))) {
err = -EINVAL;
goto err_free_skb;
}
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
status = BTMTK_WMT_ON_DONE;

View File

@ -191,6 +191,9 @@ static int ath_recv(struct hci_uart *hu, const void *data, int count)
{
struct ath_struct *ath = hu->priv;
if (!ath)
return -ENODEV;
ath->rx_skb = h4_recv_buf(hu, ath->rx_skb, data, count,
ath_recv_pkts, ARRAY_SIZE(ath_recv_pkts));
if (IS_ERR(ath->rx_skb)) {

View File

@ -585,6 +585,9 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
return -EUNATCH;
if (!bcsp)
return -ENODEV;
BT_DBG("hu %p count %d rx_state %d rx_count %ld",
hu, count, bcsp->rx_state, bcsp->rx_count);

View File

@ -109,6 +109,9 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count)
{
struct h4_struct *h4 = hu->priv;
if (!h4)
return -ENODEV;
h4->rx_skb = h4_recv_buf(hu, h4->rx_skb, data, count,
h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts));
if (IS_ERR(h4->rx_skb)) {

View File

@ -587,6 +587,9 @@ static int h5_recv(struct hci_uart *hu, const void *data, int count)
struct h5 *h5 = hu->priv;
const unsigned char *ptr = data;
if (!h5)
return -ENODEV;
BT_DBG("%s pending %zu count %d", hu->hdev->name, h5->rx_pending,
count);

View File

@ -12,6 +12,7 @@
#include <net/bluetooth/hci_core.h>
#define VERSION "0.1"
#define VIRTBT_RX_BUF_SIZE 1000
enum {
VIRTBT_VQ_TX,
@ -33,11 +34,11 @@ static int virtbt_add_inbuf(struct virtio_bluetooth *vbt)
struct sk_buff *skb;
int err;
skb = alloc_skb(1000, GFP_KERNEL);
skb = alloc_skb(VIRTBT_RX_BUF_SIZE, GFP_KERNEL);
if (!skb)
return -ENOMEM;
sg_init_one(sg, skb->data, 1000);
sg_init_one(sg, skb->data, VIRTBT_RX_BUF_SIZE);
err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_KERNEL);
if (err < 0) {
@ -197,6 +198,7 @@ static int virtbt_shutdown_generic(struct hci_dev *hdev)
static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb)
{
size_t min_hdr;
__u8 pkt_type;
pkt_type = *((__u8 *) skb->data);
@ -204,16 +206,32 @@ static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb)
switch (pkt_type) {
case HCI_EVENT_PKT:
min_hdr = sizeof(struct hci_event_hdr);
break;
case HCI_ACLDATA_PKT:
min_hdr = sizeof(struct hci_acl_hdr);
break;
case HCI_SCODATA_PKT:
min_hdr = sizeof(struct hci_sco_hdr);
break;
case HCI_ISODATA_PKT:
hci_skb_pkt_type(skb) = pkt_type;
hci_recv_frame(vbt->hdev, skb);
min_hdr = sizeof(struct hci_iso_hdr);
break;
default:
kfree_skb(skb);
break;
return;
}
if (skb->len < min_hdr) {
bt_dev_err_ratelimited(vbt->hdev,
"rx pkt_type 0x%02x payload %u < hdr %zu\n",
pkt_type, skb->len, min_hdr);
kfree_skb(skb);
return;
}
hci_skb_pkt_type(skb) = pkt_type;
hci_recv_frame(vbt->hdev, skb);
}
static void virtbt_rx_work(struct work_struct *work)
@ -227,8 +245,15 @@ static void virtbt_rx_work(struct work_struct *work)
if (!skb)
return;
skb_put(skb, len);
virtbt_rx_handle(vbt, skb);
if (!len || len > VIRTBT_RX_BUF_SIZE) {
bt_dev_err_ratelimited(vbt->hdev,
"rx reply len %u outside [1, %u]\n",
len, VIRTBT_RX_BUF_SIZE);
kfree_skb(skb);
} else {
skb_put(skb, len);
virtbt_rx_handle(vbt, skb);
}
if (virtbt_add_inbuf(vbt) < 0)
return;

View File

@ -631,6 +631,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi)
WARN_ON(!cdo->generic_packet);
/*
* Propagate the drive's write support to the block layer so BLKROGET
* reflects actual write capability. Drivers that use GET CONFIGURATION
* features (CDC_MRW_W, CDC_RAM) must have called
* cdrom_probe_write_features() before register_cdrom() so the mask is
* complete here.
*/
set_disk_ro(disk, !CDROM_CAN(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM |
CDC_CD_RW));
cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
mutex_lock(&cdrom_mutex);
list_add(&cdi->list, &cdrom_list);
@ -742,6 +752,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write)
return 0;
}
/*
* Probe write-related MMC features via GET CONFIGURATION and update
* cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE
* capabilities page (e.g. sr) should call this after those MODE SENSE bits
* have been set but before register_cdrom(), so that the full set of
* write-capability bits is known by the time register_cdrom() decides on the
* initial read-only state of the disk.
*/
void cdrom_probe_write_features(struct cdrom_device_info *cdi)
{
int mrw, mrw_write, ram_write;
mrw = 0;
if (!cdrom_is_mrw(cdi, &mrw_write))
mrw = 1;
if (CDROM_CAN(CDC_MO_DRIVE))
ram_write = 1;
else
(void) cdrom_is_random_writable(cdi, &ram_write);
if (mrw)
cdi->mask &= ~CDC_MRW;
else
cdi->mask |= CDC_MRW;
if (mrw_write)
cdi->mask &= ~CDC_MRW_W;
else
cdi->mask |= CDC_MRW_W;
if (ram_write)
cdi->mask &= ~CDC_RAM;
else
cdi->mask |= CDC_RAM;
}
EXPORT_SYMBOL(cdrom_probe_write_features);
static int cdrom_media_erasable(struct cdrom_device_info *cdi)
{
disc_information di;
@ -894,33 +942,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi)
*/
static int cdrom_open_write(struct cdrom_device_info *cdi)
{
int mrw, mrw_write, ram_write;
int ret = 1;
mrw = 0;
if (!cdrom_is_mrw(cdi, &mrw_write))
mrw = 1;
if (CDROM_CAN(CDC_MO_DRIVE))
ram_write = 1;
else
(void) cdrom_is_random_writable(cdi, &ram_write);
if (mrw)
cdi->mask &= ~CDC_MRW;
else
cdi->mask |= CDC_MRW;
if (mrw_write)
cdi->mask &= ~CDC_MRW_W;
else
cdi->mask |= CDC_MRW_W;
if (ram_write)
cdi->mask &= ~CDC_RAM;
else
cdi->mask |= CDC_RAM;
if (CDROM_CAN(CDC_MRW_W))
ret = cdrom_mrw_open_write(cdi);
else if (CDROM_CAN(CDC_DVD_RAM))

View File

@ -168,6 +168,10 @@ struct smi_info {
OEM2_DATA_AVAIL)
unsigned char msg_flags;
/* When requesting events and messages, don't do it forever. */
unsigned int num_requests_in_a_row;
bool last_was_flag_fetch;
/* Does the BMC have an event buffer? */
bool has_event_buffer;
@ -410,7 +414,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
start_new_msg(smi_info, smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
smi_info->si_state = SI_GETTING_MESSAGES;
if (smi_info->si_state != SI_GETTING_MESSAGES) {
smi_info->num_requests_in_a_row = 0;
smi_info->si_state = SI_GETTING_MESSAGES;
}
}
static void start_getting_events(struct smi_info *smi_info)
@ -421,7 +428,10 @@ static void start_getting_events(struct smi_info *smi_info)
start_new_msg(smi_info, smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
smi_info->si_state = SI_GETTING_EVENTS;
if (smi_info->si_state != SI_GETTING_EVENTS) {
smi_info->num_requests_in_a_row = 0;
smi_info->si_state = SI_GETTING_EVENTS;
}
}
/*
@ -487,15 +497,19 @@ static void handle_flags(struct smi_info *smi_info)
} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
/* Messages available. */
smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
if (!smi_info->curr_msg)
if (!smi_info->curr_msg) {
smi_info->si_state = SI_NORMAL;
return;
}
start_getting_msg_queue(smi_info);
} else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
/* Events available. */
smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
if (!smi_info->curr_msg)
if (!smi_info->curr_msg) {
smi_info->si_state = SI_NORMAL;
return;
}
start_getting_events(smi_info);
} else if (smi_info->msg_flags & OEM_DATA_AVAIL &&
@ -595,6 +609,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
smi_info->si_state = SI_NORMAL;
} else {
smi_info->msg_flags = msg[3];
smi_info->last_was_flag_fetch = true;
handle_flags(smi_info);
}
break;
@ -630,7 +645,13 @@ static void handle_transaction_done(struct smi_info *smi_info)
*/
msg = smi_info->curr_msg;
smi_info->curr_msg = NULL;
if (msg->rsp[2] != 0) {
/*
* It appears some BMCs, with no event data, return no
* data in the message and not a 0x80 error as the
* spec says they should. Shut down processing if
* the data is not the right length.
*/
if (msg->rsp[2] != 0 || msg->rsp_size != 19) {
/* Error getting event, probably done. */
msg->done(msg);
@ -640,6 +661,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
} else {
smi_inc_stat(smi_info, events);
smi_info->num_requests_in_a_row++;
if (smi_info->num_requests_in_a_row > 10)
/* Stop if we do this too many times. */
smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
/*
* Do this before we deliver the message
* because delivering the message releases the
@ -678,6 +704,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
} else {
smi_inc_stat(smi_info, incoming_messages);
smi_info->num_requests_in_a_row++;
if (smi_info->num_requests_in_a_row > 10)
/* Stop if we do this too many times. */
smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
/*
* Do this before we deliver the message
* because delivering the message releases the
@ -819,6 +850,26 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
goto out;
}
/*
* If we are currently idle, or if the last thing that was
* done was a flag fetch and there is a message pending, try
* to start the next message.
*
* We do the waiting message check to avoid a stuck flag
* completely wedging the driver. Let a message through
* in between flag operations if that happens.
*/
if (si_sm_result == SI_SM_IDLE ||
(si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
smi_info->last_was_flag_fetch)) {
smi_info->last_was_flag_fetch = false;
smi_inc_stat(smi_info, idles);
si_sm_result = start_next_msg(smi_info);
if (si_sm_result != SI_SM_IDLE)
goto restart;
}
/*
* We prefer handling attn over new messages. But don't do
* this if there is not yet an upper layer to handle anything.
@ -846,15 +897,6 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
}
}
/* If we are currently idle, try to start the next message. */
if (si_sm_result == SI_SM_IDLE) {
smi_inc_stat(smi_info, idles);
si_sm_result = start_next_msg(smi_info);
if (si_sm_result != SI_SM_IDLE)
goto restart;
}
if ((si_sm_result == SI_SM_IDLE)
&& (atomic_read(&smi_info->req_events))) {
/*

View File

@ -225,6 +225,9 @@ struct ssif_info {
bool has_event_buffer;
bool supports_alert;
/* When requesting events and messages, don't do it forever. */
unsigned int num_requests_in_a_row;
/*
* Used to tell what we should do with alerts. If we are
* waiting on a response, read the data immediately.
@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
}
ssif_info->curr_msg = msg;
ssif_info->ssif_state = SSIF_GETTING_EVENTS;
if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
ssif_info->num_requests_in_a_row = 0;
ssif_info->ssif_state = SSIF_GETTING_EVENTS;
}
ipmi_ssif_unlock_cond(ssif_info, flags);
msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
}
ssif_info->curr_msg = msg;
ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
ssif_info->num_requests_in_a_row = 0;
ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
}
ipmi_ssif_unlock_cond(ssif_info, flags);
msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
handle_flags(ssif_info, flags);
} else {
ssif_info->num_requests_in_a_row++;
if (ssif_info->num_requests_in_a_row > 10)
/* Stop if we do this too many times. */
ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
handle_flags(ssif_info, flags);
ssif_inc_stat(ssif_info, events);
deliver_recv_msg(ssif_info, msg);
@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
handle_flags(ssif_info, flags);
} else {
ssif_info->num_requests_in_a_row++;
if (ssif_info->num_requests_in_a_row > 10)
/* Stop if we do this too many times. */
ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
ssif_inc_stat(ssif_info, incoming_messages);
handle_flags(ssif_info, flags);
deliver_recv_msg(ssif_info, msg);
@ -1886,6 +1905,7 @@ static int ssif_probe(struct i2c_client *client)
"kssif%4.4x", thread_num);
if (IS_ERR(ssif_info->thread)) {
rv = PTR_ERR(ssif_info->thread);
ssif_info->thread = NULL;
dev_notice(&ssif_info->client->dev,
"Could not start kernel thread: error %d\n",
rv);

View File

@ -60,8 +60,10 @@ static int efi_pstore_open(struct pstore_info *psi)
return err;
psi->data = kzalloc(record_size, GFP_KERNEL);
if (!psi->data)
if (!psi->data) {
efivar_unlock();
return -ENOMEM;
}
return 0;
}

View File

@ -66,7 +66,7 @@ KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \
file.o mem.o random.o randomalloc.o pci.o \
skip_spaces.o lib-cmdline.o lib-ctype.o \
alignedmem.o relocate.o printk.o vsprintf.o
alignedmem.o printk.o vsprintf.o
# include the stub's libfdt dependencies from lib/ when needed
libfdt-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c \

View File

@ -1104,13 +1104,6 @@ efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
unsigned long *addr, unsigned long min);
efi_status_t efi_relocate_kernel(unsigned long *image_addr,
unsigned long image_size,
unsigned long alloc_size,
unsigned long preferred_addr,
unsigned long alignment,
unsigned long min_addr);
efi_status_t efi_parse_options(char const *cmdline);
void efi_parse_option_graphics(char *option);

View File

@ -14,6 +14,86 @@ extern int kernel_asize;
extern int kernel_fsize;
extern int kernel_entry;
/**
* efi_relocate_kernel() - copy memory area
* @image_addr: pointer to address of memory area to copy
* @image_size: size of memory area to copy
* @alloc_size: minimum size of memory to allocate, must be greater or
* equal to image_size
* @preferred_addr: preferred target address
* @alignment: minimum alignment of the allocated memory area. It
* should be a power of two.
* @min_addr: minimum target address
*
* Copy a memory area to a newly allocated memory area aligned according
* to @alignment but at least EFI_ALLOC_ALIGN. If the preferred address
* is not available, the allocated address will not be below @min_addr.
* On exit, @image_addr is updated to the target copy address that was used.
*
* This function is used to copy the Linux kernel verbatim. It does not apply
* any relocation changes.
*
* Return: status code
*/
static
efi_status_t efi_relocate_kernel(unsigned long *image_addr,
unsigned long image_size,
unsigned long alloc_size,
unsigned long preferred_addr,
unsigned long alignment,
unsigned long min_addr)
{
unsigned long cur_image_addr;
unsigned long new_addr = 0;
efi_status_t status;
unsigned long nr_pages;
efi_physical_addr_t efi_addr = preferred_addr;
if (!image_addr || !image_size || !alloc_size)
return EFI_INVALID_PARAMETER;
if (alloc_size < image_size)
return EFI_INVALID_PARAMETER;
cur_image_addr = *image_addr;
/*
* The EFI firmware loader could have placed the kernel image
* anywhere in memory, but the kernel has restrictions on the
* max physical address it can run at. Some architectures
* also have a preferred address, so first try to relocate
* to the preferred address. If that fails, allocate as low
* as possible while respecting the required alignment.
*/
nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
EFI_LOADER_DATA, nr_pages, &efi_addr);
new_addr = efi_addr;
/*
* If preferred address allocation failed allocate as low as
* possible.
*/
if (status != EFI_SUCCESS) {
status = efi_low_alloc_above(alloc_size, alignment, &new_addr,
min_addr);
}
if (status != EFI_SUCCESS) {
efi_err("Failed to allocate usable memory for kernel.\n");
return status;
}
/*
* We know source/dest won't overlap since both memory ranges
* have been allocated by UEFI, so we can safely use memcpy.
*/
memcpy((void *)new_addr, (void *)cur_image_addr, image_size);
efi_cache_sync_image(new_addr, image_size);
/* Return the new address of the relocated image. */
*image_addr = new_addr;
return status;
}
efi_status_t handle_kernel_image(unsigned long *image_addr,
unsigned long *image_size,
unsigned long *reserve_addr,

View File

@ -18,6 +18,11 @@ efi_status_t check_platform_features(void)
return EFI_SUCCESS;
}
void efi_cache_sync_image(unsigned long image_base, unsigned long alloc_size)
{
asm volatile ("ibar 0" ::: "memory");
}
struct exit_boot_struct {
efi_memory_desc_t *runtime_map;
int runtime_entry_count;

View File

@ -124,3 +124,85 @@ void efi_free(unsigned long size, unsigned long addr)
nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
efi_bs_call(free_pages, addr, nr_pages);
}
/**
* efi_low_alloc_above() - allocate pages at or above given address
* @size: size of the memory area to allocate
* @align: minimum alignment of the allocated memory area. It should
* a power of two.
* @addr: on exit the address of the allocated memory
* @min: minimum address to used for the memory allocation
*
* Allocate at the lowest possible address that is not below @min as
* EFI_LOADER_DATA. The allocated pages are aligned according to @align but at
* least EFI_ALLOC_ALIGN. The first allocated page will not below the address
* given by @min.
*
* Return: status code
*/
efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
unsigned long *addr, unsigned long min)
{
struct efi_boot_memmap *map __free(efi_pool) = NULL;
efi_status_t status;
unsigned long nr_pages;
int i;
status = efi_get_memory_map(&map, false);
if (status != EFI_SUCCESS)
return status;
/*
* Enforce minimum alignment that EFI or Linux requires when
* requesting a specific address. We are doing page-based (or
* larger) allocations, and both the address and size must meet
* alignment constraints.
*/
if (align < EFI_ALLOC_ALIGN)
align = EFI_ALLOC_ALIGN;
size = round_up(size, EFI_ALLOC_ALIGN);
nr_pages = size / EFI_PAGE_SIZE;
for (i = 0; i < map->map_size / map->desc_size; i++) {
efi_memory_desc_t *desc;
unsigned long m = (unsigned long)map->map;
u64 start, end;
desc = efi_memdesc_ptr(m, map->desc_size, i);
if (desc->type != EFI_CONVENTIONAL_MEMORY)
continue;
if (desc->attribute & EFI_MEMORY_HOT_PLUGGABLE)
continue;
if (efi_soft_reserve_enabled() &&
(desc->attribute & EFI_MEMORY_SP))
continue;
if (desc->num_pages < nr_pages)
continue;
start = desc->phys_addr;
end = start + desc->num_pages * EFI_PAGE_SIZE;
if (start < min)
start = min;
start = round_up(start, align);
if ((start + size) > end)
continue;
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
EFI_LOADER_DATA, nr_pages, &start);
if (status == EFI_SUCCESS) {
*addr = start;
break;
}
}
if (i == map->map_size / map->desc_size)
return EFI_NOT_FOUND;
return EFI_SUCCESS;
}

View File

@ -1,166 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/efi.h>
#include <asm/efi.h>
#include "efistub.h"
/**
* efi_low_alloc_above() - allocate pages at or above given address
* @size: size of the memory area to allocate
* @align: minimum alignment of the allocated memory area. It should
* a power of two.
* @addr: on exit the address of the allocated memory
* @min: minimum address to used for the memory allocation
*
* Allocate at the lowest possible address that is not below @min as
* EFI_LOADER_DATA. The allocated pages are aligned according to @align but at
* least EFI_ALLOC_ALIGN. The first allocated page will not below the address
* given by @min.
*
* Return: status code
*/
efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
unsigned long *addr, unsigned long min)
{
struct efi_boot_memmap *map __free(efi_pool) = NULL;
efi_status_t status;
unsigned long nr_pages;
int i;
status = efi_get_memory_map(&map, false);
if (status != EFI_SUCCESS)
return status;
/*
* Enforce minimum alignment that EFI or Linux requires when
* requesting a specific address. We are doing page-based (or
* larger) allocations, and both the address and size must meet
* alignment constraints.
*/
if (align < EFI_ALLOC_ALIGN)
align = EFI_ALLOC_ALIGN;
size = round_up(size, EFI_ALLOC_ALIGN);
nr_pages = size / EFI_PAGE_SIZE;
for (i = 0; i < map->map_size / map->desc_size; i++) {
efi_memory_desc_t *desc;
unsigned long m = (unsigned long)map->map;
u64 start, end;
desc = efi_memdesc_ptr(m, map->desc_size, i);
if (desc->type != EFI_CONVENTIONAL_MEMORY)
continue;
if (desc->attribute & EFI_MEMORY_HOT_PLUGGABLE)
continue;
if (efi_soft_reserve_enabled() &&
(desc->attribute & EFI_MEMORY_SP))
continue;
if (desc->num_pages < nr_pages)
continue;
start = desc->phys_addr;
end = start + desc->num_pages * EFI_PAGE_SIZE;
if (start < min)
start = min;
start = round_up(start, align);
if ((start + size) > end)
continue;
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
EFI_LOADER_DATA, nr_pages, &start);
if (status == EFI_SUCCESS) {
*addr = start;
break;
}
}
if (i == map->map_size / map->desc_size)
return EFI_NOT_FOUND;
return EFI_SUCCESS;
}
/**
* efi_relocate_kernel() - copy memory area
* @image_addr: pointer to address of memory area to copy
* @image_size: size of memory area to copy
* @alloc_size: minimum size of memory to allocate, must be greater or
* equal to image_size
* @preferred_addr: preferred target address
* @alignment: minimum alignment of the allocated memory area. It
* should be a power of two.
* @min_addr: minimum target address
*
* Copy a memory area to a newly allocated memory area aligned according
* to @alignment but at least EFI_ALLOC_ALIGN. If the preferred address
* is not available, the allocated address will not be below @min_addr.
* On exit, @image_addr is updated to the target copy address that was used.
*
* This function is used to copy the Linux kernel verbatim. It does not apply
* any relocation changes.
*
* Return: status code
*/
efi_status_t efi_relocate_kernel(unsigned long *image_addr,
unsigned long image_size,
unsigned long alloc_size,
unsigned long preferred_addr,
unsigned long alignment,
unsigned long min_addr)
{
unsigned long cur_image_addr;
unsigned long new_addr = 0;
efi_status_t status;
unsigned long nr_pages;
efi_physical_addr_t efi_addr = preferred_addr;
if (!image_addr || !image_size || !alloc_size)
return EFI_INVALID_PARAMETER;
if (alloc_size < image_size)
return EFI_INVALID_PARAMETER;
cur_image_addr = *image_addr;
/*
* The EFI firmware loader could have placed the kernel image
* anywhere in memory, but the kernel has restrictions on the
* max physical address it can run at. Some architectures
* also have a preferred address, so first try to relocate
* to the preferred address. If that fails, allocate as low
* as possible while respecting the required alignment.
*/
nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
EFI_LOADER_DATA, nr_pages, &efi_addr);
new_addr = efi_addr;
/*
* If preferred address allocation failed allocate as low as
* possible.
*/
if (status != EFI_SUCCESS) {
status = efi_low_alloc_above(alloc_size, alignment, &new_addr,
min_addr);
}
if (status != EFI_SUCCESS) {
efi_err("Failed to allocate usable memory for kernel.\n");
return status;
}
/*
* We know source/dest won't overlap since both memory ranges
* have been allocated by UEFI, so we can safely use memcpy.
*/
memcpy((void *)new_addr, (void *)cur_image_addr, image_size);
/* Return the new address of the relocated image. */
*image_addr = new_addr;
return status;
}

View File

@ -2839,8 +2839,12 @@ static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev)
* that checks whether the PSP is running. A solution for those issues
* in the APU is to trigger a GPU reset, but this should be done during
* the unload phase to avoid adding boot latency and screen flicker.
* GFX V11 has GC block as default off IP. Every time AMDGPU driver sends
* a request to PMFW to unload MP1, PMFW will put GC in reset and power down
* the voltage. Hence, skipping reset for APUs with GFX V11 or later.
*/
if ((adev->flags & AMD_IS_APU) && !adev->gmc.is_app_apu) {
if ((adev->flags & AMD_IS_APU) && !adev->gmc.is_app_apu &&
amdgpu_ip_version(adev, GC_HWIP, 0) < IP_VERSION(11, 0, 0)) {
r = amdgpu_asic_reset(adev);
if (r)
dev_err(adev->dev, "asic reset on %s failed\n", __func__);

View File

@ -3090,10 +3090,8 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(11, 5, 1):
case IP_VERSION(11, 5, 2):
case IP_VERSION(11, 5, 3):
adev->family = AMDGPU_FAMILY_GC_11_5_0;
break;
case IP_VERSION(11, 5, 4):
adev->family = AMDGPU_FAMILY_GC_11_5_4;
adev->family = AMDGPU_FAMILY_GC_11_5_0;
break;
case IP_VERSION(12, 0, 0):
case IP_VERSION(12, 0, 1):

View File

@ -3158,8 +3158,10 @@ static int __init amdgpu_init(void)
amdgpu_register_atpx_handler();
amdgpu_acpi_detect();
/* Ignore KFD init failures. Normal when CONFIG_HSA_AMD is not set. */
amdgpu_amdkfd_init();
/* Ignore KFD init failures when CONFIG_HSA_AMD is not set. */
r = amdgpu_amdkfd_init();
if (r && r != -ENOENT)
goto error_fence;
if (amdgpu_pp_feature_mask & PP_OVERDRIVE_MASK) {
add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);

View File

@ -314,7 +314,10 @@ void amdgpu_gmc_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc,
mc->gart_start = max_mc_address - mc->gart_size + 1;
break;
case AMDGPU_GART_PLACEMENT_LOW:
mc->gart_start = 0;
if (size_bf >= mc->gart_size)
mc->gart_start = 0;
else
mc->gart_start = ALIGN(mc->fb_end, four_gb);
break;
case AMDGPU_GART_PLACEMENT_BEST_FIT:
default:

View File

@ -873,68 +873,59 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
? -EFAULT : 0;
}
case AMDGPU_INFO_READ_MMR_REG: {
int ret = 0;
unsigned int n, alloc_size;
uint32_t *regs;
unsigned int se_num = (info->read_mmr_reg.instance >>
AMDGPU_INFO_MMR_SE_INDEX_SHIFT) &
AMDGPU_INFO_MMR_SE_INDEX_MASK;
unsigned int sh_num = (info->read_mmr_reg.instance >>
AMDGPU_INFO_MMR_SH_INDEX_SHIFT) &
AMDGPU_INFO_MMR_SH_INDEX_MASK;
if (!down_read_trylock(&adev->reset_domain->sem))
return -ENOENT;
unsigned int alloc_size;
uint32_t *regs;
int ret;
/* set full masks if the userspace set all bits
* in the bitfields
*/
if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) {
if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK)
se_num = 0xffffffff;
} else if (se_num >= AMDGPU_GFX_MAX_SE) {
ret = -EINVAL;
goto out;
}
else if (se_num >= AMDGPU_GFX_MAX_SE)
return -EINVAL;
if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) {
if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK)
sh_num = 0xffffffff;
} else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) {
ret = -EINVAL;
goto out;
}
else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE)
return -EINVAL;
if (info->read_mmr_reg.count > 128) {
ret = -EINVAL;
goto out;
}
if (info->read_mmr_reg.count > 128)
return -EINVAL;
regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL);
if (!regs) {
ret = -ENOMEM;
goto out;
}
regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs),
GFP_KERNEL);
if (!regs)
return -ENOMEM;
down_read(&adev->reset_domain->sem);
alloc_size = info->read_mmr_reg.count * sizeof(*regs);
amdgpu_gfx_off_ctrl(adev, false);
ret = 0;
for (i = 0; i < info->read_mmr_reg.count; i++) {
if (amdgpu_asic_read_register(adev, se_num, sh_num,
info->read_mmr_reg.dword_offset + i,
&regs[i])) {
DRM_DEBUG_KMS("unallowed offset %#x\n",
info->read_mmr_reg.dword_offset + i);
kfree(regs);
amdgpu_gfx_off_ctrl(adev, true);
ret = -EFAULT;
goto out;
break;
}
}
amdgpu_gfx_off_ctrl(adev, true);
n = copy_to_user(out, regs, min(size, alloc_size));
kfree(regs);
ret = (n ? -EFAULT : 0);
out:
up_read(&adev->reset_domain->sem);
if (!ret) {
ret = copy_to_user(out, regs, min(size, alloc_size))
? -EFAULT : 0;
}
kfree(regs);
return ret;
}
case AMDGPU_INFO_DEV_INFO: {

View File

@ -1950,7 +1950,7 @@ void amdgpu_ras_check_bad_page_status(struct amdgpu_device *adev)
if (!control || amdgpu_bad_page_threshold == 0)
return;
if (control->ras_num_bad_pages >= ras->bad_page_cnt_threshold) {
if (control->ras_num_bad_pages > ras->bad_page_cnt_threshold) {
if (amdgpu_dpm_send_rma_reason(adev))
dev_warn(adev->dev, "Unable to send out-of-band RMA CPER");
else

View File

@ -75,6 +75,9 @@ static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev,
unsigned int type,
uint64_t size_in_page)
{
if (!size_in_page)
return 0;
return ttm_range_man_init(&adev->mman.bdev, type,
false, size_in_page);
}

View File

@ -205,6 +205,19 @@ void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue)
msecs_to_jiffies(timeout_ms));
}
void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell)
{
struct xarray *xa = &adev->userq_doorbell_xa;
struct amdgpu_usermode_queue *queue;
unsigned long flags;
xa_lock_irqsave(xa, flags);
queue = xa_load(xa, doorbell);
if (queue)
amdgpu_userq_fence_driver_process(queue->fence_drv);
xa_unlock_irqrestore(xa, flags);
}
static void amdgpu_userq_init_hang_detect_work(struct amdgpu_usermode_queue *queue)
{
INIT_DELAYED_WORK(&queue->hang_detect_work, amdgpu_userq_hang_detect_work);
@ -643,12 +656,6 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
#endif
amdgpu_userq_detect_and_reset_queues(uq_mgr);
r = amdgpu_userq_unmap_helper(queue);
/*TODO: It requires a reset for userq hw unmap error*/
if (r) {
drm_warn(adev_to_drm(uq_mgr->adev), "trying to destroy a HW mapping userq\n");
queue->state = AMDGPU_USERQ_STATE_HUNG;
}
atomic_dec(&uq_mgr->userq_count[queue->queue_type]);
amdgpu_userq_cleanup(queue);
mutex_unlock(&uq_mgr->userq_mutex);
@ -1187,7 +1194,7 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr)
bo = range->bo;
ret = amdgpu_ttm_tt_get_user_pages(bo, range);
if (ret)
goto unlock_all;
goto free_ranges;
}
invalidated = true;
@ -1214,6 +1221,7 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr)
unlock_all:
drm_exec_fini(&exec);
free_ranges:
xa_for_each(&xa, tmp_key, range) {
if (!range)
continue;

View File

@ -156,6 +156,7 @@ void amdgpu_userq_reset_work(struct work_struct *work);
void amdgpu_userq_pre_reset(struct amdgpu_device *adev);
int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost);
void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue);
void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell);
int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
struct amdgpu_usermode_queue *queue,

View File

@ -3023,11 +3023,22 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
is_compute_context = vm->is_compute_context;
if (is_compute_context && !svm_range_restore_pages(adev, pasid, vmid,
node_id, addr >> PAGE_SHIFT, ts, write_fault)) {
if (is_compute_context) {
/* Unreserve root since svm_range_restore_pages might try to reserve it. */
/* TODO: rework svm_range_restore_pages so that this isn't necessary. */
amdgpu_bo_unreserve(root);
if (!svm_range_restore_pages(adev, pasid, vmid,
node_id, addr >> PAGE_SHIFT, ts, write_fault)) {
amdgpu_bo_unref(&root);
return true;
}
amdgpu_bo_unref(&root);
return true;
/* Re-acquire the VM lock, could be that the VM was freed in between. */
vm = amdgpu_vm_lock_by_pasid(adev, &root, pasid);
if (!vm)
return false;
}
addr /= AMDGPU_GPU_PAGE_SIZE;

View File

@ -6523,15 +6523,7 @@ static int gfx_v11_0_eop_irq(struct amdgpu_device *adev,
DRM_DEBUG("IH: CP EOP\n");
if (adev->enable_mes && doorbell_offset) {
struct amdgpu_usermode_queue *queue;
struct xarray *xa = &adev->userq_doorbell_xa;
unsigned long flags;
xa_lock_irqsave(xa, flags);
queue = xa_load(xa, doorbell_offset);
if (queue)
amdgpu_userq_fence_driver_process(queue->fence_drv);
xa_unlock_irqrestore(xa, flags);
amdgpu_userq_process_fence_irq(adev, doorbell_offset);
} else {
me_id = (entry->ring_id & 0x0c) >> 2;
pipe_id = (entry->ring_id & 0x03) >> 0;

View File

@ -4854,15 +4854,7 @@ static int gfx_v12_0_eop_irq(struct amdgpu_device *adev,
DRM_DEBUG("IH: CP EOP\n");
if (adev->enable_mes && doorbell_offset) {
struct xarray *xa = &adev->userq_doorbell_xa;
struct amdgpu_usermode_queue *queue;
unsigned long flags;
xa_lock_irqsave(xa, flags);
queue = xa_load(xa, doorbell_offset);
if (queue)
amdgpu_userq_fence_driver_process(queue->fence_drv);
xa_unlock_irqrestore(xa, flags);
amdgpu_userq_process_fence_irq(adev, doorbell_offset);
} else {
me_id = (entry->ring_id & 0x0c) >> 2;
pipe_id = (entry->ring_id & 0x03) >> 0;

View File

@ -3643,16 +3643,7 @@ static int gfx_v12_1_eop_irq(struct amdgpu_device *adev,
DRM_DEBUG("IH: CP EOP\n");
if (adev->enable_mes && doorbell_offset) {
struct xarray *xa = &adev->userq_doorbell_xa;
struct amdgpu_usermode_queue *queue;
unsigned long flags;
xa_lock_irqsave(xa, flags);
queue = xa_load(xa, doorbell_offset);
if (queue)
amdgpu_userq_fence_driver_process(queue->fence_drv);
xa_unlock_irqrestore(xa, flags);
amdgpu_userq_process_fence_irq(adev, doorbell_offset);
} else {
me_id = (entry->ring_id & 0x0c) >> 2;
pipe_id = (entry->ring_id & 0x03) >> 0;

View File

@ -1571,6 +1571,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev)
mutex_unlock(&adev->grbm_idx_mutex);
}
/**
* gfx_v6_0_setup_tcc() - setup which TCCs are used
*
* @adev: amdgpu_device pointer
*
* Verify whether the current GPU has any TCCs disabled,
* which can happen when the GPU is harvested and some
* memory channels are disabled, reducing the memory bus width.
* For example, on the Radeon HD 7870 XT (Tahiti LE).
*
* If some TCCs are disabled, we need to make sure that
* the disabled TCCs are not used, and the remaining TCCs
* are used optimally.
*
* TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels.
* TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used.
*
* For optimal performance:
* - Rely on the CHAN_STEER from the golden registers table,
* only skip disabled TCCs but keep the mapping order.
* - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing,
* which performs better than using the same TCC twice.
*/
static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev)
{
u32 i, tcc, tcp_addr_config, num_active_tcc = 0;
u64 chan_steer, patched_chan_steer = 0;
const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches;
const u32 dis_tcc_mask =
amdgpu_gfx_create_bitmask(num_max_tcc) &
(REG_GET_FIELD(RREG32(mmCGTS_TCC_DISABLE),
CGTS_TCC_DISABLE, TCC_DISABLE) |
REG_GET_FIELD(RREG32(mmCGTS_USER_TCC_DISABLE),
CGTS_USER_TCC_DISABLE, TCC_DISABLE));
/* When no TCC is disabled, the golden registers table already has optimal TCC setup */
if (!dis_tcc_mask)
return;
/* Each 4-bit nibble contains the index of a TCC used by all TCPs */
chan_steer = RREG32(mmTCP_CHAN_STEER_LO) | ((u64)RREG32(mmTCP_CHAN_STEER_HI) << 32ull);
/* Patch the TCP to TCC mapping to skip disabled TCCs */
for (i = 0; i < num_max_tcc; ++i) {
tcc = (chan_steer >> (u64)(4 * i)) & 0xf;
if (!((1 << tcc) & dis_tcc_mask)) {
/* Copy enabled TCC indices to the patched register value. */
patched_chan_steer |= (u64)tcc << (u64)(4 * num_active_tcc);
++num_active_tcc;
}
}
WARN_ON(num_active_tcc != num_max_tcc - hweight32(dis_tcc_mask));
/* Patch number of TCCs used by TCPs */
tcp_addr_config = REG_SET_FIELD(RREG32(mmTCP_ADDR_CONFIG),
TCP_ADDR_CONFIG, NUM_TCC_BANKS,
num_active_tcc - 1);
WREG32(mmTCP_ADDR_CONFIG, tcp_addr_config);
WREG32(mmTCP_CHAN_STEER_HI, upper_32_bits(patched_chan_steer));
WREG32(mmTCP_CHAN_STEER_LO, lower_32_bits(patched_chan_steer));
}
static void gfx_v6_0_config_init(struct amdgpu_device *adev)
{
adev->gfx.config.double_offchip_lds_buf = 0;
@ -1729,6 +1794,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev)
gfx_v6_0_tiling_mode_table_init(adev);
gfx_v6_0_setup_rb(adev);
gfx_v6_0_setup_tcc(adev);
gfx_v6_0_setup_spi(adev);

View File

@ -802,6 +802,7 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
.no_user_fence = true,
.get_rptr = jpeg_v2_0_dec_ring_get_rptr,
.get_wptr = jpeg_v2_0_dec_ring_get_wptr,
.set_wptr = jpeg_v2_0_dec_ring_set_wptr,

View File

@ -693,6 +693,7 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
.no_user_fence = true,
.get_rptr = jpeg_v2_5_dec_ring_get_rptr,
.get_wptr = jpeg_v2_5_dec_ring_get_wptr,
.set_wptr = jpeg_v2_5_dec_ring_set_wptr,
@ -724,6 +725,7 @@ static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = {
static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
.no_user_fence = true,
.get_rptr = jpeg_v2_5_dec_ring_get_rptr,
.get_wptr = jpeg_v2_5_dec_ring_get_wptr,
.set_wptr = jpeg_v2_5_dec_ring_set_wptr,

View File

@ -594,6 +594,7 @@ static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
.no_user_fence = true,
.get_rptr = jpeg_v3_0_dec_ring_get_rptr,
.get_wptr = jpeg_v3_0_dec_ring_get_wptr,
.set_wptr = jpeg_v3_0_dec_ring_set_wptr,

View File

@ -759,6 +759,7 @@ static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
.no_user_fence = true,
.get_rptr = jpeg_v4_0_dec_ring_get_rptr,
.get_wptr = jpeg_v4_0_dec_ring_get_wptr,
.set_wptr = jpeg_v4_0_dec_ring_set_wptr,

View File

@ -1219,6 +1219,7 @@ static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
.no_user_fence = true,
.get_rptr = jpeg_v4_0_3_dec_ring_get_rptr,
.get_wptr = jpeg_v4_0_3_dec_ring_get_wptr,
.set_wptr = jpeg_v4_0_3_dec_ring_set_wptr,

View File

@ -804,6 +804,7 @@ static const struct amd_ip_funcs jpeg_v4_0_5_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v4_0_5_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
.no_user_fence = true,
.get_rptr = jpeg_v4_0_5_dec_ring_get_rptr,
.get_wptr = jpeg_v4_0_5_dec_ring_get_wptr,
.set_wptr = jpeg_v4_0_5_dec_ring_set_wptr,

View File

@ -680,6 +680,7 @@ static const struct amd_ip_funcs jpeg_v5_0_0_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v5_0_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
.no_user_fence = true,
.get_rptr = jpeg_v5_0_0_dec_ring_get_rptr,
.get_wptr = jpeg_v5_0_0_dec_ring_get_wptr,
.set_wptr = jpeg_v5_0_0_dec_ring_set_wptr,

View File

@ -884,6 +884,7 @@ static const struct amd_ip_funcs jpeg_v5_0_1_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v5_0_1_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
.no_user_fence = true,
.get_rptr = jpeg_v5_0_1_dec_ring_get_rptr,
.get_wptr = jpeg_v5_0_1_dec_ring_get_wptr,
.set_wptr = jpeg_v5_0_1_dec_ring_set_wptr,

View File

@ -703,6 +703,7 @@ static const struct amd_ip_funcs jpeg_v5_0_2_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v5_0_2_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
.no_user_fence = true,
.get_rptr = jpeg_v5_0_2_dec_ring_get_rptr,
.get_wptr = jpeg_v5_0_2_dec_ring_get_wptr,
.set_wptr = jpeg_v5_0_2_dec_ring_set_wptr,

View File

@ -661,6 +661,7 @@ static const struct amd_ip_funcs jpeg_v5_3_0_ip_funcs = {
static const struct amdgpu_ring_funcs jpeg_v5_3_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_JPEG,
.align_mask = 0xf,
.no_user_fence = true,
.get_rptr = jpeg_v5_3_0_dec_ring_get_rptr,
.get_wptr = jpeg_v5_3_0_dec_ring_get_wptr,
.set_wptr = jpeg_v5_3_0_dec_ring_set_wptr,

View File

@ -1662,17 +1662,8 @@ static int sdma_v6_0_process_fence_irq(struct amdgpu_device *adev,
u32 doorbell_offset = entry->src_data[0];
if (adev->enable_mes && doorbell_offset) {
struct amdgpu_usermode_queue *queue;
struct xarray *xa = &adev->userq_doorbell_xa;
unsigned long flags;
doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
xa_lock_irqsave(xa, flags);
queue = xa_load(xa, doorbell_offset);
if (queue)
amdgpu_userq_fence_driver_process(queue->fence_drv);
xa_unlock_irqrestore(xa, flags);
amdgpu_userq_process_fence_irq(adev, doorbell_offset);
}
return 0;

View File

@ -1594,17 +1594,8 @@ static int sdma_v7_0_process_fence_irq(struct amdgpu_device *adev,
u32 doorbell_offset = entry->src_data[0];
if (adev->enable_mes && doorbell_offset) {
struct xarray *xa = &adev->userq_doorbell_xa;
struct amdgpu_usermode_queue *queue;
unsigned long flags;
doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
xa_lock_irqsave(xa, flags);
queue = xa_load(xa, doorbell_offset);
if (queue)
amdgpu_userq_fence_driver_process(queue->fence_drv);
xa_unlock_irqrestore(xa, flags);
amdgpu_userq_process_fence_irq(adev, doorbell_offset);
}
return 0;

View File

@ -242,6 +242,10 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev)
uint64_t addr;
uint32_t size;
/* When the keyselect is already set, don't perturb it. */
if (RREG32(mmUVD_FW_START))
return;
/* program the VCPU memory controller bits 0-27 */
addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3;
size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3;
@ -284,6 +288,12 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev)
int i;
uint32_t keysel = adev->uvd.keyselect;
if (RREG32(mmUVD_FW_START) & UVD_FW_STATUS__PASS_MASK) {
dev_dbg(adev->dev, "UVD keyselect already set: 0x%x (on CPU: 0x%x)\n",
RREG32(mmUVD_FW_START), adev->uvd.keyselect);
return 0;
}
WREG32(mmUVD_FW_START, keysel);
for (i = 0; i < 10; ++i) {

View File

@ -2113,6 +2113,7 @@ static const struct amd_ip_funcs vcn_v2_0_ip_funcs = {
static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_DEC,
.align_mask = 0xf,
.no_user_fence = true,
.secure_submission_supported = true,
.get_rptr = vcn_v2_0_dec_ring_get_rptr,
.get_wptr = vcn_v2_0_dec_ring_get_wptr,
@ -2145,6 +2146,7 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
.no_user_fence = true,
.get_rptr = vcn_v2_0_enc_ring_get_rptr,
.get_wptr = vcn_v2_0_enc_ring_get_wptr,
.set_wptr = vcn_v2_0_enc_ring_set_wptr,

View File

@ -1778,6 +1778,7 @@ static void vcn_v2_5_dec_ring_set_wptr(struct amdgpu_ring *ring)
static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_DEC,
.align_mask = 0xf,
.no_user_fence = true,
.secure_submission_supported = true,
.get_rptr = vcn_v2_5_dec_ring_get_rptr,
.get_wptr = vcn_v2_5_dec_ring_get_wptr,
@ -1879,6 +1880,7 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
.no_user_fence = true,
.get_rptr = vcn_v2_5_enc_ring_get_rptr,
.get_wptr = vcn_v2_5_enc_ring_get_wptr,
.set_wptr = vcn_v2_5_enc_ring_set_wptr,

View File

@ -1856,6 +1856,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_DEC,
.align_mask = 0x3f,
.nop = VCN_DEC_SW_CMD_NO_OP,
.no_user_fence = true,
.secure_submission_supported = true,
.get_rptr = vcn_v3_0_dec_ring_get_rptr,
.get_wptr = vcn_v3_0_dec_ring_get_wptr,
@ -1972,6 +1973,7 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) {
uint32_t offset, size, *create;
uint64_t buf_end;
if (msg[0] != RDECODE_MESSAGE_CREATE)
continue;
@ -1979,7 +1981,8 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
offset = msg[1];
size = msg[2];
if (size < 4 || offset + size > end - addr) {
if (size < 4 || check_add_overflow(offset, size, &buf_end) ||
buf_end > end - addr) {
DRM_ERROR("VCN message buffer exceeds BO bounds!\n");
r = -EINVAL;
goto out;
@ -2036,6 +2039,7 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_DEC,
.align_mask = 0xf,
.no_user_fence = true,
.secure_submission_supported = true,
.get_rptr = vcn_v3_0_dec_ring_get_rptr,
.get_wptr = vcn_v3_0_dec_ring_get_wptr,
@ -2138,6 +2142,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_enc_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
.no_user_fence = true,
.get_rptr = vcn_v3_0_enc_ring_get_rptr,
.get_wptr = vcn_v3_0_enc_ring_get_wptr,
.set_wptr = vcn_v3_0_enc_ring_set_wptr,

View File

@ -1889,6 +1889,7 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) {
uint32_t offset, size, *create;
uint64_t buf_end;
if (msg[0] != RDECODE_MESSAGE_CREATE)
continue;
@ -1896,7 +1897,8 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
offset = msg[1];
size = msg[2];
if (size < 4 || offset + size > end - addr) {
if (size < 4 || check_add_overflow(offset, size, &buf_end) ||
buf_end > end - addr) {
DRM_ERROR("VCN message buffer exceeds BO bounds!\n");
r = -EINVAL;
goto out;
@ -1994,6 +1996,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
.no_user_fence = true,
.extra_bytes = sizeof(struct amdgpu_vcn_rb_metadata),
.get_rptr = vcn_v4_0_unified_ring_get_rptr,
.get_wptr = vcn_v4_0_unified_ring_get_wptr,

View File

@ -1775,6 +1775,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_3_unified_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
.no_user_fence = true,
.get_rptr = vcn_v4_0_3_unified_ring_get_rptr,
.get_wptr = vcn_v4_0_3_unified_ring_get_wptr,
.set_wptr = vcn_v4_0_3_unified_ring_set_wptr,

View File

@ -1483,6 +1483,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_5_unified_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
.no_user_fence = true,
.get_rptr = vcn_v4_0_5_unified_ring_get_rptr,
.get_wptr = vcn_v4_0_5_unified_ring_get_wptr,
.set_wptr = vcn_v4_0_5_unified_ring_set_wptr,

View File

@ -1207,6 +1207,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_0_unified_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
.no_user_fence = true,
.get_rptr = vcn_v5_0_0_unified_ring_get_rptr,
.get_wptr = vcn_v5_0_0_unified_ring_get_wptr,
.set_wptr = vcn_v5_0_0_unified_ring_set_wptr,

View File

@ -1419,6 +1419,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_1_unified_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
.no_user_fence = true,
.get_rptr = vcn_v5_0_1_unified_ring_get_rptr,
.get_wptr = vcn_v5_0_1_unified_ring_get_wptr,
.set_wptr = vcn_v5_0_1_unified_ring_set_wptr,

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