mirror of
https://github.com/armbian/build.git
synced 2025-08-15 07:36:57 +02:00
5798 lines
196 KiB
Diff
5798 lines
196 KiB
Diff
diff --git a/Makefile b/Makefile
|
|
index 23e90df5785c84..587a1586e76db8 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,7 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
VERSION = 6
|
|
PATCHLEVEL = 6
|
|
-SUBLEVEL = 89
|
|
+SUBLEVEL = 90
|
|
EXTRAVERSION =
|
|
NAME = Pinguïn Aangedreven
|
|
|
|
diff --git a/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi
|
|
index f2386dcb9ff2c0..dda4fa91b2f2cc 100644
|
|
--- a/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi
|
|
+++ b/arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6ul.dtsi
|
|
@@ -40,6 +40,9 @@ ethphy1: ethernet-phy@1 {
|
|
reg = <1>;
|
|
interrupt-parent = <&gpio4>;
|
|
interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
|
|
+ micrel,led-mode = <1>;
|
|
+ clocks = <&clks IMX6UL_CLK_ENET_REF>;
|
|
+ clock-names = "rmii-ref";
|
|
status = "okay";
|
|
};
|
|
};
|
|
diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
|
|
index 5268a43218415f..ce5409acae1ce0 100644
|
|
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
|
|
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
|
|
@@ -73,14 +73,13 @@ scmi_reset: protocol@16 {
|
|
};
|
|
|
|
intc: interrupt-controller@4ac00000 {
|
|
- compatible = "arm,cortex-a7-gic";
|
|
+ compatible = "arm,gic-400";
|
|
#interrupt-cells = <3>;
|
|
- #address-cells = <1>;
|
|
interrupt-controller;
|
|
reg = <0x0 0x4ac10000 0x0 0x1000>,
|
|
- <0x0 0x4ac20000 0x0 0x2000>,
|
|
- <0x0 0x4ac40000 0x0 0x2000>,
|
|
- <0x0 0x4ac60000 0x0 0x2000>;
|
|
+ <0x0 0x4ac20000 0x0 0x20000>,
|
|
+ <0x0 0x4ac40000 0x0 0x20000>,
|
|
+ <0x0 0x4ac60000 0x0 0x20000>;
|
|
};
|
|
|
|
psci {
|
|
diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c
|
|
index ecfbff6991bb5d..edc4c727783d82 100644
|
|
--- a/arch/arm64/kernel/proton-pack.c
|
|
+++ b/arch/arm64/kernel/proton-pack.c
|
|
@@ -879,10 +879,12 @@ static u8 spectre_bhb_loop_affected(void)
|
|
static const struct midr_range spectre_bhb_k132_list[] = {
|
|
MIDR_ALL_VERSIONS(MIDR_CORTEX_X3),
|
|
MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V2),
|
|
+ {},
|
|
};
|
|
static const struct midr_range spectre_bhb_k38_list[] = {
|
|
MIDR_ALL_VERSIONS(MIDR_CORTEX_A715),
|
|
MIDR_ALL_VERSIONS(MIDR_CORTEX_A720),
|
|
+ {},
|
|
};
|
|
static const struct midr_range spectre_bhb_k32_list[] = {
|
|
MIDR_ALL_VERSIONS(MIDR_CORTEX_A78),
|
|
diff --git a/arch/parisc/math-emu/driver.c b/arch/parisc/math-emu/driver.c
|
|
index 6ce427b58836c5..ecd27b48d61f9d 100644
|
|
--- a/arch/parisc/math-emu/driver.c
|
|
+++ b/arch/parisc/math-emu/driver.c
|
|
@@ -103,9 +103,19 @@ handle_fpe(struct pt_regs *regs)
|
|
|
|
memcpy(regs->fr, frcopy, sizeof regs->fr);
|
|
if (signalcode != 0) {
|
|
- force_sig_fault(signalcode >> 24, signalcode & 0xffffff,
|
|
- (void __user *) regs->iaoq[0]);
|
|
- return -1;
|
|
+ int sig = signalcode >> 24;
|
|
+
|
|
+ if (sig == SIGFPE) {
|
|
+ /*
|
|
+ * Clear floating point trap bit to avoid trapping
|
|
+ * again on the first floating-point instruction in
|
|
+ * the userspace signal handler.
|
|
+ */
|
|
+ regs->fr[0] &= ~(1ULL << 38);
|
|
+ }
|
|
+ force_sig_fault(sig, signalcode & 0xffffff,
|
|
+ (void __user *) regs->iaoq[0]);
|
|
+ return -1;
|
|
}
|
|
|
|
return signalcode ? -1 : 0;
|
|
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
|
|
index 352d7de24018fb..ddb02cf0caaf59 100755
|
|
--- a/arch/powerpc/boot/wrapper
|
|
+++ b/arch/powerpc/boot/wrapper
|
|
@@ -234,10 +234,8 @@ fi
|
|
|
|
# suppress some warnings in recent ld versions
|
|
nowarn="-z noexecstack"
|
|
-if ! ld_is_lld; then
|
|
- if [ "$LD_VERSION" -ge "$(echo 2.39 | ld_version)" ]; then
|
|
- nowarn="$nowarn --no-warn-rwx-segments"
|
|
- fi
|
|
+if "${CROSS}ld" -v --no-warn-rwx-segments >/dev/null 2>&1; then
|
|
+ nowarn="$nowarn --no-warn-rwx-segments"
|
|
fi
|
|
|
|
platformo=$object/"$platform".o
|
|
diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c
|
|
index c6a4ac766b2bf9..28460e33408084 100644
|
|
--- a/arch/powerpc/mm/book3s64/radix_pgtable.c
|
|
+++ b/arch/powerpc/mm/book3s64/radix_pgtable.c
|
|
@@ -1056,6 +1056,19 @@ int __meminit radix__vmemmap_populate(unsigned long start, unsigned long end, in
|
|
pmd_t *pmd;
|
|
pte_t *pte;
|
|
|
|
+ /*
|
|
+ * Make sure we align the start vmemmap addr so that we calculate
|
|
+ * the correct start_pfn in altmap boundary check to decided whether
|
|
+ * we should use altmap or RAM based backing memory allocation. Also
|
|
+ * the address need to be aligned for set_pte operation.
|
|
+
|
|
+ * If the start addr is already PMD_SIZE aligned we will try to use
|
|
+ * a pmd mapping. We don't want to be too aggressive here beacause
|
|
+ * that will cause more allocations in RAM. So only if the namespace
|
|
+ * vmemmap start addr is PMD_SIZE aligned we will use PMD mapping.
|
|
+ */
|
|
+
|
|
+ start = ALIGN_DOWN(start, PAGE_SIZE);
|
|
for (addr = start; addr < end; addr = next) {
|
|
next = pmd_addr_end(addr, end);
|
|
|
|
@@ -1081,8 +1094,8 @@ int __meminit radix__vmemmap_populate(unsigned long start, unsigned long end, in
|
|
* in altmap block allocation failures, in which case
|
|
* we fallback to RAM for vmemmap allocation.
|
|
*/
|
|
- if (altmap && (!IS_ALIGNED(addr, PMD_SIZE) ||
|
|
- altmap_cross_boundary(altmap, addr, PMD_SIZE))) {
|
|
+ if (!IS_ALIGNED(addr, PMD_SIZE) || (altmap &&
|
|
+ altmap_cross_boundary(altmap, addr, PMD_SIZE))) {
|
|
/*
|
|
* make sure we don't create altmap mappings
|
|
* covering things outside the device.
|
|
diff --git a/arch/riscv/include/asm/patch.h b/arch/riscv/include/asm/patch.h
|
|
index 9f5d6e14c40553..7228e266b9a1ae 100644
|
|
--- a/arch/riscv/include/asm/patch.h
|
|
+++ b/arch/riscv/include/asm/patch.h
|
|
@@ -9,7 +9,7 @@
|
|
int patch_insn_write(void *addr, const void *insn, size_t len);
|
|
int patch_text_nosync(void *addr, const void *insns, size_t len);
|
|
int patch_text_set_nosync(void *addr, u8 c, size_t len);
|
|
-int patch_text(void *addr, u32 *insns, int ninsns);
|
|
+int patch_text(void *addr, u32 *insns, size_t len);
|
|
|
|
extern int riscv_patch_in_stop_machine;
|
|
|
|
diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c
|
|
index 78387d843aa56b..aeda87240dbc1e 100644
|
|
--- a/arch/riscv/kernel/patch.c
|
|
+++ b/arch/riscv/kernel/patch.c
|
|
@@ -19,7 +19,7 @@
|
|
struct patch_insn {
|
|
void *addr;
|
|
u32 *insns;
|
|
- int ninsns;
|
|
+ size_t len;
|
|
atomic_t cpu_count;
|
|
};
|
|
|
|
@@ -234,14 +234,10 @@ NOKPROBE_SYMBOL(patch_text_nosync);
|
|
static int patch_text_cb(void *data)
|
|
{
|
|
struct patch_insn *patch = data;
|
|
- unsigned long len;
|
|
- int i, ret = 0;
|
|
+ int ret = 0;
|
|
|
|
if (atomic_inc_return(&patch->cpu_count) == num_online_cpus()) {
|
|
- for (i = 0; ret == 0 && i < patch->ninsns; i++) {
|
|
- len = GET_INSN_LENGTH(patch->insns[i]);
|
|
- ret = patch_insn_write(patch->addr + i * len, &patch->insns[i], len);
|
|
- }
|
|
+ ret = patch_insn_write(patch->addr, patch->insns, patch->len);
|
|
/*
|
|
* Make sure the patching store is effective *before* we
|
|
* increment the counter which releases all waiting CPUs
|
|
@@ -262,13 +258,13 @@ static int patch_text_cb(void *data)
|
|
}
|
|
NOKPROBE_SYMBOL(patch_text_cb);
|
|
|
|
-int patch_text(void *addr, u32 *insns, int ninsns)
|
|
+int patch_text(void *addr, u32 *insns, size_t len)
|
|
{
|
|
int ret;
|
|
struct patch_insn patch = {
|
|
.addr = addr,
|
|
.insns = insns,
|
|
- .ninsns = ninsns,
|
|
+ .len = len,
|
|
.cpu_count = ATOMIC_INIT(0),
|
|
};
|
|
|
|
diff --git a/arch/riscv/kernel/probes/kprobes.c b/arch/riscv/kernel/probes/kprobes.c
|
|
index 4fbc70e823f0fa..297427ffc4e043 100644
|
|
--- a/arch/riscv/kernel/probes/kprobes.c
|
|
+++ b/arch/riscv/kernel/probes/kprobes.c
|
|
@@ -23,13 +23,13 @@ post_kprobe_handler(struct kprobe *, struct kprobe_ctlblk *, struct pt_regs *);
|
|
|
|
static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
|
|
{
|
|
+ size_t len = GET_INSN_LENGTH(p->opcode);
|
|
u32 insn = __BUG_INSN_32;
|
|
- unsigned long offset = GET_INSN_LENGTH(p->opcode);
|
|
|
|
- p->ainsn.api.restore = (unsigned long)p->addr + offset;
|
|
+ p->ainsn.api.restore = (unsigned long)p->addr + len;
|
|
|
|
- patch_text_nosync(p->ainsn.api.insn, &p->opcode, 1);
|
|
- patch_text_nosync((void *)p->ainsn.api.insn + offset, &insn, 1);
|
|
+ patch_text_nosync(p->ainsn.api.insn, &p->opcode, len);
|
|
+ patch_text_nosync((void *)p->ainsn.api.insn + len, &insn, GET_INSN_LENGTH(insn));
|
|
}
|
|
|
|
static void __kprobes arch_prepare_simulate(struct kprobe *p)
|
|
@@ -116,16 +116,18 @@ void *alloc_insn_page(void)
|
|
/* install breakpoint in text */
|
|
void __kprobes arch_arm_kprobe(struct kprobe *p)
|
|
{
|
|
- u32 insn = (p->opcode & __INSN_LENGTH_MASK) == __INSN_LENGTH_32 ?
|
|
- __BUG_INSN_32 : __BUG_INSN_16;
|
|
+ size_t len = GET_INSN_LENGTH(p->opcode);
|
|
+ u32 insn = len == 4 ? __BUG_INSN_32 : __BUG_INSN_16;
|
|
|
|
- patch_text(p->addr, &insn, 1);
|
|
+ patch_text(p->addr, &insn, len);
|
|
}
|
|
|
|
/* remove breakpoint from text */
|
|
void __kprobes arch_disarm_kprobe(struct kprobe *p)
|
|
{
|
|
- patch_text(p->addr, &p->opcode, 1);
|
|
+ size_t len = GET_INSN_LENGTH(p->opcode);
|
|
+
|
|
+ patch_text(p->addr, &p->opcode, len);
|
|
}
|
|
|
|
void __kprobes arch_remove_kprobe(struct kprobe *p)
|
|
diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
|
|
index 26eeb397363193..16eb4cd11cbd67 100644
|
|
--- a/arch/riscv/net/bpf_jit_comp64.c
|
|
+++ b/arch/riscv/net/bpf_jit_comp64.c
|
|
@@ -14,6 +14,7 @@
|
|
#include "bpf_jit.h"
|
|
|
|
#define RV_FENTRY_NINSNS 2
|
|
+#define RV_FENTRY_NBYTES (RV_FENTRY_NINSNS * 4)
|
|
|
|
#define RV_REG_TCC RV_REG_A6
|
|
#define RV_REG_TCC_SAVED RV_REG_S6 /* Store A6 in S6 if program do calls */
|
|
@@ -681,7 +682,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
|
|
if (ret)
|
|
return ret;
|
|
|
|
- if (memcmp(ip, old_insns, RV_FENTRY_NINSNS * 4))
|
|
+ if (memcmp(ip, old_insns, RV_FENTRY_NBYTES))
|
|
return -EFAULT;
|
|
|
|
ret = gen_jump_or_nops(new_addr, ip, new_insns, is_call);
|
|
@@ -690,8 +691,8 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
|
|
|
|
cpus_read_lock();
|
|
mutex_lock(&text_mutex);
|
|
- if (memcmp(ip, new_insns, RV_FENTRY_NINSNS * 4))
|
|
- ret = patch_text(ip, new_insns, RV_FENTRY_NINSNS);
|
|
+ if (memcmp(ip, new_insns, RV_FENTRY_NBYTES))
|
|
+ ret = patch_text(ip, new_insns, RV_FENTRY_NBYTES);
|
|
mutex_unlock(&text_mutex);
|
|
cpus_read_unlock();
|
|
|
|
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
|
|
index 66d5782df18f8c..835c9febb6a854 100644
|
|
--- a/arch/x86/events/intel/core.c
|
|
+++ b/arch/x86/events/intel/core.c
|
|
@@ -4206,7 +4206,7 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data)
|
|
arr[pebs_enable] = (struct perf_guest_switch_msr){
|
|
.msr = MSR_IA32_PEBS_ENABLE,
|
|
.host = cpuc->pebs_enabled & ~cpuc->intel_ctrl_guest_mask,
|
|
- .guest = pebs_mask & ~cpuc->intel_ctrl_host_mask,
|
|
+ .guest = pebs_mask & ~cpuc->intel_ctrl_host_mask & kvm_pmu->pebs_enable,
|
|
};
|
|
|
|
if (arr[pebs_enable].host) {
|
|
diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h
|
|
index 9b419f0de713cc..e59ded9761663e 100644
|
|
--- a/arch/x86/include/asm/kvm-x86-ops.h
|
|
+++ b/arch/x86/include/asm/kvm-x86-ops.h
|
|
@@ -48,6 +48,7 @@ KVM_X86_OP(set_idt)
|
|
KVM_X86_OP(get_gdt)
|
|
KVM_X86_OP(set_gdt)
|
|
KVM_X86_OP(sync_dirty_debug_regs)
|
|
+KVM_X86_OP(set_dr6)
|
|
KVM_X86_OP(set_dr7)
|
|
KVM_X86_OP(cache_reg)
|
|
KVM_X86_OP(get_rflags)
|
|
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
|
|
index 39672561c6be87..5dfb8cc9616e55 100644
|
|
--- a/arch/x86/include/asm/kvm_host.h
|
|
+++ b/arch/x86/include/asm/kvm_host.h
|
|
@@ -1595,6 +1595,7 @@ struct kvm_x86_ops {
|
|
void (*get_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
|
|
void (*set_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
|
|
void (*sync_dirty_debug_regs)(struct kvm_vcpu *vcpu);
|
|
+ void (*set_dr6)(struct kvm_vcpu *vcpu, unsigned long value);
|
|
void (*set_dr7)(struct kvm_vcpu *vcpu, unsigned long value);
|
|
void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg);
|
|
unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
|
|
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
|
|
index 1d06b8fc15a85c..29c1be65cb71a0 100644
|
|
--- a/arch/x86/kvm/svm/svm.c
|
|
+++ b/arch/x86/kvm/svm/svm.c
|
|
@@ -2014,11 +2014,11 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd)
|
|
svm->asid = sd->next_asid++;
|
|
}
|
|
|
|
-static void svm_set_dr6(struct vcpu_svm *svm, unsigned long value)
|
|
+static void svm_set_dr6(struct kvm_vcpu *vcpu, unsigned long value)
|
|
{
|
|
- struct vmcb *vmcb = svm->vmcb;
|
|
+ struct vmcb *vmcb = to_svm(vcpu)->vmcb;
|
|
|
|
- if (svm->vcpu.arch.guest_state_protected)
|
|
+ if (vcpu->arch.guest_state_protected)
|
|
return;
|
|
|
|
if (unlikely(value != vmcb->save.dr6)) {
|
|
@@ -4220,10 +4220,8 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
|
|
* Run with all-zero DR6 unless needed, so that we can get the exact cause
|
|
* of a #DB.
|
|
*/
|
|
- if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT))
|
|
- svm_set_dr6(svm, vcpu->arch.dr6);
|
|
- else
|
|
- svm_set_dr6(svm, DR6_ACTIVE_LOW);
|
|
+ if (likely(!(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)))
|
|
+ svm_set_dr6(vcpu, DR6_ACTIVE_LOW);
|
|
|
|
clgi();
|
|
kvm_load_guest_xsave_state(vcpu);
|
|
@@ -5002,6 +5000,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
|
|
.set_idt = svm_set_idt,
|
|
.get_gdt = svm_get_gdt,
|
|
.set_gdt = svm_set_gdt,
|
|
+ .set_dr6 = svm_set_dr6,
|
|
.set_dr7 = svm_set_dr7,
|
|
.sync_dirty_debug_regs = svm_sync_dirty_debug_regs,
|
|
.cache_reg = svm_cache_reg,
|
|
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
|
|
index 52098844290ad4..e5a2c230110ea4 100644
|
|
--- a/arch/x86/kvm/vmx/vmx.c
|
|
+++ b/arch/x86/kvm/vmx/vmx.c
|
|
@@ -5617,6 +5617,12 @@ static void vmx_sync_dirty_debug_regs(struct kvm_vcpu *vcpu)
|
|
set_debugreg(DR6_RESERVED, 6);
|
|
}
|
|
|
|
+static void vmx_set_dr6(struct kvm_vcpu *vcpu, unsigned long val)
|
|
+{
|
|
+ lockdep_assert_irqs_disabled();
|
|
+ set_debugreg(vcpu->arch.dr6, 6);
|
|
+}
|
|
+
|
|
static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val)
|
|
{
|
|
vmcs_writel(GUEST_DR7, val);
|
|
@@ -7356,10 +7362,6 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
|
|
vmx->loaded_vmcs->host_state.cr4 = cr4;
|
|
}
|
|
|
|
- /* When KVM_DEBUGREG_WONT_EXIT, dr6 is accessible in guest. */
|
|
- if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT))
|
|
- set_debugreg(vcpu->arch.dr6, 6);
|
|
-
|
|
/* When single-stepping over STI and MOV SS, we must clear the
|
|
* corresponding interruptibility bits in the guest state. Otherwise
|
|
* vmentry fails as it then expects bit 14 (BS) in pending debug
|
|
@@ -8292,6 +8294,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
|
|
.set_idt = vmx_set_idt,
|
|
.get_gdt = vmx_get_gdt,
|
|
.set_gdt = vmx_set_gdt,
|
|
+ .set_dr6 = vmx_set_dr6,
|
|
.set_dr7 = vmx_set_dr7,
|
|
.sync_dirty_debug_regs = vmx_sync_dirty_debug_regs,
|
|
.cache_reg = vmx_cache_reg,
|
|
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
|
|
index f67fe8a65820c8..1eeb01afa40ba9 100644
|
|
--- a/arch/x86/kvm/x86.c
|
|
+++ b/arch/x86/kvm/x86.c
|
|
@@ -10772,6 +10772,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
|
set_debugreg(vcpu->arch.eff_db[1], 1);
|
|
set_debugreg(vcpu->arch.eff_db[2], 2);
|
|
set_debugreg(vcpu->arch.eff_db[3], 3);
|
|
+ /* When KVM_DEBUGREG_WONT_EXIT, dr6 is accessible in guest. */
|
|
+ if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT))
|
|
+ static_call(kvm_x86_set_dr6)(vcpu, vcpu->arch.dr6);
|
|
} else if (unlikely(hw_breakpoint_active())) {
|
|
set_debugreg(0, 7);
|
|
}
|
|
diff --git a/drivers/base/module.c b/drivers/base/module.c
|
|
index a33663d92256d8..955582b34e54af 100644
|
|
--- a/drivers/base/module.c
|
|
+++ b/drivers/base/module.c
|
|
@@ -42,16 +42,13 @@ int module_add_driver(struct module *mod, struct device_driver *drv)
|
|
if (mod)
|
|
mk = &mod->mkobj;
|
|
else if (drv->mod_name) {
|
|
- struct kobject *mkobj;
|
|
-
|
|
- /* Lookup built-in module entry in /sys/modules */
|
|
- mkobj = kset_find_obj(module_kset, drv->mod_name);
|
|
- if (mkobj) {
|
|
- mk = container_of(mkobj, struct module_kobject, kobj);
|
|
+ /* Lookup or create built-in module entry in /sys/modules */
|
|
+ mk = lookup_or_create_module_kobject(drv->mod_name);
|
|
+ if (mk) {
|
|
/* remember our module structure */
|
|
drv->p->mkobj = mk;
|
|
- /* kset_find_obj took a reference */
|
|
- kobject_put(mkobj);
|
|
+ /* lookup_or_create_module_kobject took a reference */
|
|
+ kobject_put(&mk->kobj);
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
|
|
index bc3f63f1ccd863..d6195565ef7aeb 100644
|
|
--- a/drivers/bluetooth/btusb.c
|
|
+++ b/drivers/bluetooth/btusb.c
|
|
@@ -3521,22 +3521,16 @@ static void btusb_coredump_qca(struct hci_dev *hdev)
|
|
bt_dev_err(hdev, "%s: triggle crash failed (%d)", __func__, err);
|
|
}
|
|
|
|
-/*
|
|
- * ==0: not a dump pkt.
|
|
- * < 0: fails to handle a dump pkt
|
|
- * > 0: otherwise.
|
|
- */
|
|
+/* Return: 0 on success, negative errno on failure. */
|
|
static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|
{
|
|
- int ret = 1;
|
|
+ int ret = 0;
|
|
u8 pkt_type;
|
|
u8 *sk_ptr;
|
|
unsigned int sk_len;
|
|
u16 seqno;
|
|
u32 dump_size;
|
|
|
|
- struct hci_event_hdr *event_hdr;
|
|
- struct hci_acl_hdr *acl_hdr;
|
|
struct qca_dump_hdr *dump_hdr;
|
|
struct btusb_data *btdata = hci_get_drvdata(hdev);
|
|
struct usb_device *udev = btdata->udev;
|
|
@@ -3546,30 +3540,14 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|
sk_len = skb->len;
|
|
|
|
if (pkt_type == HCI_ACLDATA_PKT) {
|
|
- acl_hdr = hci_acl_hdr(skb);
|
|
- if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE)
|
|
- return 0;
|
|
sk_ptr += HCI_ACL_HDR_SIZE;
|
|
sk_len -= HCI_ACL_HDR_SIZE;
|
|
- event_hdr = (struct hci_event_hdr *)sk_ptr;
|
|
- } else {
|
|
- event_hdr = hci_event_hdr(skb);
|
|
}
|
|
|
|
- if ((event_hdr->evt != HCI_VENDOR_PKT)
|
|
- || (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE)))
|
|
- return 0;
|
|
-
|
|
sk_ptr += HCI_EVENT_HDR_SIZE;
|
|
sk_len -= HCI_EVENT_HDR_SIZE;
|
|
|
|
dump_hdr = (struct qca_dump_hdr *)sk_ptr;
|
|
- if ((sk_len < offsetof(struct qca_dump_hdr, data))
|
|
- || (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS)
|
|
- || (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
|
|
- return 0;
|
|
-
|
|
- /*it is dump pkt now*/
|
|
seqno = le16_to_cpu(dump_hdr->seqno);
|
|
if (seqno == 0) {
|
|
set_bit(BTUSB_HW_SSR_ACTIVE, &btdata->flags);
|
|
@@ -3643,17 +3621,84 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|
return ret;
|
|
}
|
|
|
|
+/* Return: true if the ACL packet is a dump packet, false otherwise. */
|
|
+static bool acl_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|
+{
|
|
+ u8 *sk_ptr;
|
|
+ unsigned int sk_len;
|
|
+
|
|
+ struct hci_event_hdr *event_hdr;
|
|
+ struct hci_acl_hdr *acl_hdr;
|
|
+ struct qca_dump_hdr *dump_hdr;
|
|
+
|
|
+ sk_ptr = skb->data;
|
|
+ sk_len = skb->len;
|
|
+
|
|
+ acl_hdr = hci_acl_hdr(skb);
|
|
+ if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE)
|
|
+ return false;
|
|
+
|
|
+ sk_ptr += HCI_ACL_HDR_SIZE;
|
|
+ sk_len -= HCI_ACL_HDR_SIZE;
|
|
+ event_hdr = (struct hci_event_hdr *)sk_ptr;
|
|
+
|
|
+ if ((event_hdr->evt != HCI_VENDOR_PKT) ||
|
|
+ (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE)))
|
|
+ return false;
|
|
+
|
|
+ sk_ptr += HCI_EVENT_HDR_SIZE;
|
|
+ sk_len -= HCI_EVENT_HDR_SIZE;
|
|
+
|
|
+ dump_hdr = (struct qca_dump_hdr *)sk_ptr;
|
|
+ if ((sk_len < offsetof(struct qca_dump_hdr, data)) ||
|
|
+ (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) ||
|
|
+ (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/* Return: true if the event packet is a dump packet, false otherwise. */
|
|
+static bool evt_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|
+{
|
|
+ u8 *sk_ptr;
|
|
+ unsigned int sk_len;
|
|
+
|
|
+ struct hci_event_hdr *event_hdr;
|
|
+ struct qca_dump_hdr *dump_hdr;
|
|
+
|
|
+ sk_ptr = skb->data;
|
|
+ sk_len = skb->len;
|
|
+
|
|
+ event_hdr = hci_event_hdr(skb);
|
|
+
|
|
+ if ((event_hdr->evt != HCI_VENDOR_PKT)
|
|
+ || (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE)))
|
|
+ return false;
|
|
+
|
|
+ sk_ptr += HCI_EVENT_HDR_SIZE;
|
|
+ sk_len -= HCI_EVENT_HDR_SIZE;
|
|
+
|
|
+ dump_hdr = (struct qca_dump_hdr *)sk_ptr;
|
|
+ if ((sk_len < offsetof(struct qca_dump_hdr, data)) ||
|
|
+ (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) ||
|
|
+ (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
static int btusb_recv_acl_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|
{
|
|
- if (handle_dump_pkt_qca(hdev, skb))
|
|
- return 0;
|
|
+ if (acl_pkt_is_dump_qca(hdev, skb))
|
|
+ return handle_dump_pkt_qca(hdev, skb);
|
|
return hci_recv_frame(hdev, skb);
|
|
}
|
|
|
|
static int btusb_recv_evt_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|
{
|
|
- if (handle_dump_pkt_qca(hdev, skb))
|
|
- return 0;
|
|
+ if (evt_pkt_is_dump_qca(hdev, skb))
|
|
+ return handle_dump_pkt_qca(hdev, skb);
|
|
return hci_recv_frame(hdev, skb);
|
|
}
|
|
|
|
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
|
|
index 0ac0998152ce81..6682f422cadd90 100644
|
|
--- a/drivers/cpufreq/cpufreq.c
|
|
+++ b/drivers/cpufreq/cpufreq.c
|
|
@@ -534,16 +534,18 @@ void cpufreq_disable_fast_switch(struct cpufreq_policy *policy)
|
|
EXPORT_SYMBOL_GPL(cpufreq_disable_fast_switch);
|
|
|
|
static unsigned int __resolve_freq(struct cpufreq_policy *policy,
|
|
- unsigned int target_freq, unsigned int relation)
|
|
+ unsigned int target_freq,
|
|
+ unsigned int min, unsigned int max,
|
|
+ unsigned int relation)
|
|
{
|
|
unsigned int idx;
|
|
|
|
- target_freq = clamp_val(target_freq, policy->min, policy->max);
|
|
+ target_freq = clamp_val(target_freq, min, max);
|
|
|
|
if (!policy->freq_table)
|
|
return target_freq;
|
|
|
|
- idx = cpufreq_frequency_table_target(policy, target_freq, relation);
|
|
+ idx = cpufreq_frequency_table_target(policy, target_freq, min, max, relation);
|
|
policy->cached_resolved_idx = idx;
|
|
policy->cached_target_freq = target_freq;
|
|
return policy->freq_table[idx].frequency;
|
|
@@ -563,7 +565,21 @@ static unsigned int __resolve_freq(struct cpufreq_policy *policy,
|
|
unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy,
|
|
unsigned int target_freq)
|
|
{
|
|
- return __resolve_freq(policy, target_freq, CPUFREQ_RELATION_LE);
|
|
+ unsigned int min = READ_ONCE(policy->min);
|
|
+ unsigned int max = READ_ONCE(policy->max);
|
|
+
|
|
+ /*
|
|
+ * If this function runs in parallel with cpufreq_set_policy(), it may
|
|
+ * read policy->min before the update and policy->max after the update
|
|
+ * or the other way around, so there is no ordering guarantee.
|
|
+ *
|
|
+ * Resolve this by always honoring the max (in case it comes from
|
|
+ * thermal throttling or similar).
|
|
+ */
|
|
+ if (unlikely(min > max))
|
|
+ min = max;
|
|
+
|
|
+ return __resolve_freq(policy, target_freq, min, max, CPUFREQ_RELATION_LE);
|
|
}
|
|
EXPORT_SYMBOL_GPL(cpufreq_driver_resolve_freq);
|
|
|
|
@@ -2335,7 +2351,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
|
if (cpufreq_disabled())
|
|
return -ENODEV;
|
|
|
|
- target_freq = __resolve_freq(policy, target_freq, relation);
|
|
+ target_freq = __resolve_freq(policy, target_freq, policy->min,
|
|
+ policy->max, relation);
|
|
|
|
pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n",
|
|
policy->cpu, target_freq, relation, old_target_freq);
|
|
@@ -2625,11 +2642,18 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
|
|
* Resolve policy min/max to available frequencies. It ensures
|
|
* no frequency resolution will neither overshoot the requested maximum
|
|
* nor undershoot the requested minimum.
|
|
+ *
|
|
+ * Avoid storing intermediate values in policy->max or policy->min and
|
|
+ * compiler optimizations around them because they may be accessed
|
|
+ * concurrently by cpufreq_driver_resolve_freq() during the update.
|
|
*/
|
|
- policy->min = new_data.min;
|
|
- policy->max = new_data.max;
|
|
- policy->min = __resolve_freq(policy, policy->min, CPUFREQ_RELATION_L);
|
|
- policy->max = __resolve_freq(policy, policy->max, CPUFREQ_RELATION_H);
|
|
+ WRITE_ONCE(policy->max, __resolve_freq(policy, new_data.max,
|
|
+ new_data.min, new_data.max,
|
|
+ CPUFREQ_RELATION_H));
|
|
+ new_data.min = __resolve_freq(policy, new_data.min, new_data.min,
|
|
+ new_data.max, CPUFREQ_RELATION_L);
|
|
+ WRITE_ONCE(policy->min, new_data.min > policy->max ? policy->max : new_data.min);
|
|
+
|
|
trace_cpu_frequency_limits(policy);
|
|
|
|
policy->cached_target_freq = UINT_MAX;
|
|
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
|
|
index c52d19d67557f5..65cbd5ecbaf83d 100644
|
|
--- a/drivers/cpufreq/cpufreq_ondemand.c
|
|
+++ b/drivers/cpufreq/cpufreq_ondemand.c
|
|
@@ -77,7 +77,8 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy,
|
|
return freq_next;
|
|
}
|
|
|
|
- index = cpufreq_frequency_table_target(policy, freq_next, relation);
|
|
+ index = cpufreq_frequency_table_target(policy, freq_next, policy->min,
|
|
+ policy->max, relation);
|
|
freq_req = freq_table[index].frequency;
|
|
freq_reduc = freq_req * od_tuners->powersave_bias / 1000;
|
|
freq_avg = freq_req - freq_reduc;
|
|
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
|
|
index c17dc51a5a022d..94de089b145394 100644
|
|
--- a/drivers/cpufreq/freq_table.c
|
|
+++ b/drivers/cpufreq/freq_table.c
|
|
@@ -116,8 +116,8 @@ int cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data *policy)
|
|
EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify);
|
|
|
|
int cpufreq_table_index_unsorted(struct cpufreq_policy *policy,
|
|
- unsigned int target_freq,
|
|
- unsigned int relation)
|
|
+ unsigned int target_freq, unsigned int min,
|
|
+ unsigned int max, unsigned int relation)
|
|
{
|
|
struct cpufreq_frequency_table optimal = {
|
|
.driver_data = ~0,
|
|
@@ -148,7 +148,7 @@ int cpufreq_table_index_unsorted(struct cpufreq_policy *policy,
|
|
cpufreq_for_each_valid_entry_idx(pos, table, i) {
|
|
freq = pos->frequency;
|
|
|
|
- if ((freq < policy->min) || (freq > policy->max))
|
|
+ if (freq < min || freq > max)
|
|
continue;
|
|
if (freq == target_freq) {
|
|
optimal.driver_data = i;
|
|
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
|
|
index 8b31cd54bdb6de..e04fd1a7e9aaea 100644
|
|
--- a/drivers/edac/altera_edac.c
|
|
+++ b/drivers/edac/altera_edac.c
|
|
@@ -98,7 +98,7 @@ static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id)
|
|
if (status & priv->ecc_stat_ce_mask) {
|
|
regmap_read(drvdata->mc_vbase, priv->ecc_saddr_offset,
|
|
&err_addr);
|
|
- if (priv->ecc_uecnt_offset)
|
|
+ if (priv->ecc_cecnt_offset)
|
|
regmap_read(drvdata->mc_vbase, priv->ecc_cecnt_offset,
|
|
&err_count);
|
|
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, err_count,
|
|
@@ -1015,9 +1015,6 @@ altr_init_a10_ecc_block(struct device_node *np, u32 irq_mask,
|
|
}
|
|
}
|
|
|
|
- /* Interrupt mode set to every SBERR */
|
|
- regmap_write(ecc_mgr_map, ALTR_A10_ECC_INTMODE_OFST,
|
|
- ALTR_A10_ECC_INTMODE);
|
|
/* Enable ECC */
|
|
ecc_set_bits(ecc_ctrl_en_mask, (ecc_block_base +
|
|
ALTR_A10_ECC_CTRL_OFST));
|
|
@@ -2138,6 +2135,10 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
|
|
return PTR_ERR(edac->ecc_mgr_map);
|
|
}
|
|
|
|
+ /* Set irq mask for DDR SBE to avoid any pending irq before registration */
|
|
+ regmap_write(edac->ecc_mgr_map, A10_SYSMGR_ECC_INTMASK_SET_OFST,
|
|
+ (A10_SYSMGR_ECC_INTMASK_SDMMCB | A10_SYSMGR_ECC_INTMASK_DDR0));
|
|
+
|
|
edac->irq_chip.name = pdev->dev.of_node->name;
|
|
edac->irq_chip.irq_mask = a10_eccmgr_irq_mask;
|
|
edac->irq_chip.irq_unmask = a10_eccmgr_irq_unmask;
|
|
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
|
|
index 3727e72c8c2e70..7248d24c4908d7 100644
|
|
--- a/drivers/edac/altera_edac.h
|
|
+++ b/drivers/edac/altera_edac.h
|
|
@@ -249,6 +249,8 @@ struct altr_sdram_mc_data {
|
|
#define A10_SYSMGR_ECC_INTMASK_SET_OFST 0x94
|
|
#define A10_SYSMGR_ECC_INTMASK_CLR_OFST 0x98
|
|
#define A10_SYSMGR_ECC_INTMASK_OCRAM BIT(1)
|
|
+#define A10_SYSMGR_ECC_INTMASK_SDMMCB BIT(16)
|
|
+#define A10_SYSMGR_ECC_INTMASK_DDR0 BIT(17)
|
|
|
|
#define A10_SYSMGR_ECC_INTSTAT_SERR_OFST 0x9C
|
|
#define A10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xA0
|
|
diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
|
|
index 7cd6b1564e8018..7c2db3f017651b 100644
|
|
--- a/drivers/firmware/arm_ffa/driver.c
|
|
+++ b/drivers/firmware/arm_ffa/driver.c
|
|
@@ -225,7 +225,8 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
|
|
memcpy(buffer + idx, drv_info->rx_buffer + idx * sz,
|
|
buf_sz);
|
|
|
|
- ffa_rx_release();
|
|
+ if (!(flags & PARTITION_INFO_GET_RETURN_COUNT_ONLY))
|
|
+ ffa_rx_release();
|
|
|
|
mutex_unlock(&drv_info->rx_lock);
|
|
|
|
diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
|
|
index dcf774d3edfe4c..51eeaf14367dac 100644
|
|
--- a/drivers/firmware/arm_scmi/bus.c
|
|
+++ b/drivers/firmware/arm_scmi/bus.c
|
|
@@ -240,6 +240,9 @@ static struct scmi_device *scmi_child_dev_find(struct device *parent,
|
|
if (!dev)
|
|
return NULL;
|
|
|
|
+ /* Drop the refcnt bumped implicitly by device_find_child */
|
|
+ put_device(dev);
|
|
+
|
|
return to_scmi_dev(dev);
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
|
|
index 2ad9f900a85749..a048022d9865a7 100644
|
|
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
|
|
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
|
|
@@ -172,7 +172,10 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
|
|
struct mod_hdcp_display_adjustment display_adjust;
|
|
unsigned int conn_index = aconnector->base.index;
|
|
|
|
- mutex_lock(&hdcp_w->mutex);
|
|
+ guard(mutex)(&hdcp_w->mutex);
|
|
+ drm_connector_get(&aconnector->base);
|
|
+ if (hdcp_w->aconnector[conn_index])
|
|
+ drm_connector_put(&hdcp_w->aconnector[conn_index]->base);
|
|
hdcp_w->aconnector[conn_index] = aconnector;
|
|
|
|
memset(&link_adjust, 0, sizeof(link_adjust));
|
|
@@ -209,7 +212,6 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
|
|
mod_hdcp_update_display(&hdcp_w->hdcp, conn_index, &link_adjust, &display_adjust, &hdcp_w->output);
|
|
|
|
process_output(hdcp_w);
|
|
- mutex_unlock(&hdcp_w->mutex);
|
|
}
|
|
|
|
static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
|
|
@@ -220,8 +222,7 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
|
|
struct drm_connector_state *conn_state = aconnector->base.state;
|
|
unsigned int conn_index = aconnector->base.index;
|
|
|
|
- mutex_lock(&hdcp_w->mutex);
|
|
- hdcp_w->aconnector[conn_index] = aconnector;
|
|
+ guard(mutex)(&hdcp_w->mutex);
|
|
|
|
/* the removal of display will invoke auth reset -> hdcp destroy and
|
|
* we'd expect the Content Protection (CP) property changed back to
|
|
@@ -237,9 +238,11 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
|
|
}
|
|
|
|
mod_hdcp_remove_display(&hdcp_w->hdcp, aconnector->base.index, &hdcp_w->output);
|
|
-
|
|
+ if (hdcp_w->aconnector[conn_index]) {
|
|
+ drm_connector_put(&hdcp_w->aconnector[conn_index]->base);
|
|
+ hdcp_w->aconnector[conn_index] = NULL;
|
|
+ }
|
|
process_output(hdcp_w);
|
|
- mutex_unlock(&hdcp_w->mutex);
|
|
}
|
|
|
|
void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
|
|
@@ -247,7 +250,7 @@ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_inde
|
|
struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
|
|
unsigned int conn_index;
|
|
|
|
- mutex_lock(&hdcp_w->mutex);
|
|
+ guard(mutex)(&hdcp_w->mutex);
|
|
|
|
mod_hdcp_reset_connection(&hdcp_w->hdcp, &hdcp_w->output);
|
|
|
|
@@ -256,11 +259,13 @@ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_inde
|
|
for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) {
|
|
hdcp_w->encryption_status[conn_index] =
|
|
MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
|
|
+ if (hdcp_w->aconnector[conn_index]) {
|
|
+ drm_connector_put(&hdcp_w->aconnector[conn_index]->base);
|
|
+ hdcp_w->aconnector[conn_index] = NULL;
|
|
+ }
|
|
}
|
|
|
|
process_output(hdcp_w);
|
|
-
|
|
- mutex_unlock(&hdcp_w->mutex);
|
|
}
|
|
|
|
void hdcp_handle_cpirq(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
|
|
@@ -277,7 +282,7 @@ static void event_callback(struct work_struct *work)
|
|
hdcp_work = container_of(to_delayed_work(work), struct hdcp_workqueue,
|
|
callback_dwork);
|
|
|
|
- mutex_lock(&hdcp_work->mutex);
|
|
+ guard(mutex)(&hdcp_work->mutex);
|
|
|
|
cancel_delayed_work(&hdcp_work->callback_dwork);
|
|
|
|
@@ -285,8 +290,6 @@ static void event_callback(struct work_struct *work)
|
|
&hdcp_work->output);
|
|
|
|
process_output(hdcp_work);
|
|
-
|
|
- mutex_unlock(&hdcp_work->mutex);
|
|
}
|
|
|
|
static void event_property_update(struct work_struct *work)
|
|
@@ -323,7 +326,7 @@ static void event_property_update(struct work_struct *work)
|
|
continue;
|
|
|
|
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
|
|
- mutex_lock(&hdcp_work->mutex);
|
|
+ guard(mutex)(&hdcp_work->mutex);
|
|
|
|
if (conn_state->commit) {
|
|
ret = wait_for_completion_interruptible_timeout(&conn_state->commit->hw_done,
|
|
@@ -355,7 +358,6 @@ static void event_property_update(struct work_struct *work)
|
|
drm_hdcp_update_content_protection(connector,
|
|
DRM_MODE_CONTENT_PROTECTION_DESIRED);
|
|
}
|
|
- mutex_unlock(&hdcp_work->mutex);
|
|
drm_modeset_unlock(&dev->mode_config.connection_mutex);
|
|
}
|
|
}
|
|
@@ -368,7 +370,7 @@ static void event_property_validate(struct work_struct *work)
|
|
struct amdgpu_dm_connector *aconnector;
|
|
unsigned int conn_index;
|
|
|
|
- mutex_lock(&hdcp_work->mutex);
|
|
+ guard(mutex)(&hdcp_work->mutex);
|
|
|
|
for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX;
|
|
conn_index++) {
|
|
@@ -408,8 +410,6 @@ static void event_property_validate(struct work_struct *work)
|
|
schedule_work(&hdcp_work->property_update_work);
|
|
}
|
|
}
|
|
-
|
|
- mutex_unlock(&hdcp_work->mutex);
|
|
}
|
|
|
|
static void event_watchdog_timer(struct work_struct *work)
|
|
@@ -420,7 +420,7 @@ static void event_watchdog_timer(struct work_struct *work)
|
|
struct hdcp_workqueue,
|
|
watchdog_timer_dwork);
|
|
|
|
- mutex_lock(&hdcp_work->mutex);
|
|
+ guard(mutex)(&hdcp_work->mutex);
|
|
|
|
cancel_delayed_work(&hdcp_work->watchdog_timer_dwork);
|
|
|
|
@@ -429,8 +429,6 @@ static void event_watchdog_timer(struct work_struct *work)
|
|
&hdcp_work->output);
|
|
|
|
process_output(hdcp_work);
|
|
-
|
|
- mutex_unlock(&hdcp_work->mutex);
|
|
}
|
|
|
|
static void event_cpirq(struct work_struct *work)
|
|
@@ -439,13 +437,11 @@ static void event_cpirq(struct work_struct *work)
|
|
|
|
hdcp_work = container_of(work, struct hdcp_workqueue, cpirq_work);
|
|
|
|
- mutex_lock(&hdcp_work->mutex);
|
|
+ guard(mutex)(&hdcp_work->mutex);
|
|
|
|
mod_hdcp_process_event(&hdcp_work->hdcp, MOD_HDCP_EVENT_CPIRQ, &hdcp_work->output);
|
|
|
|
process_output(hdcp_work);
|
|
-
|
|
- mutex_unlock(&hdcp_work->mutex);
|
|
}
|
|
|
|
void hdcp_destroy(struct kobject *kobj, struct hdcp_workqueue *hdcp_work)
|
|
@@ -479,7 +475,7 @@ static bool enable_assr(void *handle, struct dc_link *link)
|
|
|
|
dtm_cmd = (struct ta_dtm_shared_memory *)psp->dtm_context.context.mem_context.shared_buf;
|
|
|
|
- mutex_lock(&psp->dtm_context.mutex);
|
|
+ guard(mutex)(&psp->dtm_context.mutex);
|
|
memset(dtm_cmd, 0, sizeof(struct ta_dtm_shared_memory));
|
|
|
|
dtm_cmd->cmd_id = TA_DTM_COMMAND__TOPOLOGY_ASSR_ENABLE;
|
|
@@ -494,8 +490,6 @@ static bool enable_assr(void *handle, struct dc_link *link)
|
|
res = false;
|
|
}
|
|
|
|
- mutex_unlock(&psp->dtm_context.mutex);
|
|
-
|
|
return res;
|
|
}
|
|
|
|
@@ -504,6 +498,7 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
|
|
struct hdcp_workqueue *hdcp_work = handle;
|
|
struct amdgpu_dm_connector *aconnector = config->dm_stream_ctx;
|
|
int link_index = aconnector->dc_link->link_index;
|
|
+ unsigned int conn_index = aconnector->base.index;
|
|
struct mod_hdcp_display *display = &hdcp_work[link_index].display;
|
|
struct mod_hdcp_link *link = &hdcp_work[link_index].link;
|
|
struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
|
|
@@ -557,13 +552,14 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
|
|
(!!aconnector->base.state) ?
|
|
aconnector->base.state->hdcp_content_type : -1);
|
|
|
|
- mutex_lock(&hdcp_w->mutex);
|
|
+ guard(mutex)(&hdcp_w->mutex);
|
|
|
|
mod_hdcp_add_display(&hdcp_w->hdcp, link, display, &hdcp_w->output);
|
|
-
|
|
+ drm_connector_get(&aconnector->base);
|
|
+ if (hdcp_w->aconnector[conn_index])
|
|
+ drm_connector_put(&hdcp_w->aconnector[conn_index]->base);
|
|
+ hdcp_w->aconnector[conn_index] = aconnector;
|
|
process_output(hdcp_w);
|
|
- mutex_unlock(&hdcp_w->mutex);
|
|
-
|
|
}
|
|
|
|
/**
|
|
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
|
|
index 1d22dba69b2753..b943221b238f87 100644
|
|
--- a/drivers/gpu/drm/drm_file.c
|
|
+++ b/drivers/gpu/drm/drm_file.c
|
|
@@ -1015,6 +1015,10 @@ void drm_show_fdinfo(struct seq_file *m, struct file *f)
|
|
struct drm_file *file = f->private_data;
|
|
struct drm_device *dev = file->minor->dev;
|
|
struct drm_printer p = drm_seq_file_printer(m);
|
|
+ int idx;
|
|
+
|
|
+ if (!drm_dev_enter(dev, &idx))
|
|
+ return;
|
|
|
|
drm_printf(&p, "drm-driver:\t%s\n", dev->driver->name);
|
|
drm_printf(&p, "drm-client-id:\t%llu\n", file->client_id);
|
|
@@ -1029,6 +1033,8 @@ void drm_show_fdinfo(struct seq_file *m, struct file *f)
|
|
|
|
if (dev->driver->show_fdinfo)
|
|
dev->driver->show_fdinfo(&p, file);
|
|
+
|
|
+ drm_dev_exit(idx);
|
|
}
|
|
EXPORT_SYMBOL(drm_show_fdinfo);
|
|
|
|
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h b/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h
|
|
index 298ad38e6c7df6..c36d956b9b824f 100644
|
|
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h
|
|
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h
|
|
@@ -25,6 +25,7 @@ int intel_pxp_gsccs_init(struct intel_pxp *pxp);
|
|
|
|
int intel_pxp_gsccs_create_session(struct intel_pxp *pxp, int arb_session_id);
|
|
void intel_pxp_gsccs_end_arb_fw_session(struct intel_pxp *pxp, u32 arb_session_id);
|
|
+bool intel_pxp_gsccs_is_ready_for_sessions(struct intel_pxp *pxp);
|
|
|
|
#else
|
|
static inline void intel_pxp_gsccs_fini(struct intel_pxp *pxp)
|
|
@@ -36,8 +37,11 @@ static inline int intel_pxp_gsccs_init(struct intel_pxp *pxp)
|
|
return 0;
|
|
}
|
|
|
|
-#endif
|
|
+static inline bool intel_pxp_gsccs_is_ready_for_sessions(struct intel_pxp *pxp)
|
|
+{
|
|
+ return false;
|
|
+}
|
|
|
|
-bool intel_pxp_gsccs_is_ready_for_sessions(struct intel_pxp *pxp);
|
|
+#endif
|
|
|
|
#endif /*__INTEL_PXP_GSCCS_H__ */
|
|
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
|
|
index 2a942dc6a6dc23..2a82119eb58ed8 100644
|
|
--- a/drivers/gpu/drm/meson/meson_vclk.c
|
|
+++ b/drivers/gpu/drm/meson/meson_vclk.c
|
|
@@ -790,13 +790,13 @@ meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq,
|
|
FREQ_1000_1001(params[i].pixel_freq));
|
|
DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n",
|
|
i, params[i].phy_freq,
|
|
- FREQ_1000_1001(params[i].phy_freq/1000)*1000);
|
|
+ FREQ_1000_1001(params[i].phy_freq/10)*10);
|
|
/* Match strict frequency */
|
|
if (phy_freq == params[i].phy_freq &&
|
|
vclk_freq == params[i].vclk_freq)
|
|
return MODE_OK;
|
|
/* Match 1000/1001 variant */
|
|
- if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/1000)*1000) &&
|
|
+ if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) &&
|
|
vclk_freq == FREQ_1000_1001(params[i].vclk_freq))
|
|
return MODE_OK;
|
|
}
|
|
@@ -1070,7 +1070,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
|
|
|
|
for (freq = 0 ; params[freq].pixel_freq ; ++freq) {
|
|
if ((phy_freq == params[freq].phy_freq ||
|
|
- phy_freq == FREQ_1000_1001(params[freq].phy_freq/1000)*1000) &&
|
|
+ phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) &&
|
|
(vclk_freq == params[freq].vclk_freq ||
|
|
vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) {
|
|
if (vclk_freq != params[freq].vclk_freq)
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
|
|
index 03eacb22648ef7..1bfa312d6fb857 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
|
|
@@ -90,7 +90,7 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error)
|
|
while (!list_empty(&fctx->pending)) {
|
|
fence = list_entry(fctx->pending.next, typeof(*fence), head);
|
|
|
|
- if (error)
|
|
+ if (error && !dma_fence_is_signaled_locked(&fence->base))
|
|
dma_fence_set_error(&fence->base, error);
|
|
|
|
if (nouveau_fence_signal(fence))
|
|
diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
|
|
index 5d4f04a3c6d322..b44b36bd565ea4 100644
|
|
--- a/drivers/i2c/busses/i2c-imx-lpi2c.c
|
|
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
|
|
@@ -616,9 +616,9 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
|
|
return 0;
|
|
|
|
rpm_disable:
|
|
- pm_runtime_put(&pdev->dev);
|
|
- pm_runtime_disable(&pdev->dev);
|
|
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
|
+ pm_runtime_put_sync(&pdev->dev);
|
|
+ pm_runtime_disable(&pdev->dev);
|
|
|
|
return ret;
|
|
}
|
|
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
|
|
index ef3fae113dd643..2e7a12f306510c 100644
|
|
--- a/drivers/iommu/amd/init.c
|
|
+++ b/drivers/iommu/amd/init.c
|
|
@@ -3682,6 +3682,14 @@ static int __init parse_ivrs_acpihid(char *str)
|
|
while (*uid == '0' && *(uid + 1))
|
|
uid++;
|
|
|
|
+ if (strlen(hid) >= ACPIHID_HID_LEN) {
|
|
+ pr_err("Invalid command line: hid is too long\n");
|
|
+ return 1;
|
|
+ } else if (strlen(uid) >= ACPIHID_UID_LEN) {
|
|
+ pr_err("Invalid command line: uid is too long\n");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
i = early_acpihid_map_size++;
|
|
memcpy(early_acpihid_map[i].hid, hid, strlen(hid));
|
|
memcpy(early_acpihid_map[i].uid, uid, strlen(uid));
|
|
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
|
index 6cecbac0e6babf..f2260f45728e79 100644
|
|
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
|
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
|
@@ -1443,26 +1443,37 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
|
|
return 0;
|
|
}
|
|
|
|
+static int arm_smmu_streams_cmp_key(const void *lhs, const struct rb_node *rhs)
|
|
+{
|
|
+ struct arm_smmu_stream *stream_rhs =
|
|
+ rb_entry(rhs, struct arm_smmu_stream, node);
|
|
+ const u32 *sid_lhs = lhs;
|
|
+
|
|
+ if (*sid_lhs < stream_rhs->id)
|
|
+ return -1;
|
|
+ if (*sid_lhs > stream_rhs->id)
|
|
+ return 1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int arm_smmu_streams_cmp_node(struct rb_node *lhs,
|
|
+ const struct rb_node *rhs)
|
|
+{
|
|
+ return arm_smmu_streams_cmp_key(
|
|
+ &rb_entry(lhs, struct arm_smmu_stream, node)->id, rhs);
|
|
+}
|
|
+
|
|
static struct arm_smmu_master *
|
|
arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid)
|
|
{
|
|
struct rb_node *node;
|
|
- struct arm_smmu_stream *stream;
|
|
|
|
lockdep_assert_held(&smmu->streams_mutex);
|
|
|
|
- node = smmu->streams.rb_node;
|
|
- while (node) {
|
|
- stream = rb_entry(node, struct arm_smmu_stream, node);
|
|
- if (stream->id < sid)
|
|
- node = node->rb_right;
|
|
- else if (stream->id > sid)
|
|
- node = node->rb_left;
|
|
- else
|
|
- return stream->master;
|
|
- }
|
|
-
|
|
- return NULL;
|
|
+ node = rb_find(&sid, &smmu->streams, arm_smmu_streams_cmp_key);
|
|
+ if (!node)
|
|
+ return NULL;
|
|
+ return rb_entry(node, struct arm_smmu_stream, node)->master;
|
|
}
|
|
|
|
/* IRQ and event handlers */
|
|
@@ -2575,8 +2586,6 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
|
|
{
|
|
int i;
|
|
int ret = 0;
|
|
- struct arm_smmu_stream *new_stream, *cur_stream;
|
|
- struct rb_node **new_node, *parent_node = NULL;
|
|
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev);
|
|
|
|
master->streams = kcalloc(fwspec->num_ids, sizeof(*master->streams),
|
|
@@ -2587,9 +2596,10 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
|
|
|
|
mutex_lock(&smmu->streams_mutex);
|
|
for (i = 0; i < fwspec->num_ids; i++) {
|
|
+ struct arm_smmu_stream *new_stream = &master->streams[i];
|
|
+ struct rb_node *existing;
|
|
u32 sid = fwspec->ids[i];
|
|
|
|
- new_stream = &master->streams[i];
|
|
new_stream->id = sid;
|
|
new_stream->master = master;
|
|
|
|
@@ -2598,28 +2608,23 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
|
|
break;
|
|
|
|
/* Insert into SID tree */
|
|
- new_node = &(smmu->streams.rb_node);
|
|
- while (*new_node) {
|
|
- cur_stream = rb_entry(*new_node, struct arm_smmu_stream,
|
|
- node);
|
|
- parent_node = *new_node;
|
|
- if (cur_stream->id > new_stream->id) {
|
|
- new_node = &((*new_node)->rb_left);
|
|
- } else if (cur_stream->id < new_stream->id) {
|
|
- new_node = &((*new_node)->rb_right);
|
|
- } else {
|
|
- dev_warn(master->dev,
|
|
- "stream %u already in tree\n",
|
|
- cur_stream->id);
|
|
- ret = -EINVAL;
|
|
- break;
|
|
- }
|
|
- }
|
|
- if (ret)
|
|
- break;
|
|
+ existing = rb_find_add(&new_stream->node, &smmu->streams,
|
|
+ arm_smmu_streams_cmp_node);
|
|
+ if (existing) {
|
|
+ struct arm_smmu_master *existing_master =
|
|
+ rb_entry(existing, struct arm_smmu_stream, node)
|
|
+ ->master;
|
|
+
|
|
+ /* Bridged PCI devices may end up with duplicated IDs */
|
|
+ if (existing_master == master)
|
|
+ continue;
|
|
|
|
- rb_link_node(&new_stream->node, parent_node, new_node);
|
|
- rb_insert_color(&new_stream->node, &smmu->streams);
|
|
+ dev_warn(master->dev,
|
|
+ "stream %u already in tree from dev %s\n", sid,
|
|
+ dev_name(existing_master->dev));
|
|
+ ret = -EINVAL;
|
|
+ break;
|
|
+ }
|
|
}
|
|
|
|
if (ret) {
|
|
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
|
|
index d6381c00bb8ddc..6a745616d85a4b 100644
|
|
--- a/drivers/iommu/intel/iommu.c
|
|
+++ b/drivers/iommu/intel/iommu.c
|
|
@@ -4855,6 +4855,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_igfx);
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_igfx);
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_igfx);
|
|
|
|
+/* QM57/QS57 integrated gfx malfunctions with dmar */
|
|
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_iommu_igfx);
|
|
+
|
|
/* Broadwell igfx malfunctions with dmar */
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1606, quirk_iommu_igfx);
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160B, quirk_iommu_igfx);
|
|
@@ -4932,7 +4935,6 @@ static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
|
|
}
|
|
}
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
|
|
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
|
|
|
|
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
|
|
index 3f1029c0825e95..f2b3a4e2e54fc8 100644
|
|
--- a/drivers/iommu/iommu.c
|
|
+++ b/drivers/iommu/iommu.c
|
|
@@ -566,6 +566,18 @@ int iommu_probe_device(struct device *dev)
|
|
mutex_lock(&iommu_probe_device_lock);
|
|
ret = __iommu_probe_device(dev, NULL);
|
|
mutex_unlock(&iommu_probe_device_lock);
|
|
+
|
|
+ /*
|
|
+ * The dma_configure replay paths need bus_iommu_probe() to
|
|
+ * finish before they can call arch_setup_dma_ops()
|
|
+ */
|
|
+ if (IS_ENABLED(CONFIG_IOMMU_DMA) && !ret && dev->iommu_group) {
|
|
+ mutex_lock(&dev->iommu_group->mutex);
|
|
+ if (!dev->iommu_group->default_domain &&
|
|
+ !dev_iommu_ops(dev)->set_platform_dma_ops)
|
|
+ ret = -EPROBE_DEFER;
|
|
+ mutex_unlock(&dev->iommu_group->mutex);
|
|
+ }
|
|
if (ret)
|
|
return ret;
|
|
|
|
@@ -3149,6 +3161,12 @@ int iommu_device_use_default_domain(struct device *dev)
|
|
return 0;
|
|
|
|
mutex_lock(&group->mutex);
|
|
+ /* We may race against bus_iommu_probe() finalising groups here */
|
|
+ if (IS_ENABLED(CONFIG_IOMMU_DMA) && !group->default_domain &&
|
|
+ !dev_iommu_ops(dev)->set_platform_dma_ops) {
|
|
+ ret = -EPROBE_DEFER;
|
|
+ goto unlock_out;
|
|
+ }
|
|
if (group->owner_cnt) {
|
|
if (group->owner || !iommu_is_default_domain(group) ||
|
|
!xa_empty(&group->pasid_array)) {
|
|
diff --git a/drivers/irqchip/irq-qcom-mpm.c b/drivers/irqchip/irq-qcom-mpm.c
|
|
index 7124565234a586..0807e4aca933fb 100644
|
|
--- a/drivers/irqchip/irq-qcom-mpm.c
|
|
+++ b/drivers/irqchip/irq-qcom-mpm.c
|
|
@@ -226,6 +226,9 @@ static int qcom_mpm_alloc(struct irq_domain *domain, unsigned int virq,
|
|
if (ret)
|
|
return ret;
|
|
|
|
+ if (pin == GPIO_NO_WAKE_IRQ)
|
|
+ return irq_domain_disconnect_hierarchy(domain, virq);
|
|
+
|
|
ret = irq_domain_set_hwirq_and_chip(domain, virq, pin,
|
|
&qcom_mpm_chip, priv);
|
|
if (ret)
|
|
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
|
|
index 30ddfb21f65818..2d3afeaf886877 100644
|
|
--- a/drivers/md/dm-bufio.c
|
|
+++ b/drivers/md/dm-bufio.c
|
|
@@ -68,6 +68,8 @@
|
|
#define LIST_DIRTY 1
|
|
#define LIST_SIZE 2
|
|
|
|
+#define SCAN_RESCHED_CYCLE 16
|
|
+
|
|
/*--------------------------------------------------------------*/
|
|
|
|
/*
|
|
@@ -2387,7 +2389,12 @@ static void __scan(struct dm_bufio_client *c)
|
|
|
|
atomic_long_dec(&c->need_shrink);
|
|
freed++;
|
|
- cond_resched();
|
|
+
|
|
+ if (unlikely(freed % SCAN_RESCHED_CYCLE == 0)) {
|
|
+ dm_bufio_unlock(c);
|
|
+ cond_resched();
|
|
+ dm_bufio_lock(c);
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
|
|
index eb2b44f4a61f08..1e27a5bce2d942 100644
|
|
--- a/drivers/md/dm-integrity.c
|
|
+++ b/drivers/md/dm-integrity.c
|
|
@@ -4687,7 +4687,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
|
|
BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress));
|
|
BUG_ON(!list_empty(&ic->wait_list));
|
|
|
|
- if (ic->mode == 'B')
|
|
+ if (ic->mode == 'B' && ic->bitmap_flush_work.work.func)
|
|
cancel_delayed_work_sync(&ic->bitmap_flush_work);
|
|
if (ic->metadata_wq)
|
|
destroy_workqueue(ic->metadata_wq);
|
|
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
|
|
index fd84e06670e8d7..319bd10548e9ad 100644
|
|
--- a/drivers/md/dm-table.c
|
|
+++ b/drivers/md/dm-table.c
|
|
@@ -500,8 +500,9 @@ static char **realloc_argv(unsigned int *size, char **old_argv)
|
|
gfp = GFP_NOIO;
|
|
}
|
|
argv = kmalloc_array(new_size, sizeof(*argv), gfp);
|
|
- if (argv && old_argv) {
|
|
- memcpy(argv, old_argv, *size * sizeof(*argv));
|
|
+ if (argv) {
|
|
+ if (old_argv)
|
|
+ memcpy(argv, old_argv, *size * sizeof(*argv));
|
|
*size = new_size;
|
|
}
|
|
|
|
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
|
|
index c675dec587efb2..597b00e8c9539d 100644
|
|
--- a/drivers/mmc/host/renesas_sdhi_core.c
|
|
+++ b/drivers/mmc/host/renesas_sdhi_core.c
|
|
@@ -1107,26 +1107,26 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
|
num_irqs = platform_irq_count(pdev);
|
|
if (num_irqs < 0) {
|
|
ret = num_irqs;
|
|
- goto eirq;
|
|
+ goto edisclk;
|
|
}
|
|
|
|
/* There must be at least one IRQ source */
|
|
if (!num_irqs) {
|
|
ret = -ENXIO;
|
|
- goto eirq;
|
|
+ goto edisclk;
|
|
}
|
|
|
|
for (i = 0; i < num_irqs; i++) {
|
|
irq = platform_get_irq(pdev, i);
|
|
if (irq < 0) {
|
|
ret = irq;
|
|
- goto eirq;
|
|
+ goto edisclk;
|
|
}
|
|
|
|
ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0,
|
|
dev_name(&pdev->dev), host);
|
|
if (ret)
|
|
- goto eirq;
|
|
+ goto edisclk;
|
|
}
|
|
|
|
ret = tmio_mmc_host_probe(host);
|
|
@@ -1138,8 +1138,6 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
|
|
|
return ret;
|
|
|
|
-eirq:
|
|
- tmio_mmc_host_remove(host);
|
|
edisclk:
|
|
renesas_sdhi_clk_disable(host);
|
|
efree:
|
|
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
|
|
index 8d27933c3733b1..f91f25578f075b 100644
|
|
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
|
|
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
|
|
@@ -1543,7 +1543,7 @@ static void vsc9959_tas_clock_adjust(struct ocelot *ocelot)
|
|
struct tc_taprio_qopt_offload *taprio;
|
|
struct ocelot_port *ocelot_port;
|
|
struct timespec64 base_ts;
|
|
- int port;
|
|
+ int i, port;
|
|
u32 val;
|
|
|
|
mutex_lock(&ocelot->fwd_domain_lock);
|
|
@@ -1575,6 +1575,9 @@ static void vsc9959_tas_clock_adjust(struct ocelot *ocelot)
|
|
QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB_M,
|
|
QSYS_PARAM_CFG_REG_3);
|
|
|
|
+ for (i = 0; i < taprio->num_entries; i++)
|
|
+ vsc9959_tas_gcl_set(ocelot, i, &taprio->entries[i]);
|
|
+
|
|
ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
|
|
QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
|
|
QSYS_TAS_PARAM_CFG_CTRL);
|
|
diff --git a/drivers/net/ethernet/amd/pds_core/auxbus.c b/drivers/net/ethernet/amd/pds_core/auxbus.c
|
|
index fb7a5403e630db..889a18962270aa 100644
|
|
--- a/drivers/net/ethernet/amd/pds_core/auxbus.c
|
|
+++ b/drivers/net/ethernet/amd/pds_core/auxbus.c
|
|
@@ -172,48 +172,57 @@ static struct pds_auxiliary_dev *pdsc_auxbus_dev_register(struct pdsc *cf,
|
|
return padev;
|
|
}
|
|
|
|
-int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf)
|
|
+void pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf,
|
|
+ struct pds_auxiliary_dev **pd_ptr)
|
|
{
|
|
struct pds_auxiliary_dev *padev;
|
|
- int err = 0;
|
|
+
|
|
+ if (!*pd_ptr)
|
|
+ return;
|
|
|
|
mutex_lock(&pf->config_lock);
|
|
|
|
- padev = pf->vfs[cf->vf_id].padev;
|
|
- if (padev) {
|
|
- pds_client_unregister(pf, padev->client_id);
|
|
- auxiliary_device_delete(&padev->aux_dev);
|
|
- auxiliary_device_uninit(&padev->aux_dev);
|
|
- padev->client_id = 0;
|
|
- }
|
|
- pf->vfs[cf->vf_id].padev = NULL;
|
|
+ padev = *pd_ptr;
|
|
+ pds_client_unregister(pf, padev->client_id);
|
|
+ auxiliary_device_delete(&padev->aux_dev);
|
|
+ auxiliary_device_uninit(&padev->aux_dev);
|
|
+ *pd_ptr = NULL;
|
|
|
|
mutex_unlock(&pf->config_lock);
|
|
- return err;
|
|
}
|
|
|
|
-int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf)
|
|
+int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf,
|
|
+ enum pds_core_vif_types vt,
|
|
+ struct pds_auxiliary_dev **pd_ptr)
|
|
{
|
|
struct pds_auxiliary_dev *padev;
|
|
- enum pds_core_vif_types vt;
|
|
char devname[PDS_DEVNAME_LEN];
|
|
+ unsigned long mask;
|
|
u16 vt_support;
|
|
int client_id;
|
|
int err = 0;
|
|
|
|
+ if (!cf)
|
|
+ return -ENODEV;
|
|
+
|
|
+ if (vt >= PDS_DEV_TYPE_MAX)
|
|
+ return -EINVAL;
|
|
+
|
|
mutex_lock(&pf->config_lock);
|
|
|
|
- /* We only support vDPA so far, so it is the only one to
|
|
- * be verified that it is available in the Core device and
|
|
- * enabled in the devlink param. In the future this might
|
|
- * become a loop for several VIF types.
|
|
- */
|
|
+ mask = BIT_ULL(PDSC_S_FW_DEAD) |
|
|
+ BIT_ULL(PDSC_S_STOPPING_DRIVER);
|
|
+ if (cf->state & mask) {
|
|
+ dev_err(pf->dev, "%s: can't add dev, VF client in bad state %#lx\n",
|
|
+ __func__, cf->state);
|
|
+ err = -ENXIO;
|
|
+ goto out_unlock;
|
|
+ }
|
|
|
|
/* Verify that the type is supported and enabled. It is not
|
|
* an error if there is no auxbus device support for this
|
|
* VF, it just means something else needs to happen with it.
|
|
*/
|
|
- vt = PDS_DEV_TYPE_VDPA;
|
|
vt_support = !!le16_to_cpu(pf->dev_ident.vif_types[vt]);
|
|
if (!(vt_support &&
|
|
pf->viftype_status[vt].supported &&
|
|
@@ -239,7 +248,7 @@ int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf)
|
|
err = PTR_ERR(padev);
|
|
goto out_unlock;
|
|
}
|
|
- pf->vfs[cf->vf_id].padev = padev;
|
|
+ *pd_ptr = padev;
|
|
|
|
out_unlock:
|
|
mutex_unlock(&pf->config_lock);
|
|
diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h
|
|
index 858bebf7977624..61ee607ee48ace 100644
|
|
--- a/drivers/net/ethernet/amd/pds_core/core.h
|
|
+++ b/drivers/net/ethernet/amd/pds_core/core.h
|
|
@@ -300,8 +300,11 @@ void pdsc_health_thread(struct work_struct *work);
|
|
int pdsc_register_notify(struct notifier_block *nb);
|
|
void pdsc_unregister_notify(struct notifier_block *nb);
|
|
void pdsc_notify(unsigned long event, void *data);
|
|
-int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf);
|
|
-int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf);
|
|
+int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf,
|
|
+ enum pds_core_vif_types vt,
|
|
+ struct pds_auxiliary_dev **pd_ptr);
|
|
+void pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf,
|
|
+ struct pds_auxiliary_dev **pd_ptr);
|
|
|
|
void pdsc_process_adminq(struct pdsc_qcq *qcq);
|
|
void pdsc_work_thread(struct work_struct *work);
|
|
diff --git a/drivers/net/ethernet/amd/pds_core/dev.c b/drivers/net/ethernet/amd/pds_core/dev.c
|
|
index f0e39ab4004503..e65a1632df505d 100644
|
|
--- a/drivers/net/ethernet/amd/pds_core/dev.c
|
|
+++ b/drivers/net/ethernet/amd/pds_core/dev.c
|
|
@@ -42,6 +42,8 @@ int pdsc_err_to_errno(enum pds_core_status_code code)
|
|
return -ERANGE;
|
|
case PDS_RC_BAD_ADDR:
|
|
return -EFAULT;
|
|
+ case PDS_RC_BAD_PCI:
|
|
+ return -ENXIO;
|
|
case PDS_RC_EOPCODE:
|
|
case PDS_RC_EINTR:
|
|
case PDS_RC_DEV_CMD:
|
|
@@ -65,7 +67,7 @@ bool pdsc_is_fw_running(struct pdsc *pdsc)
|
|
/* Firmware is useful only if the running bit is set and
|
|
* fw_status != 0xff (bad PCI read)
|
|
*/
|
|
- return (pdsc->fw_status != 0xff) &&
|
|
+ return (pdsc->fw_status != PDS_RC_BAD_PCI) &&
|
|
(pdsc->fw_status & PDS_CORE_FW_STS_F_RUNNING);
|
|
}
|
|
|
|
@@ -131,6 +133,7 @@ static int pdsc_devcmd_wait(struct pdsc *pdsc, u8 opcode, int max_seconds)
|
|
unsigned long max_wait;
|
|
unsigned long duration;
|
|
int timeout = 0;
|
|
+ bool running;
|
|
int done = 0;
|
|
int err = 0;
|
|
int status;
|
|
@@ -139,6 +142,10 @@ static int pdsc_devcmd_wait(struct pdsc *pdsc, u8 opcode, int max_seconds)
|
|
max_wait = start_time + (max_seconds * HZ);
|
|
|
|
while (!done && !timeout) {
|
|
+ running = pdsc_is_fw_running(pdsc);
|
|
+ if (!running)
|
|
+ break;
|
|
+
|
|
done = pdsc_devcmd_done(pdsc);
|
|
if (done)
|
|
break;
|
|
@@ -155,7 +162,7 @@ static int pdsc_devcmd_wait(struct pdsc *pdsc, u8 opcode, int max_seconds)
|
|
dev_dbg(dev, "DEVCMD %d %s after %ld secs\n",
|
|
opcode, pdsc_devcmd_str(opcode), duration / HZ);
|
|
|
|
- if (!done || timeout) {
|
|
+ if ((!done || timeout) && running) {
|
|
dev_err(dev, "DEVCMD %d %s timeout, done %d timeout %d max_seconds=%d\n",
|
|
opcode, pdsc_devcmd_str(opcode), done, timeout,
|
|
max_seconds);
|
|
diff --git a/drivers/net/ethernet/amd/pds_core/devlink.c b/drivers/net/ethernet/amd/pds_core/devlink.c
|
|
index 0032e8e3518117..bee70e46e34c68 100644
|
|
--- a/drivers/net/ethernet/amd/pds_core/devlink.c
|
|
+++ b/drivers/net/ethernet/amd/pds_core/devlink.c
|
|
@@ -55,8 +55,11 @@ int pdsc_dl_enable_set(struct devlink *dl, u32 id,
|
|
for (vf_id = 0; vf_id < pdsc->num_vfs; vf_id++) {
|
|
struct pdsc *vf = pdsc->vfs[vf_id].vf;
|
|
|
|
- err = ctx->val.vbool ? pdsc_auxbus_dev_add(vf, pdsc) :
|
|
- pdsc_auxbus_dev_del(vf, pdsc);
|
|
+ if (ctx->val.vbool)
|
|
+ err = pdsc_auxbus_dev_add(vf, pdsc, vt_entry->vif_id,
|
|
+ &pdsc->vfs[vf_id].padev);
|
|
+ else
|
|
+ pdsc_auxbus_dev_del(vf, pdsc, &pdsc->vfs[vf_id].padev);
|
|
}
|
|
|
|
return err;
|
|
diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c
|
|
index eddbf0acdde77f..76652e0e5b6d9c 100644
|
|
--- a/drivers/net/ethernet/amd/pds_core/main.c
|
|
+++ b/drivers/net/ethernet/amd/pds_core/main.c
|
|
@@ -189,7 +189,8 @@ static int pdsc_init_vf(struct pdsc *vf)
|
|
devl_unlock(dl);
|
|
|
|
pf->vfs[vf->vf_id].vf = vf;
|
|
- err = pdsc_auxbus_dev_add(vf, pf);
|
|
+ err = pdsc_auxbus_dev_add(vf, pf, PDS_DEV_TYPE_VDPA,
|
|
+ &pf->vfs[vf->vf_id].padev);
|
|
if (err) {
|
|
devl_lock(dl);
|
|
devl_unregister(dl);
|
|
@@ -415,7 +416,7 @@ static void pdsc_remove(struct pci_dev *pdev)
|
|
|
|
pf = pdsc_get_pf_struct(pdsc->pdev);
|
|
if (!IS_ERR(pf)) {
|
|
- pdsc_auxbus_dev_del(pdsc, pf);
|
|
+ pdsc_auxbus_dev_del(pdsc, pf, &pf->vfs[pdsc->vf_id].padev);
|
|
pf->vfs[pdsc->vf_id].vf = NULL;
|
|
}
|
|
} else {
|
|
@@ -475,6 +476,15 @@ static void pdsc_reset_prepare(struct pci_dev *pdev)
|
|
pdsc_stop_health_thread(pdsc);
|
|
pdsc_fw_down(pdsc);
|
|
|
|
+ if (pdev->is_virtfn) {
|
|
+ struct pdsc *pf;
|
|
+
|
|
+ pf = pdsc_get_pf_struct(pdsc->pdev);
|
|
+ if (!IS_ERR(pf))
|
|
+ pdsc_auxbus_dev_del(pdsc, pf,
|
|
+ &pf->vfs[pdsc->vf_id].padev);
|
|
+ }
|
|
+
|
|
pdsc_unmap_bars(pdsc);
|
|
pci_release_regions(pdev);
|
|
pci_disable_device(pdev);
|
|
@@ -510,6 +520,15 @@ static void pdsc_reset_done(struct pci_dev *pdev)
|
|
|
|
pdsc_fw_up(pdsc);
|
|
pdsc_restart_health_thread(pdsc);
|
|
+
|
|
+ if (pdev->is_virtfn) {
|
|
+ struct pdsc *pf;
|
|
+
|
|
+ pf = pdsc_get_pf_struct(pdsc->pdev);
|
|
+ if (!IS_ERR(pf))
|
|
+ pdsc_auxbus_dev_add(pdsc, pf, PDS_DEV_TYPE_VDPA,
|
|
+ &pf->vfs[pdsc->vf_id].padev);
|
|
+ }
|
|
}
|
|
|
|
static const struct pci_error_handlers pdsc_err_handler = {
|
|
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
|
|
index 230726d7b74f63..d41b58fad37bbf 100644
|
|
--- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
|
|
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
|
|
@@ -373,8 +373,13 @@ static int xgbe_map_rx_buffer(struct xgbe_prv_data *pdata,
|
|
}
|
|
|
|
/* Set up the header page info */
|
|
- xgbe_set_buffer_data(&rdata->rx.hdr, &ring->rx_hdr_pa,
|
|
- XGBE_SKB_ALLOC_SIZE);
|
|
+ if (pdata->netdev->features & NETIF_F_RXCSUM) {
|
|
+ xgbe_set_buffer_data(&rdata->rx.hdr, &ring->rx_hdr_pa,
|
|
+ XGBE_SKB_ALLOC_SIZE);
|
|
+ } else {
|
|
+ xgbe_set_buffer_data(&rdata->rx.hdr, &ring->rx_hdr_pa,
|
|
+ pdata->rx_buf_size);
|
|
+ }
|
|
|
|
/* Set up the buffer page info */
|
|
xgbe_set_buffer_data(&rdata->rx.buf, &ring->rx_buf_pa,
|
|
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
|
|
index f393228d41c7be..f1b0fb02b3cd14 100644
|
|
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
|
|
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
|
|
@@ -320,6 +320,18 @@ static void xgbe_config_sph_mode(struct xgbe_prv_data *pdata)
|
|
XGMAC_IOWRITE_BITS(pdata, MAC_RCR, HDSMS, XGBE_SPH_HDSMS_SIZE);
|
|
}
|
|
|
|
+static void xgbe_disable_sph_mode(struct xgbe_prv_data *pdata)
|
|
+{
|
|
+ unsigned int i;
|
|
+
|
|
+ for (i = 0; i < pdata->channel_count; i++) {
|
|
+ if (!pdata->channel[i]->rx_ring)
|
|
+ break;
|
|
+
|
|
+ XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_CR, SPH, 0);
|
|
+ }
|
|
+}
|
|
+
|
|
static int xgbe_write_rss_reg(struct xgbe_prv_data *pdata, unsigned int type,
|
|
unsigned int index, unsigned int val)
|
|
{
|
|
@@ -3545,8 +3557,12 @@ static int xgbe_init(struct xgbe_prv_data *pdata)
|
|
xgbe_config_tx_coalesce(pdata);
|
|
xgbe_config_rx_buffer_size(pdata);
|
|
xgbe_config_tso_mode(pdata);
|
|
- xgbe_config_sph_mode(pdata);
|
|
- xgbe_config_rss(pdata);
|
|
+
|
|
+ if (pdata->netdev->features & NETIF_F_RXCSUM) {
|
|
+ xgbe_config_sph_mode(pdata);
|
|
+ xgbe_config_rss(pdata);
|
|
+ }
|
|
+
|
|
desc_if->wrapper_tx_desc_init(pdata);
|
|
desc_if->wrapper_rx_desc_init(pdata);
|
|
xgbe_enable_dma_interrupts(pdata);
|
|
@@ -3702,5 +3718,9 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if)
|
|
hw_if->disable_vxlan = xgbe_disable_vxlan;
|
|
hw_if->set_vxlan_id = xgbe_set_vxlan_id;
|
|
|
|
+ /* For Split Header*/
|
|
+ hw_if->enable_sph = xgbe_config_sph_mode;
|
|
+ hw_if->disable_sph = xgbe_disable_sph_mode;
|
|
+
|
|
DBGPR("<--xgbe_init_function_ptrs\n");
|
|
}
|
|
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
|
|
index 6b73648b377936..34d45cebefb5d3 100644
|
|
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
|
|
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
|
|
@@ -2257,10 +2257,17 @@ static int xgbe_set_features(struct net_device *netdev,
|
|
if (ret)
|
|
return ret;
|
|
|
|
- if ((features & NETIF_F_RXCSUM) && !rxcsum)
|
|
+ if ((features & NETIF_F_RXCSUM) && !rxcsum) {
|
|
+ hw_if->enable_sph(pdata);
|
|
+ hw_if->enable_vxlan(pdata);
|
|
hw_if->enable_rx_csum(pdata);
|
|
- else if (!(features & NETIF_F_RXCSUM) && rxcsum)
|
|
+ schedule_work(&pdata->restart_work);
|
|
+ } else if (!(features & NETIF_F_RXCSUM) && rxcsum) {
|
|
+ hw_if->disable_sph(pdata);
|
|
+ hw_if->disable_vxlan(pdata);
|
|
hw_if->disable_rx_csum(pdata);
|
|
+ schedule_work(&pdata->restart_work);
|
|
+ }
|
|
|
|
if ((features & NETIF_F_HW_VLAN_CTAG_RX) && !rxvlan)
|
|
hw_if->enable_rx_vlan_stripping(pdata);
|
|
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
|
|
index ad136ed493ed1f..173f4dad470f55 100644
|
|
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
|
|
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
|
|
@@ -865,6 +865,10 @@ struct xgbe_hw_if {
|
|
void (*enable_vxlan)(struct xgbe_prv_data *);
|
|
void (*disable_vxlan)(struct xgbe_prv_data *);
|
|
void (*set_vxlan_id)(struct xgbe_prv_data *);
|
|
+
|
|
+ /* For Split Header */
|
|
+ void (*enable_sph)(struct xgbe_prv_data *pdata);
|
|
+ void (*disable_sph)(struct xgbe_prv_data *pdata);
|
|
};
|
|
|
|
/* This structure represents implementation specific routines for an
|
|
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c
|
|
index c067898820360e..32813cdd5aa5cb 100644
|
|
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c
|
|
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c
|
|
@@ -66,20 +66,30 @@ static int bnxt_hwrm_dbg_dma_data(struct bnxt *bp, void *msg,
|
|
}
|
|
}
|
|
|
|
+ if (cmn_req->req_type ==
|
|
+ cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE))
|
|
+ info->dest_buf_size += len;
|
|
+
|
|
if (info->dest_buf) {
|
|
if ((info->seg_start + off + len) <=
|
|
BNXT_COREDUMP_BUF_LEN(info->buf_len)) {
|
|
- memcpy(info->dest_buf + off, dma_buf, len);
|
|
+ u16 copylen = min_t(u16, len,
|
|
+ info->dest_buf_size - off);
|
|
+
|
|
+ memcpy(info->dest_buf + off, dma_buf, copylen);
|
|
+ if (copylen < len)
|
|
+ break;
|
|
} else {
|
|
rc = -ENOBUFS;
|
|
+ if (cmn_req->req_type ==
|
|
+ cpu_to_le16(HWRM_DBG_COREDUMP_LIST)) {
|
|
+ kfree(info->dest_buf);
|
|
+ info->dest_buf = NULL;
|
|
+ }
|
|
break;
|
|
}
|
|
}
|
|
|
|
- if (cmn_req->req_type ==
|
|
- cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE))
|
|
- info->dest_buf_size += len;
|
|
-
|
|
if (!(cmn_resp->flags & HWRM_DBG_CMN_FLAGS_MORE))
|
|
break;
|
|
|
|
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
|
|
index 2e7ddbca9d53b1..dcedafa4d2e14f 100644
|
|
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
|
|
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
|
|
@@ -1393,6 +1393,17 @@ static int bnxt_get_regs_len(struct net_device *dev)
|
|
return reg_len;
|
|
}
|
|
|
|
+#define BNXT_PCIE_32B_ENTRY(start, end) \
|
|
+ { offsetof(struct pcie_ctx_hw_stats, start), \
|
|
+ offsetof(struct pcie_ctx_hw_stats, end) }
|
|
+
|
|
+static const struct {
|
|
+ u16 start;
|
|
+ u16 end;
|
|
+} bnxt_pcie_32b_entries[] = {
|
|
+ BNXT_PCIE_32B_ENTRY(pcie_ltssm_histogram[0], pcie_ltssm_histogram[3]),
|
|
+};
|
|
+
|
|
static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs,
|
|
void *_p)
|
|
{
|
|
@@ -1424,12 +1435,27 @@ static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs,
|
|
req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr);
|
|
rc = hwrm_req_send(bp, req);
|
|
if (!rc) {
|
|
- __le64 *src = (__le64 *)hw_pcie_stats;
|
|
- u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN);
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++)
|
|
- dst[i] = le64_to_cpu(src[i]);
|
|
+ u8 *dst = (u8 *)(_p + BNXT_PXP_REG_LEN);
|
|
+ u8 *src = (u8 *)hw_pcie_stats;
|
|
+ int i, j;
|
|
+
|
|
+ for (i = 0, j = 0; i < sizeof(*hw_pcie_stats); ) {
|
|
+ if (i >= bnxt_pcie_32b_entries[j].start &&
|
|
+ i <= bnxt_pcie_32b_entries[j].end) {
|
|
+ u32 *dst32 = (u32 *)(dst + i);
|
|
+
|
|
+ *dst32 = le32_to_cpu(*(__le32 *)(src + i));
|
|
+ i += 4;
|
|
+ if (i > bnxt_pcie_32b_entries[j].end &&
|
|
+ j < ARRAY_SIZE(bnxt_pcie_32b_entries) - 1)
|
|
+ j++;
|
|
+ } else {
|
|
+ u64 *dst64 = (u64 *)(dst + i);
|
|
+
|
|
+ *dst64 = le64_to_cpu(*(__le64 *)(src + i));
|
|
+ i += 8;
|
|
+ }
|
|
+ }
|
|
}
|
|
hwrm_req_drop(bp, req);
|
|
}
|
|
diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c
|
|
index db6615aa921b19..ce46f3ac3b5a18 100644
|
|
--- a/drivers/net/ethernet/dlink/dl2k.c
|
|
+++ b/drivers/net/ethernet/dlink/dl2k.c
|
|
@@ -352,7 +352,7 @@ parse_eeprom (struct net_device *dev)
|
|
eth_hw_addr_set(dev, psrom->mac_addr);
|
|
|
|
if (np->chip_id == CHIP_IP1000A) {
|
|
- np->led_mode = psrom->led_mode;
|
|
+ np->led_mode = le16_to_cpu(psrom->led_mode);
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/net/ethernet/dlink/dl2k.h b/drivers/net/ethernet/dlink/dl2k.h
|
|
index 195dc6cfd8955c..0e33e2eaae9606 100644
|
|
--- a/drivers/net/ethernet/dlink/dl2k.h
|
|
+++ b/drivers/net/ethernet/dlink/dl2k.h
|
|
@@ -335,7 +335,7 @@ typedef struct t_SROM {
|
|
u16 sub_system_id; /* 0x06 */
|
|
u16 pci_base_1; /* 0x08 (IP1000A only) */
|
|
u16 pci_base_2; /* 0x0a (IP1000A only) */
|
|
- u16 led_mode; /* 0x0c (IP1000A only) */
|
|
+ __le16 led_mode; /* 0x0c (IP1000A only) */
|
|
u16 reserved1[9]; /* 0x0e-0x1f */
|
|
u8 mac_addr[6]; /* 0x20-0x25 */
|
|
u8 reserved2[10]; /* 0x26-0x2f */
|
|
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
|
|
index 2d6b50903c923d..7261838a09db63 100644
|
|
--- a/drivers/net/ethernet/freescale/fec_main.c
|
|
+++ b/drivers/net/ethernet/freescale/fec_main.c
|
|
@@ -695,7 +695,12 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
|
|
txq->bd.cur = bdp;
|
|
|
|
/* Trigger transmission start */
|
|
- writel(0, txq->bd.reg_desc_active);
|
|
+ if (!(fep->quirks & FEC_QUIRK_ERR007885) ||
|
|
+ !readl(txq->bd.reg_desc_active) ||
|
|
+ !readl(txq->bd.reg_desc_active) ||
|
|
+ !readl(txq->bd.reg_desc_active) ||
|
|
+ !readl(txq->bd.reg_desc_active))
|
|
+ writel(0, txq->bd.reg_desc_active);
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
|
|
index 4f385a18d288e4..36206273453f3a 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
|
|
@@ -60,7 +60,7 @@ static struct hns3_dbg_cmd_info hns3_dbg_cmd[] = {
|
|
.name = "tm_qset",
|
|
.cmd = HNAE3_DBG_CMD_TM_QSET,
|
|
.dentry = HNS3_DBG_DENTRY_TM,
|
|
- .buf_len = HNS3_DBG_READ_LEN,
|
|
+ .buf_len = HNS3_DBG_READ_LEN_1MB,
|
|
.init = hns3_dbg_common_file_init,
|
|
},
|
|
{
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
|
|
index 801801e8803e9f..0ed01f4d680618 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
|
|
@@ -473,20 +473,14 @@ static void hns3_mask_vector_irq(struct hns3_enet_tqp_vector *tqp_vector,
|
|
writel(mask_en, tqp_vector->mask_addr);
|
|
}
|
|
|
|
-static void hns3_vector_enable(struct hns3_enet_tqp_vector *tqp_vector)
|
|
+static void hns3_irq_enable(struct hns3_enet_tqp_vector *tqp_vector)
|
|
{
|
|
napi_enable(&tqp_vector->napi);
|
|
enable_irq(tqp_vector->vector_irq);
|
|
-
|
|
- /* enable vector */
|
|
- hns3_mask_vector_irq(tqp_vector, 1);
|
|
}
|
|
|
|
-static void hns3_vector_disable(struct hns3_enet_tqp_vector *tqp_vector)
|
|
+static void hns3_irq_disable(struct hns3_enet_tqp_vector *tqp_vector)
|
|
{
|
|
- /* disable vector */
|
|
- hns3_mask_vector_irq(tqp_vector, 0);
|
|
-
|
|
disable_irq(tqp_vector->vector_irq);
|
|
napi_disable(&tqp_vector->napi);
|
|
cancel_work_sync(&tqp_vector->rx_group.dim.work);
|
|
@@ -707,11 +701,42 @@ static int hns3_set_rx_cpu_rmap(struct net_device *netdev)
|
|
return 0;
|
|
}
|
|
|
|
+static void hns3_enable_irqs_and_tqps(struct net_device *netdev)
|
|
+{
|
|
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
|
|
+ struct hnae3_handle *h = priv->ae_handle;
|
|
+ u16 i;
|
|
+
|
|
+ for (i = 0; i < priv->vector_num; i++)
|
|
+ hns3_irq_enable(&priv->tqp_vector[i]);
|
|
+
|
|
+ for (i = 0; i < priv->vector_num; i++)
|
|
+ hns3_mask_vector_irq(&priv->tqp_vector[i], 1);
|
|
+
|
|
+ for (i = 0; i < h->kinfo.num_tqps; i++)
|
|
+ hns3_tqp_enable(h->kinfo.tqp[i]);
|
|
+}
|
|
+
|
|
+static void hns3_disable_irqs_and_tqps(struct net_device *netdev)
|
|
+{
|
|
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
|
|
+ struct hnae3_handle *h = priv->ae_handle;
|
|
+ u16 i;
|
|
+
|
|
+ for (i = 0; i < h->kinfo.num_tqps; i++)
|
|
+ hns3_tqp_disable(h->kinfo.tqp[i]);
|
|
+
|
|
+ for (i = 0; i < priv->vector_num; i++)
|
|
+ hns3_mask_vector_irq(&priv->tqp_vector[i], 0);
|
|
+
|
|
+ for (i = 0; i < priv->vector_num; i++)
|
|
+ hns3_irq_disable(&priv->tqp_vector[i]);
|
|
+}
|
|
+
|
|
static int hns3_nic_net_up(struct net_device *netdev)
|
|
{
|
|
struct hns3_nic_priv *priv = netdev_priv(netdev);
|
|
struct hnae3_handle *h = priv->ae_handle;
|
|
- int i, j;
|
|
int ret;
|
|
|
|
ret = hns3_nic_reset_all_ring(h);
|
|
@@ -720,23 +745,13 @@ static int hns3_nic_net_up(struct net_device *netdev)
|
|
|
|
clear_bit(HNS3_NIC_STATE_DOWN, &priv->state);
|
|
|
|
- /* enable the vectors */
|
|
- for (i = 0; i < priv->vector_num; i++)
|
|
- hns3_vector_enable(&priv->tqp_vector[i]);
|
|
-
|
|
- /* enable rcb */
|
|
- for (j = 0; j < h->kinfo.num_tqps; j++)
|
|
- hns3_tqp_enable(h->kinfo.tqp[j]);
|
|
+ hns3_enable_irqs_and_tqps(netdev);
|
|
|
|
/* start the ae_dev */
|
|
ret = h->ae_algo->ops->start ? h->ae_algo->ops->start(h) : 0;
|
|
if (ret) {
|
|
set_bit(HNS3_NIC_STATE_DOWN, &priv->state);
|
|
- while (j--)
|
|
- hns3_tqp_disable(h->kinfo.tqp[j]);
|
|
-
|
|
- for (j = i - 1; j >= 0; j--)
|
|
- hns3_vector_disable(&priv->tqp_vector[j]);
|
|
+ hns3_disable_irqs_and_tqps(netdev);
|
|
}
|
|
|
|
return ret;
|
|
@@ -823,17 +838,9 @@ static void hns3_reset_tx_queue(struct hnae3_handle *h)
|
|
static void hns3_nic_net_down(struct net_device *netdev)
|
|
{
|
|
struct hns3_nic_priv *priv = netdev_priv(netdev);
|
|
- struct hnae3_handle *h = hns3_get_handle(netdev);
|
|
const struct hnae3_ae_ops *ops;
|
|
- int i;
|
|
|
|
- /* disable vectors */
|
|
- for (i = 0; i < priv->vector_num; i++)
|
|
- hns3_vector_disable(&priv->tqp_vector[i]);
|
|
-
|
|
- /* disable rcb */
|
|
- for (i = 0; i < h->kinfo.num_tqps; i++)
|
|
- hns3_tqp_disable(h->kinfo.tqp[i]);
|
|
+ hns3_disable_irqs_and_tqps(netdev);
|
|
|
|
/* stop ae_dev */
|
|
ops = priv->ae_handle->ae_algo->ops;
|
|
@@ -5870,8 +5877,6 @@ int hns3_set_channels(struct net_device *netdev,
|
|
void hns3_external_lb_prepare(struct net_device *ndev, bool if_running)
|
|
{
|
|
struct hns3_nic_priv *priv = netdev_priv(ndev);
|
|
- struct hnae3_handle *h = priv->ae_handle;
|
|
- int i;
|
|
|
|
if (!if_running)
|
|
return;
|
|
@@ -5882,11 +5887,7 @@ void hns3_external_lb_prepare(struct net_device *ndev, bool if_running)
|
|
netif_carrier_off(ndev);
|
|
netif_tx_disable(ndev);
|
|
|
|
- for (i = 0; i < priv->vector_num; i++)
|
|
- hns3_vector_disable(&priv->tqp_vector[i]);
|
|
-
|
|
- for (i = 0; i < h->kinfo.num_tqps; i++)
|
|
- hns3_tqp_disable(h->kinfo.tqp[i]);
|
|
+ hns3_disable_irqs_and_tqps(ndev);
|
|
|
|
/* delay ring buffer clearing to hns3_reset_notify_uninit_enet
|
|
* during reset process, because driver may not be able
|
|
@@ -5902,7 +5903,6 @@ void hns3_external_lb_restore(struct net_device *ndev, bool if_running)
|
|
{
|
|
struct hns3_nic_priv *priv = netdev_priv(ndev);
|
|
struct hnae3_handle *h = priv->ae_handle;
|
|
- int i;
|
|
|
|
if (!if_running)
|
|
return;
|
|
@@ -5918,11 +5918,7 @@ void hns3_external_lb_restore(struct net_device *ndev, bool if_running)
|
|
|
|
clear_bit(HNS3_NIC_STATE_DOWN, &priv->state);
|
|
|
|
- for (i = 0; i < priv->vector_num; i++)
|
|
- hns3_vector_enable(&priv->tqp_vector[i]);
|
|
-
|
|
- for (i = 0; i < h->kinfo.num_tqps; i++)
|
|
- hns3_tqp_enable(h->kinfo.tqp[i]);
|
|
+ hns3_enable_irqs_and_tqps(ndev);
|
|
|
|
netif_tx_wake_all_queues(ndev);
|
|
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c
|
|
index ddc691424c8163..9a806ac727cf5b 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c
|
|
@@ -440,6 +440,13 @@ static int hclge_ptp_create_clock(struct hclge_dev *hdev)
|
|
ptp->info.settime64 = hclge_ptp_settime;
|
|
|
|
ptp->info.n_alarm = 0;
|
|
+
|
|
+ spin_lock_init(&ptp->lock);
|
|
+ ptp->io_base = hdev->hw.hw.io_base + HCLGE_PTP_REG_OFFSET;
|
|
+ ptp->ts_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
|
|
+ ptp->ts_cfg.tx_type = HWTSTAMP_TX_OFF;
|
|
+ hdev->ptp = ptp;
|
|
+
|
|
ptp->clock = ptp_clock_register(&ptp->info, &hdev->pdev->dev);
|
|
if (IS_ERR(ptp->clock)) {
|
|
dev_err(&hdev->pdev->dev,
|
|
@@ -451,12 +458,6 @@ static int hclge_ptp_create_clock(struct hclge_dev *hdev)
|
|
return -ENODEV;
|
|
}
|
|
|
|
- spin_lock_init(&ptp->lock);
|
|
- ptp->io_base = hdev->hw.hw.io_base + HCLGE_PTP_REG_OFFSET;
|
|
- ptp->ts_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
|
|
- ptp->ts_cfg.tx_type = HWTSTAMP_TX_OFF;
|
|
- hdev->ptp = ptp;
|
|
-
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
|
|
index 69bfcfb148def4..1ba0b57c7a72d7 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
|
|
@@ -1257,9 +1257,8 @@ static void hclgevf_sync_vlan_filter(struct hclgevf_dev *hdev)
|
|
rtnl_unlock();
|
|
}
|
|
|
|
-static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable)
|
|
+static int hclgevf_en_hw_strip_rxvtag_cmd(struct hclgevf_dev *hdev, bool enable)
|
|
{
|
|
- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
|
|
struct hclge_vf_to_pf_msg send_msg;
|
|
|
|
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_VLAN,
|
|
@@ -1268,6 +1267,19 @@ static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable)
|
|
return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0);
|
|
}
|
|
|
|
+static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable)
|
|
+{
|
|
+ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
|
|
+ int ret;
|
|
+
|
|
+ ret = hclgevf_en_hw_strip_rxvtag_cmd(hdev, enable);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ hdev->rxvtag_strip_en = enable;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int hclgevf_reset_tqp(struct hnae3_handle *handle)
|
|
{
|
|
#define HCLGEVF_RESET_ALL_QUEUE_DONE 1U
|
|
@@ -2143,12 +2155,13 @@ static int hclgevf_rss_init_hw(struct hclgevf_dev *hdev)
|
|
tc_valid, tc_size);
|
|
}
|
|
|
|
-static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev)
|
|
+static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev,
|
|
+ bool rxvtag_strip_en)
|
|
{
|
|
struct hnae3_handle *nic = &hdev->nic;
|
|
int ret;
|
|
|
|
- ret = hclgevf_en_hw_strip_rxvtag(nic, true);
|
|
+ ret = hclgevf_en_hw_strip_rxvtag(nic, rxvtag_strip_en);
|
|
if (ret) {
|
|
dev_err(&hdev->pdev->dev,
|
|
"failed to enable rx vlan offload, ret = %d\n", ret);
|
|
@@ -2815,7 +2828,7 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev)
|
|
if (ret)
|
|
return ret;
|
|
|
|
- ret = hclgevf_init_vlan_config(hdev);
|
|
+ ret = hclgevf_init_vlan_config(hdev, hdev->rxvtag_strip_en);
|
|
if (ret) {
|
|
dev_err(&hdev->pdev->dev,
|
|
"failed(%d) to initialize VLAN config\n", ret);
|
|
@@ -2928,7 +2941,7 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev)
|
|
goto err_config;
|
|
}
|
|
|
|
- ret = hclgevf_init_vlan_config(hdev);
|
|
+ ret = hclgevf_init_vlan_config(hdev, true);
|
|
if (ret) {
|
|
dev_err(&hdev->pdev->dev,
|
|
"failed(%d) to initialize VLAN config\n", ret);
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
|
|
index cccef32284616b..0208425ab594f5 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
|
|
@@ -253,6 +253,7 @@ struct hclgevf_dev {
|
|
int *vector_irq;
|
|
|
|
bool gro_en;
|
|
+ bool rxvtag_strip_en;
|
|
|
|
unsigned long vlan_del_fail_bmap[BITS_TO_LONGS(VLAN_N_VID)];
|
|
|
|
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c
|
|
index 3ca5f44dea26eb..88c1acd5e8f05d 100644
|
|
--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c
|
|
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c
|
|
@@ -1824,6 +1824,11 @@ int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg)
|
|
pf = vf->pf;
|
|
dev = ice_pf_to_dev(pf);
|
|
vf_vsi = ice_get_vf_vsi(vf);
|
|
+ if (!vf_vsi) {
|
|
+ dev_err(dev, "Can not get FDIR vf_vsi for VF %u\n", vf->vf_id);
|
|
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
|
|
+ goto err_exit;
|
|
+ }
|
|
|
|
#define ICE_VF_MAX_FDIR_FILTERS 128
|
|
if (!ice_fdir_num_avail_fltr(&pf->hw, vf_vsi) ||
|
|
diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c
|
|
index b6bb01a486d9d8..a82af96e6bd12f 100644
|
|
--- a/drivers/net/ethernet/intel/igc/igc_ptp.c
|
|
+++ b/drivers/net/ethernet/intel/igc/igc_ptp.c
|
|
@@ -1237,6 +1237,8 @@ void igc_ptp_reset(struct igc_adapter *adapter)
|
|
/* reset the tstamp_config */
|
|
igc_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config);
|
|
|
|
+ mutex_lock(&adapter->ptm_lock);
|
|
+
|
|
spin_lock_irqsave(&adapter->tmreg_lock, flags);
|
|
|
|
switch (adapter->hw.mac.type) {
|
|
@@ -1255,7 +1257,6 @@ void igc_ptp_reset(struct igc_adapter *adapter)
|
|
if (!igc_is_crosststamp_supported(adapter))
|
|
break;
|
|
|
|
- mutex_lock(&adapter->ptm_lock);
|
|
wr32(IGC_PCIE_DIG_DELAY, IGC_PCIE_DIG_DELAY_DEFAULT);
|
|
wr32(IGC_PCIE_PHY_DELAY, IGC_PCIE_PHY_DELAY_DEFAULT);
|
|
|
|
@@ -1279,7 +1280,6 @@ void igc_ptp_reset(struct igc_adapter *adapter)
|
|
netdev_err(adapter->netdev, "Timeout reading IGC_PTM_STAT register\n");
|
|
|
|
igc_ptm_reset(hw);
|
|
- mutex_unlock(&adapter->ptm_lock);
|
|
break;
|
|
default:
|
|
/* No work to do. */
|
|
@@ -1296,5 +1296,7 @@ void igc_ptp_reset(struct igc_adapter *adapter)
|
|
out:
|
|
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
|
|
|
|
+ mutex_unlock(&adapter->ptm_lock);
|
|
+
|
|
wrfl();
|
|
}
|
|
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
|
|
index 6f1fe7e283d4eb..7a30095b3486f3 100644
|
|
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
|
|
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
|
|
@@ -917,7 +917,7 @@ static void octep_hb_timeout_task(struct work_struct *work)
|
|
miss_cnt);
|
|
rtnl_lock();
|
|
if (netif_running(oct->netdev))
|
|
- octep_stop(oct->netdev);
|
|
+ dev_close(oct->netdev);
|
|
rtnl_unlock();
|
|
}
|
|
|
|
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
|
index dc89dbc13b251f..d2ec8f642c2fa0 100644
|
|
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
|
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
|
@@ -2180,14 +2180,18 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
|
|
ring->data[idx] = new_data;
|
|
rxd->rxd1 = (unsigned int)dma_addr;
|
|
release_desc:
|
|
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA)) {
|
|
+ if (unlikely(dma_addr == DMA_MAPPING_ERROR))
|
|
+ addr64 = FIELD_GET(RX_DMA_ADDR64_MASK,
|
|
+ rxd->rxd2);
|
|
+ else
|
|
+ addr64 = RX_DMA_PREP_ADDR64(dma_addr);
|
|
+ }
|
|
+
|
|
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
|
|
rxd->rxd2 = RX_DMA_LSO;
|
|
else
|
|
- rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size);
|
|
-
|
|
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA) &&
|
|
- likely(dma_addr != DMA_MAPPING_ERROR))
|
|
- rxd->rxd2 |= RX_DMA_PREP_ADDR64(dma_addr);
|
|
+ rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size) | addr64;
|
|
|
|
ring->calc_idx = idx;
|
|
done++;
|
|
diff --git a/drivers/net/ethernet/mediatek/mtk_star_emac.c b/drivers/net/ethernet/mediatek/mtk_star_emac.c
|
|
index 25989c79c92e61..c2ab87828d8589 100644
|
|
--- a/drivers/net/ethernet/mediatek/mtk_star_emac.c
|
|
+++ b/drivers/net/ethernet/mediatek/mtk_star_emac.c
|
|
@@ -1163,6 +1163,7 @@ static int mtk_star_tx_poll(struct napi_struct *napi, int budget)
|
|
struct net_device *ndev = priv->ndev;
|
|
unsigned int head = ring->head;
|
|
unsigned int entry = ring->tail;
|
|
+ unsigned long flags;
|
|
|
|
while (entry != head && count < (MTK_STAR_RING_NUM_DESCS - 1)) {
|
|
ret = mtk_star_tx_complete_one(priv);
|
|
@@ -1182,9 +1183,9 @@ static int mtk_star_tx_poll(struct napi_struct *napi, int budget)
|
|
netif_wake_queue(ndev);
|
|
|
|
if (napi_complete(napi)) {
|
|
- spin_lock(&priv->lock);
|
|
+ spin_lock_irqsave(&priv->lock, flags);
|
|
mtk_star_enable_dma_irq(priv, false, true);
|
|
- spin_unlock(&priv->lock);
|
|
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
}
|
|
|
|
return 0;
|
|
@@ -1341,16 +1342,16 @@ static int mtk_star_rx(struct mtk_star_priv *priv, int budget)
|
|
static int mtk_star_rx_poll(struct napi_struct *napi, int budget)
|
|
{
|
|
struct mtk_star_priv *priv;
|
|
+ unsigned long flags;
|
|
int work_done = 0;
|
|
|
|
priv = container_of(napi, struct mtk_star_priv, rx_napi);
|
|
|
|
work_done = mtk_star_rx(priv, budget);
|
|
- if (work_done < budget) {
|
|
- napi_complete_done(napi, work_done);
|
|
- spin_lock(&priv->lock);
|
|
+ if (work_done < budget && napi_complete_done(napi, work_done)) {
|
|
+ spin_lock_irqsave(&priv->lock, flags);
|
|
mtk_star_enable_dma_irq(priv, true, false);
|
|
- spin_unlock(&priv->lock);
|
|
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
}
|
|
|
|
return work_done;
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
|
|
index 7eba3a5bb97cae..326c72b3df8671 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
|
|
@@ -3499,7 +3499,9 @@ int esw_offloads_enable(struct mlx5_eswitch *esw)
|
|
int err;
|
|
|
|
mutex_init(&esw->offloads.termtbl_mutex);
|
|
- mlx5_rdma_enable_roce(esw->dev);
|
|
+ err = mlx5_rdma_enable_roce(esw->dev);
|
|
+ if (err)
|
|
+ goto err_roce;
|
|
|
|
err = mlx5_esw_host_number_init(esw);
|
|
if (err)
|
|
@@ -3560,6 +3562,7 @@ int esw_offloads_enable(struct mlx5_eswitch *esw)
|
|
esw_offloads_metadata_uninit(esw);
|
|
err_metadata:
|
|
mlx5_rdma_disable_roce(esw->dev);
|
|
+err_roce:
|
|
mutex_destroy(&esw->offloads.termtbl_mutex);
|
|
return err;
|
|
}
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c
|
|
index a42f6cd99b7448..5c552b71e371c5 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c
|
|
@@ -118,8 +118,8 @@ static void mlx5_rdma_make_default_gid(struct mlx5_core_dev *dev, union ib_gid *
|
|
|
|
static int mlx5_rdma_add_roce_addr(struct mlx5_core_dev *dev)
|
|
{
|
|
+ u8 mac[ETH_ALEN] = {};
|
|
union ib_gid gid;
|
|
- u8 mac[ETH_ALEN];
|
|
|
|
mlx5_rdma_make_default_gid(dev, &gid);
|
|
return mlx5_core_roce_gid_set(dev, 0,
|
|
@@ -140,17 +140,17 @@ void mlx5_rdma_disable_roce(struct mlx5_core_dev *dev)
|
|
mlx5_nic_vport_disable_roce(dev);
|
|
}
|
|
|
|
-void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev)
|
|
+int mlx5_rdma_enable_roce(struct mlx5_core_dev *dev)
|
|
{
|
|
int err;
|
|
|
|
if (!MLX5_CAP_GEN(dev, roce))
|
|
- return;
|
|
+ return 0;
|
|
|
|
err = mlx5_nic_vport_enable_roce(dev);
|
|
if (err) {
|
|
mlx5_core_err(dev, "Failed to enable RoCE: %d\n", err);
|
|
- return;
|
|
+ return err;
|
|
}
|
|
|
|
err = mlx5_rdma_add_roce_addr(dev);
|
|
@@ -165,10 +165,11 @@ void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev)
|
|
goto del_roce_addr;
|
|
}
|
|
|
|
- return;
|
|
+ return err;
|
|
|
|
del_roce_addr:
|
|
mlx5_rdma_del_roce_addr(dev);
|
|
disable_roce:
|
|
mlx5_nic_vport_disable_roce(dev);
|
|
+ return err;
|
|
}
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/rdma.h b/drivers/net/ethernet/mellanox/mlx5/core/rdma.h
|
|
index 750cff2a71a4bb..3d9e76c3d42fb1 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/rdma.h
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/rdma.h
|
|
@@ -8,12 +8,12 @@
|
|
|
|
#ifdef CONFIG_MLX5_ESWITCH
|
|
|
|
-void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev);
|
|
+int mlx5_rdma_enable_roce(struct mlx5_core_dev *dev);
|
|
void mlx5_rdma_disable_roce(struct mlx5_core_dev *dev);
|
|
|
|
#else /* CONFIG_MLX5_ESWITCH */
|
|
|
|
-static inline void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev) {}
|
|
+static inline int mlx5_rdma_enable_roce(struct mlx5_core_dev *dev) { return 0; }
|
|
static inline void mlx5_rdma_disable_roce(struct mlx5_core_dev *dev) {}
|
|
|
|
#endif /* CONFIG_MLX5_ESWITCH */
|
|
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
|
|
index 92010bfe5e4133..5d2ceff72784f2 100644
|
|
--- a/drivers/net/ethernet/microchip/lan743x_main.c
|
|
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
|
|
@@ -1949,6 +1949,7 @@ static void lan743x_tx_frame_add_lso(struct lan743x_tx *tx,
|
|
if (nr_frags <= 0) {
|
|
tx->frame_data0 |= TX_DESC_DATA0_LS_;
|
|
tx->frame_data0 |= TX_DESC_DATA0_IOC_;
|
|
+ tx->frame_last = tx->frame_first;
|
|
}
|
|
tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
|
|
tx_descriptor->data0 = cpu_to_le32(tx->frame_data0);
|
|
@@ -2018,6 +2019,7 @@ static int lan743x_tx_frame_add_fragment(struct lan743x_tx *tx,
|
|
tx->frame_first = 0;
|
|
tx->frame_data0 = 0;
|
|
tx->frame_tail = 0;
|
|
+ tx->frame_last = 0;
|
|
return -ENOMEM;
|
|
}
|
|
|
|
@@ -2058,16 +2060,18 @@ static void lan743x_tx_frame_end(struct lan743x_tx *tx,
|
|
TX_DESC_DATA0_DTYPE_DATA_) {
|
|
tx->frame_data0 |= TX_DESC_DATA0_LS_;
|
|
tx->frame_data0 |= TX_DESC_DATA0_IOC_;
|
|
+ tx->frame_last = tx->frame_tail;
|
|
}
|
|
|
|
- tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
|
|
- buffer_info = &tx->buffer_info[tx->frame_tail];
|
|
+ tx_descriptor = &tx->ring_cpu_ptr[tx->frame_last];
|
|
+ buffer_info = &tx->buffer_info[tx->frame_last];
|
|
buffer_info->skb = skb;
|
|
if (time_stamp)
|
|
buffer_info->flags |= TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED;
|
|
if (ignore_sync)
|
|
buffer_info->flags |= TX_BUFFER_INFO_FLAG_IGNORE_SYNC;
|
|
|
|
+ tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
|
|
tx_descriptor->data0 = cpu_to_le32(tx->frame_data0);
|
|
tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail);
|
|
tx->last_tail = tx->frame_tail;
|
|
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
|
|
index 3b2c6046eb3ad5..b6c83c68241e63 100644
|
|
--- a/drivers/net/ethernet/microchip/lan743x_main.h
|
|
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
|
|
@@ -974,6 +974,7 @@ struct lan743x_tx {
|
|
u32 frame_first;
|
|
u32 frame_data0;
|
|
u32 frame_tail;
|
|
+ u32 frame_last;
|
|
|
|
struct lan743x_tx_buffer_info *buffer_info;
|
|
|
|
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
|
|
index f6aa5d6b6597e0..252d8e6f18c3cc 100644
|
|
--- a/drivers/net/ethernet/mscc/ocelot.c
|
|
+++ b/drivers/net/ethernet/mscc/ocelot.c
|
|
@@ -453,9 +453,158 @@ static u16 ocelot_vlan_unaware_pvid(struct ocelot *ocelot,
|
|
return VLAN_N_VID - bridge_num - 1;
|
|
}
|
|
|
|
+/**
|
|
+ * ocelot_update_vlan_reclassify_rule() - Make switch aware only to bridge VLAN TPID
|
|
+ *
|
|
+ * @ocelot: Switch private data structure
|
|
+ * @port: Index of ingress port
|
|
+ *
|
|
+ * IEEE 802.1Q-2018 clauses "5.5 C-VLAN component conformance" and "5.6 S-VLAN
|
|
+ * component conformance" suggest that a C-VLAN component should only recognize
|
|
+ * and filter on C-Tags, and an S-VLAN component should only recognize and
|
|
+ * process based on C-Tags.
|
|
+ *
|
|
+ * In Linux, as per commit 1a0b20b25732 ("Merge branch 'bridge-next'"), C-VLAN
|
|
+ * components are largely represented by a bridge with vlan_protocol 802.1Q,
|
|
+ * and S-VLAN components by a bridge with vlan_protocol 802.1ad.
|
|
+ *
|
|
+ * Currently the driver only offloads vlan_protocol 802.1Q, but the hardware
|
|
+ * design is non-conformant, because the switch assigns each frame to a VLAN
|
|
+ * based on an entirely different question, as detailed in figure "Basic VLAN
|
|
+ * Classification Flow" from its manual and reproduced below.
|
|
+ *
|
|
+ * Set TAG_TYPE, PCP, DEI, VID to port-default values in VLAN_CFG register
|
|
+ * if VLAN_AWARE_ENA[port] and frame has outer tag then:
|
|
+ * if VLAN_INNER_TAG_ENA[port] and frame has inner tag then:
|
|
+ * TAG_TYPE = (Frame.InnerTPID <> 0x8100)
|
|
+ * Set PCP, DEI, VID to values from inner VLAN header
|
|
+ * else:
|
|
+ * TAG_TYPE = (Frame.OuterTPID <> 0x8100)
|
|
+ * Set PCP, DEI, VID to values from outer VLAN header
|
|
+ * if VID == 0 then:
|
|
+ * VID = VLAN_CFG.VLAN_VID
|
|
+ *
|
|
+ * Summarized, the switch will recognize both 802.1Q and 802.1ad TPIDs as VLAN
|
|
+ * "with equal rights", and just set the TAG_TYPE bit to 0 (if 802.1Q) or to 1
|
|
+ * (if 802.1ad). It will classify based on whichever of the tags is "outer", no
|
|
+ * matter what TPID that may have (or "inner", if VLAN_INNER_TAG_ENA[port]).
|
|
+ *
|
|
+ * In the VLAN Table, the TAG_TYPE information is not accessible - just the
|
|
+ * classified VID is - so it is as if each VLAN Table entry is for 2 VLANs:
|
|
+ * C-VLAN X, and S-VLAN X.
|
|
+ *
|
|
+ * Whereas the Linux bridge behavior is to only filter on frames with a TPID
|
|
+ * equal to the vlan_protocol, and treat everything else as VLAN-untagged.
|
|
+ *
|
|
+ * Consider an ingress packet tagged with 802.1ad VID=3 and 802.1Q VID=5,
|
|
+ * received on a bridge vlan_filtering=1 vlan_protocol=802.1Q port. This frame
|
|
+ * should be treated as 802.1Q-untagged, and classified to the PVID of that
|
|
+ * bridge port. Not to VID=3, and not to VID=5.
|
|
+ *
|
|
+ * The VCAP IS1 TCAM has everything we need to overwrite the choices made in
|
|
+ * the basic VLAN classification pipeline: it can match on TAG_TYPE in the key,
|
|
+ * and it can modify the classified VID in the action. Thus, for each port
|
|
+ * under a vlan_filtering bridge, we can insert a rule in VCAP IS1 lookup 0 to
|
|
+ * match on 802.1ad tagged frames and modify their classified VID to the 802.1Q
|
|
+ * PVID of the port. This effectively makes it appear to the outside world as
|
|
+ * if those packets were processed as VLAN-untagged.
|
|
+ *
|
|
+ * The rule needs to be updated each time the bridge PVID changes, and needs
|
|
+ * to be deleted if the bridge PVID is deleted, or if the port becomes
|
|
+ * VLAN-unaware.
|
|
+ */
|
|
+static int ocelot_update_vlan_reclassify_rule(struct ocelot *ocelot, int port)
|
|
+{
|
|
+ unsigned long cookie = OCELOT_VCAP_IS1_VLAN_RECLASSIFY(ocelot, port);
|
|
+ struct ocelot_vcap_block *block_vcap_is1 = &ocelot->block[VCAP_IS1];
|
|
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
|
|
+ const struct ocelot_bridge_vlan *pvid_vlan;
|
|
+ struct ocelot_vcap_filter *filter;
|
|
+ int err, val, pcp, dei;
|
|
+ bool vid_replace_ena;
|
|
+ u16 vid;
|
|
+
|
|
+ pvid_vlan = ocelot_port->pvid_vlan;
|
|
+ vid_replace_ena = ocelot_port->vlan_aware && pvid_vlan;
|
|
+
|
|
+ filter = ocelot_vcap_block_find_filter_by_id(block_vcap_is1, cookie,
|
|
+ false);
|
|
+ if (!vid_replace_ena) {
|
|
+ /* If the reclassification filter doesn't need to exist, delete
|
|
+ * it if it was previously installed, and exit doing nothing
|
|
+ * otherwise.
|
|
+ */
|
|
+ if (filter)
|
|
+ return ocelot_vcap_filter_del(ocelot, filter);
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* The reclassification rule must apply. See if it already exists
|
|
+ * or if it must be created.
|
|
+ */
|
|
+
|
|
+ /* Treating as VLAN-untagged means using as classified VID equal to
|
|
+ * the bridge PVID, and PCP/DEI set to the port default QoS values.
|
|
+ */
|
|
+ vid = pvid_vlan->vid;
|
|
+ val = ocelot_read_gix(ocelot, ANA_PORT_QOS_CFG, port);
|
|
+ pcp = ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL_X(val);
|
|
+ dei = !!(val & ANA_PORT_QOS_CFG_DP_DEFAULT_VAL);
|
|
+
|
|
+ if (filter) {
|
|
+ bool changed = false;
|
|
+
|
|
+ /* Filter exists, just update it */
|
|
+ if (filter->action.vid != vid) {
|
|
+ filter->action.vid = vid;
|
|
+ changed = true;
|
|
+ }
|
|
+ if (filter->action.pcp != pcp) {
|
|
+ filter->action.pcp = pcp;
|
|
+ changed = true;
|
|
+ }
|
|
+ if (filter->action.dei != dei) {
|
|
+ filter->action.dei = dei;
|
|
+ changed = true;
|
|
+ }
|
|
+
|
|
+ if (!changed)
|
|
+ return 0;
|
|
+
|
|
+ return ocelot_vcap_filter_replace(ocelot, filter);
|
|
+ }
|
|
+
|
|
+ /* Filter doesn't exist, create it */
|
|
+ filter = kzalloc(sizeof(*filter), GFP_KERNEL);
|
|
+ if (!filter)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ filter->key_type = OCELOT_VCAP_KEY_ANY;
|
|
+ filter->ingress_port_mask = BIT(port);
|
|
+ filter->vlan.tpid = OCELOT_VCAP_BIT_1;
|
|
+ filter->prio = 1;
|
|
+ filter->id.cookie = cookie;
|
|
+ filter->id.tc_offload = false;
|
|
+ filter->block_id = VCAP_IS1;
|
|
+ filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
|
|
+ filter->lookup = 0;
|
|
+ filter->action.vid_replace_ena = true;
|
|
+ filter->action.pcp_dei_ena = true;
|
|
+ filter->action.vid = vid;
|
|
+ filter->action.pcp = pcp;
|
|
+ filter->action.dei = dei;
|
|
+
|
|
+ err = ocelot_vcap_filter_add(ocelot, filter, NULL);
|
|
+ if (err)
|
|
+ kfree(filter);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
/* Default vlan to clasify for untagged frames (may be zero) */
|
|
-static void ocelot_port_set_pvid(struct ocelot *ocelot, int port,
|
|
- const struct ocelot_bridge_vlan *pvid_vlan)
|
|
+static int ocelot_port_set_pvid(struct ocelot *ocelot, int port,
|
|
+ const struct ocelot_bridge_vlan *pvid_vlan)
|
|
{
|
|
struct ocelot_port *ocelot_port = ocelot->ports[port];
|
|
u16 pvid = ocelot_vlan_unaware_pvid(ocelot, ocelot_port->bridge);
|
|
@@ -475,15 +624,23 @@ static void ocelot_port_set_pvid(struct ocelot *ocelot, int port,
|
|
* happens automatically), but also 802.1p traffic which gets
|
|
* classified to VLAN 0, but that is always in our RX filter, so it
|
|
* would get accepted were it not for this setting.
|
|
+ *
|
|
+ * Also, we only support the bridge 802.1Q VLAN protocol, so
|
|
+ * 802.1ad-tagged frames (carrying S-Tags) should be considered
|
|
+ * 802.1Q-untagged, and also dropped.
|
|
*/
|
|
if (!pvid_vlan && ocelot_port->vlan_aware)
|
|
val = ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA |
|
|
- ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA;
|
|
+ ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA |
|
|
+ ANA_PORT_DROP_CFG_DROP_S_TAGGED_ENA;
|
|
|
|
ocelot_rmw_gix(ocelot, val,
|
|
ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA |
|
|
- ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA,
|
|
+ ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA |
|
|
+ ANA_PORT_DROP_CFG_DROP_S_TAGGED_ENA,
|
|
ANA_PORT_DROP_CFG, port);
|
|
+
|
|
+ return ocelot_update_vlan_reclassify_rule(ocelot, port);
|
|
}
|
|
|
|
static struct ocelot_bridge_vlan *ocelot_bridge_vlan_find(struct ocelot *ocelot,
|
|
@@ -631,7 +788,10 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
|
|
ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M,
|
|
ANA_PORT_VLAN_CFG, port);
|
|
|
|
- ocelot_port_set_pvid(ocelot, port, ocelot_port->pvid_vlan);
|
|
+ err = ocelot_port_set_pvid(ocelot, port, ocelot_port->pvid_vlan);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
ocelot_port_manage_port_tag(ocelot, port);
|
|
|
|
return 0;
|
|
@@ -670,6 +830,7 @@ EXPORT_SYMBOL(ocelot_vlan_prepare);
|
|
int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
|
|
bool untagged)
|
|
{
|
|
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
|
|
int err;
|
|
|
|
/* Ignore VID 0 added to our RX filter by the 8021q module, since
|
|
@@ -684,9 +845,17 @@ int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
|
|
return err;
|
|
|
|
/* Default ingress vlan classification */
|
|
- if (pvid)
|
|
- ocelot_port_set_pvid(ocelot, port,
|
|
- ocelot_bridge_vlan_find(ocelot, vid));
|
|
+ if (pvid) {
|
|
+ err = ocelot_port_set_pvid(ocelot, port,
|
|
+ ocelot_bridge_vlan_find(ocelot, vid));
|
|
+ if (err)
|
|
+ return err;
|
|
+ } else if (ocelot_port->pvid_vlan &&
|
|
+ ocelot_bridge_vlan_find(ocelot, vid) == ocelot_port->pvid_vlan) {
|
|
+ err = ocelot_port_set_pvid(ocelot, port, NULL);
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
|
|
/* Untagged egress vlan clasification */
|
|
ocelot_port_manage_port_tag(ocelot, port);
|
|
@@ -712,8 +881,11 @@ int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid)
|
|
return err;
|
|
|
|
/* Ingress */
|
|
- if (del_pvid)
|
|
- ocelot_port_set_pvid(ocelot, port, NULL);
|
|
+ if (del_pvid) {
|
|
+ err = ocelot_port_set_pvid(ocelot, port, NULL);
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
|
|
/* Egress */
|
|
ocelot_port_manage_port_tag(ocelot, port);
|
|
@@ -2607,7 +2779,7 @@ int ocelot_port_set_default_prio(struct ocelot *ocelot, int port, u8 prio)
|
|
ANA_PORT_QOS_CFG,
|
|
port);
|
|
|
|
- return 0;
|
|
+ return ocelot_update_vlan_reclassify_rule(ocelot, port);
|
|
}
|
|
EXPORT_SYMBOL_GPL(ocelot_port_set_default_prio);
|
|
|
|
diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.c b/drivers/net/ethernet/mscc/ocelot_vcap.c
|
|
index 73cdec5ca6a34d..5734b86aed5b53 100644
|
|
--- a/drivers/net/ethernet/mscc/ocelot_vcap.c
|
|
+++ b/drivers/net/ethernet/mscc/ocelot_vcap.c
|
|
@@ -695,6 +695,7 @@ static void is1_entry_set(struct ocelot *ocelot, int ix,
|
|
vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_MC, filter->dmac_mc);
|
|
vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_BC, filter->dmac_bc);
|
|
vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_VLAN_TAGGED, tag->tagged);
|
|
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TPID, tag->tpid);
|
|
vcap_key_set(vcap, &data, VCAP_IS1_HK_VID,
|
|
tag->vid.value, tag->vid.mask);
|
|
vcap_key_set(vcap, &data, VCAP_IS1_HK_PCP,
|
|
diff --git a/drivers/net/ethernet/vertexcom/mse102x.c b/drivers/net/ethernet/vertexcom/mse102x.c
|
|
index 8f67c39f479eef..060a566bc6aae1 100644
|
|
--- a/drivers/net/ethernet/vertexcom/mse102x.c
|
|
+++ b/drivers/net/ethernet/vertexcom/mse102x.c
|
|
@@ -6,6 +6,7 @@
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
+#include <linux/if_vlan.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
@@ -33,7 +34,7 @@
|
|
#define CMD_CTR (0x2 << CMD_SHIFT)
|
|
|
|
#define CMD_MASK GENMASK(15, CMD_SHIFT)
|
|
-#define LEN_MASK GENMASK(CMD_SHIFT - 1, 0)
|
|
+#define LEN_MASK GENMASK(CMD_SHIFT - 2, 0)
|
|
|
|
#define DET_CMD_LEN 4
|
|
#define DET_SOF_LEN 2
|
|
@@ -262,7 +263,7 @@ static int mse102x_tx_frame_spi(struct mse102x_net *mse, struct sk_buff *txp,
|
|
}
|
|
|
|
static int mse102x_rx_frame_spi(struct mse102x_net *mse, u8 *buff,
|
|
- unsigned int frame_len)
|
|
+ unsigned int frame_len, bool drop)
|
|
{
|
|
struct mse102x_net_spi *mses = to_mse102x_spi(mse);
|
|
struct spi_transfer *xfer = &mses->spi_xfer;
|
|
@@ -280,6 +281,9 @@ static int mse102x_rx_frame_spi(struct mse102x_net *mse, u8 *buff,
|
|
netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n",
|
|
__func__, ret);
|
|
mse->stats.xfer_err++;
|
|
+ } else if (drop) {
|
|
+ netdev_dbg(mse->ndev, "%s: Drop frame\n", __func__);
|
|
+ ret = -EINVAL;
|
|
} else if (*sof != cpu_to_be16(DET_SOF)) {
|
|
netdev_dbg(mse->ndev, "%s: SPI start of frame is invalid (0x%04x)\n",
|
|
__func__, *sof);
|
|
@@ -307,6 +311,7 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse)
|
|
struct sk_buff *skb;
|
|
unsigned int rxalign;
|
|
unsigned int rxlen;
|
|
+ bool drop = false;
|
|
__be16 rx = 0;
|
|
u16 cmd_resp;
|
|
u8 *rxpkt;
|
|
@@ -329,7 +334,8 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse)
|
|
net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n",
|
|
__func__, cmd_resp);
|
|
mse->stats.invalid_rts++;
|
|
- return;
|
|
+ drop = true;
|
|
+ goto drop;
|
|
}
|
|
|
|
net_dbg_ratelimited("%s: Unexpected response to first CMD\n",
|
|
@@ -337,12 +343,20 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse)
|
|
}
|
|
|
|
rxlen = cmd_resp & LEN_MASK;
|
|
- if (!rxlen) {
|
|
- net_dbg_ratelimited("%s: No frame length defined\n", __func__);
|
|
+ if (rxlen < ETH_ZLEN || rxlen > VLAN_ETH_FRAME_LEN) {
|
|
+ net_dbg_ratelimited("%s: Invalid frame length: %d\n", __func__,
|
|
+ rxlen);
|
|
mse->stats.invalid_len++;
|
|
- return;
|
|
+ drop = true;
|
|
}
|
|
|
|
+ /* In case of a invalid CMD_RTS, the frame must be consumed anyway.
|
|
+ * So assume the maximum possible frame length.
|
|
+ */
|
|
+drop:
|
|
+ if (drop)
|
|
+ rxlen = VLAN_ETH_FRAME_LEN;
|
|
+
|
|
rxalign = ALIGN(rxlen + DET_SOF_LEN + DET_DFT_LEN, 4);
|
|
skb = netdev_alloc_skb_ip_align(mse->ndev, rxalign);
|
|
if (!skb)
|
|
@@ -353,7 +367,7 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse)
|
|
* They are copied, but ignored.
|
|
*/
|
|
rxpkt = skb_put(skb, rxlen) - DET_SOF_LEN;
|
|
- if (mse102x_rx_frame_spi(mse, rxpkt, rxlen)) {
|
|
+ if (mse102x_rx_frame_spi(mse, rxpkt, rxlen, drop)) {
|
|
mse->ndev->stats.rx_errors++;
|
|
dev_kfree_skb(skb);
|
|
return;
|
|
@@ -509,6 +523,7 @@ static irqreturn_t mse102x_irq(int irq, void *_mse)
|
|
static int mse102x_net_open(struct net_device *ndev)
|
|
{
|
|
struct mse102x_net *mse = netdev_priv(ndev);
|
|
+ struct mse102x_net_spi *mses = to_mse102x_spi(mse);
|
|
int ret;
|
|
|
|
ret = request_threaded_irq(ndev->irq, NULL, mse102x_irq, IRQF_ONESHOT,
|
|
@@ -524,6 +539,13 @@ static int mse102x_net_open(struct net_device *ndev)
|
|
|
|
netif_carrier_on(ndev);
|
|
|
|
+ /* The SPI interrupt can stuck in case of pending packet(s).
|
|
+ * So poll for possible packet(s) to re-arm the interrupt.
|
|
+ */
|
|
+ mutex_lock(&mses->lock);
|
|
+ mse102x_rx_pkt_spi(mse);
|
|
+ mutex_unlock(&mses->lock);
|
|
+
|
|
netif_dbg(mse, ifup, ndev, "network device up\n");
|
|
|
|
return 0;
|
|
diff --git a/drivers/net/mdio/mdio-mux-meson-gxl.c b/drivers/net/mdio/mdio-mux-meson-gxl.c
|
|
index 76188575ca1fcf..19153d44800a94 100644
|
|
--- a/drivers/net/mdio/mdio-mux-meson-gxl.c
|
|
+++ b/drivers/net/mdio/mdio-mux-meson-gxl.c
|
|
@@ -17,6 +17,7 @@
|
|
#define REG2_LEDACT GENMASK(23, 22)
|
|
#define REG2_LEDLINK GENMASK(25, 24)
|
|
#define REG2_DIV4SEL BIT(27)
|
|
+#define REG2_REVERSED BIT(28)
|
|
#define REG2_ADCBYPASS BIT(30)
|
|
#define REG2_CLKINSEL BIT(31)
|
|
#define ETH_REG3 0x4
|
|
@@ -65,7 +66,7 @@ static void gxl_enable_internal_mdio(struct gxl_mdio_mux *priv)
|
|
* The only constraint is that it must match the one in
|
|
* drivers/net/phy/meson-gxl.c to properly match the PHY.
|
|
*/
|
|
- writel(FIELD_PREP(REG2_PHYID, EPHY_GXL_ID),
|
|
+ writel(REG2_REVERSED | FIELD_PREP(REG2_PHYID, EPHY_GXL_ID),
|
|
priv->regs + ETH_REG2);
|
|
|
|
/* Enable the internal phy */
|
|
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
|
|
index bb0bf141587274..7b3739b29c8f72 100644
|
|
--- a/drivers/net/usb/rndis_host.c
|
|
+++ b/drivers/net/usb/rndis_host.c
|
|
@@ -630,16 +630,6 @@ static const struct driver_info zte_rndis_info = {
|
|
.tx_fixup = rndis_tx_fixup,
|
|
};
|
|
|
|
-static const struct driver_info wwan_rndis_info = {
|
|
- .description = "Mobile Broadband RNDIS device",
|
|
- .flags = FLAG_WWAN | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT,
|
|
- .bind = rndis_bind,
|
|
- .unbind = rndis_unbind,
|
|
- .status = rndis_status,
|
|
- .rx_fixup = rndis_rx_fixup,
|
|
- .tx_fixup = rndis_tx_fixup,
|
|
-};
|
|
-
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
static const struct usb_device_id products [] = {
|
|
@@ -676,11 +666,9 @@ static const struct usb_device_id products [] = {
|
|
USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
|
|
.driver_info = (unsigned long) &rndis_info,
|
|
}, {
|
|
- /* Mobile Broadband Modem, seen in Novatel Verizon USB730L and
|
|
- * Telit FN990A (RNDIS)
|
|
- */
|
|
+ /* Novatel Verizon USB730L */
|
|
USB_INTERFACE_INFO(USB_CLASS_MISC, 4, 1),
|
|
- .driver_info = (unsigned long)&wwan_rndis_info,
|
|
+ .driver_info = (unsigned long) &rndis_info,
|
|
},
|
|
{ }, // END
|
|
};
|
|
diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
|
|
index 6e6e9f05509ab0..06d19e90eadb59 100644
|
|
--- a/drivers/net/vxlan/vxlan_vnifilter.c
|
|
+++ b/drivers/net/vxlan/vxlan_vnifilter.c
|
|
@@ -627,7 +627,11 @@ static void vxlan_vni_delete_group(struct vxlan_dev *vxlan,
|
|
* default dst remote_ip previously added for this vni
|
|
*/
|
|
if (!vxlan_addr_any(&vninode->remote_ip) ||
|
|
- !vxlan_addr_any(&dst->remote_ip))
|
|
+ !vxlan_addr_any(&dst->remote_ip)) {
|
|
+ u32 hash_index = fdb_head_index(vxlan, all_zeros_mac,
|
|
+ vninode->vni);
|
|
+
|
|
+ spin_lock_bh(&vxlan->hash_lock[hash_index]);
|
|
__vxlan_fdb_delete(vxlan, all_zeros_mac,
|
|
(vxlan_addr_any(&vninode->remote_ip) ?
|
|
dst->remote_ip : vninode->remote_ip),
|
|
@@ -635,6 +639,8 @@ static void vxlan_vni_delete_group(struct vxlan_dev *vxlan,
|
|
vninode->vni, vninode->vni,
|
|
dst->remote_ifindex,
|
|
true);
|
|
+ spin_unlock_bh(&vxlan->hash_lock[hash_index]);
|
|
+ }
|
|
|
|
if (vxlan->dev->flags & IFF_UP) {
|
|
if (vxlan_addr_multicast(&vninode->remote_ip) &&
|
|
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
|
index 2178675ae1a44d..6f64a05debd2cb 100644
|
|
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
|
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
|
@@ -903,14 +903,16 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
|
|
}
|
|
|
|
/* 1) Prepare USB boot loader for runtime image */
|
|
- brcmf_usb_dl_cmd(devinfo, DL_START, &state, sizeof(state));
|
|
+ err = brcmf_usb_dl_cmd(devinfo, DL_START, &state, sizeof(state));
|
|
+ if (err)
|
|
+ goto fail;
|
|
|
|
rdlstate = le32_to_cpu(state.state);
|
|
rdlbytes = le32_to_cpu(state.bytes);
|
|
|
|
/* 2) Check we are in the Waiting state */
|
|
if (rdlstate != DL_WAITING) {
|
|
- brcmf_err("Failed to DL_START\n");
|
|
+ brcmf_err("Invalid DL state: %u\n", rdlstate);
|
|
err = -EINVAL;
|
|
goto fail;
|
|
}
|
|
diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.c b/drivers/net/wireless/purelifi/plfxlc/mac.c
|
|
index 506d2f31efb5af..7ebc0df0944cb5 100644
|
|
--- a/drivers/net/wireless/purelifi/plfxlc/mac.c
|
|
+++ b/drivers/net/wireless/purelifi/plfxlc/mac.c
|
|
@@ -103,7 +103,6 @@ int plfxlc_mac_init_hw(struct ieee80211_hw *hw)
|
|
void plfxlc_mac_release(struct plfxlc_mac *mac)
|
|
{
|
|
plfxlc_chip_release(&mac->chip);
|
|
- lockdep_assert_held(&mac->lock);
|
|
}
|
|
|
|
int plfxlc_op_start(struct ieee80211_hw *hw)
|
|
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
|
|
index a763df0200ab46..fdde38903ebcd5 100644
|
|
--- a/drivers/nvme/host/pci.c
|
|
+++ b/drivers/nvme/host/pci.c
|
|
@@ -3377,7 +3377,7 @@ static pci_ers_result_t nvme_slot_reset(struct pci_dev *pdev)
|
|
|
|
dev_info(dev->ctrl.device, "restart after slot reset\n");
|
|
pci_restore_state(pdev);
|
|
- if (!nvme_try_sched_reset(&dev->ctrl))
|
|
+ if (nvme_try_sched_reset(&dev->ctrl))
|
|
nvme_unquiesce_io_queues(&dev->ctrl);
|
|
return PCI_ERS_RESULT_RECOVERED;
|
|
}
|
|
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
|
|
index 84db7f4f861cb1..5b76670f34be29 100644
|
|
--- a/drivers/nvme/host/tcp.c
|
|
+++ b/drivers/nvme/host/tcp.c
|
|
@@ -1710,7 +1710,7 @@ static void __nvme_tcp_stop_queue(struct nvme_tcp_queue *queue)
|
|
cancel_work_sync(&queue->io_work);
|
|
}
|
|
|
|
-static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid)
|
|
+static void nvme_tcp_stop_queue_nowait(struct nvme_ctrl *nctrl, int qid)
|
|
{
|
|
struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
|
|
struct nvme_tcp_queue *queue = &ctrl->queues[qid];
|
|
@@ -1724,6 +1724,31 @@ static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid)
|
|
mutex_unlock(&queue->queue_lock);
|
|
}
|
|
|
|
+static void nvme_tcp_wait_queue(struct nvme_ctrl *nctrl, int qid)
|
|
+{
|
|
+ struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
|
|
+ struct nvme_tcp_queue *queue = &ctrl->queues[qid];
|
|
+ int timeout = 100;
|
|
+
|
|
+ while (timeout > 0) {
|
|
+ if (!test_bit(NVME_TCP_Q_ALLOCATED, &queue->flags) ||
|
|
+ !sk_wmem_alloc_get(queue->sock->sk))
|
|
+ return;
|
|
+ msleep(2);
|
|
+ timeout -= 2;
|
|
+ }
|
|
+ dev_warn(nctrl->device,
|
|
+ "qid %d: timeout draining sock wmem allocation expired\n",
|
|
+ qid);
|
|
+}
|
|
+
|
|
+static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid)
|
|
+{
|
|
+ nvme_tcp_stop_queue_nowait(nctrl, qid);
|
|
+ nvme_tcp_wait_queue(nctrl, qid);
|
|
+}
|
|
+
|
|
+
|
|
static void nvme_tcp_setup_sock_ops(struct nvme_tcp_queue *queue)
|
|
{
|
|
write_lock_bh(&queue->sock->sk->sk_callback_lock);
|
|
@@ -1790,7 +1815,9 @@ static void nvme_tcp_stop_io_queues(struct nvme_ctrl *ctrl)
|
|
int i;
|
|
|
|
for (i = 1; i < ctrl->queue_count; i++)
|
|
- nvme_tcp_stop_queue(ctrl, i);
|
|
+ nvme_tcp_stop_queue_nowait(ctrl, i);
|
|
+ for (i = 1; i < ctrl->queue_count; i++)
|
|
+ nvme_tcp_wait_queue(ctrl, i);
|
|
}
|
|
|
|
static int nvme_tcp_start_io_queues(struct nvme_ctrl *ctrl,
|
|
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
|
|
index 822a750b064b27..cedfbd4258631d 100644
|
|
--- a/drivers/pci/controller/dwc/pci-imx6.c
|
|
+++ b/drivers/pci/controller/dwc/pci-imx6.c
|
|
@@ -1283,7 +1283,8 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
|
case IMX8MQ_EP:
|
|
if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR)
|
|
imx6_pcie->controller_id = 1;
|
|
-
|
|
+ fallthrough;
|
|
+ case IMX7D:
|
|
imx6_pcie->pciephy_reset = devm_reset_control_get_exclusive(dev,
|
|
"pciephy");
|
|
if (IS_ERR(imx6_pcie->pciephy_reset)) {
|
|
diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c
|
|
index 70907e8f3ea96d..946a546cd9dd01 100644
|
|
--- a/drivers/platform/x86/amd/pmc/pmc.c
|
|
+++ b/drivers/platform/x86/amd/pmc/pmc.c
|
|
@@ -823,10 +823,9 @@ static void amd_pmc_s2idle_check(void)
|
|
struct smu_metrics table;
|
|
int rc;
|
|
|
|
- /* CZN: Ensure that future s0i3 entry attempts at least 10ms passed */
|
|
- if (pdev->cpu_id == AMD_CPU_ID_CZN && !get_metrics_table(pdev, &table) &&
|
|
- table.s0i3_last_entry_status)
|
|
- usleep_range(10000, 20000);
|
|
+ /* Avoid triggering OVP */
|
|
+ if (!get_metrics_table(pdev, &table) && table.s0i3_last_entry_status)
|
|
+ msleep(2500);
|
|
|
|
/* Dump the IdleMask before we add to the STB */
|
|
amd_pmc_idlemask_read(pdev, pdev->dev, NULL);
|
|
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c
|
|
index a3b25253b6fdeb..2c9c5cc7d854ed 100644
|
|
--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c
|
|
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c
|
|
@@ -121,15 +121,13 @@ static int uncore_event_cpu_online(unsigned int cpu)
|
|
{
|
|
struct uncore_data *data;
|
|
int target;
|
|
+ int ret;
|
|
|
|
/* Check if there is an online cpu in the package for uncore MSR */
|
|
target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu));
|
|
if (target < nr_cpu_ids)
|
|
return 0;
|
|
|
|
- /* Use this CPU on this die as a control CPU */
|
|
- cpumask_set_cpu(cpu, &uncore_cpu_mask);
|
|
-
|
|
data = uncore_get_instance(cpu);
|
|
if (!data)
|
|
return 0;
|
|
@@ -138,7 +136,14 @@ static int uncore_event_cpu_online(unsigned int cpu)
|
|
data->die_id = topology_die_id(cpu);
|
|
data->domain_id = UNCORE_DOMAIN_ID_INVALID;
|
|
|
|
- return uncore_freq_add_entry(data, cpu);
|
|
+ ret = uncore_freq_add_entry(data, cpu);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /* Use this CPU on this die as a control CPU */
|
|
+ cpumask_set_cpu(cpu, &uncore_cpu_mask);
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
static int uncore_event_cpu_offline(unsigned int cpu)
|
|
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
|
|
index 460f232dad508b..147d7052794f77 100644
|
|
--- a/drivers/spi/spi-tegra114.c
|
|
+++ b/drivers/spi/spi-tegra114.c
|
|
@@ -728,9 +728,9 @@ static int tegra_spi_set_hw_cs_timing(struct spi_device *spi)
|
|
u32 inactive_cycles;
|
|
u8 cs_state;
|
|
|
|
- if (setup->unit != SPI_DELAY_UNIT_SCK ||
|
|
- hold->unit != SPI_DELAY_UNIT_SCK ||
|
|
- inactive->unit != SPI_DELAY_UNIT_SCK) {
|
|
+ if ((setup->unit && setup->unit != SPI_DELAY_UNIT_SCK) ||
|
|
+ (hold->unit && hold->unit != SPI_DELAY_UNIT_SCK) ||
|
|
+ (inactive->unit && inactive->unit != SPI_DELAY_UNIT_SCK)) {
|
|
dev_err(&spi->dev,
|
|
"Invalid delay unit %d, should be SPI_DELAY_UNIT_SCK\n",
|
|
SPI_DELAY_UNIT_SCK);
|
|
diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
|
|
index 99baa60ef50fe9..15a8402ee8a17a 100644
|
|
--- a/drivers/usb/host/xhci-debugfs.c
|
|
+++ b/drivers/usb/host/xhci-debugfs.c
|
|
@@ -693,7 +693,7 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
|
|
"command-ring",
|
|
xhci->debugfs_root);
|
|
|
|
- xhci_debugfs_create_ring_dir(xhci, &xhci->interrupter->event_ring,
|
|
+ xhci_debugfs_create_ring_dir(xhci, &xhci->interrupters[0]->event_ring,
|
|
"event-ring",
|
|
xhci->debugfs_root);
|
|
|
|
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
|
|
index 0df5d807a77e8f..a2b6a922077ee3 100644
|
|
--- a/drivers/usb/host/xhci-hub.c
|
|
+++ b/drivers/usb/host/xhci-hub.c
|
|
@@ -1880,9 +1880,10 @@ int xhci_bus_resume(struct usb_hcd *hcd)
|
|
int slot_id;
|
|
int sret;
|
|
u32 next_state;
|
|
- u32 temp, portsc;
|
|
+ u32 portsc;
|
|
struct xhci_hub *rhub;
|
|
struct xhci_port **ports;
|
|
+ bool disabled_irq = false;
|
|
|
|
rhub = xhci_get_rhub(hcd);
|
|
ports = rhub->ports;
|
|
@@ -1898,17 +1899,20 @@ int xhci_bus_resume(struct usb_hcd *hcd)
|
|
return -ESHUTDOWN;
|
|
}
|
|
|
|
- /* delay the irqs */
|
|
- temp = readl(&xhci->op_regs->command);
|
|
- temp &= ~CMD_EIE;
|
|
- writel(temp, &xhci->op_regs->command);
|
|
-
|
|
/* bus specific resume for ports we suspended at bus_suspend */
|
|
- if (hcd->speed >= HCD_USB3)
|
|
+ if (hcd->speed >= HCD_USB3) {
|
|
next_state = XDEV_U0;
|
|
- else
|
|
+ } else {
|
|
next_state = XDEV_RESUME;
|
|
-
|
|
+ if (bus_state->bus_suspended) {
|
|
+ /*
|
|
+ * prevent port event interrupts from interfering
|
|
+ * with usb2 port resume process
|
|
+ */
|
|
+ xhci_disable_interrupter(xhci->interrupters[0]);
|
|
+ disabled_irq = true;
|
|
+ }
|
|
+ }
|
|
port_index = max_ports;
|
|
while (port_index--) {
|
|
portsc = readl(ports[port_index]->addr);
|
|
@@ -1977,11 +1981,9 @@ int xhci_bus_resume(struct usb_hcd *hcd)
|
|
(void) readl(&xhci->op_regs->command);
|
|
|
|
bus_state->next_statechange = jiffies + msecs_to_jiffies(5);
|
|
- /* re-enable irqs */
|
|
- temp = readl(&xhci->op_regs->command);
|
|
- temp |= CMD_EIE;
|
|
- writel(temp, &xhci->op_regs->command);
|
|
- temp = readl(&xhci->op_regs->command);
|
|
+ /* re-enable interrupter */
|
|
+ if (disabled_irq)
|
|
+ xhci_enable_interrupter(xhci->interrupters[0]);
|
|
|
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
|
return 0;
|
|
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
|
|
index fbc486546b8533..22cca89efbfd72 100644
|
|
--- a/drivers/usb/host/xhci-mem.c
|
|
+++ b/drivers/usb/host/xhci-mem.c
|
|
@@ -29,6 +29,7 @@
|
|
static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
|
|
unsigned int cycle_state,
|
|
unsigned int max_packet,
|
|
+ unsigned int num,
|
|
gfp_t flags)
|
|
{
|
|
struct xhci_segment *seg;
|
|
@@ -60,6 +61,7 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
|
|
for (i = 0; i < TRBS_PER_SEGMENT; i++)
|
|
seg->trbs[i].link.control = cpu_to_le32(TRB_CYCLE);
|
|
}
|
|
+ seg->num = num;
|
|
seg->dma = dma;
|
|
seg->next = NULL;
|
|
|
|
@@ -316,6 +318,7 @@ void xhci_initialize_ring_info(struct xhci_ring *ring,
|
|
*/
|
|
ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
|
|
}
|
|
+EXPORT_SYMBOL_GPL(xhci_initialize_ring_info);
|
|
|
|
/* Allocate segments and link them for a ring */
|
|
static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
|
|
@@ -324,6 +327,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
|
|
enum xhci_ring_type type, unsigned int max_packet, gfp_t flags)
|
|
{
|
|
struct xhci_segment *prev;
|
|
+ unsigned int num = 0;
|
|
bool chain_links;
|
|
|
|
/* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */
|
|
@@ -331,16 +335,17 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
|
|
(type == TYPE_ISOC &&
|
|
(xhci->quirks & XHCI_AMD_0x96_HOST)));
|
|
|
|
- prev = xhci_segment_alloc(xhci, cycle_state, max_packet, flags);
|
|
+ prev = xhci_segment_alloc(xhci, cycle_state, max_packet, num, flags);
|
|
if (!prev)
|
|
return -ENOMEM;
|
|
- num_segs--;
|
|
+ num++;
|
|
|
|
*first = prev;
|
|
- while (num_segs > 0) {
|
|
+ while (num < num_segs) {
|
|
struct xhci_segment *next;
|
|
|
|
- next = xhci_segment_alloc(xhci, cycle_state, max_packet, flags);
|
|
+ next = xhci_segment_alloc(xhci, cycle_state, max_packet, num,
|
|
+ flags);
|
|
if (!next) {
|
|
prev = *first;
|
|
while (prev) {
|
|
@@ -353,7 +358,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
|
|
xhci_link_segments(prev, next, type, chain_links);
|
|
|
|
prev = next;
|
|
- num_segs--;
|
|
+ num++;
|
|
}
|
|
xhci_link_segments(prev, *first, type, chain_links);
|
|
*last = prev;
|
|
@@ -1799,23 +1804,13 @@ int xhci_alloc_erst(struct xhci_hcd *xhci,
|
|
}
|
|
|
|
static void
|
|
-xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
|
+xhci_remove_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
|
{
|
|
- struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
|
- size_t erst_size;
|
|
- u64 tmp64;
|
|
u32 tmp;
|
|
|
|
if (!ir)
|
|
return;
|
|
|
|
- erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries;
|
|
- if (ir->erst.entries)
|
|
- dma_free_coherent(dev, erst_size,
|
|
- ir->erst.entries,
|
|
- ir->erst.erst_dma_addr);
|
|
- ir->erst.entries = NULL;
|
|
-
|
|
/*
|
|
* Clean out interrupter registers except ERSTBA. Clearing either the
|
|
* low or high 32 bits of ERSTBA immediately causes the controller to
|
|
@@ -1826,19 +1821,60 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
|
tmp &= ERST_SIZE_MASK;
|
|
writel(tmp, &ir->ir_set->erst_size);
|
|
|
|
- tmp64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
|
|
- tmp64 &= (u64) ERST_PTR_MASK;
|
|
- xhci_write_64(xhci, tmp64, &ir->ir_set->erst_dequeue);
|
|
+ xhci_write_64(xhci, ERST_EHB, &ir->ir_set->erst_dequeue);
|
|
}
|
|
+}
|
|
|
|
- /* free interrrupter event ring */
|
|
+static void
|
|
+xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
|
+{
|
|
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
|
+ size_t erst_size;
|
|
+
|
|
+ if (!ir)
|
|
+ return;
|
|
+
|
|
+ erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries;
|
|
+ if (ir->erst.entries)
|
|
+ dma_free_coherent(dev, erst_size,
|
|
+ ir->erst.entries,
|
|
+ ir->erst.erst_dma_addr);
|
|
+ ir->erst.entries = NULL;
|
|
+
|
|
+ /* free interrupter event ring */
|
|
if (ir->event_ring)
|
|
xhci_ring_free(xhci, ir->event_ring);
|
|
+
|
|
ir->event_ring = NULL;
|
|
|
|
kfree(ir);
|
|
}
|
|
|
|
+void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir)
|
|
+{
|
|
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
|
+ unsigned int intr_num;
|
|
+
|
|
+ spin_lock_irq(&xhci->lock);
|
|
+
|
|
+ /* interrupter 0 is primary interrupter, don't touch it */
|
|
+ if (!ir || !ir->intr_num || ir->intr_num >= xhci->max_interrupters) {
|
|
+ xhci_dbg(xhci, "Invalid secondary interrupter, can't remove\n");
|
|
+ spin_unlock_irq(&xhci->lock);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ intr_num = ir->intr_num;
|
|
+
|
|
+ xhci_remove_interrupter(xhci, ir);
|
|
+ xhci->interrupters[intr_num] = NULL;
|
|
+
|
|
+ spin_unlock_irq(&xhci->lock);
|
|
+
|
|
+ xhci_free_interrupter(xhci, ir);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter);
|
|
+
|
|
void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
|
{
|
|
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
|
@@ -1846,9 +1882,14 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
|
|
|
cancel_delayed_work_sync(&xhci->cmd_timer);
|
|
|
|
- xhci_free_interrupter(xhci, xhci->interrupter);
|
|
- xhci->interrupter = NULL;
|
|
- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring");
|
|
+ for (i = 0; xhci->interrupters && i < xhci->max_interrupters; i++) {
|
|
+ if (xhci->interrupters[i]) {
|
|
+ xhci_remove_interrupter(xhci, xhci->interrupters[i]);
|
|
+ xhci_free_interrupter(xhci, xhci->interrupters[i]);
|
|
+ xhci->interrupters[i] = NULL;
|
|
+ }
|
|
+ }
|
|
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed interrupters");
|
|
|
|
if (xhci->cmd_ring)
|
|
xhci_ring_free(xhci, xhci->cmd_ring);
|
|
@@ -1918,6 +1959,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
|
for (i = 0; i < xhci->num_port_caps; i++)
|
|
kfree(xhci->port_caps[i].psi);
|
|
kfree(xhci->port_caps);
|
|
+ kfree(xhci->interrupters);
|
|
xhci->num_port_caps = 0;
|
|
|
|
xhci->usb2_rhub.ports = NULL;
|
|
@@ -1926,6 +1968,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
|
xhci->rh_bw = NULL;
|
|
xhci->ext_caps = NULL;
|
|
xhci->port_caps = NULL;
|
|
+ xhci->interrupters = NULL;
|
|
|
|
xhci->page_size = 0;
|
|
xhci->page_shift = 0;
|
|
@@ -1935,7 +1978,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
|
|
|
static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
|
{
|
|
- u64 temp;
|
|
dma_addr_t deq;
|
|
|
|
deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
|
|
@@ -1943,15 +1985,12 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter
|
|
if (!deq)
|
|
xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr.\n");
|
|
/* Update HC event ring dequeue pointer */
|
|
- temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
|
|
- temp &= ERST_PTR_MASK;
|
|
/* Don't clear the EHB bit (which is RW1C) because
|
|
* there might be more events to service.
|
|
*/
|
|
- temp &= ~ERST_EHB;
|
|
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
|
"// Write event ring dequeue pointer, preserving EHB bit");
|
|
- xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
|
|
+ xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK),
|
|
&ir->ir_set->erst_dequeue);
|
|
}
|
|
|
|
@@ -2236,18 +2275,24 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
|
|
}
|
|
|
|
static struct xhci_interrupter *
|
|
-xhci_alloc_interrupter(struct xhci_hcd *xhci, gfp_t flags)
|
|
+xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int segs, gfp_t flags)
|
|
{
|
|
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
|
struct xhci_interrupter *ir;
|
|
+ unsigned int max_segs;
|
|
int ret;
|
|
|
|
+ if (!segs)
|
|
+ segs = ERST_DEFAULT_SEGS;
|
|
+
|
|
+ max_segs = BIT(HCS_ERST_MAX(xhci->hcs_params2));
|
|
+ segs = min(segs, max_segs);
|
|
+
|
|
ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
|
|
if (!ir)
|
|
return NULL;
|
|
|
|
- ir->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
|
|
- 0, flags);
|
|
+ ir->event_ring = xhci_ring_alloc(xhci, segs, 1, TYPE_EVENT, 0, flags);
|
|
if (!ir->event_ring) {
|
|
xhci_warn(xhci, "Failed to allocate interrupter event ring\n");
|
|
kfree(ir);
|
|
@@ -2278,12 +2323,19 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
|
|
return -EINVAL;
|
|
}
|
|
|
|
+ if (xhci->interrupters[intr_num]) {
|
|
+ xhci_warn(xhci, "Interrupter %d\n already set up", intr_num);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ xhci->interrupters[intr_num] = ir;
|
|
+ ir->intr_num = intr_num;
|
|
ir->ir_set = &xhci->run_regs->ir_set[intr_num];
|
|
|
|
/* set ERST count with the number of entries in the segment table */
|
|
erst_size = readl(&ir->ir_set->erst_size);
|
|
erst_size &= ERST_SIZE_MASK;
|
|
- erst_size |= ERST_NUM_SEGS;
|
|
+ erst_size |= ir->event_ring->num_segs;
|
|
writel(erst_size, &ir->ir_set->erst_size);
|
|
|
|
erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
|
|
@@ -2300,10 +2352,58 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
|
|
return 0;
|
|
}
|
|
|
|
+struct xhci_interrupter *
|
|
+xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs,
|
|
+ u32 imod_interval)
|
|
+{
|
|
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
|
+ struct xhci_interrupter *ir;
|
|
+ unsigned int i;
|
|
+ int err = -ENOSPC;
|
|
+
|
|
+ if (!xhci->interrupters || xhci->max_interrupters <= 1)
|
|
+ return NULL;
|
|
+
|
|
+ ir = xhci_alloc_interrupter(xhci, segs, GFP_KERNEL);
|
|
+ if (!ir)
|
|
+ return NULL;
|
|
+
|
|
+ spin_lock_irq(&xhci->lock);
|
|
+
|
|
+ /* Find available secondary interrupter, interrupter 0 is reserved for primary */
|
|
+ for (i = 1; i < xhci->max_interrupters; i++) {
|
|
+ if (xhci->interrupters[i] == NULL) {
|
|
+ err = xhci_add_interrupter(xhci, ir, i);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ spin_unlock_irq(&xhci->lock);
|
|
+
|
|
+ if (err) {
|
|
+ xhci_warn(xhci, "Failed to add secondary interrupter, max interrupters %d\n",
|
|
+ xhci->max_interrupters);
|
|
+ xhci_free_interrupter(xhci, ir);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ err = xhci_set_interrupter_moderation(ir, imod_interval);
|
|
+ if (err)
|
|
+ xhci_warn(xhci, "Failed to set interrupter %d moderation to %uns\n",
|
|
+ i, imod_interval);
|
|
+
|
|
+ xhci_dbg(xhci, "Add secondary interrupter %d, max interrupters %d\n",
|
|
+ i, xhci->max_interrupters);
|
|
+
|
|
+ return ir;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(xhci_create_secondary_interrupter);
|
|
+
|
|
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
|
{
|
|
- dma_addr_t dma;
|
|
+ struct xhci_interrupter *ir;
|
|
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
|
+ dma_addr_t dma;
|
|
unsigned int val, val2;
|
|
u64 val_64;
|
|
u32 page_size, temp;
|
|
@@ -2428,11 +2528,14 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
|
/* Allocate and set up primary interrupter 0 with an event ring. */
|
|
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
|
"Allocating primary event ring");
|
|
- xhci->interrupter = xhci_alloc_interrupter(xhci, flags);
|
|
- if (!xhci->interrupter)
|
|
+ xhci->interrupters = kcalloc_node(xhci->max_interrupters, sizeof(*xhci->interrupters),
|
|
+ flags, dev_to_node(dev));
|
|
+
|
|
+ ir = xhci_alloc_interrupter(xhci, 0, flags);
|
|
+ if (!ir)
|
|
goto fail;
|
|
|
|
- if (xhci_add_interrupter(xhci, xhci->interrupter, 0))
|
|
+ if (xhci_add_interrupter(xhci, ir, 0))
|
|
goto fail;
|
|
|
|
xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
|
|
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
|
|
index cb944396294516..5a53280fa2edfd 100644
|
|
--- a/drivers/usb/host/xhci-ring.c
|
|
+++ b/drivers/usb/host/xhci-ring.c
|
|
@@ -3167,7 +3167,7 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
|
|
return;
|
|
|
|
/* Update HC event ring dequeue pointer */
|
|
- temp_64 &= ERST_DESI_MASK;
|
|
+ temp_64 = ir->event_ring->deq_seg->num & ERST_DESI_MASK;
|
|
temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK);
|
|
}
|
|
|
|
@@ -3225,7 +3225,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
|
writel(status, &xhci->op_regs->status);
|
|
|
|
/* This is the handler of the primary interrupter */
|
|
- ir = xhci->interrupter;
|
|
+ ir = xhci->interrupters[0];
|
|
if (!hcd->msi_enabled) {
|
|
u32 irq_pending;
|
|
irq_pending = readl(&ir->ir_set->irq_pending);
|
|
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
|
|
index 70e6c240a5409f..ce38cd2435c8c3 100644
|
|
--- a/drivers/usb/host/xhci.c
|
|
+++ b/drivers/usb/host/xhci.c
|
|
@@ -297,7 +297,7 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci)
|
|
xhci_info(xhci, "Fault detected\n");
|
|
}
|
|
|
|
-static int xhci_enable_interrupter(struct xhci_interrupter *ir)
|
|
+int xhci_enable_interrupter(struct xhci_interrupter *ir)
|
|
{
|
|
u32 iman;
|
|
|
|
@@ -310,7 +310,7 @@ static int xhci_enable_interrupter(struct xhci_interrupter *ir)
|
|
return 0;
|
|
}
|
|
|
|
-static int xhci_disable_interrupter(struct xhci_interrupter *ir)
|
|
+int xhci_disable_interrupter(struct xhci_interrupter *ir)
|
|
{
|
|
u32 iman;
|
|
|
|
@@ -323,6 +323,23 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir)
|
|
return 0;
|
|
}
|
|
|
|
+/* interrupt moderation interval imod_interval in nanoseconds */
|
|
+int xhci_set_interrupter_moderation(struct xhci_interrupter *ir,
|
|
+ u32 imod_interval)
|
|
+{
|
|
+ u32 imod;
|
|
+
|
|
+ if (!ir || !ir->ir_set || imod_interval > U16_MAX * 250)
|
|
+ return -EINVAL;
|
|
+
|
|
+ imod = readl(&ir->ir_set->irq_control);
|
|
+ imod &= ~ER_IRQ_INTERVAL_MASK;
|
|
+ imod |= (imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
|
|
+ writel(imod, &ir->ir_set->irq_control);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static void compliance_mode_recovery(struct timer_list *t)
|
|
{
|
|
struct xhci_hcd *xhci;
|
|
@@ -457,7 +474,7 @@ static int xhci_init(struct usb_hcd *hcd)
|
|
|
|
static int xhci_run_finished(struct xhci_hcd *xhci)
|
|
{
|
|
- struct xhci_interrupter *ir = xhci->interrupter;
|
|
+ struct xhci_interrupter *ir = xhci->interrupters[0];
|
|
unsigned long flags;
|
|
u32 temp;
|
|
|
|
@@ -505,11 +522,10 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
|
|
*/
|
|
int xhci_run(struct usb_hcd *hcd)
|
|
{
|
|
- u32 temp;
|
|
u64 temp_64;
|
|
int ret;
|
|
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
|
- struct xhci_interrupter *ir = xhci->interrupter;
|
|
+ struct xhci_interrupter *ir = xhci->interrupters[0];
|
|
/* Start the xHCI host controller running only after the USB 2.0 roothub
|
|
* is setup.
|
|
*/
|
|
@@ -525,12 +541,7 @@ int xhci_run(struct usb_hcd *hcd)
|
|
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
|
"ERST deq = 64'h%0lx", (long unsigned int) temp_64);
|
|
|
|
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
|
- "// Set the interrupt modulation register");
|
|
- temp = readl(&ir->ir_set->irq_control);
|
|
- temp &= ~ER_IRQ_INTERVAL_MASK;
|
|
- temp |= (xhci->imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
|
|
- writel(temp, &ir->ir_set->irq_control);
|
|
+ xhci_set_interrupter_moderation(ir, xhci->imod_interval);
|
|
|
|
if (xhci->quirks & XHCI_NEC_HOST) {
|
|
struct xhci_command *command;
|
|
@@ -573,7 +584,7 @@ void xhci_stop(struct usb_hcd *hcd)
|
|
{
|
|
u32 temp;
|
|
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
|
- struct xhci_interrupter *ir = xhci->interrupter;
|
|
+ struct xhci_interrupter *ir = xhci->interrupters[0];
|
|
|
|
mutex_lock(&xhci->mutex);
|
|
|
|
@@ -669,36 +680,51 @@ EXPORT_SYMBOL_GPL(xhci_shutdown);
|
|
#ifdef CONFIG_PM
|
|
static void xhci_save_registers(struct xhci_hcd *xhci)
|
|
{
|
|
- struct xhci_interrupter *ir = xhci->interrupter;
|
|
+ struct xhci_interrupter *ir;
|
|
+ unsigned int i;
|
|
|
|
xhci->s3.command = readl(&xhci->op_regs->command);
|
|
xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification);
|
|
xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
|
|
xhci->s3.config_reg = readl(&xhci->op_regs->config_reg);
|
|
|
|
- if (!ir)
|
|
- return;
|
|
+ /* save both primary and all secondary interrupters */
|
|
+ /* fixme, shold we lock to prevent race with remove secondary interrupter? */
|
|
+ for (i = 0; i < xhci->max_interrupters; i++) {
|
|
+ ir = xhci->interrupters[i];
|
|
+ if (!ir)
|
|
+ continue;
|
|
|
|
- ir->s3_erst_size = readl(&ir->ir_set->erst_size);
|
|
- ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
|
|
- ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
|
|
- ir->s3_irq_pending = readl(&ir->ir_set->irq_pending);
|
|
- ir->s3_irq_control = readl(&ir->ir_set->irq_control);
|
|
+ ir->s3_erst_size = readl(&ir->ir_set->erst_size);
|
|
+ ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
|
|
+ ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
|
|
+ ir->s3_irq_pending = readl(&ir->ir_set->irq_pending);
|
|
+ ir->s3_irq_control = readl(&ir->ir_set->irq_control);
|
|
+ }
|
|
}
|
|
|
|
static void xhci_restore_registers(struct xhci_hcd *xhci)
|
|
{
|
|
- struct xhci_interrupter *ir = xhci->interrupter;
|
|
+ struct xhci_interrupter *ir;
|
|
+ unsigned int i;
|
|
|
|
writel(xhci->s3.command, &xhci->op_regs->command);
|
|
writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
|
|
xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
|
|
writel(xhci->s3.config_reg, &xhci->op_regs->config_reg);
|
|
- writel(ir->s3_erst_size, &ir->ir_set->erst_size);
|
|
- xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base);
|
|
- xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue);
|
|
- writel(ir->s3_irq_pending, &ir->ir_set->irq_pending);
|
|
- writel(ir->s3_irq_control, &ir->ir_set->irq_control);
|
|
+
|
|
+ /* FIXME should we lock to protect against freeing of interrupters */
|
|
+ for (i = 0; i < xhci->max_interrupters; i++) {
|
|
+ ir = xhci->interrupters[i];
|
|
+ if (!ir)
|
|
+ continue;
|
|
+
|
|
+ writel(ir->s3_erst_size, &ir->ir_set->erst_size);
|
|
+ xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base);
|
|
+ xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue);
|
|
+ writel(ir->s3_irq_pending, &ir->ir_set->irq_pending);
|
|
+ writel(ir->s3_irq_control, &ir->ir_set->irq_control);
|
|
+ }
|
|
}
|
|
|
|
static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
|
|
@@ -1061,7 +1087,7 @@ int xhci_resume(struct xhci_hcd *xhci, pm_message_t msg)
|
|
xhci_dbg(xhci, "// Disabling event ring interrupts\n");
|
|
temp = readl(&xhci->op_regs->status);
|
|
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
|
|
- xhci_disable_interrupter(xhci->interrupter);
|
|
+ xhci_disable_interrupter(xhci->interrupters[0]);
|
|
|
|
xhci_dbg(xhci, "cleaning up memory\n");
|
|
xhci_mem_cleanup(xhci);
|
|
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
|
|
index df87e8bcb7d246..74bdd035d756a4 100644
|
|
--- a/drivers/usb/host/xhci.h
|
|
+++ b/drivers/usb/host/xhci.h
|
|
@@ -1293,6 +1293,7 @@ struct xhci_segment {
|
|
union xhci_trb *trbs;
|
|
/* private to HCD */
|
|
struct xhci_segment *next;
|
|
+ unsigned int num;
|
|
dma_addr_t dma;
|
|
/* Max packet sized bounce buffer for td-fragmant alignment */
|
|
dma_addr_t bounce_dma;
|
|
@@ -1422,12 +1423,8 @@ struct urb_priv {
|
|
struct xhci_td td[];
|
|
};
|
|
|
|
-/*
|
|
- * Each segment table entry is 4*32bits long. 1K seems like an ok size:
|
|
- * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
|
|
- * meaning 64 ring segments.
|
|
- * Initial allocated size of the ERST, in number of entries */
|
|
-#define ERST_NUM_SEGS 1
|
|
+/* Number of Event Ring segments to allocate, when amount is not specified. (spec allows 32k) */
|
|
+#define ERST_DEFAULT_SEGS 2
|
|
/* Poll every 60 seconds */
|
|
#define POLL_TIMEOUT 60
|
|
/* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */
|
|
@@ -1552,7 +1549,7 @@ struct xhci_hcd {
|
|
struct reset_control *reset;
|
|
/* data structures */
|
|
struct xhci_device_context_array *dcbaa;
|
|
- struct xhci_interrupter *interrupter;
|
|
+ struct xhci_interrupter **interrupters;
|
|
struct xhci_ring *cmd_ring;
|
|
unsigned int cmd_ring_state;
|
|
#define CMD_RING_STATE_RUNNING (1 << 0)
|
|
@@ -1869,6 +1866,11 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
|
|
int type, gfp_t flags);
|
|
void xhci_free_container_ctx(struct xhci_hcd *xhci,
|
|
struct xhci_container_ctx *ctx);
|
|
+struct xhci_interrupter *
|
|
+xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs,
|
|
+ u32 imod_interval);
|
|
+void xhci_remove_secondary_interrupter(struct usb_hcd
|
|
+ *hcd, struct xhci_interrupter *ir);
|
|
|
|
/* xHCI host controller glue */
|
|
typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
|
|
@@ -1904,6 +1906,10 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci,
|
|
struct xhci_virt_device *virt_dev,
|
|
struct usb_device *hdev,
|
|
struct usb_tt *tt, gfp_t mem_flags);
|
|
+int xhci_set_interrupter_moderation(struct xhci_interrupter *ir,
|
|
+ u32 imod_interval);
|
|
+int xhci_enable_interrupter(struct xhci_interrupter *ir);
|
|
+int xhci_disable_interrupter(struct xhci_interrupter *ir);
|
|
|
|
/* xHCI ring, segment, TRB, and TD functions */
|
|
dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
|
|
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
|
|
index 11c4d69177f0ca..48d2579236729d 100644
|
|
--- a/fs/btrfs/inode.c
|
|
+++ b/fs/btrfs/inode.c
|
|
@@ -2058,12 +2058,13 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
|
|
|
|
/*
|
|
* If the found extent starts after requested offset, then
|
|
- * adjust extent_end to be right before this extent begins
|
|
+ * adjust cur_offset to be right before this extent begins.
|
|
*/
|
|
if (found_key.offset > cur_offset) {
|
|
- extent_end = found_key.offset;
|
|
- extent_type = 0;
|
|
- goto must_cow;
|
|
+ if (cow_start == (u64)-1)
|
|
+ cow_start = cur_offset;
|
|
+ cur_offset = found_key.offset;
|
|
+ goto next_slot;
|
|
}
|
|
|
|
/*
|
|
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
|
|
index 0af3535e08f308..4536b6fcfa0256 100644
|
|
--- a/fs/smb/client/smb2pdu.c
|
|
+++ b/fs/smb/client/smb2pdu.c
|
|
@@ -2932,6 +2932,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
|
|
req->CreateContextsOffset = cpu_to_le32(
|
|
sizeof(struct smb2_create_req) +
|
|
iov[1].iov_len);
|
|
+ le32_add_cpu(&req->CreateContextsLength, iov[n_iov-1].iov_len);
|
|
pc_buf = iov[n_iov-1].iov_base;
|
|
}
|
|
|
|
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
|
|
index 5345d2417c7fc9..f4b20b80af0620 100644
|
|
--- a/fs/smb/server/auth.c
|
|
+++ b/fs/smb/server/auth.c
|
|
@@ -546,7 +546,19 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
|
|
retval = -ENOMEM;
|
|
goto out;
|
|
}
|
|
- sess->user = user;
|
|
+
|
|
+ if (!sess->user) {
|
|
+ /* First successful authentication */
|
|
+ sess->user = user;
|
|
+ } else {
|
|
+ if (!ksmbd_compare_user(sess->user, user)) {
|
|
+ ksmbd_debug(AUTH, "different user tried to reuse session\n");
|
|
+ retval = -EPERM;
|
|
+ ksmbd_free_user(user);
|
|
+ goto out;
|
|
+ }
|
|
+ ksmbd_free_user(user);
|
|
+ }
|
|
|
|
memcpy(sess->sess_key, resp->payload, resp->session_key_len);
|
|
memcpy(out_blob, resp->payload + resp->session_key_len,
|
|
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
|
|
index d41d67ec5ee51a..13750a5e5ba02e 100644
|
|
--- a/fs/smb/server/smb2pdu.c
|
|
+++ b/fs/smb/server/smb2pdu.c
|
|
@@ -1599,11 +1599,6 @@ static int krb5_authenticate(struct ksmbd_work *work,
|
|
if (prev_sess_id && prev_sess_id != sess->id)
|
|
destroy_previous_session(conn, sess->user, prev_sess_id);
|
|
|
|
- if (sess->state == SMB2_SESSION_VALID) {
|
|
- ksmbd_free_user(sess->user);
|
|
- sess->user = NULL;
|
|
- }
|
|
-
|
|
retval = ksmbd_krb5_authenticate(sess, in_blob, in_len,
|
|
out_blob, &out_len);
|
|
if (retval) {
|
|
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
|
|
index 035e627f94f62d..17de12a98f858a 100644
|
|
--- a/include/linux/bpf.h
|
|
+++ b/include/linux/bpf.h
|
|
@@ -1430,6 +1430,7 @@ struct bpf_prog_aux {
|
|
bool sleepable;
|
|
bool tail_call_reachable;
|
|
bool xdp_has_frags;
|
|
+ bool changes_pkt_data;
|
|
/* BTF_KIND_FUNC_PROTO for valid attach_btf_id */
|
|
const struct btf_type *attach_func_proto;
|
|
/* function name for valid attach_btf_id */
|
|
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
|
|
index 92919d52f7e1b2..32e89758176be8 100644
|
|
--- a/include/linux/bpf_verifier.h
|
|
+++ b/include/linux/bpf_verifier.h
|
|
@@ -573,6 +573,7 @@ struct bpf_subprog_info {
|
|
bool tail_call_reachable;
|
|
bool has_ld_abs;
|
|
bool is_async_cb;
|
|
+ bool changes_pkt_data;
|
|
};
|
|
|
|
struct bpf_verifier_env;
|
|
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
|
|
index 9ca4211c063f39..184a84dd467ec7 100644
|
|
--- a/include/linux/cpufreq.h
|
|
+++ b/include/linux/cpufreq.h
|
|
@@ -787,8 +787,8 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy,
|
|
int cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data *policy);
|
|
|
|
int cpufreq_table_index_unsorted(struct cpufreq_policy *policy,
|
|
- unsigned int target_freq,
|
|
- unsigned int relation);
|
|
+ unsigned int target_freq, unsigned int min,
|
|
+ unsigned int max, unsigned int relation);
|
|
int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
|
|
unsigned int freq);
|
|
|
|
@@ -853,12 +853,12 @@ static inline int cpufreq_table_find_index_dl(struct cpufreq_policy *policy,
|
|
return best;
|
|
}
|
|
|
|
-/* Works only on sorted freq-tables */
|
|
-static inline int cpufreq_table_find_index_l(struct cpufreq_policy *policy,
|
|
- unsigned int target_freq,
|
|
- bool efficiencies)
|
|
+static inline int find_index_l(struct cpufreq_policy *policy,
|
|
+ unsigned int target_freq,
|
|
+ unsigned int min, unsigned int max,
|
|
+ bool efficiencies)
|
|
{
|
|
- target_freq = clamp_val(target_freq, policy->min, policy->max);
|
|
+ target_freq = clamp_val(target_freq, min, max);
|
|
|
|
if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
|
|
return cpufreq_table_find_index_al(policy, target_freq,
|
|
@@ -868,6 +868,14 @@ static inline int cpufreq_table_find_index_l(struct cpufreq_policy *policy,
|
|
efficiencies);
|
|
}
|
|
|
|
+/* Works only on sorted freq-tables */
|
|
+static inline int cpufreq_table_find_index_l(struct cpufreq_policy *policy,
|
|
+ unsigned int target_freq,
|
|
+ bool efficiencies)
|
|
+{
|
|
+ return find_index_l(policy, target_freq, policy->min, policy->max, efficiencies);
|
|
+}
|
|
+
|
|
/* Find highest freq at or below target in a table in ascending order */
|
|
static inline int cpufreq_table_find_index_ah(struct cpufreq_policy *policy,
|
|
unsigned int target_freq,
|
|
@@ -921,12 +929,12 @@ static inline int cpufreq_table_find_index_dh(struct cpufreq_policy *policy,
|
|
return best;
|
|
}
|
|
|
|
-/* Works only on sorted freq-tables */
|
|
-static inline int cpufreq_table_find_index_h(struct cpufreq_policy *policy,
|
|
- unsigned int target_freq,
|
|
- bool efficiencies)
|
|
+static inline int find_index_h(struct cpufreq_policy *policy,
|
|
+ unsigned int target_freq,
|
|
+ unsigned int min, unsigned int max,
|
|
+ bool efficiencies)
|
|
{
|
|
- target_freq = clamp_val(target_freq, policy->min, policy->max);
|
|
+ target_freq = clamp_val(target_freq, min, max);
|
|
|
|
if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
|
|
return cpufreq_table_find_index_ah(policy, target_freq,
|
|
@@ -936,6 +944,14 @@ static inline int cpufreq_table_find_index_h(struct cpufreq_policy *policy,
|
|
efficiencies);
|
|
}
|
|
|
|
+/* Works only on sorted freq-tables */
|
|
+static inline int cpufreq_table_find_index_h(struct cpufreq_policy *policy,
|
|
+ unsigned int target_freq,
|
|
+ bool efficiencies)
|
|
+{
|
|
+ return find_index_h(policy, target_freq, policy->min, policy->max, efficiencies);
|
|
+}
|
|
+
|
|
/* Find closest freq to target in a table in ascending order */
|
|
static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy,
|
|
unsigned int target_freq,
|
|
@@ -1006,12 +1022,12 @@ static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy,
|
|
return best;
|
|
}
|
|
|
|
-/* Works only on sorted freq-tables */
|
|
-static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy,
|
|
- unsigned int target_freq,
|
|
- bool efficiencies)
|
|
+static inline int find_index_c(struct cpufreq_policy *policy,
|
|
+ unsigned int target_freq,
|
|
+ unsigned int min, unsigned int max,
|
|
+ bool efficiencies)
|
|
{
|
|
- target_freq = clamp_val(target_freq, policy->min, policy->max);
|
|
+ target_freq = clamp_val(target_freq, min, max);
|
|
|
|
if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
|
|
return cpufreq_table_find_index_ac(policy, target_freq,
|
|
@@ -1021,7 +1037,17 @@ static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy,
|
|
efficiencies);
|
|
}
|
|
|
|
-static inline bool cpufreq_is_in_limits(struct cpufreq_policy *policy, int idx)
|
|
+/* Works only on sorted freq-tables */
|
|
+static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy,
|
|
+ unsigned int target_freq,
|
|
+ bool efficiencies)
|
|
+{
|
|
+ return find_index_c(policy, target_freq, policy->min, policy->max, efficiencies);
|
|
+}
|
|
+
|
|
+static inline bool cpufreq_is_in_limits(struct cpufreq_policy *policy,
|
|
+ unsigned int min, unsigned int max,
|
|
+ int idx)
|
|
{
|
|
unsigned int freq;
|
|
|
|
@@ -1030,11 +1056,13 @@ static inline bool cpufreq_is_in_limits(struct cpufreq_policy *policy, int idx)
|
|
|
|
freq = policy->freq_table[idx].frequency;
|
|
|
|
- return freq == clamp_val(freq, policy->min, policy->max);
|
|
+ return freq == clamp_val(freq, min, max);
|
|
}
|
|
|
|
static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
|
|
unsigned int target_freq,
|
|
+ unsigned int min,
|
|
+ unsigned int max,
|
|
unsigned int relation)
|
|
{
|
|
bool efficiencies = policy->efficiencies_available &&
|
|
@@ -1045,29 +1073,26 @@ static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
|
|
relation &= ~CPUFREQ_RELATION_E;
|
|
|
|
if (unlikely(policy->freq_table_sorted == CPUFREQ_TABLE_UNSORTED))
|
|
- return cpufreq_table_index_unsorted(policy, target_freq,
|
|
- relation);
|
|
+ return cpufreq_table_index_unsorted(policy, target_freq, min,
|
|
+ max, relation);
|
|
retry:
|
|
switch (relation) {
|
|
case CPUFREQ_RELATION_L:
|
|
- idx = cpufreq_table_find_index_l(policy, target_freq,
|
|
- efficiencies);
|
|
+ idx = find_index_l(policy, target_freq, min, max, efficiencies);
|
|
break;
|
|
case CPUFREQ_RELATION_H:
|
|
- idx = cpufreq_table_find_index_h(policy, target_freq,
|
|
- efficiencies);
|
|
+ idx = find_index_h(policy, target_freq, min, max, efficiencies);
|
|
break;
|
|
case CPUFREQ_RELATION_C:
|
|
- idx = cpufreq_table_find_index_c(policy, target_freq,
|
|
- efficiencies);
|
|
+ idx = find_index_c(policy, target_freq, min, max, efficiencies);
|
|
break;
|
|
default:
|
|
WARN_ON_ONCE(1);
|
|
return 0;
|
|
}
|
|
|
|
- /* Limit frequency index to honor policy->min/max */
|
|
- if (!cpufreq_is_in_limits(policy, idx) && efficiencies) {
|
|
+ /* Limit frequency index to honor min and max */
|
|
+ if (!cpufreq_is_in_limits(policy, min, max, idx) && efficiencies) {
|
|
efficiencies = false;
|
|
goto retry;
|
|
}
|
|
diff --git a/include/linux/filter.h b/include/linux/filter.h
|
|
index 5090e940ba3e46..adf65eacade062 100644
|
|
--- a/include/linux/filter.h
|
|
+++ b/include/linux/filter.h
|
|
@@ -915,7 +915,7 @@ bool bpf_jit_needs_zext(void);
|
|
bool bpf_jit_supports_subprog_tailcalls(void);
|
|
bool bpf_jit_supports_kfunc_call(void);
|
|
bool bpf_jit_supports_far_kfunc_call(void);
|
|
-bool bpf_helper_changes_pkt_data(void *func);
|
|
+bool bpf_helper_changes_pkt_data(enum bpf_func_id func_id);
|
|
|
|
static inline bool bpf_dump_raw_ok(const struct cred *cred)
|
|
{
|
|
diff --git a/include/linux/module.h b/include/linux/module.h
|
|
index a98e188cf37b81..f2a8624eef1eca 100644
|
|
--- a/include/linux/module.h
|
|
+++ b/include/linux/module.h
|
|
@@ -162,6 +162,8 @@ extern void cleanup_module(void);
|
|
#define __INITRODATA_OR_MODULE __INITRODATA
|
|
#endif /*CONFIG_MODULES*/
|
|
|
|
+struct module_kobject *lookup_or_create_module_kobject(const char *name);
|
|
+
|
|
/* Generic info of form tag = "info" */
|
|
#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
|
|
|
|
diff --git a/include/linux/pds/pds_core_if.h b/include/linux/pds/pds_core_if.h
|
|
index e838a2b90440ca..17a87c1a55d7c7 100644
|
|
--- a/include/linux/pds/pds_core_if.h
|
|
+++ b/include/linux/pds/pds_core_if.h
|
|
@@ -79,6 +79,7 @@ enum pds_core_status_code {
|
|
PDS_RC_EVFID = 31, /* VF ID does not exist */
|
|
PDS_RC_BAD_FW = 32, /* FW file is invalid or corrupted */
|
|
PDS_RC_ECLIENT = 33, /* No such client id */
|
|
+ PDS_RC_BAD_PCI = 255, /* Broken PCI when reading status */
|
|
};
|
|
|
|
/**
|
|
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
|
|
index 5f11f987334190..f7d392d849be56 100644
|
|
--- a/include/linux/skbuff.h
|
|
+++ b/include/linux/skbuff.h
|
|
@@ -685,6 +685,11 @@ typedef unsigned int sk_buff_data_t;
|
|
typedef unsigned char *sk_buff_data_t;
|
|
#endif
|
|
|
|
+enum skb_tstamp_type {
|
|
+ SKB_CLOCK_REALTIME,
|
|
+ SKB_CLOCK_MONOTONIC,
|
|
+};
|
|
+
|
|
/**
|
|
* DOC: Basic sk_buff geometry
|
|
*
|
|
@@ -804,10 +809,8 @@ typedef unsigned char *sk_buff_data_t;
|
|
* @dst_pending_confirm: need to confirm neighbour
|
|
* @decrypted: Decrypted SKB
|
|
* @slow_gro: state present at GRO time, slower prepare step required
|
|
- * @mono_delivery_time: When set, skb->tstamp has the
|
|
- * delivery_time in mono clock base (i.e. EDT). Otherwise, the
|
|
- * skb->tstamp has the (rcv) timestamp at ingress and
|
|
- * delivery_time at egress.
|
|
+ * @tstamp_type: When set, skb->tstamp has the
|
|
+ * delivery_time clock base of skb->tstamp.
|
|
* @napi_id: id of the NAPI struct this skb came from
|
|
* @sender_cpu: (aka @napi_id) source CPU in XPS
|
|
* @alloc_cpu: CPU which did the skb allocation.
|
|
@@ -935,7 +938,7 @@ struct sk_buff {
|
|
/* private: */
|
|
__u8 __mono_tc_offset[0];
|
|
/* public: */
|
|
- __u8 mono_delivery_time:1; /* See SKB_MONO_DELIVERY_TIME_MASK */
|
|
+ __u8 tstamp_type:1; /* See skb_tstamp_type */
|
|
#ifdef CONFIG_NET_XGRESS
|
|
__u8 tc_at_ingress:1; /* See TC_AT_INGRESS_MASK */
|
|
__u8 tc_skip_classify:1;
|
|
@@ -4189,7 +4192,7 @@ static inline void skb_get_new_timestampns(const struct sk_buff *skb,
|
|
static inline void __net_timestamp(struct sk_buff *skb)
|
|
{
|
|
skb->tstamp = ktime_get_real();
|
|
- skb->mono_delivery_time = 0;
|
|
+ skb->tstamp_type = SKB_CLOCK_REALTIME;
|
|
}
|
|
|
|
static inline ktime_t net_timedelta(ktime_t t)
|
|
@@ -4198,10 +4201,33 @@ static inline ktime_t net_timedelta(ktime_t t)
|
|
}
|
|
|
|
static inline void skb_set_delivery_time(struct sk_buff *skb, ktime_t kt,
|
|
- bool mono)
|
|
+ u8 tstamp_type)
|
|
{
|
|
skb->tstamp = kt;
|
|
- skb->mono_delivery_time = kt && mono;
|
|
+
|
|
+ if (kt)
|
|
+ skb->tstamp_type = tstamp_type;
|
|
+ else
|
|
+ skb->tstamp_type = SKB_CLOCK_REALTIME;
|
|
+}
|
|
+
|
|
+static inline void skb_set_delivery_type_by_clockid(struct sk_buff *skb,
|
|
+ ktime_t kt, clockid_t clockid)
|
|
+{
|
|
+ u8 tstamp_type = SKB_CLOCK_REALTIME;
|
|
+
|
|
+ switch (clockid) {
|
|
+ case CLOCK_REALTIME:
|
|
+ break;
|
|
+ case CLOCK_MONOTONIC:
|
|
+ tstamp_type = SKB_CLOCK_MONOTONIC;
|
|
+ break;
|
|
+ default:
|
|
+ WARN_ON_ONCE(1);
|
|
+ kt = 0;
|
|
+ }
|
|
+
|
|
+ skb_set_delivery_time(skb, kt, tstamp_type);
|
|
}
|
|
|
|
DECLARE_STATIC_KEY_FALSE(netstamp_needed_key);
|
|
@@ -4211,8 +4237,8 @@ DECLARE_STATIC_KEY_FALSE(netstamp_needed_key);
|
|
*/
|
|
static inline void skb_clear_delivery_time(struct sk_buff *skb)
|
|
{
|
|
- if (skb->mono_delivery_time) {
|
|
- skb->mono_delivery_time = 0;
|
|
+ if (skb->tstamp_type) {
|
|
+ skb->tstamp_type = SKB_CLOCK_REALTIME;
|
|
if (static_branch_unlikely(&netstamp_needed_key))
|
|
skb->tstamp = ktime_get_real();
|
|
else
|
|
@@ -4222,7 +4248,7 @@ static inline void skb_clear_delivery_time(struct sk_buff *skb)
|
|
|
|
static inline void skb_clear_tstamp(struct sk_buff *skb)
|
|
{
|
|
- if (skb->mono_delivery_time)
|
|
+ if (skb->tstamp_type)
|
|
return;
|
|
|
|
skb->tstamp = 0;
|
|
@@ -4230,7 +4256,7 @@ static inline void skb_clear_tstamp(struct sk_buff *skb)
|
|
|
|
static inline ktime_t skb_tstamp(const struct sk_buff *skb)
|
|
{
|
|
- if (skb->mono_delivery_time)
|
|
+ if (skb->tstamp_type)
|
|
return 0;
|
|
|
|
return skb->tstamp;
|
|
@@ -4238,7 +4264,7 @@ static inline ktime_t skb_tstamp(const struct sk_buff *skb)
|
|
|
|
static inline ktime_t skb_tstamp_cond(const struct sk_buff *skb, bool cond)
|
|
{
|
|
- if (!skb->mono_delivery_time && skb->tstamp)
|
|
+ if (skb->tstamp_type != SKB_CLOCK_MONOTONIC && skb->tstamp)
|
|
return skb->tstamp;
|
|
|
|
if (static_branch_unlikely(&netstamp_needed_key) || cond)
|
|
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
|
|
index 153960663ce4c2..5af6eb14c5db15 100644
|
|
--- a/include/net/inet_frag.h
|
|
+++ b/include/net/inet_frag.h
|
|
@@ -76,7 +76,7 @@ struct frag_v6_compare_key {
|
|
* @stamp: timestamp of the last received fragment
|
|
* @len: total length of the original datagram
|
|
* @meat: length of received fragments so far
|
|
- * @mono_delivery_time: stamp has a mono delivery time (EDT)
|
|
+ * @tstamp_type: stamp has a mono delivery time (EDT)
|
|
* @flags: fragment queue flags
|
|
* @max_size: maximum received fragment size
|
|
* @fqdir: pointer to struct fqdir
|
|
@@ -97,7 +97,7 @@ struct inet_frag_queue {
|
|
ktime_t stamp;
|
|
int len;
|
|
int meat;
|
|
- u8 mono_delivery_time;
|
|
+ u8 tstamp_type;
|
|
__u8 flags;
|
|
u16 max_size;
|
|
struct fqdir *fqdir;
|
|
diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h
|
|
index c601a4598b0da8..eb19668a06db17 100644
|
|
--- a/include/soc/mscc/ocelot_vcap.h
|
|
+++ b/include/soc/mscc/ocelot_vcap.h
|
|
@@ -13,6 +13,7 @@
|
|
*/
|
|
#define OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port, upstream) ((upstream) << 16 | (port))
|
|
#define OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port) (port)
|
|
+#define OCELOT_VCAP_IS1_VLAN_RECLASSIFY(ocelot, port) ((ocelot)->num_phys_ports + (port))
|
|
#define OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port) (port)
|
|
#define OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port) ((ocelot)->num_phys_ports + (port))
|
|
#define OCELOT_VCAP_IS2_MRP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2)
|
|
@@ -499,6 +500,7 @@ struct ocelot_vcap_key_vlan {
|
|
struct ocelot_vcap_u8 pcp; /* PCP (3 bit) */
|
|
enum ocelot_vcap_bit dei; /* DEI */
|
|
enum ocelot_vcap_bit tagged; /* Tagged/untagged frame */
|
|
+ enum ocelot_vcap_bit tpid;
|
|
};
|
|
|
|
struct ocelot_vcap_key_etype {
|
|
diff --git a/include/sound/ump_convert.h b/include/sound/ump_convert.h
|
|
index d099ae27f8491a..682499b871eac4 100644
|
|
--- a/include/sound/ump_convert.h
|
|
+++ b/include/sound/ump_convert.h
|
|
@@ -19,7 +19,7 @@ struct ump_cvt_to_ump_bank {
|
|
/* context for converting from MIDI1 byte stream to UMP packet */
|
|
struct ump_cvt_to_ump {
|
|
/* MIDI1 intermediate buffer */
|
|
- unsigned char buf[4];
|
|
+ unsigned char buf[6]; /* up to 6 bytes for SysEx */
|
|
int len;
|
|
int cmd_bytes;
|
|
|
|
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
|
|
index 02f327f05fd619..81fd1bb9941644 100644
|
|
--- a/kernel/bpf/core.c
|
|
+++ b/kernel/bpf/core.c
|
|
@@ -2893,7 +2893,7 @@ void __weak bpf_jit_compile(struct bpf_prog *prog)
|
|
{
|
|
}
|
|
|
|
-bool __weak bpf_helper_changes_pkt_data(void *func)
|
|
+bool __weak bpf_helper_changes_pkt_data(enum bpf_func_id func_id)
|
|
{
|
|
return false;
|
|
}
|
|
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
|
|
index e443506b0a65a1..756e179a1efe3e 100644
|
|
--- a/kernel/bpf/verifier.c
|
|
+++ b/kernel/bpf/verifier.c
|
|
@@ -2636,16 +2636,36 @@ static int cmp_subprogs(const void *a, const void *b)
|
|
((struct bpf_subprog_info *)b)->start;
|
|
}
|
|
|
|
+/* Find subprogram that contains instruction at 'off' */
|
|
+static struct bpf_subprog_info *find_containing_subprog(struct bpf_verifier_env *env, int off)
|
|
+{
|
|
+ struct bpf_subprog_info *vals = env->subprog_info;
|
|
+ int l, r, m;
|
|
+
|
|
+ if (off >= env->prog->len || off < 0 || env->subprog_cnt == 0)
|
|
+ return NULL;
|
|
+
|
|
+ l = 0;
|
|
+ r = env->subprog_cnt - 1;
|
|
+ while (l < r) {
|
|
+ m = l + (r - l + 1) / 2;
|
|
+ if (vals[m].start <= off)
|
|
+ l = m;
|
|
+ else
|
|
+ r = m - 1;
|
|
+ }
|
|
+ return &vals[l];
|
|
+}
|
|
+
|
|
+/* Find subprogram that starts exactly at 'off' */
|
|
static int find_subprog(struct bpf_verifier_env *env, int off)
|
|
{
|
|
struct bpf_subprog_info *p;
|
|
|
|
- p = bsearch(&off, env->subprog_info, env->subprog_cnt,
|
|
- sizeof(env->subprog_info[0]), cmp_subprogs);
|
|
- if (!p)
|
|
+ p = find_containing_subprog(env, off);
|
|
+ if (!p || p->start != off)
|
|
return -ENOENT;
|
|
return p - env->subprog_info;
|
|
-
|
|
}
|
|
|
|
static int add_subprog(struct bpf_verifier_env *env, int off)
|
|
@@ -9344,6 +9364,8 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
|
|
|
|
if (env->log.level & BPF_LOG_LEVEL)
|
|
verbose(env, "Func#%d is global and valid. Skipping.\n", subprog);
|
|
+ if (env->subprog_info[subprog].changes_pkt_data)
|
|
+ clear_all_pkt_pointers(env);
|
|
clear_caller_saved_regs(env, caller->regs);
|
|
|
|
/* All global functions return a 64-bit SCALAR_VALUE */
|
|
@@ -9987,7 +10009,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
|
|
}
|
|
|
|
/* With LD_ABS/IND some JITs save/restore skb from r1. */
|
|
- changes_data = bpf_helper_changes_pkt_data(fn->func);
|
|
+ changes_data = bpf_helper_changes_pkt_data(func_id);
|
|
if (changes_data && fn->arg1_type != ARG_PTR_TO_CTX) {
|
|
verbose(env, "kernel subsystem misconfigured func %s#%d: r1 != ctx\n",
|
|
func_id_name(func_id), func_id);
|
|
@@ -15094,6 +15116,29 @@ static int check_return_code(struct bpf_verifier_env *env)
|
|
return 0;
|
|
}
|
|
|
|
+static void mark_subprog_changes_pkt_data(struct bpf_verifier_env *env, int off)
|
|
+{
|
|
+ struct bpf_subprog_info *subprog;
|
|
+
|
|
+ subprog = find_containing_subprog(env, off);
|
|
+ subprog->changes_pkt_data = true;
|
|
+}
|
|
+
|
|
+/* 't' is an index of a call-site.
|
|
+ * 'w' is a callee entry point.
|
|
+ * Eventually this function would be called when env->cfg.insn_state[w] == EXPLORED.
|
|
+ * Rely on DFS traversal order and absence of recursive calls to guarantee that
|
|
+ * callee's change_pkt_data marks would be correct at that moment.
|
|
+ */
|
|
+static void merge_callee_effects(struct bpf_verifier_env *env, int t, int w)
|
|
+{
|
|
+ struct bpf_subprog_info *caller, *callee;
|
|
+
|
|
+ caller = find_containing_subprog(env, t);
|
|
+ callee = find_containing_subprog(env, w);
|
|
+ caller->changes_pkt_data |= callee->changes_pkt_data;
|
|
+}
|
|
+
|
|
/* non-recursive DFS pseudo code
|
|
* 1 procedure DFS-iterative(G,v):
|
|
* 2 label v as discovered
|
|
@@ -15227,6 +15272,7 @@ static int visit_func_call_insn(int t, struct bpf_insn *insns,
|
|
bool visit_callee)
|
|
{
|
|
int ret, insn_sz;
|
|
+ int w;
|
|
|
|
insn_sz = bpf_is_ldimm64(&insns[t]) ? 2 : 1;
|
|
ret = push_insn(t, t + insn_sz, FALLTHROUGH, env);
|
|
@@ -15238,8 +15284,10 @@ static int visit_func_call_insn(int t, struct bpf_insn *insns,
|
|
mark_jmp_point(env, t + insn_sz);
|
|
|
|
if (visit_callee) {
|
|
+ w = t + insns[t].imm + 1;
|
|
mark_prune_point(env, t);
|
|
- ret = push_insn(t, t + insns[t].imm + 1, BRANCH, env);
|
|
+ merge_callee_effects(env, t, w);
|
|
+ ret = push_insn(t, w, BRANCH, env);
|
|
}
|
|
return ret;
|
|
}
|
|
@@ -15291,6 +15339,8 @@ static int visit_insn(int t, struct bpf_verifier_env *env)
|
|
mark_prune_point(env, t);
|
|
mark_jmp_point(env, t);
|
|
}
|
|
+ if (bpf_helper_call(insn) && bpf_helper_changes_pkt_data(insn->imm))
|
|
+ mark_subprog_changes_pkt_data(env, t);
|
|
if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
|
|
struct bpf_kfunc_call_arg_meta meta;
|
|
|
|
@@ -15412,6 +15462,7 @@ static int check_cfg(struct bpf_verifier_env *env)
|
|
}
|
|
}
|
|
ret = 0; /* cfg looks good */
|
|
+ env->prog->aux->changes_pkt_data = env->subprog_info[0].changes_pkt_data;
|
|
|
|
err_free:
|
|
kvfree(insn_state);
|
|
@@ -18572,6 +18623,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
|
|
}
|
|
func[i]->aux->num_exentries = num_exentries;
|
|
func[i]->aux->tail_call_reachable = env->subprog_info[i].tail_call_reachable;
|
|
+ func[i]->aux->changes_pkt_data = env->subprog_info[i].changes_pkt_data;
|
|
func[i] = bpf_int_jit_compile(func[i]);
|
|
if (!func[i]->jited) {
|
|
err = -ENOTSUPP;
|
|
@@ -19856,6 +19908,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
|
|
}
|
|
if (tgt_prog) {
|
|
struct bpf_prog_aux *aux = tgt_prog->aux;
|
|
+ bool tgt_changes_pkt_data;
|
|
|
|
if (bpf_prog_is_dev_bound(prog->aux) &&
|
|
!bpf_prog_dev_bound_match(prog, tgt_prog)) {
|
|
@@ -19884,6 +19937,14 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
|
|
"Extension programs should be JITed\n");
|
|
return -EINVAL;
|
|
}
|
|
+ tgt_changes_pkt_data = aux->func
|
|
+ ? aux->func[subprog]->aux->changes_pkt_data
|
|
+ : aux->changes_pkt_data;
|
|
+ if (prog->aux->changes_pkt_data && !tgt_changes_pkt_data) {
|
|
+ bpf_log(log,
|
|
+ "Extension program changes packet data, while original does not\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
}
|
|
if (!tgt_prog->jited) {
|
|
bpf_log(log, "Can attach to only JITed progs\n");
|
|
@@ -20343,10 +20404,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
|
|
if (ret < 0)
|
|
goto skip_full_check;
|
|
|
|
- ret = check_attach_btf_id(env);
|
|
- if (ret)
|
|
- goto skip_full_check;
|
|
-
|
|
ret = resolve_pseudo_ldimm64(env);
|
|
if (ret < 0)
|
|
goto skip_full_check;
|
|
@@ -20361,6 +20418,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
|
|
if (ret < 0)
|
|
goto skip_full_check;
|
|
|
|
+ ret = check_attach_btf_id(env);
|
|
+ if (ret)
|
|
+ goto skip_full_check;
|
|
+
|
|
ret = do_check_subprogs(env);
|
|
ret = ret ?: do_check_main(env);
|
|
|
|
diff --git a/kernel/params.c b/kernel/params.c
|
|
index 2d4a0564697e83..c7aed3c51cd538 100644
|
|
--- a/kernel/params.c
|
|
+++ b/kernel/params.c
|
|
@@ -759,7 +759,7 @@ void destroy_params(const struct kernel_param *params, unsigned num)
|
|
params[i].ops->free(params[i].arg);
|
|
}
|
|
|
|
-static struct module_kobject * __init locate_module_kobject(const char *name)
|
|
+struct module_kobject __modinit * lookup_or_create_module_kobject(const char *name)
|
|
{
|
|
struct module_kobject *mk;
|
|
struct kobject *kobj;
|
|
@@ -801,7 +801,7 @@ static void __init kernel_add_sysfs_param(const char *name,
|
|
struct module_kobject *mk;
|
|
int err;
|
|
|
|
- mk = locate_module_kobject(name);
|
|
+ mk = lookup_or_create_module_kobject(name);
|
|
if (!mk)
|
|
return;
|
|
|
|
@@ -872,7 +872,7 @@ static void __init version_sysfs_builtin(void)
|
|
int err;
|
|
|
|
for (vattr = __start___modver; vattr < __stop___modver; vattr++) {
|
|
- mk = locate_module_kobject(vattr->module_name);
|
|
+ mk = lookup_or_create_module_kobject(vattr->module_name);
|
|
if (mk) {
|
|
err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr);
|
|
WARN_ON_ONCE(err);
|
|
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
|
|
index a41c99350a5bf7..95868c31573007 100644
|
|
--- a/kernel/trace/trace.c
|
|
+++ b/kernel/trace/trace.c
|
|
@@ -7027,13 +7027,14 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
|
|
/* Copy the data into the page, so we can start over. */
|
|
ret = trace_seq_to_buffer(&iter->seq,
|
|
page_address(spd.pages[i]),
|
|
- trace_seq_used(&iter->seq));
|
|
+ min((size_t)trace_seq_used(&iter->seq),
|
|
+ PAGE_SIZE));
|
|
if (ret < 0) {
|
|
__free_page(spd.pages[i]);
|
|
break;
|
|
}
|
|
spd.partial[i].offset = 0;
|
|
- spd.partial[i].len = trace_seq_used(&iter->seq);
|
|
+ spd.partial[i].len = ret;
|
|
|
|
trace_seq_init(&iter->seq);
|
|
}
|
|
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
|
|
index 2b948d35fb59ea..448ee37ae2450a 100644
|
|
--- a/kernel/trace/trace_output.c
|
|
+++ b/kernel/trace/trace_output.c
|
|
@@ -950,11 +950,12 @@ enum print_line_t print_event_fields(struct trace_iterator *iter,
|
|
struct trace_event_call *call;
|
|
struct list_head *head;
|
|
|
|
+ lockdep_assert_held_read(&trace_event_sem);
|
|
+
|
|
/* ftrace defined events have separate call structures */
|
|
if (event->type <= __TRACE_LAST_TYPE) {
|
|
bool found = false;
|
|
|
|
- down_read(&trace_event_sem);
|
|
list_for_each_entry(call, &ftrace_events, list) {
|
|
if (call->event.type == event->type) {
|
|
found = true;
|
|
@@ -964,7 +965,6 @@ enum print_line_t print_event_fields(struct trace_iterator *iter,
|
|
if (call->event.type > __TRACE_LAST_TYPE)
|
|
break;
|
|
}
|
|
- up_read(&trace_event_sem);
|
|
if (!found) {
|
|
trace_seq_printf(&iter->seq, "UNKNOWN TYPE %d\n", event->type);
|
|
goto out;
|
|
diff --git a/mm/memblock.c b/mm/memblock.c
|
|
index e8a2a1537d6a85..047dce35cf6e0e 100644
|
|
--- a/mm/memblock.c
|
|
+++ b/mm/memblock.c
|
|
@@ -2122,11 +2122,14 @@ static void __init memmap_init_reserved_pages(void)
|
|
struct memblock_region *region;
|
|
phys_addr_t start, end;
|
|
int nid;
|
|
+ unsigned long max_reserved;
|
|
|
|
/*
|
|
* set nid on all reserved pages and also treat struct
|
|
* pages for the NOMAP regions as PageReserved
|
|
*/
|
|
+repeat:
|
|
+ max_reserved = memblock.reserved.max;
|
|
for_each_mem_region(region) {
|
|
nid = memblock_get_region_node(region);
|
|
start = region->base;
|
|
@@ -2135,8 +2138,15 @@ static void __init memmap_init_reserved_pages(void)
|
|
if (memblock_is_nomap(region))
|
|
reserve_bootmem_region(start, end, nid);
|
|
|
|
- memblock_set_node(start, end, &memblock.reserved, nid);
|
|
+ memblock_set_node(start, region->size, &memblock.reserved, nid);
|
|
}
|
|
+ /*
|
|
+ * 'max' is changed means memblock.reserved has been doubled its
|
|
+ * array, which may result a new reserved region before current
|
|
+ * 'start'. Now we should repeat the procedure to set its node id.
|
|
+ */
|
|
+ if (max_reserved != memblock.reserved.max)
|
|
+ goto repeat;
|
|
|
|
/* initialize struct pages for the reserved regions */
|
|
for_each_reserved_mem_region(region) {
|
|
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
|
|
index d4dcdb2370cc98..72ee41b894a520 100644
|
|
--- a/net/bluetooth/l2cap_core.c
|
|
+++ b/net/bluetooth/l2cap_core.c
|
|
@@ -7386,6 +7386,9 @@ static int l2cap_recv_frag(struct l2cap_conn *conn, struct sk_buff *skb,
|
|
return -ENOMEM;
|
|
/* Init rx_len */
|
|
conn->rx_len = len;
|
|
+
|
|
+ skb_set_delivery_time(conn->rx_skb, skb->tstamp,
|
|
+ skb->tstamp_type);
|
|
}
|
|
|
|
/* Copy as much as the rx_skb can hold */
|
|
diff --git a/net/bridge/netfilter/nf_conntrack_bridge.c b/net/bridge/netfilter/nf_conntrack_bridge.c
|
|
index 6ef04f9fe481be..4fbfbafdfa0274 100644
|
|
--- a/net/bridge/netfilter/nf_conntrack_bridge.c
|
|
+++ b/net/bridge/netfilter/nf_conntrack_bridge.c
|
|
@@ -32,7 +32,7 @@ static int nf_br_ip_fragment(struct net *net, struct sock *sk,
|
|
struct sk_buff *))
|
|
{
|
|
int frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size;
|
|
- bool mono_delivery_time = skb->mono_delivery_time;
|
|
+ u8 tstamp_type = skb->tstamp_type;
|
|
unsigned int hlen, ll_rs, mtu;
|
|
ktime_t tstamp = skb->tstamp;
|
|
struct ip_frag_state state;
|
|
@@ -82,7 +82,7 @@ static int nf_br_ip_fragment(struct net *net, struct sock *sk,
|
|
if (iter.frag)
|
|
ip_fraglist_prepare(skb, &iter);
|
|
|
|
- skb_set_delivery_time(skb, tstamp, mono_delivery_time);
|
|
+ skb_set_delivery_time(skb, tstamp, tstamp_type);
|
|
err = output(net, sk, data, skb);
|
|
if (err || !iter.frag)
|
|
break;
|
|
@@ -113,7 +113,7 @@ static int nf_br_ip_fragment(struct net *net, struct sock *sk,
|
|
goto blackhole;
|
|
}
|
|
|
|
- skb_set_delivery_time(skb2, tstamp, mono_delivery_time);
|
|
+ skb_set_delivery_time(skb2, tstamp, tstamp_type);
|
|
err = output(net, sk, data, skb2);
|
|
if (err)
|
|
goto blackhole;
|
|
diff --git a/net/core/dev.c b/net/core/dev.c
|
|
index c31a7f7bedf3db..4006fd164b7bc7 100644
|
|
--- a/net/core/dev.c
|
|
+++ b/net/core/dev.c
|
|
@@ -2189,7 +2189,7 @@ EXPORT_SYMBOL(net_disable_timestamp);
|
|
static inline void net_timestamp_set(struct sk_buff *skb)
|
|
{
|
|
skb->tstamp = 0;
|
|
- skb->mono_delivery_time = 0;
|
|
+ skb->tstamp_type = SKB_CLOCK_REALTIME;
|
|
if (static_branch_unlikely(&netstamp_needed_key))
|
|
skb->tstamp = ktime_get_real();
|
|
}
|
|
diff --git a/net/core/filter.c b/net/core/filter.c
|
|
index 39eef3370d800e..066277b91a1be8 100644
|
|
--- a/net/core/filter.c
|
|
+++ b/net/core/filter.c
|
|
@@ -7734,13 +7734,13 @@ BPF_CALL_3(bpf_skb_set_tstamp, struct sk_buff *, skb,
|
|
if (!tstamp)
|
|
return -EINVAL;
|
|
skb->tstamp = tstamp;
|
|
- skb->mono_delivery_time = 1;
|
|
+ skb->tstamp_type = SKB_CLOCK_MONOTONIC;
|
|
break;
|
|
case BPF_SKB_TSTAMP_UNSPEC:
|
|
if (tstamp)
|
|
return -EINVAL;
|
|
skb->tstamp = 0;
|
|
- skb->mono_delivery_time = 0;
|
|
+ skb->tstamp_type = SKB_CLOCK_REALTIME;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
@@ -7868,42 +7868,37 @@ static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv6_proto = {
|
|
|
|
#endif /* CONFIG_INET */
|
|
|
|
-bool bpf_helper_changes_pkt_data(void *func)
|
|
-{
|
|
- if (func == bpf_skb_vlan_push ||
|
|
- func == bpf_skb_vlan_pop ||
|
|
- func == bpf_skb_store_bytes ||
|
|
- func == bpf_skb_change_proto ||
|
|
- func == bpf_skb_change_head ||
|
|
- func == sk_skb_change_head ||
|
|
- func == bpf_skb_change_tail ||
|
|
- func == sk_skb_change_tail ||
|
|
- func == bpf_skb_adjust_room ||
|
|
- func == sk_skb_adjust_room ||
|
|
- func == bpf_skb_pull_data ||
|
|
- func == sk_skb_pull_data ||
|
|
- func == bpf_clone_redirect ||
|
|
- func == bpf_l3_csum_replace ||
|
|
- func == bpf_l4_csum_replace ||
|
|
- func == bpf_xdp_adjust_head ||
|
|
- func == bpf_xdp_adjust_meta ||
|
|
- func == bpf_msg_pull_data ||
|
|
- func == bpf_msg_push_data ||
|
|
- func == bpf_msg_pop_data ||
|
|
- func == bpf_xdp_adjust_tail ||
|
|
-#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)
|
|
- func == bpf_lwt_seg6_store_bytes ||
|
|
- func == bpf_lwt_seg6_adjust_srh ||
|
|
- func == bpf_lwt_seg6_action ||
|
|
-#endif
|
|
-#ifdef CONFIG_INET
|
|
- func == bpf_sock_ops_store_hdr_opt ||
|
|
-#endif
|
|
- func == bpf_lwt_in_push_encap ||
|
|
- func == bpf_lwt_xmit_push_encap)
|
|
+bool bpf_helper_changes_pkt_data(enum bpf_func_id func_id)
|
|
+{
|
|
+ switch (func_id) {
|
|
+ case BPF_FUNC_clone_redirect:
|
|
+ case BPF_FUNC_l3_csum_replace:
|
|
+ case BPF_FUNC_l4_csum_replace:
|
|
+ case BPF_FUNC_lwt_push_encap:
|
|
+ case BPF_FUNC_lwt_seg6_action:
|
|
+ case BPF_FUNC_lwt_seg6_adjust_srh:
|
|
+ case BPF_FUNC_lwt_seg6_store_bytes:
|
|
+ case BPF_FUNC_msg_pop_data:
|
|
+ case BPF_FUNC_msg_pull_data:
|
|
+ case BPF_FUNC_msg_push_data:
|
|
+ case BPF_FUNC_skb_adjust_room:
|
|
+ case BPF_FUNC_skb_change_head:
|
|
+ case BPF_FUNC_skb_change_proto:
|
|
+ case BPF_FUNC_skb_change_tail:
|
|
+ case BPF_FUNC_skb_pull_data:
|
|
+ case BPF_FUNC_skb_store_bytes:
|
|
+ case BPF_FUNC_skb_vlan_pop:
|
|
+ case BPF_FUNC_skb_vlan_push:
|
|
+ case BPF_FUNC_store_hdr_opt:
|
|
+ case BPF_FUNC_xdp_adjust_head:
|
|
+ case BPF_FUNC_xdp_adjust_meta:
|
|
+ case BPF_FUNC_xdp_adjust_tail:
|
|
+ /* tail-called program could call any of the above */
|
|
+ case BPF_FUNC_tail_call:
|
|
return true;
|
|
-
|
|
- return false;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
}
|
|
|
|
const struct bpf_func_proto bpf_event_output_data_proto __weak;
|
|
@@ -9443,7 +9438,7 @@ static struct bpf_insn *bpf_convert_tstamp_read(const struct bpf_prog *prog,
|
|
TC_AT_INGRESS_MASK | SKB_MONO_DELIVERY_TIME_MASK);
|
|
*insn++ = BPF_JMP32_IMM(BPF_JNE, tmp_reg,
|
|
TC_AT_INGRESS_MASK | SKB_MONO_DELIVERY_TIME_MASK, 2);
|
|
- /* skb->tc_at_ingress && skb->mono_delivery_time,
|
|
+ /* skb->tc_at_ingress && skb->tstamp_type,
|
|
* read 0 as the (rcv) timestamp.
|
|
*/
|
|
*insn++ = BPF_MOV64_IMM(value_reg, 0);
|
|
@@ -9468,7 +9463,7 @@ static struct bpf_insn *bpf_convert_tstamp_write(const struct bpf_prog *prog,
|
|
* the bpf prog is aware the tstamp could have delivery time.
|
|
* Thus, write skb->tstamp as is if tstamp_type_access is true.
|
|
* Otherwise, writing at ingress will have to clear the
|
|
- * mono_delivery_time bit also.
|
|
+ * skb->tstamp_type bit also.
|
|
*/
|
|
if (!prog->tstamp_type_access) {
|
|
__u8 tmp_reg = BPF_REG_AX;
|
|
@@ -9478,7 +9473,7 @@ static struct bpf_insn *bpf_convert_tstamp_write(const struct bpf_prog *prog,
|
|
*insn++ = BPF_JMP32_IMM(BPF_JSET, tmp_reg, TC_AT_INGRESS_MASK, 1);
|
|
/* goto <store> */
|
|
*insn++ = BPF_JMP_A(2);
|
|
- /* <clear>: mono_delivery_time */
|
|
+ /* <clear>: skb->tstamp_type */
|
|
*insn++ = BPF_ALU32_IMM(BPF_AND, tmp_reg, ~SKB_MONO_DELIVERY_TIME_MASK);
|
|
*insn++ = BPF_STX_MEM(BPF_B, skb_reg, tmp_reg, SKB_BF_MONO_TC_OFFSET);
|
|
}
|
|
diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
|
|
index 6dd960ec558cf6..ba0455ad770193 100644
|
|
--- a/net/ieee802154/6lowpan/reassembly.c
|
|
+++ b/net/ieee802154/6lowpan/reassembly.c
|
|
@@ -130,7 +130,7 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq,
|
|
goto err;
|
|
|
|
fq->q.stamp = skb->tstamp;
|
|
- fq->q.mono_delivery_time = skb->mono_delivery_time;
|
|
+ fq->q.tstamp_type = skb->tstamp_type;
|
|
if (frag_type == LOWPAN_DISPATCH_FRAG1)
|
|
fq->q.flags |= INET_FRAG_FIRST_IN;
|
|
|
|
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
|
|
index c88c9034d63004..496308c0238485 100644
|
|
--- a/net/ipv4/inet_fragment.c
|
|
+++ b/net/ipv4/inet_fragment.c
|
|
@@ -619,7 +619,7 @@ void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head,
|
|
skb_mark_not_on_list(head);
|
|
head->prev = NULL;
|
|
head->tstamp = q->stamp;
|
|
- head->mono_delivery_time = q->mono_delivery_time;
|
|
+ head->tstamp_type = q->tstamp_type;
|
|
|
|
if (sk)
|
|
refcount_add(sum_truesize - head_truesize, &sk->sk_wmem_alloc);
|
|
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
|
|
index 877d1e03150c77..484edc8513e4b7 100644
|
|
--- a/net/ipv4/ip_fragment.c
|
|
+++ b/net/ipv4/ip_fragment.c
|
|
@@ -360,7 +360,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
|
|
qp->iif = dev->ifindex;
|
|
|
|
qp->q.stamp = skb->tstamp;
|
|
- qp->q.mono_delivery_time = skb->mono_delivery_time;
|
|
+ qp->q.tstamp_type = skb->tstamp_type;
|
|
qp->q.meat += skb->len;
|
|
qp->ecn |= ecn;
|
|
add_frag_mem_limit(qp->q.fqdir, skb->truesize);
|
|
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
|
|
index 765bd3f2a84089..b8cfe6afc84b88 100644
|
|
--- a/net/ipv4/ip_output.c
|
|
+++ b/net/ipv4/ip_output.c
|
|
@@ -764,7 +764,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
|
{
|
|
struct iphdr *iph;
|
|
struct sk_buff *skb2;
|
|
- bool mono_delivery_time = skb->mono_delivery_time;
|
|
+ u8 tstamp_type = skb->tstamp_type;
|
|
struct rtable *rt = skb_rtable(skb);
|
|
unsigned int mtu, hlen, ll_rs;
|
|
struct ip_fraglist_iter iter;
|
|
@@ -856,7 +856,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
|
}
|
|
}
|
|
|
|
- skb_set_delivery_time(skb, tstamp, mono_delivery_time);
|
|
+ skb_set_delivery_time(skb, tstamp, tstamp_type);
|
|
err = output(net, sk, skb);
|
|
|
|
if (!err)
|
|
@@ -912,7 +912,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
|
/*
|
|
* Put this fragment into the sending queue.
|
|
*/
|
|
- skb_set_delivery_time(skb2, tstamp, mono_delivery_time);
|
|
+ skb_set_delivery_time(skb2, tstamp, tstamp_type);
|
|
err = output(net, sk, skb2);
|
|
if (err)
|
|
goto fail;
|
|
@@ -1648,7 +1648,8 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
|
|
arg->csumoffset) = csum_fold(csum_add(nskb->csum,
|
|
arg->csum));
|
|
nskb->ip_summed = CHECKSUM_NONE;
|
|
- nskb->mono_delivery_time = !!transmit_time;
|
|
+ if (transmit_time)
|
|
+ nskb->tstamp_type = SKB_CLOCK_MONOTONIC;
|
|
if (txhash)
|
|
skb_set_hash(nskb, txhash, PKT_HASH_TYPE_L4);
|
|
ip_push_pending_frames(sk, &fl4);
|
|
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
|
|
index 3771ed22c2f56f..560273e7f77365 100644
|
|
--- a/net/ipv4/tcp_output.c
|
|
+++ b/net/ipv4/tcp_output.c
|
|
@@ -1266,7 +1266,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb,
|
|
tp = tcp_sk(sk);
|
|
prior_wstamp = tp->tcp_wstamp_ns;
|
|
tp->tcp_wstamp_ns = max(tp->tcp_wstamp_ns, tp->tcp_clock_cache);
|
|
- skb_set_delivery_time(skb, tp->tcp_wstamp_ns, true);
|
|
+ skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC);
|
|
if (clone_it) {
|
|
oskb = skb;
|
|
|
|
@@ -1607,7 +1607,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue,
|
|
|
|
skb_split(skb, buff, len);
|
|
|
|
- skb_set_delivery_time(buff, skb->tstamp, true);
|
|
+ skb_set_delivery_time(buff, skb->tstamp, SKB_CLOCK_MONOTONIC);
|
|
tcp_fragment_tstamp(skb, buff);
|
|
|
|
old_factor = tcp_skb_pcount(skb);
|
|
@@ -2703,7 +2703,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
|
|
if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) {
|
|
/* "skb_mstamp_ns" is used as a start point for the retransmit timer */
|
|
tp->tcp_wstamp_ns = tp->tcp_clock_cache;
|
|
- skb_set_delivery_time(skb, tp->tcp_wstamp_ns, true);
|
|
+ skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC);
|
|
list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue);
|
|
tcp_init_tso_segs(skb, mss_now);
|
|
goto repair; /* Skip network transmission */
|
|
@@ -3688,11 +3688,11 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
|
|
#ifdef CONFIG_SYN_COOKIES
|
|
if (unlikely(synack_type == TCP_SYNACK_COOKIE && ireq->tstamp_ok))
|
|
skb_set_delivery_time(skb, cookie_init_timestamp(req, now),
|
|
- true);
|
|
+ SKB_CLOCK_MONOTONIC);
|
|
else
|
|
#endif
|
|
{
|
|
- skb_set_delivery_time(skb, now, true);
|
|
+ skb_set_delivery_time(skb, now, SKB_CLOCK_MONOTONIC);
|
|
if (!tcp_rsk(req)->snt_synack) /* Timestamp first SYNACK */
|
|
tcp_rsk(req)->snt_synack = tcp_skb_timestamp_us(skb);
|
|
}
|
|
@@ -3741,7 +3741,7 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
|
|
bpf_skops_write_hdr_opt((struct sock *)sk, skb, req, syn_skb,
|
|
synack_type, &opts);
|
|
|
|
- skb_set_delivery_time(skb, now, true);
|
|
+ skb_set_delivery_time(skb, now, SKB_CLOCK_MONOTONIC);
|
|
tcp_add_tx_delay(skb, tp);
|
|
|
|
return skb;
|
|
@@ -3923,7 +3923,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
|
|
|
|
err = tcp_transmit_skb(sk, syn_data, 1, sk->sk_allocation);
|
|
|
|
- skb_set_delivery_time(syn, syn_data->skb_mstamp_ns, true);
|
|
+ skb_set_delivery_time(syn, syn_data->skb_mstamp_ns, SKB_CLOCK_MONOTONIC);
|
|
|
|
/* Now full SYN+DATA was cloned and sent (or not),
|
|
* remove the SYN from the original skb (syn_data)
|
|
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
|
|
index 2ab16139c197b3..132cfc3b2c847b 100644
|
|
--- a/net/ipv4/udp_offload.c
|
|
+++ b/net/ipv4/udp_offload.c
|
|
@@ -247,6 +247,62 @@ static struct sk_buff *__udpv4_gso_segment_list_csum(struct sk_buff *segs)
|
|
return segs;
|
|
}
|
|
|
|
+static void __udpv6_gso_segment_csum(struct sk_buff *seg,
|
|
+ struct in6_addr *oldip,
|
|
+ const struct in6_addr *newip,
|
|
+ __be16 *oldport, __be16 newport)
|
|
+{
|
|
+ struct udphdr *uh = udp_hdr(seg);
|
|
+
|
|
+ if (ipv6_addr_equal(oldip, newip) && *oldport == newport)
|
|
+ return;
|
|
+
|
|
+ if (uh->check) {
|
|
+ inet_proto_csum_replace16(&uh->check, seg, oldip->s6_addr32,
|
|
+ newip->s6_addr32, true);
|
|
+
|
|
+ inet_proto_csum_replace2(&uh->check, seg, *oldport, newport,
|
|
+ false);
|
|
+ if (!uh->check)
|
|
+ uh->check = CSUM_MANGLED_0;
|
|
+ }
|
|
+
|
|
+ *oldip = *newip;
|
|
+ *oldport = newport;
|
|
+}
|
|
+
|
|
+static struct sk_buff *__udpv6_gso_segment_list_csum(struct sk_buff *segs)
|
|
+{
|
|
+ const struct ipv6hdr *iph;
|
|
+ const struct udphdr *uh;
|
|
+ struct ipv6hdr *iph2;
|
|
+ struct sk_buff *seg;
|
|
+ struct udphdr *uh2;
|
|
+
|
|
+ seg = segs;
|
|
+ uh = udp_hdr(seg);
|
|
+ iph = ipv6_hdr(seg);
|
|
+ uh2 = udp_hdr(seg->next);
|
|
+ iph2 = ipv6_hdr(seg->next);
|
|
+
|
|
+ if (!(*(const u32 *)&uh->source ^ *(const u32 *)&uh2->source) &&
|
|
+ ipv6_addr_equal(&iph->saddr, &iph2->saddr) &&
|
|
+ ipv6_addr_equal(&iph->daddr, &iph2->daddr))
|
|
+ return segs;
|
|
+
|
|
+ while ((seg = seg->next)) {
|
|
+ uh2 = udp_hdr(seg);
|
|
+ iph2 = ipv6_hdr(seg);
|
|
+
|
|
+ __udpv6_gso_segment_csum(seg, &iph2->saddr, &iph->saddr,
|
|
+ &uh2->source, uh->source);
|
|
+ __udpv6_gso_segment_csum(seg, &iph2->daddr, &iph->daddr,
|
|
+ &uh2->dest, uh->dest);
|
|
+ }
|
|
+
|
|
+ return segs;
|
|
+}
|
|
+
|
|
static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
|
|
netdev_features_t features,
|
|
bool is_ipv6)
|
|
@@ -259,7 +315,10 @@ static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
|
|
|
|
udp_hdr(skb)->len = htons(sizeof(struct udphdr) + mss);
|
|
|
|
- return is_ipv6 ? skb : __udpv4_gso_segment_list_csum(skb);
|
|
+ if (is_ipv6)
|
|
+ return __udpv6_gso_segment_list_csum(skb);
|
|
+ else
|
|
+ return __udpv4_gso_segment_list_csum(skb);
|
|
}
|
|
|
|
struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
|
|
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
|
|
index cd89a2b35dfb56..c86d5dca29df01 100644
|
|
--- a/net/ipv6/ip6_output.c
|
|
+++ b/net/ipv6/ip6_output.c
|
|
@@ -864,7 +864,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
|
struct rt6_info *rt = dst_rt6_info(skb_dst(skb));
|
|
struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
|
|
inet6_sk(skb->sk) : NULL;
|
|
- bool mono_delivery_time = skb->mono_delivery_time;
|
|
+ u8 tstamp_type = skb->tstamp_type;
|
|
struct ip6_frag_state state;
|
|
unsigned int mtu, hlen, nexthdr_offset;
|
|
ktime_t tstamp = skb->tstamp;
|
|
@@ -958,7 +958,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
|
if (iter.frag)
|
|
ip6_fraglist_prepare(skb, &iter);
|
|
|
|
- skb_set_delivery_time(skb, tstamp, mono_delivery_time);
|
|
+ skb_set_delivery_time(skb, tstamp, tstamp_type);
|
|
err = output(net, sk, skb);
|
|
if (!err)
|
|
IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
|
|
@@ -1019,7 +1019,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
|
/*
|
|
* Put this fragment into the sending queue.
|
|
*/
|
|
- skb_set_delivery_time(frag, tstamp, mono_delivery_time);
|
|
+ skb_set_delivery_time(frag, tstamp, tstamp_type);
|
|
err = output(net, sk, frag);
|
|
if (err)
|
|
goto fail;
|
|
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
|
|
index 857713d7a38a54..7c4af48d529e1e 100644
|
|
--- a/net/ipv6/netfilter.c
|
|
+++ b/net/ipv6/netfilter.c
|
|
@@ -126,7 +126,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
|
struct sk_buff *))
|
|
{
|
|
int frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size;
|
|
- bool mono_delivery_time = skb->mono_delivery_time;
|
|
+ u8 tstamp_type = skb->tstamp_type;
|
|
ktime_t tstamp = skb->tstamp;
|
|
struct ip6_frag_state state;
|
|
u8 *prevhdr, nexthdr = 0;
|
|
@@ -192,7 +192,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
|
if (iter.frag)
|
|
ip6_fraglist_prepare(skb, &iter);
|
|
|
|
- skb_set_delivery_time(skb, tstamp, mono_delivery_time);
|
|
+ skb_set_delivery_time(skb, tstamp, tstamp_type);
|
|
err = output(net, sk, data, skb);
|
|
if (err || !iter.frag)
|
|
break;
|
|
@@ -225,7 +225,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
|
goto blackhole;
|
|
}
|
|
|
|
- skb_set_delivery_time(skb2, tstamp, mono_delivery_time);
|
|
+ skb_set_delivery_time(skb2, tstamp, tstamp_type);
|
|
err = output(net, sk, data, skb2);
|
|
if (err)
|
|
goto blackhole;
|
|
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
|
|
index c78b13ea5b196a..82e51b2ec4f512 100644
|
|
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
|
|
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
|
|
@@ -268,7 +268,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb,
|
|
fq->iif = dev->ifindex;
|
|
|
|
fq->q.stamp = skb->tstamp;
|
|
- fq->q.mono_delivery_time = skb->mono_delivery_time;
|
|
+ fq->q.tstamp_type = skb->tstamp_type;
|
|
fq->q.meat += skb->len;
|
|
fq->ecn |= ecn;
|
|
if (payload_len > fq->q.max_size)
|
|
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
|
|
index 2af98edef87ee0..cb219d4bdf25ed 100644
|
|
--- a/net/ipv6/reassembly.c
|
|
+++ b/net/ipv6/reassembly.c
|
|
@@ -198,7 +198,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
|
|
fq->iif = dev->ifindex;
|
|
|
|
fq->q.stamp = skb->tstamp;
|
|
- fq->q.mono_delivery_time = skb->mono_delivery_time;
|
|
+ fq->q.tstamp_type = skb->tstamp_type;
|
|
fq->q.meat += skb->len;
|
|
fq->ecn |= ecn;
|
|
add_frag_mem_limit(fq->q.fqdir, skb->truesize);
|
|
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
|
|
index f285e52b8b8579..624ab1424eba7d 100644
|
|
--- a/net/ipv6/tcp_ipv6.c
|
|
+++ b/net/ipv6/tcp_ipv6.c
|
|
@@ -934,7 +934,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
|
|
mark = inet_twsk(sk)->tw_mark;
|
|
else
|
|
mark = READ_ONCE(sk->sk_mark);
|
|
- skb_set_delivery_time(buff, tcp_transmit_time(sk), true);
|
|
+ skb_set_delivery_time(buff, tcp_transmit_time(sk), SKB_CLOCK_MONOTONIC);
|
|
}
|
|
if (txhash) {
|
|
/* autoflowlabel/skb_get_hash_flowi6 rely on buff->hash */
|
|
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
|
|
index b0455fda7d0baf..ac87fcff4795e8 100644
|
|
--- a/net/sched/act_bpf.c
|
|
+++ b/net/sched/act_bpf.c
|
|
@@ -54,8 +54,8 @@ TC_INDIRECT_SCOPE int tcf_bpf_act(struct sk_buff *skb,
|
|
bpf_compute_data_pointers(skb);
|
|
filter_res = bpf_prog_run(filter, skb);
|
|
}
|
|
- if (unlikely(!skb->tstamp && skb->mono_delivery_time))
|
|
- skb->mono_delivery_time = 0;
|
|
+ if (unlikely(!skb->tstamp && skb->tstamp_type))
|
|
+ skb->tstamp_type = SKB_CLOCK_REALTIME;
|
|
if (skb_sk_is_prefetched(skb) && filter_res != TC_ACT_OK)
|
|
skb_orphan(skb);
|
|
|
|
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
|
|
index 382c7a71f81f2d..db7151c6b70b79 100644
|
|
--- a/net/sched/cls_bpf.c
|
|
+++ b/net/sched/cls_bpf.c
|
|
@@ -104,8 +104,8 @@ TC_INDIRECT_SCOPE int cls_bpf_classify(struct sk_buff *skb,
|
|
bpf_compute_data_pointers(skb);
|
|
filter_res = bpf_prog_run(prog->filter, skb);
|
|
}
|
|
- if (unlikely(!skb->tstamp && skb->mono_delivery_time))
|
|
- skb->mono_delivery_time = 0;
|
|
+ if (unlikely(!skb->tstamp && skb->tstamp_type))
|
|
+ skb->tstamp_type = SKB_CLOCK_REALTIME;
|
|
|
|
if (prog->exts_integrated) {
|
|
res->class = 0;
|
|
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
|
|
index 19901e77cd3b7f..9b36955e32b142 100644
|
|
--- a/net/sched/sch_drr.c
|
|
+++ b/net/sched/sch_drr.c
|
|
@@ -35,6 +35,11 @@ struct drr_sched {
|
|
struct Qdisc_class_hash clhash;
|
|
};
|
|
|
|
+static bool cl_is_active(struct drr_class *cl)
|
|
+{
|
|
+ return !list_empty(&cl->alist);
|
|
+}
|
|
+
|
|
static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid)
|
|
{
|
|
struct drr_sched *q = qdisc_priv(sch);
|
|
@@ -105,6 +110,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
|
|
return -ENOBUFS;
|
|
|
|
gnet_stats_basic_sync_init(&cl->bstats);
|
|
+ INIT_LIST_HEAD(&cl->alist);
|
|
cl->common.classid = classid;
|
|
cl->quantum = quantum;
|
|
cl->qdisc = qdisc_create_dflt(sch->dev_queue,
|
|
@@ -229,7 +235,7 @@ static void drr_qlen_notify(struct Qdisc *csh, unsigned long arg)
|
|
{
|
|
struct drr_class *cl = (struct drr_class *)arg;
|
|
|
|
- list_del(&cl->alist);
|
|
+ list_del_init(&cl->alist);
|
|
}
|
|
|
|
static int drr_dump_class(struct Qdisc *sch, unsigned long arg,
|
|
@@ -336,7 +342,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|
struct drr_sched *q = qdisc_priv(sch);
|
|
struct drr_class *cl;
|
|
int err = 0;
|
|
- bool first;
|
|
|
|
cl = drr_classify(skb, sch, &err);
|
|
if (cl == NULL) {
|
|
@@ -346,7 +351,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|
return err;
|
|
}
|
|
|
|
- first = !cl->qdisc->q.qlen;
|
|
err = qdisc_enqueue(skb, cl->qdisc, to_free);
|
|
if (unlikely(err != NET_XMIT_SUCCESS)) {
|
|
if (net_xmit_drop_count(err)) {
|
|
@@ -356,7 +360,7 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|
return err;
|
|
}
|
|
|
|
- if (first) {
|
|
+ if (!cl_is_active(cl)) {
|
|
list_add_tail(&cl->alist, &q->active);
|
|
cl->deficit = cl->quantum;
|
|
}
|
|
@@ -390,7 +394,7 @@ static struct sk_buff *drr_dequeue(struct Qdisc *sch)
|
|
if (unlikely(skb == NULL))
|
|
goto out;
|
|
if (cl->qdisc->q.qlen == 0)
|
|
- list_del(&cl->alist);
|
|
+ list_del_init(&cl->alist);
|
|
|
|
bstats_update(&cl->bstats, skb);
|
|
qdisc_bstats_update(sch, skb);
|
|
@@ -431,7 +435,7 @@ static void drr_reset_qdisc(struct Qdisc *sch)
|
|
for (i = 0; i < q->clhash.hashsize; i++) {
|
|
hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) {
|
|
if (cl->qdisc->q.qlen)
|
|
- list_del(&cl->alist);
|
|
+ list_del_init(&cl->alist);
|
|
qdisc_reset(cl->qdisc);
|
|
}
|
|
}
|
|
diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c
|
|
index 9fd70462b41d5a..9da86db4d2c2fe 100644
|
|
--- a/net/sched/sch_ets.c
|
|
+++ b/net/sched/sch_ets.c
|
|
@@ -74,6 +74,11 @@ static const struct nla_policy ets_class_policy[TCA_ETS_MAX + 1] = {
|
|
[TCA_ETS_QUANTA_BAND] = { .type = NLA_U32 },
|
|
};
|
|
|
|
+static bool cl_is_active(struct ets_class *cl)
|
|
+{
|
|
+ return !list_empty(&cl->alist);
|
|
+}
|
|
+
|
|
static int ets_quantum_parse(struct Qdisc *sch, const struct nlattr *attr,
|
|
unsigned int *quantum,
|
|
struct netlink_ext_ack *extack)
|
|
@@ -293,7 +298,7 @@ static void ets_class_qlen_notify(struct Qdisc *sch, unsigned long arg)
|
|
* to remove them.
|
|
*/
|
|
if (!ets_class_is_strict(q, cl) && sch->q.qlen)
|
|
- list_del(&cl->alist);
|
|
+ list_del_init(&cl->alist);
|
|
}
|
|
|
|
static int ets_class_dump(struct Qdisc *sch, unsigned long arg,
|
|
@@ -416,7 +421,6 @@ static int ets_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|
struct ets_sched *q = qdisc_priv(sch);
|
|
struct ets_class *cl;
|
|
int err = 0;
|
|
- bool first;
|
|
|
|
cl = ets_classify(skb, sch, &err);
|
|
if (!cl) {
|
|
@@ -426,7 +430,6 @@ static int ets_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|
return err;
|
|
}
|
|
|
|
- first = !cl->qdisc->q.qlen;
|
|
err = qdisc_enqueue(skb, cl->qdisc, to_free);
|
|
if (unlikely(err != NET_XMIT_SUCCESS)) {
|
|
if (net_xmit_drop_count(err)) {
|
|
@@ -436,7 +439,7 @@ static int ets_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|
return err;
|
|
}
|
|
|
|
- if (first && !ets_class_is_strict(q, cl)) {
|
|
+ if (!cl_is_active(cl) && !ets_class_is_strict(q, cl)) {
|
|
list_add_tail(&cl->alist, &q->active);
|
|
cl->deficit = cl->quantum;
|
|
}
|
|
@@ -488,7 +491,7 @@ static struct sk_buff *ets_qdisc_dequeue(struct Qdisc *sch)
|
|
if (unlikely(!skb))
|
|
goto out;
|
|
if (cl->qdisc->q.qlen == 0)
|
|
- list_del(&cl->alist);
|
|
+ list_del_init(&cl->alist);
|
|
return ets_qdisc_dequeue_skb(sch, skb);
|
|
}
|
|
|
|
@@ -657,7 +660,7 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt,
|
|
}
|
|
for (i = q->nbands; i < oldbands; i++) {
|
|
if (i >= q->nstrict && q->classes[i].qdisc->q.qlen)
|
|
- list_del(&q->classes[i].alist);
|
|
+ list_del_init(&q->classes[i].alist);
|
|
qdisc_tree_flush_backlog(q->classes[i].qdisc);
|
|
}
|
|
q->nstrict = nstrict;
|
|
@@ -713,7 +716,7 @@ static void ets_qdisc_reset(struct Qdisc *sch)
|
|
|
|
for (band = q->nstrict; band < q->nbands; band++) {
|
|
if (q->classes[band].qdisc->q.qlen)
|
|
- list_del(&q->classes[band].alist);
|
|
+ list_del_init(&q->classes[band].alist);
|
|
}
|
|
for (band = 0; band < q->nbands; band++)
|
|
qdisc_reset(q->classes[band].qdisc);
|
|
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
|
|
index 371255e624332f..5d9cccfac4a155 100644
|
|
--- a/net/sched/sch_hfsc.c
|
|
+++ b/net/sched/sch_hfsc.c
|
|
@@ -203,7 +203,10 @@ eltree_insert(struct hfsc_class *cl)
|
|
static inline void
|
|
eltree_remove(struct hfsc_class *cl)
|
|
{
|
|
- rb_erase(&cl->el_node, &cl->sched->eligible);
|
|
+ if (!RB_EMPTY_NODE(&cl->el_node)) {
|
|
+ rb_erase(&cl->el_node, &cl->sched->eligible);
|
|
+ RB_CLEAR_NODE(&cl->el_node);
|
|
+ }
|
|
}
|
|
|
|
static inline void
|
|
@@ -1224,7 +1227,8 @@ hfsc_qlen_notify(struct Qdisc *sch, unsigned long arg)
|
|
/* vttree is now handled in update_vf() so that update_vf(cl, 0, 0)
|
|
* needs to be called explicitly to remove a class from vttree.
|
|
*/
|
|
- update_vf(cl, 0, 0);
|
|
+ if (cl->cl_nactive)
|
|
+ update_vf(cl, 0, 0);
|
|
if (cl->cl_flags & HFSC_RSC)
|
|
eltree_remove(cl);
|
|
}
|
|
@@ -1566,7 +1570,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
|
|
return err;
|
|
}
|
|
|
|
- if (first) {
|
|
+ if (first && !cl->cl_nactive) {
|
|
if (cl->cl_flags & HFSC_RSC)
|
|
init_ed(cl, len);
|
|
if (cl->cl_flags & HFSC_FSC)
|
|
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
|
|
index 19035ef8387fed..9a3f7ea80b34b9 100644
|
|
--- a/net/sched/sch_htb.c
|
|
+++ b/net/sched/sch_htb.c
|
|
@@ -1485,6 +1485,8 @@ static void htb_qlen_notify(struct Qdisc *sch, unsigned long arg)
|
|
{
|
|
struct htb_class *cl = (struct htb_class *)arg;
|
|
|
|
+ if (!cl->prio_activity)
|
|
+ return;
|
|
htb_deactivate(qdisc_priv(sch), cl);
|
|
}
|
|
|
|
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c
|
|
index 546c10adcacdea..5e557b960bde33 100644
|
|
--- a/net/sched/sch_qfq.c
|
|
+++ b/net/sched/sch_qfq.c
|
|
@@ -202,6 +202,11 @@ struct qfq_sched {
|
|
*/
|
|
enum update_reason {enqueue, requeue};
|
|
|
|
+static bool cl_is_active(struct qfq_class *cl)
|
|
+{
|
|
+ return !list_empty(&cl->alist);
|
|
+}
|
|
+
|
|
static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid)
|
|
{
|
|
struct qfq_sched *q = qdisc_priv(sch);
|
|
@@ -347,7 +352,7 @@ static void qfq_deactivate_class(struct qfq_sched *q, struct qfq_class *cl)
|
|
struct qfq_aggregate *agg = cl->agg;
|
|
|
|
|
|
- list_del(&cl->alist); /* remove from RR queue of the aggregate */
|
|
+ list_del_init(&cl->alist); /* remove from RR queue of the aggregate */
|
|
if (list_empty(&agg->active)) /* agg is now inactive */
|
|
qfq_deactivate_agg(q, agg);
|
|
}
|
|
@@ -477,6 +482,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
|
|
gnet_stats_basic_sync_init(&cl->bstats);
|
|
cl->common.classid = classid;
|
|
cl->deficit = lmax;
|
|
+ INIT_LIST_HEAD(&cl->alist);
|
|
|
|
cl->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
|
|
classid, NULL);
|
|
@@ -985,7 +991,7 @@ static struct sk_buff *agg_dequeue(struct qfq_aggregate *agg,
|
|
cl->deficit -= (int) len;
|
|
|
|
if (cl->qdisc->q.qlen == 0) /* no more packets, remove from list */
|
|
- list_del(&cl->alist);
|
|
+ list_del_init(&cl->alist);
|
|
else if (cl->deficit < qdisc_pkt_len(cl->qdisc->ops->peek(cl->qdisc))) {
|
|
cl->deficit += agg->lmax;
|
|
list_move_tail(&cl->alist, &agg->active);
|
|
@@ -1217,7 +1223,6 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|
struct qfq_class *cl;
|
|
struct qfq_aggregate *agg;
|
|
int err = 0;
|
|
- bool first;
|
|
|
|
cl = qfq_classify(skb, sch, &err);
|
|
if (cl == NULL) {
|
|
@@ -1239,7 +1244,6 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|
}
|
|
|
|
gso_segs = skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1;
|
|
- first = !cl->qdisc->q.qlen;
|
|
err = qdisc_enqueue(skb, cl->qdisc, to_free);
|
|
if (unlikely(err != NET_XMIT_SUCCESS)) {
|
|
pr_debug("qfq_enqueue: enqueue failed %d\n", err);
|
|
@@ -1255,8 +1259,8 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|
++sch->q.qlen;
|
|
|
|
agg = cl->agg;
|
|
- /* if the queue was not empty, then done here */
|
|
- if (!first) {
|
|
+ /* if the class is active, then done here */
|
|
+ if (cl_is_active(cl)) {
|
|
if (unlikely(skb == cl->qdisc->ops->peek(cl->qdisc)) &&
|
|
list_first_entry(&agg->active, struct qfq_class, alist)
|
|
== cl && cl->deficit < len)
|
|
@@ -1418,6 +1422,8 @@ static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg)
|
|
struct qfq_sched *q = qdisc_priv(sch);
|
|
struct qfq_class *cl = (struct qfq_class *)arg;
|
|
|
|
+ if (list_empty(&cl->alist))
|
|
+ return;
|
|
qfq_deactivate_class(q, cl);
|
|
}
|
|
|
|
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
|
|
index 619a817ee91cb8..4c1318ce8ae58f 100644
|
|
--- a/sound/soc/codecs/ak4613.c
|
|
+++ b/sound/soc/codecs/ak4613.c
|
|
@@ -840,14 +840,14 @@ static void ak4613_parse_of(struct ak4613_priv *priv,
|
|
/* Input 1 - 2 */
|
|
for (i = 0; i < 2; i++) {
|
|
snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1);
|
|
- if (!of_get_property(np, prop, NULL))
|
|
+ if (!of_property_read_bool(np, prop))
|
|
priv->ic |= 1 << i;
|
|
}
|
|
|
|
/* Output 1 - 6 */
|
|
for (i = 0; i < 6; i++) {
|
|
snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1);
|
|
- if (!of_get_property(np, prop, NULL))
|
|
+ if (!of_property_read_bool(np, prop))
|
|
priv->oc |= 1 << i;
|
|
}
|
|
|
|
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
|
|
index e65fe3a7c3e42c..7eea70eea68b47 100644
|
|
--- a/sound/soc/soc-core.c
|
|
+++ b/sound/soc/soc-core.c
|
|
@@ -2935,7 +2935,7 @@ int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop)
|
|
unsigned int i, nb_controls;
|
|
int ret;
|
|
|
|
- if (!of_property_read_bool(dev->of_node, prop))
|
|
+ if (!of_property_present(dev->of_node, prop))
|
|
return 0;
|
|
|
|
strings = devm_kcalloc(dev, nb_controls_max,
|
|
@@ -3009,23 +3009,17 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
|
|
if (rx_mask)
|
|
snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask);
|
|
|
|
- if (of_property_read_bool(np, "dai-tdm-slot-num")) {
|
|
- ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- if (slots)
|
|
- *slots = val;
|
|
- }
|
|
-
|
|
- if (of_property_read_bool(np, "dai-tdm-slot-width")) {
|
|
- ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
|
|
- if (ret)
|
|
- return ret;
|
|
+ ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
|
|
+ if (ret && ret != -EINVAL)
|
|
+ return ret;
|
|
+ if (!ret && slots)
|
|
+ *slots = val;
|
|
|
|
- if (slot_width)
|
|
- *slot_width = val;
|
|
- }
|
|
+ ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
|
|
+ if (ret && ret != -EINVAL)
|
|
+ return ret;
|
|
+ if (!ret && slot_width)
|
|
+ *slot_width = val;
|
|
|
|
return 0;
|
|
}
|
|
@@ -3249,10 +3243,10 @@ unsigned int snd_soc_daifmt_parse_format(struct device_node *np,
|
|
* SND_SOC_DAIFMT_INV_MASK area
|
|
*/
|
|
snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix);
|
|
- bit = !!of_get_property(np, prop, NULL);
|
|
+ bit = of_property_read_bool(np, prop);
|
|
|
|
snprintf(prop, sizeof(prop), "%sframe-inversion", prefix);
|
|
- frame = !!of_get_property(np, prop, NULL);
|
|
+ frame = of_property_read_bool(np, prop);
|
|
|
|
switch ((bit << 4) + frame) {
|
|
case 0x11:
|
|
@@ -3289,12 +3283,12 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np,
|
|
* check "[prefix]frame-master"
|
|
*/
|
|
snprintf(prop, sizeof(prop), "%sbitclock-master", prefix);
|
|
- bit = !!of_get_property(np, prop, NULL);
|
|
+ bit = of_property_present(np, prop);
|
|
if (bit && bitclkmaster)
|
|
*bitclkmaster = of_parse_phandle(np, prop, 0);
|
|
|
|
snprintf(prop, sizeof(prop), "%sframe-master", prefix);
|
|
- frame = !!of_get_property(np, prop, NULL);
|
|
+ frame = of_property_present(np, prop);
|
|
if (frame && framemaster)
|
|
*framemaster = of_parse_phandle(np, prop, 0);
|
|
|
|
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
|
|
index 60248a6820aacc..30e93f9aad7624 100644
|
|
--- a/sound/soc/soc-pcm.c
|
|
+++ b/sound/soc/soc-pcm.c
|
|
@@ -1534,10 +1534,13 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
|
|
/*
|
|
* Filter for systems with 'component_chaining' enabled.
|
|
* This helps to avoid unnecessary re-configuration of an
|
|
- * already active BE on such systems.
|
|
+ * already active BE on such systems and ensures the BE DAI
|
|
+ * widget is powered ON after hw_params() BE DAI callback.
|
|
*/
|
|
if (fe->card->component_chaining &&
|
|
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
|
|
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
|
|
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
|
|
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
|
|
continue;
|
|
|
|
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
|
|
index 68aa174be12d71..f71f6ff3e2b0f7 100644
|
|
--- a/sound/usb/endpoint.c
|
|
+++ b/sound/usb/endpoint.c
|
|
@@ -926,14 +926,21 @@ static int endpoint_set_interface(struct snd_usb_audio *chip,
|
|
{
|
|
int altset = set ? ep->altsetting : 0;
|
|
int err;
|
|
+ int retries = 0;
|
|
+ const int max_retries = 5;
|
|
|
|
if (ep->iface_ref->altset == altset)
|
|
return 0;
|
|
|
|
usb_audio_dbg(chip, "Setting usb interface %d:%d for EP 0x%x\n",
|
|
ep->iface, altset, ep->ep_num);
|
|
+retry:
|
|
err = usb_set_interface(chip->dev, ep->iface, altset);
|
|
if (err < 0) {
|
|
+ if (err == -EPROTO && ++retries <= max_retries) {
|
|
+ msleep(5 * (1 << (retries - 1)));
|
|
+ goto retry;
|
|
+ }
|
|
usb_audio_err_ratelimited(
|
|
chip, "%d:%d: usb_set_interface failed (%d)\n",
|
|
ep->iface, altset, err);
|
|
diff --git a/sound/usb/format.c b/sound/usb/format.c
|
|
index 3b3a5ea6fcbfc0..f33d25a4e4cc7c 100644
|
|
--- a/sound/usb/format.c
|
|
+++ b/sound/usb/format.c
|
|
@@ -263,7 +263,8 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
|
|
}
|
|
|
|
/* Jabra Evolve 65 headset */
|
|
- if (chip->usb_id == USB_ID(0x0b0e, 0x030b)) {
|
|
+ if (chip->usb_id == USB_ID(0x0b0e, 0x030b) ||
|
|
+ chip->usb_id == USB_ID(0x0b0e, 0x030c)) {
|
|
/* only 48kHz for playback while keeping 16kHz for capture */
|
|
if (fp->nr_rates != 1)
|
|
return set_fixed_rate(fp, 48000, SNDRV_PCM_RATE_48000);
|
|
diff --git a/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c b/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c
|
|
new file mode 100644
|
|
index 00000000000000..7526de3790814c
|
|
--- /dev/null
|
|
+++ b/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c
|
|
@@ -0,0 +1,107 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+#include "bpf/libbpf.h"
|
|
+#include "changes_pkt_data_freplace.skel.h"
|
|
+#include "changes_pkt_data.skel.h"
|
|
+#include <test_progs.h>
|
|
+
|
|
+static void print_verifier_log(const char *log)
|
|
+{
|
|
+ if (env.verbosity >= VERBOSE_VERY)
|
|
+ fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log);
|
|
+}
|
|
+
|
|
+static void test_aux(const char *main_prog_name,
|
|
+ const char *to_be_replaced,
|
|
+ const char *replacement,
|
|
+ bool expect_load)
|
|
+{
|
|
+ struct changes_pkt_data_freplace *freplace = NULL;
|
|
+ struct bpf_program *freplace_prog = NULL;
|
|
+ struct bpf_program *main_prog = NULL;
|
|
+ LIBBPF_OPTS(bpf_object_open_opts, opts);
|
|
+ struct changes_pkt_data *main = NULL;
|
|
+ char log[16*1024];
|
|
+ int err;
|
|
+
|
|
+ opts.kernel_log_buf = log;
|
|
+ opts.kernel_log_size = sizeof(log);
|
|
+ if (env.verbosity >= VERBOSE_SUPER)
|
|
+ opts.kernel_log_level = 1 | 2 | 4;
|
|
+ main = changes_pkt_data__open_opts(&opts);
|
|
+ if (!ASSERT_OK_PTR(main, "changes_pkt_data__open"))
|
|
+ goto out;
|
|
+ main_prog = bpf_object__find_program_by_name(main->obj, main_prog_name);
|
|
+ if (!ASSERT_OK_PTR(main_prog, "main_prog"))
|
|
+ goto out;
|
|
+ bpf_program__set_autoload(main_prog, true);
|
|
+ err = changes_pkt_data__load(main);
|
|
+ print_verifier_log(log);
|
|
+ if (!ASSERT_OK(err, "changes_pkt_data__load"))
|
|
+ goto out;
|
|
+ freplace = changes_pkt_data_freplace__open_opts(&opts);
|
|
+ if (!ASSERT_OK_PTR(freplace, "changes_pkt_data_freplace__open"))
|
|
+ goto out;
|
|
+ freplace_prog = bpf_object__find_program_by_name(freplace->obj, replacement);
|
|
+ if (!ASSERT_OK_PTR(freplace_prog, "freplace_prog"))
|
|
+ goto out;
|
|
+ bpf_program__set_autoload(freplace_prog, true);
|
|
+ bpf_program__set_autoattach(freplace_prog, true);
|
|
+ bpf_program__set_attach_target(freplace_prog,
|
|
+ bpf_program__fd(main_prog),
|
|
+ to_be_replaced);
|
|
+ err = changes_pkt_data_freplace__load(freplace);
|
|
+ print_verifier_log(log);
|
|
+ if (expect_load) {
|
|
+ ASSERT_OK(err, "changes_pkt_data_freplace__load");
|
|
+ } else {
|
|
+ ASSERT_ERR(err, "changes_pkt_data_freplace__load");
|
|
+ ASSERT_HAS_SUBSTR(log, "Extension program changes packet data", "error log");
|
|
+ }
|
|
+
|
|
+out:
|
|
+ changes_pkt_data_freplace__destroy(freplace);
|
|
+ changes_pkt_data__destroy(main);
|
|
+}
|
|
+
|
|
+/* There are two global subprograms in both changes_pkt_data.skel.h:
|
|
+ * - one changes packet data;
|
|
+ * - another does not.
|
|
+ * It is ok to freplace subprograms that change packet data with those
|
|
+ * that either do or do not. It is only ok to freplace subprograms
|
|
+ * that do not change packet data with those that do not as well.
|
|
+ * The below tests check outcomes for each combination of such freplace.
|
|
+ * Also test a case when main subprogram itself is replaced and is a single
|
|
+ * subprogram in a program.
|
|
+ */
|
|
+void test_changes_pkt_data_freplace(void)
|
|
+{
|
|
+ struct {
|
|
+ const char *main;
|
|
+ const char *to_be_replaced;
|
|
+ bool changes;
|
|
+ } mains[] = {
|
|
+ { "main_with_subprogs", "changes_pkt_data", true },
|
|
+ { "main_with_subprogs", "does_not_change_pkt_data", false },
|
|
+ { "main_changes", "main_changes", true },
|
|
+ { "main_does_not_change", "main_does_not_change", false },
|
|
+ };
|
|
+ struct {
|
|
+ const char *func;
|
|
+ bool changes;
|
|
+ } replacements[] = {
|
|
+ { "changes_pkt_data", true },
|
|
+ { "does_not_change_pkt_data", false }
|
|
+ };
|
|
+ char buf[64];
|
|
+
|
|
+ for (int i = 0; i < ARRAY_SIZE(mains); ++i) {
|
|
+ for (int j = 0; j < ARRAY_SIZE(replacements); ++j) {
|
|
+ snprintf(buf, sizeof(buf), "%s_with_%s",
|
|
+ mains[i].to_be_replaced, replacements[j].func);
|
|
+ if (!test__start_subtest(buf))
|
|
+ continue;
|
|
+ test_aux(mains[i].main, mains[i].to_be_replaced, replacements[j].func,
|
|
+ mains[i].changes || !replacements[j].changes);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/tools/testing/selftests/bpf/progs/changes_pkt_data.c b/tools/testing/selftests/bpf/progs/changes_pkt_data.c
|
|
new file mode 100644
|
|
index 00000000000000..43cada48b28ad4
|
|
--- /dev/null
|
|
+++ b/tools/testing/selftests/bpf/progs/changes_pkt_data.c
|
|
@@ -0,0 +1,39 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+
|
|
+#include <linux/bpf.h>
|
|
+#include <bpf/bpf_helpers.h>
|
|
+
|
|
+__noinline
|
|
+long changes_pkt_data(struct __sk_buff *sk)
|
|
+{
|
|
+ return bpf_skb_pull_data(sk, 0);
|
|
+}
|
|
+
|
|
+__noinline __weak
|
|
+long does_not_change_pkt_data(struct __sk_buff *sk)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+SEC("?tc")
|
|
+int main_with_subprogs(struct __sk_buff *sk)
|
|
+{
|
|
+ changes_pkt_data(sk);
|
|
+ does_not_change_pkt_data(sk);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+SEC("?tc")
|
|
+int main_changes(struct __sk_buff *sk)
|
|
+{
|
|
+ bpf_skb_pull_data(sk, 0);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+SEC("?tc")
|
|
+int main_does_not_change(struct __sk_buff *sk)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+char _license[] SEC("license") = "GPL";
|
|
diff --git a/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c b/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c
|
|
new file mode 100644
|
|
index 00000000000000..f9a622705f1b3b
|
|
--- /dev/null
|
|
+++ b/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c
|
|
@@ -0,0 +1,18 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+
|
|
+#include <linux/bpf.h>
|
|
+#include <bpf/bpf_helpers.h>
|
|
+
|
|
+SEC("?freplace")
|
|
+long changes_pkt_data(struct __sk_buff *sk)
|
|
+{
|
|
+ return bpf_skb_pull_data(sk, 0);
|
|
+}
|
|
+
|
|
+SEC("?freplace")
|
|
+long does_not_change_pkt_data(struct __sk_buff *sk)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+char _license[] SEC("license") = "GPL";
|
|
diff --git a/tools/testing/selftests/bpf/progs/verifier_sock.c b/tools/testing/selftests/bpf/progs/verifier_sock.c
|
|
index ee76b51005abe7..3c8f6646e33dae 100644
|
|
--- a/tools/testing/selftests/bpf/progs/verifier_sock.c
|
|
+++ b/tools/testing/selftests/bpf/progs/verifier_sock.c
|
|
@@ -50,6 +50,13 @@ struct {
|
|
__uint(map_flags, BPF_F_NO_PREALLOC);
|
|
} sk_storage_map SEC(".maps");
|
|
|
|
+struct {
|
|
+ __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
|
|
+ __uint(max_entries, 1);
|
|
+ __uint(key_size, sizeof(__u32));
|
|
+ __uint(value_size, sizeof(__u32));
|
|
+} jmp_table SEC(".maps");
|
|
+
|
|
SEC("cgroup/skb")
|
|
__description("skb->sk: no NULL check")
|
|
__failure __msg("invalid mem access 'sock_common_or_null'")
|
|
@@ -977,4 +984,53 @@ l1_%=: r0 = *(u8*)(r7 + 0); \
|
|
: __clobber_all);
|
|
}
|
|
|
|
+__noinline
|
|
+long skb_pull_data2(struct __sk_buff *sk, __u32 len)
|
|
+{
|
|
+ return bpf_skb_pull_data(sk, len);
|
|
+}
|
|
+
|
|
+__noinline
|
|
+long skb_pull_data1(struct __sk_buff *sk, __u32 len)
|
|
+{
|
|
+ return skb_pull_data2(sk, len);
|
|
+}
|
|
+
|
|
+/* global function calls bpf_skb_pull_data(), which invalidates packet
|
|
+ * pointers established before global function call.
|
|
+ */
|
|
+SEC("tc")
|
|
+__failure __msg("invalid mem access")
|
|
+int invalidate_pkt_pointers_from_global_func(struct __sk_buff *sk)
|
|
+{
|
|
+ int *p = (void *)(long)sk->data;
|
|
+
|
|
+ if ((void *)(p + 1) > (void *)(long)sk->data_end)
|
|
+ return TCX_DROP;
|
|
+ skb_pull_data1(sk, 0);
|
|
+ *p = 42; /* this is unsafe */
|
|
+ return TCX_PASS;
|
|
+}
|
|
+
|
|
+__noinline
|
|
+int tail_call(struct __sk_buff *sk)
|
|
+{
|
|
+ bpf_tail_call_static(sk, &jmp_table, 0);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Tail calls invalidate packet pointers. */
|
|
+SEC("tc")
|
|
+__failure __msg("invalid mem access")
|
|
+int invalidate_pkt_pointers_by_tail_call(struct __sk_buff *sk)
|
|
+{
|
|
+ int *p = (void *)(long)sk->data;
|
|
+
|
|
+ if ((void *)(p + 1) > (void *)(long)sk->data_end)
|
|
+ return TCX_DROP;
|
|
+ tail_call(sk);
|
|
+ *p = 42; /* this is unsafe */
|
|
+ return TCX_PASS;
|
|
+}
|
|
+
|
|
char _license[] SEC("license") = "GPL";
|