mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
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:
1
.mailmap
1
.mailmap
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)::
|
||||
|
||||
|
||||
45
MAINTAINERS
45
MAINTAINERS
@@ -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>
|
||||
|
||||
4
Makefile
4
Makefile
@@ -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 \
|
||||
|
||||
@@ -983,8 +983,8 @@ static int sve_set_common(struct task_struct *target,
|
||||
}
|
||||
|
||||
/* Always zero V regs, FPSR, and FPCR */
|
||||
memset(¤t->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 */
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -220,6 +220,7 @@ menu "Kernel type and options"
|
||||
|
||||
choice
|
||||
prompt "Kernel type"
|
||||
default 64BIT # Keep existing behavior
|
||||
|
||||
config 32BIT
|
||||
bool "32-bit kernel"
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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; \
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))) {
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) &&
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))) {
|
||||
/*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) |
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user