mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
Merge branch 'for-linus' into for-next
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
commit
27ceefc531
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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -482,7 +482,7 @@ static int adc5_gen3_get_fw_channel_data(struct adc5_chip *adc,
|
|||
sid = FIELD_GET(ADC5_GEN3_VIRTUAL_SID_MASK, chan);
|
||||
chan = FIELD_GET(ADC5_GEN3_CHANNEL_MASK, chan);
|
||||
|
||||
if (chan > ADC5_MAX_CHANNEL)
|
||||
if (chan >= ADC5_MAX_CHANNEL)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"%s invalid channel number %d\n",
|
||||
name, chan);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user