mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
Merge tag 'v6.6.66' of git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable into odroid-6.6.y
This is the 6.6.66 stable release Change-Id: Ia568a3963998c89d4ca0cad7e563ac7052f555ce
This commit is contained in:
@@ -163,6 +163,17 @@ Description:
|
||||
will be present in sysfs. Writing 1 to this file
|
||||
will perform reset.
|
||||
|
||||
What: /sys/bus/pci/devices/.../reset_subordinate
|
||||
Date: October 2024
|
||||
Contact: linux-pci@vger.kernel.org
|
||||
Description:
|
||||
This is visible only for bridge devices. If you want to reset
|
||||
all devices attached through the subordinate bus of a specific
|
||||
bridge device, writing 1 to this will try to do it. This will
|
||||
affect all devices attached to the system through this bridge
|
||||
similiar to writing 1 to their individual "reset" file, so use
|
||||
with caution.
|
||||
|
||||
What: /sys/bus/pci/devices/.../vpd
|
||||
Date: February 2008
|
||||
Contact: Ben Hutchings <bwh@kernel.org>
|
||||
|
||||
@@ -328,7 +328,7 @@ as idle::
|
||||
From now on, any pages on zram are idle pages. The idle mark
|
||||
will be removed until someone requests access of the block.
|
||||
IOW, unless there is access request, those pages are still idle pages.
|
||||
Additionally, when CONFIG_ZRAM_MEMORY_TRACKING is enabled pages can be
|
||||
Additionally, when CONFIG_ZRAM_TRACK_ENTRY_ACTIME is enabled pages can be
|
||||
marked as idle based on how long (in seconds) it's been since they were
|
||||
last accessed::
|
||||
|
||||
|
||||
@@ -64,7 +64,12 @@ attribute-sets:
|
||||
name: bits
|
||||
type: nest
|
||||
nested-attributes: bitset-bits
|
||||
|
||||
-
|
||||
name: value
|
||||
type: binary
|
||||
-
|
||||
name: mask
|
||||
type: binary
|
||||
-
|
||||
name: string
|
||||
attributes:
|
||||
|
||||
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 6
|
||||
PATCHLEVEL = 6
|
||||
SUBLEVEL = 65
|
||||
SUBLEVEL = 66
|
||||
EXTRAVERSION =
|
||||
NAME = Pinguïn Aangedreven
|
||||
|
||||
|
||||
@@ -1385,7 +1385,7 @@ static int tagged_addr_ctrl_get(struct task_struct *target,
|
||||
{
|
||||
long ctrl = get_tagged_addr_ctrl(target);
|
||||
|
||||
if (IS_ERR_VALUE(ctrl))
|
||||
if (WARN_ON_ONCE(IS_ERR_VALUE(ctrl)))
|
||||
return ctrl;
|
||||
|
||||
return membuf_write(&to, &ctrl, sizeof(ctrl));
|
||||
@@ -1399,6 +1399,10 @@ static int tagged_addr_ctrl_set(struct task_struct *target, const struct
|
||||
int ret;
|
||||
long ctrl;
|
||||
|
||||
ctrl = get_tagged_addr_ctrl(target);
|
||||
if (WARN_ON_ONCE(IS_ERR_VALUE(ctrl)))
|
||||
return ctrl;
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl, 0, -1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -900,7 +900,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
|
||||
|
||||
if (run->exit_reason == KVM_EXIT_MMIO) {
|
||||
ret = kvm_handle_mmio_return(vcpu);
|
||||
if (ret)
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,31 @@ unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len)
|
||||
return data;
|
||||
}
|
||||
|
||||
static bool kvm_pending_sync_exception(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (!vcpu_get_flag(vcpu, PENDING_EXCEPTION))
|
||||
return false;
|
||||
|
||||
if (vcpu_el1_is_32bit(vcpu)) {
|
||||
switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) {
|
||||
case unpack_vcpu_flag(EXCEPT_AA32_UND):
|
||||
case unpack_vcpu_flag(EXCEPT_AA32_IABT):
|
||||
case unpack_vcpu_flag(EXCEPT_AA32_DABT):
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) {
|
||||
case unpack_vcpu_flag(EXCEPT_AA64_EL1_SYNC):
|
||||
case unpack_vcpu_flag(EXCEPT_AA64_EL2_SYNC):
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
|
||||
* or in-kernel IO emulation
|
||||
@@ -84,9 +109,12 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu)
|
||||
unsigned int len;
|
||||
int mask;
|
||||
|
||||
/* Detect an already handled MMIO return */
|
||||
if (unlikely(!vcpu->mmio_needed))
|
||||
return 0;
|
||||
/*
|
||||
* Detect if the MMIO return was already handled or if userspace aborted
|
||||
* the MMIO access.
|
||||
*/
|
||||
if (unlikely(!vcpu->mmio_needed || kvm_pending_sync_exception(vcpu)))
|
||||
return 1;
|
||||
|
||||
vcpu->mmio_needed = 0;
|
||||
|
||||
@@ -117,7 +145,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu)
|
||||
*/
|
||||
kvm_incr_pc(vcpu);
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
|
||||
|
||||
@@ -32,9 +32,9 @@ static unsigned long nr_pinned_asids;
|
||||
static unsigned long *pinned_asid_map;
|
||||
|
||||
#define ASID_MASK (~GENMASK(asid_bits - 1, 0))
|
||||
#define ASID_FIRST_VERSION (1UL << asid_bits)
|
||||
#define ASID_FIRST_VERSION (1UL << 16)
|
||||
|
||||
#define NUM_USER_ASIDS ASID_FIRST_VERSION
|
||||
#define NUM_USER_ASIDS (1UL << asid_bits)
|
||||
#define ctxid2asid(asid) ((asid) & ~ASID_MASK)
|
||||
#define asid2ctxid(asid, genid) ((asid) | (genid))
|
||||
|
||||
|
||||
@@ -29,6 +29,16 @@ static inline int prepare_hugepage_range(struct file *file,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_HUGE_PTE_CLEAR
|
||||
static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
|
||||
pte_t *ptep, unsigned long sz)
|
||||
{
|
||||
pte_t clear;
|
||||
|
||||
pte_val(clear) = (unsigned long)invalid_pte_table;
|
||||
set_pte_at(mm, addr, ptep, clear);
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR
|
||||
static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
|
||||
unsigned long addr, pte_t *ptep)
|
||||
|
||||
@@ -292,7 +292,7 @@ static void setup_tlb_handler(int cpu)
|
||||
/* Avoid lockdep warning */
|
||||
rcu_cpu_starting(cpu);
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
#if defined(CONFIG_NUMA) && !defined(CONFIG_PREEMPT_RT)
|
||||
vec_sz = sizeof(exception_handlers);
|
||||
|
||||
if (pcpu_handlers[cpu])
|
||||
|
||||
@@ -70,7 +70,6 @@
|
||||
device_type = "pci";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <2>;
|
||||
msi-parent = <&msi>;
|
||||
|
||||
reg = <0 0x1a000000 0 0x02000000>,
|
||||
@@ -234,7 +233,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
pci_bridge@9,0 {
|
||||
pcie@9,0 {
|
||||
compatible = "pci0014,7a19.1",
|
||||
"pci0014,7a19",
|
||||
"pciclass060400",
|
||||
@@ -244,12 +243,16 @@
|
||||
interrupts = <32 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&pic>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &pic 32 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ranges;
|
||||
};
|
||||
|
||||
pci_bridge@a,0 {
|
||||
pcie@a,0 {
|
||||
compatible = "pci0014,7a09.1",
|
||||
"pci0014,7a09",
|
||||
"pciclass060400",
|
||||
@@ -259,12 +262,16 @@
|
||||
interrupts = <33 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&pic>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &pic 33 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ranges;
|
||||
};
|
||||
|
||||
pci_bridge@b,0 {
|
||||
pcie@b,0 {
|
||||
compatible = "pci0014,7a09.1",
|
||||
"pci0014,7a09",
|
||||
"pciclass060400",
|
||||
@@ -274,12 +281,16 @@
|
||||
interrupts = <34 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&pic>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &pic 34 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ranges;
|
||||
};
|
||||
|
||||
pci_bridge@c,0 {
|
||||
pcie@c,0 {
|
||||
compatible = "pci0014,7a09.1",
|
||||
"pci0014,7a09",
|
||||
"pciclass060400",
|
||||
@@ -289,12 +300,16 @@
|
||||
interrupts = <35 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&pic>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &pic 35 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ranges;
|
||||
};
|
||||
|
||||
pci_bridge@d,0 {
|
||||
pcie@d,0 {
|
||||
compatible = "pci0014,7a19.1",
|
||||
"pci0014,7a19",
|
||||
"pciclass060400",
|
||||
@@ -304,12 +319,16 @@
|
||||
interrupts = <36 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&pic>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &pic 36 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ranges;
|
||||
};
|
||||
|
||||
pci_bridge@e,0 {
|
||||
pcie@e,0 {
|
||||
compatible = "pci0014,7a09.1",
|
||||
"pci0014,7a09",
|
||||
"pciclass060400",
|
||||
@@ -319,12 +338,16 @@
|
||||
interrupts = <37 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&pic>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &pic 37 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ranges;
|
||||
};
|
||||
|
||||
pci_bridge@f,0 {
|
||||
pcie@f,0 {
|
||||
compatible = "pci0014,7a29.1",
|
||||
"pci0014,7a29",
|
||||
"pciclass060400",
|
||||
@@ -334,12 +357,16 @@
|
||||
interrupts = <40 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&pic>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &pic 40 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ranges;
|
||||
};
|
||||
|
||||
pci_bridge@10,0 {
|
||||
pcie@10,0 {
|
||||
compatible = "pci0014,7a19.1",
|
||||
"pci0014,7a19",
|
||||
"pciclass060400",
|
||||
@@ -349,12 +376,16 @@
|
||||
interrupts = <41 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&pic>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &pic 41 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ranges;
|
||||
};
|
||||
|
||||
pci_bridge@11,0 {
|
||||
pcie@11,0 {
|
||||
compatible = "pci0014,7a29.1",
|
||||
"pci0014,7a29",
|
||||
"pciclass060400",
|
||||
@@ -364,12 +395,16 @@
|
||||
interrupts = <42 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&pic>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &pic 42 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ranges;
|
||||
};
|
||||
|
||||
pci_bridge@12,0 {
|
||||
pcie@12,0 {
|
||||
compatible = "pci0014,7a19.1",
|
||||
"pci0014,7a19",
|
||||
"pciclass060400",
|
||||
@@ -379,12 +414,16 @@
|
||||
interrupts = <43 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&pic>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &pic 43 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ranges;
|
||||
};
|
||||
|
||||
pci_bridge@13,0 {
|
||||
pcie@13,0 {
|
||||
compatible = "pci0014,7a29.1",
|
||||
"pci0014,7a29",
|
||||
"pciclass060400",
|
||||
@@ -394,12 +433,16 @@
|
||||
interrupts = <38 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&pic>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &pic 38 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ranges;
|
||||
};
|
||||
|
||||
pci_bridge@14,0 {
|
||||
pcie@14,0 {
|
||||
compatible = "pci0014,7a19.1",
|
||||
"pci0014,7a19",
|
||||
"pciclass060400",
|
||||
@@ -409,9 +452,13 @@
|
||||
interrupts = <39 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&pic>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &pic 39 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ranges;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -2924,7 +2924,7 @@ static void __init fixup_device_tree_chrp(void)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PPC64) && defined(CONFIG_PPC_PMAC)
|
||||
static void __init fixup_device_tree_pmac(void)
|
||||
static void __init fixup_device_tree_pmac64(void)
|
||||
{
|
||||
phandle u3, i2c, mpic;
|
||||
u32 u3_rev;
|
||||
@@ -2964,7 +2964,31 @@ static void __init fixup_device_tree_pmac(void)
|
||||
&parent, sizeof(parent));
|
||||
}
|
||||
#else
|
||||
#define fixup_device_tree_pmac()
|
||||
#define fixup_device_tree_pmac64()
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
static void __init fixup_device_tree_pmac(void)
|
||||
{
|
||||
__be32 val = 1;
|
||||
char type[8];
|
||||
phandle node;
|
||||
|
||||
// Some pmacs are missing #size-cells on escc nodes
|
||||
for (node = 0; prom_next_node(&node); ) {
|
||||
type[0] = '\0';
|
||||
prom_getprop(node, "device_type", type, sizeof(type));
|
||||
if (prom_strcmp(type, "escc"))
|
||||
continue;
|
||||
|
||||
if (prom_getproplen(node, "#size-cells") != PROM_ERROR)
|
||||
continue;
|
||||
|
||||
prom_setprop(node, NULL, "#size-cells", &val, sizeof(val));
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline void fixup_device_tree_pmac(void) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PPC_EFIKA
|
||||
@@ -3189,6 +3213,7 @@ static void __init fixup_device_tree(void)
|
||||
fixup_device_tree_maple_memory_controller();
|
||||
fixup_device_tree_chrp();
|
||||
fixup_device_tree_pmac();
|
||||
fixup_device_tree_pmac64();
|
||||
fixup_device_tree_efika();
|
||||
fixup_device_tree_pasemi();
|
||||
}
|
||||
|
||||
@@ -10,28 +10,11 @@ obj-vdso64 = sigtramp64-64.o gettimeofday-64.o datapage-64.o cacheflush-64.o not
|
||||
|
||||
ifneq ($(c-gettimeofday-y),)
|
||||
CFLAGS_vgettimeofday-32.o += -include $(c-gettimeofday-y)
|
||||
CFLAGS_vgettimeofday-32.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
|
||||
CFLAGS_vgettimeofday-32.o += $(call cc-option, -fno-stack-protector)
|
||||
CFLAGS_vgettimeofday-32.o += -DDISABLE_BRANCH_PROFILING
|
||||
CFLAGS_vgettimeofday-32.o += -ffreestanding -fasynchronous-unwind-tables
|
||||
CFLAGS_REMOVE_vgettimeofday-32.o = $(CC_FLAGS_FTRACE)
|
||||
CFLAGS_REMOVE_vgettimeofday-32.o += -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc
|
||||
# This flag is supported by clang for 64-bit but not 32-bit so it will cause
|
||||
# an unused command line flag warning for this file.
|
||||
ifdef CONFIG_CC_IS_CLANG
|
||||
CFLAGS_REMOVE_vgettimeofday-32.o += -fno-stack-clash-protection
|
||||
endif
|
||||
CFLAGS_vgettimeofday-64.o += -include $(c-gettimeofday-y)
|
||||
CFLAGS_vgettimeofday-64.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
|
||||
CFLAGS_vgettimeofday-64.o += $(call cc-option, -fno-stack-protector)
|
||||
CFLAGS_vgettimeofday-64.o += -DDISABLE_BRANCH_PROFILING
|
||||
CFLAGS_vgettimeofday-64.o += -ffreestanding -fasynchronous-unwind-tables
|
||||
CFLAGS_REMOVE_vgettimeofday-64.o = $(CC_FLAGS_FTRACE)
|
||||
# Go prior to 1.16.x assumes r30 is not clobbered by any VDSO code. That used to be true
|
||||
# by accident when the VDSO was hand-written asm code, but may not be now that the VDSO is
|
||||
# compiler generated. To avoid breaking Go tell GCC not to use r30. Impact on code
|
||||
# generation is minimal, it will just use r29 instead.
|
||||
CFLAGS_vgettimeofday-64.o += $(call cc-option, -ffixed-r30)
|
||||
CFLAGS_vgettimeofday-64.o += -include $(c-gettimeofday-y) $(call cc-option, -ffixed-r30)
|
||||
endif
|
||||
|
||||
# Build rules
|
||||
@@ -54,6 +37,11 @@ KASAN_SANITIZE := n
|
||||
KCSAN_SANITIZE := n
|
||||
|
||||
ccflags-y := -fno-common -fno-builtin
|
||||
ccflags-y += $(DISABLE_LATENT_ENTROPY_PLUGIN)
|
||||
ccflags-y += $(call cc-option, -fno-stack-protector)
|
||||
ccflags-y += -DDISABLE_BRANCH_PROFILING
|
||||
ccflags-y += -ffreestanding -fasynchronous-unwind-tables
|
||||
ccflags-remove-y := $(CC_FLAGS_FTRACE)
|
||||
ldflags-y := -Wl,--hash-style=both -nostdlib -shared -z noexecstack $(CLANG_FLAGS)
|
||||
ldflags-$(CONFIG_LD_IS_LLD) += $(call cc-option,--ld-path=$(LD),-fuse-ld=lld)
|
||||
ldflags-$(CONFIG_LD_ORPHAN_WARN) += -Wl,--orphan-handling=$(CONFIG_LD_ORPHAN_WARN_LEVEL)
|
||||
@@ -62,6 +50,16 @@ ldflags-$(CONFIG_LD_ORPHAN_WARN) += -Wl,--orphan-handling=$(CONFIG_LD_ORPHAN_WAR
|
||||
ldflags-y += $(filter-out $(CC_AUTO_VAR_INIT_ZERO_ENABLER) $(CC_FLAGS_FTRACE) -Wa$(comma)%, $(KBUILD_CFLAGS))
|
||||
|
||||
CC32FLAGS := -m32
|
||||
CC32FLAGSREMOVE := -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc
|
||||
ifdef CONFIG_CC_IS_CLANG
|
||||
# This flag is supported by clang for 64-bit but not 32-bit so it will cause
|
||||
# an unused command line flag warning for this file.
|
||||
CC32FLAGSREMOVE += -fno-stack-clash-protection
|
||||
# -mstack-protector-guard values from the 64-bit build are not valid for the
|
||||
# 32-bit one. clang validates the values passed to these arguments during
|
||||
# parsing, even when -fno-stack-protector is passed afterwards.
|
||||
CC32FLAGSREMOVE += -mstack-protector-guard%
|
||||
endif
|
||||
LD32FLAGS := -Wl,-soname=linux-vdso32.so.1
|
||||
AS32FLAGS := -D__VDSO32__
|
||||
|
||||
@@ -108,7 +106,7 @@ quiet_cmd_vdso32ld_and_check = VDSO32L $@
|
||||
quiet_cmd_vdso32as = VDSO32A $@
|
||||
cmd_vdso32as = $(VDSOCC) $(a_flags) $(CC32FLAGS) $(AS32FLAGS) -c -o $@ $<
|
||||
quiet_cmd_vdso32cc = VDSO32C $@
|
||||
cmd_vdso32cc = $(VDSOCC) $(c_flags) $(CC32FLAGS) -c -o $@ $<
|
||||
cmd_vdso32cc = $(VDSOCC) $(filter-out $(CC32FLAGSREMOVE), $(c_flags)) $(CC32FLAGS) -c -o $@ $<
|
||||
|
||||
quiet_cmd_vdso64ld_and_check = VDSO64L $@
|
||||
cmd_vdso64ld_and_check = $(VDSOCC) $(ldflags-y) $(LD64FLAGS) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^); $(cmd_vdso_check)
|
||||
|
||||
@@ -1922,7 +1922,9 @@ static void cpumsf_pmu_stop(struct perf_event *event, int flags)
|
||||
event->hw.state |= PERF_HES_STOPPED;
|
||||
|
||||
if ((flags & PERF_EF_UPDATE) && !(event->hw.state & PERF_HES_UPTODATE)) {
|
||||
hw_perf_event_update(event, 1);
|
||||
/* CPU hotplug off removes SDBs. No samples to extract. */
|
||||
if (cpuhw->flags & PMU_F_RESERVED)
|
||||
hw_perf_event_update(event, 1);
|
||||
event->hw.state |= PERF_HES_UPTODATE;
|
||||
}
|
||||
perf_pmu_enable(event->pmu);
|
||||
|
||||
@@ -895,11 +895,12 @@ static int amd_pmu_handle_irq(struct pt_regs *regs)
|
||||
static int amd_pmu_v2_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
|
||||
static atomic64_t status_warned = ATOMIC64_INIT(0);
|
||||
u64 reserved, status, mask, new_bits, prev_bits;
|
||||
struct perf_sample_data data;
|
||||
struct hw_perf_event *hwc;
|
||||
struct perf_event *event;
|
||||
int handled = 0, idx;
|
||||
u64 reserved, status, mask;
|
||||
bool pmu_enabled;
|
||||
|
||||
/*
|
||||
@@ -964,7 +965,12 @@ static int amd_pmu_v2_handle_irq(struct pt_regs *regs)
|
||||
* the corresponding PMCs are expected to be inactive according to the
|
||||
* active_mask
|
||||
*/
|
||||
WARN_ON(status > 0);
|
||||
if (status > 0) {
|
||||
prev_bits = atomic64_fetch_or(status, &status_warned);
|
||||
// A new bit was set for the very first time.
|
||||
new_bits = status & ~prev_bits;
|
||||
WARN(new_bits, "New overflows for inactive PMCs: %llx\n", new_bits);
|
||||
}
|
||||
|
||||
/* Clear overflow and freeze bits */
|
||||
amd_pmu_ack_global_status(~status);
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
#define _PAGE_BIT_DEVMAP _PAGE_BIT_SOFTW4
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW5 /* Saved Dirty bit */
|
||||
#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW5 /* Saved Dirty bit (leaf) */
|
||||
#define _PAGE_BIT_NOPTISHADOW _PAGE_BIT_SOFTW5 /* No PTI shadow (root PGD) */
|
||||
#else
|
||||
/* Shared with _PAGE_BIT_UFFD_WP which is not supported on 32 bit */
|
||||
#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW2 /* Saved Dirty bit */
|
||||
#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW2 /* Saved Dirty bit (leaf) */
|
||||
#define _PAGE_BIT_NOPTISHADOW _PAGE_BIT_SOFTW2 /* No PTI shadow (root PGD) */
|
||||
#endif
|
||||
|
||||
/* If _PAGE_BIT_PRESENT is clear, we use these: */
|
||||
@@ -139,6 +141,8 @@
|
||||
|
||||
#define _PAGE_PROTNONE (_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE)
|
||||
|
||||
#define _PAGE_NOPTISHADOW (_AT(pteval_t, 1) << _PAGE_BIT_NOPTISHADOW)
|
||||
|
||||
/*
|
||||
* Set of bits not changed in pte_modify. The pte's
|
||||
* protection key is treated like _PAGE_RW, for
|
||||
|
||||
@@ -1205,7 +1205,7 @@ static void init_amd(struct cpuinfo_x86 *c)
|
||||
*/
|
||||
if (spectre_v2_in_eibrs_mode(spectre_v2_enabled) &&
|
||||
cpu_has(c, X86_FEATURE_AUTOIBRS))
|
||||
WARN_ON_ONCE(msr_set_bit(MSR_EFER, _EFER_AUTOIBRS));
|
||||
WARN_ON_ONCE(msr_set_bit(MSR_EFER, _EFER_AUTOIBRS) < 0);
|
||||
|
||||
if (!cpu_has(c, X86_FEATURE_HYPERVISOR) &&
|
||||
cpu_has_amd_erratum(c, amd_erratum_1485))
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <asm/pgtable_types.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/unwind_hints.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
/*
|
||||
* Must be relocatable PIC code callable as a C function, in particular
|
||||
@@ -240,6 +241,13 @@ SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
|
||||
movq CR0(%r8), %r8
|
||||
movq %rax, %cr3
|
||||
movq %r8, %cr0
|
||||
|
||||
#ifdef CONFIG_KEXEC_JUMP
|
||||
/* Saved in save_processor_state. */
|
||||
movq $saved_context, %rax
|
||||
lgdt saved_context_gdt_desc(%rax)
|
||||
#endif
|
||||
|
||||
movq %rbp, %rax
|
||||
|
||||
popf
|
||||
|
||||
@@ -4363,6 +4363,7 @@ static bool is_page_fault_stale(struct kvm_vcpu *vcpu,
|
||||
|
||||
static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
|
||||
{
|
||||
kvm_pfn_t orig_pfn;
|
||||
int r;
|
||||
|
||||
/* Dummy roots are used only for shadowing bad guest roots. */
|
||||
@@ -4384,6 +4385,8 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
|
||||
if (r != RET_PF_CONTINUE)
|
||||
return r;
|
||||
|
||||
orig_pfn = fault->pfn;
|
||||
|
||||
r = RET_PF_RETRY;
|
||||
write_lock(&vcpu->kvm->mmu_lock);
|
||||
|
||||
@@ -4398,7 +4401,7 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
|
||||
|
||||
out_unlock:
|
||||
write_unlock(&vcpu->kvm->mmu_lock);
|
||||
kvm_release_pfn_clean(fault->pfn);
|
||||
kvm_release_pfn_clean(orig_pfn);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -4447,6 +4450,7 @@ EXPORT_SYMBOL_GPL(kvm_handle_page_fault);
|
||||
static int kvm_tdp_mmu_page_fault(struct kvm_vcpu *vcpu,
|
||||
struct kvm_page_fault *fault)
|
||||
{
|
||||
kvm_pfn_t orig_pfn;
|
||||
int r;
|
||||
|
||||
if (page_fault_handle_page_track(vcpu, fault))
|
||||
@@ -4464,6 +4468,8 @@ static int kvm_tdp_mmu_page_fault(struct kvm_vcpu *vcpu,
|
||||
if (r != RET_PF_CONTINUE)
|
||||
return r;
|
||||
|
||||
orig_pfn = fault->pfn;
|
||||
|
||||
r = RET_PF_RETRY;
|
||||
read_lock(&vcpu->kvm->mmu_lock);
|
||||
|
||||
@@ -4474,7 +4480,7 @@ static int kvm_tdp_mmu_page_fault(struct kvm_vcpu *vcpu,
|
||||
|
||||
out_unlock:
|
||||
read_unlock(&vcpu->kvm->mmu_lock);
|
||||
kvm_release_pfn_clean(fault->pfn);
|
||||
kvm_release_pfn_clean(orig_pfn);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -777,6 +777,7 @@ out_gpte_changed:
|
||||
static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
|
||||
{
|
||||
struct guest_walker walker;
|
||||
kvm_pfn_t orig_pfn;
|
||||
int r;
|
||||
|
||||
WARN_ON_ONCE(fault->is_tdp);
|
||||
@@ -835,6 +836,8 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
|
||||
walker.pte_access &= ~ACC_EXEC_MASK;
|
||||
}
|
||||
|
||||
orig_pfn = fault->pfn;
|
||||
|
||||
r = RET_PF_RETRY;
|
||||
write_lock(&vcpu->kvm->mmu_lock);
|
||||
|
||||
@@ -848,7 +851,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
|
||||
|
||||
out_unlock:
|
||||
write_unlock(&vcpu->kvm->mmu_lock);
|
||||
kvm_release_pfn_clean(fault->pfn);
|
||||
kvm_release_pfn_clean(orig_pfn);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ static int ident_p4d_init(struct x86_mapping_info *info, p4d_t *p4d_page,
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
set_p4d(p4d, __p4d(__pa(pud) | info->kernpg_flag));
|
||||
set_p4d(p4d, __p4d(__pa(pud) | info->kernpg_flag | _PAGE_NOPTISHADOW));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -132,14 +132,14 @@ int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
|
||||
if (result)
|
||||
return result;
|
||||
if (pgtable_l5_enabled()) {
|
||||
set_pgd(pgd, __pgd(__pa(p4d) | info->kernpg_flag));
|
||||
set_pgd(pgd, __pgd(__pa(p4d) | info->kernpg_flag | _PAGE_NOPTISHADOW));
|
||||
} else {
|
||||
/*
|
||||
* With p4d folded, pgd is equal to p4d.
|
||||
* The pgd entry has to point to the pud page table in this case.
|
||||
*/
|
||||
pud_t *pud = pud_offset(p4d, 0);
|
||||
set_pgd(pgd, __pgd(__pa(pud) | info->kernpg_flag));
|
||||
set_pgd(pgd, __pgd(__pa(pud) | info->kernpg_flag | _PAGE_NOPTISHADOW));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ pgd_t __pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd)
|
||||
* Top-level entries added to init_mm's usermode pgd after boot
|
||||
* will not be automatically propagated to other mms.
|
||||
*/
|
||||
if (!pgdp_maps_userspace(pgdp))
|
||||
if (!pgdp_maps_userspace(pgdp) || (pgd.pgd & _PAGE_NOPTISHADOW))
|
||||
return pgd;
|
||||
|
||||
/*
|
||||
|
||||
@@ -250,6 +250,125 @@ void __init pci_acpi_crs_quirks(void)
|
||||
pr_info("Please notify linux-pci@vger.kernel.org so future kernels can do this automatically\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if pdev is part of a PCIe switch that is directly below the
|
||||
* specified bridge.
|
||||
*/
|
||||
static bool pcie_switch_directly_under(struct pci_dev *bridge,
|
||||
struct pci_dev *pdev)
|
||||
{
|
||||
struct pci_dev *parent = pci_upstream_bridge(pdev);
|
||||
|
||||
/* If the device doesn't have a parent, it's not under anything */
|
||||
if (!parent)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* If the device has a PCIe type, check if it is below the
|
||||
* corresponding PCIe switch components (if applicable). Then check
|
||||
* if its upstream port is directly beneath the specified bridge.
|
||||
*/
|
||||
switch (pci_pcie_type(pdev)) {
|
||||
case PCI_EXP_TYPE_UPSTREAM:
|
||||
return parent == bridge;
|
||||
|
||||
case PCI_EXP_TYPE_DOWNSTREAM:
|
||||
if (pci_pcie_type(parent) != PCI_EXP_TYPE_UPSTREAM)
|
||||
return false;
|
||||
parent = pci_upstream_bridge(parent);
|
||||
return parent == bridge;
|
||||
|
||||
case PCI_EXP_TYPE_ENDPOINT:
|
||||
if (pci_pcie_type(parent) != PCI_EXP_TYPE_DOWNSTREAM)
|
||||
return false;
|
||||
parent = pci_upstream_bridge(parent);
|
||||
if (!parent || pci_pcie_type(parent) != PCI_EXP_TYPE_UPSTREAM)
|
||||
return false;
|
||||
parent = pci_upstream_bridge(parent);
|
||||
return parent == bridge;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool pcie_has_usb4_host_interface(struct pci_dev *pdev)
|
||||
{
|
||||
struct fwnode_handle *fwnode;
|
||||
|
||||
/*
|
||||
* For USB4, the tunneled PCIe Root or Downstream Ports are marked
|
||||
* with the "usb4-host-interface" ACPI property, so we look for
|
||||
* that first. This should cover most cases.
|
||||
*/
|
||||
fwnode = fwnode_find_reference(dev_fwnode(&pdev->dev),
|
||||
"usb4-host-interface", 0);
|
||||
if (!IS_ERR(fwnode)) {
|
||||
fwnode_handle_put(fwnode);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any integrated Thunderbolt 3/4 PCIe Root Ports from Intel
|
||||
* before Alder Lake do not have the "usb4-host-interface"
|
||||
* property so we use their PCI IDs instead. All these are
|
||||
* tunneled. This list is not expected to grow.
|
||||
*/
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
|
||||
switch (pdev->device) {
|
||||
/* Ice Lake Thunderbolt 3 PCIe Root Ports */
|
||||
case 0x8a1d:
|
||||
case 0x8a1f:
|
||||
case 0x8a21:
|
||||
case 0x8a23:
|
||||
/* Tiger Lake-LP Thunderbolt 4 PCIe Root Ports */
|
||||
case 0x9a23:
|
||||
case 0x9a25:
|
||||
case 0x9a27:
|
||||
case 0x9a29:
|
||||
/* Tiger Lake-H Thunderbolt 4 PCIe Root Ports */
|
||||
case 0x9a2b:
|
||||
case 0x9a2d:
|
||||
case 0x9a2f:
|
||||
case 0x9a31:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool arch_pci_dev_is_removable(struct pci_dev *pdev)
|
||||
{
|
||||
struct pci_dev *parent, *root;
|
||||
|
||||
/* pdev without a parent or Root Port is never tunneled */
|
||||
parent = pci_upstream_bridge(pdev);
|
||||
if (!parent)
|
||||
return false;
|
||||
root = pcie_find_root_port(pdev);
|
||||
if (!root)
|
||||
return false;
|
||||
|
||||
/* Internal PCIe devices are not tunneled */
|
||||
if (!root->external_facing)
|
||||
return false;
|
||||
|
||||
/* Anything directly behind a "usb4-host-interface" is tunneled */
|
||||
if (pcie_has_usb4_host_interface(parent))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Check if this is a discrete Thunderbolt/USB4 controller that is
|
||||
* directly behind the non-USB4 PCIe Root Port marked as
|
||||
* "ExternalFacingPort". Those are not behind a PCIe tunnel.
|
||||
*/
|
||||
if (pcie_switch_directly_under(root, pdev))
|
||||
return false;
|
||||
|
||||
/* PCIe devices after the discrete chip are tunneled */
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_MMCONFIG
|
||||
static int check_segment(u16 seg, struct device *dev, char *estr)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/cpu_device_id.h>
|
||||
#include <asm/intel-family.h>
|
||||
@@ -287,6 +288,7 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
|
||||
/*
|
||||
* 2. Devices which also have the skip i2c/serdev quirks and which
|
||||
* need the x86-android-tablets module to properly work.
|
||||
* Sorted alphabetically.
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_X86_ANDROID_TABLETS)
|
||||
{
|
||||
@@ -300,6 +302,19 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
|
||||
ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS),
|
||||
},
|
||||
{
|
||||
/* Acer Iconia One 8 A1-840 (non FHD version) */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "BayTrail"),
|
||||
/* Above strings are too generic also match BIOS date */
|
||||
DMI_MATCH(DMI_BIOS_DATE, "04/01/2014"),
|
||||
},
|
||||
.driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |
|
||||
ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY |
|
||||
ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS),
|
||||
},
|
||||
{
|
||||
/* Asus ME176C tablet */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"),
|
||||
@@ -309,6 +324,16 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
|
||||
ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY |
|
||||
ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS),
|
||||
},
|
||||
{
|
||||
/* Asus TF103C transformer 2-in-1 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"),
|
||||
},
|
||||
.driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |
|
||||
ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY |
|
||||
ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS),
|
||||
},
|
||||
{
|
||||
/* Lenovo Yoga Book X90F/L */
|
||||
.matches = {
|
||||
@@ -321,15 +346,6 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
|
||||
ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY |
|
||||
ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS),
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"),
|
||||
},
|
||||
.driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |
|
||||
ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY |
|
||||
ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS),
|
||||
},
|
||||
{
|
||||
/* Lenovo Yoga Tablet 2 1050F/L */
|
||||
.matches = {
|
||||
@@ -384,6 +400,19 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
|
||||
.driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |
|
||||
ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY),
|
||||
},
|
||||
{
|
||||
/* Vexia Edu Atla 10 tablet 9V version */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
|
||||
/* Above strings are too generic, also match on BIOS date */
|
||||
DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"),
|
||||
},
|
||||
.driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |
|
||||
ACPI_QUIRK_UART1_SKIP |
|
||||
ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY |
|
||||
ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS),
|
||||
},
|
||||
{
|
||||
/* Whitelabel (sold as various brands) TM800A550L */
|
||||
.matches = {
|
||||
@@ -404,6 +433,7 @@ static const struct acpi_device_id i2c_acpi_known_good_ids[] = {
|
||||
{ "10EC5640", 0 }, /* RealTek ALC5640 audio codec */
|
||||
{ "10EC5651", 0 }, /* RealTek ALC5651 audio codec */
|
||||
{ "INT33F4", 0 }, /* X-Powers AXP288 PMIC */
|
||||
{ "INT33F5", 0 }, /* TI Dollar Cove PMIC */
|
||||
{ "INT33FD", 0 }, /* Intel Crystal Cove PMIC */
|
||||
{ "INT34D3", 0 }, /* Intel Whiskey Cove PMIC */
|
||||
{ "NPCE69A", 0 }, /* Asus Transformer keyboard dock */
|
||||
@@ -432,18 +462,35 @@ static int acpi_dmi_skip_serdev_enumeration(struct device *controller_parent, bo
|
||||
struct acpi_device *adev = ACPI_COMPANION(controller_parent);
|
||||
const struct dmi_system_id *dmi_id;
|
||||
long quirks = 0;
|
||||
u64 uid;
|
||||
int ret;
|
||||
|
||||
ret = acpi_dev_uid_to_integer(adev, &uid);
|
||||
if (ret)
|
||||
return 0;
|
||||
u64 uid = 0;
|
||||
|
||||
dmi_id = dmi_first_match(acpi_quirk_skip_dmi_ids);
|
||||
if (dmi_id)
|
||||
quirks = (unsigned long)dmi_id->driver_data;
|
||||
if (!dmi_id)
|
||||
return 0;
|
||||
|
||||
if (!dev_is_platform(controller_parent)) {
|
||||
quirks = (unsigned long)dmi_id->driver_data;
|
||||
|
||||
/* uid is left at 0 on errors and 0 is not a valid UART UID */
|
||||
acpi_dev_uid_to_integer(adev, &uid);
|
||||
|
||||
/* For PCI UARTs without an UID */
|
||||
if (!uid && dev_is_pci(controller_parent)) {
|
||||
struct pci_dev *pdev = to_pci_dev(controller_parent);
|
||||
|
||||
/*
|
||||
* Devfn values for PCI UARTs on Bay Trail SoCs, which are
|
||||
* the only devices where this fallback is necessary.
|
||||
*/
|
||||
if (pdev->devfn == PCI_DEVFN(0x1e, 3))
|
||||
uid = 1;
|
||||
else if (pdev->devfn == PCI_DEVFN(0x1e, 4))
|
||||
uid = 2;
|
||||
}
|
||||
|
||||
if (!uid)
|
||||
return 0;
|
||||
|
||||
if (!dev_is_platform(controller_parent) && !dev_is_pci(controller_parent)) {
|
||||
/* PNP enumerated UARTs */
|
||||
if ((quirks & ACPI_QUIRK_PNP_UART1_SKIP) && uid == 1)
|
||||
*skip = true;
|
||||
|
||||
@@ -58,7 +58,7 @@ bool last_level_cache_is_valid(unsigned int cpu)
|
||||
{
|
||||
struct cacheinfo *llc;
|
||||
|
||||
if (!cache_leaves(cpu))
|
||||
if (!cache_leaves(cpu) || !per_cpu_cacheinfo(cpu))
|
||||
return false;
|
||||
|
||||
llc = per_cpu_cacheinfo_idx(cpu, cache_leaves(cpu) - 1);
|
||||
@@ -478,11 +478,9 @@ int __weak populate_cache_leaves(unsigned int cpu)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static inline
|
||||
int allocate_cache_info(int cpu)
|
||||
static inline int allocate_cache_info(int cpu)
|
||||
{
|
||||
per_cpu_cacheinfo(cpu) = kcalloc(cache_leaves(cpu),
|
||||
sizeof(struct cacheinfo), GFP_ATOMIC);
|
||||
per_cpu_cacheinfo(cpu) = kcalloc(cache_leaves(cpu), sizeof(struct cacheinfo), GFP_ATOMIC);
|
||||
if (!per_cpu_cacheinfo(cpu)) {
|
||||
cache_leaves(cpu) = 0;
|
||||
return -ENOMEM;
|
||||
@@ -554,7 +552,11 @@ static inline int init_level_allocate_ci(unsigned int cpu)
|
||||
*/
|
||||
ci_cacheinfo(cpu)->early_ci_levels = false;
|
||||
|
||||
if (cache_leaves(cpu) <= early_leaves)
|
||||
/*
|
||||
* Some architectures (e.g., x86) do not use early initialization.
|
||||
* Allocate memory now in such case.
|
||||
*/
|
||||
if (cache_leaves(cpu) <= early_leaves && per_cpu_cacheinfo(cpu))
|
||||
return 0;
|
||||
|
||||
kfree(per_cpu_cacheinfo(cpu));
|
||||
|
||||
@@ -125,7 +125,7 @@ static void __fwnode_link_del(struct fwnode_link *link)
|
||||
*/
|
||||
static void __fwnode_link_cycle(struct fwnode_link *link)
|
||||
{
|
||||
pr_debug("%pfwf: Relaxing link with %pfwf\n",
|
||||
pr_debug("%pfwf: cycle: depends on %pfwf\n",
|
||||
link->consumer, link->supplier);
|
||||
link->flags |= FWLINK_FLAG_CYCLE;
|
||||
}
|
||||
@@ -1025,7 +1025,8 @@ static struct fwnode_handle *fwnode_links_check_suppliers(
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(link, &fwnode->suppliers, c_hook)
|
||||
if (!(link->flags & FWLINK_FLAG_CYCLE))
|
||||
if (!(link->flags &
|
||||
(FWLINK_FLAG_CYCLE | FWLINK_FLAG_IGNORE)))
|
||||
return link->supplier;
|
||||
|
||||
return NULL;
|
||||
@@ -1935,10 +1936,10 @@ static bool fwnode_ancestor_init_without_drv(struct fwnode_handle *fwnode)
|
||||
*
|
||||
* Return true if one or more cycles were found. Otherwise, return false.
|
||||
*/
|
||||
static bool __fw_devlink_relax_cycles(struct device *con,
|
||||
static bool __fw_devlink_relax_cycles(struct fwnode_handle *con_handle,
|
||||
struct fwnode_handle *sup_handle)
|
||||
{
|
||||
struct device *sup_dev = NULL, *par_dev = NULL;
|
||||
struct device *sup_dev = NULL, *par_dev = NULL, *con_dev = NULL;
|
||||
struct fwnode_link *link;
|
||||
struct device_link *dev_link;
|
||||
bool ret = false;
|
||||
@@ -1955,27 +1956,31 @@ static bool __fw_devlink_relax_cycles(struct device *con,
|
||||
|
||||
sup_handle->flags |= FWNODE_FLAG_VISITED;
|
||||
|
||||
sup_dev = get_dev_from_fwnode(sup_handle);
|
||||
|
||||
/* Termination condition. */
|
||||
if (sup_dev == con) {
|
||||
if (sup_handle == con_handle) {
|
||||
pr_debug("----- cycle: start -----\n");
|
||||
ret = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sup_dev = get_dev_from_fwnode(sup_handle);
|
||||
con_dev = get_dev_from_fwnode(con_handle);
|
||||
/*
|
||||
* If sup_dev is bound to a driver and @con hasn't started binding to a
|
||||
* driver, sup_dev can't be a consumer of @con. So, no need to check
|
||||
* further.
|
||||
*/
|
||||
if (sup_dev && sup_dev->links.status == DL_DEV_DRIVER_BOUND &&
|
||||
con->links.status == DL_DEV_NO_DRIVER) {
|
||||
con_dev && con_dev->links.status == DL_DEV_NO_DRIVER) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_for_each_entry(link, &sup_handle->suppliers, c_hook) {
|
||||
if (__fw_devlink_relax_cycles(con, link->supplier)) {
|
||||
if (link->flags & FWLINK_FLAG_IGNORE)
|
||||
continue;
|
||||
|
||||
if (__fw_devlink_relax_cycles(con_handle, link->supplier)) {
|
||||
__fwnode_link_cycle(link);
|
||||
ret = true;
|
||||
}
|
||||
@@ -1990,8 +1995,11 @@ static bool __fw_devlink_relax_cycles(struct device *con,
|
||||
else
|
||||
par_dev = fwnode_get_next_parent_dev(sup_handle);
|
||||
|
||||
if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode))
|
||||
if (par_dev && __fw_devlink_relax_cycles(con_handle, par_dev->fwnode)) {
|
||||
pr_debug("%pfwf: cycle: child of %pfwf\n", sup_handle,
|
||||
par_dev->fwnode);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (!sup_dev)
|
||||
goto out;
|
||||
@@ -2005,8 +2013,10 @@ static bool __fw_devlink_relax_cycles(struct device *con,
|
||||
!(dev_link->flags & DL_FLAG_CYCLE))
|
||||
continue;
|
||||
|
||||
if (__fw_devlink_relax_cycles(con,
|
||||
if (__fw_devlink_relax_cycles(con_handle,
|
||||
dev_link->supplier->fwnode)) {
|
||||
pr_debug("%pfwf: cycle: depends on %pfwf\n", sup_handle,
|
||||
dev_link->supplier->fwnode);
|
||||
fw_devlink_relax_link(dev_link);
|
||||
dev_link->flags |= DL_FLAG_CYCLE;
|
||||
ret = true;
|
||||
@@ -2048,10 +2058,8 @@ static int fw_devlink_create_devlink(struct device *con,
|
||||
int ret = 0;
|
||||
u32 flags;
|
||||
|
||||
if (con->fwnode == link->consumer)
|
||||
flags = fw_devlink_get_flags(link->flags);
|
||||
else
|
||||
flags = FW_DEVLINK_FLAGS_PERMISSIVE;
|
||||
if (link->flags & FWLINK_FLAG_IGNORE)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* In some cases, a device P might also be a supplier to its child node
|
||||
@@ -2073,24 +2081,23 @@ static int fw_devlink_create_devlink(struct device *con,
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* SYNC_STATE_ONLY device links don't block probing and supports cycles.
|
||||
* So, one might expect that cycle detection isn't necessary for them.
|
||||
* However, if the device link was marked as SYNC_STATE_ONLY because
|
||||
* it's part of a cycle, then we still need to do cycle detection. This
|
||||
* is because the consumer and supplier might be part of multiple cycles
|
||||
* and we need to detect all those cycles.
|
||||
* Don't try to optimize by not calling the cycle detection logic under
|
||||
* certain conditions. There's always some corner case that won't get
|
||||
* detected.
|
||||
*/
|
||||
if (!device_link_flag_is_sync_state_only(flags) ||
|
||||
flags & DL_FLAG_CYCLE) {
|
||||
device_links_write_lock();
|
||||
if (__fw_devlink_relax_cycles(con, sup_handle)) {
|
||||
__fwnode_link_cycle(link);
|
||||
flags = fw_devlink_get_flags(link->flags);
|
||||
dev_info(con, "Fixed dependency cycle(s) with %pfwf\n",
|
||||
sup_handle);
|
||||
}
|
||||
device_links_write_unlock();
|
||||
device_links_write_lock();
|
||||
if (__fw_devlink_relax_cycles(link->consumer, sup_handle)) {
|
||||
__fwnode_link_cycle(link);
|
||||
pr_debug("----- cycle: end -----\n");
|
||||
pr_info("%pfwf: Fixed dependency cycle(s) with %pfwf\n",
|
||||
link->consumer, sup_handle);
|
||||
}
|
||||
device_links_write_unlock();
|
||||
|
||||
if (con->fwnode == link->consumer)
|
||||
flags = fw_devlink_get_flags(link->flags);
|
||||
else
|
||||
flags = FW_DEVLINK_FLAGS_PERMISSIVE;
|
||||
|
||||
if (sup_handle->flags & FWNODE_FLAG_NOT_DEVICE)
|
||||
sup_dev = fwnode_get_next_parent_dev(sup_handle);
|
||||
|
||||
@@ -59,6 +59,7 @@ struct regmap {
|
||||
unsigned long raw_spinlock_flags;
|
||||
};
|
||||
};
|
||||
struct lock_class_key *lock_key;
|
||||
regmap_lock lock;
|
||||
regmap_unlock unlock;
|
||||
void *lock_arg; /* This is passed to lock/unlock functions */
|
||||
|
||||
@@ -356,6 +356,9 @@ static int regcache_maple_init(struct regmap *map)
|
||||
|
||||
mt_init(mt);
|
||||
|
||||
if (!mt_external_lock(mt) && map->lock_key)
|
||||
lockdep_set_class_and_subclass(&mt->ma_lock, map->lock_key, 1);
|
||||
|
||||
if (!map->num_reg_defaults)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -598,6 +598,17 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_attach_dev);
|
||||
|
||||
static int dev_get_regmap_match(struct device *dev, void *res, void *data);
|
||||
|
||||
static int regmap_detach_dev(struct device *dev, struct regmap *map)
|
||||
{
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
return devres_release(dev, dev_get_regmap_release,
|
||||
dev_get_regmap_match, (void *)map->name);
|
||||
}
|
||||
|
||||
static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus,
|
||||
const struct regmap_config *config)
|
||||
{
|
||||
@@ -745,6 +756,7 @@ struct regmap *__regmap_init(struct device *dev,
|
||||
lock_key, lock_name);
|
||||
}
|
||||
map->lock_arg = map;
|
||||
map->lock_key = lock_key;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1442,6 +1454,7 @@ void regmap_exit(struct regmap *map)
|
||||
{
|
||||
struct regmap_async *async;
|
||||
|
||||
regmap_detach_dev(map->dev, map);
|
||||
regcache_exit(map);
|
||||
regmap_debugfs_exit(map);
|
||||
regmap_range_exit(map);
|
||||
|
||||
@@ -69,9 +69,18 @@ config ZRAM_WRITEBACK
|
||||
|
||||
See Documentation/admin-guide/blockdev/zram.rst for more information.
|
||||
|
||||
config ZRAM_TRACK_ENTRY_ACTIME
|
||||
bool "Track access time of zram entries"
|
||||
depends on ZRAM
|
||||
help
|
||||
With this feature zram tracks access time of every stored
|
||||
entry (page), which can be used for a more fine grained IDLE
|
||||
pages writeback.
|
||||
|
||||
config ZRAM_MEMORY_TRACKING
|
||||
bool "Track zRam block status"
|
||||
depends on ZRAM && DEBUG_FS
|
||||
select ZRAM_TRACK_ENTRY_ACTIME
|
||||
help
|
||||
With this feature, admin can track the state of allocated blocks
|
||||
of zRAM. Admin could see the information via
|
||||
@@ -86,4 +95,4 @@ config ZRAM_MULTI_COMP
|
||||
This will enable multi-compression streams, so that ZRAM can
|
||||
re-compress pages using a potentially slower but more effective
|
||||
compression algorithm. Note, that IDLE page recompression
|
||||
requires ZRAM_MEMORY_TRACKING.
|
||||
requires ZRAM_TRACK_ENTRY_ACTIME.
|
||||
|
||||
@@ -174,6 +174,14 @@ static inline u32 zram_get_priority(struct zram *zram, u32 index)
|
||||
return prio & ZRAM_COMP_PRIORITY_MASK;
|
||||
}
|
||||
|
||||
static void zram_accessed(struct zram *zram, u32 index)
|
||||
{
|
||||
zram_clear_flag(zram, index, ZRAM_IDLE);
|
||||
#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME
|
||||
zram->table[index].ac_time = ktime_get_boottime();
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void update_used_max(struct zram *zram,
|
||||
const unsigned long pages)
|
||||
{
|
||||
@@ -289,16 +297,30 @@ static void mark_idle(struct zram *zram, ktime_t cutoff)
|
||||
/*
|
||||
* Do not mark ZRAM_UNDER_WB slot as ZRAM_IDLE to close race.
|
||||
* See the comment in writeback_store.
|
||||
*
|
||||
* Also do not mark ZRAM_SAME slots as ZRAM_IDLE, because no
|
||||
* post-processing (recompress, writeback) happens to the
|
||||
* ZRAM_SAME slot.
|
||||
*
|
||||
* And ZRAM_WB slots simply cannot be ZRAM_IDLE.
|
||||
*/
|
||||
zram_slot_lock(zram, index);
|
||||
if (zram_allocated(zram, index) &&
|
||||
!zram_test_flag(zram, index, ZRAM_UNDER_WB)) {
|
||||
#ifdef CONFIG_ZRAM_MEMORY_TRACKING
|
||||
is_idle = !cutoff || ktime_after(cutoff, zram->table[index].ac_time);
|
||||
#endif
|
||||
if (is_idle)
|
||||
zram_set_flag(zram, index, ZRAM_IDLE);
|
||||
if (!zram_allocated(zram, index) ||
|
||||
zram_test_flag(zram, index, ZRAM_WB) ||
|
||||
zram_test_flag(zram, index, ZRAM_UNDER_WB) ||
|
||||
zram_test_flag(zram, index, ZRAM_SAME)) {
|
||||
zram_slot_unlock(zram, index);
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME
|
||||
is_idle = !cutoff ||
|
||||
ktime_after(cutoff, zram->table[index].ac_time);
|
||||
#endif
|
||||
if (is_idle)
|
||||
zram_set_flag(zram, index, ZRAM_IDLE);
|
||||
else
|
||||
zram_clear_flag(zram, index, ZRAM_IDLE);
|
||||
zram_slot_unlock(zram, index);
|
||||
}
|
||||
}
|
||||
@@ -317,7 +339,7 @@ static ssize_t idle_store(struct device *dev,
|
||||
*/
|
||||
u64 age_sec;
|
||||
|
||||
if (IS_ENABLED(CONFIG_ZRAM_MEMORY_TRACKING) && !kstrtoull(buf, 0, &age_sec))
|
||||
if (IS_ENABLED(CONFIG_ZRAM_TRACK_ENTRY_ACTIME) && !kstrtoull(buf, 0, &age_sec))
|
||||
cutoff_time = ktime_sub(ktime_get_boottime(),
|
||||
ns_to_ktime(age_sec * NSEC_PER_SEC));
|
||||
else
|
||||
@@ -844,12 +866,6 @@ static void zram_debugfs_destroy(void)
|
||||
debugfs_remove_recursive(zram_debugfs_root);
|
||||
}
|
||||
|
||||
static void zram_accessed(struct zram *zram, u32 index)
|
||||
{
|
||||
zram_clear_flag(zram, index, ZRAM_IDLE);
|
||||
zram->table[index].ac_time = ktime_get_boottime();
|
||||
}
|
||||
|
||||
static ssize_t read_block_state(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
@@ -933,10 +949,6 @@ static void zram_debugfs_unregister(struct zram *zram)
|
||||
#else
|
||||
static void zram_debugfs_create(void) {};
|
||||
static void zram_debugfs_destroy(void) {};
|
||||
static void zram_accessed(struct zram *zram, u32 index)
|
||||
{
|
||||
zram_clear_flag(zram, index, ZRAM_IDLE);
|
||||
};
|
||||
static void zram_debugfs_register(struct zram *zram) {};
|
||||
static void zram_debugfs_unregister(struct zram *zram) {};
|
||||
#endif
|
||||
@@ -1257,7 +1269,7 @@ static void zram_free_page(struct zram *zram, size_t index)
|
||||
{
|
||||
unsigned long handle;
|
||||
|
||||
#ifdef CONFIG_ZRAM_MEMORY_TRACKING
|
||||
#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME
|
||||
zram->table[index].ac_time = 0;
|
||||
#endif
|
||||
if (zram_test_flag(zram, index, ZRAM_IDLE))
|
||||
|
||||
@@ -69,7 +69,7 @@ struct zram_table_entry {
|
||||
unsigned long element;
|
||||
};
|
||||
unsigned long flags;
|
||||
#ifdef CONFIG_ZRAM_MEMORY_TRACKING
|
||||
#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME
|
||||
ktime_t ac_time;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -555,6 +555,8 @@ static const struct usb_device_id quirks_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3591), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe123), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe125), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
@@ -4488,6 +4490,8 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
set_bit(HCI_QUIRK_BROKEN_SET_RPA_TIMEOUT, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_BROKEN_EXT_SCAN, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_BROKEN_READ_ENC_KEY_SIZE, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_BROKEN_EXT_CREATE_CONN, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_BROKEN_WRITE_AUTH_PAYLOAD_TIMEOUT, &hdev->quirks);
|
||||
}
|
||||
|
||||
if (!reset)
|
||||
|
||||
@@ -284,6 +284,8 @@ static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_dat
|
||||
u32 rate;
|
||||
int i;
|
||||
|
||||
clk_data->num = EN7523_NUM_CLOCKS;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(en7523_base_clks); i++) {
|
||||
const struct en_clk_desc *desc = &en7523_base_clks[i];
|
||||
|
||||
@@ -302,8 +304,6 @@ static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_dat
|
||||
|
||||
hw = en7523_register_pcie_clk(dev, np_base);
|
||||
clk_data->hws[EN7523_CLK_PCIE] = hw;
|
||||
|
||||
clk_data->num = EN7523_NUM_CLOCKS;
|
||||
}
|
||||
|
||||
static int en7523_clk_probe(struct platform_device *pdev)
|
||||
|
||||
@@ -176,6 +176,7 @@ extern const struct clk_ops clk_byte2_ops;
|
||||
extern const struct clk_ops clk_pixel_ops;
|
||||
extern const struct clk_ops clk_gfx3d_ops;
|
||||
extern const struct clk_ops clk_rcg2_shared_ops;
|
||||
extern const struct clk_ops clk_rcg2_shared_floor_ops;
|
||||
extern const struct clk_ops clk_rcg2_shared_no_init_park_ops;
|
||||
extern const struct clk_ops clk_dp_ops;
|
||||
|
||||
|
||||
@@ -1020,15 +1020,23 @@ clk_rcg2_shared_force_enable_clear(struct clk_hw *hw, const struct freq_tbl *f)
|
||||
return clk_rcg2_clear_force_enable(hw);
|
||||
}
|
||||
|
||||
static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
static int __clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate,
|
||||
enum freq_policy policy)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
const struct freq_tbl *f;
|
||||
|
||||
f = qcom_find_freq(rcg->freq_tbl, rate);
|
||||
if (!f)
|
||||
switch (policy) {
|
||||
case FLOOR:
|
||||
f = qcom_find_freq_floor(rcg->freq_tbl, rate);
|
||||
break;
|
||||
case CEIL:
|
||||
f = qcom_find_freq(rcg->freq_tbl, rate);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case clock is disabled, update the M, N and D registers, cache
|
||||
@@ -1041,10 +1049,28 @@ static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
return clk_rcg2_shared_force_enable_clear(hw, f);
|
||||
}
|
||||
|
||||
static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return __clk_rcg2_shared_set_rate(hw, rate, parent_rate, CEIL);
|
||||
}
|
||||
|
||||
static int clk_rcg2_shared_set_rate_and_parent(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long parent_rate, u8 index)
|
||||
{
|
||||
return clk_rcg2_shared_set_rate(hw, rate, parent_rate);
|
||||
return __clk_rcg2_shared_set_rate(hw, rate, parent_rate, CEIL);
|
||||
}
|
||||
|
||||
static int clk_rcg2_shared_set_floor_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return __clk_rcg2_shared_set_rate(hw, rate, parent_rate, FLOOR);
|
||||
}
|
||||
|
||||
static int clk_rcg2_shared_set_floor_rate_and_parent(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long parent_rate, u8 index)
|
||||
{
|
||||
return __clk_rcg2_shared_set_rate(hw, rate, parent_rate, FLOOR);
|
||||
}
|
||||
|
||||
static int clk_rcg2_shared_enable(struct clk_hw *hw)
|
||||
@@ -1182,6 +1208,18 @@ const struct clk_ops clk_rcg2_shared_ops = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops);
|
||||
|
||||
const struct clk_ops clk_rcg2_shared_floor_ops = {
|
||||
.enable = clk_rcg2_shared_enable,
|
||||
.disable = clk_rcg2_shared_disable,
|
||||
.get_parent = clk_rcg2_shared_get_parent,
|
||||
.set_parent = clk_rcg2_shared_set_parent,
|
||||
.recalc_rate = clk_rcg2_shared_recalc_rate,
|
||||
.determine_rate = clk_rcg2_determine_floor_rate,
|
||||
.set_rate = clk_rcg2_shared_set_floor_rate,
|
||||
.set_rate_and_parent = clk_rcg2_shared_set_floor_rate_and_parent,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_rcg2_shared_floor_ops);
|
||||
|
||||
static int clk_rcg2_shared_no_init_park(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
|
||||
@@ -385,6 +385,18 @@ DEFINE_CLK_RPMH_BCM(ipa, "IP0");
|
||||
DEFINE_CLK_RPMH_BCM(pka, "PKA0");
|
||||
DEFINE_CLK_RPMH_BCM(qpic_clk, "QP0");
|
||||
|
||||
static struct clk_hw *sar2130p_rpmh_clocks[] = {
|
||||
[RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div1.hw,
|
||||
[RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div1_ao.hw,
|
||||
[RPMH_RF_CLK1] = &clk_rpmh_rf_clk1_a.hw,
|
||||
[RPMH_RF_CLK1_A] = &clk_rpmh_rf_clk1_a_ao.hw,
|
||||
};
|
||||
|
||||
static const struct clk_rpmh_desc clk_rpmh_sar2130p = {
|
||||
.clks = sar2130p_rpmh_clocks,
|
||||
.num_clks = ARRAY_SIZE(sar2130p_rpmh_clocks),
|
||||
};
|
||||
|
||||
static struct clk_hw *sdm845_rpmh_clocks[] = {
|
||||
[RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div2.hw,
|
||||
[RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div2_ao.hw,
|
||||
@@ -804,6 +816,7 @@ static int clk_rpmh_probe(struct platform_device *pdev)
|
||||
static const struct of_device_id clk_rpmh_match_table[] = {
|
||||
{ .compatible = "qcom,qdu1000-rpmh-clk", .data = &clk_rpmh_qdu1000},
|
||||
{ .compatible = "qcom,sa8775p-rpmh-clk", .data = &clk_rpmh_sa8775p},
|
||||
{ .compatible = "qcom,sar2130p-rpmh-clk", .data = &clk_rpmh_sar2130p},
|
||||
{ .compatible = "qcom,sc7180-rpmh-clk", .data = &clk_rpmh_sc7180},
|
||||
{ .compatible = "qcom,sc8180x-rpmh-clk", .data = &clk_rpmh_sc8180x},
|
||||
{ .compatible = "qcom,sc8280xp-rpmh-clk", .data = &clk_rpmh_sc8280xp},
|
||||
|
||||
@@ -129,6 +129,13 @@ static struct clk_branch tcsr_usb3_clkref_en = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap *tcsr_cc_sar2130p_clocks[] = {
|
||||
[TCSR_PCIE_0_CLKREF_EN] = &tcsr_pcie_0_clkref_en.clkr,
|
||||
[TCSR_PCIE_1_CLKREF_EN] = &tcsr_pcie_1_clkref_en.clkr,
|
||||
[TCSR_USB2_CLKREF_EN] = &tcsr_usb2_clkref_en.clkr,
|
||||
[TCSR_USB3_CLKREF_EN] = &tcsr_usb3_clkref_en.clkr,
|
||||
};
|
||||
|
||||
static struct clk_regmap *tcsr_cc_sm8550_clocks[] = {
|
||||
[TCSR_PCIE_0_CLKREF_EN] = &tcsr_pcie_0_clkref_en.clkr,
|
||||
[TCSR_PCIE_1_CLKREF_EN] = &tcsr_pcie_1_clkref_en.clkr,
|
||||
@@ -146,6 +153,12 @@ static const struct regmap_config tcsr_cc_sm8550_regmap_config = {
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static const struct qcom_cc_desc tcsr_cc_sar2130p_desc = {
|
||||
.config = &tcsr_cc_sm8550_regmap_config,
|
||||
.clks = tcsr_cc_sar2130p_clocks,
|
||||
.num_clks = ARRAY_SIZE(tcsr_cc_sar2130p_clocks),
|
||||
};
|
||||
|
||||
static const struct qcom_cc_desc tcsr_cc_sm8550_desc = {
|
||||
.config = &tcsr_cc_sm8550_regmap_config,
|
||||
.clks = tcsr_cc_sm8550_clocks,
|
||||
@@ -153,7 +166,8 @@ static const struct qcom_cc_desc tcsr_cc_sm8550_desc = {
|
||||
};
|
||||
|
||||
static const struct of_device_id tcsr_cc_sm8550_match_table[] = {
|
||||
{ .compatible = "qcom,sm8550-tcsr" },
|
||||
{ .compatible = "qcom,sar2130p-tcsr", .data = &tcsr_cc_sar2130p_desc },
|
||||
{ .compatible = "qcom,sm8550-tcsr", .data = &tcsr_cc_sm8550_desc },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tcsr_cc_sm8550_match_table);
|
||||
@@ -162,7 +176,7 @@ static int tcsr_cc_sm8550_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = qcom_cc_map(pdev, &tcsr_cc_sm8550_desc);
|
||||
regmap = qcom_cc_map(pdev, of_device_get_match_data(&pdev->dev));
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
|
||||
@@ -103,10 +103,36 @@ static bool dma_fence_array_enable_signaling(struct dma_fence *fence)
|
||||
static bool dma_fence_array_signaled(struct dma_fence *fence)
|
||||
{
|
||||
struct dma_fence_array *array = to_dma_fence_array(fence);
|
||||
int num_pending;
|
||||
unsigned int i;
|
||||
|
||||
if (atomic_read(&array->num_pending) > 0)
|
||||
/*
|
||||
* We need to read num_pending before checking the enable_signal bit
|
||||
* to avoid racing with the enable_signaling() implementation, which
|
||||
* might decrement the counter, and cause a partial check.
|
||||
* atomic_read_acquire() pairs with atomic_dec_and_test() in
|
||||
* dma_fence_array_enable_signaling()
|
||||
*
|
||||
* The !--num_pending check is here to account for the any_signaled case
|
||||
* if we race with enable_signaling(), that means the !num_pending check
|
||||
* in the is_signalling_enabled branch might be outdated (num_pending
|
||||
* might have been decremented), but that's fine. The user will get the
|
||||
* right value when testing again later.
|
||||
*/
|
||||
num_pending = atomic_read_acquire(&array->num_pending);
|
||||
if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &array->base.flags)) {
|
||||
if (num_pending <= 0)
|
||||
goto signal;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < array->num_fences; ++i) {
|
||||
if (dma_fence_is_signaled(array->fences[i]) && !--num_pending)
|
||||
goto signal;
|
||||
}
|
||||
return false;
|
||||
|
||||
signal:
|
||||
dma_fence_array_clear_pending_error(array);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/dma-fence-chain.h>
|
||||
#include <linux/dma-fence-unwrap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sort.h>
|
||||
|
||||
/* Internal helper to start new array iteration, don't use directly */
|
||||
static struct dma_fence *
|
||||
@@ -59,6 +60,25 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_fence_unwrap_next);
|
||||
|
||||
|
||||
static int fence_cmp(const void *_a, const void *_b)
|
||||
{
|
||||
struct dma_fence *a = *(struct dma_fence **)_a;
|
||||
struct dma_fence *b = *(struct dma_fence **)_b;
|
||||
|
||||
if (a->context < b->context)
|
||||
return -1;
|
||||
else if (a->context > b->context)
|
||||
return 1;
|
||||
|
||||
if (dma_fence_is_later(b, a))
|
||||
return 1;
|
||||
else if (dma_fence_is_later(a, b))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Implementation for the dma_fence_merge() marco, don't use directly */
|
||||
struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
|
||||
struct dma_fence **fences,
|
||||
@@ -67,8 +87,7 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
|
||||
struct dma_fence_array *result;
|
||||
struct dma_fence *tmp, **array;
|
||||
ktime_t timestamp;
|
||||
unsigned int i;
|
||||
size_t count;
|
||||
int i, j, count;
|
||||
|
||||
count = 0;
|
||||
timestamp = ns_to_ktime(0);
|
||||
@@ -96,78 +115,55 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
|
||||
if (!array)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* This trashes the input fence array and uses it as position for the
|
||||
* following merge loop. This works because the dma_fence_merge()
|
||||
* wrapper macro is creating this temporary array on the stack together
|
||||
* with the iterators.
|
||||
*/
|
||||
for (i = 0; i < num_fences; ++i)
|
||||
fences[i] = dma_fence_unwrap_first(fences[i], &iter[i]);
|
||||
|
||||
count = 0;
|
||||
do {
|
||||
unsigned int sel;
|
||||
|
||||
restart:
|
||||
tmp = NULL;
|
||||
for (i = 0; i < num_fences; ++i) {
|
||||
struct dma_fence *next;
|
||||
|
||||
while (fences[i] && dma_fence_is_signaled(fences[i]))
|
||||
fences[i] = dma_fence_unwrap_next(&iter[i]);
|
||||
|
||||
next = fences[i];
|
||||
if (!next)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We can't guarantee that inpute fences are ordered by
|
||||
* context, but it is still quite likely when this
|
||||
* function is used multiple times. So attempt to order
|
||||
* the fences by context as we pass over them and merge
|
||||
* fences with the same context.
|
||||
*/
|
||||
if (!tmp || tmp->context > next->context) {
|
||||
tmp = next;
|
||||
sel = i;
|
||||
|
||||
} else if (tmp->context < next->context) {
|
||||
continue;
|
||||
|
||||
} else if (dma_fence_is_later(tmp, next)) {
|
||||
fences[i] = dma_fence_unwrap_next(&iter[i]);
|
||||
goto restart;
|
||||
for (i = 0; i < num_fences; ++i) {
|
||||
dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) {
|
||||
if (!dma_fence_is_signaled(tmp)) {
|
||||
array[count++] = dma_fence_get(tmp);
|
||||
} else {
|
||||
fences[sel] = dma_fence_unwrap_next(&iter[sel]);
|
||||
goto restart;
|
||||
ktime_t t = dma_fence_timestamp(tmp);
|
||||
|
||||
if (ktime_after(t, timestamp))
|
||||
timestamp = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp) {
|
||||
array[count++] = dma_fence_get(tmp);
|
||||
fences[sel] = dma_fence_unwrap_next(&iter[sel]);
|
||||
if (count == 0 || count == 1)
|
||||
goto return_fastpath;
|
||||
|
||||
sort(array, count, sizeof(*array), fence_cmp, NULL);
|
||||
|
||||
/*
|
||||
* Only keep the most recent fence for each context.
|
||||
*/
|
||||
j = 0;
|
||||
for (i = 1; i < count; i++) {
|
||||
if (array[i]->context == array[j]->context)
|
||||
dma_fence_put(array[i]);
|
||||
else
|
||||
array[++j] = array[i];
|
||||
}
|
||||
count = ++j;
|
||||
|
||||
if (count > 1) {
|
||||
result = dma_fence_array_create(count, array,
|
||||
dma_fence_context_alloc(1),
|
||||
1, false);
|
||||
if (!result) {
|
||||
for (i = 0; i < count; i++)
|
||||
dma_fence_put(array[i]);
|
||||
tmp = NULL;
|
||||
goto return_tmp;
|
||||
}
|
||||
} while (tmp);
|
||||
|
||||
if (count == 0) {
|
||||
tmp = dma_fence_allocate_private_stub(ktime_get());
|
||||
goto return_tmp;
|
||||
return &result->base;
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
return_fastpath:
|
||||
if (count == 0)
|
||||
tmp = dma_fence_allocate_private_stub(timestamp);
|
||||
else
|
||||
tmp = array[0];
|
||||
goto return_tmp;
|
||||
}
|
||||
|
||||
result = dma_fence_array_create(count, array,
|
||||
dma_fence_context_alloc(1),
|
||||
1, false);
|
||||
if (!result) {
|
||||
tmp = NULL;
|
||||
goto return_tmp;
|
||||
}
|
||||
return &result->base;
|
||||
|
||||
return_tmp:
|
||||
kfree(array);
|
||||
|
||||
@@ -328,6 +328,7 @@ static const struct irq_domain_ops grgpio_irq_domain_ops = {
|
||||
static int grgpio_probe(struct platform_device *ofdev)
|
||||
{
|
||||
struct device_node *np = ofdev->dev.of_node;
|
||||
struct device *dev = &ofdev->dev;
|
||||
void __iomem *regs;
|
||||
struct gpio_chip *gc;
|
||||
struct grgpio_priv *priv;
|
||||
@@ -337,7 +338,7 @@ static int grgpio_probe(struct platform_device *ofdev)
|
||||
int size;
|
||||
int i;
|
||||
|
||||
priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -346,28 +347,31 @@ static int grgpio_probe(struct platform_device *ofdev)
|
||||
return PTR_ERR(regs);
|
||||
|
||||
gc = &priv->gc;
|
||||
err = bgpio_init(gc, &ofdev->dev, 4, regs + GRGPIO_DATA,
|
||||
err = bgpio_init(gc, dev, 4, regs + GRGPIO_DATA,
|
||||
regs + GRGPIO_OUTPUT, NULL, regs + GRGPIO_DIR, NULL,
|
||||
BGPIOF_BIG_ENDIAN_BYTE_ORDER);
|
||||
if (err) {
|
||||
dev_err(&ofdev->dev, "bgpio_init() failed\n");
|
||||
dev_err(dev, "bgpio_init() failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
priv->regs = regs;
|
||||
priv->imask = gc->read_reg(regs + GRGPIO_IMASK);
|
||||
priv->dev = &ofdev->dev;
|
||||
priv->dev = dev;
|
||||
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->to_irq = grgpio_to_irq;
|
||||
gc->label = devm_kasprintf(&ofdev->dev, GFP_KERNEL, "%pOF", np);
|
||||
gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np);
|
||||
if (!gc->label)
|
||||
return -ENOMEM;
|
||||
|
||||
gc->base = -1;
|
||||
|
||||
err = of_property_read_u32(np, "nbits", &prop);
|
||||
if (err || prop <= 0 || prop > GRGPIO_MAX_NGPIO) {
|
||||
gc->ngpio = GRGPIO_MAX_NGPIO;
|
||||
dev_dbg(&ofdev->dev,
|
||||
"No or invalid nbits property: assume %d\n", gc->ngpio);
|
||||
dev_dbg(dev, "No or invalid nbits property: assume %d\n",
|
||||
gc->ngpio);
|
||||
} else {
|
||||
gc->ngpio = prop;
|
||||
}
|
||||
@@ -379,7 +383,7 @@ static int grgpio_probe(struct platform_device *ofdev)
|
||||
irqmap = (s32 *)of_get_property(np, "irqmap", &size);
|
||||
if (irqmap) {
|
||||
if (size < gc->ngpio) {
|
||||
dev_err(&ofdev->dev,
|
||||
dev_err(dev,
|
||||
"irqmap shorter than ngpio (%d < %d)\n",
|
||||
size, gc->ngpio);
|
||||
return -EINVAL;
|
||||
@@ -389,7 +393,7 @@ static int grgpio_probe(struct platform_device *ofdev)
|
||||
&grgpio_irq_domain_ops,
|
||||
priv);
|
||||
if (!priv->domain) {
|
||||
dev_err(&ofdev->dev, "Could not add irq domain\n");
|
||||
dev_err(dev, "Could not add irq domain\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -419,13 +423,13 @@ static int grgpio_probe(struct platform_device *ofdev)
|
||||
|
||||
err = gpiochip_add_data(gc, priv);
|
||||
if (err) {
|
||||
dev_err(&ofdev->dev, "Could not add gpiochip\n");
|
||||
dev_err(dev, "Could not add gpiochip\n");
|
||||
if (priv->domain)
|
||||
irq_domain_remove(priv->domain);
|
||||
return err;
|
||||
}
|
||||
|
||||
dev_info(&ofdev->dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n",
|
||||
dev_info(dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n",
|
||||
priv->regs, gc->base, gc->ngpio, priv->domain ? "on" : "off");
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -798,6 +798,7 @@ int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
kfree(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -3172,7 +3172,7 @@ static int amdgpu_device_ip_resume_phase1(struct amdgpu_device *adev)
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* First resume function for hardware IPs. The list of all the hardware
|
||||
* Second resume function for hardware IPs. The list of all the hardware
|
||||
* IPs that make up the asic is walked and the resume callbacks are run for
|
||||
* all blocks except COMMON, GMC, and IH. resume puts the hardware into a
|
||||
* functional state after a suspend and updates the software state as
|
||||
@@ -3190,6 +3190,7 @@ static int amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev)
|
||||
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON ||
|
||||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC ||
|
||||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH ||
|
||||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE ||
|
||||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP)
|
||||
continue;
|
||||
r = adev->ip_blocks[i].version->funcs->resume(adev);
|
||||
@@ -3204,6 +3205,36 @@ static int amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_device_ip_resume_phase3 - run resume for hardware IPs
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* Third resume function for hardware IPs. The list of all the hardware
|
||||
* IPs that make up the asic is walked and the resume callbacks are run for
|
||||
* all DCE. resume puts the hardware into a functional state after a suspend
|
||||
* and updates the software state as necessary. This function is also used
|
||||
* for restoring the GPU after a GPU reset.
|
||||
*
|
||||
* Returns 0 on success, negative error code on failure.
|
||||
*/
|
||||
static int amdgpu_device_ip_resume_phase3(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!adev->ip_blocks[i].status.valid || adev->ip_blocks[i].status.hw)
|
||||
continue;
|
||||
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) {
|
||||
r = adev->ip_blocks[i].version->funcs->resume(adev);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_device_ip_resume - run resume for hardware IPs
|
||||
*
|
||||
@@ -3230,6 +3261,13 @@ static int amdgpu_device_ip_resume(struct amdgpu_device *adev)
|
||||
|
||||
r = amdgpu_device_ip_resume_phase2(adev);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_fence_driver_hw_init(adev);
|
||||
|
||||
r = amdgpu_device_ip_resume_phase3(adev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -4229,7 +4267,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon)
|
||||
dev_err(adev->dev, "amdgpu_device_ip_resume failed (%d).\n", r);
|
||||
goto exit;
|
||||
}
|
||||
amdgpu_fence_driver_hw_init(adev);
|
||||
|
||||
r = amdgpu_device_ip_late_init(adev);
|
||||
if (r)
|
||||
@@ -4999,6 +5036,10 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle,
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
r = amdgpu_device_ip_resume_phase3(tmp_adev);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
if (vram_lost)
|
||||
amdgpu_device_fill_reset_magic(tmp_adev);
|
||||
|
||||
@@ -5841,6 +5882,9 @@ bool amdgpu_device_cache_pci_state(struct pci_dev *pdev)
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
int r;
|
||||
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
return false;
|
||||
|
||||
r = pci_save_state(pdev);
|
||||
if (!r) {
|
||||
kfree(adev->pci_state);
|
||||
|
||||
@@ -794,7 +794,7 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_device *bdev,
|
||||
/* Map SG to device */
|
||||
r = dma_map_sgtable(adev->dev, ttm->sg, direction, 0);
|
||||
if (r)
|
||||
goto release_sg;
|
||||
goto release_sg_table;
|
||||
|
||||
/* convert SG to linear array of pages and dma addresses */
|
||||
drm_prime_sg_to_dma_addr_array(ttm->sg, gtt->ttm.dma_address,
|
||||
@@ -802,6 +802,8 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_device *bdev,
|
||||
|
||||
return 0;
|
||||
|
||||
release_sg_table:
|
||||
sg_free_table(ttm->sg);
|
||||
release_sg:
|
||||
kfree(ttm->sg);
|
||||
ttm->sg = NULL;
|
||||
@@ -1833,6 +1835,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
|
||||
|
||||
mutex_init(&adev->mman.gtt_window_lock);
|
||||
|
||||
dma_set_max_seg_size(adev->dev, UINT_MAX);
|
||||
/* No others user of address space so set it to 0 */
|
||||
r = ttm_device_init(&adev->mman.bdev, &amdgpu_bo_driver, adev->dev,
|
||||
adev_to_drm(adev)->anon_inode->i_mapping,
|
||||
|
||||
@@ -31,13 +31,15 @@
|
||||
static void hdp_v5_2_flush_hdp(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring)
|
||||
{
|
||||
if (!ring || !ring->funcs->emit_wreg)
|
||||
if (!ring || !ring->funcs->emit_wreg) {
|
||||
WREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2,
|
||||
0);
|
||||
else
|
||||
RREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2);
|
||||
} else {
|
||||
amdgpu_ring_emit_wreg(ring,
|
||||
(adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
static void hdp_v5_2_update_mem_power_gating(struct amdgpu_device *adev,
|
||||
|
||||
@@ -77,6 +77,20 @@ static int vcn_v4_0_3_early_init(void *handle)
|
||||
return amdgpu_vcn_early_init(adev);
|
||||
}
|
||||
|
||||
static int vcn_v4_0_3_fw_shared_init(struct amdgpu_device *adev, int inst_idx)
|
||||
{
|
||||
struct amdgpu_vcn4_fw_shared *fw_shared;
|
||||
|
||||
fw_shared = adev->vcn.inst[inst_idx].fw_shared.cpu_addr;
|
||||
fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE);
|
||||
fw_shared->sq.is_enabled = 1;
|
||||
|
||||
if (amdgpu_vcnfw_log)
|
||||
amdgpu_vcn_fwlog_init(&adev->vcn.inst[inst_idx]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vcn_v4_0_3_sw_init - sw init for VCN block
|
||||
*
|
||||
@@ -107,8 +121,6 @@ static int vcn_v4_0_3_sw_init(void *handle)
|
||||
return r;
|
||||
|
||||
for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
|
||||
volatile struct amdgpu_vcn4_fw_shared *fw_shared;
|
||||
|
||||
vcn_inst = GET_INST(VCN, i);
|
||||
|
||||
ring = &adev->vcn.inst[i].ring_enc[0];
|
||||
@@ -131,12 +143,7 @@ static int vcn_v4_0_3_sw_init(void *handle)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
|
||||
fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE);
|
||||
fw_shared->sq.is_enabled = true;
|
||||
|
||||
if (amdgpu_vcnfw_log)
|
||||
amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
|
||||
vcn_v4_0_3_fw_shared_init(adev, i);
|
||||
}
|
||||
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
@@ -221,6 +228,8 @@ static int vcn_v4_0_3_hw_init(void *handle)
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
|
||||
struct amdgpu_vcn4_fw_shared *fw_shared;
|
||||
|
||||
vcn_inst = GET_INST(VCN, i);
|
||||
ring = &adev->vcn.inst[i].ring_enc[0];
|
||||
|
||||
@@ -244,6 +253,11 @@ static int vcn_v4_0_3_hw_init(void *handle)
|
||||
regVCN_RB1_DB_CTRL);
|
||||
}
|
||||
|
||||
/* Re-init fw_shared when RAS fatal error occurred */
|
||||
fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
|
||||
if (!fw_shared->sq.is_enabled)
|
||||
vcn_v4_0_3_fw_shared_init(adev, i);
|
||||
|
||||
r = amdgpu_ring_test_helper(ring);
|
||||
if (r)
|
||||
goto done;
|
||||
|
||||
@@ -114,6 +114,33 @@ static int vega20_ih_toggle_ring_interrupts(struct amdgpu_device *adev,
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_ENABLE, (enable ? 1 : 0));
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_GPU_TS_ENABLE, 1);
|
||||
|
||||
if (enable) {
|
||||
/* Unset the CLEAR_OVERFLOW bit to make sure the next step
|
||||
* is switching the bit from 0 to 1
|
||||
*/
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
|
||||
if (amdgpu_sriov_vf(adev) && amdgpu_sriov_reg_indirect_ih(adev)) {
|
||||
if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp))
|
||||
return -ETIMEDOUT;
|
||||
} else {
|
||||
WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
|
||||
}
|
||||
|
||||
/* Clear RB_OVERFLOW bit */
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
|
||||
if (amdgpu_sriov_vf(adev) && amdgpu_sriov_reg_indirect_ih(adev)) {
|
||||
if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp))
|
||||
return -ETIMEDOUT;
|
||||
} else {
|
||||
WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
|
||||
}
|
||||
|
||||
/* Unset the CLEAR_OVERFLOW bit immediately so new overflows
|
||||
* can be detected.
|
||||
*/
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
|
||||
}
|
||||
|
||||
/* enable_intr field is only valid in ring0 */
|
||||
if (ih == &adev->irq.ih)
|
||||
tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, ENABLE_INTR, (enable ? 1 : 0));
|
||||
|
||||
@@ -2611,10 +2611,10 @@ static int it6505_poweron(struct it6505 *it6505)
|
||||
/* time interval between OVDD and SYSRSTN at least be 10ms */
|
||||
if (pdata->gpiod_reset) {
|
||||
usleep_range(10000, 20000);
|
||||
gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
|
||||
usleep_range(1000, 2000);
|
||||
gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
|
||||
usleep_range(10000, 20000);
|
||||
usleep_range(1000, 2000);
|
||||
gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
|
||||
usleep_range(25000, 35000);
|
||||
}
|
||||
|
||||
it6505->powered = true;
|
||||
@@ -2640,7 +2640,7 @@ static int it6505_poweroff(struct it6505 *it6505)
|
||||
}
|
||||
|
||||
if (pdata->gpiod_reset)
|
||||
gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
|
||||
gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
|
||||
|
||||
if (pdata->pwr18) {
|
||||
err = regulator_disable(pdata->pwr18);
|
||||
@@ -3132,7 +3132,7 @@ static int it6505_init_pdata(struct it6505 *it6505)
|
||||
return PTR_ERR(pdata->ovdd);
|
||||
}
|
||||
|
||||
pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(pdata->gpiod_reset)) {
|
||||
dev_err(dev, "gpiod_reset gpio not found");
|
||||
return PTR_ERR(pdata->gpiod_reset);
|
||||
@@ -3503,6 +3503,7 @@ static const struct of_device_id it6505_of_match[] = {
|
||||
{ .compatible = "ite,it6505" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, it6505_of_match);
|
||||
|
||||
static struct i2c_driver it6505_i2c_driver = {
|
||||
.driver = {
|
||||
|
||||
@@ -160,11 +160,11 @@ EXPORT_SYMBOL(drm_dp_dual_mode_write);
|
||||
|
||||
static bool is_hdmi_adaptor(const char hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN])
|
||||
{
|
||||
static const char dp_dual_mode_hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN] =
|
||||
static const char dp_dual_mode_hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN + 1] =
|
||||
"DP-HDMI ADAPTOR\x04";
|
||||
|
||||
return memcmp(hdmi_id, dp_dual_mode_hdmi_id,
|
||||
sizeof(dp_dual_mode_hdmi_id)) == 0;
|
||||
DP_DUAL_MODE_HDMI_ID_LEN) == 0;
|
||||
}
|
||||
|
||||
static bool is_type1_adaptor(uint8_t adaptor_id)
|
||||
|
||||
@@ -319,6 +319,9 @@ static bool drm_dp_decode_sideband_msg_hdr(const struct drm_dp_mst_topology_mgr
|
||||
hdr->broadcast = (buf[idx] >> 7) & 0x1;
|
||||
hdr->path_msg = (buf[idx] >> 6) & 0x1;
|
||||
hdr->msg_len = buf[idx] & 0x3f;
|
||||
if (hdr->msg_len < 1) /* min space for body CRC */
|
||||
return false;
|
||||
|
||||
idx++;
|
||||
hdr->somt = (buf[idx] >> 7) & 0x1;
|
||||
hdr->eomt = (buf[idx] >> 6) & 0x1;
|
||||
@@ -3652,8 +3655,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
|
||||
ret = 0;
|
||||
mgr->payload_id_table_cleared = false;
|
||||
|
||||
memset(&mgr->down_rep_recv, 0, sizeof(mgr->down_rep_recv));
|
||||
memset(&mgr->up_req_recv, 0, sizeof(mgr->up_req_recv));
|
||||
mgr->reset_rx_state = true;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
@@ -3781,6 +3783,11 @@ out_fail:
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_mst_topology_mgr_resume);
|
||||
|
||||
static void reset_msg_rx_state(struct drm_dp_sideband_msg_rx *msg)
|
||||
{
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
}
|
||||
|
||||
static bool
|
||||
drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up,
|
||||
struct drm_dp_mst_branch **mstb)
|
||||
@@ -3859,6 +3866,34 @@ drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up,
|
||||
return true;
|
||||
}
|
||||
|
||||
static int get_msg_request_type(u8 data)
|
||||
{
|
||||
return data & 0x7f;
|
||||
}
|
||||
|
||||
static bool verify_rx_request_type(struct drm_dp_mst_topology_mgr *mgr,
|
||||
const struct drm_dp_sideband_msg_tx *txmsg,
|
||||
const struct drm_dp_sideband_msg_rx *rxmsg)
|
||||
{
|
||||
const struct drm_dp_sideband_msg_hdr *hdr = &rxmsg->initial_hdr;
|
||||
const struct drm_dp_mst_branch *mstb = txmsg->dst;
|
||||
int tx_req_type = get_msg_request_type(txmsg->msg[0]);
|
||||
int rx_req_type = get_msg_request_type(rxmsg->msg[0]);
|
||||
char rad_str[64];
|
||||
|
||||
if (tx_req_type == rx_req_type)
|
||||
return true;
|
||||
|
||||
drm_dp_mst_rad_to_str(mstb->rad, mstb->lct, rad_str, sizeof(rad_str));
|
||||
drm_dbg_kms(mgr->dev,
|
||||
"Got unexpected MST reply, mstb: %p seqno: %d lct: %d rad: %s rx_req_type: %s (%02x) != tx_req_type: %s (%02x)\n",
|
||||
mstb, hdr->seqno, mstb->lct, rad_str,
|
||||
drm_dp_mst_req_type_str(rx_req_type), rx_req_type,
|
||||
drm_dp_mst_req_type_str(tx_req_type), tx_req_type);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
|
||||
{
|
||||
struct drm_dp_sideband_msg_tx *txmsg;
|
||||
@@ -3888,6 +3923,9 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
|
||||
goto out_clear_reply;
|
||||
}
|
||||
|
||||
if (!verify_rx_request_type(mgr, txmsg, msg))
|
||||
goto out_clear_reply;
|
||||
|
||||
drm_dp_sideband_parse_reply(mgr, msg, &txmsg->reply);
|
||||
|
||||
if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
|
||||
@@ -4063,6 +4101,17 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void update_msg_rx_state(struct drm_dp_mst_topology_mgr *mgr)
|
||||
{
|
||||
mutex_lock(&mgr->lock);
|
||||
if (mgr->reset_rx_state) {
|
||||
mgr->reset_rx_state = false;
|
||||
reset_msg_rx_state(&mgr->down_rep_recv);
|
||||
reset_msg_rx_state(&mgr->up_req_recv);
|
||||
}
|
||||
mutex_unlock(&mgr->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_dp_mst_hpd_irq_handle_event() - MST hotplug IRQ handle MST event
|
||||
* @mgr: manager to notify irq for.
|
||||
@@ -4097,6 +4146,8 @@ int drm_dp_mst_hpd_irq_handle_event(struct drm_dp_mst_topology_mgr *mgr, const u
|
||||
*handled = true;
|
||||
}
|
||||
|
||||
update_msg_rx_state(mgr);
|
||||
|
||||
if (esi[1] & DP_DOWN_REP_MSG_RDY) {
|
||||
ret = drm_dp_mst_handle_down_rep(mgr);
|
||||
*handled = true;
|
||||
|
||||
@@ -184,6 +184,12 @@ static const struct dmi_system_id orientation_data[] = {
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T103HAF"),
|
||||
},
|
||||
.driver_data = (void *)&lcd800x1280_rightside_up,
|
||||
}, { /* AYA NEO AYANEO 2 */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "AYANEO 2"),
|
||||
},
|
||||
.driver_data = (void *)&lcd1200x1920_rightside_up,
|
||||
}, { /* AYA NEO 2021 */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYADEVICE"),
|
||||
@@ -196,6 +202,18 @@ static const struct dmi_system_id orientation_data[] = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "AIR"),
|
||||
},
|
||||
.driver_data = (void *)&lcd1080x1920_leftside_up,
|
||||
}, { /* AYA NEO Founder */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYA NEO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "AYA NEO Founder"),
|
||||
},
|
||||
.driver_data = (void *)&lcd800x1280_rightside_up,
|
||||
}, { /* AYA NEO GEEK */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYANEO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "GEEK"),
|
||||
},
|
||||
.driver_data = (void *)&lcd800x1280_rightside_up,
|
||||
}, { /* AYA NEO NEXT */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
|
||||
@@ -465,6 +465,7 @@ static const struct of_device_id mcde_of_match[] = {
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mcde_of_match);
|
||||
|
||||
static struct platform_driver mcde_driver = {
|
||||
.driver = {
|
||||
|
||||
@@ -4087,6 +4087,31 @@ static const struct panel_desc yes_optoelectronics_ytc700tlag_05_201c = {
|
||||
.connector_type = DRM_MODE_CONNECTOR_LVDS,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode mchp_ac69t88a_mode = {
|
||||
.clock = 25000,
|
||||
.hdisplay = 800,
|
||||
.hsync_start = 800 + 88,
|
||||
.hsync_end = 800 + 88 + 5,
|
||||
.htotal = 800 + 88 + 5 + 40,
|
||||
.vdisplay = 480,
|
||||
.vsync_start = 480 + 23,
|
||||
.vsync_end = 480 + 23 + 5,
|
||||
.vtotal = 480 + 23 + 5 + 1,
|
||||
};
|
||||
|
||||
static const struct panel_desc mchp_ac69t88a = {
|
||||
.modes = &mchp_ac69t88a_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 8,
|
||||
.size = {
|
||||
.width = 108,
|
||||
.height = 65,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH,
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
|
||||
.connector_type = DRM_MODE_CONNECTOR_LVDS,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode arm_rtsm_mode[] = {
|
||||
{
|
||||
.clock = 65000,
|
||||
@@ -4522,6 +4547,9 @@ static const struct of_device_id platform_of_match[] = {
|
||||
}, {
|
||||
.compatible = "yes-optoelectronics,ytc700tlag-05-201c",
|
||||
.data = &yes_optoelectronics_ytc700tlag_05_201c,
|
||||
}, {
|
||||
.compatible = "microchip,ac69t88a",
|
||||
.data = &mchp_ac69t88a,
|
||||
}, {
|
||||
/* Must be the last entry */
|
||||
.compatible = "panel-dpi",
|
||||
|
||||
@@ -2104,7 +2104,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
offset = radeon_get_ib_value(p, idx+1) << 8;
|
||||
offset = (u64)radeon_get_ib_value(p, idx+1) << 8;
|
||||
if (offset != track->vgt_strmout_bo_offset[idx_value]) {
|
||||
DRM_ERROR("bad STRMOUT_BASE_UPDATE, bo offset does not match: 0x%llx, 0x%x\n",
|
||||
offset, track->vgt_strmout_bo_offset[idx_value]);
|
||||
|
||||
@@ -635,6 +635,14 @@ int drm_sched_job_init(struct drm_sched_job *job,
|
||||
if (!entity->rq)
|
||||
return -ENOENT;
|
||||
|
||||
/*
|
||||
* We don't know for sure how the user has allocated. Thus, zero the
|
||||
* struct so that unallowed (i.e., too early) usage of pointers that
|
||||
* this function does not set is guaranteed to lead to a NULL pointer
|
||||
* exception instead of UB.
|
||||
*/
|
||||
memset(job, 0, sizeof(*job));
|
||||
|
||||
job->entity = entity;
|
||||
job->s_fence = drm_sched_fence_alloc(entity, owner);
|
||||
if (!job->s_fence)
|
||||
|
||||
@@ -137,7 +137,7 @@ static void mixer_dbg_crb(struct seq_file *s, int val)
|
||||
}
|
||||
}
|
||||
|
||||
static void mixer_dbg_mxn(struct seq_file *s, void *addr)
|
||||
static void mixer_dbg_mxn(struct seq_file *s, void __iomem *addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
@@ -51,9 +51,9 @@ void v3d_perfmon_start(struct v3d_dev *v3d, struct v3d_perfmon *perfmon)
|
||||
V3D_CORE_WRITE(0, V3D_V4_PCTR_0_SRC_X(source), channel);
|
||||
}
|
||||
|
||||
V3D_CORE_WRITE(0, V3D_V4_PCTR_0_EN, mask);
|
||||
V3D_CORE_WRITE(0, V3D_V4_PCTR_0_CLR, mask);
|
||||
V3D_CORE_WRITE(0, V3D_PCTR_0_OVERFLOW, mask);
|
||||
V3D_CORE_WRITE(0, V3D_V4_PCTR_0_EN, mask);
|
||||
|
||||
v3d->active_perfmon = perfmon;
|
||||
}
|
||||
|
||||
@@ -2396,7 +2396,7 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data)
|
||||
}
|
||||
|
||||
if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) {
|
||||
ret = -ENODEV;
|
||||
ret = -ENOTSUPP;
|
||||
goto out_dev_exit;
|
||||
}
|
||||
|
||||
|
||||
@@ -956,6 +956,17 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
|
||||
SCALER_DISPCTRL_SCLEIRQ);
|
||||
|
||||
|
||||
/* Set AXI panic mode.
|
||||
* VC4 panics when < 2 lines in FIFO.
|
||||
* VC5 panics when less than 1 line in the FIFO.
|
||||
*/
|
||||
dispctrl &= ~(SCALER_DISPCTRL_PANIC0_MASK |
|
||||
SCALER_DISPCTRL_PANIC1_MASK |
|
||||
SCALER_DISPCTRL_PANIC2_MASK);
|
||||
dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC0);
|
||||
dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC1);
|
||||
dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC2);
|
||||
|
||||
/* Set AXI panic mode.
|
||||
* VC4 panics when < 2 lines in FIFO.
|
||||
* VC5 panics when less than 1 line in the FIFO.
|
||||
|
||||
@@ -2607,9 +2607,10 @@ static bool hid_check_device_match(struct hid_device *hdev,
|
||||
/*
|
||||
* hid-generic implements .match(), so we must be dealing with a
|
||||
* different HID driver here, and can simply check if
|
||||
* hid_ignore_special_drivers is set or not.
|
||||
* hid_ignore_special_drivers or HID_QUIRK_IGNORE_SPECIAL_DRIVER
|
||||
* are set or not.
|
||||
*/
|
||||
return !hid_ignore_special_drivers;
|
||||
return !hid_ignore_special_drivers && !(hdev->quirks & HID_QUIRK_IGNORE_SPECIAL_DRIVER);
|
||||
}
|
||||
|
||||
static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)
|
||||
|
||||
@@ -40,6 +40,9 @@ static bool hid_generic_match(struct hid_device *hdev,
|
||||
if (ignore_special_driver)
|
||||
return true;
|
||||
|
||||
if (hdev->quirks & HID_QUIRK_IGNORE_SPECIAL_DRIVER)
|
||||
return true;
|
||||
|
||||
if (hdev->quirks & HID_QUIRK_HAVE_SPECIAL_DRIVER)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
#define USB_DEVICE_ID_APPLE_MAGICMOUSE2 0x0269
|
||||
#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e
|
||||
#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 0x0265
|
||||
#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC 0x0324
|
||||
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
|
||||
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
|
||||
#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
|
||||
|
||||
@@ -224,7 +224,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
|
||||
touch_minor = tdata[4];
|
||||
state = tdata[7] & TOUCH_STATE_MASK;
|
||||
down = state != TOUCH_STATE_NONE;
|
||||
} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
|
||||
} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
|
||||
input->id.product ==
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
|
||||
id = tdata[8] & 0xf;
|
||||
x = (tdata[1] << 27 | tdata[0] << 19) >> 19;
|
||||
y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19);
|
||||
@@ -256,8 +258,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
|
||||
/* If requested, emulate a scroll wheel by detecting small
|
||||
* vertical touch motions.
|
||||
*/
|
||||
if (emulate_scroll_wheel && (input->id.product !=
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)) {
|
||||
if (emulate_scroll_wheel &&
|
||||
input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
|
||||
input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
|
||||
unsigned long now = jiffies;
|
||||
int step_x = msc->touches[id].scroll_x - x;
|
||||
int step_y = msc->touches[id].scroll_y - y;
|
||||
@@ -356,7 +359,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
|
||||
input_report_abs(input, ABS_MT_POSITION_X, x);
|
||||
input_report_abs(input, ABS_MT_POSITION_Y, y);
|
||||
|
||||
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)
|
||||
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
|
||||
input->id.product ==
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC)
|
||||
input_report_abs(input, ABS_MT_PRESSURE, pressure);
|
||||
|
||||
if (report_undeciphered) {
|
||||
@@ -364,7 +369,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
|
||||
input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2)
|
||||
input_event(input, EV_MSC, MSC_RAW, tdata[7]);
|
||||
else if (input->id.product !=
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
|
||||
input->id.product !=
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC)
|
||||
input_event(input, EV_MSC, MSC_RAW, tdata[8]);
|
||||
}
|
||||
}
|
||||
@@ -490,7 +497,9 @@ static int magicmouse_raw_event(struct hid_device *hdev,
|
||||
magicmouse_emit_buttons(msc, clicks & 3);
|
||||
input_report_rel(input, REL_X, x);
|
||||
input_report_rel(input, REL_Y, y);
|
||||
} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
|
||||
} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
|
||||
input->id.product ==
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
|
||||
input_mt_sync_frame(input);
|
||||
input_report_key(input, BTN_MOUSE, clicks & 1);
|
||||
} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
|
||||
@@ -542,7 +551,9 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
|
||||
__set_bit(REL_WHEEL_HI_RES, input->relbit);
|
||||
__set_bit(REL_HWHEEL_HI_RES, input->relbit);
|
||||
}
|
||||
} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
|
||||
} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
|
||||
input->id.product ==
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
|
||||
/* If the trackpad has been connected to a Mac, the name is
|
||||
* automatically personalized, e.g., "José Expósito's Trackpad".
|
||||
* When connected through Bluetooth, the personalized name is
|
||||
@@ -618,7 +629,9 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
|
||||
MOUSE_RES_X);
|
||||
input_abs_set_res(input, ABS_MT_POSITION_Y,
|
||||
MOUSE_RES_Y);
|
||||
} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
|
||||
} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
|
||||
input->id.product ==
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
|
||||
input_set_abs_params(input, ABS_MT_PRESSURE, 0, 253, 0, 0);
|
||||
input_set_abs_params(input, ABS_PRESSURE, 0, 253, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_ORIENTATION, -3, 4, 0, 0);
|
||||
@@ -657,7 +670,8 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
|
||||
input_set_events_per_packet(input, 60);
|
||||
|
||||
if (report_undeciphered &&
|
||||
input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
|
||||
input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
|
||||
input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
|
||||
__set_bit(EV_MSC, input->evbit);
|
||||
__set_bit(MSC_RAW, input->mscbit);
|
||||
}
|
||||
@@ -682,7 +696,9 @@ static int magicmouse_input_mapping(struct hid_device *hdev,
|
||||
|
||||
/* Magic Trackpad does not give relative data after switching to MT */
|
||||
if ((hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD ||
|
||||
hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) &&
|
||||
hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
|
||||
hi->input->id.product ==
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) &&
|
||||
field->flags & HID_MAIN_ITEM_RELATIVE)
|
||||
return -1;
|
||||
|
||||
@@ -718,7 +734,8 @@ static int magicmouse_enable_multitouch(struct hid_device *hdev)
|
||||
int ret;
|
||||
int feature_size;
|
||||
|
||||
if (hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
|
||||
if (hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
|
||||
hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
|
||||
if (hdev->vendor == BT_VENDOR_ID_APPLE) {
|
||||
feature_size = sizeof(feature_mt_trackpad2_bt);
|
||||
feature = feature_mt_trackpad2_bt;
|
||||
@@ -763,7 +780,8 @@ static int magicmouse_fetch_battery(struct hid_device *hdev)
|
||||
|
||||
if (!hdev->battery || hdev->vendor != USB_VENDOR_ID_APPLE ||
|
||||
(hdev->product != USB_DEVICE_ID_APPLE_MAGICMOUSE2 &&
|
||||
hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2))
|
||||
hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
|
||||
hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC))
|
||||
return -1;
|
||||
|
||||
report_enum = &hdev->report_enum[hdev->battery_report_type];
|
||||
@@ -832,7 +850,9 @@ static int magicmouse_probe(struct hid_device *hdev,
|
||||
|
||||
if (id->vendor == USB_VENDOR_ID_APPLE &&
|
||||
(id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
|
||||
(id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && hdev->type != HID_TYPE_USBMOUSE)))
|
||||
((id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
|
||||
id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) &&
|
||||
hdev->type != HID_TYPE_USBMOUSE)))
|
||||
return 0;
|
||||
|
||||
if (!msc->input) {
|
||||
@@ -847,7 +867,8 @@ static int magicmouse_probe(struct hid_device *hdev,
|
||||
else if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2)
|
||||
report = hid_register_report(hdev, HID_INPUT_REPORT,
|
||||
MOUSE2_REPORT_ID, 0);
|
||||
else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
|
||||
else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
|
||||
id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
|
||||
if (id->vendor == BT_VENDOR_ID_APPLE)
|
||||
report = hid_register_report(hdev, HID_INPUT_REPORT,
|
||||
TRACKPAD2_BT_REPORT_ID, 0);
|
||||
@@ -917,7 +938,8 @@ static __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
*/
|
||||
if (hdev->vendor == USB_VENDOR_ID_APPLE &&
|
||||
(hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
|
||||
hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) &&
|
||||
hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
|
||||
hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) &&
|
||||
*rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) {
|
||||
hid_info(hdev,
|
||||
"fixing up magicmouse battery report descriptor\n");
|
||||
@@ -948,6 +970,10 @@ static const struct hid_device_id magic_mice[] = {
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE,
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 },
|
||||
{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC), .driver_data = 0 },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE,
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC), .driver_data = 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, magic_mice);
|
||||
|
||||
@@ -2234,7 +2234,8 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
|
||||
if (hid_is_usb(wacom->hdev)) {
|
||||
struct usb_interface *intf = to_usb_interface(wacom->hdev->dev.parent);
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
product_name = dev->product;
|
||||
if (dev->product != NULL)
|
||||
product_name = dev->product;
|
||||
}
|
||||
|
||||
if (wacom->hdev->bus == BUS_I2C) {
|
||||
|
||||
@@ -1350,6 +1350,8 @@ static const char * const asus_msi_boards[] = {
|
||||
"Pro H610M-CT D4",
|
||||
"Pro H610T D4",
|
||||
"Pro Q670M-C",
|
||||
"Pro WS 600M-CL",
|
||||
"Pro WS 665-ACE",
|
||||
"Pro WS W680-ACE",
|
||||
"Pro WS W680-ACE IPMI",
|
||||
"Pro WS W790-ACE",
|
||||
|
||||
@@ -280,7 +280,8 @@ static int i3c_device_uevent(const struct device *dev, struct kobj_uevent_env *e
|
||||
struct i3c_device_info devinfo;
|
||||
u16 manuf, part, ext;
|
||||
|
||||
i3c_device_get_info(i3cdev, &devinfo);
|
||||
if (i3cdev->desc)
|
||||
devinfo = i3cdev->desc->info;
|
||||
manuf = I3C_PID_MANUF_ID(devinfo.pid);
|
||||
part = I3C_PID_PART_ID(devinfo.pid);
|
||||
ext = I3C_PID_EXTRA_INFO(devinfo.pid);
|
||||
@@ -342,10 +343,10 @@ struct bus_type i3c_bus_type = {
|
||||
};
|
||||
|
||||
static enum i3c_addr_slot_status
|
||||
i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
|
||||
i3c_bus_get_addr_slot_status_mask(struct i3c_bus *bus, u16 addr, u32 mask)
|
||||
{
|
||||
unsigned long status;
|
||||
int bitpos = addr * 2;
|
||||
int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS;
|
||||
|
||||
if (addr > I2C_MAX_ADDR)
|
||||
return I3C_ADDR_SLOT_RSVD;
|
||||
@@ -353,22 +354,33 @@ i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
|
||||
status = bus->addrslots[bitpos / BITS_PER_LONG];
|
||||
status >>= bitpos % BITS_PER_LONG;
|
||||
|
||||
return status & I3C_ADDR_SLOT_STATUS_MASK;
|
||||
return status & mask;
|
||||
}
|
||||
|
||||
static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
|
||||
enum i3c_addr_slot_status status)
|
||||
static enum i3c_addr_slot_status
|
||||
i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
|
||||
{
|
||||
int bitpos = addr * 2;
|
||||
return i3c_bus_get_addr_slot_status_mask(bus, addr, I3C_ADDR_SLOT_STATUS_MASK);
|
||||
}
|
||||
|
||||
static void i3c_bus_set_addr_slot_status_mask(struct i3c_bus *bus, u16 addr,
|
||||
enum i3c_addr_slot_status status, u32 mask)
|
||||
{
|
||||
int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS;
|
||||
unsigned long *ptr;
|
||||
|
||||
if (addr > I2C_MAX_ADDR)
|
||||
return;
|
||||
|
||||
ptr = bus->addrslots + (bitpos / BITS_PER_LONG);
|
||||
*ptr &= ~((unsigned long)I3C_ADDR_SLOT_STATUS_MASK <<
|
||||
(bitpos % BITS_PER_LONG));
|
||||
*ptr |= (unsigned long)status << (bitpos % BITS_PER_LONG);
|
||||
*ptr &= ~((unsigned long)mask << (bitpos % BITS_PER_LONG));
|
||||
*ptr |= ((unsigned long)status & mask) << (bitpos % BITS_PER_LONG);
|
||||
}
|
||||
|
||||
static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
|
||||
enum i3c_addr_slot_status status)
|
||||
{
|
||||
i3c_bus_set_addr_slot_status_mask(bus, addr, status, I3C_ADDR_SLOT_STATUS_MASK);
|
||||
}
|
||||
|
||||
static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr)
|
||||
@@ -380,13 +392,44 @@ static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr)
|
||||
return status == I3C_ADDR_SLOT_FREE;
|
||||
}
|
||||
|
||||
/*
|
||||
* ┌────┬─────────────┬───┬─────────┬───┐
|
||||
* │S/Sr│ 7'h7E RnW=0 │ACK│ ENTDAA │ T ├────┐
|
||||
* └────┴─────────────┴───┴─────────┴───┘ │
|
||||
* ┌─────────────────────────────────────────┘
|
||||
* │ ┌──┬─────────────┬───┬─────────────────┬────────────────┬───┬─────────┐
|
||||
* └─►│Sr│7'h7E RnW=1 │ACK│48bit UID BCR DCR│Assign 7bit Addr│PAR│ ACK/NACK│
|
||||
* └──┴─────────────┴───┴─────────────────┴────────────────┴───┴─────────┘
|
||||
* Some master controllers (such as HCI) need to prepare the entire above transaction before
|
||||
* sending it out to the I3C bus. This means that a 7-bit dynamic address needs to be allocated
|
||||
* before knowing the target device's UID information.
|
||||
*
|
||||
* However, some I3C targets may request specific addresses (called as "init_dyn_addr"), which is
|
||||
* typically specified by the DT-'s assigned-address property. Lower addresses having higher IBI
|
||||
* priority. If it is available, i3c_bus_get_free_addr() preferably return a free address that is
|
||||
* not in the list of desired addresses (called as "init_dyn_addr"). This allows the device with
|
||||
* the "init_dyn_addr" to switch to its "init_dyn_addr" when it hot-joins the I3C bus. Otherwise,
|
||||
* if the "init_dyn_addr" is already in use by another I3C device, the target device will not be
|
||||
* able to switch to its desired address.
|
||||
*
|
||||
* If the previous step fails, fallback returning one of the remaining unassigned address,
|
||||
* regardless of its state in the desired list.
|
||||
*/
|
||||
static int i3c_bus_get_free_addr(struct i3c_bus *bus, u8 start_addr)
|
||||
{
|
||||
enum i3c_addr_slot_status status;
|
||||
u8 addr;
|
||||
|
||||
for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) {
|
||||
status = i3c_bus_get_addr_slot_status(bus, addr);
|
||||
status = i3c_bus_get_addr_slot_status_mask(bus, addr,
|
||||
I3C_ADDR_SLOT_EXT_STATUS_MASK);
|
||||
if (status == I3C_ADDR_SLOT_FREE)
|
||||
return addr;
|
||||
}
|
||||
|
||||
for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) {
|
||||
status = i3c_bus_get_addr_slot_status_mask(bus, addr,
|
||||
I3C_ADDR_SLOT_STATUS_MASK);
|
||||
if (status == I3C_ADDR_SLOT_FREE)
|
||||
return addr;
|
||||
}
|
||||
@@ -526,6 +569,88 @@ static ssize_t i2c_scl_frequency_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RO(i2c_scl_frequency);
|
||||
|
||||
static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!master || !master->ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!master->ops->enable_hotjoin || !master->ops->disable_hotjoin)
|
||||
return -EINVAL;
|
||||
|
||||
i3c_bus_normaluse_lock(&master->bus);
|
||||
|
||||
if (enable)
|
||||
ret = master->ops->enable_hotjoin(master);
|
||||
else
|
||||
ret = master->ops->disable_hotjoin(master);
|
||||
|
||||
master->hotjoin = enable;
|
||||
|
||||
i3c_bus_normaluse_unlock(&master->bus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t hotjoin_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
|
||||
int ret;
|
||||
bool res;
|
||||
|
||||
if (!i3cbus->cur_master)
|
||||
return -EINVAL;
|
||||
|
||||
if (kstrtobool(buf, &res))
|
||||
return -EINVAL;
|
||||
|
||||
ret = i3c_set_hotjoin(i3cbus->cur_master->common.master, res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* i3c_master_enable_hotjoin - Enable hotjoin
|
||||
* @master: I3C master object
|
||||
*
|
||||
* Return: a 0 in case of success, an negative error code otherwise.
|
||||
*/
|
||||
int i3c_master_enable_hotjoin(struct i3c_master_controller *master)
|
||||
{
|
||||
return i3c_set_hotjoin(master, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_master_enable_hotjoin);
|
||||
|
||||
/*
|
||||
* i3c_master_disable_hotjoin - Disable hotjoin
|
||||
* @master: I3C master object
|
||||
*
|
||||
* Return: a 0 in case of success, an negative error code otherwise.
|
||||
*/
|
||||
int i3c_master_disable_hotjoin(struct i3c_master_controller *master)
|
||||
{
|
||||
return i3c_set_hotjoin(master, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_master_disable_hotjoin);
|
||||
|
||||
static ssize_t hotjoin_show(struct device *dev, struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
|
||||
ssize_t ret;
|
||||
|
||||
i3c_bus_normaluse_lock(i3cbus);
|
||||
ret = sysfs_emit(buf, "%d\n", i3cbus->cur_master->common.master->hotjoin);
|
||||
i3c_bus_normaluse_unlock(i3cbus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(hotjoin);
|
||||
|
||||
static struct attribute *i3c_masterdev_attrs[] = {
|
||||
&dev_attr_mode.attr,
|
||||
&dev_attr_current_master.attr,
|
||||
@@ -536,6 +661,7 @@ static struct attribute *i3c_masterdev_attrs[] = {
|
||||
&dev_attr_pid.attr,
|
||||
&dev_attr_dynamic_address.attr,
|
||||
&dev_attr_hdrcap.attr,
|
||||
&dev_attr_hotjoin.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(i3c_masterdev);
|
||||
@@ -1382,16 +1508,9 @@ static int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev,
|
||||
u8 old_dyn_addr)
|
||||
{
|
||||
struct i3c_master_controller *master = i3c_dev_get_master(dev);
|
||||
enum i3c_addr_slot_status status;
|
||||
int ret;
|
||||
|
||||
if (dev->info.dyn_addr != old_dyn_addr &&
|
||||
(!dev->boardinfo ||
|
||||
dev->info.dyn_addr != dev->boardinfo->init_dyn_addr)) {
|
||||
status = i3c_bus_get_addr_slot_status(&master->bus,
|
||||
dev->info.dyn_addr);
|
||||
if (status != I3C_ADDR_SLOT_FREE)
|
||||
return -EBUSY;
|
||||
if (dev->info.dyn_addr != old_dyn_addr) {
|
||||
i3c_bus_set_addr_slot_status(&master->bus,
|
||||
dev->info.dyn_addr,
|
||||
I3C_ADDR_SLOT_I3C_DEV);
|
||||
@@ -1744,6 +1863,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
|
||||
goto err_bus_cleanup;
|
||||
}
|
||||
|
||||
if (master->ops->set_speed) {
|
||||
ret = master->ops->set_speed(master, I3C_OPEN_DRAIN_SLOW_SPEED);
|
||||
if (ret)
|
||||
goto err_bus_cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset all dynamic address that may have been assigned before
|
||||
* (assigned by the bootloader for example).
|
||||
@@ -1752,6 +1877,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
|
||||
if (ret && ret != I3C_ERROR_M2)
|
||||
goto err_bus_cleanup;
|
||||
|
||||
if (master->ops->set_speed) {
|
||||
master->ops->set_speed(master, I3C_OPEN_DRAIN_NORMAL_SPEED);
|
||||
if (ret)
|
||||
goto err_bus_cleanup;
|
||||
}
|
||||
|
||||
/* Disable all slave events before starting DAA. */
|
||||
ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR,
|
||||
I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR |
|
||||
@@ -1782,9 +1913,11 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
|
||||
goto err_rstdaa;
|
||||
}
|
||||
|
||||
i3c_bus_set_addr_slot_status(&master->bus,
|
||||
i3cboardinfo->init_dyn_addr,
|
||||
I3C_ADDR_SLOT_I3C_DEV);
|
||||
/* Do not mark as occupied until real device exist in bus */
|
||||
i3c_bus_set_addr_slot_status_mask(&master->bus,
|
||||
i3cboardinfo->init_dyn_addr,
|
||||
I3C_ADDR_SLOT_EXT_DESIRED,
|
||||
I3C_ADDR_SLOT_EXT_STATUS_MASK);
|
||||
|
||||
/*
|
||||
* Only try to create/attach devices that have a static
|
||||
@@ -1915,11 +2048,16 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
|
||||
ibireq.max_payload_len = olddev->ibi->max_payload_len;
|
||||
ibireq.num_slots = olddev->ibi->num_slots;
|
||||
|
||||
if (olddev->ibi->enabled) {
|
||||
if (olddev->ibi->enabled)
|
||||
enable_ibi = true;
|
||||
i3c_dev_disable_ibi_locked(olddev);
|
||||
}
|
||||
|
||||
/*
|
||||
* The olddev should not receive any commands on the
|
||||
* i3c bus as it does not exist and has been assigned
|
||||
* a new address. This will result in NACK or timeout.
|
||||
* So, update the olddev->ibi->enabled flag to false
|
||||
* to avoid DISEC with OldAddr.
|
||||
*/
|
||||
olddev->ibi->enabled = false;
|
||||
i3c_dev_free_ibi_locked(olddev);
|
||||
}
|
||||
mutex_unlock(&olddev->ibi_lock);
|
||||
@@ -1947,7 +2085,8 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
|
||||
else
|
||||
expected_dyn_addr = newdev->info.dyn_addr;
|
||||
|
||||
if (newdev->info.dyn_addr != expected_dyn_addr) {
|
||||
if (newdev->info.dyn_addr != expected_dyn_addr &&
|
||||
i3c_bus_get_addr_slot_status(&master->bus, expected_dyn_addr) == I3C_ADDR_SLOT_FREE) {
|
||||
/*
|
||||
* Try to apply the expected dynamic address. If it fails, keep
|
||||
* the address assigned by the master.
|
||||
|
||||
@@ -174,10 +174,10 @@ static void hci_dma_cleanup(struct i3c_hci *hci)
|
||||
for (i = 0; i < rings->total; i++) {
|
||||
rh = &rings->headers[i];
|
||||
|
||||
rh_reg_write(INTR_SIGNAL_ENABLE, 0);
|
||||
rh_reg_write(RING_CONTROL, 0);
|
||||
rh_reg_write(CR_SETUP, 0);
|
||||
rh_reg_write(IBI_SETUP, 0);
|
||||
rh_reg_write(INTR_SIGNAL_ENABLE, 0);
|
||||
|
||||
if (rh->xfer)
|
||||
dma_free_coherent(&hci->master.dev,
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/* This parameter depends on the implementation and may be tuned */
|
||||
#define SVC_I3C_FIFO_SIZE 16
|
||||
|
||||
#define SVC_I3C_EVENT_IBI GENMASK(7, 0)
|
||||
#define SVC_I3C_EVENT_HOTJOIN BIT(31)
|
||||
|
||||
struct svc_i3c_cmd {
|
||||
u8 addr;
|
||||
bool rnw;
|
||||
@@ -178,6 +181,8 @@ struct svc_i3c_regs_save {
|
||||
* @ibi.tbq_slot: To be queued IBI slot
|
||||
* @ibi.lock: IBI lock
|
||||
* @lock: Transfer lock, protect between IBI work thread and callbacks from master
|
||||
* @enabled_events: Bit masks for enable events (IBI, HotJoin).
|
||||
* @mctrl_config: Configuration value in SVC_I3C_MCTRL for setting speed back.
|
||||
*/
|
||||
struct svc_i3c_master {
|
||||
struct i3c_master_controller base;
|
||||
@@ -207,6 +212,8 @@ struct svc_i3c_master {
|
||||
spinlock_t lock;
|
||||
} ibi;
|
||||
struct mutex lock;
|
||||
u32 enabled_events;
|
||||
u32 mctrl_config;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -221,6 +228,11 @@ struct svc_i3c_i2c_dev_data {
|
||||
struct i3c_generic_ibi_pool *ibi_pool;
|
||||
};
|
||||
|
||||
static inline bool is_events_enabled(struct svc_i3c_master *master, u32 mask)
|
||||
{
|
||||
return !!(master->enabled_events & mask);
|
||||
}
|
||||
|
||||
static bool svc_i3c_master_error(struct svc_i3c_master *master)
|
||||
{
|
||||
u32 mstatus, merrwarn;
|
||||
@@ -440,13 +452,16 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
|
||||
switch (ibitype) {
|
||||
case SVC_I3C_MSTATUS_IBITYPE_IBI:
|
||||
dev = svc_i3c_master_dev_from_addr(master, ibiaddr);
|
||||
if (!dev)
|
||||
if (!dev || !is_events_enabled(master, SVC_I3C_EVENT_IBI))
|
||||
svc_i3c_master_nack_ibi(master);
|
||||
else
|
||||
svc_i3c_master_handle_ibi(master, dev);
|
||||
break;
|
||||
case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
|
||||
svc_i3c_master_ack_ibi(master, false);
|
||||
if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN))
|
||||
svc_i3c_master_ack_ibi(master, false);
|
||||
else
|
||||
svc_i3c_master_nack_ibi(master);
|
||||
break;
|
||||
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
|
||||
svc_i3c_master_nack_ibi(master);
|
||||
@@ -483,7 +498,9 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
|
||||
svc_i3c_master_emit_stop(master);
|
||||
break;
|
||||
case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
|
||||
queue_work(master->base.wq, &master->hj_work);
|
||||
svc_i3c_master_emit_stop(master);
|
||||
if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN))
|
||||
queue_work(master->base.wq, &master->hj_work);
|
||||
break;
|
||||
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
|
||||
default:
|
||||
@@ -514,6 +531,54 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int svc_i3c_master_set_speed(struct i3c_master_controller *m,
|
||||
enum i3c_open_drain_speed speed)
|
||||
{
|
||||
struct svc_i3c_master *master = to_svc_i3c_master(m);
|
||||
struct i3c_bus *bus = i3c_master_get_bus(&master->base);
|
||||
u32 ppbaud, odbaud, odhpp, mconfig;
|
||||
unsigned long fclk_rate;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(master->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (speed) {
|
||||
case I3C_OPEN_DRAIN_SLOW_SPEED:
|
||||
fclk_rate = clk_get_rate(master->fclk);
|
||||
if (!fclk_rate) {
|
||||
ret = -EINVAL;
|
||||
goto rpm_out;
|
||||
}
|
||||
/*
|
||||
* Set 50% duty-cycle I2C speed to I3C OPEN-DRAIN mode, so the first
|
||||
* broadcast address is visible to all I2C/I3C devices on the I3C bus.
|
||||
* I3C device working as a I2C device will turn off its 50ns Spike
|
||||
* Filter to change to I3C mode.
|
||||
*/
|
||||
mconfig = master->mctrl_config;
|
||||
ppbaud = FIELD_GET(GENMASK(11, 8), mconfig);
|
||||
odhpp = 0;
|
||||
odbaud = DIV_ROUND_UP(fclk_rate, bus->scl_rate.i2c * (2 + 2 * ppbaud)) - 1;
|
||||
mconfig &= ~GENMASK(24, 16);
|
||||
mconfig |= SVC_I3C_MCONFIG_ODBAUD(odbaud) | SVC_I3C_MCONFIG_ODHPP(odhpp);
|
||||
writel(mconfig, master->regs + SVC_I3C_MCONFIG);
|
||||
break;
|
||||
case I3C_OPEN_DRAIN_NORMAL_SPEED:
|
||||
writel(master->mctrl_config, master->regs + SVC_I3C_MCONFIG);
|
||||
break;
|
||||
}
|
||||
|
||||
rpm_out:
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
|
||||
{
|
||||
struct svc_i3c_master *master = to_svc_i3c_master(m);
|
||||
@@ -596,6 +661,7 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
|
||||
SVC_I3C_MCONFIG_I2CBAUD(i2cbaud);
|
||||
writel(reg, master->regs + SVC_I3C_MCONFIG);
|
||||
|
||||
master->mctrl_config = reg;
|
||||
/* Master core's registration */
|
||||
ret = i3c_master_get_free_addr(m, 0);
|
||||
if (ret < 0)
|
||||
@@ -952,12 +1018,27 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m)
|
||||
goto rpm_out;
|
||||
}
|
||||
|
||||
/* Register all devices who participated to the core */
|
||||
for (i = 0; i < dev_nb; i++) {
|
||||
ret = i3c_master_add_i3c_dev_locked(m, addrs[i]);
|
||||
if (ret)
|
||||
goto rpm_out;
|
||||
}
|
||||
/*
|
||||
* Register all devices who participated to the core
|
||||
*
|
||||
* If two devices (A and B) are detected in DAA and address 0xa is assigned to
|
||||
* device A and 0xb to device B, a failure in i3c_master_add_i3c_dev_locked()
|
||||
* for device A (addr: 0xa) could prevent device B (addr: 0xb) from being
|
||||
* registered on the bus. The I3C stack might still consider 0xb a free
|
||||
* address. If a subsequent Hotjoin occurs, 0xb might be assigned to Device A,
|
||||
* causing both devices A and B to use the same address 0xb, violating the I3C
|
||||
* specification.
|
||||
*
|
||||
* The return value for i3c_master_add_i3c_dev_locked() should not be checked
|
||||
* because subsequent steps will scan the entire I3C bus, independent of
|
||||
* whether i3c_master_add_i3c_dev_locked() returns success.
|
||||
*
|
||||
* If device A registration fails, there is still a chance to register device
|
||||
* B. i3c_master_add_i3c_dev_locked() can reset DAA if a failure occurs while
|
||||
* retrieving device information.
|
||||
*/
|
||||
for (i = 0; i < dev_nb; i++)
|
||||
i3c_master_add_i3c_dev_locked(m, addrs[i]);
|
||||
|
||||
/* Configure IBI auto-rules */
|
||||
ret = svc_i3c_update_ibirules(master);
|
||||
@@ -1520,6 +1601,7 @@ static int svc_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
master->enabled_events++;
|
||||
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
|
||||
|
||||
return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
|
||||
@@ -1531,7 +1613,9 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
|
||||
struct svc_i3c_master *master = to_svc_i3c_master(m);
|
||||
int ret;
|
||||
|
||||
svc_i3c_master_disable_interrupts(master);
|
||||
master->enabled_events--;
|
||||
if (!master->enabled_events)
|
||||
svc_i3c_master_disable_interrupts(master);
|
||||
|
||||
ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
|
||||
|
||||
@@ -1541,6 +1625,39 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int svc_i3c_master_enable_hotjoin(struct i3c_master_controller *m)
|
||||
{
|
||||
struct svc_i3c_master *master = to_svc_i3c_master(m);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(master->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
master->enabled_events |= SVC_I3C_EVENT_HOTJOIN;
|
||||
|
||||
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int svc_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
|
||||
{
|
||||
struct svc_i3c_master *master = to_svc_i3c_master(m);
|
||||
|
||||
master->enabled_events &= ~SVC_I3C_EVENT_HOTJOIN;
|
||||
|
||||
if (!master->enabled_events)
|
||||
svc_i3c_master_disable_interrupts(master);
|
||||
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void svc_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
|
||||
struct i3c_ibi_slot *slot)
|
||||
{
|
||||
@@ -1567,6 +1684,9 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = {
|
||||
.recycle_ibi_slot = svc_i3c_master_recycle_ibi_slot,
|
||||
.enable_ibi = svc_i3c_master_enable_ibi,
|
||||
.disable_ibi = svc_i3c_master_disable_ibi,
|
||||
.enable_hotjoin = svc_i3c_master_enable_hotjoin,
|
||||
.disable_hotjoin = svc_i3c_master_disable_hotjoin,
|
||||
.set_speed = svc_i3c_master_set_speed,
|
||||
};
|
||||
|
||||
static int svc_i3c_master_prepare_clks(struct svc_i3c_master *master)
|
||||
|
||||
@@ -70,6 +70,10 @@ int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts,
|
||||
if (mult != ts->mult)
|
||||
ts->new_mult = mult;
|
||||
|
||||
/* When FIFO is off, directly apply the new ODR */
|
||||
if (!fifo)
|
||||
inv_sensors_timestamp_apply_odr(ts, 0, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_update_odr, IIO_INV_SENSORS_TIMESTAMP);
|
||||
|
||||
@@ -99,7 +99,6 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev,
|
||||
const unsigned long *scan_mask)
|
||||
{
|
||||
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
|
||||
struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
|
||||
struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
|
||||
unsigned int fifo_en = 0;
|
||||
unsigned int sleep_temp = 0;
|
||||
@@ -127,7 +126,6 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev,
|
||||
}
|
||||
|
||||
/* update data FIFO write */
|
||||
inv_sensors_timestamp_apply_odr(ts, 0, 0, 0);
|
||||
ret = inv_icm42600_buffer_set_fifo_en(st, fifo_en | st->fifo.en);
|
||||
|
||||
out_unlock:
|
||||
|
||||
@@ -99,7 +99,6 @@ static int inv_icm42600_gyro_update_scan_mode(struct iio_dev *indio_dev,
|
||||
const unsigned long *scan_mask)
|
||||
{
|
||||
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
|
||||
struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
|
||||
struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
|
||||
unsigned int fifo_en = 0;
|
||||
unsigned int sleep_gyro = 0;
|
||||
@@ -127,7 +126,6 @@ static int inv_icm42600_gyro_update_scan_mode(struct iio_dev *indio_dev,
|
||||
}
|
||||
|
||||
/* update data FIFO write */
|
||||
inv_sensors_timestamp_apply_odr(ts, 0, 0, 0);
|
||||
ret = inv_icm42600_buffer_set_fifo_en(st, fifo_en | st->fifo.en);
|
||||
|
||||
out_unlock:
|
||||
|
||||
@@ -111,7 +111,6 @@ int inv_mpu6050_prepare_fifo(struct inv_mpu6050_state *st, bool enable)
|
||||
if (enable) {
|
||||
/* reset timestamping */
|
||||
inv_sensors_timestamp_reset(&st->timestamp);
|
||||
inv_sensors_timestamp_apply_odr(&st->timestamp, 0, 0, 0);
|
||||
/* reset FIFO */
|
||||
d = st->chip_config.user_ctrl | INV_MPU6050_BIT_FIFO_RST;
|
||||
ret = regmap_write(st->map, st->reg->user_ctrl, d);
|
||||
|
||||
@@ -1612,6 +1612,8 @@ static const struct acpi_device_id ltr_acpi_match[] = {
|
||||
{ "LTER0501", ltr501 },
|
||||
{ "LTER0559", ltr559 },
|
||||
{ "LTER0301", ltr301 },
|
||||
/* https://www.catalog.update.microsoft.com/Search.aspx?q=lter0303 */
|
||||
{ "LTER0303", ltr303 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, ltr_acpi_match);
|
||||
|
||||
@@ -372,6 +372,7 @@ static int yas537_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y
|
||||
u8 data[8];
|
||||
u16 xy1y2[3];
|
||||
s32 h[3], s[3];
|
||||
int half_range = BIT(13);
|
||||
int i, ret;
|
||||
|
||||
mutex_lock(&yas5xx->lock);
|
||||
@@ -406,13 +407,13 @@ static int yas537_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y
|
||||
/* The second version of YAS537 needs to include calibration coefficients */
|
||||
if (yas5xx->version == YAS537_VERSION_1) {
|
||||
for (i = 0; i < 3; i++)
|
||||
s[i] = xy1y2[i] - BIT(13);
|
||||
h[0] = (c->k * (128 * s[0] + c->a2 * s[1] + c->a3 * s[2])) / BIT(13);
|
||||
h[1] = (c->k * (c->a4 * s[0] + c->a5 * s[1] + c->a6 * s[2])) / BIT(13);
|
||||
h[2] = (c->k * (c->a7 * s[0] + c->a8 * s[1] + c->a9 * s[2])) / BIT(13);
|
||||
s[i] = xy1y2[i] - half_range;
|
||||
h[0] = (c->k * (128 * s[0] + c->a2 * s[1] + c->a3 * s[2])) / half_range;
|
||||
h[1] = (c->k * (c->a4 * s[0] + c->a5 * s[1] + c->a6 * s[2])) / half_range;
|
||||
h[2] = (c->k * (c->a7 * s[0] + c->a8 * s[1] + c->a9 * s[2])) / half_range;
|
||||
for (i = 0; i < 3; i++) {
|
||||
clamp_val(h[i], -BIT(13), BIT(13) - 1);
|
||||
xy1y2[i] = h[i] + BIT(13);
|
||||
h[i] = clamp(h[i], -half_range, half_range - 1);
|
||||
xy1y2[i] = h[i] + half_range;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -348,15 +348,15 @@ static int dst_fetch_ha(const struct dst_entry *dst,
|
||||
|
||||
static bool has_gateway(const struct dst_entry *dst, sa_family_t family)
|
||||
{
|
||||
struct rtable *rt;
|
||||
struct rt6_info *rt6;
|
||||
const struct rtable *rt;
|
||||
const struct rt6_info *rt6;
|
||||
|
||||
if (family == AF_INET) {
|
||||
rt = container_of(dst, struct rtable, dst);
|
||||
return rt->rt_uses_gateway;
|
||||
}
|
||||
|
||||
rt6 = container_of(dst, struct rt6_info, dst);
|
||||
rt6 = dst_rt6_info(dst);
|
||||
return rt6->rt6i_flags & RTF_GATEWAY;
|
||||
}
|
||||
|
||||
|
||||
@@ -1359,6 +1359,17 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
|
||||
goto out_free;
|
||||
} else if (fwspec && fwspec->ops == &arm_smmu_ops) {
|
||||
smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
|
||||
|
||||
/*
|
||||
* Defer probe if the relevant SMMU instance hasn't finished
|
||||
* probing yet. This is a fragile hack and we'd ideally
|
||||
* avoid this race in the core code. Until that's ironed
|
||||
* out, however, this is the most pragmatic option on the
|
||||
* table.
|
||||
*/
|
||||
if (!smmu)
|
||||
return ERR_PTR(dev_err_probe(dev, -EPROBE_DEFER,
|
||||
"smmu dev has not bound yet\n"));
|
||||
} else {
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
@@ -29,11 +29,14 @@ static ssize_t brightness_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
unsigned int brightness;
|
||||
|
||||
/* no lock needed for this */
|
||||
mutex_lock(&led_cdev->led_access);
|
||||
led_update_brightness(led_cdev);
|
||||
brightness = led_cdev->brightness;
|
||||
mutex_unlock(&led_cdev->led_access);
|
||||
|
||||
return sprintf(buf, "%u\n", led_cdev->brightness);
|
||||
return sprintf(buf, "%u\n", brightness);
|
||||
}
|
||||
|
||||
static ssize_t brightness_store(struct device *dev,
|
||||
@@ -70,8 +73,13 @@ static ssize_t max_brightness_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
unsigned int max_brightness;
|
||||
|
||||
return sprintf(buf, "%u\n", led_cdev->max_brightness);
|
||||
mutex_lock(&led_cdev->led_access);
|
||||
max_brightness = led_cdev->max_brightness;
|
||||
mutex_unlock(&led_cdev->led_access);
|
||||
|
||||
return sprintf(buf, "%u\n", max_brightness);
|
||||
}
|
||||
static DEVICE_ATTR_RO(max_brightness);
|
||||
|
||||
|
||||
@@ -1724,7 +1724,7 @@ static void cache_set_flush(struct closure *cl)
|
||||
if (!IS_ERR_OR_NULL(c->gc_thread))
|
||||
kthread_stop(c->gc_thread);
|
||||
|
||||
if (!IS_ERR(c->root))
|
||||
if (!IS_ERR_OR_NULL(c->root))
|
||||
list_add(&c->root->list, &c->btree_cache);
|
||||
|
||||
/*
|
||||
|
||||
@@ -994,6 +994,8 @@ const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
|
||||
|
||||
/* table of devices that work with this driver */
|
||||
struct usb_device_id cx231xx_id_table[] = {
|
||||
{USB_DEVICE(0x1D19, 0x6108),
|
||||
.driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
|
||||
{USB_DEVICE(0x1D19, 0x6109),
|
||||
.driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
|
||||
{USB_DEVICE(0x0572, 0x5A3C),
|
||||
|
||||
@@ -2488,6 +2488,8 @@ static const struct uvc_device_info uvc_quirk_force_y8 = {
|
||||
* The Logitech cameras listed below have their interface class set to
|
||||
* VENDOR_SPEC because they don't announce themselves as UVC devices, even
|
||||
* though they are compliant.
|
||||
*
|
||||
* Sort these by vendor/product ID.
|
||||
*/
|
||||
static const struct usb_device_id uvc_ids[] = {
|
||||
/* Quanta USB2.0 HD UVC Webcam */
|
||||
@@ -3076,6 +3078,15 @@ static const struct usb_device_id uvc_ids[] = {
|
||||
.bInterfaceProtocol = 0,
|
||||
.driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_MINMAX
|
||||
| UVC_QUIRK_IGNORE_SELECTOR_UNIT) },
|
||||
/* NXP Semiconductors IR VIDEO */
|
||||
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
|
||||
| USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x1fc9,
|
||||
.idProduct = 0x009b,
|
||||
.bInterfaceClass = USB_CLASS_VIDEO,
|
||||
.bInterfaceSubClass = 1,
|
||||
.bInterfaceProtocol = 0,
|
||||
.driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax },
|
||||
/* Oculus VR Positional Tracker DK2 */
|
||||
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
|
||||
| USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
@@ -3229,6 +3240,15 @@ static const struct usb_device_id uvc_ids[] = {
|
||||
.bInterfaceSubClass = 1,
|
||||
.bInterfaceProtocol = 0,
|
||||
.driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) },
|
||||
/* Intel D421 Depth Module */
|
||||
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
|
||||
| USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x8086,
|
||||
.idProduct = 0x1155,
|
||||
.bInterfaceClass = USB_CLASS_VIDEO,
|
||||
.bInterfaceSubClass = 1,
|
||||
.bInterfaceProtocol = 0,
|
||||
.driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) },
|
||||
/* Generic USB Video Class */
|
||||
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
|
||||
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) },
|
||||
|
||||
@@ -186,6 +186,11 @@ void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, const u8 word,
|
||||
eeprom_93cx6_write_bits(eeprom, command,
|
||||
PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
|
||||
|
||||
if (has_quirk_extra_read_cycle(eeprom)) {
|
||||
eeprom_93cx6_pulse_high(eeprom);
|
||||
eeprom_93cx6_pulse_low(eeprom);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the requested 16 bits.
|
||||
*/
|
||||
@@ -252,6 +257,11 @@ void eeprom_93cx6_readb(struct eeprom_93cx6 *eeprom, const u8 byte,
|
||||
eeprom_93cx6_write_bits(eeprom, command,
|
||||
PCI_EEPROM_WIDTH_OPCODE + eeprom->width + 1);
|
||||
|
||||
if (has_quirk_extra_read_cycle(eeprom)) {
|
||||
eeprom_93cx6_pulse_high(eeprom);
|
||||
eeprom_93cx6_pulse_low(eeprom);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the requested 8 bits.
|
||||
*/
|
||||
|
||||
@@ -149,6 +149,8 @@ static void mmc_bus_shutdown(struct device *dev)
|
||||
if (dev->driver && drv->shutdown)
|
||||
drv->shutdown(card);
|
||||
|
||||
__mmc_stop_host(host);
|
||||
|
||||
if (host->bus_ops->shutdown) {
|
||||
ret = host->bus_ops->shutdown(host);
|
||||
if (ret)
|
||||
|
||||
@@ -82,6 +82,7 @@ struct mmc_fixup {
|
||||
#define CID_MANFID_SANDISK_SD 0x3
|
||||
#define CID_MANFID_ATP 0x9
|
||||
#define CID_MANFID_TOSHIBA 0x11
|
||||
#define CID_MANFID_GIGASTONE 0x12
|
||||
#define CID_MANFID_MICRON 0x13
|
||||
#define CID_MANFID_SAMSUNG 0x15
|
||||
#define CID_MANFID_APACER 0x27
|
||||
@@ -284,4 +285,10 @@ static inline int mmc_card_broken_cache_flush(const struct mmc_card *c)
|
||||
{
|
||||
return c->quirks & MMC_QUIRK_BROKEN_CACHE_FLUSH;
|
||||
}
|
||||
|
||||
static inline int mmc_card_broken_sd_poweroff_notify(const struct mmc_card *c)
|
||||
{
|
||||
return c->quirks & MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2296,6 +2296,9 @@ void mmc_start_host(struct mmc_host *host)
|
||||
|
||||
void __mmc_stop_host(struct mmc_host *host)
|
||||
{
|
||||
if (host->rescan_disable)
|
||||
return;
|
||||
|
||||
if (host->slot.cd_irq >= 0) {
|
||||
mmc_gpio_set_cd_wake(host, false);
|
||||
disable_irq(host->slot.cd_irq);
|
||||
|
||||
@@ -25,6 +25,15 @@ static const struct mmc_fixup __maybe_unused mmc_sd_fixups[] = {
|
||||
0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
|
||||
MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
|
||||
|
||||
/*
|
||||
* GIGASTONE Gaming Plus microSD cards manufactured on 02/2022 never
|
||||
* clear Flush Cache bit and set Poweroff Notification Ready bit.
|
||||
*/
|
||||
_FIXUP_EXT("ASTC", CID_MANFID_GIGASTONE, 0x3456, 2022, 2,
|
||||
0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
|
||||
MMC_QUIRK_BROKEN_SD_CACHE | MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY,
|
||||
EXT_CSD_REV_ANY),
|
||||
|
||||
END_FIXUP
|
||||
};
|
||||
|
||||
|
||||
@@ -1118,7 +1118,7 @@ static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
|
||||
card->ext_power.rev = reg_buf[0] & 0xf;
|
||||
|
||||
/* Power Off Notification support at bit 4. */
|
||||
if (reg_buf[1] & BIT(4))
|
||||
if ((reg_buf[1] & BIT(4)) && !mmc_card_broken_sd_poweroff_notify(card))
|
||||
card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY;
|
||||
|
||||
/* Power Sustenance support at bit 5. */
|
||||
|
||||
@@ -2674,20 +2674,18 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* Allocate MMC host for this device */
|
||||
mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev);
|
||||
mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(struct msdc_host));
|
||||
if (!mmc)
|
||||
return -ENOMEM;
|
||||
|
||||
host = mmc_priv(mmc);
|
||||
ret = mmc_of_parse(mmc);
|
||||
if (ret)
|
||||
goto host_free;
|
||||
return ret;
|
||||
|
||||
host->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(host->base)) {
|
||||
ret = PTR_ERR(host->base);
|
||||
goto host_free;
|
||||
}
|
||||
if (IS_ERR(host->base))
|
||||
return PTR_ERR(host->base);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (res) {
|
||||
@@ -2698,53 +2696,45 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
|
||||
ret = mmc_regulator_get_supply(mmc);
|
||||
if (ret)
|
||||
goto host_free;
|
||||
return ret;
|
||||
|
||||
ret = msdc_of_clock_parse(pdev, host);
|
||||
if (ret)
|
||||
goto host_free;
|
||||
return ret;
|
||||
|
||||
host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
|
||||
"hrst");
|
||||
if (IS_ERR(host->reset)) {
|
||||
ret = PTR_ERR(host->reset);
|
||||
goto host_free;
|
||||
}
|
||||
if (IS_ERR(host->reset))
|
||||
return PTR_ERR(host->reset);
|
||||
|
||||
/* only eMMC has crypto property */
|
||||
if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) {
|
||||
host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto");
|
||||
if (IS_ERR(host->crypto_clk))
|
||||
host->crypto_clk = NULL;
|
||||
else
|
||||
return PTR_ERR(host->crypto_clk);
|
||||
else if (host->crypto_clk)
|
||||
mmc->caps2 |= MMC_CAP2_CRYPTO;
|
||||
}
|
||||
|
||||
host->irq = platform_get_irq(pdev, 0);
|
||||
if (host->irq < 0) {
|
||||
ret = host->irq;
|
||||
goto host_free;
|
||||
}
|
||||
if (host->irq < 0)
|
||||
return host->irq;
|
||||
|
||||
host->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (IS_ERR(host->pinctrl)) {
|
||||
ret = PTR_ERR(host->pinctrl);
|
||||
dev_err(&pdev->dev, "Cannot find pinctrl!\n");
|
||||
goto host_free;
|
||||
}
|
||||
if (IS_ERR(host->pinctrl))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(host->pinctrl),
|
||||
"Cannot find pinctrl");
|
||||
|
||||
host->pins_default = pinctrl_lookup_state(host->pinctrl, "default");
|
||||
if (IS_ERR(host->pins_default)) {
|
||||
ret = PTR_ERR(host->pins_default);
|
||||
dev_err(&pdev->dev, "Cannot find pinctrl default!\n");
|
||||
goto host_free;
|
||||
return PTR_ERR(host->pins_default);
|
||||
}
|
||||
|
||||
host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs");
|
||||
if (IS_ERR(host->pins_uhs)) {
|
||||
ret = PTR_ERR(host->pins_uhs);
|
||||
dev_err(&pdev->dev, "Cannot find pinctrl uhs!\n");
|
||||
goto host_free;
|
||||
return PTR_ERR(host->pins_uhs);
|
||||
}
|
||||
|
||||
/* Support for SDIO eint irq ? */
|
||||
@@ -2823,7 +2813,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
ret = msdc_ungate_clock(host);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Cannot ungate clocks!\n");
|
||||
goto release_mem;
|
||||
goto release_clk;
|
||||
}
|
||||
msdc_init_hw(host);
|
||||
|
||||
@@ -2833,14 +2823,14 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
GFP_KERNEL);
|
||||
if (!host->cq_host) {
|
||||
ret = -ENOMEM;
|
||||
goto host_free;
|
||||
goto release;
|
||||
}
|
||||
host->cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
|
||||
host->cq_host->mmio = host->base + 0x800;
|
||||
host->cq_host->ops = &msdc_cmdq_ops;
|
||||
ret = cqhci_init(host->cq_host, mmc, true);
|
||||
if (ret)
|
||||
goto host_free;
|
||||
goto release;
|
||||
mmc->max_segs = 128;
|
||||
/* cqhci 16bit length */
|
||||
/* 0 size, means 65536 so we don't have to -1 here */
|
||||
@@ -2867,9 +2857,10 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
end:
|
||||
pm_runtime_disable(host->dev);
|
||||
release:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
msdc_deinit_hw(host);
|
||||
release_clk:
|
||||
msdc_gate_clock(host);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
release_mem:
|
||||
if (host->dma.gpd)
|
||||
dma_free_coherent(&pdev->dev,
|
||||
@@ -2877,11 +2868,8 @@ release_mem:
|
||||
host->dma.gpd, host->dma.gpd_addr);
|
||||
if (host->dma.bd)
|
||||
dma_free_coherent(&pdev->dev,
|
||||
MAX_BD_NUM * sizeof(struct mt_bdma_desc),
|
||||
host->dma.bd, host->dma.bd_addr);
|
||||
host_free:
|
||||
mmc_free_host(mmc);
|
||||
|
||||
MAX_BD_NUM * sizeof(struct mt_bdma_desc),
|
||||
host->dma.bd, host->dma.bd_addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2906,9 +2894,7 @@ static void msdc_drv_remove(struct platform_device *pdev)
|
||||
2 * sizeof(struct mt_gpdma_desc),
|
||||
host->dma.gpd, host->dma.gpd_addr);
|
||||
dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc),
|
||||
host->dma.bd, host->dma.bd_addr);
|
||||
|
||||
mmc_free_host(mmc);
|
||||
host->dma.bd, host->dma.bd_addr);
|
||||
}
|
||||
|
||||
static void msdc_save_reg(struct msdc_host *host)
|
||||
|
||||
@@ -235,6 +235,7 @@ struct esdhc_platform_data {
|
||||
|
||||
struct esdhc_soc_data {
|
||||
u32 flags;
|
||||
u32 quirks;
|
||||
};
|
||||
|
||||
static const struct esdhc_soc_data esdhc_imx25_data = {
|
||||
@@ -306,10 +307,12 @@ static struct esdhc_soc_data usdhc_imx7ulp_data = {
|
||||
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
|
||||
| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400
|
||||
| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
|
||||
.quirks = SDHCI_QUIRK_NO_LED,
|
||||
};
|
||||
static struct esdhc_soc_data usdhc_imxrt1050_data = {
|
||||
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
|
||||
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
|
||||
.quirks = SDHCI_QUIRK_NO_LED,
|
||||
};
|
||||
|
||||
static struct esdhc_soc_data usdhc_imx8qxp_data = {
|
||||
@@ -318,6 +321,7 @@ static struct esdhc_soc_data usdhc_imx8qxp_data = {
|
||||
| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
|
||||
| ESDHC_FLAG_STATE_LOST_IN_LPMODE
|
||||
| ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME,
|
||||
.quirks = SDHCI_QUIRK_NO_LED,
|
||||
};
|
||||
|
||||
static struct esdhc_soc_data usdhc_imx8mm_data = {
|
||||
@@ -325,6 +329,7 @@ static struct esdhc_soc_data usdhc_imx8mm_data = {
|
||||
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
|
||||
| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
|
||||
| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
|
||||
.quirks = SDHCI_QUIRK_NO_LED,
|
||||
};
|
||||
|
||||
struct pltfm_imx_data {
|
||||
@@ -1664,6 +1669,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
|
||||
|
||||
imx_data->socdata = device_get_match_data(&pdev->dev);
|
||||
|
||||
host->quirks |= imx_data->socdata->quirks;
|
||||
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
|
||||
cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/debugfs.h>
|
||||
@@ -1234,6 +1235,29 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
|
||||
.priv_size = sizeof(struct intel_host),
|
||||
};
|
||||
|
||||
/* DMI quirks for devices with missing or broken CD GPIO info */
|
||||
static const struct gpiod_lookup_table vexia_edu_atla10_cd_gpios = {
|
||||
.dev_id = "0000:00:12.0",
|
||||
.table = {
|
||||
GPIO_LOOKUP("INT33FC:00", 38, "cd", GPIO_ACTIVE_HIGH),
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static const struct dmi_system_id sdhci_intel_byt_cd_gpio_override[] = {
|
||||
{
|
||||
/* Vexia Edu Atla 10 tablet 9V version */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
|
||||
/* Above strings are too generic, also match on BIOS date */
|
||||
DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"),
|
||||
},
|
||||
.driver_data = (void *)&vexia_edu_atla10_cd_gpios,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.resume = byt_resume,
|
||||
@@ -1252,6 +1276,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
|
||||
.add_host = byt_add_host,
|
||||
.remove_slot = byt_remove_slot,
|
||||
.ops = &sdhci_intel_byt_ops,
|
||||
.cd_gpio_override = sdhci_intel_byt_cd_gpio_override,
|
||||
.priv_size = sizeof(struct intel_host),
|
||||
};
|
||||
|
||||
@@ -2036,6 +2061,42 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = {
|
||||
* *
|
||||
\*****************************************************************************/
|
||||
|
||||
static struct gpiod_lookup_table *sdhci_pci_add_gpio_lookup_table(
|
||||
struct sdhci_pci_chip *chip)
|
||||
{
|
||||
struct gpiod_lookup_table *cd_gpio_lookup_table;
|
||||
const struct dmi_system_id *dmi_id = NULL;
|
||||
size_t count;
|
||||
|
||||
if (chip->fixes && chip->fixes->cd_gpio_override)
|
||||
dmi_id = dmi_first_match(chip->fixes->cd_gpio_override);
|
||||
|
||||
if (!dmi_id)
|
||||
return NULL;
|
||||
|
||||
cd_gpio_lookup_table = dmi_id->driver_data;
|
||||
for (count = 0; cd_gpio_lookup_table->table[count].key; count++)
|
||||
;
|
||||
|
||||
cd_gpio_lookup_table = kmemdup(dmi_id->driver_data,
|
||||
/* count + 1 terminating entry */
|
||||
struct_size(cd_gpio_lookup_table, table, count + 1),
|
||||
GFP_KERNEL);
|
||||
if (!cd_gpio_lookup_table)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
gpiod_add_lookup_table(cd_gpio_lookup_table);
|
||||
return cd_gpio_lookup_table;
|
||||
}
|
||||
|
||||
static void sdhci_pci_remove_gpio_lookup_table(struct gpiod_lookup_table *lookup_table)
|
||||
{
|
||||
if (lookup_table) {
|
||||
gpiod_remove_lookup_table(lookup_table);
|
||||
kfree(lookup_table);
|
||||
}
|
||||
}
|
||||
|
||||
static struct sdhci_pci_slot *sdhci_pci_probe_slot(
|
||||
struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar,
|
||||
int slotno)
|
||||
@@ -2111,8 +2172,19 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
|
||||
if (slot->cd_idx >= 0) {
|
||||
struct gpiod_lookup_table *cd_gpio_lookup_table;
|
||||
|
||||
cd_gpio_lookup_table = sdhci_pci_add_gpio_lookup_table(chip);
|
||||
if (IS_ERR(cd_gpio_lookup_table)) {
|
||||
ret = PTR_ERR(cd_gpio_lookup_table);
|
||||
goto remove;
|
||||
}
|
||||
|
||||
ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx,
|
||||
slot->cd_override_level, 0);
|
||||
|
||||
sdhci_pci_remove_gpio_lookup_table(cd_gpio_lookup_table);
|
||||
|
||||
if (ret && ret != -EPROBE_DEFER)
|
||||
ret = mmc_gpiod_request_cd(host->mmc, NULL,
|
||||
slot->cd_idx,
|
||||
|
||||
@@ -156,6 +156,7 @@ struct sdhci_pci_fixes {
|
||||
#endif
|
||||
|
||||
const struct sdhci_ops *ops;
|
||||
const struct dmi_system_id *cd_gpio_override;
|
||||
size_t priv_size;
|
||||
};
|
||||
|
||||
|
||||
@@ -1014,49 +1014,57 @@ static int c_can_handle_bus_err(struct net_device *dev,
|
||||
|
||||
/* propagate the error condition to the CAN stack */
|
||||
skb = alloc_can_err_skb(dev, &cf);
|
||||
if (unlikely(!skb))
|
||||
return 0;
|
||||
|
||||
/* check for 'last error code' which tells us the
|
||||
* type of the last error to occur on the CAN bus
|
||||
*/
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
if (likely(skb))
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
|
||||
switch (lec_type) {
|
||||
case LEC_STUFF_ERROR:
|
||||
netdev_dbg(dev, "stuff error\n");
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
stats->rx_errors++;
|
||||
break;
|
||||
case LEC_FORM_ERROR:
|
||||
netdev_dbg(dev, "form error\n");
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
stats->rx_errors++;
|
||||
break;
|
||||
case LEC_ACK_ERROR:
|
||||
netdev_dbg(dev, "ack error\n");
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_ACK;
|
||||
if (likely(skb))
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_ACK;
|
||||
stats->tx_errors++;
|
||||
break;
|
||||
case LEC_BIT1_ERROR:
|
||||
netdev_dbg(dev, "bit1 error\n");
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT1;
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT1;
|
||||
stats->tx_errors++;
|
||||
break;
|
||||
case LEC_BIT0_ERROR:
|
||||
netdev_dbg(dev, "bit0 error\n");
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT0;
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT0;
|
||||
stats->tx_errors++;
|
||||
break;
|
||||
case LEC_CRC_ERROR:
|
||||
netdev_dbg(dev, "CRC error\n");
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
|
||||
if (likely(skb))
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
|
||||
stats->rx_errors++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely(!skb))
|
||||
return 0;
|
||||
|
||||
netif_receive_skb(skb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ static int can_set_termination(struct net_device *ndev, u16 term)
|
||||
else
|
||||
set = 0;
|
||||
|
||||
gpiod_set_value(priv->termination_gpio, set);
|
||||
gpiod_set_value_cansleep(priv->termination_gpio, set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -390,36 +390,55 @@ static int ifi_canfd_handle_lec_err(struct net_device *ndev)
|
||||
return 0;
|
||||
|
||||
priv->can.can_stats.bus_error++;
|
||||
stats->rx_errors++;
|
||||
|
||||
/* Propagate the error condition to the CAN stack. */
|
||||
skb = alloc_can_err_skb(ndev, &cf);
|
||||
if (unlikely(!skb))
|
||||
return 0;
|
||||
|
||||
/* Read the error counter register and check for new errors. */
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
if (likely(skb))
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST)
|
||||
cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST) {
|
||||
stats->rx_errors++;
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
|
||||
}
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST)
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_ACK;
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST) {
|
||||
stats->tx_errors++;
|
||||
if (likely(skb))
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_ACK;
|
||||
}
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST)
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT0;
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST) {
|
||||
stats->tx_errors++;
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT0;
|
||||
}
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST)
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT1;
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST) {
|
||||
stats->tx_errors++;
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT1;
|
||||
}
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST)
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST) {
|
||||
stats->rx_errors++;
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
}
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST)
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST) {
|
||||
stats->rx_errors++;
|
||||
if (likely(skb))
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
|
||||
}
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST)
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST) {
|
||||
stats->rx_errors++;
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
}
|
||||
|
||||
/* Reset the error counter, ack the IRQ and re-enable the counter. */
|
||||
writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR);
|
||||
@@ -427,6 +446,9 @@ static int ifi_canfd_handle_lec_err(struct net_device *ndev)
|
||||
priv->base + IFI_CANFD_INTERRUPT);
|
||||
writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR);
|
||||
|
||||
if (unlikely(!skb))
|
||||
return 0;
|
||||
|
||||
netif_receive_skb(skb);
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -636,47 +636,60 @@ static int m_can_handle_lec_err(struct net_device *dev,
|
||||
u32 timestamp = 0;
|
||||
|
||||
cdev->can.can_stats.bus_error++;
|
||||
stats->rx_errors++;
|
||||
|
||||
/* propagate the error condition to the CAN stack */
|
||||
skb = alloc_can_err_skb(dev, &cf);
|
||||
if (unlikely(!skb))
|
||||
return 0;
|
||||
|
||||
/* check for 'last error code' which tells us the
|
||||
* type of the last error to occur on the CAN bus
|
||||
*/
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
if (likely(skb))
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
|
||||
switch (lec_type) {
|
||||
case LEC_STUFF_ERROR:
|
||||
netdev_dbg(dev, "stuff error\n");
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
stats->rx_errors++;
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
break;
|
||||
case LEC_FORM_ERROR:
|
||||
netdev_dbg(dev, "form error\n");
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
stats->rx_errors++;
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
break;
|
||||
case LEC_ACK_ERROR:
|
||||
netdev_dbg(dev, "ack error\n");
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_ACK;
|
||||
stats->tx_errors++;
|
||||
if (likely(skb))
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_ACK;
|
||||
break;
|
||||
case LEC_BIT1_ERROR:
|
||||
netdev_dbg(dev, "bit1 error\n");
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT1;
|
||||
stats->tx_errors++;
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT1;
|
||||
break;
|
||||
case LEC_BIT0_ERROR:
|
||||
netdev_dbg(dev, "bit0 error\n");
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT0;
|
||||
stats->tx_errors++;
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT0;
|
||||
break;
|
||||
case LEC_CRC_ERROR:
|
||||
netdev_dbg(dev, "CRC error\n");
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
|
||||
stats->rx_errors++;
|
||||
if (likely(skb))
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely(!skb))
|
||||
return 0;
|
||||
|
||||
if (cdev->is_peripheral)
|
||||
timestamp = m_can_get_timestamp(cdev);
|
||||
|
||||
|
||||
@@ -416,8 +416,6 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
||||
int ret = 0;
|
||||
|
||||
skb = alloc_can_err_skb(dev, &cf);
|
||||
if (skb == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
txerr = priv->read_reg(priv, SJA1000_TXERR);
|
||||
rxerr = priv->read_reg(priv, SJA1000_RXERR);
|
||||
@@ -425,8 +423,11 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
||||
if (isrc & IRQ_DOI) {
|
||||
/* data overrun interrupt */
|
||||
netdev_dbg(dev, "data overrun interrupt\n");
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
||||
}
|
||||
|
||||
stats->rx_over_errors++;
|
||||
stats->rx_errors++;
|
||||
sja1000_write_cmdreg(priv, CMD_CDO); /* clear bit */
|
||||
@@ -452,7 +453,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
||||
else
|
||||
state = CAN_STATE_ERROR_ACTIVE;
|
||||
}
|
||||
if (state != CAN_STATE_BUS_OFF) {
|
||||
if (state != CAN_STATE_BUS_OFF && skb) {
|
||||
cf->can_id |= CAN_ERR_CNT;
|
||||
cf->data[6] = txerr;
|
||||
cf->data[7] = rxerr;
|
||||
@@ -460,33 +461,38 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
||||
if (isrc & IRQ_BEI) {
|
||||
/* bus error interrupt */
|
||||
priv->can.can_stats.bus_error++;
|
||||
stats->rx_errors++;
|
||||
|
||||
ecc = priv->read_reg(priv, SJA1000_ECC);
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
/* set error type */
|
||||
switch (ecc & ECC_MASK) {
|
||||
case ECC_BIT:
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT;
|
||||
break;
|
||||
case ECC_FORM:
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
break;
|
||||
case ECC_STUFF:
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* set error type */
|
||||
switch (ecc & ECC_MASK) {
|
||||
case ECC_BIT:
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT;
|
||||
break;
|
||||
case ECC_FORM:
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
break;
|
||||
case ECC_STUFF:
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
/* set error location */
|
||||
cf->data[3] = ecc & ECC_SEG;
|
||||
}
|
||||
|
||||
/* set error location */
|
||||
cf->data[3] = ecc & ECC_SEG;
|
||||
|
||||
/* Error occurred during transmission? */
|
||||
if ((ecc & ECC_DIR) == 0)
|
||||
cf->data[2] |= CAN_ERR_PROT_TX;
|
||||
if ((ecc & ECC_DIR) == 0) {
|
||||
stats->tx_errors++;
|
||||
if (skb)
|
||||
cf->data[2] |= CAN_ERR_PROT_TX;
|
||||
} else {
|
||||
stats->rx_errors++;
|
||||
}
|
||||
}
|
||||
if (isrc & IRQ_EPI) {
|
||||
/* error passive interrupt */
|
||||
@@ -502,8 +508,10 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
||||
netdev_dbg(dev, "arbitration lost interrupt\n");
|
||||
alc = priv->read_reg(priv, SJA1000_ALC);
|
||||
priv->can.can_stats.arbitration_lost++;
|
||||
cf->can_id |= CAN_ERR_LOSTARB;
|
||||
cf->data[0] = alc & 0x1f;
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_LOSTARB;
|
||||
cf->data[0] = alc & 0x1f;
|
||||
}
|
||||
}
|
||||
|
||||
if (state != priv->can.state) {
|
||||
@@ -516,6 +524,9 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
||||
can_bus_off(dev);
|
||||
}
|
||||
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
netif_rx(skb);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -671,9 +671,9 @@ static irqreturn_t hi3110_can_ist(int irq, void *dev_id)
|
||||
tx_state = txerr >= rxerr ? new_state : 0;
|
||||
rx_state = txerr <= rxerr ? new_state : 0;
|
||||
can_change_state(net, cf, tx_state, rx_state);
|
||||
netif_rx(skb);
|
||||
|
||||
if (new_state == CAN_STATE_BUS_OFF) {
|
||||
netif_rx(skb);
|
||||
can_bus_off(net);
|
||||
if (priv->can.restart_ms == 0) {
|
||||
priv->force_quit = 1;
|
||||
@@ -684,6 +684,7 @@ static irqreturn_t hi3110_can_ist(int irq, void *dev_id)
|
||||
cf->can_id |= CAN_ERR_CNT;
|
||||
cf->data[6] = txerr;
|
||||
cf->data[7] = rxerr;
|
||||
netif_rx(skb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -696,27 +697,38 @@ static irqreturn_t hi3110_can_ist(int irq, void *dev_id)
|
||||
/* Check for protocol errors */
|
||||
if (eflag & HI3110_ERR_PROTOCOL_MASK) {
|
||||
skb = alloc_can_err_skb(net, &cf);
|
||||
if (!skb)
|
||||
break;
|
||||
if (skb)
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
priv->can.can_stats.bus_error++;
|
||||
priv->net->stats.rx_errors++;
|
||||
if (eflag & HI3110_ERR_BITERR)
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT;
|
||||
else if (eflag & HI3110_ERR_FRMERR)
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
else if (eflag & HI3110_ERR_STUFERR)
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
else if (eflag & HI3110_ERR_CRCERR)
|
||||
cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
|
||||
else if (eflag & HI3110_ERR_ACKERR)
|
||||
cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
|
||||
if (eflag & HI3110_ERR_BITERR) {
|
||||
priv->net->stats.tx_errors++;
|
||||
if (skb)
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT;
|
||||
} else if (eflag & HI3110_ERR_FRMERR) {
|
||||
priv->net->stats.rx_errors++;
|
||||
if (skb)
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
} else if (eflag & HI3110_ERR_STUFERR) {
|
||||
priv->net->stats.rx_errors++;
|
||||
if (skb)
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
} else if (eflag & HI3110_ERR_CRCERR) {
|
||||
priv->net->stats.rx_errors++;
|
||||
if (skb)
|
||||
cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
|
||||
} else if (eflag & HI3110_ERR_ACKERR) {
|
||||
priv->net->stats.tx_errors++;
|
||||
if (skb)
|
||||
cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
|
||||
}
|
||||
|
||||
cf->data[6] = hi3110_read(spi, HI3110_READ_TEC);
|
||||
cf->data[7] = hi3110_read(spi, HI3110_READ_REC);
|
||||
netdev_dbg(priv->net, "Bus Error\n");
|
||||
netif_rx(skb);
|
||||
if (skb) {
|
||||
cf->data[6] = hi3110_read(spi, HI3110_READ_TEC);
|
||||
cf->data[7] = hi3110_read(spi, HI3110_READ_REC);
|
||||
netif_rx(skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,11 @@ static inline bool mcp251xfd_tx_fifo_sta_empty(u32 fifo_sta)
|
||||
return fifo_sta & MCP251XFD_REG_FIFOSTA_TFERFFIF;
|
||||
}
|
||||
|
||||
static inline bool mcp251xfd_tx_fifo_sta_less_than_half_full(u32 fifo_sta)
|
||||
{
|
||||
return fifo_sta & MCP251XFD_REG_FIFOSTA_TFHRFHIF;
|
||||
}
|
||||
|
||||
static inline int
|
||||
mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv,
|
||||
u8 *tef_tail)
|
||||
@@ -147,7 +152,29 @@ mcp251xfd_get_tef_len(struct mcp251xfd_priv *priv, u8 *len_p)
|
||||
BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(len));
|
||||
|
||||
len = (chip_tx_tail << shift) - (tail << shift);
|
||||
*len_p = len >> shift;
|
||||
len >>= shift;
|
||||
|
||||
/* According to mcp2518fd erratum DS80000789E 6. the FIFOCI
|
||||
* bits of a FIFOSTA register, here the TX-FIFO tail index
|
||||
* might be corrupted.
|
||||
*
|
||||
* However here it seems the bit indicating that the TX-FIFO
|
||||
* is empty (MCP251XFD_REG_FIFOSTA_TFERFFIF) is not correct
|
||||
* while the TX-FIFO tail index is.
|
||||
*
|
||||
* We assume the TX-FIFO is empty, i.e. all pending CAN frames
|
||||
* haven been send, if:
|
||||
* - Chip's head and tail index are equal (len == 0).
|
||||
* - The TX-FIFO is less than half full.
|
||||
* (The TX-FIFO empty case has already been checked at the
|
||||
* beginning of this function.)
|
||||
* - No free buffers in the TX ring.
|
||||
*/
|
||||
if (len == 0 && mcp251xfd_tx_fifo_sta_less_than_half_full(fifo_sta) &&
|
||||
mcp251xfd_get_tx_free(tx_ring) == 0)
|
||||
len = tx_ring->obj_num;
|
||||
|
||||
*len_p = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -579,11 +579,9 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status)
|
||||
/* bus error interrupt */
|
||||
netdev_dbg(dev, "bus error interrupt\n");
|
||||
priv->can.can_stats.bus_error++;
|
||||
stats->rx_errors++;
|
||||
ecc = readl(priv->base + SUN4I_REG_STA_ADDR);
|
||||
|
||||
if (likely(skb)) {
|
||||
ecc = readl(priv->base + SUN4I_REG_STA_ADDR);
|
||||
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
|
||||
switch (ecc & SUN4I_STA_MASK_ERR) {
|
||||
@@ -601,9 +599,15 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status)
|
||||
>> 16;
|
||||
break;
|
||||
}
|
||||
/* error occurred during transmission? */
|
||||
if ((ecc & SUN4I_STA_ERR_DIR) == 0)
|
||||
}
|
||||
|
||||
/* error occurred during transmission? */
|
||||
if ((ecc & SUN4I_STA_ERR_DIR) == 0) {
|
||||
if (likely(skb))
|
||||
cf->data[2] |= CAN_ERR_PROT_TX;
|
||||
stats->tx_errors++;
|
||||
} else {
|
||||
stats->rx_errors++;
|
||||
}
|
||||
}
|
||||
if (isrc & SUN4I_INT_ERR_PASSIVE) {
|
||||
@@ -629,10 +633,10 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status)
|
||||
tx_state = txerr >= rxerr ? state : 0;
|
||||
rx_state = txerr <= rxerr ? state : 0;
|
||||
|
||||
if (likely(skb))
|
||||
can_change_state(dev, cf, tx_state, rx_state);
|
||||
else
|
||||
priv->can.state = state;
|
||||
/* The skb allocation might fail, but can_change_state()
|
||||
* handles cf == NULL.
|
||||
*/
|
||||
can_change_state(dev, cf, tx_state, rx_state);
|
||||
if (state == CAN_STATE_BUS_OFF)
|
||||
can_bus_off(dev);
|
||||
}
|
||||
|
||||
@@ -335,15 +335,14 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
|
||||
struct net_device_stats *stats = &dev->netdev->stats;
|
||||
|
||||
skb = alloc_can_err_skb(dev->netdev, &cf);
|
||||
if (skb == NULL)
|
||||
return;
|
||||
|
||||
if (msg->type == CPC_MSG_TYPE_CAN_STATE) {
|
||||
u8 state = msg->msg.can_state;
|
||||
|
||||
if (state & SJA1000_SR_BS) {
|
||||
dev->can.state = CAN_STATE_BUS_OFF;
|
||||
cf->can_id |= CAN_ERR_BUSOFF;
|
||||
if (skb)
|
||||
cf->can_id |= CAN_ERR_BUSOFF;
|
||||
|
||||
dev->can.can_stats.bus_off++;
|
||||
can_bus_off(dev->netdev);
|
||||
@@ -361,44 +360,53 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
|
||||
|
||||
/* bus error interrupt */
|
||||
dev->can.can_stats.bus_error++;
|
||||
stats->rx_errors++;
|
||||
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
|
||||
switch (ecc & SJA1000_ECC_MASK) {
|
||||
case SJA1000_ECC_BIT:
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT;
|
||||
break;
|
||||
case SJA1000_ECC_FORM:
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
break;
|
||||
case SJA1000_ECC_STUFF:
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
break;
|
||||
default:
|
||||
cf->data[3] = ecc & SJA1000_ECC_SEG;
|
||||
break;
|
||||
switch (ecc & SJA1000_ECC_MASK) {
|
||||
case SJA1000_ECC_BIT:
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT;
|
||||
break;
|
||||
case SJA1000_ECC_FORM:
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
break;
|
||||
case SJA1000_ECC_STUFF:
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
break;
|
||||
default:
|
||||
cf->data[3] = ecc & SJA1000_ECC_SEG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Error occurred during transmission? */
|
||||
if ((ecc & SJA1000_ECC_DIR) == 0)
|
||||
cf->data[2] |= CAN_ERR_PROT_TX;
|
||||
if ((ecc & SJA1000_ECC_DIR) == 0) {
|
||||
stats->tx_errors++;
|
||||
if (skb)
|
||||
cf->data[2] |= CAN_ERR_PROT_TX;
|
||||
} else {
|
||||
stats->rx_errors++;
|
||||
}
|
||||
|
||||
if (dev->can.state == CAN_STATE_ERROR_WARNING ||
|
||||
dev->can.state == CAN_STATE_ERROR_PASSIVE) {
|
||||
if (skb && (dev->can.state == CAN_STATE_ERROR_WARNING ||
|
||||
dev->can.state == CAN_STATE_ERROR_PASSIVE)) {
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] = (txerr > rxerr) ?
|
||||
CAN_ERR_CRTL_TX_PASSIVE : CAN_ERR_CRTL_RX_PASSIVE;
|
||||
}
|
||||
} else if (msg->type == CPC_MSG_TYPE_OVERRUN) {
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
||||
}
|
||||
|
||||
stats->rx_over_errors++;
|
||||
stats->rx_errors++;
|
||||
}
|
||||
|
||||
netif_rx(skb);
|
||||
if (skb)
|
||||
netif_rx(skb);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -526,7 +526,6 @@ static void f81604_handle_can_bus_errors(struct f81604_port_priv *priv,
|
||||
netdev_dbg(netdev, "bus error interrupt\n");
|
||||
|
||||
priv->can.can_stats.bus_error++;
|
||||
stats->rx_errors++;
|
||||
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
@@ -548,10 +547,15 @@ static void f81604_handle_can_bus_errors(struct f81604_port_priv *priv,
|
||||
|
||||
/* set error location */
|
||||
cf->data[3] = data->ecc & F81604_SJA1000_ECC_SEG;
|
||||
}
|
||||
|
||||
/* Error occurred during transmission? */
|
||||
if ((data->ecc & F81604_SJA1000_ECC_DIR) == 0)
|
||||
/* Error occurred during transmission? */
|
||||
if ((data->ecc & F81604_SJA1000_ECC_DIR) == 0) {
|
||||
stats->tx_errors++;
|
||||
if (skb)
|
||||
cf->data[2] |= CAN_ERR_PROT_TX;
|
||||
} else {
|
||||
stats->rx_errors++;
|
||||
}
|
||||
|
||||
set_bit(F81604_CLEAR_ECC, &priv->clear_flags);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user