mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
ASoC: nau8822: add support for supply regulators
Alexey Charkov <alchark@flipper.net> says: The Nuvoton NAU8822 codec has four power supply pins: VDDA, VDDB, VDDC and VDDSPK, which must be online and stable before the device can be accessed over I2C. On boards where these rails are software-controlled, probing the codec before the regulators are up results in -ENXIO errors during register access. This short series adds optional regulator support to both the device tree binding and the driver, so platforms that need explicit power sequencing can describe and enforce it: Link: https://patch.msgid.link/20260525-nau8822-reg-v2-0-7d37ae393e46@flipper.net
This commit is contained in:
commit
a67c554dbc
6
.mailmap
6
.mailmap
|
|
@ -263,8 +263,9 @@ Enric Balletbo i Serra <eballetbo@kernel.org> <enric.balletbo@collabora.com>
|
|||
Enric Balletbo i Serra <eballetbo@kernel.org> <eballetbo@iseebcn.com>
|
||||
Erik Kaneda <erik.kaneda@intel.com> <erik.schmauss@intel.com>
|
||||
Ethan Carter Edwards <ethan@ethancedwards.com> Ethan Edwards <ethancarteredwards@gmail.com>
|
||||
Eugen Hristev <eugen.hristev@linaro.org> <eugen.hristev@microchip.com>
|
||||
Eugen Hristev <eugen.hristev@linaro.org> <eugen.hristev@collabora.com>
|
||||
Eugen Hristev <ehristev@kernel.org> <eugen.hristev@microchip.com>
|
||||
Eugen Hristev <ehristev@kernel.org> <eugen.hristev@linaro.org>
|
||||
Eugen Hristev <ehristev@kernel.org> <eugen.hristev@collabora.com>
|
||||
Evgeniy Polyakov <johnpol@2ka.mipt.ru>
|
||||
Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> <ezequiel@collabora.com>
|
||||
Faith Ekstrand <faith.ekstrand@collabora.com> <jason@jlekstrand.net>
|
||||
|
|
@ -339,6 +340,7 @@ Henrik Rydberg <rydberg@bitmath.org>
|
|||
Herbert Xu <herbert@gondor.apana.org.au>
|
||||
Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
|
||||
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
|
||||
Ian Ray <ian.ray@gehealthcare.com> <ian.ray@ge.com>
|
||||
Ignat Korchagin <ignat@linux.win> <ignat@cloudflare.com>
|
||||
Igor Korotin <igor.korotin@linux.dev> <igor.korotin.linux@gmail.com>
|
||||
Ike Panhc <ikepanhc@gmail.com> <ike.pan@canonical.com>
|
||||
|
|
|
|||
|
|
@ -789,24 +789,6 @@ Kernel parameters
|
|||
cio_ignore= [S390]
|
||||
See Documentation/arch/s390/common_io.rst for details.
|
||||
|
||||
clearcpuid=X[,X...] [X86]
|
||||
Disable CPUID feature X for the kernel. See
|
||||
arch/x86/include/asm/cpufeatures.h for the valid bit
|
||||
numbers X. Note the Linux-specific bits are not necessarily
|
||||
stable over kernel options, but the vendor-specific
|
||||
ones should be.
|
||||
X can also be a string as appearing in the flags: line
|
||||
in /proc/cpuinfo which does not have the above
|
||||
instability issue. However, not all features have names
|
||||
in /proc/cpuinfo.
|
||||
Note that using this option will taint your kernel.
|
||||
Also note that user programs calling CPUID directly
|
||||
or using the feature without checking anything
|
||||
will still see it. This just prevents it from
|
||||
being used by the kernel or shown in /proc/cpuinfo.
|
||||
Also note the kernel might malfunction if you disable
|
||||
some critical bits.
|
||||
|
||||
clk_ignore_unused
|
||||
[CLK]
|
||||
Prevents the clock framework from automatically gating
|
||||
|
|
|
|||
|
|
@ -187,6 +187,10 @@ to disable features using the feature number as defined in
|
|||
Protection can be disabled using clearcpuid=514. The number 514 is calculated
|
||||
from #define X86_FEATURE_UMIP (16*32 + 2).
|
||||
|
||||
DO NOT USE this cmdline option in production - it is meant to be used only as
|
||||
a quick'n'dirty debugging aid to rule out a feature-enabling code is the
|
||||
culprit. If you use it, it'll taint the kernel.
|
||||
|
||||
In addition, there exists a variety of custom command-line parameters that
|
||||
disable specific features. The list of parameters includes, but is not limited
|
||||
to, nofsgsbase, nosgx, noxsave, etc. 5-level paging can also be disabled using
|
||||
|
|
|
|||
|
|
@ -30,6 +30,20 @@ properties:
|
|||
clock-names:
|
||||
const: mclk
|
||||
|
||||
vdda-supply:
|
||||
description: Analog power supply
|
||||
|
||||
vddb-supply:
|
||||
description: Digital buffer (input/output) supply
|
||||
|
||||
vddc-supply:
|
||||
description: Digital core supply
|
||||
|
||||
vddspk-supply:
|
||||
description:
|
||||
Speaker supply (power supply pin for RSPKOUT, LSPKOUT, AUXOUT2 and
|
||||
AUXTOUT1 output drivers)
|
||||
|
||||
nuvoton,spk-btl:
|
||||
description:
|
||||
If set, configure the two loudspeaker outputs as a Bridge Tied Load output
|
||||
|
|
@ -54,5 +68,9 @@ examples:
|
|||
codec@1a {
|
||||
compatible = "nuvoton,nau8822";
|
||||
reg = <0x1a>;
|
||||
vdda-supply = <&vcca_3v3_s0>;
|
||||
vddb-supply = <&vcca_3v3_s0>;
|
||||
vddc-supply = <&vcca_3v3_s0>;
|
||||
vddspk-supply = <&vcca_3v3_s0>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- qcom,ipq5018-snand
|
||||
- qcom,ipq5210-snand
|
||||
- qcom,ipq5332-snand
|
||||
- qcom,ipq5424-snand
|
||||
- const: qcom,ipq9574-snand
|
||||
|
|
|
|||
|
|
@ -41,12 +41,13 @@ properties:
|
|||
- const: usb_en
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
maxItems: 3
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: vaux
|
||||
- const: usb_rst
|
||||
- const: usb_phy
|
||||
|
||||
eswin,hsp-sp-csr:
|
||||
description:
|
||||
|
|
@ -85,8 +86,8 @@ examples:
|
|||
interrupt-parent = <&plic>;
|
||||
interrupts = <85>;
|
||||
interrupt-names = "peripheral";
|
||||
resets = <&reset 84>, <&hspcrg 2>;
|
||||
reset-names = "vaux", "usb_rst";
|
||||
resets = <&reset 84>, <&hspcrg 2>, <&hspcrg 4>;
|
||||
reset-names = "vaux", "usb_rst", "usb_phy";
|
||||
dr_mode = "peripheral";
|
||||
maximum-speed = "high-speed";
|
||||
phy_type = "utmi";
|
||||
|
|
|
|||
|
|
@ -81,9 +81,7 @@ properties:
|
|||
const: usb2-phy
|
||||
|
||||
usb-phy:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: Phandle for the PHY device.
|
||||
deprecated: true
|
||||
maxItems: 1
|
||||
|
||||
ctrl-module:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
|
@ -96,6 +94,9 @@ required:
|
|||
- interrupts
|
||||
- interrupt-names
|
||||
|
||||
allOf:
|
||||
- $ref: usb-hcd.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
|||
|
|
@ -12,6 +12,12 @@ protocol: genetlink
|
|||
doc: Netlink protocol to request a transport layer security handshake.
|
||||
|
||||
definitions:
|
||||
-
|
||||
type: const
|
||||
name: max-errno
|
||||
value: 4095
|
||||
header: linux/err.h
|
||||
scope: kernel
|
||||
-
|
||||
type: enum
|
||||
name: handler-class
|
||||
|
|
@ -80,6 +86,8 @@ attribute-sets:
|
|||
-
|
||||
name: status
|
||||
type: u32
|
||||
checks:
|
||||
max: max-errno
|
||||
-
|
||||
name: sockfd
|
||||
type: s32
|
||||
|
|
|
|||
19
MAINTAINERS
19
MAINTAINERS
|
|
@ -1150,8 +1150,9 @@ F: Documentation/arch/x86/amd-hfi.rst
|
|||
F: drivers/platform/x86/amd/hfi/
|
||||
|
||||
AMD IOMMU (AMD-VI)
|
||||
M: Joerg Roedel <joro@8bytes.org>
|
||||
M: Joerg Roedel (AMD) <joro@8bytes.org>
|
||||
R: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
|
||||
R: Vasant Hegde <vasant.hegde@amd.com>
|
||||
L: iommu@lists.linux.dev
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux.git
|
||||
|
|
@ -10835,7 +10836,7 @@ F: include/linux/generic-radix-tree.h
|
|||
F: lib/generic-radix-tree.c
|
||||
|
||||
GENERIC RESISTIVE TOUCHSCREEN ADC DRIVER
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
L: linux-input@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/input/touchscreen/resistive-adc-touch.c
|
||||
|
|
@ -13483,7 +13484,7 @@ F: include/linux/iommu-dma.h
|
|||
F: include/linux/iova.h
|
||||
|
||||
IOMMU SUBSYSTEM
|
||||
M: Joerg Roedel <joro@8bytes.org>
|
||||
M: Joerg Roedel (AMD) <joro@8bytes.org>
|
||||
M: Will Deacon <will@kernel.org>
|
||||
R: Robin Murphy <robin.murphy@arm.com>
|
||||
L: iommu@lists.linux.dev
|
||||
|
|
@ -16506,7 +16507,7 @@ F: drivers/usb/mtu3/
|
|||
|
||||
MEGACHIPS STDPXXXX-GE-B850V3-FW LVDS/DP++ BRIDGES
|
||||
M: Peter Senna Tschudin <peter.senna@gmail.com>
|
||||
M: Ian Ray <ian.ray@ge.com>
|
||||
M: Ian Ray <ian.ray@gehealthcare.com>
|
||||
M: Martyn Welch <martyn.welch@collabora.co.uk>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt
|
||||
|
|
@ -17345,7 +17346,7 @@ F: Documentation/devicetree/bindings/sound/mikroe,mikroe-proto.txt
|
|||
F: sound/soc/atmel
|
||||
|
||||
MICROCHIP CSI2DC DRIVER
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/media/microchip,csi2dc.yaml
|
||||
|
|
@ -17372,7 +17373,7 @@ F: drivers/i2c/busses/i2c-at91-*.c
|
|||
F: drivers/i2c/busses/i2c-at91.h
|
||||
|
||||
MICROCHIP ISC DRIVER
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/media/atmel,isc.yaml
|
||||
|
|
@ -17384,7 +17385,7 @@ F: drivers/staging/media/deprecated/atmel/atmel-sama*-isc*
|
|||
F: include/linux/atmel-isc-media.h
|
||||
|
||||
MICROCHIP ISI DRIVER
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/media/platform/atmel/atmel-isi.c
|
||||
|
|
@ -17574,7 +17575,7 @@ F: Documentation/devicetree/bindings/display/bridge/microchip,sam9x75-lvds.yaml
|
|||
F: drivers/gpu/drm/bridge/microchip-lvds.c
|
||||
|
||||
MICROCHIP SAMA5D2-COMPATIBLE ADC DRIVER
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
M: Eugen Hristev <ehristev@kernel.org>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml
|
||||
|
|
@ -24124,7 +24125,7 @@ F: drivers/mmc/host/sdhci*
|
|||
|
||||
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER
|
||||
M: Aubin Constans <aubin.constans@microchip.com>
|
||||
R: Eugen Hristev <eugen.hristev@collabora.com>
|
||||
R: Eugen Hristev <ehristev@kernel.org>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/mmc/host/sdhci-of-at91.c
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
VERSION = 7
|
||||
PATCHLEVEL = 1
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc5
|
||||
EXTRAVERSION = -rc6
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
|||
|
|
@ -511,7 +511,6 @@ enum vcpu_sysreg {
|
|||
ACTLR_EL2, /* Auxiliary Control Register (EL2) */
|
||||
CPTR_EL2, /* Architectural Feature Trap Register (EL2) */
|
||||
HACR_EL2, /* Hypervisor Auxiliary Control Register */
|
||||
ZCR_EL2, /* SVE Control Register (EL2) */
|
||||
TTBR0_EL2, /* Translation Table Base Register 0 (EL2) */
|
||||
TTBR1_EL2, /* Translation Table Base Register 1 (EL2) */
|
||||
TCR_EL2, /* Translation Control Register (EL2) */
|
||||
|
|
@ -543,6 +542,7 @@ enum vcpu_sysreg {
|
|||
SCTLR2_EL2, /* System Control Register 2 (EL2) */
|
||||
MDCR_EL2, /* Monitor Debug Configuration Register (EL2) */
|
||||
CNTHCTL_EL2, /* Counter-timer Hypervisor Control register */
|
||||
ZCR_EL2, /* SVE Control Register (EL2) */
|
||||
|
||||
/* Any VNCR-capable reg goes after this point */
|
||||
MARKER(__VNCR_START__),
|
||||
|
|
|
|||
|
|
@ -462,11 +462,13 @@ static inline bool kvm_hyp_handle_mops(struct kvm_vcpu *vcpu, u64 *exit_code)
|
|||
|
||||
static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
|
||||
|
||||
/*
|
||||
* The vCPU's saved SVE state layout always matches the max VL of the
|
||||
* vCPU. Start off with the max VL so we can load the SVE state.
|
||||
*/
|
||||
sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1, SYS_ZCR_EL2);
|
||||
sve_cond_update_zcr_vq(zcr_el2, SYS_ZCR_EL2);
|
||||
__sve_restore_state(vcpu_sve_pffr(vcpu),
|
||||
&vcpu->arch.ctxt.fp_regs.fpsr,
|
||||
true);
|
||||
|
|
@ -476,8 +478,10 @@ static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu)
|
|||
* nested guest, as the guest hypervisor could select a smaller VL. Slap
|
||||
* that into hardware before wrapping up.
|
||||
*/
|
||||
if (is_nested_ctxt(vcpu))
|
||||
sve_cond_update_zcr_vq(__vcpu_sys_reg(vcpu, ZCR_EL2), SYS_ZCR_EL2);
|
||||
if (is_nested_ctxt(vcpu)) {
|
||||
zcr_el2 = min(zcr_el2, __vcpu_sys_reg(vcpu, ZCR_EL2));
|
||||
sve_cond_update_zcr_vq(zcr_el2, SYS_ZCR_EL2);
|
||||
}
|
||||
|
||||
write_sysreg_el1(__vcpu_sys_reg(vcpu, vcpu_sve_zcr_elx(vcpu)), SYS_ZCR);
|
||||
}
|
||||
|
|
@ -501,11 +505,11 @@ static inline void fpsimd_lazy_switch_to_guest(struct kvm_vcpu *vcpu)
|
|||
return;
|
||||
|
||||
if (vcpu_has_sve(vcpu)) {
|
||||
zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
|
||||
|
||||
/* A guest hypervisor may restrict the effective max VL. */
|
||||
if (is_nested_ctxt(vcpu))
|
||||
zcr_el2 = __vcpu_sys_reg(vcpu, ZCR_EL2);
|
||||
else
|
||||
zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
|
||||
zcr_el2 = min(zcr_el2, __vcpu_sys_reg(vcpu, ZCR_EL2));
|
||||
|
||||
write_sysreg_el2(zcr_el2, SYS_ZCR);
|
||||
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ SYM_FUNC_START(__hyp_do_panic)
|
|||
|
||||
mov x29, x0
|
||||
|
||||
#ifdef PKVM_DISABLE_STAGE2_ON_PANIC
|
||||
#ifdef CONFIG_PKVM_DISABLE_STAGE2_ON_PANIC
|
||||
/* Ensure host stage-2 is disabled */
|
||||
mrs x0, hcr_el2
|
||||
bic x0, x0, #HCR_VM
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ static void hyp_trace_buffer_unshare_hyp(struct hyp_trace_buffer *trace_buffer,
|
|||
if (cpu > last_cpu)
|
||||
break;
|
||||
|
||||
__share_page(rb_desc->meta_va);
|
||||
__unshare_page(rb_desc->meta_va);
|
||||
for (p = 0; p < rb_desc->nr_page_va; p++)
|
||||
__unshare_page(rb_desc->page_va[p]);
|
||||
}
|
||||
|
|
@ -212,14 +212,15 @@ static int hyp_trace_buffer_share_hyp(struct hyp_trace_buffer *trace_buffer)
|
|||
}
|
||||
|
||||
if (ret) {
|
||||
for (p--; p >= 0; p--)
|
||||
while (--p >= 0)
|
||||
__unshare_page(rb_desc->page_va[p]);
|
||||
__unshare_page(rb_desc->meta_va);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
hyp_trace_buffer_unshare_hyp(trace_buffer, cpu--);
|
||||
hyp_trace_buffer_unshare_hyp(trace_buffer, --cpu);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -248,6 +249,7 @@ static struct trace_buffer_desc *hyp_trace_load(unsigned long size, void *priv)
|
|||
goto err_free_desc;
|
||||
|
||||
trace_buffer->desc = desc;
|
||||
trace_buffer->desc_size = desc_size;
|
||||
|
||||
ret = hyp_trace_buffer_alloc_bpages_backing(trace_buffer, size);
|
||||
if (ret)
|
||||
|
|
@ -297,6 +299,7 @@ static void hyp_trace_unload(struct trace_buffer_desc *desc, void *priv)
|
|||
hyp_trace_buffer_free_bpages_backing(trace_buffer);
|
||||
free_pages_exact(trace_buffer->desc, trace_buffer->desc_size);
|
||||
trace_buffer->desc = NULL;
|
||||
trace_buffer->desc_size = 0;
|
||||
}
|
||||
|
||||
static int hyp_trace_enable_tracing(bool enable, void *priv)
|
||||
|
|
|
|||
|
|
@ -1834,6 +1834,11 @@ int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu)
|
|||
resx.res1 = VNCR_EL2_RES1;
|
||||
set_sysreg_masks(kvm, VNCR_EL2, resx);
|
||||
|
||||
/* ZCR_EL2 - bits 8:4 are RAZ/WI so treat them as RES0 */
|
||||
resx.res0 = ZCR_ELx_RES0 | GENMASK_ULL(8, 4);
|
||||
resx.res1 = ZCR_ELx_RES1;
|
||||
set_sysreg_masks(kvm, ZCR_EL2, resx);
|
||||
|
||||
out:
|
||||
for (enum vcpu_sysreg sr = __SANITISED_REG_START__; sr < NR_SYS_REGS; sr++)
|
||||
__vcpu_rmw_sys_reg(vcpu, sr, |=, 0);
|
||||
|
|
|
|||
|
|
@ -174,8 +174,8 @@ static void kvm_pmu_set_pmc_value(struct kvm_pmc *pmc, u64 val, bool force)
|
|||
* action is to use PMCR.P, which will reset them to
|
||||
* 0 (the only use of the 'force' parameter).
|
||||
*/
|
||||
val = __vcpu_sys_reg(vcpu, reg) & GENMASK(63, 32);
|
||||
val |= lower_32_bits(val);
|
||||
val = (__vcpu_sys_reg(vcpu, reg) & GENMASK(63, 32)) |
|
||||
lower_32_bits(val);
|
||||
}
|
||||
|
||||
__vcpu_assign_sys_reg(vcpu, reg, val);
|
||||
|
|
|
|||
|
|
@ -2862,21 +2862,16 @@ static bool access_zcr_el2(struct kvm_vcpu *vcpu,
|
|||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
unsigned int vq;
|
||||
|
||||
if (guest_hyp_sve_traps_enabled(vcpu)) {
|
||||
kvm_inject_nested_sve_trap(vcpu);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!p->is_write) {
|
||||
if (!p->is_write)
|
||||
p->regval = __vcpu_sys_reg(vcpu, ZCR_EL2);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
__vcpu_assign_sys_reg(vcpu, ZCR_EL2, p->regval);
|
||||
|
||||
vq = SYS_FIELD_GET(ZCR_ELx, LEN, p->regval) + 1;
|
||||
vq = min(vq, vcpu_sve_max_vq(vcpu));
|
||||
__vcpu_assign_sys_reg(vcpu, ZCR_EL2, vq - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,14 @@
|
|||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
|
||||
#include <asm/dec/interrupts.h>
|
||||
#include <asm/dec/ioasic_addrs.h>
|
||||
#include <asm/dec/kn01.h>
|
||||
#include <asm/dec/kn02.h>
|
||||
#include <asm/dec/system.h>
|
||||
|
||||
static struct resource dec_rtc_resources[] = {
|
||||
{
|
||||
.name = "rtc",
|
||||
|
|
@ -30,11 +38,110 @@ static struct platform_device dec_rtc_device = {
|
|||
.num_resources = ARRAY_SIZE(dec_rtc_resources),
|
||||
};
|
||||
|
||||
static struct resource dec_dz_resources[] = {
|
||||
{ .name = "dz", .flags = IORESOURCE_MEM, },
|
||||
{ .name = "dz", .flags = IORESOURCE_IRQ, },
|
||||
};
|
||||
|
||||
static struct platform_device dec_dz_device = {
|
||||
.name = "dz",
|
||||
.id = PLATFORM_DEVID_NONE,
|
||||
.resource = dec_dz_resources,
|
||||
.num_resources = ARRAY_SIZE(dec_dz_resources),
|
||||
};
|
||||
|
||||
static struct platform_device *dec_dz_devices[] __initdata = {
|
||||
&dec_dz_device,
|
||||
};
|
||||
|
||||
static struct resource dec_zs_resources[][2] = {
|
||||
{
|
||||
{ .name = "scc0", .flags = IORESOURCE_MEM, },
|
||||
{ .name = "scc0", .flags = IORESOURCE_IRQ, },
|
||||
},
|
||||
{
|
||||
{ .name = "scc1", .flags = IORESOURCE_MEM, },
|
||||
{ .name = "scc1", .flags = IORESOURCE_IRQ, },
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device dec_zs_device[] = {
|
||||
{
|
||||
.name = "zs",
|
||||
.id = 0,
|
||||
.resource = dec_zs_resources[0],
|
||||
.num_resources = ARRAY_SIZE(dec_zs_resources[0]),
|
||||
},
|
||||
{
|
||||
.name = "zs",
|
||||
.id = 1,
|
||||
.resource = dec_zs_resources[1],
|
||||
.num_resources = ARRAY_SIZE(dec_zs_resources[1]),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init dec_add_devices(void)
|
||||
{
|
||||
struct platform_device *dec_zs_devices[ARRAY_SIZE(dec_zs_device)];
|
||||
int ret1, ret2, ret3;
|
||||
int num_dz, num_zs;
|
||||
int irq, i;
|
||||
|
||||
dec_rtc_resources[0].start = RTC_PORT(0);
|
||||
dec_rtc_resources[0].end = RTC_PORT(0) + dec_kn_slot_size - 1;
|
||||
return platform_device_register(&dec_rtc_device);
|
||||
|
||||
i = 0;
|
||||
irq = dec_interrupt[DEC_IRQ_DZ11];
|
||||
if (IS_ENABLED(CONFIG_32BIT) && irq >= 0) {
|
||||
resource_size_t base;
|
||||
|
||||
switch (mips_machtype) {
|
||||
case MACH_DS23100:
|
||||
case MACH_DS5100:
|
||||
base = dec_kn_slot_base + KN01_DZ11;
|
||||
break;
|
||||
default:
|
||||
base = dec_kn_slot_base + KN02_DZ11;
|
||||
break;
|
||||
}
|
||||
dec_dz_device.resource[0].start = base;
|
||||
dec_dz_device.resource[0].end = base + dec_kn_slot_size - 1;
|
||||
dec_dz_device.resource[1].start = irq;
|
||||
dec_dz_device.resource[1].end = irq;
|
||||
i++;
|
||||
}
|
||||
num_dz = i;
|
||||
|
||||
i = 0;
|
||||
irq = dec_interrupt[DEC_IRQ_SCC0];
|
||||
if (irq >= 0) {
|
||||
resource_size_t base = dec_kn_slot_base + IOASIC_SCC0;
|
||||
|
||||
dec_zs_device[i].resource[0].start = base;
|
||||
dec_zs_device[i].resource[0].end = base + dec_kn_slot_size - 1;
|
||||
dec_zs_device[i].resource[1].start = irq;
|
||||
dec_zs_device[i].resource[1].end = irq;
|
||||
dec_zs_devices[i] = &dec_zs_device[i];
|
||||
i++;
|
||||
}
|
||||
irq = dec_interrupt[DEC_IRQ_SCC1];
|
||||
if (irq >= 0) {
|
||||
resource_size_t base = dec_kn_slot_base + IOASIC_SCC1;
|
||||
|
||||
dec_zs_device[i].resource[0].start = base;
|
||||
dec_zs_device[i].resource[0].end = base + dec_kn_slot_size - 1;
|
||||
dec_zs_device[i].resource[1].start = irq;
|
||||
dec_zs_device[i].resource[1].end = irq;
|
||||
dec_zs_devices[i] = &dec_zs_device[i];
|
||||
i++;
|
||||
}
|
||||
num_zs = i;
|
||||
|
||||
ret1 = platform_device_register(&dec_rtc_device);
|
||||
ret2 = IS_ENABLED(CONFIG_32BIT) ?
|
||||
platform_add_devices(dec_dz_devices, num_dz) : 0;
|
||||
ret3 = platform_add_devices(dec_zs_devices, num_zs);
|
||||
return ret1 ? ret1 : ret2 ? ret2 : ret3;
|
||||
}
|
||||
|
||||
device_initcall(dec_add_devices);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ asmlinkage long __riscv_sys_ni_syscall(const struct pt_regs *);
|
|||
__diag_push(); \
|
||||
__diag_ignore(GCC, 8, "-Wattribute-alias", \
|
||||
"Type aliasing is used to sanitize syscall arguments"); \
|
||||
__diag_ignore(clang, 23, "-Wunknown-warning-option", \
|
||||
"Avoid breaking versions without -Wattribute-alias"); \
|
||||
__diag_ignore(clang, 23, "-Wattribute-alias", \
|
||||
"Type aliasing is used to sanitize syscall arguments"); \
|
||||
static long __se_##prefix##name(ulong, ulong, ulong, ulong, ulong, ulong, \
|
||||
ulong) \
|
||||
__attribute__((alias(__stringify(___se_##prefix##name)))); \
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ noinstr void x86_entry_from_kvm(unsigned int event_type, unsigned int vector)
|
|||
* The FRED NMI context is significantly different and will not work
|
||||
* right (specifically FRED fixed the NMI recursion issue).
|
||||
*/
|
||||
idt_entry_from_kvm(vector);
|
||||
idt_do_nmi_irqoff();
|
||||
}
|
||||
EXPORT_SYMBOL_FOR_KVM(x86_entry_from_kvm);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -109,11 +109,13 @@ EXPORT_SYMBOL(__ref_stack_chk_guard);
|
|||
RET
|
||||
.endm
|
||||
|
||||
#ifndef CONFIG_X86_64
|
||||
.pushsection .text, "ax"
|
||||
SYM_FUNC_START(idt_do_interrupt_irqoff)
|
||||
IDT_DO_EVENT_IRQOFF CALL_NOSPEC _ASM_ARG1
|
||||
SYM_FUNC_END(idt_do_interrupt_irqoff)
|
||||
.popsection
|
||||
#endif
|
||||
|
||||
.pushsection .noinstr.text, "ax"
|
||||
SYM_FUNC_START(idt_do_nmi_irqoff)
|
||||
|
|
|
|||
|
|
@ -1504,6 +1504,7 @@ struct kvm_arch {
|
|||
bool use_master_clock;
|
||||
u64 master_kernel_ns;
|
||||
u64 master_cycle_now;
|
||||
struct ratelimit_state kvmclock_update_rs;
|
||||
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
struct kvm_hv hyperv;
|
||||
|
|
|
|||
|
|
@ -733,6 +733,7 @@ bool xen_set_default_idle(void);
|
|||
#endif
|
||||
|
||||
void __noreturn stop_this_cpu(void *dummy);
|
||||
extern bool x86_hypervisor_present;
|
||||
void microcode_check(struct cpuinfo_x86 *prev_info);
|
||||
void store_cpu_caps(struct cpuinfo_x86 *info);
|
||||
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ static u32 get_patch_level(void)
|
|||
{
|
||||
u32 rev, dummy __always_unused;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MICROCODE_DBG) && hypervisor_present) {
|
||||
if (IS_ENABLED(CONFIG_MICROCODE_DBG) && x86_hypervisor_present) {
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
if (!microcode_rev[cpu]) {
|
||||
|
|
@ -714,7 +714,7 @@ static bool __apply_microcode_amd(struct microcode_amd *mc, u32 *cur_rev,
|
|||
invlpg(p_addr_end);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_MICROCODE_DBG) && hypervisor_present)
|
||||
if (IS_ENABLED(CONFIG_MICROCODE_DBG) && x86_hypervisor_present)
|
||||
microcode_rev[smp_processor_id()] = mc->hdr.patch_id;
|
||||
|
||||
/* verify patch application was successful */
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV);
|
|||
u32 base_rev;
|
||||
u32 microcode_rev[NR_CPUS] = {};
|
||||
|
||||
bool hypervisor_present;
|
||||
bool __ro_after_init x86_hypervisor_present;
|
||||
|
||||
/*
|
||||
* Synchronization.
|
||||
|
|
@ -118,14 +118,9 @@ bool __init microcode_loader_disabled(void)
|
|||
/*
|
||||
* Disable when:
|
||||
*
|
||||
* 1) The CPU does not support CPUID.
|
||||
*/
|
||||
if (!cpuid_feature()) {
|
||||
dis_ucode_ldr = true;
|
||||
return dis_ucode_ldr;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1) The CPU does not support CPUID, detected below in
|
||||
* load_ucode_bsp().
|
||||
*
|
||||
* 2) Bit 31 in CPUID[1]:ECX is clear
|
||||
* The bit is reserved for hypervisor use. This is still not
|
||||
* completely accurate as XEN PV guests don't see that CPUID bit
|
||||
|
|
@ -135,9 +130,7 @@ bool __init microcode_loader_disabled(void)
|
|||
* 3) Certain AMD patch levels are not allowed to be
|
||||
* overwritten.
|
||||
*/
|
||||
hypervisor_present = native_cpuid_ecx(1) & BIT(31);
|
||||
|
||||
if ((hypervisor_present && !IS_ENABLED(CONFIG_MICROCODE_DBG)) ||
|
||||
if ((x86_hypervisor_present && !IS_ENABLED(CONFIG_MICROCODE_DBG)) ||
|
||||
amd_check_current_patch_level())
|
||||
dis_ucode_ldr = true;
|
||||
|
||||
|
|
@ -179,6 +172,11 @@ void __init load_ucode_bsp(void)
|
|||
|
||||
early_parse_cmdline();
|
||||
|
||||
if (!cpuid_feature())
|
||||
dis_ucode_ldr = true;
|
||||
else
|
||||
x86_hypervisor_present = native_cpuid_ecx(1) & BIT(31);
|
||||
|
||||
if (microcode_loader_disabled())
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,9 @@ u32 intel_get_platform_id(void)
|
|||
{
|
||||
unsigned int val[2];
|
||||
|
||||
if (x86_hypervisor_present)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* This can be called early. Use CPUID directly instead of
|
||||
* relying on cpuinfo_x86 which may not be fully initialized.
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ extern struct early_load_data early_data;
|
|||
extern struct ucode_cpu_info ucode_cpu_info[];
|
||||
extern u32 microcode_rev[NR_CPUS];
|
||||
extern u32 base_rev;
|
||||
extern bool hypervisor_present;
|
||||
|
||||
struct cpio_data find_microcode_in_initrd(const char *path);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,14 +27,19 @@
|
|||
static inline bool check_xstate_in_sigframe(struct fxregs_state __user *fxbuf,
|
||||
struct _fpx_sw_bytes *fx_sw)
|
||||
{
|
||||
int min_xstate_size = sizeof(struct fxregs_state) +
|
||||
sizeof(struct xstate_header);
|
||||
void __user *fpstate = fxbuf;
|
||||
unsigned int magic2;
|
||||
|
||||
if (__copy_from_user(fx_sw, &fxbuf->sw_reserved[0], sizeof(*fx_sw)))
|
||||
return false;
|
||||
|
||||
/* Check for the first magic field */
|
||||
if (fx_sw->magic1 != FP_XSTATE_MAGIC1)
|
||||
/* Check for the first magic field and other error scenarios. */
|
||||
if (fx_sw->magic1 != FP_XSTATE_MAGIC1 ||
|
||||
fx_sw->xstate_size < min_xstate_size ||
|
||||
fx_sw->xstate_size > x86_task_fpu(current)->fpstate->user_size ||
|
||||
fx_sw->xstate_size > fx_sw->extended_size)
|
||||
goto setfx;
|
||||
|
||||
/*
|
||||
|
|
@ -43,7 +48,7 @@ static inline bool check_xstate_in_sigframe(struct fxregs_state __user *fxbuf,
|
|||
* fpstate layout with out copying the extended state information
|
||||
* in the memory layout.
|
||||
*/
|
||||
if (__get_user(magic2, (__u32 __user *)(fpstate + x86_task_fpu(current)->fpstate->user_size)))
|
||||
if (__get_user(magic2, (__u32 __user *)(fpstate + fx_sw->xstate_size)))
|
||||
return false;
|
||||
|
||||
if (likely(magic2 == FP_XSTATE_MAGIC2))
|
||||
|
|
|
|||
|
|
@ -375,6 +375,13 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generated trampoline may contain rIP-relative addressing which
|
||||
* displacement needs to be fixed.
|
||||
*/
|
||||
text_poke_apply_relocation(trampoline, trampoline, size,
|
||||
(void *)start_offset, size);
|
||||
|
||||
/*
|
||||
* The address of the ftrace_ops that is used for this trampoline
|
||||
* is stored at the end of the trampoline. This will be used to
|
||||
|
|
|
|||
|
|
@ -268,18 +268,10 @@ void __init idt_setup_early_pf(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_KVM_INTEL)
|
||||
noinstr void idt_entry_from_kvm(unsigned int vector)
|
||||
#if IS_ENABLED(CONFIG_KVM_INTEL) && !defined(CONFIG_X86_64)
|
||||
void idt_entry_from_kvm(unsigned int vector)
|
||||
{
|
||||
if (vector == NMI_VECTOR)
|
||||
return idt_do_nmi_irqoff();
|
||||
|
||||
/*
|
||||
* Only the NMI path requires noinstr.
|
||||
*/
|
||||
instrumentation_begin();
|
||||
idt_do_interrupt_irqoff(gate_offset(idt_table + vector));
|
||||
instrumentation_end();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -206,6 +206,35 @@ static void avic_activate_vmcb(struct vcpu_svm *svm)
|
|||
|
||||
svm_clr_intercept(svm, INTERCEPT_CR8_WRITE);
|
||||
|
||||
/*
|
||||
* Flush the TLB when enabling (x2)AVIC and when transitioning between
|
||||
* xAVIC and x2AVIC, as the CPU may have inserted a TLB entry for the
|
||||
* "wrong" mapping.
|
||||
*
|
||||
* KVM uses a per-VM "scratch" page to back the APIC memslot, because
|
||||
* KVM also uses per-VM page tables *and* maintains the page table (NPT
|
||||
* or shadow page) mappings for said memslot even if one or more vCPUs
|
||||
* have their local APIC hardware-disabled or are in x2APIC mode, i.e.
|
||||
* even if one or more vCPUs' APIC MMIO BAR is effectively disabled.
|
||||
*
|
||||
* If xAVIC is fully enabled, hardware ignores the physical address in
|
||||
* KVM's page tables, i.e. in the leaf SPTE for the APIC memslot, and
|
||||
* instead redirects the access to the AVIC backing page, i.e. to the
|
||||
* vCPU's virtual APIC page. If xAVIC is not enabled (APIC is either
|
||||
* hardware-disabled or in x2APIC mode), then guest accesses will use
|
||||
* the page table mapping verbatim, i.e. will access the per-VM scratch
|
||||
* page, as normal memory.
|
||||
*
|
||||
* In both cases, the CPU is allowed to cache TLB entries for the APIC
|
||||
* base GPA. So, KVM needs to flush the TLB when enabling xAVIC, as
|
||||
* accesses need to be redirected to the virtual APIC page, but the TLB
|
||||
* may contain entries pointing at the scratch page. KVM also needs to
|
||||
* flush the TLB when enabling x2AVIC, as accesses need to go to the
|
||||
* scratch page, but the TLB may contain entries tagged as xAVIC, i.e.
|
||||
* entries pointing to the vCPU's virtual APIC page.
|
||||
*/
|
||||
kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, &svm->vcpu);
|
||||
|
||||
/*
|
||||
* Note: KVM supports hybrid-AVIC mode, where KVM emulates x2APIC MSR
|
||||
* accesses, while interrupt injection to a running vCPU can be
|
||||
|
|
@ -219,12 +248,6 @@ static void avic_activate_vmcb(struct vcpu_svm *svm)
|
|||
/* Disabling MSR intercept for x2APIC registers */
|
||||
avic_set_x2apic_msr_interception(svm, false);
|
||||
} else {
|
||||
/*
|
||||
* Flush the TLB, the guest may have inserted a non-APIC
|
||||
* mapping into the TLB while AVIC was disabled.
|
||||
*/
|
||||
kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, &svm->vcpu);
|
||||
|
||||
/* Enabling MSR intercept for x2APIC registers */
|
||||
avic_set_x2apic_msr_interception(svm, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3662,23 +3662,26 @@ int pre_sev_run(struct vcpu_svm *svm, int cpu)
|
|||
}
|
||||
|
||||
#define GHCB_SCRATCH_AREA_LIMIT (16ULL * PAGE_SIZE)
|
||||
static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
|
||||
static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 min_len)
|
||||
{
|
||||
struct vmcb_control_area *control = &svm->vmcb->control;
|
||||
u64 ghcb_scratch_beg, ghcb_scratch_end;
|
||||
u64 scratch_gpa_beg, scratch_gpa_end;
|
||||
void *scratch_va;
|
||||
|
||||
if (WARN_ON_ONCE(!min_len))
|
||||
goto e_scratch;
|
||||
|
||||
scratch_gpa_beg = svm->sev_es.sw_scratch;
|
||||
if (!scratch_gpa_beg) {
|
||||
pr_err("vmgexit: scratch gpa not provided\n");
|
||||
goto e_scratch;
|
||||
}
|
||||
|
||||
scratch_gpa_end = scratch_gpa_beg + len;
|
||||
scratch_gpa_end = scratch_gpa_beg + min_len;
|
||||
if (scratch_gpa_end < scratch_gpa_beg) {
|
||||
pr_err("vmgexit: scratch length (%#llx) not valid for scratch address (%#llx)\n",
|
||||
len, scratch_gpa_beg);
|
||||
min_len, scratch_gpa_beg);
|
||||
goto e_scratch;
|
||||
}
|
||||
|
||||
|
|
@ -3702,21 +3705,27 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
|
|||
|
||||
scratch_va = (void *)svm->sev_es.ghcb;
|
||||
scratch_va += (scratch_gpa_beg - control->ghcb_gpa);
|
||||
|
||||
svm->sev_es.ghcb_sa_len = ghcb_scratch_end - scratch_gpa_beg;
|
||||
} else {
|
||||
/* GHCB v2 requires the scratch area to be within the GHCB. */
|
||||
if (to_kvm_sev_info(svm->vcpu.kvm)->ghcb_version >= 2)
|
||||
goto e_scratch;
|
||||
|
||||
/*
|
||||
* The guest memory must be read into a kernel buffer, so
|
||||
* limit the size
|
||||
*/
|
||||
if (len > GHCB_SCRATCH_AREA_LIMIT) {
|
||||
if (min_len > GHCB_SCRATCH_AREA_LIMIT) {
|
||||
pr_err("vmgexit: scratch area exceeds KVM limits (%#llx requested, %#llx limit)\n",
|
||||
len, GHCB_SCRATCH_AREA_LIMIT);
|
||||
min_len, GHCB_SCRATCH_AREA_LIMIT);
|
||||
goto e_scratch;
|
||||
}
|
||||
scratch_va = kvzalloc(len, GFP_KERNEL_ACCOUNT);
|
||||
scratch_va = kvzalloc(min_len, GFP_KERNEL_ACCOUNT);
|
||||
if (!scratch_va)
|
||||
return -ENOMEM;
|
||||
|
||||
if (kvm_read_guest(svm->vcpu.kvm, scratch_gpa_beg, scratch_va, len)) {
|
||||
if (kvm_read_guest(svm->vcpu.kvm, scratch_gpa_beg, scratch_va, min_len)) {
|
||||
/* Unable to copy scratch area from guest */
|
||||
pr_err("vmgexit: kvm_read_guest for scratch area failed\n");
|
||||
|
||||
|
|
@ -3732,11 +3741,10 @@ static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
|
|||
*/
|
||||
svm->sev_es.ghcb_sa_sync = sync;
|
||||
svm->sev_es.ghcb_sa_free = true;
|
||||
svm->sev_es.ghcb_sa_len = min_len;
|
||||
}
|
||||
|
||||
svm->sev_es.ghcb_sa = scratch_va;
|
||||
svm->sev_es.ghcb_sa_len = len;
|
||||
|
||||
return 0;
|
||||
|
||||
e_scratch:
|
||||
|
|
@ -3833,7 +3841,7 @@ struct psc_buffer {
|
|||
struct psc_entry entries[];
|
||||
} __packed;
|
||||
|
||||
static int snp_begin_psc(struct vcpu_svm *svm, struct psc_buffer *psc);
|
||||
static int snp_begin_psc(struct vcpu_svm *svm);
|
||||
|
||||
static void snp_complete_psc(struct vcpu_svm *svm, u64 psc_ret)
|
||||
{
|
||||
|
|
@ -3864,9 +3872,9 @@ static void __snp_complete_one_psc(struct vcpu_svm *svm)
|
|||
*/
|
||||
for (idx = svm->sev_es.psc_idx; svm->sev_es.psc_inflight;
|
||||
svm->sev_es.psc_inflight--, idx++) {
|
||||
struct psc_entry *entry = &entries[idx];
|
||||
struct psc_entry entry = READ_ONCE(entries[idx]);
|
||||
|
||||
entry->cur_page = entry->pagesize ? 512 : 1;
|
||||
entries[idx].cur_page = entry.pagesize ? 512 : 1;
|
||||
}
|
||||
|
||||
hdr->cur_entry = idx;
|
||||
|
|
@ -3875,7 +3883,6 @@ static void __snp_complete_one_psc(struct vcpu_svm *svm)
|
|||
static int snp_complete_one_psc(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
struct psc_buffer *psc = svm->sev_es.ghcb_sa;
|
||||
|
||||
if (vcpu->run->hypercall.ret) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC);
|
||||
|
|
@ -3885,16 +3892,18 @@ static int snp_complete_one_psc(struct kvm_vcpu *vcpu)
|
|||
__snp_complete_one_psc(svm);
|
||||
|
||||
/* Handle the next range (if any). */
|
||||
return snp_begin_psc(svm, psc);
|
||||
return snp_begin_psc(svm);
|
||||
}
|
||||
|
||||
static int snp_begin_psc(struct vcpu_svm *svm, struct psc_buffer *psc)
|
||||
static int snp_begin_psc(struct vcpu_svm *svm)
|
||||
{
|
||||
struct vcpu_sev_es_state *sev_es = &svm->sev_es;
|
||||
struct psc_buffer *psc = sev_es->ghcb_sa;
|
||||
struct psc_entry *entries = psc->entries;
|
||||
struct kvm_vcpu *vcpu = &svm->vcpu;
|
||||
struct psc_hdr *hdr = &psc->hdr;
|
||||
struct psc_entry entry_start;
|
||||
u16 idx, idx_start, idx_end;
|
||||
u16 idx, idx_start, idx_end, max_nr_entries;
|
||||
int npages;
|
||||
bool huge;
|
||||
u64 gfn;
|
||||
|
|
@ -3904,6 +3913,19 @@ static int snp_begin_psc(struct vcpu_svm *svm, struct psc_buffer *psc)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* GHCB v2 requires the scratch area to reside within the GHCB itself,
|
||||
* and PSC requests are only supported for GHCB v2+. Thus it should be
|
||||
* impossible to exceed the max PSC entry count (which is derived from
|
||||
* the size of the shared GHCB buffer).
|
||||
*/
|
||||
max_nr_entries = (sev_es->ghcb_sa_len - sizeof(struct psc_hdr)) /
|
||||
sizeof(struct psc_entry);
|
||||
if (WARN_ON_ONCE(max_nr_entries > VMGEXIT_PSC_MAX_COUNT)) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC);
|
||||
return 1;
|
||||
}
|
||||
|
||||
next_range:
|
||||
/* There should be no other PSCs in-flight at this point. */
|
||||
if (WARN_ON_ONCE(svm->sev_es.psc_inflight)) {
|
||||
|
|
@ -3916,17 +3938,17 @@ static int snp_begin_psc(struct vcpu_svm *svm, struct psc_buffer *psc)
|
|||
* validation, so take care to only use validated copies of values used
|
||||
* for things like array indexing.
|
||||
*/
|
||||
idx_start = hdr->cur_entry;
|
||||
idx_end = hdr->end_entry;
|
||||
idx_start = READ_ONCE(hdr->cur_entry);
|
||||
idx_end = READ_ONCE(hdr->end_entry);
|
||||
|
||||
if (idx_end >= VMGEXIT_PSC_MAX_COUNT) {
|
||||
if (idx_end >= max_nr_entries) {
|
||||
snp_complete_psc(svm, VMGEXIT_PSC_ERROR_INVALID_HDR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Find the start of the next range which needs processing. */
|
||||
for (idx = idx_start; idx <= idx_end; idx++, hdr->cur_entry++) {
|
||||
entry_start = entries[idx];
|
||||
entry_start = READ_ONCE(entries[idx]);
|
||||
|
||||
gfn = entry_start.gfn;
|
||||
huge = entry_start.pagesize;
|
||||
|
|
@ -3970,7 +3992,7 @@ static int snp_begin_psc(struct vcpu_svm *svm, struct psc_buffer *psc)
|
|||
* KVM_HC_MAP_GPA_RANGE exit.
|
||||
*/
|
||||
while (++idx <= idx_end) {
|
||||
struct psc_entry entry = entries[idx];
|
||||
struct psc_entry entry = READ_ONCE(entries[idx]);
|
||||
|
||||
if (entry.operation != entry_start.operation ||
|
||||
entry.gfn != entry_start.gfn + npages ||
|
||||
|
|
@ -4493,13 +4515,22 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
|
|||
case SVM_VMGEXIT_MMIO_READ:
|
||||
case SVM_VMGEXIT_MMIO_WRITE: {
|
||||
bool is_write = control->exit_code == SVM_VMGEXIT_MMIO_WRITE;
|
||||
u64 len = control->exit_info_2;
|
||||
|
||||
ret = setup_vmgexit_scratch(svm, !is_write, control->exit_info_2);
|
||||
if (!len)
|
||||
return 1;
|
||||
|
||||
if (to_kvm_sev_info(vcpu->kvm)->ghcb_version >= 2 && len > 8) {
|
||||
svm_vmgexit_bad_input(svm, GHCB_ERR_INVALID_INPUT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = setup_vmgexit_scratch(svm, !is_write, len);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
ret = kvm_sev_es_mmio(vcpu, is_write, control->exit_info_1,
|
||||
control->exit_info_2, svm->sev_es.ghcb_sa);
|
||||
ret = kvm_sev_es_mmio(vcpu, is_write, control->exit_info_1, len,
|
||||
svm->sev_es.ghcb_sa);
|
||||
break;
|
||||
}
|
||||
case SVM_VMGEXIT_NMI_COMPLETE:
|
||||
|
|
@ -4546,11 +4577,11 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
|
|||
vcpu->run->system_event.data[0] = control->ghcb_gpa;
|
||||
break;
|
||||
case SVM_VMGEXIT_PSC:
|
||||
ret = setup_vmgexit_scratch(svm, true, control->exit_info_2);
|
||||
ret = setup_vmgexit_scratch(svm, true, sizeof(struct psc_hdr));
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
ret = snp_begin_psc(svm, svm->sev_es.ghcb_sa);
|
||||
ret = snp_begin_psc(svm);
|
||||
break;
|
||||
case SVM_VMGEXIT_AP_CREATION:
|
||||
ret = sev_snp_ap_creation(svm);
|
||||
|
|
@ -4572,6 +4603,11 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
|
|||
control->exit_info_1, control->exit_info_2);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case SVM_EXIT_IOIO:
|
||||
if (!((control->exit_info_1 & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT))
|
||||
return 1;
|
||||
|
||||
fallthrough;
|
||||
default:
|
||||
ret = svm_invoke_exit_handler(vcpu, control->exit_code);
|
||||
}
|
||||
|
|
@ -4592,6 +4628,9 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in)
|
|||
if (unlikely(check_mul_overflow(count, size, &bytes)))
|
||||
return -EINVAL;
|
||||
|
||||
if (!bytes)
|
||||
return 1;
|
||||
|
||||
r = setup_vmgexit_scratch(svm, in, bytes);
|
||||
if (r)
|
||||
return r;
|
||||
|
|
|
|||
|
|
@ -5227,8 +5227,13 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
|||
* On a host with synchronized TSC, there is no need to update
|
||||
* kvmclock on vcpu->cpu migration
|
||||
*/
|
||||
if (!vcpu->kvm->arch.use_master_clock || vcpu->cpu == -1)
|
||||
kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);
|
||||
if (!vcpu->kvm->arch.use_master_clock || vcpu->cpu == -1) {
|
||||
if (__ratelimit(&vcpu->kvm->arch.kvmclock_update_rs))
|
||||
kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);
|
||||
else
|
||||
kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
|
||||
}
|
||||
|
||||
if (vcpu->cpu != cpu)
|
||||
kvm_make_request(KVM_REQ_MIGRATE_TIMER, vcpu);
|
||||
vcpu->cpu = cpu;
|
||||
|
|
@ -13366,6 +13371,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
|||
raw_spin_lock_init(&kvm->arch.tsc_write_lock);
|
||||
mutex_init(&kvm->arch.apic_map_lock);
|
||||
seqcount_raw_spinlock_init(&kvm->arch.pvclock_sc, &kvm->arch.tsc_write_lock);
|
||||
ratelimit_state_init(&kvm->arch.kvmclock_update_rs, HZ, 10);
|
||||
ratelimit_set_flags(&kvm->arch.kvmclock_update_rs, RATELIMIT_MSG_ON_RELEASE);
|
||||
kvm->arch.kvmclock_offset = -get_kvmclock_base_ns();
|
||||
|
||||
raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
|
||||
|
|
@ -14323,7 +14330,7 @@ int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva)
|
|||
* the RAP (Return Address Predicator).
|
||||
*/
|
||||
if (guest_cpu_cap_has(vcpu, X86_FEATURE_ERAPS))
|
||||
kvm_register_is_dirty(vcpu, VCPU_EXREG_ERAPS);
|
||||
kvm_register_mark_dirty(vcpu, VCPU_EXREG_ERAPS);
|
||||
|
||||
kvm_invalidate_pcid(vcpu, operand.pcid);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,20 @@ static void x86_virt_invoke_kvm_emergency_callback(void)
|
|||
{
|
||||
cpu_emergency_virt_cb *kvm_callback;
|
||||
|
||||
kvm_callback = rcu_dereference(kvm_emergency_callback);
|
||||
/*
|
||||
* RCU may not be watching the crashing CPU here, so rcu_dereference()
|
||||
* triggers a suspicious-RCU-usage splat. In principle, a concurrent
|
||||
* KVM module unload could race with this read; see commit 2baa33a8ddd6
|
||||
* ("KVM: x86: Leave user-return notifier registered on reboot/shutdown")
|
||||
* which notes that nothing prevents module unload during panic/reboot.
|
||||
*
|
||||
* However, taking a lock here would be riskier than the current race:
|
||||
* the system is going down via NMI shootdown, and any lock could be
|
||||
* held by an already-stopped CPU. Use rcu_dereference_raw() to silence
|
||||
* the lockdep splat and accept the comically small remaining race;
|
||||
* panic context inherently cannot guarantee complete correctness.
|
||||
*/
|
||||
kvm_callback = rcu_dereference_raw(kvm_emergency_callback);
|
||||
if (kvm_callback)
|
||||
kvm_callback();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3246,7 +3246,7 @@ void blk_mq_submit_bio(struct bio *bio)
|
|||
if (!rq)
|
||||
blk_queue_exit(q);
|
||||
else
|
||||
blk_mq_free_request(rq);
|
||||
rq_list_add_head(&plug->cached_rqs, rq);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_MQ_STACKING
|
||||
|
|
|
|||
|
|
@ -511,6 +511,11 @@ static int aie2_init(struct amdxdna_dev *xdna)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!xdna->group) {
|
||||
XDNA_ERR(xdna, "Running without IOMMU not supported");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ndev = drmm_kzalloc(&xdna->ddev, sizeof(*ndev), GFP_KERNEL);
|
||||
if (!ndev)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -450,7 +450,7 @@ priority_bands_fops_write(struct file *file, const char __user *user_buf, size_t
|
|||
u32 band;
|
||||
int ret;
|
||||
|
||||
if (size >= sizeof(buf))
|
||||
if (*pos != 0 || size >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
||||
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, pos, user_buf, size);
|
||||
|
|
|
|||
|
|
@ -79,11 +79,6 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file *
|
|||
rkt_obj->size = args->size;
|
||||
rkt_obj->offset = 0;
|
||||
|
||||
ret = drm_gem_handle_create(file, gem_obj, &args->handle);
|
||||
drm_gem_object_put(gem_obj);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
sgt = drm_gem_shmem_get_pages_sgt(shmem_obj);
|
||||
if (IS_ERR(sgt)) {
|
||||
ret = PTR_ERR(sgt);
|
||||
|
|
@ -95,6 +90,8 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file *
|
|||
rkt_obj->size, PAGE_SIZE,
|
||||
0, 0);
|
||||
mutex_unlock(&rocket_priv->mm_lock);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = iommu_map_sgtable(rocket_priv->domain->domain,
|
||||
rkt_obj->mm.start,
|
||||
|
|
@ -112,8 +109,18 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file *
|
|||
args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
|
||||
args->dma_address = rkt_obj->mm.start;
|
||||
|
||||
ret = drm_gem_handle_create(file, gem_obj, &args->handle);
|
||||
if (ret)
|
||||
goto err_unmap;
|
||||
|
||||
drm_gem_object_put(gem_obj);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unmap:
|
||||
iommu_unmap(rocket_priv->domain->domain,
|
||||
rkt_obj->mm.start, rkt_obj->size);
|
||||
|
||||
err_remove_node:
|
||||
mutex_lock(&rocket_priv->mm_lock);
|
||||
drm_mm_remove_node(&rkt_obj->mm);
|
||||
|
|
|
|||
|
|
@ -78,18 +78,22 @@ ACPI_EXPORT_SYMBOL(acpi_update_all_gpes)
|
|||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_enable_gpe
|
||||
* FUNCTION: acpi_enable_gpe_cond
|
||||
*
|
||||
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
|
||||
* gpe_number - GPE level within the GPE block
|
||||
* dispatch_type - GPE dispatch type to match
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
|
||||
* hardware-enabled.
|
||||
* DESCRIPTION: Add a reference to a GPE so long as its dispatch type matches
|
||||
* the supplied one, or it is different from ACPI_GPE_DISPATCH_NONE
|
||||
* if the supplied one is ACPI_GPE_DISPATCH_MASK. On the first
|
||||
* reference, the GPE is hardware-enabled.
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
|
||||
acpi_status acpi_enable_gpe_cond(acpi_handle gpe_device, u32 gpe_number,
|
||||
u8 dispatch_type)
|
||||
{
|
||||
acpi_status status = AE_BAD_PARAMETER;
|
||||
struct acpi_gpe_event_info *gpe_event_info;
|
||||
|
|
@ -100,14 +104,18 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
|
|||
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
|
||||
|
||||
/*
|
||||
* Ensure that we have a valid GPE number and that there is some way
|
||||
* of handling the GPE (handler or a GPE method). In other words, we
|
||||
* won't allow a valid GPE to be enabled if there is no way to handle it.
|
||||
* Ensure that we have a valid GPE number and that the dispatch type of
|
||||
* the GPE matches the supplied one (or it is not ACPI_GPE_DISPATCH_NONE
|
||||
* if the supplied one is ACPI_GPE_DISPATCH_MASK).
|
||||
*/
|
||||
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
|
||||
if (gpe_event_info) {
|
||||
if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
|
||||
ACPI_GPE_DISPATCH_NONE) {
|
||||
if (dispatch_type == ACPI_GPE_DISPATCH_MASK)
|
||||
dispatch_type = ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags);
|
||||
else if (dispatch_type != ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags))
|
||||
dispatch_type = ACPI_GPE_DISPATCH_NONE;
|
||||
|
||||
if (dispatch_type != ACPI_GPE_DISPATCH_NONE) {
|
||||
status = acpi_ev_add_gpe_reference(gpe_event_info, TRUE);
|
||||
if (ACPI_SUCCESS(status) &&
|
||||
ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
|
||||
|
|
@ -128,6 +136,30 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
|
|||
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
ACPI_EXPORT_SYMBOL(acpi_enable_gpe_cond)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_enable_gpe
|
||||
*
|
||||
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
|
||||
* gpe_number - GPE level within the GPE block
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
|
||||
* hardware-enabled.
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
|
||||
{
|
||||
/*
|
||||
* Ensure that there is some way of handling the GPE (handler or a GPE
|
||||
* method). In other words, we won't allow a valid GPE to be enabled if
|
||||
* there is no way to handle it.
|
||||
*/
|
||||
return acpi_enable_gpe_cond(gpe_device, gpe_number, ACPI_GPE_DISPATCH_MASK);
|
||||
}
|
||||
ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ struct acpi_button {
|
|||
ktime_t last_time;
|
||||
bool suspended;
|
||||
bool lid_state_initialized;
|
||||
bool gpe_enabled;
|
||||
};
|
||||
|
||||
static struct acpi_device *lid_device;
|
||||
|
|
@ -646,6 +647,21 @@ static int acpi_button_probe(struct platform_device *pdev)
|
|||
status = acpi_install_notify_handler(device->handle,
|
||||
ACPI_ALL_NOTIFY, handler,
|
||||
button);
|
||||
if (ACPI_SUCCESS(status) && device->wakeup.flags.valid) {
|
||||
acpi_status st;
|
||||
|
||||
/*
|
||||
* If the wakeup GPE has a handler method, enable it in
|
||||
* case it is also used for signaling runtime events.
|
||||
*/
|
||||
st = acpi_enable_gpe_cond(device->wakeup.gpe_device,
|
||||
device->wakeup.gpe_number,
|
||||
ACPI_GPE_DISPATCH_METHOD);
|
||||
button->gpe_enabled = ACPI_SUCCESS(st);
|
||||
if (button->gpe_enabled)
|
||||
dev_dbg(button->dev, "Enabled ACPI GPE%02llx\n",
|
||||
device->wakeup.gpe_number);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
|
@ -671,6 +687,7 @@ static int acpi_button_probe(struct platform_device *pdev)
|
|||
acpi_button_remove_fs(button);
|
||||
err_free_button:
|
||||
kfree(button);
|
||||
memset(acpi_device_class(device), 0, sizeof(acpi_device_class));
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -689,7 +706,13 @@ static void acpi_button_remove(struct platform_device *pdev)
|
|||
acpi_button_event);
|
||||
break;
|
||||
default:
|
||||
acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
|
||||
if (button->gpe_enabled) {
|
||||
dev_dbg(button->dev, "Disabling ACPI GPE%02llx\n",
|
||||
adev->wakeup.gpe_number);
|
||||
acpi_disable_gpe(adev->wakeup.gpe_device,
|
||||
adev->wakeup.gpe_number);
|
||||
}
|
||||
acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY,
|
||||
button->type == ACPI_BUTTON_TYPE_LID ?
|
||||
acpi_lid_notify :
|
||||
acpi_button_notify);
|
||||
|
|
|
|||
|
|
@ -157,6 +157,14 @@ pub(crate) fn set_info_target_node(&mut self, target_node: NodeRef) {
|
|||
self.get_or_init_info().target_node = Some(target_node);
|
||||
}
|
||||
|
||||
pub(crate) fn take_oneway_node(&mut self) -> Option<DArc<Node>> {
|
||||
if let Some(info) = self.allocation_info.as_mut() {
|
||||
info.oneway_node.take()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Reserve enough space to push at least `num_fds` fds.
|
||||
pub(crate) fn info_add_fd_reserve(&mut self, num_fds: usize) -> Result {
|
||||
self.get_or_init_info()
|
||||
|
|
|
|||
|
|
@ -1402,7 +1402,12 @@ fn deferred_release(self: Arc<Self>) {
|
|||
// Clear delivered_deaths list.
|
||||
//
|
||||
// Scope ensures that MutexGuard is dropped while executing the body.
|
||||
while let Some(delivered_death) = { self.inner.lock().delivered_deaths.pop_front() } {
|
||||
while let Some(delivered_death) = {
|
||||
// Explicitly bind to avoid tail expression lifetime extension of the lockguard
|
||||
// Can be removed when the kernel moves to edition 2024
|
||||
let maybe_death = self.inner.lock().delivered_deaths.pop_front();
|
||||
maybe_death
|
||||
} {
|
||||
drop(delivered_death);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -270,7 +270,8 @@ fn drop_outstanding_txn(&self) {
|
|||
/// Not used for replies.
|
||||
pub(crate) fn submit(self: DLArc<Self>, info: &mut TransactionInfo) -> BinderResult {
|
||||
// Defined before `process_inner` so that the destructor runs after releasing the lock.
|
||||
let mut _t_outdated;
|
||||
let _t_outdated;
|
||||
let _oneway_node;
|
||||
|
||||
let oneway = self.flags & TF_ONE_WAY != 0;
|
||||
let process = self.to.clone();
|
||||
|
|
@ -287,6 +288,14 @@ pub(crate) fn submit(self: DLArc<Self>, info: &mut TransactionInfo) -> BinderRes
|
|||
if let Some(t_outdated) =
|
||||
target_node.take_outdated_transaction(&self, &mut process_inner)
|
||||
{
|
||||
let mut alloc_guard = t_outdated.allocation.lock();
|
||||
if let Some(alloc) = (*alloc_guard).as_mut() {
|
||||
// Take the oneway node to prevent `Allocation::drop` from calling
|
||||
// `pending_oneway_finished()`, which would be incorrect as this
|
||||
// transaction is not being submitted.
|
||||
_oneway_node = alloc.take_oneway_node();
|
||||
}
|
||||
drop(alloc_guard);
|
||||
// Save the transaction to be dropped after locks are released.
|
||||
_t_outdated = t_outdated;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3257,6 +3257,9 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
|
|||
*change = false;
|
||||
|
||||
if (regmap_volatile(map, reg) && map->reg_update_bits) {
|
||||
if (map->cache_only)
|
||||
return -EBUSY;
|
||||
|
||||
reg = regmap_reg_addr(map, reg);
|
||||
ret = map->reg_update_bits(map->bus_context, reg, mask, val);
|
||||
if (ret == 0 && change)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <linux/cpuhotplug.h>
|
||||
#include <linux/part_stat.h>
|
||||
#include <linux/kernel_read_file.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
#include "zram_drv.h"
|
||||
|
||||
|
|
@ -504,6 +505,7 @@ struct zram_wb_ctl {
|
|||
wait_queue_head_t done_wait;
|
||||
spinlock_t done_lock;
|
||||
atomic_t num_inflight;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
struct zram_wb_req {
|
||||
|
|
@ -847,7 +849,7 @@ static void release_wb_ctl(struct zram_wb_ctl *wb_ctl)
|
|||
release_wb_req(req);
|
||||
}
|
||||
|
||||
kfree(wb_ctl);
|
||||
kfree_rcu(wb_ctl, rcu);
|
||||
}
|
||||
|
||||
static struct zram_wb_ctl *init_wb_ctl(struct zram *zram)
|
||||
|
|
@ -964,11 +966,13 @@ static void zram_writeback_endio(struct bio *bio)
|
|||
struct zram_wb_ctl *wb_ctl = bio->bi_private;
|
||||
unsigned long flags;
|
||||
|
||||
rcu_read_lock();
|
||||
spin_lock_irqsave(&wb_ctl->done_lock, flags);
|
||||
list_add(&req->entry, &wb_ctl->done_reqs);
|
||||
spin_unlock_irqrestore(&wb_ctl->done_lock, flags);
|
||||
|
||||
wake_up(&wb_ctl->done_wait);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void zram_submit_wb_request(struct zram *zram,
|
||||
|
|
|
|||
|
|
@ -3540,7 +3540,13 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
|
|||
"firmware rome 0x%x build 0x%x",
|
||||
rver_rom, rver_patch, ver_rom, ver_patch);
|
||||
|
||||
if (rver_rom != ver_rom || rver_patch <= ver_patch) {
|
||||
/* Allow rampatch when the patch version equals the firmware version.
|
||||
* A firmware download may be aborted by a transient USB error (e.g.
|
||||
* disconnect) after the controller updates version info but before
|
||||
* completion.
|
||||
* Allowing equal versions enables re-flashing during recovery.
|
||||
*/
|
||||
if (rver_rom != ver_rom || rver_patch < ver_patch) {
|
||||
bt_dev_err(hdev, "rampatch file version did not match with firmware");
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -1680,8 +1680,8 @@ static void qca_hw_error(struct hci_dev *hdev, u8 code)
|
|||
mod_timer(&qca->tx_idle_timer, jiffies +
|
||||
msecs_to_jiffies(qca->tx_idle_delay));
|
||||
|
||||
/* Controller reset completion time is 50ms */
|
||||
msleep(50);
|
||||
/* Wait for the controller to load the rampatch and NVM. */
|
||||
msleep(100);
|
||||
|
||||
clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
|
||||
clear_bit(QCA_IBS_DISABLED, &qca->flags);
|
||||
|
|
|
|||
|
|
@ -274,6 +274,7 @@ static int waveform_ai_cmdtest(struct comedi_device *dev,
|
|||
/* Step 2a : make sure trigger sources are unique */
|
||||
|
||||
err |= comedi_check_trigger_is_unique(cmd->convert_src);
|
||||
err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
|
||||
err |= comedi_check_trigger_is_unique(cmd->stop_src);
|
||||
|
||||
/* Step 2b : and mutually compatible */
|
||||
|
|
@ -324,10 +325,10 @@ static int waveform_ai_cmdtest(struct comedi_device *dev,
|
|||
arg = min(arg,
|
||||
rounddown(UINT_MAX, (unsigned int)NSEC_PER_USEC));
|
||||
arg = NSEC_PER_USEC * DIV_ROUND_CLOSEST(arg, NSEC_PER_USEC);
|
||||
if (cmd->scan_begin_arg == TRIG_TIMER) {
|
||||
if (cmd->scan_begin_src == TRIG_TIMER) {
|
||||
/* limit convert_arg to keep scan_begin_arg in range */
|
||||
limit = UINT_MAX / cmd->scan_end_arg;
|
||||
limit = rounddown(limit, (unsigned int)NSEC_PER_SEC);
|
||||
limit = rounddown(limit, (unsigned int)NSEC_PER_USEC);
|
||||
arg = min(arg, limit);
|
||||
}
|
||||
err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
|
||||
|
|
|
|||
|
|
@ -124,7 +124,8 @@ struct counter_device *counter_alloc(size_t sizeof_priv)
|
|||
|
||||
err_dev_set_name:
|
||||
|
||||
counter_chrdev_remove(counter);
|
||||
put_device(dev);
|
||||
return NULL;
|
||||
err_chrdev_add:
|
||||
|
||||
ida_free(&counter_ida, dev->id);
|
||||
|
|
|
|||
|
|
@ -302,12 +302,6 @@ static int amd_pstate_ut_epp(u32 index)
|
|||
cpufreq_cpu_put(policy);
|
||||
policy = NULL;
|
||||
|
||||
/* disable dynamic EPP before running test */
|
||||
if (cpudata->dynamic_epp) {
|
||||
pr_debug("Dynamic EPP is enabled, disabling it\n");
|
||||
amd_pstate_clear_dynamic_epp(policy);
|
||||
}
|
||||
|
||||
buf = (char *)__get_free_page(GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
|
@ -327,6 +321,16 @@ static int amd_pstate_ut_epp(u32 index)
|
|||
orig_policy = cpudata->policy;
|
||||
cpudata->policy = CPUFREQ_POLICY_POWERSAVE;
|
||||
|
||||
/*
|
||||
* Disable dynamic EPP before running test. If "orig_dynamic_epp" is
|
||||
* true, the driver will do a redundant switch at the end and there
|
||||
* is no need for enabling it again at the end of the test.
|
||||
*/
|
||||
if (cpudata->dynamic_epp) {
|
||||
pr_debug("Dynamic EPP is enabled, disabling it\n");
|
||||
amd_pstate_clear_dynamic_epp(policy);
|
||||
}
|
||||
|
||||
for (epp = 0; epp <= U8_MAX; epp++) {
|
||||
u8 val;
|
||||
|
||||
|
|
|
|||
|
|
@ -792,9 +792,13 @@ int dma_buf_fd(struct dma_buf *dmabuf, int flags)
|
|||
if (!dmabuf || !dmabuf->file)
|
||||
return -EINVAL;
|
||||
|
||||
fd = FD_ADD(flags, dmabuf->file);
|
||||
fd = get_unused_fd_flags(flags);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
DMA_BUF_TRACE(trace_dma_buf_fd, dmabuf, fd);
|
||||
|
||||
fd_install(fd, dmabuf->file);
|
||||
return fd;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(dma_buf_fd, "DMA_BUF");
|
||||
|
|
|
|||
|
|
@ -829,12 +829,21 @@ int dpll_device_delete_ntf(struct dpll_device *dpll)
|
|||
return dpll_device_event_send(DPLL_CMD_DEVICE_DELETE_NTF, dpll);
|
||||
}
|
||||
|
||||
static int
|
||||
__dpll_device_change_ntf(struct dpll_device *dpll)
|
||||
/**
|
||||
* __dpll_device_change_ntf - notify that the dpll device has been changed
|
||||
* @dpll: registered dpll pointer
|
||||
*
|
||||
* Context: caller must hold dpll_lock. Suitable for use inside device
|
||||
* callbacks which are already invoked under dpll_lock.
|
||||
* Return: 0 if succeeds, error code otherwise.
|
||||
*/
|
||||
int __dpll_device_change_ntf(struct dpll_device *dpll)
|
||||
{
|
||||
lockdep_assert_held(&dpll_lock);
|
||||
dpll_device_notify(dpll, DPLL_DEVICE_CHANGED);
|
||||
return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__dpll_device_change_ntf);
|
||||
|
||||
/**
|
||||
* dpll_device_change_ntf - notify that the dpll device has been changed
|
||||
|
|
|
|||
|
|
@ -762,18 +762,15 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
|
|||
dev_warn(zldev->dev, "Failed to update phase offsets: %pe\n",
|
||||
ERR_PTR(rc));
|
||||
|
||||
/* Update measured input reference frequencies if any DPLL has
|
||||
* frequency monitoring enabled.
|
||||
/* Update measured input reference frequencies if frequency
|
||||
* monitoring is enabled.
|
||||
*/
|
||||
list_for_each_entry(zldpll, &zldev->dplls, list) {
|
||||
if (zldpll->freq_monitor) {
|
||||
rc = zl3073x_ref_freq_meas_update(zldev);
|
||||
if (rc)
|
||||
dev_warn(zldev->dev,
|
||||
"Failed to update measured frequencies: %pe\n",
|
||||
ERR_PTR(rc));
|
||||
break;
|
||||
}
|
||||
if (zldev->freq_monitor) {
|
||||
rc = zl3073x_ref_freq_meas_update(zldev);
|
||||
if (rc)
|
||||
dev_warn(zldev->dev,
|
||||
"Failed to update measured frequencies: %pe\n",
|
||||
ERR_PTR(rc));
|
||||
}
|
||||
|
||||
/* Update references' fractional frequency offsets */
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ struct zl3073x_chip_info {
|
|||
* @work: periodic work
|
||||
* @clock_id: clock id of the device
|
||||
* @phase_avg_factor: phase offset measurement averaging factor
|
||||
* @freq_monitor: is frequency monitor enabled
|
||||
*/
|
||||
struct zl3073x_dev {
|
||||
struct device *dev;
|
||||
|
|
@ -77,9 +78,10 @@ struct zl3073x_dev {
|
|||
struct kthread_worker *kworker;
|
||||
struct kthread_delayed_work work;
|
||||
|
||||
/* Devlink parameters */
|
||||
/* Per-chip parameters */
|
||||
u64 clock_id;
|
||||
u8 phase_avg_factor;
|
||||
bool freq_monitor;
|
||||
};
|
||||
|
||||
extern const struct regmap_config zl3073x_regmap_config;
|
||||
|
|
|
|||
|
|
@ -1079,15 +1079,6 @@ zl3073x_dpll_phase_offset_avg_factor_get(const struct dpll_device *dpll,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
zl3073x_dpll_change_work(struct work_struct *work)
|
||||
{
|
||||
struct zl3073x_dpll *zldpll;
|
||||
|
||||
zldpll = container_of(work, struct zl3073x_dpll, change_work);
|
||||
dpll_device_change_ntf(zldpll->dpll_dev);
|
||||
}
|
||||
|
||||
static int
|
||||
zl3073x_dpll_phase_offset_avg_factor_set(const struct dpll_device *dpll,
|
||||
void *dpll_priv, u32 factor,
|
||||
|
|
@ -1113,8 +1104,10 @@ zl3073x_dpll_phase_offset_avg_factor_set(const struct dpll_device *dpll,
|
|||
* we have to send a notification for other DPLL devices.
|
||||
*/
|
||||
list_for_each_entry(item, &zldpll->dev->dplls, list) {
|
||||
if (item != zldpll)
|
||||
schedule_work(&item->change_work);
|
||||
struct dpll_device *dpll_dev = READ_ONCE(item->dpll_dev);
|
||||
|
||||
if (item != zldpll && dpll_dev)
|
||||
__dpll_device_change_ntf(dpll_dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1219,7 +1212,7 @@ zl3073x_dpll_freq_monitor_get(const struct dpll_device *dpll,
|
|||
{
|
||||
struct zl3073x_dpll *zldpll = dpll_priv;
|
||||
|
||||
if (zldpll->freq_monitor)
|
||||
if (zldpll->dev->freq_monitor)
|
||||
*state = DPLL_FEATURE_STATE_ENABLE;
|
||||
else
|
||||
*state = DPLL_FEATURE_STATE_DISABLE;
|
||||
|
|
@ -1233,9 +1226,19 @@ zl3073x_dpll_freq_monitor_set(const struct dpll_device *dpll,
|
|||
enum dpll_feature_state state,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct zl3073x_dpll *zldpll = dpll_priv;
|
||||
struct zl3073x_dpll *item, *zldpll = dpll_priv;
|
||||
|
||||
zldpll->freq_monitor = (state == DPLL_FEATURE_STATE_ENABLE);
|
||||
zldpll->dev->freq_monitor = (state == DPLL_FEATURE_STATE_ENABLE);
|
||||
|
||||
/* The frequency monitoring is common for all DPLL channels so after
|
||||
* change we have to send a notification for other DPLL devices.
|
||||
*/
|
||||
list_for_each_entry(item, &zldpll->dev->dplls, list) {
|
||||
struct dpll_device *dpll_dev = READ_ONCE(item->dpll_dev);
|
||||
|
||||
if (item != zldpll && dpll_dev)
|
||||
__dpll_device_change_ntf(dpll_dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1627,13 +1630,13 @@ zl3073x_dpll_device_register(struct zl3073x_dpll *zldpll)
|
|||
static void
|
||||
zl3073x_dpll_device_unregister(struct zl3073x_dpll *zldpll)
|
||||
{
|
||||
WARN(!zldpll->dpll_dev, "DPLL device is not registered\n");
|
||||
struct dpll_device *dpll_dev = READ_ONCE(zldpll->dpll_dev);
|
||||
|
||||
cancel_work_sync(&zldpll->change_work);
|
||||
WARN(!dpll_dev, "DPLL device is not registered\n");
|
||||
|
||||
dpll_device_unregister(zldpll->dpll_dev, &zldpll->ops, zldpll);
|
||||
dpll_device_put(zldpll->dpll_dev, &zldpll->tracker);
|
||||
zldpll->dpll_dev = NULL;
|
||||
WRITE_ONCE(zldpll->dpll_dev, NULL);
|
||||
dpll_device_unregister(dpll_dev, &zldpll->ops, zldpll);
|
||||
dpll_device_put(dpll_dev, &zldpll->tracker);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1752,7 +1755,7 @@ zl3073x_dpll_pin_measured_freq_check(struct zl3073x_dpll_pin *pin)
|
|||
u8 ref_id;
|
||||
u32 freq;
|
||||
|
||||
if (!zldpll->freq_monitor)
|
||||
if (!zldpll->dev->freq_monitor)
|
||||
return false;
|
||||
|
||||
ref_id = zl3073x_input_pin_ref_get(pin->id);
|
||||
|
|
@ -1785,10 +1788,8 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
|
|||
struct zl3073x_dev *zldev = zldpll->dev;
|
||||
enum dpll_lock_status lock_status;
|
||||
struct device *dev = zldev->dev;
|
||||
const struct zl3073x_chan *chan;
|
||||
struct zl3073x_dpll_pin *pin;
|
||||
int rc;
|
||||
u8 mode;
|
||||
|
||||
zldpll->check_count++;
|
||||
|
||||
|
|
@ -1807,15 +1808,6 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
|
|||
dpll_device_change_ntf(zldpll->dpll_dev);
|
||||
}
|
||||
|
||||
/* Input pin monitoring does make sense only in automatic
|
||||
* or forced reference modes.
|
||||
*/
|
||||
chan = zl3073x_chan_state_get(zldev, zldpll->id);
|
||||
mode = zl3073x_chan_mode_get(chan);
|
||||
if (mode != ZL_DPLL_MODE_REFSEL_MODE_AUTO &&
|
||||
mode != ZL_DPLL_MODE_REFSEL_MODE_REFLOCK)
|
||||
return;
|
||||
|
||||
/* Update phase offset latch registers for this DPLL if the phase
|
||||
* offset monitor feature is enabled.
|
||||
*/
|
||||
|
|
@ -1926,7 +1918,6 @@ zl3073x_dpll_alloc(struct zl3073x_dev *zldev, u8 ch)
|
|||
zldpll->dev = zldev;
|
||||
zldpll->id = ch;
|
||||
INIT_LIST_HEAD(&zldpll->pins);
|
||||
INIT_WORK(&zldpll->change_work, zl3073x_dpll_change_work);
|
||||
|
||||
return zldpll;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,13 +15,11 @@
|
|||
* @id: DPLL index
|
||||
* @check_count: periodic check counter
|
||||
* @phase_monitor: is phase offset monitor enabled
|
||||
* @freq_monitor: is frequency monitor enabled
|
||||
* @ops: DPLL device operations for this instance
|
||||
* @dpll_dev: pointer to registered DPLL device
|
||||
* @tracker: tracking object for the acquired reference
|
||||
* @lock_status: last saved DPLL lock status
|
||||
* @pins: list of pins
|
||||
* @change_work: device change notification work
|
||||
*/
|
||||
struct zl3073x_dpll {
|
||||
struct list_head list;
|
||||
|
|
@ -29,13 +27,11 @@ struct zl3073x_dpll {
|
|||
u8 id;
|
||||
u8 check_count;
|
||||
bool phase_monitor;
|
||||
bool freq_monitor;
|
||||
struct dpll_device_ops ops;
|
||||
struct dpll_device *dpll_dev;
|
||||
dpll_tracker tracker;
|
||||
enum dpll_lock_status lock_status;
|
||||
struct list_head pins;
|
||||
struct work_struct change_work;
|
||||
};
|
||||
|
||||
struct zl3073x_dpll *zl3073x_dpll_alloc(struct zl3073x_dev *zldev, u8 ch);
|
||||
|
|
|
|||
|
|
@ -237,7 +237,9 @@ static irqreturn_t adnp_irq(int irq, void *data)
|
|||
unsigned long pending;
|
||||
int err;
|
||||
|
||||
scoped_guard(mutex, &adnp->i2c_lock) {
|
||||
{
|
||||
guard(mutex)(&adnp->i2c_lock);
|
||||
|
||||
err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level);
|
||||
if (err < 0)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
|||
* the handler is needed only once, but doing it for every port
|
||||
* is more robust and easier.
|
||||
*/
|
||||
port->irq_high = -1;
|
||||
port->irq_high = 0;
|
||||
port->mx_irq_handler = mx2_gpio_irq_handler;
|
||||
} else
|
||||
port->mx_irq_handler = mx3_gpio_irq_handler;
|
||||
|
|
|
|||
|
|
@ -638,10 +638,17 @@ static int rockchip_gpiolib_register(struct rockchip_pin_bank *bank)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void rockchip_clk_put(void *data)
|
||||
{
|
||||
struct clk *clk = data;
|
||||
|
||||
clk_put(clk);
|
||||
}
|
||||
|
||||
static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
|
||||
{
|
||||
struct resource res;
|
||||
int id = 0;
|
||||
int id = 0, ret;
|
||||
|
||||
if (of_address_to_resource(bank->of_node, 0, &res)) {
|
||||
dev_err(bank->dev, "cannot find IO resource for bank\n");
|
||||
|
|
@ -656,11 +663,10 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
|
|||
if (!bank->irq)
|
||||
return -EINVAL;
|
||||
|
||||
bank->clk = of_clk_get(bank->of_node, 0);
|
||||
bank->clk = devm_clk_get_enabled(bank->dev, NULL);
|
||||
if (IS_ERR(bank->clk))
|
||||
return PTR_ERR(bank->clk);
|
||||
|
||||
clk_prepare_enable(bank->clk);
|
||||
id = readl(bank->reg_base + gpio_regs_v2.version_id);
|
||||
|
||||
switch (id) {
|
||||
|
|
@ -672,9 +678,13 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
|
|||
bank->db_clk = of_clk_get(bank->of_node, 1);
|
||||
if (IS_ERR(bank->db_clk)) {
|
||||
dev_err(bank->dev, "cannot find debounce clk\n");
|
||||
clk_disable_unprepare(bank->clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(bank->dev, rockchip_clk_put,
|
||||
bank->db_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case GPIO_TYPE_V1:
|
||||
bank->gpio_regs = &gpio_regs_v1;
|
||||
|
|
@ -751,7 +761,6 @@ static int rockchip_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
ret = rockchip_gpiolib_register(bank);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(bank->clk);
|
||||
mutex_unlock(&bank->deferred_lock);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -792,7 +801,9 @@ static void rockchip_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct rockchip_pin_bank *bank = platform_get_drvdata(pdev);
|
||||
|
||||
clk_disable_unprepare(bank->clk);
|
||||
irq_set_chained_handler_and_data(bank->irq, NULL, NULL);
|
||||
if (bank->domain)
|
||||
irq_domain_remove(bank->domain);
|
||||
gpiochip_remove(&bank->gpio_chip);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -103,9 +103,18 @@ static void gpio_shared_proxy_free(struct gpio_chip *gc, unsigned int offset)
|
|||
{
|
||||
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
|
||||
struct gpio_shared_desc *shared_desc = proxy->shared_desc;
|
||||
int ret;
|
||||
|
||||
guard(gpio_shared_desc_lock)(shared_desc);
|
||||
|
||||
if (proxy->voted_high) {
|
||||
ret = gpio_shared_proxy_set_unlocked(proxy,
|
||||
shared_desc->can_sleep ? gpiod_set_value_cansleep : gpiod_set_value, 0);
|
||||
if (ret)
|
||||
dev_err(proxy->dev,
|
||||
"Failed to unset the shared GPIO value on release: %d\n", ret);
|
||||
}
|
||||
|
||||
proxy->shared_desc->usecnt--;
|
||||
|
||||
dev_dbg(proxy->dev, "Shared GPIO freed, number of users: %u\n",
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ static ssize_t gpio_virtuser_direction_do_write(struct file *file,
|
|||
char buf[32], *trimmed;
|
||||
int ret, dir, val = 0;
|
||||
|
||||
if (count >= sizeof(buf))
|
||||
if (*ppos != 0 || count >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
||||
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
|
||||
|
|
@ -622,7 +622,7 @@ static ssize_t gpio_virtuser_consumer_write(struct file *file,
|
|||
char buf[GPIO_VIRTUSER_NAME_BUF_LEN + 2];
|
||||
int ret;
|
||||
|
||||
if (count >= sizeof(buf))
|
||||
if (*ppos != 0 || count >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
||||
ret = simple_write_to_buffer(buf, GPIO_VIRTUSER_NAME_BUF_LEN, ppos,
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ struct gpio_shared_entry {
|
|||
unsigned int offset;
|
||||
/* Index in the property value array. */
|
||||
size_t index;
|
||||
/* Synchronizes the modification of shared_desc. */
|
||||
/* Synchronizes the modification of shared_desc and offset. */
|
||||
struct mutex lock;
|
||||
struct gpio_shared_desc *shared_desc;
|
||||
struct kref ref;
|
||||
|
|
@ -598,16 +598,13 @@ void gpio_device_teardown_shared(struct gpio_device *gdev)
|
|||
struct gpio_shared_ref *ref;
|
||||
|
||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||
guard(mutex)(&entry->lock);
|
||||
|
||||
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
|
||||
continue;
|
||||
|
||||
gpiod_free_commit(&gdev->descs[entry->offset]);
|
||||
scoped_guard(mutex, &entry->lock)
|
||||
gpiod_free_commit(&gdev->descs[entry->offset]);
|
||||
|
||||
list_for_each_entry(ref, &entry->refs, list) {
|
||||
guard(mutex)(&ref->lock);
|
||||
|
||||
if (ref->lookup) {
|
||||
gpiod_remove_lookup_table(ref->lookup);
|
||||
kfree(ref->lookup->table[0].key);
|
||||
|
|
|
|||
|
|
@ -1093,9 +1093,16 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data,
|
|||
* If that number is larger than the size of the array, the ioctl must
|
||||
* be retried.
|
||||
*/
|
||||
if (args->num_entries > INT_MAX / sizeof(*vm_entries)) {
|
||||
r = -EINVAL;
|
||||
goto out_exec;
|
||||
}
|
||||
|
||||
vm_entries = kvcalloc(args->num_entries, sizeof(*vm_entries), GFP_KERNEL);
|
||||
if (!vm_entries)
|
||||
return -ENOMEM;
|
||||
if (!vm_entries) {
|
||||
r = -ENOMEM;
|
||||
goto out_exec;
|
||||
}
|
||||
|
||||
amdgpu_vm_bo_va_for_each_valid_mapping(bo_va, mapping) {
|
||||
if (num_mappings < args->num_entries) {
|
||||
|
|
|
|||
|
|
@ -51,8 +51,6 @@
|
|||
#include "amdgpu_amdkfd.h"
|
||||
#include "amdgpu_hmm.h"
|
||||
|
||||
#define MAX_WALK_BYTE (2UL << 30)
|
||||
|
||||
/**
|
||||
* amdgpu_hmm_invalidate_gfx - callback to notify about mm change
|
||||
*
|
||||
|
|
@ -78,6 +76,7 @@ static bool amdgpu_hmm_invalidate_gfx(struct mmu_interval_notifier *mni,
|
|||
|
||||
mmu_interval_set_seq(mni, cur_seq);
|
||||
|
||||
amdgpu_vm_bo_invalidate(bo, false);
|
||||
r = dma_resv_wait_timeout(bo->tbo.base.resv, DMA_RESV_USAGE_BOOKKEEP,
|
||||
false, MAX_SCHEDULE_TIMEOUT);
|
||||
mutex_unlock(&adev->notifier_lock);
|
||||
|
|
@ -170,11 +169,13 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
|
|||
void *owner,
|
||||
struct amdgpu_hmm_range *range)
|
||||
{
|
||||
unsigned long end;
|
||||
const u64 max_bytes = SZ_2G;
|
||||
|
||||
struct hmm_range *hmm_range = &range->hmm_range;
|
||||
unsigned long timeout;
|
||||
unsigned long *pfns;
|
||||
int r = 0;
|
||||
struct hmm_range *hmm_range = &range->hmm_range;
|
||||
unsigned long end;
|
||||
int r;
|
||||
|
||||
pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
|
||||
if (unlikely(!pfns)) {
|
||||
|
|
@ -191,8 +192,9 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
|
|||
end = start + npages * PAGE_SIZE;
|
||||
hmm_range->dev_private_owner = owner;
|
||||
|
||||
hmm_range->notifier_seq = mmu_interval_read_begin(notifier);
|
||||
do {
|
||||
hmm_range->end = min(hmm_range->start + MAX_WALK_BYTE, end);
|
||||
hmm_range->end = min(hmm_range->start + max_bytes, end);
|
||||
|
||||
pr_debug("hmm range: start = 0x%lx, end = 0x%lx",
|
||||
hmm_range->start, hmm_range->end);
|
||||
|
|
@ -200,7 +202,6 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
|
|||
timeout = jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
|
||||
|
||||
retry:
|
||||
hmm_range->notifier_seq = mmu_interval_read_begin(notifier);
|
||||
r = hmm_range_fault(hmm_range);
|
||||
if (unlikely(r)) {
|
||||
if (r == -EBUSY && !time_after(jiffies, timeout))
|
||||
|
|
@ -210,7 +211,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
|
|||
|
||||
if (hmm_range->end == end)
|
||||
break;
|
||||
hmm_range->hmm_pfns += MAX_WALK_BYTE >> PAGE_SHIFT;
|
||||
hmm_range->hmm_pfns += max_bytes >> PAGE_SHIFT;
|
||||
hmm_range->start = hmm_range->end;
|
||||
} while (hmm_range->end < end);
|
||||
|
||||
|
|
|
|||
|
|
@ -2280,7 +2280,8 @@ void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev)
|
|||
list_for_each_entry(obj, &con->head, node) {
|
||||
if (amdgpu_ras_is_supported(adev, obj->head.block) &&
|
||||
(obj->attr_inuse == 1)) {
|
||||
sprintf(fs_info.debugfs_name, "%s_err_inject",
|
||||
snprintf(fs_info.debugfs_name, sizeof(fs_info.debugfs_name),
|
||||
"%s_err_inject",
|
||||
get_ras_block_str(&obj->head));
|
||||
fs_info.head = obj->head;
|
||||
amdgpu_ras_debugfs_create(adev, &fs_info, dir);
|
||||
|
|
|
|||
|
|
@ -215,33 +215,15 @@ void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell)
|
|||
xa_unlock_irqrestore(xa, flags);
|
||||
}
|
||||
|
||||
static int amdgpu_userq_buffer_va_list_add(struct amdgpu_usermode_queue *queue,
|
||||
struct amdgpu_bo_va_mapping *va_map, u64 addr)
|
||||
{
|
||||
struct amdgpu_userq_va_cursor *va_cursor;
|
||||
struct userq_va_list;
|
||||
|
||||
va_cursor = kzalloc_obj(*va_cursor);
|
||||
if (!va_cursor)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&va_cursor->list);
|
||||
va_cursor->gpu_addr = addr;
|
||||
va_map->bo_va->userq_va_mapped = true;
|
||||
list_add(&va_cursor->list, &queue->userq_va_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
|
||||
struct amdgpu_usermode_queue *queue,
|
||||
u64 addr, u64 expected_size)
|
||||
u64 addr, u64 expected_size,
|
||||
u64 *va_out)
|
||||
{
|
||||
struct amdgpu_bo_va_mapping *va_map;
|
||||
struct amdgpu_vm *vm = queue->vm;
|
||||
u64 user_addr;
|
||||
u64 size;
|
||||
int r = 0;
|
||||
|
||||
/* Caller must hold vm->root.bo reservation */
|
||||
dma_resv_assert_held(queue->vm->root.bo->tbo.base.resv);
|
||||
|
|
@ -250,20 +232,18 @@ int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
|
|||
size = expected_size >> AMDGPU_GPU_PAGE_SHIFT;
|
||||
|
||||
va_map = amdgpu_vm_bo_lookup_mapping(vm, user_addr);
|
||||
if (!va_map) {
|
||||
r = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
if (!va_map)
|
||||
return -EINVAL;
|
||||
|
||||
/* Only validate the userq whether resident in the VM mapping range */
|
||||
if (user_addr >= va_map->start &&
|
||||
va_map->last - user_addr + 1 >= size) {
|
||||
amdgpu_userq_buffer_va_list_add(queue, va_map, user_addr);
|
||||
va_map->bo_va->userq_va_mapped = true;
|
||||
*va_out = user_addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = -EINVAL;
|
||||
out_err:
|
||||
return r;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static bool amdgpu_userq_buffer_va_mapped(struct amdgpu_vm *vm, u64 addr)
|
||||
|
|
@ -284,14 +264,16 @@ static bool amdgpu_userq_buffer_va_mapped(struct amdgpu_vm *vm, u64 addr)
|
|||
|
||||
static bool amdgpu_userq_buffer_vas_mapped(struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
struct amdgpu_userq_va_cursor *va_cursor, *tmp;
|
||||
int r = 0;
|
||||
int i, r = 0;
|
||||
|
||||
list_for_each_entry_safe(va_cursor, tmp, &queue->userq_va_list, list) {
|
||||
r += amdgpu_userq_buffer_va_mapped(queue->vm, va_cursor->gpu_addr);
|
||||
for (i = 0; i < ARRAY_SIZE(queue->userq_vas.va_array); i++) {
|
||||
if (!queue->userq_vas.va_array[i])
|
||||
continue;
|
||||
r += amdgpu_userq_buffer_va_mapped(queue->vm,
|
||||
queue->userq_vas.va_array[i]);
|
||||
dev_dbg(queue->userq_mgr->adev->dev,
|
||||
"validate the userq mapping:%p va:%llx r:%d\n",
|
||||
queue, va_cursor->gpu_addr, r);
|
||||
queue, queue->userq_vas.va_array[i], r);
|
||||
}
|
||||
|
||||
if (r != 0)
|
||||
|
|
@ -300,24 +282,7 @@ static bool amdgpu_userq_buffer_vas_mapped(struct amdgpu_usermode_queue *queue)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void amdgpu_userq_buffer_vas_list_cleanup(struct amdgpu_device *adev,
|
||||
struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
struct amdgpu_userq_va_cursor *va_cursor, *tmp;
|
||||
struct amdgpu_bo_va_mapping *mapping;
|
||||
|
||||
/* Caller must hold vm->root.bo reservation */
|
||||
dma_resv_assert_held(queue->vm->root.bo->tbo.base.resv);
|
||||
|
||||
list_for_each_entry_safe(va_cursor, tmp, &queue->userq_va_list, list) {
|
||||
mapping = amdgpu_vm_bo_lookup_mapping(queue->vm, va_cursor->gpu_addr);
|
||||
if (mapping)
|
||||
dev_dbg(adev->dev, "delete the userq:%p va:%llx\n",
|
||||
queue, va_cursor->gpu_addr);
|
||||
list_del(&va_cursor->list);
|
||||
kfree(va_cursor);
|
||||
}
|
||||
}
|
||||
|
||||
static int amdgpu_userq_preempt_helper(struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
|
|
@ -417,18 +382,14 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue)
|
|||
{
|
||||
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
|
||||
struct amdgpu_device *adev = uq_mgr->adev;
|
||||
const struct amdgpu_userq_funcs *uq_funcs = adev->userq_funcs[queue->queue_type];
|
||||
|
||||
/* Wait for mode-1 reset to complete */
|
||||
down_read(&adev->reset_domain->sem);
|
||||
|
||||
uq_funcs->mqd_destroy(queue);
|
||||
/* Use interrupt-safe locking since IRQ handlers may access these XArrays */
|
||||
xa_erase_irq(&adev->userq_doorbell_xa, queue->doorbell_index);
|
||||
amdgpu_userq_fence_driver_free(queue);
|
||||
queue->fence_drv = NULL;
|
||||
queue->userq_mgr = NULL;
|
||||
list_del(&queue->userq_va_list);
|
||||
|
||||
up_read(&adev->reset_domain->sem);
|
||||
}
|
||||
|
|
@ -467,81 +428,15 @@ amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *uq_mgr,
|
|||
dma_fence_put(ev_fence);
|
||||
}
|
||||
|
||||
int amdgpu_userq_create_object(struct amdgpu_userq_mgr *uq_mgr,
|
||||
struct amdgpu_userq_obj *userq_obj,
|
||||
int size)
|
||||
{
|
||||
struct amdgpu_device *adev = uq_mgr->adev;
|
||||
struct amdgpu_bo_param bp;
|
||||
int r;
|
||||
|
||||
memset(&bp, 0, sizeof(bp));
|
||||
bp.byte_align = PAGE_SIZE;
|
||||
bp.domain = AMDGPU_GEM_DOMAIN_GTT;
|
||||
bp.flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
|
||||
AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
|
||||
bp.type = ttm_bo_type_kernel;
|
||||
bp.size = size;
|
||||
bp.resv = NULL;
|
||||
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
|
||||
|
||||
r = amdgpu_bo_create(adev, &bp, &userq_obj->obj);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to allocate BO for userqueue (%d)", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_bo_reserve(userq_obj->obj, true);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to reserve BO to map (%d)", r);
|
||||
goto free_obj;
|
||||
}
|
||||
|
||||
r = amdgpu_bo_pin(userq_obj->obj, AMDGPU_GEM_DOMAIN_GTT);
|
||||
if (r)
|
||||
goto unresv;
|
||||
|
||||
r = amdgpu_ttm_alloc_gart(&(userq_obj->obj)->tbo);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to alloc GART for userqueue object (%d)", r);
|
||||
goto unpin_bo;
|
||||
}
|
||||
|
||||
r = amdgpu_bo_kmap(userq_obj->obj, &userq_obj->cpu_ptr);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to map BO for userqueue (%d)", r);
|
||||
goto unpin_bo;
|
||||
}
|
||||
|
||||
userq_obj->gpu_addr = amdgpu_bo_gpu_offset(userq_obj->obj);
|
||||
amdgpu_bo_unreserve(userq_obj->obj);
|
||||
memset(userq_obj->cpu_ptr, 0, size);
|
||||
return 0;
|
||||
|
||||
unpin_bo:
|
||||
amdgpu_bo_unpin(userq_obj->obj);
|
||||
unresv:
|
||||
amdgpu_bo_unreserve(userq_obj->obj);
|
||||
free_obj:
|
||||
amdgpu_bo_unref(&userq_obj->obj);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void amdgpu_userq_destroy_object(struct amdgpu_userq_mgr *uq_mgr,
|
||||
struct amdgpu_userq_obj *userq_obj)
|
||||
{
|
||||
amdgpu_bo_kunmap(userq_obj->obj);
|
||||
amdgpu_bo_unpin(userq_obj->obj);
|
||||
amdgpu_bo_unref(&userq_obj->obj);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
static int
|
||||
amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
|
||||
struct amdgpu_db_info *db_info,
|
||||
struct drm_file *filp)
|
||||
struct drm_file *filp,
|
||||
u64 *index)
|
||||
{
|
||||
uint64_t index;
|
||||
u64 doorbell_index;
|
||||
struct drm_gem_object *gobj;
|
||||
struct amdgpu_userq_obj *db_obj = db_info->db_obj;
|
||||
int r, db_size;
|
||||
|
|
@ -588,12 +483,13 @@ amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
|
|||
goto unpin_bo;
|
||||
}
|
||||
|
||||
index = amdgpu_doorbell_index_on_bar(uq_mgr->adev, db_obj->obj,
|
||||
db_info->doorbell_offset, db_size);
|
||||
doorbell_index = amdgpu_doorbell_index_on_bar(uq_mgr->adev, db_obj->obj,
|
||||
db_info->doorbell_offset, db_size);
|
||||
drm_dbg_driver(adev_to_drm(uq_mgr->adev),
|
||||
"[Usermode queues] doorbell index=%lld\n", index);
|
||||
"[Usermode queues] doorbell index=%lld\n", doorbell_index);
|
||||
amdgpu_bo_unreserve(db_obj->obj);
|
||||
return index;
|
||||
*index = doorbell_index;
|
||||
return 0;
|
||||
|
||||
unpin_bo:
|
||||
amdgpu_bo_unpin(db_obj->obj);
|
||||
|
|
@ -608,9 +504,7 @@ static int
|
|||
amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
struct amdgpu_device *adev = uq_mgr->adev;
|
||||
struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr);
|
||||
struct amdgpu_vm *vm = &fpriv->vm;
|
||||
|
||||
const struct amdgpu_userq_funcs *uq_funcs = adev->userq_funcs[queue->queue_type];
|
||||
int r = 0;
|
||||
|
||||
cancel_delayed_work_sync(&uq_mgr->resume_work);
|
||||
|
|
@ -618,14 +512,6 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
|
|||
/* Cancel any pending hang detection work and cleanup */
|
||||
cancel_delayed_work_sync(&queue->hang_detect_work);
|
||||
|
||||
r = amdgpu_bo_reserve(vm->root.bo, false);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to reserve root bo during userqueue destroy\n");
|
||||
return r;
|
||||
}
|
||||
amdgpu_userq_buffer_vas_list_cleanup(adev, queue);
|
||||
amdgpu_bo_unreserve(vm->root.bo);
|
||||
|
||||
mutex_lock(&uq_mgr->userq_mutex);
|
||||
amdgpu_userq_wait_for_last_fence(queue);
|
||||
|
||||
|
|
@ -637,6 +523,10 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
|
|||
amdgpu_userq_cleanup(queue);
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
|
||||
cancel_delayed_work_sync(&queue->hang_detect_work);
|
||||
uq_funcs->mqd_destroy(queue);
|
||||
queue->userq_mgr = NULL;
|
||||
|
||||
amdgpu_bo_reserve(queue->db_obj.obj, true);
|
||||
amdgpu_bo_unpin(queue->db_obj.obj);
|
||||
amdgpu_bo_unreserve(queue->db_obj.obj);
|
||||
|
|
@ -739,7 +629,6 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
}
|
||||
|
||||
kref_init(&queue->refcount);
|
||||
INIT_LIST_HEAD(&queue->userq_va_list);
|
||||
queue->doorbell_handle = args->in.doorbell_handle;
|
||||
queue->queue_type = args->in.ip_type;
|
||||
queue->vm = &fpriv->vm;
|
||||
|
|
@ -748,26 +637,29 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
INIT_DELAYED_WORK(&queue->hang_detect_work,
|
||||
amdgpu_userq_hang_detect_work);
|
||||
|
||||
mutex_init(&queue->fence_drv_lock);
|
||||
xa_init_flags(&queue->fence_drv_xa, XA_FLAGS_ALLOC);
|
||||
r = amdgpu_userq_fence_driver_alloc(adev, &queue->fence_drv);
|
||||
if (r)
|
||||
goto free_queue;
|
||||
|
||||
xa_init_flags(&queue->fence_drv_xa, XA_FLAGS_ALLOC);
|
||||
mutex_init(&queue->fence_drv_lock);
|
||||
/* Make sure the queue can actually run with those virtual addresses. */
|
||||
r = amdgpu_bo_reserve(fpriv->vm.root.bo, false);
|
||||
if (r)
|
||||
goto free_fence_drv;
|
||||
|
||||
if (amdgpu_userq_input_va_validate(adev, queue, args->in.queue_va,
|
||||
args->in.queue_size) ||
|
||||
args->in.queue_size,
|
||||
&queue->userq_vas.va.queue_rb) ||
|
||||
amdgpu_userq_input_va_validate(adev, queue, args->in.rptr_va,
|
||||
AMDGPU_GPU_PAGE_SIZE) ||
|
||||
AMDGPU_GPU_PAGE_SIZE,
|
||||
&queue->userq_vas.va.rptr) ||
|
||||
amdgpu_userq_input_va_validate(adev, queue, args->in.wptr_va,
|
||||
AMDGPU_GPU_PAGE_SIZE)) {
|
||||
AMDGPU_GPU_PAGE_SIZE,
|
||||
&queue->userq_vas.va.wptr)) {
|
||||
r = -EINVAL;
|
||||
amdgpu_bo_unreserve(fpriv->vm.root.bo);
|
||||
goto clean_mapping;
|
||||
goto free_fence_drv;
|
||||
}
|
||||
amdgpu_bo_unreserve(fpriv->vm.root.bo);
|
||||
|
||||
|
|
@ -776,18 +668,17 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
db_info.doorbell_handle = queue->doorbell_handle;
|
||||
db_info.db_obj = &queue->db_obj;
|
||||
db_info.doorbell_offset = args->in.doorbell_offset;
|
||||
index = amdgpu_userq_get_doorbell_index(uq_mgr, &db_info, filp);
|
||||
if (index == (uint64_t)-EINVAL) {
|
||||
r = amdgpu_userq_get_doorbell_index(uq_mgr, &db_info, filp, &index);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to get doorbell for queue\n");
|
||||
r = -EINVAL;
|
||||
goto clean_mapping;
|
||||
goto free_fence_drv;
|
||||
}
|
||||
|
||||
queue->doorbell_index = index;
|
||||
r = uq_funcs->mqd_create(queue, &args->in);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to create Queue\n");
|
||||
goto clean_mapping;
|
||||
goto clean_doorbell_bo;
|
||||
}
|
||||
|
||||
/* Update VM owner at userq submit-time for page-fault attribution. */
|
||||
|
|
@ -808,7 +699,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to map Queue\n");
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
goto clean_doorbell;
|
||||
goto erase_doorbell;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -831,15 +722,15 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
args->out.queue_id = qid;
|
||||
return 0;
|
||||
|
||||
clean_doorbell:
|
||||
erase_doorbell:
|
||||
xa_erase_irq(&adev->userq_doorbell_xa, index);
|
||||
clean_mqd:
|
||||
uq_funcs->mqd_destroy(queue);
|
||||
clean_mapping:
|
||||
amdgpu_bo_reserve(fpriv->vm.root.bo, true);
|
||||
amdgpu_userq_buffer_vas_list_cleanup(adev, queue);
|
||||
amdgpu_bo_unreserve(fpriv->vm.root.bo);
|
||||
mutex_destroy(&queue->fence_drv_lock);
|
||||
clean_doorbell_bo:
|
||||
amdgpu_bo_reserve(queue->db_obj.obj, true);
|
||||
amdgpu_bo_unpin(queue->db_obj.obj);
|
||||
amdgpu_bo_unreserve(queue->db_obj.obj);
|
||||
amdgpu_bo_unref(&queue->db_obj.obj);
|
||||
free_fence_drv:
|
||||
amdgpu_userq_fence_driver_free(queue);
|
||||
free_queue:
|
||||
|
|
|
|||
|
|
@ -48,11 +48,6 @@ struct amdgpu_userq_obj {
|
|||
struct amdgpu_bo *obj;
|
||||
};
|
||||
|
||||
struct amdgpu_userq_va_cursor {
|
||||
u64 gpu_addr;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct amdgpu_usermode_queue {
|
||||
int queue_type;
|
||||
enum amdgpu_userq_state state;
|
||||
|
|
@ -93,7 +88,17 @@ struct amdgpu_usermode_queue {
|
|||
struct delayed_work hang_detect_work;
|
||||
struct kref refcount;
|
||||
|
||||
struct list_head userq_va_list;
|
||||
union {
|
||||
struct {
|
||||
u64 queue_rb;
|
||||
u64 wptr;
|
||||
u64 rptr;
|
||||
u64 eop;
|
||||
u64 shadow;
|
||||
u64 csa;
|
||||
} va;
|
||||
u64 va_array[6];
|
||||
} userq_vas;
|
||||
};
|
||||
|
||||
struct amdgpu_userq_funcs {
|
||||
|
|
@ -151,22 +156,11 @@ void amdgpu_userq_mgr_cancel_reset_work(struct amdgpu_device *adev);
|
|||
void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr *userq_mgr);
|
||||
void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr);
|
||||
|
||||
int amdgpu_userq_create_object(struct amdgpu_userq_mgr *uq_mgr,
|
||||
struct amdgpu_userq_obj *userq_obj,
|
||||
int size);
|
||||
|
||||
void amdgpu_userq_destroy_object(struct amdgpu_userq_mgr *uq_mgr,
|
||||
struct amdgpu_userq_obj *userq_obj);
|
||||
|
||||
void amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr);
|
||||
|
||||
void amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *userq_mgr,
|
||||
struct amdgpu_eviction_fence_mgr *evf_mgr);
|
||||
|
||||
uint64_t amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
|
||||
struct amdgpu_db_info *db_info,
|
||||
struct drm_file *filp);
|
||||
|
||||
u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev);
|
||||
bool amdgpu_userq_enabled(struct drm_device *dev);
|
||||
|
||||
|
|
@ -185,7 +179,8 @@ void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell);
|
|||
|
||||
int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
|
||||
struct amdgpu_usermode_queue *queue,
|
||||
u64 addr, u64 expected_size);
|
||||
u64 addr, u64 expected_size, u64 *va_out);
|
||||
|
||||
void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_va_mapping *mapping,
|
||||
uint64_t saddr);
|
||||
|
|
|
|||
|
|
@ -1631,6 +1631,7 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev,
|
|||
{
|
||||
struct amdgpu_bo_va *bo_va;
|
||||
struct dma_resv *resv;
|
||||
struct amdgpu_bo *bo;
|
||||
bool clear, unlock;
|
||||
int r;
|
||||
|
||||
|
|
@ -1650,11 +1651,13 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev,
|
|||
while (!list_empty(&vm->invalidated)) {
|
||||
bo_va = list_first_entry(&vm->invalidated, struct amdgpu_bo_va,
|
||||
base.vm_status);
|
||||
resv = bo_va->base.bo->tbo.base.resv;
|
||||
bo = bo_va->base.bo;
|
||||
resv = bo->tbo.base.resv;
|
||||
spin_unlock(&vm->status_lock);
|
||||
|
||||
/* Try to reserve the BO to avoid clearing its ptes */
|
||||
if (!adev->debug_vm && dma_resv_trylock(resv)) {
|
||||
if (!adev->debug_vm && !amdgpu_ttm_tt_get_usermm(bo->tbo.ttm) &&
|
||||
dma_resv_trylock(resv)) {
|
||||
clear = false;
|
||||
unlock = true;
|
||||
/* The caller is already holding the reservation lock */
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ mes_userq_create_wptr_mapping(struct amdgpu_device *adev,
|
|||
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;
|
||||
goto fail_alloc_gart;
|
||||
}
|
||||
|
||||
queue->wptr_obj.gpu_addr = amdgpu_bo_gpu_offset(wptr_obj->obj);
|
||||
|
|
@ -89,6 +89,8 @@ mes_userq_create_wptr_mapping(struct amdgpu_device *adev,
|
|||
drm_exec_fini(&exec);
|
||||
return 0;
|
||||
|
||||
fail_alloc_gart:
|
||||
amdgpu_bo_unpin(wptr_obj->obj);
|
||||
fail_map:
|
||||
amdgpu_bo_unref(&wptr_obj->obj);
|
||||
fail_lock:
|
||||
|
|
@ -190,12 +192,16 @@ static int mes_userq_create_ctx_space(struct amdgpu_userq_mgr *uq_mgr,
|
|||
* for the same.
|
||||
*/
|
||||
size = AMDGPU_USERQ_PROC_CTX_SZ + AMDGPU_USERQ_GANG_CTX_SZ;
|
||||
r = amdgpu_userq_create_object(uq_mgr, ctx, size);
|
||||
r = amdgpu_bo_create_kernel(uq_mgr->adev, size, 0,
|
||||
AMDGPU_GEM_DOMAIN_GTT,
|
||||
&ctx->obj, &ctx->gpu_addr,
|
||||
&ctx->cpu_ptr);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to allocate ctx space bo for userqueue, err:%d\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
memset(ctx->cpu_ptr, 0, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -268,13 +274,19 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = amdgpu_userq_create_object(uq_mgr, &queue->mqd,
|
||||
AMDGPU_MQD_SIZE_ALIGN(mqd_hw_default->mqd_size));
|
||||
r = amdgpu_bo_create_kernel(adev,
|
||||
AMDGPU_MQD_SIZE_ALIGN(mqd_hw_default->mqd_size),
|
||||
0, AMDGPU_GEM_DOMAIN_GTT,
|
||||
&queue->mqd.obj, &queue->mqd.gpu_addr,
|
||||
&queue->mqd.cpu_ptr);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to create MQD object for userqueue\n");
|
||||
goto free_props;
|
||||
}
|
||||
|
||||
memset(queue->mqd.cpu_ptr, 0,
|
||||
AMDGPU_MQD_SIZE_ALIGN(mqd_hw_default->mqd_size));
|
||||
|
||||
/* Initialize the MQD BO with user given values */
|
||||
userq_props->wptr_gpu_addr = mqd_user->wptr_va;
|
||||
userq_props->rptr_gpu_addr = mqd_user->rptr_va;
|
||||
|
|
@ -306,8 +318,9 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
kfree(compute_mqd);
|
||||
goto free_mqd;
|
||||
}
|
||||
r = amdgpu_userq_input_va_validate(adev, queue, compute_mqd->eop_va,
|
||||
2048);
|
||||
r = amdgpu_userq_input_va_validate(adev, queue,
|
||||
compute_mqd->eop_va, 2048,
|
||||
&queue->userq_vas.va.eop);
|
||||
amdgpu_bo_unreserve(queue->vm->root.bo);
|
||||
if (r) {
|
||||
kfree(compute_mqd);
|
||||
|
|
@ -356,7 +369,8 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
goto free_mqd;
|
||||
}
|
||||
r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->shadow_va,
|
||||
shadow_info.shadow_size);
|
||||
shadow_info.shadow_size,
|
||||
&queue->userq_vas.va.shadow);
|
||||
if (r) {
|
||||
amdgpu_bo_unreserve(queue->vm->root.bo);
|
||||
kfree(mqd_gfx_v11);
|
||||
|
|
@ -364,7 +378,8 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
}
|
||||
|
||||
r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->csa_va,
|
||||
shadow_info.csa_size);
|
||||
shadow_info.csa_size,
|
||||
&queue->userq_vas.va.csa);
|
||||
amdgpu_bo_unreserve(queue->vm->root.bo);
|
||||
if (r) {
|
||||
kfree(mqd_gfx_v11);
|
||||
|
|
@ -394,7 +409,8 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
goto free_mqd;
|
||||
}
|
||||
r = amdgpu_userq_input_va_validate(adev, queue, mqd_sdma_v11->csa_va,
|
||||
32);
|
||||
32,
|
||||
&queue->userq_vas.va.csa);
|
||||
amdgpu_bo_unreserve(queue->vm->root.bo);
|
||||
if (r) {
|
||||
kfree(mqd_sdma_v11);
|
||||
|
|
@ -430,10 +446,12 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
return 0;
|
||||
|
||||
free_ctx:
|
||||
amdgpu_userq_destroy_object(uq_mgr, &queue->fw_obj);
|
||||
amdgpu_bo_free_kernel(&queue->fw_obj.obj, &queue->fw_obj.gpu_addr,
|
||||
&queue->fw_obj.cpu_ptr);
|
||||
|
||||
free_mqd:
|
||||
amdgpu_userq_destroy_object(uq_mgr, &queue->mqd);
|
||||
amdgpu_bo_free_kernel(&queue->mqd.obj, &queue->mqd.gpu_addr,
|
||||
&queue->mqd.cpu_ptr);
|
||||
|
||||
free_props:
|
||||
kfree(userq_props);
|
||||
|
|
@ -443,11 +461,12 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
|
||||
static void mes_userq_mqd_destroy(struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
|
||||
|
||||
amdgpu_userq_destroy_object(uq_mgr, &queue->fw_obj);
|
||||
amdgpu_bo_free_kernel(&queue->fw_obj.obj, &queue->fw_obj.gpu_addr,
|
||||
&queue->fw_obj.cpu_ptr);
|
||||
kfree(queue->userq_prop);
|
||||
amdgpu_userq_destroy_object(uq_mgr, &queue->mqd);
|
||||
amdgpu_bo_free_kernel(&queue->mqd.obj, &queue->mqd.gpu_addr,
|
||||
&queue->mqd.cpu_ptr);
|
||||
}
|
||||
|
||||
static int mes_userq_preempt(struct amdgpu_usermode_queue *queue)
|
||||
|
|
|
|||
|
|
@ -2300,6 +2300,11 @@ static int criu_restore_devices(struct kfd_process *p,
|
|||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (pdd->drm_file) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
pdd->user_gpu_id = device_buckets[i].user_gpu_id;
|
||||
|
||||
drm_file = fget(device_buckets[i].drm_fd);
|
||||
|
|
@ -2310,11 +2315,6 @@ static int criu_restore_devices(struct kfd_process *p,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
if (pdd->drm_file) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* create the vm using render nodes for kfd pdd */
|
||||
if (kfd_process_device_init_vm(pdd, drm_file)) {
|
||||
pr_err("could not init vm for given pdd\n");
|
||||
|
|
|
|||
|
|
@ -3308,12 +3308,14 @@ static void copy_context_work_handler(struct work_struct *work)
|
|||
|
||||
static uint32_t *get_queue_ids(uint32_t num_queues, uint32_t *usr_queue_id_array)
|
||||
{
|
||||
size_t array_size = num_queues * sizeof(uint32_t);
|
||||
|
||||
if (!usr_queue_id_array)
|
||||
return NULL;
|
||||
|
||||
return memdup_user(usr_queue_id_array, array_size);
|
||||
if (num_queues > KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return memdup_user(usr_queue_id_array,
|
||||
array_size(num_queues, sizeof(uint32_t)));
|
||||
}
|
||||
|
||||
int resume_queues(struct kfd_process *p,
|
||||
|
|
|
|||
|
|
@ -3732,6 +3732,9 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
|
|||
|
||||
svms = &p->svms;
|
||||
|
||||
if (!process_info)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&process_info->lock);
|
||||
|
||||
svm_range_list_lock_and_flush_work(svms, mm);
|
||||
|
|
|
|||
|
|
@ -105,15 +105,26 @@ static void dccg21_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppcl
|
|||
* dccg2_init() unconditionally overwrites MICROSECOND_TIME_BASE_DIV to
|
||||
* 0x00120264, destroying the marker before it can be read.
|
||||
*
|
||||
* Guard the call: if the S0i3 marker is present, skip dccg2_init() so the
|
||||
* Guard the call: if the S0i3 marker is present, skip init so the
|
||||
* WA can function correctly. bios_golden_init() will handle init in that case.
|
||||
*
|
||||
* DCN21 uses 48MHz refclk, not 100MHz, so we must explicitly set the correct
|
||||
* values (48MHz is taken from rn_clk_mgr_construct()).
|
||||
*/
|
||||
static void dccg21_init(struct dccg *dccg)
|
||||
{
|
||||
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
|
||||
|
||||
if (dccg2_is_s0i3_golden_init_wa_done(dccg))
|
||||
return;
|
||||
|
||||
dccg2_init(dccg);
|
||||
/* 48MHz refclk from rn_clk_mgr_construct() */
|
||||
REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x00120230);
|
||||
REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x0010bb80);
|
||||
REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0x0e01003c);
|
||||
|
||||
if (REG(REFCLK_CNTL))
|
||||
REG_WRITE(REFCLK_CNTL, 0);
|
||||
}
|
||||
|
||||
static const struct dccg_funcs dccg21_funcs = {
|
||||
|
|
|
|||
|
|
@ -3076,6 +3076,10 @@ static bool si_dpm_vblank_too_short(void *handle)
|
|||
/* we never hit the non-gddr5 limit so disable it */
|
||||
u32 switch_limit = adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 0;
|
||||
|
||||
/* Disregard vblank time when there are no displays connected */
|
||||
if (!adev->pm.pm_display_cfg.num_display)
|
||||
return false;
|
||||
|
||||
/* Consider zero vblank time too short and disable MCLK switching.
|
||||
* Note that the vblank time is set to maximum when no displays are attached,
|
||||
* so we'll still enable MCLK switching in that case.
|
||||
|
|
|
|||
|
|
@ -70,8 +70,11 @@ static int drm_mode_align_dumb(struct drm_mode_create_dumb *args,
|
|||
if (!pitch)
|
||||
return -EINVAL;
|
||||
|
||||
if (hw_pitch_align)
|
||||
if (hw_pitch_align) {
|
||||
pitch = roundup(pitch, hw_pitch_align);
|
||||
if (pitch < hw_pitch_align)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!hw_size_align)
|
||||
hw_size_align = PAGE_SIZE;
|
||||
|
|
@ -80,7 +83,7 @@ static int drm_mode_align_dumb(struct drm_mode_create_dumb *args,
|
|||
|
||||
if (check_mul_overflow(args->height, pitch, &size))
|
||||
return -EINVAL;
|
||||
size = ALIGN(size, hw_size_align);
|
||||
size = roundup(size, hw_size_align);
|
||||
if (!size)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -199,6 +202,13 @@ int drm_mode_create_dumb(struct drm_device *dev,
|
|||
if (!args->width || !args->height || !args->bpp)
|
||||
return -EINVAL;
|
||||
|
||||
/* Reject unreasonable inputs early. Dumb buffers are for software
|
||||
* rendering; nothing legitimate needs more than 8192x8192 at 32bpp.
|
||||
* This prevents overflows in downstream alignment helpers.
|
||||
*/
|
||||
if (args->width >= 8192 || args->height >= 8192 || args->bpp > 32)
|
||||
return -EINVAL;
|
||||
|
||||
/* overflow checks for 32bit size calculations */
|
||||
if (args->bpp > U32_MAX - 8)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -1065,6 +1065,7 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
|
|||
goto out_unlock;
|
||||
}
|
||||
|
||||
idr_replace(&file_priv->object_idr, NULL, args->handle);
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
|
||||
if (obj->dma_buf) {
|
||||
|
|
@ -1073,6 +1074,7 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
|
|||
if (ret < 0) {
|
||||
spin_lock(&file_priv->table_lock);
|
||||
idr_remove(&file_priv->object_idr, handle);
|
||||
idr_replace(&file_priv->object_idr, obj, args->handle);
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -391,8 +391,11 @@ static int hyperv_get_supported_resolution(struct hv_device *hdev)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (msg->resolution_resp.resolution_count == 0) {
|
||||
drm_err(dev, "No supported resolutions\n");
|
||||
if (msg->resolution_resp.resolution_count == 0 ||
|
||||
msg->resolution_resp.resolution_count >
|
||||
SYNTHVID_MAX_RESOLUTION_COUNT) {
|
||||
drm_err(dev, "Invalid resolution count: %d\n",
|
||||
msg->resolution_resp.resolution_count);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
@ -417,30 +420,92 @@ static int hyperv_get_supported_resolution(struct hv_device *hdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void hyperv_receive_sub(struct hv_device *hdev)
|
||||
static void hyperv_receive_sub(struct hv_device *hdev, u32 bytes_recvd)
|
||||
{
|
||||
struct hyperv_drm_device *hv = hv_get_drvdata(hdev);
|
||||
struct synthvid_msg *msg;
|
||||
size_t hdr_size;
|
||||
size_t need;
|
||||
|
||||
if (!hv)
|
||||
return;
|
||||
|
||||
msg = (struct synthvid_msg *)hv->recv_buf;
|
||||
|
||||
/* Complete the wait event */
|
||||
if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
|
||||
msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
|
||||
msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
|
||||
memcpy(hv->init_buf, msg, VMBUS_MAX_PACKET_SIZE);
|
||||
complete(&hv->wait);
|
||||
hdr_size = sizeof(struct pipe_msg_hdr) +
|
||||
sizeof(struct synthvid_msg_hdr);
|
||||
if (bytes_recvd < hdr_size) {
|
||||
drm_err_ratelimited(&hv->dev,
|
||||
"synthvid packet too small for header: %u\n",
|
||||
bytes_recvd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) {
|
||||
msg = (struct synthvid_msg *)hv->recv_buf;
|
||||
need = hdr_size;
|
||||
|
||||
switch (msg->vid_hdr.type) {
|
||||
case SYNTHVID_VERSION_RESPONSE:
|
||||
need += sizeof(struct synthvid_version_resp);
|
||||
break;
|
||||
case SYNTHVID_RESOLUTION_RESPONSE:
|
||||
/*
|
||||
* The resolution response is variable length: the host
|
||||
* fills resolution_count entries, not the full
|
||||
* SYNTHVID_MAX_RESOLUTION_COUNT array. Require the fixed
|
||||
* prefix first so resolution_count can be read, then
|
||||
* demand exactly the count-sized array.
|
||||
*/
|
||||
need += offsetof(struct synthvid_supported_resolution_resp,
|
||||
supported_resolution);
|
||||
if (bytes_recvd < need)
|
||||
break;
|
||||
if (msg->resolution_resp.resolution_count >
|
||||
SYNTHVID_MAX_RESOLUTION_COUNT) {
|
||||
drm_err_ratelimited(&hv->dev,
|
||||
"synthvid resolution count too large: %u\n",
|
||||
msg->resolution_resp.resolution_count);
|
||||
return;
|
||||
}
|
||||
need += msg->resolution_resp.resolution_count *
|
||||
sizeof(struct hvd_screen_info);
|
||||
break;
|
||||
case SYNTHVID_VRAM_LOCATION_ACK:
|
||||
need += sizeof(struct synthvid_vram_location_ack);
|
||||
break;
|
||||
case SYNTHVID_FEATURE_CHANGE:
|
||||
/*
|
||||
* Not a completion-driving message: validate its own payload
|
||||
* and consume it here rather than falling through to the
|
||||
* memcpy/complete shared by the wait-event responses.
|
||||
*/
|
||||
if (bytes_recvd < need +
|
||||
sizeof(struct synthvid_feature_change)) {
|
||||
drm_err_ratelimited(&hv->dev,
|
||||
"synthvid feature change packet too small: %u\n",
|
||||
bytes_recvd);
|
||||
return;
|
||||
}
|
||||
hv->dirt_needed = msg->feature_chg.is_dirt_needed;
|
||||
if (hv->dirt_needed)
|
||||
hyperv_hide_hw_ptr(hv->hdev);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shared completion path for the wait-event responses
|
||||
* (VERSION_RESPONSE, RESOLUTION_RESPONSE, VRAM_LOCATION_ACK):
|
||||
* require the type-specific payload before handing the buffer to
|
||||
* the waiter.
|
||||
*/
|
||||
if (bytes_recvd < need) {
|
||||
drm_err_ratelimited(&hv->dev,
|
||||
"synthvid packet too small for type %u: %u < %zu\n",
|
||||
msg->vid_hdr.type, bytes_recvd, need);
|
||||
return;
|
||||
}
|
||||
memcpy(hv->init_buf, msg, bytes_recvd);
|
||||
complete(&hv->wait);
|
||||
}
|
||||
|
||||
static void hyperv_receive(void *ctx)
|
||||
|
|
@ -461,9 +526,21 @@ static void hyperv_receive(void *ctx)
|
|||
ret = vmbus_recvpacket(hdev->channel, recv_buf,
|
||||
VMBUS_MAX_PACKET_SIZE,
|
||||
&bytes_recvd, &req_id);
|
||||
if (bytes_recvd > 0 &&
|
||||
recv_buf->pipe_hdr.type == PIPE_MSG_DATA)
|
||||
hyperv_receive_sub(hdev);
|
||||
if (ret) {
|
||||
/*
|
||||
* A nonzero return (e.g. -ENOBUFS for an oversized
|
||||
* packet) is itself a malformed message: bytes_recvd
|
||||
* then reports the required length rather than a copied
|
||||
* payload, so it must not be forwarded to the
|
||||
* sub-handler. Channel recovery is not attempted.
|
||||
*/
|
||||
drm_err_ratelimited(&hv->dev,
|
||||
"vmbus_recvpacket failed: %d (need %u)\n",
|
||||
ret, bytes_recvd);
|
||||
} else if (bytes_recvd > 0 &&
|
||||
recv_buf->pipe_hdr.type == PIPE_MSG_DATA) {
|
||||
hyperv_receive_sub(hdev, bytes_recvd);
|
||||
}
|
||||
} while (bytes_recvd > 0 && ret == 0);
|
||||
}
|
||||
|
||||
|
|
@ -508,9 +585,13 @@ int hyperv_connect_vsp(struct hv_device *hdev)
|
|||
ret = hyperv_get_supported_resolution(hdev);
|
||||
if (ret)
|
||||
drm_err(dev, "Failed to get supported resolution from host, use default\n");
|
||||
} else {
|
||||
}
|
||||
|
||||
if (!hv->screen_width_max) {
|
||||
hv->screen_width_max = SYNTHVID_WIDTH_WIN8;
|
||||
hv->screen_height_max = SYNTHVID_HEIGHT_WIN8;
|
||||
hv->preferred_width = SYNTHVID_WIDTH_WIN8;
|
||||
hv->preferred_height = SYNTHVID_HEIGHT_WIN8;
|
||||
}
|
||||
|
||||
hv->mmio_megabytes = hdev->channel->offermsg.offer.mmio_megabytes;
|
||||
|
|
|
|||
|
|
@ -3976,7 +3976,7 @@ xelpd_program_plane_pre_csc_lut(struct intel_dsb *dsb,
|
|||
intel_de_write_dsb(display, dsb,
|
||||
PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0),
|
||||
(1 << 24));
|
||||
} while (i++ > 130);
|
||||
} while (i++ < 130);
|
||||
} else {
|
||||
for (i = 0; i < lut_size; i++) {
|
||||
u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1);
|
||||
|
|
|
|||
|
|
@ -497,6 +497,7 @@ struct intel_display {
|
|||
u8 vblank_enabled;
|
||||
|
||||
int vblank_enable_count;
|
||||
bool vblank_status_last_notified;
|
||||
|
||||
struct work_struct vblank_notify_work;
|
||||
|
||||
|
|
|
|||
|
|
@ -1773,8 +1773,12 @@ static void intel_display_vblank_notify_work(struct work_struct *work)
|
|||
struct intel_display *display =
|
||||
container_of(work, typeof(*display), irq.vblank_notify_work);
|
||||
int vblank_enable_count = READ_ONCE(display->irq.vblank_enable_count);
|
||||
bool vblank_status = !!vblank_enable_count;
|
||||
|
||||
intel_psr_notify_vblank_enable_disable(display, vblank_enable_count);
|
||||
if (display->irq.vblank_status_last_notified != vblank_status) {
|
||||
intel_psr_notify_vblank_enable_disable(display, vblank_status);
|
||||
display->irq.vblank_status_last_notified = vblank_status;
|
||||
}
|
||||
}
|
||||
|
||||
int bdw_enable_vblank(struct drm_crtc *_crtc)
|
||||
|
|
@ -1787,10 +1791,10 @@ int bdw_enable_vblank(struct drm_crtc *_crtc)
|
|||
if (gen11_dsi_configure_te(crtc, true))
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&display->irq.lock, irqflags);
|
||||
if (crtc->vblank_psr_notify && display->irq.vblank_enable_count++ == 0)
|
||||
schedule_work(&display->irq.vblank_notify_work);
|
||||
|
||||
spin_lock_irqsave(&display->irq.lock, irqflags);
|
||||
bdw_enable_pipe_irq(display, pipe, GEN8_PIPE_VBLANK);
|
||||
spin_unlock_irqrestore(&display->irq.lock, irqflags);
|
||||
|
||||
|
|
|
|||
|
|
@ -1790,6 +1790,8 @@ struct intel_psr {
|
|||
u8 active_non_psr_pipes;
|
||||
|
||||
const char *no_psr_reason;
|
||||
|
||||
struct ref_tracker *vblank_wakeref;
|
||||
};
|
||||
|
||||
struct intel_dp {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "intel_dp.h"
|
||||
#include "intel_dp_aux.h"
|
||||
#include "intel_dp_aux_regs.h"
|
||||
#include "intel_parent.h"
|
||||
#include "intel_pps.h"
|
||||
#include "intel_quirks.h"
|
||||
#include "intel_tc.h"
|
||||
|
|
@ -60,18 +61,29 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp)
|
|||
struct intel_display *display = to_intel_display(intel_dp);
|
||||
i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
|
||||
const unsigned int timeout_ms = 10;
|
||||
bool done = true;
|
||||
u32 status;
|
||||
bool done;
|
||||
int ret;
|
||||
|
||||
if (intel_parent_irq_enabled(display)) {
|
||||
#define C (((status = intel_de_read_notrace(display, ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
|
||||
done = wait_event_timeout(display->gmbus.wait_queue, C,
|
||||
msecs_to_jiffies_timeout(timeout_ms));
|
||||
done = wait_event_timeout(display->gmbus.wait_queue, C,
|
||||
msecs_to_jiffies_timeout(timeout_ms));
|
||||
|
||||
#undef C
|
||||
} else {
|
||||
ret = intel_de_wait_ms(display, ch_ctl,
|
||||
DP_AUX_CH_CTL_SEND_BUSY, 0,
|
||||
timeout_ms, &status);
|
||||
|
||||
if (ret == -ETIMEDOUT)
|
||||
done = false;
|
||||
}
|
||||
|
||||
if (!done)
|
||||
drm_err(display->drm,
|
||||
"%s: did not complete or timeout within %ums (status 0x%08x)\n",
|
||||
intel_dp->aux.name, timeout_ms, status);
|
||||
#undef C
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4156,27 +4156,22 @@ void intel_psr_notify_vblank_enable_disable(struct intel_display *display,
|
|||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
|
||||
mutex_lock(&intel_dp->psr.lock);
|
||||
if (intel_dp->psr.panel_replay_enabled) {
|
||||
mutex_unlock(&intel_dp->psr.lock);
|
||||
break;
|
||||
if (CAN_PANEL_REPLAY(intel_dp)) {
|
||||
if (enable)
|
||||
intel_dp->psr.vblank_wakeref =
|
||||
intel_display_power_get(display,
|
||||
POWER_DOMAIN_DC_OFF);
|
||||
else
|
||||
intel_display_power_put(display, POWER_DOMAIN_DC_OFF,
|
||||
intel_dp->psr.vblank_wakeref);
|
||||
}
|
||||
|
||||
if (intel_dp->psr.enabled && intel_dp->psr.pkg_c_latency_used)
|
||||
if (intel_dp->psr.enabled && !intel_dp->psr.panel_replay_enabled &&
|
||||
intel_dp->psr.pkg_c_latency_used)
|
||||
intel_psr_apply_underrun_on_idle_wa_locked(intel_dp);
|
||||
|
||||
mutex_unlock(&intel_dp->psr.lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: intel_display_power_set_target_dc_state is used
|
||||
* only by PSR * code for DC3CO handling. DC3CO target
|
||||
* state is currently disabled in * PSR code. If DC3CO
|
||||
* is taken into use we need take that into account here
|
||||
* as well.
|
||||
*/
|
||||
intel_display_power_set_target_dc_state(display, enable ? DC_STATE_DISABLE :
|
||||
DC_STATE_EN_UPTO_DC6);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -419,8 +419,6 @@ void i915_ttm_free_cached_io_rsgt(struct drm_i915_gem_object *obj)
|
|||
int i915_ttm_purge(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
|
||||
struct i915_ttm_tt *i915_tt =
|
||||
container_of(bo->ttm, typeof(*i915_tt), ttm);
|
||||
struct ttm_operation_ctx ctx = {
|
||||
.interruptible = true,
|
||||
.no_wait_gpu = false,
|
||||
|
|
@ -435,16 +433,22 @@ int i915_ttm_purge(struct drm_i915_gem_object *obj)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (bo->ttm && i915_tt->filp) {
|
||||
/*
|
||||
* The below fput(which eventually calls shmem_truncate) might
|
||||
* be delayed by worker, so when directly called to purge the
|
||||
* pages(like by the shrinker) we should try to be more
|
||||
* aggressive and release the pages immediately.
|
||||
*/
|
||||
shmem_truncate_range(file_inode(i915_tt->filp),
|
||||
0, (loff_t)-1);
|
||||
fput(fetch_and_zero(&i915_tt->filp));
|
||||
if (bo->ttm) {
|
||||
struct i915_ttm_tt *i915_tt =
|
||||
container_of(bo->ttm, typeof(*i915_tt), ttm);
|
||||
|
||||
if (i915_tt->filp) {
|
||||
/*
|
||||
* The below fput(which eventually calls shmem_truncate)
|
||||
* might be delayed by worker, so when directly called
|
||||
* to purge the pages(like by the shrinker) we should
|
||||
* try to be more aggressive and release the pages
|
||||
* immediately.
|
||||
*/
|
||||
shmem_truncate_range(file_inode(i915_tt->filp),
|
||||
0, (loff_t)-1);
|
||||
fput(fetch_and_zero(&i915_tt->filp));
|
||||
}
|
||||
}
|
||||
|
||||
obj->write_domain = 0;
|
||||
|
|
|
|||
|
|
@ -767,6 +767,11 @@ static unsigned int guc_mmio_regset_write(struct xe_guc_ads *ads,
|
|||
}
|
||||
}
|
||||
|
||||
if (XE_GT_WA(hwe->gt, 16023105232))
|
||||
guc_mmio_regset_write_one(ads, regset_map,
|
||||
RING_IDLEDLY(hwe->mmio_base),
|
||||
count++);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1284,6 +1284,7 @@
|
|||
|
||||
#define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f
|
||||
#define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002
|
||||
#define USB_DEVICE_ID_SIGMA_MICRO_USB_MOUSE 0x0034
|
||||
#define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD2 0x0059
|
||||
|
||||
#define USB_VENDOR_ID_SIGMATEL 0x066F
|
||||
|
|
|
|||
|
|
@ -382,11 +382,9 @@ static int get_endpoint_address(struct hid_device *hdev)
|
|||
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
|
||||
struct usb_host_endpoint *ep;
|
||||
|
||||
if (intf) {
|
||||
ep = intf->cur_altsetting->endpoint;
|
||||
if (ep)
|
||||
return ep->desc.bEndpointAddress;
|
||||
}
|
||||
ep = intf->cur_altsetting->endpoint;
|
||||
if (ep)
|
||||
return ep->desc.bEndpointAddress;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
@ -1461,6 +1459,9 @@ static int hid_gos_probe(struct hid_device *hdev,
|
|||
{
|
||||
int ret, ep;
|
||||
|
||||
if (!hid_is_usb(hdev))
|
||||
return -EINVAL;
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
if (ret) {
|
||||
hid_err(hdev, "Parse failed\n");
|
||||
|
|
|
|||
|
|
@ -641,9 +641,6 @@ static int get_endpoint_address(struct hid_device *hdev)
|
|||
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
|
||||
struct usb_host_endpoint *ep;
|
||||
|
||||
if (!intf)
|
||||
return -ENODEV;
|
||||
|
||||
ep = intf->cur_altsetting->endpoint;
|
||||
if (!ep)
|
||||
return -ENODEV;
|
||||
|
|
@ -2419,6 +2416,9 @@ static int hid_go_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
{
|
||||
int ret, ep;
|
||||
|
||||
if (!hid_is_usb(hdev))
|
||||
return -EINVAL;
|
||||
|
||||
hdev->quirks |= HID_QUIRK_INPUT_PER_APP | HID_QUIRK_MULTI_INPUT;
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/hid.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
|
@ -793,8 +794,8 @@ static int lenovo_raw_event(struct hid_device *hdev,
|
|||
*/
|
||||
if (unlikely((hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB
|
||||
|| hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2)
|
||||
&& size >= 3 && report->id == 0x03))
|
||||
return lenovo_raw_event_TP_X12_tab(hdev, le32_to_cpu(*(__le32 *)data));
|
||||
&& size >= 4 && report->id == 0x03))
|
||||
return lenovo_raw_event_TP_X12_tab(hdev, get_unaligned_le32(data));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,6 +187,7 @@ static const struct hid_device_id hid_quirks[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD), HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_USB_MOUSE), HID_QUIRK_ALWAYS_POLL },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780), HID_QUIRK_NOGET },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH), HID_QUIRK_NOGET },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH), HID_QUIRK_NOGET },
|
||||
|
|
|
|||
|
|
@ -341,29 +341,33 @@ static int u2fzero_probe(struct hid_device *hdev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
u2fzero_fill_in_urb(dev);
|
||||
ret = u2fzero_fill_in_urb(dev);
|
||||
if (ret)
|
||||
goto err_hid_hw_stop;
|
||||
|
||||
dev->present = true;
|
||||
|
||||
minor = ((struct hidraw *) hdev->hidraw)->minor;
|
||||
|
||||
ret = u2fzero_init_led(dev, minor);
|
||||
if (ret) {
|
||||
hid_hw_stop(hdev);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto err_free_urb;
|
||||
|
||||
hid_info(hdev, "%s LED initialised\n", hw_configs[dev->hw_revision].name);
|
||||
|
||||
ret = u2fzero_init_hwrng(dev, minor);
|
||||
if (ret) {
|
||||
hid_hw_stop(hdev);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto err_free_urb;
|
||||
|
||||
hid_info(hdev, "%s RNG initialised\n", hw_configs[dev->hw_revision].name);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_urb:
|
||||
usb_free_urb(dev->urb);
|
||||
err_hid_hw_stop:
|
||||
hid_hw_stop(hdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void u2fzero_remove(struct hid_device *hdev)
|
||||
|
|
|
|||
|
|
@ -356,6 +356,7 @@ static void wacom_feature_mapping(struct hid_device *hdev,
|
|||
|
||||
hid_data->inputmode = field->report->id;
|
||||
hid_data->inputmode_index = usage->usage_index;
|
||||
hid_data->inputmode_field_index = field->index;
|
||||
break;
|
||||
|
||||
case HID_UP_DIGITIZER:
|
||||
|
|
@ -571,9 +572,14 @@ static int wacom_hid_set_device_mode(struct hid_device *hdev)
|
|||
|
||||
re = &(hdev->report_enum[HID_FEATURE_REPORT]);
|
||||
r = re->report_id_hash[hid_data->inputmode];
|
||||
if (r) {
|
||||
r->field[0]->value[hid_data->inputmode_index] = 2;
|
||||
hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
|
||||
if (r && hid_data->inputmode_field_index >= 0 &&
|
||||
hid_data->inputmode_field_index < r->maxfield) {
|
||||
struct hid_field *field = r->field[hid_data->inputmode_field_index];
|
||||
|
||||
if (field && hid_data->inputmode_index < field->report_count) {
|
||||
field->value[hid_data->inputmode_index] = 2;
|
||||
hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2846,6 +2852,7 @@ static int wacom_probe(struct hid_device *hdev,
|
|||
return -ENODEV;
|
||||
|
||||
wacom_wac->hid_data.inputmode = -1;
|
||||
wacom_wac->hid_data.inputmode_field_index = -1;
|
||||
wacom_wac->mode_report = -1;
|
||||
|
||||
if (hid_is_usb(hdev)) {
|
||||
|
|
|
|||
|
|
@ -295,6 +295,7 @@ struct wacom_shared {
|
|||
struct hid_data {
|
||||
__s16 inputmode; /* InputMode HID feature, -1 if non-existent */
|
||||
__s16 inputmode_index; /* InputMode HID feature index in the report */
|
||||
__s16 inputmode_field_index; /* InputMode HID feature field index in the report */
|
||||
bool sense_state;
|
||||
bool inrange_state;
|
||||
bool eraser;
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@
|
|||
/* timeout for pm runtime autosuspend */
|
||||
#define DAVINCI_I2C_PM_TIMEOUT 1000 /* ms */
|
||||
|
||||
#define DAVINCI_I2C_DEFAULT_BUS_FREQ 100
|
||||
#define DAVINCI_I2C_DEFAULT_BUS_FREQ 100000
|
||||
|
||||
struct davinci_i2c_dev {
|
||||
struct device *dev;
|
||||
|
|
|
|||
|
|
@ -222,6 +222,8 @@ static int virtio_i2c_probe(struct virtio_device *vdev)
|
|||
*/
|
||||
ACPI_COMPANION_SET(&vi->adap.dev, ACPI_COMPANION(vdev->dev.parent));
|
||||
|
||||
virtio_device_ready(vdev);
|
||||
|
||||
ret = i2c_add_adapter(&vi->adap);
|
||||
if (ret)
|
||||
virtio_i2c_del_vqs(vdev);
|
||||
|
|
|
|||
|
|
@ -876,14 +876,14 @@ static int ad4695_offload_buffer_postenable(struct iio_dev *indio_dev)
|
|||
if (ret)
|
||||
goto err_unoptimize_message;
|
||||
|
||||
ret = spi_offload_trigger_enable(st->offload, st->offload_trigger,
|
||||
&config);
|
||||
ret = ad4695_enter_advanced_sequencer_mode(st, num_slots);
|
||||
if (ret)
|
||||
goto err_disable_busy_output;
|
||||
|
||||
ret = ad4695_enter_advanced_sequencer_mode(st, num_slots);
|
||||
ret = spi_offload_trigger_enable(st->offload, st->offload_trigger,
|
||||
&config);
|
||||
if (ret)
|
||||
goto err_offload_trigger_disable;
|
||||
goto err_exit_conversion_mode;
|
||||
|
||||
mutex_lock(&st->cnv_pwm_lock);
|
||||
pwm_get_state(st->cnv_pwm, &state);
|
||||
|
|
@ -895,23 +895,16 @@ static int ad4695_offload_buffer_postenable(struct iio_dev *indio_dev)
|
|||
ret = pwm_apply_might_sleep(st->cnv_pwm, &state);
|
||||
mutex_unlock(&st->cnv_pwm_lock);
|
||||
if (ret)
|
||||
goto err_offload_exit_conversion_mode;
|
||||
goto err_offload_trigger_disable;
|
||||
|
||||
return 0;
|
||||
|
||||
err_offload_exit_conversion_mode:
|
||||
/*
|
||||
* We have to unwind in a different order to avoid triggering offload.
|
||||
* ad4695_exit_conversion_mode() triggers a conversion, so it has to be
|
||||
* done after spi_offload_trigger_disable().
|
||||
*/
|
||||
spi_offload_trigger_disable(st->offload, st->offload_trigger);
|
||||
ad4695_exit_conversion_mode(st);
|
||||
goto err_disable_busy_output;
|
||||
|
||||
err_offload_trigger_disable:
|
||||
spi_offload_trigger_disable(st->offload, st->offload_trigger);
|
||||
|
||||
err_exit_conversion_mode:
|
||||
ad4695_exit_conversion_mode(st);
|
||||
|
||||
err_disable_busy_output:
|
||||
regmap_clear_bits(st->regmap, AD4695_REG_GP_MODE,
|
||||
AD4695_REG_GP_MODE_BUSY_GP_EN);
|
||||
|
|
|
|||
|
|
@ -817,9 +817,11 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
|
|||
}
|
||||
|
||||
priv->tsc_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "amlogic,hhi-sysctrl");
|
||||
if (IS_ERR(priv->tsc_regmap))
|
||||
if (IS_ERR(priv->tsc_regmap)) {
|
||||
kfree(buf);
|
||||
return dev_err_probe(dev, PTR_ERR(priv->tsc_regmap),
|
||||
"failed to get amlogic,hhi-sysctrl regmap\n");
|
||||
}
|
||||
|
||||
trimming_bits = priv->param->temperature_trimming_bits;
|
||||
trimming_mask = BIT(trimming_bits) - 1;
|
||||
|
|
|
|||
|
|
@ -497,6 +497,7 @@ static int mt6358_read_imp(struct mt6359_auxadc *adc_dev,
|
|||
return ret;
|
||||
|
||||
/* Read the params before stopping */
|
||||
val_v = 0;
|
||||
regmap_read(regmap, reg_adc0 + (cinfo->imp_adc_num << 1), &val_v);
|
||||
|
||||
mt6358_stop_imp_conv(adc_dev);
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ static int npcm_adc_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(info->reset))
|
||||
return PTR_ERR(info->reset);
|
||||
|
||||
info->adc_clk = devm_clk_get(&pdev->dev, NULL);
|
||||
info->adc_clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(info->adc_clk)) {
|
||||
dev_warn(&pdev->dev, "ADC clock failed: can't read clk\n");
|
||||
return PTR_ERR(info->adc_clk);
|
||||
|
|
@ -244,17 +244,13 @@ static int npcm_adc_probe(struct platform_device *pdev)
|
|||
info->adc_sample_hz = clk_get_rate(info->adc_clk) / ((div + 1) * 2);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
ret = irq;
|
||||
goto err_disable_clk;
|
||||
}
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, npcm_adc_isr, 0,
|
||||
"NPCM_ADC", indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed requesting interrupt\n");
|
||||
goto err_disable_clk;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
reg_con = ioread32(info->regs + NPCM_ADCCON);
|
||||
info->vref = devm_regulator_get_optional(&pdev->dev, "vref");
|
||||
|
|
@ -262,7 +258,7 @@ static int npcm_adc_probe(struct platform_device *pdev)
|
|||
ret = regulator_enable(info->vref);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Can't enable ADC reference voltage\n");
|
||||
goto err_disable_clk;
|
||||
return ret;
|
||||
}
|
||||
|
||||
iowrite32(reg_con & ~NPCM_ADCCON_REFSEL,
|
||||
|
|
@ -272,10 +268,8 @@ static int npcm_adc_probe(struct platform_device *pdev)
|
|||
* Any error which is not ENODEV indicates the regulator
|
||||
* has been specified and so is a failure case.
|
||||
*/
|
||||
if (PTR_ERR(info->vref) != -ENODEV) {
|
||||
ret = PTR_ERR(info->vref);
|
||||
goto err_disable_clk;
|
||||
}
|
||||
if (PTR_ERR(info->vref) != -ENODEV)
|
||||
return PTR_ERR(info->vref);
|
||||
|
||||
/* Use internal reference */
|
||||
iowrite32(reg_con | NPCM_ADCCON_REFSEL,
|
||||
|
|
@ -314,8 +308,6 @@ static int npcm_adc_probe(struct platform_device *pdev)
|
|||
iowrite32(reg_con & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);
|
||||
if (!IS_ERR(info->vref))
|
||||
regulator_disable(info->vref);
|
||||
err_disable_clk:
|
||||
clk_disable_unprepare(info->adc_clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -332,7 +324,6 @@ static void npcm_adc_remove(struct platform_device *pdev)
|
|||
iowrite32(regtemp & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);
|
||||
if (!IS_ERR(info->vref))
|
||||
regulator_disable(info->vref);
|
||||
clk_disable_unprepare(info->adc_clk);
|
||||
}
|
||||
|
||||
static struct platform_driver npcm_adc_driver = {
|
||||
|
|
|
|||
|
|
@ -198,6 +198,15 @@ static void nxp_sar_adc_irq_cfg(struct nxp_sar_adc *info, bool enable)
|
|||
writel(0, NXP_SAR_ADC_IMR(info->regs));
|
||||
}
|
||||
|
||||
static void nxp_sar_adc_wait_for(struct nxp_sar_adc *info, unsigned int cycles)
|
||||
{
|
||||
u64 rate;
|
||||
|
||||
rate = clk_get_rate(info->clk);
|
||||
if (rate)
|
||||
ndelay(div64_u64(NSEC_PER_SEC, rate * cycles));
|
||||
}
|
||||
|
||||
static bool nxp_sar_adc_set_enabled(struct nxp_sar_adc *info, bool enable)
|
||||
{
|
||||
u32 mcr;
|
||||
|
|
@ -221,7 +230,7 @@ static bool nxp_sar_adc_set_enabled(struct nxp_sar_adc *info, bool enable)
|
|||
* configuration of NCMR and the setting of NSTART.
|
||||
*/
|
||||
if (enable)
|
||||
ndelay(div64_u64(NSEC_PER_SEC, clk_get_rate(info->clk) * 3));
|
||||
nxp_sar_adc_wait_for(info, 3);
|
||||
|
||||
return pwdn;
|
||||
}
|
||||
|
|
@ -469,7 +478,7 @@ static void nxp_sar_adc_stop_conversion(struct nxp_sar_adc *info)
|
|||
* only when the capture finishes. The delay will be very
|
||||
* short, usec-ish, which is acceptable in the atomic context.
|
||||
*/
|
||||
ndelay(div64_u64(NSEC_PER_SEC, clk_get_rate(info->clk)) * 80);
|
||||
nxp_sar_adc_wait_for(info, 80);
|
||||
}
|
||||
|
||||
static int nxp_sar_adc_start_conversion(struct nxp_sar_adc *info, bool raw)
|
||||
|
|
@ -560,6 +569,9 @@ static int nxp_sar_adc_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec
|
|||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
if (val <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Configures the sample period duration in terms of the SAR
|
||||
* controller clock. The minimum acceptable value is 8.
|
||||
|
|
@ -568,7 +580,11 @@ static int nxp_sar_adc_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec
|
|||
* sampling timing which gives us the number of cycles expected.
|
||||
* The value is 8-bit wide, consequently the max value is 0xFF.
|
||||
*/
|
||||
inpsamp = clk_get_rate(info->clk) / val - NXP_SAR_ADC_CONV_TIME;
|
||||
inpsamp = clk_get_rate(info->clk) / val;
|
||||
if (inpsamp < NXP_SAR_ADC_CONV_TIME)
|
||||
return -EINVAL;
|
||||
|
||||
inpsamp -= NXP_SAR_ADC_CONV_TIME;
|
||||
nxp_sar_adc_conversion_timing_set(info, inpsamp);
|
||||
return 0;
|
||||
|
||||
|
|
@ -660,7 +676,7 @@ static void nxp_sar_adc_dma_cb(void *data)
|
|||
static int nxp_sar_adc_start_cyclic_dma(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
||||
struct dma_slave_config config;
|
||||
struct dma_slave_config config = { };
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
int ret;
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user