spi: switch to managed controller allocation (part 2/3)

Johan Hovold <johan@kernel.org> says:

In preparation for fixing the SPI controller API so that it no longer
drops a reference when deregistering (non-managed) controllers (cf.
[1]), this series converts drivers using non-managed registration to use
managed allocation.

Included is also a related cleanup of a ti-qspi error path.

This second set will be followed by a third set of 12 patches for
drivers using managed registration.

That leaves us with 18 drivers using non-managed allocation, which is
few enough to be able to fix the API in tree-wide change.

Johan

[1] https://lore.kernel.org/lkml/20260325145319.1132072-1-johan@kernel.org/

Link: https://patch.msgid.link/20260505072909.618363-1-johan@kernel.org
This commit is contained in:
Mark Brown
2026-05-11 09:55:56 +09:00
542 changed files with 7599 additions and 4123 deletions

View File

@@ -682,6 +682,7 @@ Peter A Jonsson <pj@ludd.ltu.se>
Peter Hilber <peter.hilber@oss.qualcomm.com> <quic_philber@quicinc.com>
Peter Oruba <peter.oruba@amd.com>
Peter Oruba <peter@oruba.de>
Peter Rosin <peda@lysator.liu.se> <peda@axentia.se>
Pierre-Louis Bossart <pierre-louis.bossart@linux.dev> <pierre-louis.bossart@linux.intel.com>
Pratyush Anand <pratyush.anand@gmail.com> <pratyush.anand@st.com>
Pratyush Yadav <pratyush@kernel.org> <ptyadav@amazon.de>

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

@@ -16,10 +16,15 @@ allOf:
properties:
compatible:
enum:
- amlogic,meson6-i2c # Meson6, Meson8 and compatible SoCs
- amlogic,meson-gxbb-i2c # GXBB and compatible SoCs
- amlogic,meson-axg-i2c # AXG and compatible SoCs
oneOf:
- items:
- enum:
- amlogic,t7-i2c
- const: amlogic,meson-axg-i2c
- enum:
- amlogic,meson6-i2c # Meson6, Meson8 and compatible SoCs
- amlogic,meson-gxbb-i2c # GXBB and compatible SoCs
- amlogic,meson-axg-i2c # AXG and compatible SoCs
reg:
maxItems: 1

View File

@@ -22,7 +22,9 @@ properties:
compatible:
oneOf:
- items:
- const: apple,t6020-i2c
- enum:
- apple,t6020-i2c
- apple,t8122-i2c
- const: apple,t8103-i2c
- items:
- enum:

View File

@@ -135,4 +135,4 @@ References
4. **Lenovo IdeaPad Laptop Driver:** Reference for DMI-based hardware
feature gating in Lenovo laptops.
https://github.com/torvalds/linux/blob/master/drivers/platform/x86/ideapad-laptop.c
https://github.com/torvalds/linux/blob/master/drivers/platform/x86/lenovo/ideapad-laptop.c

View File

@@ -24,6 +24,97 @@ Quick access to CPU number, node ID
Allows to implement per CPU data efficiently. Documentation is in code and
selftests. :(
Optimized RSEQ V2
-----------------
On architectures which utilize the generic entry code and generic TIF bits
the kernel supports runtime optimizations for RSEQ, which also enable
enhanced features like scheduler time slice extensions.
To enable them a task has to register the RSEQ region with at least the
length advertised by getauxval(AT_RSEQ_FEATURE_SIZE).
If existing binaries register with RSEQ_ORIG_SIZE (32 bytes), the kernel
keeps the legacy low performance mode enabled to fulfil the expectations
of existing users regarding the original RSEQ implementation behaviour.
The following table documents the ABI and behavioral guarantees of the
legacy and the optimized V2 mode.
.. list-table:: RSEQ modes
:header-rows: 1
* - Nr
- What
- Legacy
- Optimized V2
* - 1
- The cpu_id_start, cpu_id, node_id and mm_cid fields (User mode read
only)
.. Legacy
- Updated by the kernel unconditionally after each context switch and
before signal delivery
.. Optimized V2
- Updated by the kernel if and only if they change, i.e. if the task
is migrated or mm_cid changes
* - 2
- The rseq_cs critical section field
.. Legacy
- Evaluated and handled unconditionally after each context switch and
before signal delivery
.. Optimized V2
- Evaluated and handled conditionally only when user space was
interrupted and was scheduled out or before delivering a signal in
the interrupted context.
* - 3
- Read only fields
.. Legacy
- No strict enforcement except in debug mode
.. Optimized V2
- Strict enforcement
* - 4
- membarrier(...RSEQ)
.. Legacy
- All running threads of the process are interrupted and the ID fields
are rewritten and eventually active critical sections are aborted
before they return to user space. All threads which are scheduled
out whether voluntary or not are covered by #1/#2 above.
.. Optimized V2
- All running threads of the process are interrupted and eventually
active critical sections are aborted before these threads return to
user space. The ID fields are only updated if changed as a
consequence of the interrupt. All threads which are scheduled out
whether voluntary or not are covered by #1/#2 above.
* - 5
- Time slice extensions
.. Legacy
- Not supported
.. Optimized V2
- Supported
The legacy mode is obviously less performant as it does unconditional
updates and critical section checks even if not strictly required by the
ABI contract. That can't be changed anymore as some users depend on that
observed behavior, which in turn enables them to violate the ABI and
overwrite the cpu_id_start field for their own purposes. This is obviously
discouraged as it renders RSEQ incompatible with the intended usage and
breaks the expectation of other libraries in the same application.
The ABI compliant optimized v2 mode, which respects the read only fields,
does not require unconditional updates and therefore is way more
performant. The kernel validates the read only fields for compliance. If
user space modifies them, the process is killed. Compliant usage allows
multiple libraries in the same application to benefit from the RSEQ
functionality without disturbing each other. The ABI compliant optimized v2
mode also enables extended RSEQ features like time slice extensions.
Scheduler time slice extensions
-------------------------------
@@ -37,7 +128,8 @@ The prerequisites for this functionality are:
* Enabled at boot time (default is enabled)
* A rseq userspace pointer has been registered for the thread
* A rseq userspace pointer has been registered for the thread in
optimized V2 mode
The thread has to enable the functionality via prctl(2)::

View File

@@ -4299,18 +4299,16 @@ F: Documentation/devicetree/bindings/leds/backlight/awinic,aw99706.yaml
F: drivers/video/backlight/aw99706.c
AXENTIA ARM DEVICES
M: Peter Rosin <peda@axentia.se>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
S: Orphan
F: arch/arm/boot/dts/microchip/at91-linea.dtsi
F: arch/arm/boot/dts/microchip/at91-natte.dtsi
F: arch/arm/boot/dts/microchip/at91-nattis-2-natte-2.dts
F: arch/arm/boot/dts/microchip/at91-tse850-3.dts
AXENTIA ASOC DRIVERS
M: Peter Rosin <peda@axentia.se>
L: linux-sound@vger.kernel.org
S: Maintained
S: Orphan
F: Documentation/devicetree/bindings/sound/axentia,*
F: sound/soc/atmel/tse850-pcm5142.c
@@ -6358,6 +6356,7 @@ F: include/uapi/linux/comedi.h
COMMON CLK FRAMEWORK
M: Michael Turquette <mturquette@baylibre.com>
M: Stephen Boyd <sboyd@kernel.org>
R: Brian Masney <bmasney@redhat.com>
L: linux-clk@vger.kernel.org
S: Maintained
Q: http://patchwork.kernel.org/project/linux-clk/list/
@@ -7077,6 +7076,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
@@ -8193,10 +8198,9 @@ F: include/uapi/drm/nouveau_drm.h
CORE DRIVER FOR NVIDIA GPUS [RUST]
M: Danilo Krummrich <dakr@kernel.org>
M: Alexandre Courbot <acourbot@nvidia.com>
L: nouveau@lists.freedesktop.org
L: nova-gpu@lists.linux.dev
S: Supported
W: https://rust-for-linux.com/nova-gpu-driver
Q: https://patchwork.freedesktop.org/project/nouveau/
B: https://gitlab.freedesktop.org/drm/nova/-/issues
C: irc://irc.oftc.net/nouveau
T: git https://gitlab.freedesktop.org/drm/rust/kernel.git drm-rust-next
@@ -8205,10 +8209,9 @@ F: drivers/gpu/nova-core/
DRM DRIVER FOR NVIDIA GPUS [RUST]
M: Danilo Krummrich <dakr@kernel.org>
L: nouveau@lists.freedesktop.org
L: nova-gpu@lists.linux.dev
S: Supported
W: https://rust-for-linux.com/nova-gpu-driver
Q: https://patchwork.freedesktop.org/project/nouveau/
B: https://gitlab.freedesktop.org/drm/nova/-/issues
C: irc://irc.oftc.net/nouveau
T: git https://gitlab.freedesktop.org/drm/rust/kernel.git drm-rust-next
@@ -12046,7 +12049,7 @@ F: Documentation/i2c/busses/i2c-nvidia-gpu.rst
F: drivers/i2c/busses/i2c-nvidia-gpu.c
I2C MUXES
M: Peter Rosin <peda@axentia.se>
M: Peter Rosin <peda@lysator.liu.se>
L: linux-i2c@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/i2c/i2c-arb*
@@ -12447,7 +12450,7 @@ F: drivers/iio/industrialio-backend.c
F: include/linux/iio/backend.h
IIO DIGITAL POTENTIOMETER DAC
M: Peter Rosin <peda@axentia.se>
M: Peter Rosin <peda@lysator.liu.se>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-iio-dac-dpot-dac
@@ -12455,7 +12458,7 @@ F: Documentation/devicetree/bindings/iio/dac/dpot-dac.yaml
F: drivers/iio/dac/dpot-dac.c
IIO ENVELOPE DETECTOR
M: Peter Rosin <peda@axentia.se>
M: Peter Rosin <peda@lysator.liu.se>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-iio-adc-envelope-detector
@@ -12471,7 +12474,7 @@ F: include/linux/iio/iio-gts-helper.h
F: drivers/iio/test/iio-test-gts.c
IIO MULTIPLEXER
M: Peter Rosin <peda@axentia.se>
M: Peter Rosin <peda@lysator.liu.se>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.yaml
@@ -12502,7 +12505,7 @@ F: include/linux/iio/
F: tools/iio/
IIO UNIT CONVERTER
M: Peter Rosin <peda@axentia.se>
M: Peter Rosin <peda@lysator.liu.se>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.yaml
@@ -15718,7 +15721,7 @@ F: Documentation/devicetree/bindings/media/i2c/maxim,max96717.yaml
F: drivers/media/i2c/max96717.c
MAX9860 MONO AUDIO VOICE CODEC DRIVER
M: Peter Rosin <peda@axentia.se>
M: Peter Rosin <peda@lysator.liu.se>
L: linux-sound@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/sound/max9860.txt
@@ -15933,7 +15936,7 @@ F: Documentation/devicetree/bindings/net/can/microchip,mcp251xfd.yaml
F: drivers/net/can/spi/mcp251xfd/
MCP4018 AND MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVERS
M: Peter Rosin <peda@axentia.se>
M: Peter Rosin <peda@lysator.liu.se>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-iio-potentiometer-mcp4531
@@ -18238,7 +18241,7 @@ F: include/linux/mmc/
F: include/uapi/linux/mmc/
MULTIPLEXER SUBSYSTEM
M: Peter Rosin <peda@axentia.se>
M: Peter Rosin <peda@lysator.liu.se>
S: Odd Fixes
F: Documentation/ABI/testing/sysfs-class-mux*
F: Documentation/devicetree/bindings/mux/
@@ -19347,7 +19350,7 @@ F: include/dt-bindings/display/tda998x.h
K: "nxp,tda998x"
NXP TFA9879 DRIVER
M: Peter Rosin <peda@axentia.se>
M: Peter Rosin <peda@lysator.liu.se>
L: linux-sound@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/sound/trivial-codec.yaml
@@ -20348,13 +20351,14 @@ F: Documentation/devicetree/bindings/pci/marvell,armada8k-pcie.yaml
F: drivers/pci/controller/dwc/pcie-armada8k.c
PCI DRIVER FOR CADENCE PCIE IP
R: Aksh Garg <a-garg7@ti.com>
L: linux-pci@vger.kernel.org
S: Orphan
F: Documentation/devicetree/bindings/pci/cdns,*
F: drivers/pci/controller/cadence/*cadence*
F: drivers/pci/controller/cadence/
PCI DRIVER FOR CIX Sky1
M: Hans Zhang <hans.zhang@cixtech.com>
M: Hans Zhang <18255117159@163.com>
L: linux-pci@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/pci/cix,sky1-pcie-*.yaml
@@ -20466,7 +20470,7 @@ F: drivers/pci/controller/plda/pcie-plda-host.c
F: drivers/pci/controller/plda/pcie-plda.h
PCI DRIVER FOR RENESAS R-CAR
M: Marek Vasut <marek.vasut+renesas@gmail.com>
M: Marek Vasut <marek.vasut+renesas@mailbox.org>
M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
L: linux-pci@vger.kernel.org
L: linux-renesas-soc@vger.kernel.org
@@ -24650,6 +24654,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>

View File

@@ -2,7 +2,7 @@
VERSION = 7
PATCHLEVEL = 1
SUBLEVEL = 0
EXTRAVERSION = -rc2
EXTRAVERSION = -rc3
NAME = Baby Opossum Posse
# *DOCUMENTATION*
@@ -486,6 +486,8 @@ export rust_common_flags := --edition=2021 \
-Wclippy::as_ptr_cast_mut \
-Wclippy::as_underscore \
-Wclippy::cast_lossless \
-Aclippy::collapsible_if \
-Aclippy::collapsible_match \
-Wclippy::ignored_unit_patterns \
-Aclippy::incompatible_msrv \
-Wclippy::mut_mut \

View File

@@ -983,8 +983,8 @@ static int sve_set_common(struct task_struct *target,
}
/* Always zero V regs, FPSR, and FPCR */
memset(&current->thread.uw.fpsimd_state, 0,
sizeof(current->thread.uw.fpsimd_state));
memset(&target->thread.uw.fpsimd_state, 0,
sizeof(target->thread.uw.fpsimd_state));
/* Registers: FPSIMD-only case */

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

@@ -76,7 +76,6 @@ CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_TILEBLITTING=y
CONFIG_FB_RADEON=y
CONFIG_FB_3DFX=y

View File

@@ -76,7 +76,6 @@ CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_NVRAM=y
# CONFIG_HWMON is not set
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_OF=y
CONFIG_FB_MATROX=y
CONFIG_FB_MATROX_MILLENIUM=y

View File

@@ -121,7 +121,6 @@ CONFIG_I2C_CHARDEV=y
CONFIG_AGP=m
CONFIG_AGP_UNINORTH=m
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_TILEBLITTING=y
CONFIG_FB_OF=y
CONFIG_FB_NVIDIA=y

View File

@@ -98,7 +98,6 @@ CONFIG_SENSORS_LM85=y
CONFIG_SENSORS_LM90=y
CONFIG_DRM=y
CONFIG_DRM_RADEON=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_TILEBLITTING=y
CONFIG_FB_VGA16=y
CONFIG_FB_NVIDIA=y

View File

@@ -196,7 +196,6 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_PTP_1588_CLOCK is not set
CONFIG_DRM=y
CONFIG_DRM_AST=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_OF=y
CONFIG_FB_MATROX=m
CONFIG_FB_MATROX_MILLENIUM=y

View File

@@ -249,7 +249,6 @@ CONFIG_I2C_CHARDEV=y
CONFIG_I2C_AMD8111=y
CONFIG_I2C_PASEMI=y
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_OF=y
CONFIG_FB_MATROX=y
CONFIG_FB_MATROX_MILLENIUM=y

View File

@@ -118,7 +118,6 @@ CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_AMD8111=y
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_OF=y
CONFIG_FB_MATROX=y
CONFIG_FB_MATROX_MILLENIUM=y

View File

@@ -214,7 +214,6 @@ CONFIG_SENSORS_IBMPOWERNV=m
CONFIG_DRM=m
CONFIG_DRM_AST=m
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
# CONFIG_VGA_CONSOLE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y

View File

@@ -62,6 +62,12 @@ CC32FLAGSREMOVE += -fno-stack-clash-protection
# 32-bit one. clang validates the values passed to these arguments during
# parsing, even when -fno-stack-protector is passed afterwards.
CC32FLAGSREMOVE += -mstack-protector-guard%
# ftrace is disabled for the vdso but arch/powerpc/Makefile adds this define to
# KBUILD_CPPFLAGS, which enables use of the 'patchable_function_entry'
# attribute in the 'inline' define via 'notrace'. This attribute is not
# supported for the powerpcle target, resulting in many instances of
# -Wunknown-attributes.
CC32FLAGSREMOVE += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
endif
LD32FLAGS := -Wl,-soname=linux-vdso32.so.1
AS32FLAGS := -D__VDSO32__

View File

@@ -16,4 +16,4 @@ GCOV_PROFILE_core_$(BITS).o := n
KCOV_INSTRUMENT_core_$(BITS).o := n
UBSAN_SANITIZE_core_$(BITS).o := n
KASAN_SANITIZE_core.o := n
KASAN_SANITIZE_core_$(BITS) := n
KASAN_SANITIZE_core_$(BITS).o := n

View File

@@ -52,7 +52,14 @@ int exit_vmx_usercopy(void)
}
EXPORT_SYMBOL(exit_vmx_usercopy);
int enter_vmx_ops(void)
/*
* Can be called from kexec copy_page() path with MMU off. The kexec
* code sets preempt_count to HARDIRQ_OFFSET so we return early here.
* Since in_interrupt() is always inline, __no_sanitize_address on this
* function is sufficient to avoid KASAN shadow memory accesses in real
* mode.
*/
int __no_sanitize_address enter_vmx_ops(void)
{
if (in_interrupt())
return 0;

View File

@@ -2242,6 +2242,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
const u64 last_period = event->hw.last_period;
s64 prev, delta, left;
int record = 0;
int mark_event = regs->dsisr & MMCRA_SAMPLE_ENABLE;
if (event->hw.state & PERF_HES_STOPPED) {
write_pmc(event->hw.idx, 0);
@@ -2304,9 +2305,9 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
* In ISA v3.0 and before values "0" and "7" are considered reserved.
* In ISA v3.1, value "7" has been used to indicate "larx/stcx".
* Drop the sample if "type" has reserved values for this field with a
* ISA version check.
* ISA version check for marked events.
*/
if (event->attr.sample_type & PERF_SAMPLE_DATA_SRC &&
if (mark_event && event->attr.sample_type & PERF_SAMPLE_DATA_SRC &&
ppmu->get_mem_data_src) {
val = (regs->dar & SIER_TYPE_MASK) >> SIER_TYPE_SHIFT;
if (val == 0 || (val == 7 && !cpu_has_feature(CPU_FTR_ARCH_31))) {

View File

@@ -477,7 +477,7 @@ int cpm1_gpiochip_add16(struct device *dev)
struct device_node *np = dev->of_node;
struct cpm1_gpio16_chip *cpm1_gc;
struct gpio_chip *gc;
u16 mask;
u32 mask;
cpm1_gc = devm_kzalloc(dev, sizeof(*cpm1_gc), GFP_KERNEL);
if (!cpm1_gc)
@@ -485,7 +485,7 @@ int cpm1_gpiochip_add16(struct device *dev)
spin_lock_init(&cpm1_gc->lock);
if (!of_property_read_u16(np, "fsl,cpm1-gpio-irq-mask", &mask)) {
if (!of_property_read_u32(np, "fsl,cpm1-gpio-irq-mask", &mask)) {
int i, j;
for (i = 0, j = 0; i < 16; i++)

View File

@@ -272,13 +272,12 @@ void __init pas_pci_init(void)
{
struct device_node *root = of_find_node_by_path("/");
struct device_node *np;
int res;
pci_set_flags(PCI_SCAN_ALL_PCIE_DEVS);
np = of_find_compatible_node(root, NULL, "pasemi,rootbus");
if (np) {
res = pas_add_bridge(np);
pas_add_bridge(np);
of_node_put(np);
}
of_node_put(root);

View File

@@ -950,8 +950,6 @@ static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type)
static int __init ps3_register_devices(void)
{
int result;
if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
return -ENODEV;
@@ -959,7 +957,7 @@ static int __init ps3_register_devices(void)
/* ps3_repository_dump_bus_info(); */
result = ps3_start_probe_thread(PS3_BUS_TYPE_STORAGE);
ps3_start_probe_thread(PS3_BUS_TYPE_STORAGE);
ps3_register_vuart_devices();

View File

@@ -16,6 +16,7 @@ static void *htm_buf;
static void *htm_status_buf;
static void *htm_info_buf;
static void *htm_caps_buf;
static void *htm_mem_buf;
static u32 nodeindex;
static u32 nodalchipindex;
static u32 coreindexonchip;
@@ -86,7 +87,7 @@ static ssize_t htm_return_check(long rc)
static ssize_t htmdump_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *ppos)
{
void *htm_buf = filp->private_data;
void *htm_buf_data = filp->private_data;
unsigned long page, read_size, available;
loff_t offset;
long rc, ret;
@@ -100,7 +101,7 @@ static ssize_t htmdump_read(struct file *filp, char __user *ubuf,
* - last three values are address, size and offset
*/
rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
htmtype, H_HTM_OP_DUMP_DATA, virt_to_phys(htm_buf),
htmtype, H_HTM_OP_DUMP_DATA, virt_to_phys(htm_buf_data),
PAGE_SIZE, page);
ret = htm_return_check(rc);
@@ -112,7 +113,61 @@ static ssize_t htmdump_read(struct file *filp, char __user *ubuf,
available = PAGE_SIZE;
read_size = min(count, available);
*ppos += read_size;
return simple_read_from_buffer(ubuf, count, &offset, htm_buf, available);
return simple_read_from_buffer(ubuf, count, &offset, htm_buf_data, available);
}
static ssize_t htmsystem_mem_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *ppos)
{
void *htm_mem_data = filp->private_data;
long rc, ret;
u64 *num_entries;
u64 to_copy = 0;
loff_t offset = 0;
u64 mem_offset = 0;
/*
* Invoke H_HTM call with:
* - operation as htm status (H_HTM_OP_STATUS)
* - last three values as addr, size and offset. "offset"
* is value from output buffer header that points to next
* entry to dump. 0 is the first entry to dump. next entry
* is read from the output bufferbyte offset 0x8.
*
* When first time hcall is invoked, mem_offset should be
* zero because zero is the first entry.
* In the next hcall, offset of next entry to read from is
* picked from output buffer header itself. So don't fill
* mem_offset for first read.
*
* If there is no further data to read in next iteration,
* offset value from output buffer header will point to -1.
*/
if (*ppos) {
mem_offset = *(u64 *)(htm_mem_data + 0x8);
if (mem_offset == -1)
return 0;
}
rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
htmtype, H_HTM_OP_DUMP_SYSMEM_CONF, virt_to_phys(htm_mem_data),
PAGE_SIZE, be64_to_cpu(mem_offset));
ret = htm_return_check(rc);
if (ret <= 0) {
pr_debug("H_HTM hcall returned for op: H_HTM_OP_DUMP_SYSMEM_CONF with hcall returning %ld\n", ret);
return ret;
}
/*
* HTM system mem buffer, start of buffer + 0x10 gives the
* number of HTM entries in the buffer.
* So total count to copy is:
* 32 bytes (for first 5 fields) + (number of HTM entries * entry size)
*/
num_entries = htm_mem_data + 0x10;
to_copy = 32 + (be64_to_cpu(*num_entries) * 32);
*ppos += to_copy;
return simple_read_from_buffer(ubuf, count, &offset, htm_mem_data, to_copy);
}
static const struct file_operations htmdump_fops = {
@@ -121,6 +176,12 @@ static const struct file_operations htmdump_fops = {
.open = simple_open,
};
static const struct file_operations htmsystem_mem_fops = {
.llseek = NULL,
.read = htmsystem_mem_read,
.open = simple_open,
};
static int htmconfigure_set(void *data, u64 val)
{
long rc, ret;
@@ -226,20 +287,31 @@ static int htmstart_get(void *data, u64 *val)
static ssize_t htmstatus_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *ppos)
{
void *htm_status_buf = filp->private_data;
void *htm_status_data = filp->private_data;
long rc, ret;
u64 *num_entries;
u64 to_copy;
int htmstatus_flag;
loff_t offset = 0;
u64 status_offset = 0;
/*
* Invoke H_HTM call with:
* - operation as htm status (H_HTM_OP_STATUS)
* - last three values as addr, size and offset
* - last three values as addr, size and offset.
* "offset" is value from output buffer header
* that points to next entry to dump. 0 is the first
* entry to dump. next entry is read from the output
* bufferbyte offset 0x8.
*/
if (*ppos) {
status_offset = *(u64 *)(htm_status_data + 0x8);
if (status_offset == -1)
return 0;
}
rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
htmtype, H_HTM_OP_STATUS, virt_to_phys(htm_status_buf),
PAGE_SIZE, 0);
htmtype, H_HTM_OP_STATUS, virt_to_phys(htm_status_data),
PAGE_SIZE, be64_to_cpu(status_offset));
ret = htm_return_check(rc);
if (ret <= 0) {
@@ -255,13 +327,15 @@ static ssize_t htmstatus_read(struct file *filp, char __user *ubuf,
* So total count to copy is:
* 32 bytes (for first 7 fields) + (number of HTM entries * entry size)
*/
num_entries = htm_status_buf + 0x10;
num_entries = htm_status_data + 0x10;
if (htmtype == 0x2)
htmstatus_flag = 0x8;
else
htmstatus_flag = 0x6;
to_copy = 32 + (be64_to_cpu(*num_entries) * htmstatus_flag);
return simple_read_from_buffer(ubuf, count, ppos, htm_status_buf, to_copy);
*ppos += to_copy;
return simple_read_from_buffer(ubuf, count, &offset, htm_status_data, to_copy);
}
static const struct file_operations htmstatus_fops = {
@@ -273,19 +347,30 @@ static const struct file_operations htmstatus_fops = {
static ssize_t htminfo_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *ppos)
{
void *htm_info_buf = filp->private_data;
void *htm_info_data = filp->private_data;
long rc, ret;
u64 *num_entries;
u64 to_copy;
loff_t offset = 0;
u64 info_offset = 0;
/*
* Invoke H_HTM call with:
* - operation as htm status (H_HTM_OP_STATUS)
* - last three values as addr, size and offset
* "offset" is value from output buffer header
* that points to next entry to dump. 0 is the first
* entry to dump. next entry is read from the output
* bufferbyte offset 0x8.
*/
if (*ppos) {
info_offset = *(u64 *)(htm_info_data + 0x8);
if (info_offset == -1)
return 0;
}
rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
htmtype, H_HTM_OP_DUMP_SYSPROC_CONF, virt_to_phys(htm_info_buf),
PAGE_SIZE, 0);
htmtype, H_HTM_OP_DUMP_SYSPROC_CONF, virt_to_phys(htm_info_data),
PAGE_SIZE, be64_to_cpu(info_offset));
ret = htm_return_check(rc);
if (ret <= 0) {
@@ -301,15 +386,17 @@ static ssize_t htminfo_read(struct file *filp, char __user *ubuf,
* So total count to copy is:
* 32 bytes (for first 5 fields) + (number of HTM entries * entry size)
*/
num_entries = htm_info_buf + 0x10;
num_entries = htm_info_data + 0x10;
to_copy = 32 + (be64_to_cpu(*num_entries) * 16);
return simple_read_from_buffer(ubuf, count, ppos, htm_info_buf, to_copy);
*ppos += to_copy;
return simple_read_from_buffer(ubuf, count, &offset, htm_info_data, to_copy);
}
static ssize_t htmcaps_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *ppos)
{
void *htm_caps_buf = filp->private_data;
void *htm_caps_data = filp->private_data;
long rc, ret;
/*
@@ -319,7 +406,7 @@ static ssize_t htmcaps_read(struct file *filp, char __user *ubuf,
* and zero
*/
rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
htmtype, H_HTM_OP_CAPABILITIES, virt_to_phys(htm_caps_buf),
htmtype, H_HTM_OP_CAPABILITIES, virt_to_phys(htm_caps_data),
0x80, 0);
ret = htm_return_check(rc);
@@ -328,7 +415,7 @@ static ssize_t htmcaps_read(struct file *filp, char __user *ubuf,
return ret;
}
return simple_read_from_buffer(ubuf, count, ppos, htm_caps_buf, 0x80);
return simple_read_from_buffer(ubuf, count, ppos, htm_caps_data, 0x80);
}
static const struct file_operations htminfo_fops = {
@@ -457,9 +544,17 @@ static int htmdump_init_debugfs(void)
return -ENOMEM;
}
/* Memory to present HTM system memory configuration */
htm_mem_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!htm_mem_buf) {
pr_err("Failed to allocate htm mem buf\n");
return -ENOMEM;
}
debugfs_create_file("htmstatus", 0400, htmdump_debugfs_dir, htm_status_buf, &htmstatus_fops);
debugfs_create_file("htminfo", 0400, htmdump_debugfs_dir, htm_info_buf, &htminfo_fops);
debugfs_create_file("htmcaps", 0400, htmdump_debugfs_dir, htm_caps_buf, &htmcaps_fops);
debugfs_create_file("htmsystem_mem", 0400, htmdump_debugfs_dir, htm_mem_buf, &htmsystem_mem_fops);
return 0;
}
@@ -482,6 +577,10 @@ static void __exit htmdump_exit(void)
{
debugfs_remove_recursive(htmdump_debugfs_dir);
kfree(htm_buf);
kfree(htm_status_buf);
kfree(htm_info_buf);
kfree(htm_caps_buf);
kfree(htm_mem_buf);
}
module_init(htmdump_init);

View File

@@ -190,33 +190,34 @@ static int hvpipe_rtas_recv_msg(char __user *buf, int size)
return -ENOMEM;
}
ret = rtas_ibm_receive_hvpipe_msg(work_area, &srcID,
&bytes_written);
if (!ret) {
/*
* Recv HVPIPE RTAS is successful.
* When releasing FD or no one is waiting on the
* specific source, issue recv HVPIPE RTAS call
* so that pipe is not blocked - this func is called
* with NULL buf.
*/
if (buf) {
if (size < bytes_written) {
pr_err("Received the payload size = %d, but the buffer size = %d\n",
bytes_written, size);
bytes_written = size;
}
ret = copy_to_user(buf,
rtas_work_area_raw_buf(work_area),
bytes_written);
if (!ret)
ret = bytes_written;
}
} else {
pr_err("ibm,receive-hvpipe-msg failed with %d\n",
ret);
/*
* Recv HVPIPE RTAS is successful.
* When releasing FD or no one is waiting on the
* specific source, issue recv HVPIPE RTAS call
* so that pipe is not blocked - this func is called
* with NULL buf.
*/
ret = rtas_ibm_receive_hvpipe_msg(work_area, &srcID, &bytes_written);
if (ret) {
pr_err("ibm,receive-hvpipe-msg failed with %d\n", ret);
goto out;
}
if (!buf)
goto out;
if (size < bytes_written) {
pr_err("Received the payload size = %d, but the buffer size = %d\n",
bytes_written, size);
bytes_written = size;
}
if (copy_to_user(buf, rtas_work_area_raw_buf(work_area), bytes_written))
ret = -EFAULT;
else
ret = bytes_written;
out:
rtas_work_area_free(work_area);
return ret;
}
@@ -327,8 +328,8 @@ static ssize_t papr_hvpipe_handle_read(struct file *file,
{
struct hvpipe_source_info *src_info = file->private_data;
struct papr_hvpipe_hdr hdr;
long ret;
struct papr_hvpipe_hdr hdr = {};
ssize_t ret = 0;
/*
* Return -ENXIO during migration
@@ -376,7 +377,7 @@ static ssize_t papr_hvpipe_handle_read(struct file *file,
ret = copy_to_user(buf, &hdr, HVPIPE_HDR_LEN);
if (ret)
return ret;
return -EFAULT;
/*
* Message event has payload, so get the payload with
@@ -385,19 +386,23 @@ static ssize_t papr_hvpipe_handle_read(struct file *file,
if (hdr.flags & HVPIPE_MSG_AVAILABLE) {
ret = hvpipe_rtas_recv_msg(buf + HVPIPE_HDR_LEN,
size - HVPIPE_HDR_LEN);
if (ret > 0) {
/*
* Always clear MSG_AVAILABLE once the RTAS call has drained
* the message, regardless of whether copy_to_user succeeded.
*/
if (ret >= 0 || ret == -EFAULT)
src_info->hvpipe_status &= ~HVPIPE_MSG_AVAILABLE;
ret += HVPIPE_HDR_LEN;
}
} else if (hdr.flags & HVPIPE_LOST_CONNECTION) {
/*
* Hypervisor is closing the pipe for the specific
* source. So notify user space.
*/
src_info->hvpipe_status &= ~HVPIPE_LOST_CONNECTION;
ret = HVPIPE_HDR_LEN;
}
if (ret >= 0)
ret += HVPIPE_HDR_LEN;
return ret;
}
@@ -444,16 +449,18 @@ static int papr_hvpipe_handle_release(struct inode *inode,
struct file *file)
{
struct hvpipe_source_info *src_info;
unsigned long flags;
/*
* Hold the lock, remove source from src_list, reset the
* hvpipe status and release the lock to prevent any race
* with message event IRQ.
*/
spin_lock(&hvpipe_src_list_lock);
spin_lock_irqsave(&hvpipe_src_list_lock, flags);
src_info = file->private_data;
list_del(&src_info->list);
file->private_data = NULL;
spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
/*
* If the pipe for this specific source has any pending
* payload, issue recv HVPIPE RTAS so that pipe will not
@@ -461,10 +468,8 @@ static int papr_hvpipe_handle_release(struct inode *inode,
*/
if (src_info->hvpipe_status & HVPIPE_MSG_AVAILABLE) {
src_info->hvpipe_status = 0;
spin_unlock(&hvpipe_src_list_lock);
hvpipe_rtas_recv_msg(NULL, 0);
} else
spin_unlock(&hvpipe_src_list_lock);
}
kfree(src_info);
return 0;
@@ -479,50 +484,53 @@ static const struct file_operations papr_hvpipe_handle_ops = {
static int papr_hvpipe_dev_create_handle(u32 srcID)
{
struct hvpipe_source_info *src_info __free(kfree) = NULL;
spin_lock(&hvpipe_src_list_lock);
/*
* Do not allow more than one process communicates with
* each source.
*/
src_info = hvpipe_find_source(srcID);
if (src_info) {
spin_unlock(&hvpipe_src_list_lock);
pr_err("pid(%d) is already using the source(%d)\n",
src_info->tsk->pid, srcID);
return -EALREADY;
}
spin_unlock(&hvpipe_src_list_lock);
struct hvpipe_source_info *src_info;
int fd;
unsigned long flags;
src_info = kzalloc_obj(*src_info, GFP_KERNEL_ACCOUNT);
if (!src_info)
return -ENOMEM;
src_info->srcID = srcID;
src_info->tsk = current;
init_waitqueue_head(&src_info->recv_wqh);
FD_PREPARE(fdf, O_RDONLY | O_CLOEXEC,
anon_inode_getfile("[papr-hvpipe]", &papr_hvpipe_handle_ops,
(void *)src_info, O_RDWR));
if (fdf.err)
return fdf.err;
retain_and_null_ptr(src_info);
spin_lock(&hvpipe_src_list_lock);
/*
* If two processes are executing ioctl() for the same
* source ID concurrently, prevent the second process to
* acquire FD.
* Do not allow more than one process communicates with
* each source.
*/
spin_lock_irqsave(&hvpipe_src_list_lock, flags);
if (hvpipe_find_source(srcID)) {
spin_unlock(&hvpipe_src_list_lock);
spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
pr_err("pid(%s:%d) could not get the source(%d)\n",
current->comm, task_pid_nr(current), srcID);
kfree(src_info);
return -EALREADY;
}
list_add(&src_info->list, &hvpipe_src_list);
spin_unlock(&hvpipe_src_list_lock);
return fd_publish(fdf);
spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
fd = FD_ADD(O_RDONLY | O_CLOEXEC,
anon_inode_getfile("[papr-hvpipe]", &papr_hvpipe_handle_ops,
(void *)src_info, O_RDWR));
if (fd < 0) {
spin_lock_irqsave(&hvpipe_src_list_lock, flags);
list_del(&src_info->list);
spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
/*
* if we fail to add FD, that means no userspace program is
* polling. In that case if there is a msg pending because the
* interrupt was fired after the src_info was added to the
* global list, then let's consume it here, to unblock the
* hvpipe
*/
if (src_info->hvpipe_status & HVPIPE_MSG_AVAILABLE)
hvpipe_rtas_recv_msg(NULL, 0);
kfree(src_info);
return fd;
}
return fd;
}
/*
@@ -685,20 +693,19 @@ static int __init enable_hvpipe_IRQ(void)
struct device_node *np;
hvpipe_check_exception_token = rtas_function_token(RTAS_FN_CHECK_EXCEPTION);
if (hvpipe_check_exception_token == RTAS_UNKNOWN_SERVICE)
if (hvpipe_check_exception_token == RTAS_UNKNOWN_SERVICE)
return -ENODEV;
/* hvpipe events */
np = of_find_node_by_path("/event-sources/ibm,hvpipe-msg-events");
if (np != NULL) {
request_event_sources_irqs(np, hvpipe_event_interrupt,
"HPIPE_EVENT");
of_node_put(np);
} else {
pr_err("Can not enable hvpipe event IRQ\n");
if (!np) {
pr_err("No device node found, could not enable hvpipe event IRQ\n");
return -ENODEV;
}
request_event_sources_irqs(np, hvpipe_event_interrupt, "HPIPE_EVENT");
of_node_put(np);
return 0;
}
@@ -775,23 +782,29 @@ static int __init papr_hvpipe_init(void)
}
ret = enable_hvpipe_IRQ();
if (!ret) {
ret = set_hvpipe_sys_param(1);
if (!ret)
ret = misc_register(&papr_hvpipe_dev);
}
if (ret)
goto out_wq;
if (!ret) {
pr_info("hvpipe feature is enabled\n");
hvpipe_feature = true;
return 0;
}
ret = misc_register(&papr_hvpipe_dev);
if (ret)
goto out_wq;
pr_err("hvpipe feature is not enabled %d\n", ret);
ret = set_hvpipe_sys_param(1);
if (ret)
goto out_misc;
pr_info("hvpipe feature is enabled\n");
hvpipe_feature = true;
return 0;
out_misc:
misc_deregister(&papr_hvpipe_dev);
out_wq:
destroy_workqueue(papr_hvpipe_wq);
out:
kfree(papr_hvpipe_work);
papr_hvpipe_work = NULL;
pr_err("hvpipe feature is not enabled %d\n", ret);
return ret;
}
machine_device_initcall(pseries, papr_hvpipe_init);

View File

@@ -21,7 +21,6 @@ struct hvpipe_source_info {
u32 srcID;
u32 hvpipe_status;
wait_queue_head_t recv_wqh; /* wake up poll() waitq */
struct task_struct *tsk;
};
/*

View File

@@ -1294,13 +1294,16 @@ int x86_perf_rdpmc_index(struct perf_event *event)
return event->hw.event_base_rdpmc;
}
static inline int match_prev_assignment(struct hw_perf_event *hwc,
static inline int match_prev_assignment(struct perf_event *event,
struct cpu_hw_events *cpuc,
int i)
{
struct hw_perf_event *hwc = &event->hw;
return hwc->idx == cpuc->assign[i] &&
hwc->last_cpu == smp_processor_id() &&
hwc->last_tag == cpuc->tags[i];
hwc->last_cpu == smp_processor_id() &&
hwc->last_tag == cpuc->tags[i] &&
!is_acr_event_group(event);
}
static void x86_pmu_start(struct perf_event *event, int flags);
@@ -1346,7 +1349,7 @@ static void x86_pmu_enable(struct pmu *pmu)
* - no other event has used the counter since
*/
if (hwc->idx == -1 ||
match_prev_assignment(hwc, cpuc, i))
match_prev_assignment(event, cpuc, i))
continue;
/*
@@ -1367,7 +1370,7 @@ static void x86_pmu_enable(struct pmu *pmu)
event = cpuc->event_list[i];
hwc = &event->hw;
if (!match_prev_assignment(hwc, cpuc, i))
if (!match_prev_assignment(event, cpuc, i))
x86_assign_hw_event(event, cpuc, i);
else if (i < n_running)
continue;

View File

@@ -3118,11 +3118,11 @@ static void intel_pmu_enable_fixed(struct perf_event *event)
intel_set_masks(event, idx);
/*
* Enable IRQ generation (0x8), if not PEBS,
* and enable ring-3 counting (0x2) and ring-0 counting (0x1)
* if requested:
* Enable IRQ generation (0x8), if not PEBS or self-reloaded
* ACR event, and enable ring-3 counting (0x2) and ring-0
* counting (0x1) if requested:
*/
if (!event->attr.precise_ip)
if (!event->attr.precise_ip && !is_acr_self_reload_event(event))
bits |= INTEL_FIXED_0_ENABLE_PMI;
if (hwc->config & ARCH_PERFMON_EVENTSEL_USR)
bits |= INTEL_FIXED_0_USER;
@@ -3306,6 +3306,15 @@ static void intel_pmu_enable_event(struct perf_event *event)
intel_set_masks(event, idx);
static_call_cond(intel_pmu_enable_acr_event)(event);
static_call_cond(intel_pmu_enable_event_ext)(event);
/*
* For self-reloaded ACR event, don't enable PMI since
* HW won't set overflow bit in GLOBAL_STATUS. Otherwise,
* the PMI would be recognized as a suspicious NMI.
*/
if (is_acr_self_reload_event(event))
hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT;
else if (!event->attr.precise_ip)
hwc->config |= ARCH_PERFMON_EVENTSEL_INT;
__x86_pmu_enable_event(hwc, enable_mask);
break;
case INTEL_PMC_IDX_FIXED ... INTEL_PMC_IDX_FIXED_BTS - 1:
@@ -3332,23 +3341,41 @@ static void intel_pmu_enable_event(struct perf_event *event)
static void intel_pmu_acr_late_setup(struct cpu_hw_events *cpuc)
{
struct perf_event *event, *leader;
int i, j, idx;
int i, j, k, bit, idx;
/*
* FIXME: ACR mask parsing relies on cpuc->event_list[] (active events only).
* Disabling an ACR event causes bit-shifting errors in the acr_mask of
* remaining group members. As ACR sampling requires all events to be active,
* this limitation is acceptable for now. Revisit if independent event toggling
* is required.
*/
for (i = 0; i < cpuc->n_events; i++) {
leader = cpuc->event_list[i];
if (!is_acr_event_group(leader))
continue;
/* The ACR events must be contiguous. */
/* Find the last event of the ACR group. */
for (j = i; j < cpuc->n_events; j++) {
event = cpuc->event_list[j];
if (event->group_leader != leader->group_leader)
break;
for_each_set_bit(idx, (unsigned long *)&event->attr.config2, X86_PMC_IDX_MAX) {
if (i + idx >= cpuc->n_events ||
!is_acr_event_group(cpuc->event_list[i + idx]))
return;
__set_bit(cpuc->assign[i + idx], (unsigned long *)&event->hw.config1);
}
/*
* Translate the user-space ACR mask (attr.config2) into the physical
* counter bitmask (hw.config1) for each ACR event in the group.
* NOTE: ACR event contiguity is guaranteed by intel_pmu_hw_config().
*/
for (k = i; k < j; k++) {
event = cpuc->event_list[k];
event->hw.config1 = 0;
for_each_set_bit(bit, (unsigned long *)&event->attr.config2, X86_PMC_IDX_MAX) {
idx = i + bit;
/* Event index of ACR group must locate in [i, j). */
if (idx >= j || !is_acr_event_group(cpuc->event_list[idx]))
continue;
__set_bit(cpuc->assign[idx], (unsigned long *)&event->hw.config1);
}
}
i = j - 1;
@@ -7504,6 +7531,7 @@ static __always_inline void intel_pmu_init_pnc(struct pmu *pmu)
hybrid(pmu, event_constraints) = intel_pnc_event_constraints;
hybrid(pmu, pebs_constraints) = intel_pnc_pebs_event_constraints;
hybrid(pmu, extra_regs) = intel_pnc_extra_regs;
static_call_update(intel_pmu_enable_acr_event, intel_pmu_enable_acr);
}
static __always_inline void intel_pmu_init_skt(struct pmu *pmu)

View File

@@ -137,6 +137,16 @@ static inline bool is_acr_event_group(struct perf_event *event)
return check_leader_group(event->group_leader, PERF_X86_EVENT_ACR);
}
static inline bool is_acr_self_reload_event(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
if (hwc->idx < 0)
return false;
return test_bit(hwc->idx, (unsigned long *)&hwc->config1);
}
struct amd_nb {
int nb_id; /* NorthBridge id */
int refcnt; /* reference count */

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

@@ -450,6 +450,10 @@ __init static int append_e820_table(struct boot_e820_entry *entries, u32 nr_entr
{
struct boot_e820_entry *entry = entries;
/* If there aren't any entries, we'll want to fall back to another source: */
if (!nr_entries)
return -ENOENT;
while (nr_entries) {
u64 start = entry->addr;
u64 size = entry->size;
@@ -458,7 +462,7 @@ __init static int append_e820_table(struct boot_e820_entry *entries, u32 nr_entr
/* Ignore the remaining entries on 64-bit overflow: */
if (start > end && likely(size))
return -1;
return -EINVAL;
e820__range_add(start, size, type);

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

@@ -695,17 +695,22 @@ static void __init xen_e820_resolve_conflicts(phys_addr_t start,
return;
end = start + size;
entry = xen_e820_table.entries;
mapcnt = 0;
for (mapcnt = 0; mapcnt < xen_e820_table.nr_entries; mapcnt++) {
while (mapcnt < xen_e820_table.nr_entries) {
entry = xen_e820_table.entries + mapcnt;
if (entry->addr >= end)
return;
if (entry->addr + entry->size > start &&
entry->type == E820_TYPE_NVS)
entry->type == E820_TYPE_NVS) {
xen_e820_swap_entry_with_ram(entry);
/* E820 map has been changed, restart loop! */
mapcnt = 0;
continue;
}
entry++;
mapcnt++;
}
}

View File

@@ -857,6 +857,8 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
#endif
struct blk_iou_cmd {
u64 start;
u64 len;
int res;
bool nowait;
};
@@ -946,23 +948,27 @@ int blkdev_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
{
struct block_device *bdev = I_BDEV(cmd->file->f_mapping->host);
struct blk_iou_cmd *bic = io_uring_cmd_to_pdu(cmd, struct blk_iou_cmd);
const struct io_uring_sqe *sqe = cmd->sqe;
u32 cmd_op = cmd->cmd_op;
uint64_t start, len;
if (unlikely(sqe->ioprio || sqe->__pad1 || sqe->len ||
sqe->rw_flags || sqe->file_index))
return -EINVAL;
/* Read what we need from the SQE on the first issue */
if (!(issue_flags & IORING_URING_CMD_REISSUE)) {
const struct io_uring_sqe *sqe = cmd->sqe;
if (unlikely(sqe->ioprio || sqe->__pad1 || sqe->len ||
sqe->rw_flags || sqe->file_index))
return -EINVAL;
bic->start = READ_ONCE(sqe->addr);
bic->len = READ_ONCE(sqe->addr3);
}
bic->res = 0;
bic->nowait = issue_flags & IO_URING_F_NONBLOCK;
start = READ_ONCE(sqe->addr);
len = READ_ONCE(sqe->addr3);
switch (cmd_op) {
case BLOCK_URING_CMD_DISCARD:
return blkdev_cmd_discard(cmd, bdev, start, len, bic->nowait);
return blkdev_cmd_discard(cmd, bdev, bic->start, bic->len,
bic->nowait);
}
return -EINVAL;
}

View File

@@ -537,6 +537,26 @@ static const struct file_operations ivpu_fops = {
#endif
};
static int ivpu_gem_prime_handle_to_fd(struct drm_device *dev, struct drm_file *file_priv,
u32 handle, u32 flags, int *prime_fd)
{
struct drm_gem_object *obj;
obj = drm_gem_object_lookup(file_priv, handle);
if (!obj)
return -ENOENT;
if (drm_gem_is_imported(obj)) {
/* Do not allow re-exporting */
drm_gem_object_put(obj);
return -EOPNOTSUPP;
}
drm_gem_object_put(obj);
return drm_gem_prime_handle_to_fd(dev, file_priv, handle, flags, prime_fd);
}
static const struct drm_driver driver = {
.driver_features = DRIVER_GEM | DRIVER_COMPUTE_ACCEL,
@@ -545,6 +565,7 @@ static const struct drm_driver driver = {
.gem_create_object = ivpu_gem_create_object,
.gem_prime_import = ivpu_gem_prime_import,
.prime_handle_to_fd = ivpu_gem_prime_handle_to_fd,
.ioctls = ivpu_drm_ioctls,
.num_ioctls = ARRAY_SIZE(ivpu_drm_ioctls),

View File

@@ -497,11 +497,11 @@ static void decode_ras_msg(struct qaic_device *qdev, struct ras_data *msg)
qdev->ce_count++;
break;
case UE:
if (qdev->ce_count != UINT_MAX)
if (qdev->ue_count != UINT_MAX)
qdev->ue_count++;
break;
case UE_NF:
if (qdev->ce_count != UINT_MAX)
if (qdev->ue_nf_count != UINT_MAX)
qdev->ue_nf_count++;
break;
default:

View File

@@ -204,7 +204,6 @@ pub(crate) fn reservation_abort(&mut self, offset: usize) -> Result<FreedRange>
// caller will mark them as unused, which means that they can be freed if the system comes
// under memory pressure.
let mut freed_range = FreedRange::interior_pages(offset, size);
#[expect(clippy::collapsible_if)] // reads better like this
if offset % PAGE_SIZE != 0 {
if i == 0 || self.ranges[i - 1].endpoint() <= (offset & PAGE_MASK) {
freed_range.start_page_idx -= 1;

View File

@@ -900,6 +900,20 @@ static int ublk_validate_params(const struct ublk_device *ub)
if (p->logical_bs_shift > PAGE_SHIFT || p->logical_bs_shift < 9)
return -EINVAL;
/*
* 256M is a reasonable upper bound for physical block size,
* io_min and io_opt; it aligns with the maximum physical
* block size possible in NVMe.
*/
if (p->physical_bs_shift > ilog2(SZ_256M))
return -EINVAL;
if (p->io_min_shift > ilog2(SZ_256M))
return -EINVAL;
if (p->io_opt_shift > ilog2(SZ_256M))
return -EINVAL;
if (p->logical_bs_shift > p->physical_bs_shift)
return -EINVAL;
@@ -2397,8 +2411,14 @@ static void ublk_reset_ch_dev(struct ublk_device *ub)
{
int i;
for (i = 0; i < ub->dev_info.nr_hw_queues; i++)
ublk_queue_reinit(ub, ublk_get_queue(ub, i));
for (i = 0; i < ub->dev_info.nr_hw_queues; i++) {
struct ublk_queue *ubq = ublk_get_queue(ub, i);
/* Sync with ublk_cancel_cmd() */
spin_lock(&ubq->cancel_lock);
ublk_queue_reinit(ub, ubq);
spin_unlock(&ubq->cancel_lock);
}
/* set to NULL, otherwise new tasks cannot mmap io_cmd_buf */
ub->mm = NULL;
@@ -2739,6 +2759,7 @@ static void ublk_cancel_cmd(struct ublk_queue *ubq, unsigned tag,
{
struct ublk_io *io = &ubq->ios[tag];
struct ublk_device *ub = ubq->dev;
struct io_uring_cmd *cmd = NULL;
struct request *req;
bool done;
@@ -2761,12 +2782,15 @@ static void ublk_cancel_cmd(struct ublk_queue *ubq, unsigned tag,
spin_lock(&ubq->cancel_lock);
done = !!(io->flags & UBLK_IO_FLAG_CANCELED);
if (!done)
if (!done) {
io->flags |= UBLK_IO_FLAG_CANCELED;
cmd = io->cmd;
io->cmd = NULL;
}
spin_unlock(&ubq->cancel_lock);
if (!done)
io_uring_cmd_done(io->cmd, UBLK_IO_RES_ABORT, issue_flags);
if (!done && cmd)
io_uring_cmd_done(cmd, UBLK_IO_RES_ABORT, issue_flags);
}
/*
@@ -3496,8 +3520,10 @@ static void ublk_ch_uring_cmd_cb(struct io_tw_req tw_req, io_tw_token_t tw)
{
unsigned int issue_flags = IO_URING_CMD_TASK_WORK_ISSUE_FLAGS;
struct io_uring_cmd *cmd = io_uring_cmd_from_tw(tw_req);
int ret = ublk_ch_uring_cmd_local(cmd, issue_flags);
int ret = -ECANCELED;
if (!tw.cancel)
ret = ublk_ch_uring_cmd_local(cmd, issue_flags);
if (ret != -EIOCBQUEUED)
io_uring_cmd_done(cmd, ret, issue_flags);
}
@@ -4990,13 +5016,15 @@ static int ublk_ctrl_set_params(struct ublk_device *ub,
*/
ret = -EACCES;
} else if (copy_from_user(&ub->params, argp, ph.len)) {
/* zero out partial copy so no stale params survive */
memset(&ub->params, 0, sizeof(ub->params));
ret = -EFAULT;
} else {
/* clear all we don't support yet */
ub->params.types &= UBLK_PARAM_TYPE_ALL;
ret = ublk_validate_params(ub);
if (ret)
ub->params.types = 0;
memset(&ub->params, 0, sizeof(ub->params));
}
mutex_unlock(&ub->mutex);

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

@@ -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

@@ -110,6 +110,7 @@ struct eqc_match_data {
const char *reset_auxdev_name;
const char *pinctrl_auxdev_name;
const char *eth_phy_auxdev_name;
unsigned int early_clk_count;
};
@@ -321,38 +322,18 @@ static void eqc_probe_init_fixed_factors(struct device *dev,
}
}
static void eqc_auxdev_release(struct device *dev)
{
struct auxiliary_device *adev = to_auxiliary_dev(dev);
kfree(adev);
}
static int eqc_auxdev_create(struct device *dev, void __iomem *base,
const char *name, u32 id)
static void eqc_auxdev_create_optional(struct device *dev, void __iomem *base,
const char *name)
{
struct auxiliary_device *adev;
int ret;
adev = kzalloc_obj(*adev);
if (!adev)
return -ENOMEM;
adev->name = name;
adev->dev.parent = dev;
adev->dev.platform_data = (void __force *)base;
adev->dev.release = eqc_auxdev_release;
adev->id = id;
ret = auxiliary_device_init(adev);
if (ret)
return ret;
ret = auxiliary_device_add(adev);
if (ret)
auxiliary_device_uninit(adev);
return ret;
if (name) {
adev = devm_auxiliary_device_create(dev, name,
(void __force *)base);
if (!adev)
dev_warn(dev, "failed creating auxiliary device %s.%s\n",
KBUILD_MODNAME, name);
}
}
static int eqc_probe(struct platform_device *pdev)
@@ -364,7 +345,6 @@ static int eqc_probe(struct platform_device *pdev)
unsigned int i, clk_count;
struct resource *res;
void __iomem *base;
int ret;
data = device_get_match_data(dev);
if (!data)
@@ -378,21 +358,10 @@ static int eqc_probe(struct platform_device *pdev)
if (!base)
return -ENOMEM;
/* Init optional reset auxiliary device. */
if (data->reset_auxdev_name) {
ret = eqc_auxdev_create(dev, base, data->reset_auxdev_name, 0);
if (ret)
dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n",
KBUILD_MODNAME, data->reset_auxdev_name, ret);
}
/* Init optional pinctrl auxiliary device. */
if (data->pinctrl_auxdev_name) {
ret = eqc_auxdev_create(dev, base, data->pinctrl_auxdev_name, 0);
if (ret)
dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n",
KBUILD_MODNAME, data->pinctrl_auxdev_name, ret);
}
/* Init optional auxiliary devices. */
eqc_auxdev_create_optional(dev, base, data->reset_auxdev_name);
eqc_auxdev_create_optional(dev, base, data->pinctrl_auxdev_name);
eqc_auxdev_create_optional(dev, base, data->eth_phy_auxdev_name);
if (data->pll_count + data->div_count + data->fixed_factor_count == 0)
return 0; /* Zero clocks, we are done. */
@@ -553,6 +522,7 @@ static const struct eqc_match_data eqc_eyeq5_match_data = {
.reset_auxdev_name = "reset",
.pinctrl_auxdev_name = "pinctrl",
.eth_phy_auxdev_name = "phy",
.early_clk_count = ARRAY_SIZE(eqc_eyeq5_early_plls) +
ARRAY_SIZE(eqc_eyeq5_early_fixed_factors),

View File

@@ -153,7 +153,7 @@ static int rk808_clkout_probe(struct platform_device *pdev)
struct rk808_clkout *rk808_clkout;
int ret;
dev->of_node = pdev->dev.parent->of_node;
device_set_of_node_from_dev(dev, dev->parent);
rk808_clkout = devm_kzalloc(dev,
sizeof(*rk808_clkout), GFP_KERNEL);

View File

@@ -846,7 +846,7 @@ static const struct clk_parent_data top_parents[] = {
CCU_PARENT_HW(pll6_d3),
};
CCU_MUX_DIV_GATE_FC_DEFINE(top_dclk, top_parents, APMU_TOP_DCLK_CTRL, 5, 3,
BIT(8), 2, 3, BIT(1), 0);
BIT(8), 2, 3, BIT(1), CLK_IS_CRITICAL);
static const struct clk_parent_data ucie_parents[] = {
CCU_PARENT_HW(pll1_d8_307p2),

View File

@@ -777,9 +777,9 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i
u32 num_chans, rank, dwidth, config;
struct edac_mc_layer layers[2];
struct mem_ctl_info *mci;
char name[MC_NAME_LEN];
struct device *dev;
enum dev_type dt;
char *name;
int rc;
config = priv->adec[CONF + i * ADEC_NUM];
@@ -813,13 +813,9 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i
layers[1].is_virt_csrow = false;
rc = -ENOMEM;
name = kzalloc(MC_NAME_LEN, GFP_KERNEL);
if (!name)
return rc;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
goto err_name_free;
return rc;
mci = edac_mc_alloc(i, ARRAY_SIZE(layers), layers, sizeof(struct mc_priv));
if (!mci) {
@@ -858,8 +854,6 @@ static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i
edac_mc_free(mci);
err_dev_free:
kfree(dev);
err_name_free:
kfree(name);
return rc;
}

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

@@ -3149,11 +3149,7 @@ static int __init amdgpu_init(void)
r = amdgpu_sync_init();
if (r)
goto error_sync;
r = amdgpu_userq_fence_slab_init();
if (r)
goto error_fence;
return r;
amdgpu_register_atpx_handler();
amdgpu_acpi_detect();
@@ -3161,7 +3157,7 @@ static int __init amdgpu_init(void)
/* Ignore KFD init failures when CONFIG_HSA_AMD is not set. */
r = amdgpu_amdkfd_init();
if (r && r != -ENOENT)
goto error_fence;
goto error_fini_sync;
if (amdgpu_pp_feature_mask & PP_OVERDRIVE_MASK) {
add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
@@ -3172,10 +3168,8 @@ static int __init amdgpu_init(void)
/* let modprobe override vga console setting */
return pci_register_driver(&amdgpu_kms_pci_driver);
error_fence:
error_fini_sync:
amdgpu_sync_fini();
error_sync:
return r;
}
@@ -3186,7 +3180,6 @@ static void __exit amdgpu_exit(void)
amdgpu_unregister_atpx_handler();
amdgpu_acpi_release();
amdgpu_sync_fini();
amdgpu_userq_fence_slab_fini();
mmu_notifier_synchronize();
amdgpu_xcp_drv_release();
}

View File

@@ -262,12 +262,19 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev)
*/
int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev)
{
int r;
if (adev->gart.bo != NULL)
return 0;
return amdgpu_bo_create_kernel(adev, adev->gart.table_size, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM, &adev->gart.bo,
NULL, (void *)&adev->gart.ptr);
r = amdgpu_bo_create_kernel(adev, adev->gart.table_size, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM, &adev->gart.bo,
NULL, (void *)&adev->gart.ptr);
if (r)
return r;
memset_io(adev->gart.ptr, adev->gart.gart_pte_flags, adev->gart.table_size);
return 0;
}
/**

View File

@@ -32,29 +32,9 @@
#include "amdgpu.h"
#include "amdgpu_userq_fence.h"
static const struct dma_fence_ops amdgpu_userq_fence_ops;
static struct kmem_cache *amdgpu_userq_fence_slab;
#define AMDGPU_USERQ_MAX_HANDLES (1U << 16)
int amdgpu_userq_fence_slab_init(void)
{
amdgpu_userq_fence_slab = kmem_cache_create("amdgpu_userq_fence",
sizeof(struct amdgpu_userq_fence),
0,
SLAB_HWCACHE_ALIGN,
NULL);
if (!amdgpu_userq_fence_slab)
return -ENOMEM;
return 0;
}
void amdgpu_userq_fence_slab_fini(void)
{
rcu_barrier();
kmem_cache_destroy(amdgpu_userq_fence_slab);
}
static const struct dma_fence_ops amdgpu_userq_fence_ops;
static inline struct amdgpu_userq_fence *to_amdgpu_userq_fence(struct dma_fence *f)
{
@@ -231,7 +211,7 @@ void amdgpu_userq_fence_driver_put(struct amdgpu_userq_fence_driver *fence_drv)
static int amdgpu_userq_fence_alloc(struct amdgpu_userq_fence **userq_fence)
{
*userq_fence = kmem_cache_alloc(amdgpu_userq_fence_slab, GFP_ATOMIC);
*userq_fence = kmalloc(sizeof(**userq_fence), GFP_KERNEL);
return *userq_fence ? 0 : -ENOMEM;
}
@@ -342,7 +322,7 @@ static void amdgpu_userq_fence_free(struct rcu_head *rcu)
amdgpu_userq_fence_driver_put(fence_drv);
kvfree(userq_fence->fence_drv_array);
kmem_cache_free(amdgpu_userq_fence_slab, userq_fence);
kfree(userq_fence);
}
static void amdgpu_userq_fence_release(struct dma_fence *f)
@@ -545,7 +525,7 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
r = amdgpu_userq_fence_create(queue, userq_fence, wptr, &fence);
if (r) {
mutex_unlock(&userq_mgr->userq_mutex);
kmem_cache_free(amdgpu_userq_fence_slab, userq_fence);
kfree(userq_fence);
goto put_gobj_write;
}

View File

@@ -58,9 +58,6 @@ struct amdgpu_userq_fence_driver {
char timeline_name[TASK_COMM_LEN];
};
int amdgpu_userq_fence_slab_init(void);
void amdgpu_userq_fence_slab_fini(void);
void amdgpu_userq_fence_driver_get(struct amdgpu_userq_fence_driver *fence_drv);
void amdgpu_userq_fence_driver_put(struct amdgpu_userq_fence_driver *fence_drv);
int amdgpu_userq_fence_driver_alloc(struct amdgpu_device *adev,

View File

@@ -5660,9 +5660,6 @@ static void gfx_v9_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr,
{
struct amdgpu_device *adev = ring->adev;
/* we only allocate 32bit for each seq wb address */
BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
/* write fence seq to the "addr" */
amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |

View File

@@ -30,34 +30,6 @@
#define AMDGPU_USERQ_PROC_CTX_SZ PAGE_SIZE
#define AMDGPU_USERQ_GANG_CTX_SZ PAGE_SIZE
static int
mes_userq_map_gtt_bo_to_gart(struct amdgpu_bo *bo)
{
int ret;
ret = amdgpu_bo_reserve(bo, true);
if (ret) {
DRM_ERROR("Failed to reserve bo. ret %d\n", ret);
goto err_reserve_bo_failed;
}
ret = amdgpu_ttm_alloc_gart(&bo->tbo);
if (ret) {
DRM_ERROR("Failed to bind bo to GART. ret %d\n", ret);
goto err_map_bo_gart_failed;
}
amdgpu_bo_unreserve(bo);
bo = amdgpu_bo_ref(bo);
return 0;
err_map_bo_gart_failed:
amdgpu_bo_unreserve(bo);
err_reserve_bo_failed:
return ret;
}
static int
mes_userq_create_wptr_mapping(struct amdgpu_device *adev,
struct amdgpu_userq_mgr *uq_mgr,
@@ -65,55 +37,62 @@ mes_userq_create_wptr_mapping(struct amdgpu_device *adev,
uint64_t wptr)
{
struct amdgpu_bo_va_mapping *wptr_mapping;
struct amdgpu_vm *wptr_vm;
struct amdgpu_userq_obj *wptr_obj = &queue->wptr_obj;
struct amdgpu_bo *obj;
struct amdgpu_vm *vm = queue->vm;
struct drm_exec exec;
int ret;
wptr_vm = queue->vm;
ret = amdgpu_bo_reserve(wptr_vm->root.bo, false);
if (ret)
return ret;
wptr &= AMDGPU_GMC_HOLE_MASK;
wptr_mapping = amdgpu_vm_bo_lookup_mapping(wptr_vm, wptr >> PAGE_SHIFT);
amdgpu_bo_unreserve(wptr_vm->root.bo);
if (!wptr_mapping) {
DRM_ERROR("Failed to lookup wptr bo\n");
return -EINVAL;
drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 2);
drm_exec_until_all_locked(&exec) {
ret = amdgpu_vm_lock_pd(vm, &exec, 1);
drm_exec_retry_on_contention(&exec);
if (unlikely(ret))
goto fail_lock;
wptr_mapping = amdgpu_vm_bo_lookup_mapping(vm, wptr >> PAGE_SHIFT);
if (!wptr_mapping) {
ret = -EINVAL;
goto fail_lock;
}
obj = wptr_mapping->bo_va->base.bo;
ret = drm_exec_lock_obj(&exec, &obj->tbo.base);
drm_exec_retry_on_contention(&exec);
if (unlikely(ret))
goto fail_lock;
}
wptr_obj->obj = wptr_mapping->bo_va->base.bo;
wptr_obj->obj = amdgpu_bo_ref(wptr_mapping->bo_va->base.bo);
if (wptr_obj->obj->tbo.base.size > PAGE_SIZE) {
DRM_ERROR("Requested GART mapping for wptr bo larger than one page\n");
return -EINVAL;
}
ret = mes_userq_map_gtt_bo_to_gart(wptr_obj->obj);
if (ret) {
DRM_ERROR("Failed to map wptr bo to GART\n");
return ret;
}
ret = amdgpu_bo_reserve(wptr_obj->obj, true);
if (ret) {
DRM_ERROR("Failed to reserve wptr bo\n");
return ret;
ret = -EINVAL;
goto fail_map;
}
/* TODO use eviction fence instead of pinning. */
ret = amdgpu_bo_pin(wptr_obj->obj, AMDGPU_GEM_DOMAIN_GTT);
if (ret) {
drm_file_err(uq_mgr->file, "[Usermode queues] Failed to pin wptr bo\n");
goto unresv_bo;
DRM_ERROR("Failed to pin wptr bo. ret %d\n", ret);
goto fail_map;
}
ret = amdgpu_ttm_alloc_gart(&wptr_obj->obj->tbo);
if (ret) {
DRM_ERROR("Failed to bind bo to GART. ret %d\n", ret);
goto fail_map;
}
queue->wptr_obj.gpu_addr = amdgpu_bo_gpu_offset(wptr_obj->obj);
amdgpu_bo_unreserve(wptr_obj->obj);
drm_exec_fini(&exec);
return 0;
unresv_bo:
amdgpu_bo_unreserve(wptr_obj->obj);
fail_map:
amdgpu_bo_unref(&wptr_obj->obj);
fail_lock:
drm_exec_fini(&exec);
return ret;
}

View File

@@ -889,7 +889,7 @@ static void sdma_v4_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
/* write the fence */
amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE));
/* zero in first two bits */
BUG_ON(addr & 0x3);
WARN_ON(addr & 0x3);
amdgpu_ring_write(ring, lower_32_bits(addr));
amdgpu_ring_write(ring, upper_32_bits(addr));
amdgpu_ring_write(ring, lower_32_bits(seq));
@@ -899,7 +899,7 @@ static void sdma_v4_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
addr += 4;
amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE));
/* zero in first two bits */
BUG_ON(addr & 0x3);
WARN_ON(addr & 0x3);
amdgpu_ring_write(ring, lower_32_bits(addr));
amdgpu_ring_write(ring, upper_32_bits(addr));
amdgpu_ring_write(ring, upper_32_bits(seq));

View File

@@ -1360,7 +1360,7 @@ static int kfd_ioctl_map_memory_to_gpu(struct file *filep,
peer_pdd = kfd_process_device_data_by_id(p, devices_arr[i]);
if (WARN_ON_ONCE(!peer_pdd))
continue;
kfd_flush_tlb(peer_pdd, TLB_FLUSH_LEGACY);
kfd_flush_tlb(peer_pdd);
}
kfree(devices_arr);
@@ -1455,7 +1455,7 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file *filep,
if (WARN_ON_ONCE(!peer_pdd))
continue;
if (flush_tlb)
kfd_flush_tlb(peer_pdd, TLB_FLUSH_HEAVYWEIGHT);
kfd_flush_tlb(peer_pdd);
/* Remove dma mapping after tlb flush to avoid IO_PAGE_FAULT */
err = amdgpu_amdkfd_gpuvm_dmaunmap_mem(mem, peer_pdd->drm_priv);

View File

@@ -1737,37 +1737,6 @@ bool kgd2kfd_vmfault_fast_path(struct amdgpu_device *adev, struct amdgpu_iv_entr
return false;
}
/* check if there is kfd process still uses adev */
static bool kgd2kfd_check_device_idle(struct amdgpu_device *adev)
{
struct kfd_process *p;
struct hlist_node *p_temp;
unsigned int temp;
struct kfd_node *dev;
mutex_lock(&kfd_processes_mutex);
if (hash_empty(kfd_processes_table)) {
mutex_unlock(&kfd_processes_mutex);
return true;
}
/* check if there is device still use adev */
hash_for_each_safe(kfd_processes_table, temp, p_temp, p, kfd_processes) {
for (int i = 0; i < p->n_pdds; i++) {
dev = p->pdds[i]->dev;
if (dev->adev == adev) {
mutex_unlock(&kfd_processes_mutex);
return false;
}
}
}
mutex_unlock(&kfd_processes_mutex);
return true;
}
/** kgd2kfd_teardown_processes - gracefully tear down existing
* kfd processes that use adev
*
@@ -1800,7 +1769,7 @@ void kgd2kfd_teardown_processes(struct amdgpu_device *adev)
mutex_unlock(&kfd_processes_mutex);
/* wait all kfd processes use adev terminate */
while (!kgd2kfd_check_device_idle(adev))
while (!!atomic_read(&adev->kfd.dev->kfd_processes_count))
cond_resched();
}

View File

@@ -572,7 +572,7 @@ static int allocate_vmid(struct device_queue_manager *dqm,
qpd->vmid,
qpd->page_table_base);
/* invalidate the VM context after pasid and vmid mapping is set up */
kfd_flush_tlb(qpd_to_pdd(qpd), TLB_FLUSH_LEGACY);
kfd_flush_tlb(qpd_to_pdd(qpd));
if (dqm->dev->kfd2kgd->set_scratch_backing_va)
dqm->dev->kfd2kgd->set_scratch_backing_va(dqm->dev->adev,
@@ -610,7 +610,7 @@ static void deallocate_vmid(struct device_queue_manager *dqm,
if (flush_texture_cache_nocpsch(q->device, qpd))
dev_err(dev, "Failed to flush TC\n");
kfd_flush_tlb(qpd_to_pdd(qpd), TLB_FLUSH_LEGACY);
kfd_flush_tlb(qpd_to_pdd(qpd));
/* Release the vmid mapping */
set_pasid_vmid_mapping(dqm, 0, qpd->vmid);
@@ -1284,7 +1284,7 @@ static int restore_process_queues_nocpsch(struct device_queue_manager *dqm,
dqm->dev->adev,
qpd->vmid,
qpd->page_table_base);
kfd_flush_tlb(pdd, TLB_FLUSH_LEGACY);
kfd_flush_tlb(pdd);
}
/* Take a safe reference to the mm_struct, which may otherwise

View File

@@ -1554,13 +1554,13 @@ void kfd_signal_reset_event(struct kfd_node *dev);
void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid);
void kfd_signal_process_terminate_event(struct kfd_process *p);
static inline void kfd_flush_tlb(struct kfd_process_device *pdd,
enum TLB_FLUSH_TYPE type)
static inline void kfd_flush_tlb(struct kfd_process_device *pdd)
{
struct amdgpu_device *adev = pdd->dev->adev;
struct amdgpu_vm *vm = drm_priv_to_vm(pdd->drm_priv);
amdgpu_vm_flush_compute_tlb(adev, vm, type, pdd->dev->xcc_mask);
amdgpu_vm_flush_compute_tlb(adev, vm, TLB_FLUSH_HEAVYWEIGHT,
pdd->dev->xcc_mask);
}
static inline bool kfd_flush_tlb_after_unmap(struct kfd_dev *dev)

View File

@@ -1424,7 +1424,7 @@ svm_range_unmap_from_gpus(struct svm_range *prange, unsigned long start,
if (r)
break;
}
kfd_flush_tlb(pdd, TLB_FLUSH_HEAVYWEIGHT);
kfd_flush_tlb(pdd);
}
return r;
@@ -1571,7 +1571,7 @@ svm_range_map_to_gpus(struct svm_range *prange, unsigned long offset,
}
}
kfd_flush_tlb(pdd, TLB_FLUSH_LEGACY);
kfd_flush_tlb(pdd);
}
return r;

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