mirror of
https://github.com/Fishwaldo/build.git
synced 2025-07-12 07:58:47 +00:00
* add upstream patches * Add more patches Co-authored-by: Igor Pecovnik <igor.pecovnik@gmail.com>
7730 lines
231 KiB
Diff
7730 lines
231 KiB
Diff
diff --git a/Makefile b/Makefile
|
|
index 4801cc25e3472..cb76f64abb6da 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,7 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
VERSION = 5
|
|
PATCHLEVEL = 10
|
|
-SUBLEVEL = 27
|
|
+SUBLEVEL = 28
|
|
EXTRAVERSION =
|
|
NAME = Dare mighty things
|
|
|
|
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
|
|
index 6aabf1eced31e..afdad76078506 100644
|
|
--- a/arch/arm64/mm/mmu.c
|
|
+++ b/arch/arm64/mm/mmu.c
|
|
@@ -1447,14 +1447,30 @@ static void __remove_pgd_mapping(pgd_t *pgdir, unsigned long start, u64 size)
|
|
|
|
static bool inside_linear_region(u64 start, u64 size)
|
|
{
|
|
+ u64 start_linear_pa = __pa(_PAGE_OFFSET(vabits_actual));
|
|
+ u64 end_linear_pa = __pa(PAGE_END - 1);
|
|
+
|
|
+ if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
|
|
+ /*
|
|
+ * Check for a wrap, it is possible because of randomized linear
|
|
+ * mapping the start physical address is actually bigger than
|
|
+ * the end physical address. In this case set start to zero
|
|
+ * because [0, end_linear_pa] range must still be able to cover
|
|
+ * all addressable physical addresses.
|
|
+ */
|
|
+ if (start_linear_pa > end_linear_pa)
|
|
+ start_linear_pa = 0;
|
|
+ }
|
|
+
|
|
+ WARN_ON(start_linear_pa > end_linear_pa);
|
|
+
|
|
/*
|
|
* Linear mapping region is the range [PAGE_OFFSET..(PAGE_END - 1)]
|
|
* accommodating both its ends but excluding PAGE_END. Max physical
|
|
* range which can be mapped inside this linear mapping range, must
|
|
* also be derived from its end points.
|
|
*/
|
|
- return start >= __pa(_PAGE_OFFSET(vabits_actual)) &&
|
|
- (start + size - 1) <= __pa(PAGE_END - 1);
|
|
+ return start >= start_linear_pa && (start + size - 1) <= end_linear_pa;
|
|
}
|
|
|
|
int arch_add_memory(int nid, u64 start, u64 size,
|
|
diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h
|
|
index 824b2c9da75bd..f944062c9d990 100644
|
|
--- a/arch/riscv/include/asm/uaccess.h
|
|
+++ b/arch/riscv/include/asm/uaccess.h
|
|
@@ -306,7 +306,9 @@ do { \
|
|
* data types like structures or arrays.
|
|
*
|
|
* @ptr must have pointer-to-simple-variable type, and @x must be assignable
|
|
- * to the result of dereferencing @ptr.
|
|
+ * to the result of dereferencing @ptr. The value of @x is copied to avoid
|
|
+ * re-ordering where @x is evaluated inside the block that enables user-space
|
|
+ * access (thus bypassing user space protection if @x is a function).
|
|
*
|
|
* Caller must check the pointer with access_ok() before calling this
|
|
* function.
|
|
@@ -316,12 +318,13 @@ do { \
|
|
#define __put_user(x, ptr) \
|
|
({ \
|
|
__typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
|
|
+ __typeof__(*__gu_ptr) __val = (x); \
|
|
long __pu_err = 0; \
|
|
\
|
|
__chk_user_ptr(__gu_ptr); \
|
|
\
|
|
__enable_user_access(); \
|
|
- __put_user_nocheck(x, __gu_ptr, __pu_err); \
|
|
+ __put_user_nocheck(__val, __gu_ptr, __pu_err); \
|
|
__disable_user_access(); \
|
|
\
|
|
__pu_err; \
|
|
diff --git a/arch/s390/include/asm/vdso/data.h b/arch/s390/include/asm/vdso/data.h
|
|
index 7b3cdb4a5f481..73ee891426662 100644
|
|
--- a/arch/s390/include/asm/vdso/data.h
|
|
+++ b/arch/s390/include/asm/vdso/data.h
|
|
@@ -6,7 +6,7 @@
|
|
#include <vdso/datapage.h>
|
|
|
|
struct arch_vdso_data {
|
|
- __u64 tod_steering_delta;
|
|
+ __s64 tod_steering_delta;
|
|
__u64 tod_steering_end;
|
|
};
|
|
|
|
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
|
|
index 0ac30ee2c6330..b6517453fa234 100644
|
|
--- a/arch/s390/kernel/time.c
|
|
+++ b/arch/s390/kernel/time.c
|
|
@@ -398,6 +398,7 @@ static void clock_sync_global(unsigned long long delta)
|
|
tod_steering_delta);
|
|
tod_steering_end = now + (abs(tod_steering_delta) << 15);
|
|
vdso_data->arch_data.tod_steering_end = tod_steering_end;
|
|
+ vdso_data->arch_data.tod_steering_delta = tod_steering_delta;
|
|
|
|
/* Update LPAR offset. */
|
|
if (ptff_query(PTFF_QTO) && ptff(&qto, sizeof(qto), PTFF_QTO) == 0)
|
|
diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
|
|
index c0538f82c9a22..57ef2094af93e 100644
|
|
--- a/arch/x86/include/asm/smp.h
|
|
+++ b/arch/x86/include/asm/smp.h
|
|
@@ -132,6 +132,7 @@ void native_play_dead(void);
|
|
void play_dead_common(void);
|
|
void wbinvd_on_cpu(int cpu);
|
|
int wbinvd_on_all_cpus(void);
|
|
+bool wakeup_cpu0(void);
|
|
|
|
void native_smp_send_reschedule(int cpu);
|
|
void native_send_call_func_ipi(const struct cpumask *mask);
|
|
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
|
|
index 7bdc0239a9435..14cd3186dc77d 100644
|
|
--- a/arch/x86/kernel/acpi/boot.c
|
|
+++ b/arch/x86/kernel/acpi/boot.c
|
|
@@ -1554,10 +1554,18 @@ void __init acpi_boot_table_init(void)
|
|
/*
|
|
* Initialize the ACPI boot-time table parser.
|
|
*/
|
|
- if (acpi_table_init()) {
|
|
+ if (acpi_locate_initial_tables())
|
|
disable_acpi();
|
|
- return;
|
|
- }
|
|
+ else
|
|
+ acpi_reserve_initial_tables();
|
|
+}
|
|
+
|
|
+int __init early_acpi_boot_init(void)
|
|
+{
|
|
+ if (acpi_disabled)
|
|
+ return 1;
|
|
+
|
|
+ acpi_table_init_complete();
|
|
|
|
acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
|
|
|
|
@@ -1570,18 +1578,9 @@ void __init acpi_boot_table_init(void)
|
|
} else {
|
|
printk(KERN_WARNING PREFIX "Disabling ACPI support\n");
|
|
disable_acpi();
|
|
- return;
|
|
+ return 1;
|
|
}
|
|
}
|
|
-}
|
|
-
|
|
-int __init early_acpi_boot_init(void)
|
|
-{
|
|
- /*
|
|
- * If acpi_disabled, bail out
|
|
- */
|
|
- if (acpi_disabled)
|
|
- return 1;
|
|
|
|
/*
|
|
* Process the Multiple APIC Description Table (MADT), if present
|
|
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
|
|
index 84f581c91db45..d23795057c4f1 100644
|
|
--- a/arch/x86/kernel/setup.c
|
|
+++ b/arch/x86/kernel/setup.c
|
|
@@ -1051,6 +1051,9 @@ void __init setup_arch(char **cmdline_p)
|
|
|
|
cleanup_highmap();
|
|
|
|
+ /* Look for ACPI tables and reserve memory occupied by them. */
|
|
+ acpi_boot_table_init();
|
|
+
|
|
memblock_set_current_limit(ISA_END_ADDRESS);
|
|
e820__memblock_setup();
|
|
|
|
@@ -1136,11 +1139,6 @@ void __init setup_arch(char **cmdline_p)
|
|
|
|
early_platform_quirks();
|
|
|
|
- /*
|
|
- * Parse the ACPI tables for possible boot-time SMP configuration.
|
|
- */
|
|
- acpi_boot_table_init();
|
|
-
|
|
early_acpi_boot_init();
|
|
|
|
initmem_init();
|
|
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
|
|
index c65642c10aaea..5ea5f964f0a97 100644
|
|
--- a/arch/x86/kernel/smpboot.c
|
|
+++ b/arch/x86/kernel/smpboot.c
|
|
@@ -1655,7 +1655,7 @@ void play_dead_common(void)
|
|
local_irq_disable();
|
|
}
|
|
|
|
-static bool wakeup_cpu0(void)
|
|
+bool wakeup_cpu0(void)
|
|
{
|
|
if (smp_processor_id() == 0 && enable_start_cpu0)
|
|
return true;
|
|
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
|
|
index 1008cc6cb66c5..da6ce73c10bb7 100644
|
|
--- a/arch/x86/kvm/svm/nested.c
|
|
+++ b/arch/x86/kvm/svm/nested.c
|
|
@@ -246,11 +246,18 @@ static bool nested_vmcb_check_controls(struct vmcb_control_area *control)
|
|
return true;
|
|
}
|
|
|
|
-static bool nested_vmcb_checks(struct vcpu_svm *svm, struct vmcb *vmcb12)
|
|
+static bool nested_vmcb_check_save(struct vcpu_svm *svm, struct vmcb *vmcb12)
|
|
{
|
|
struct kvm_vcpu *vcpu = &svm->vcpu;
|
|
bool vmcb12_lma;
|
|
|
|
+ /*
|
|
+ * FIXME: these should be done after copying the fields,
|
|
+ * to avoid TOC/TOU races. For these save area checks
|
|
+ * the possible damage is limited since kvm_set_cr0 and
|
|
+ * kvm_set_cr4 handle failure; EFER_SVME is an exception
|
|
+ * so it is force-set later in nested_prepare_vmcb_save.
|
|
+ */
|
|
if ((vmcb12->save.efer & EFER_SVME) == 0)
|
|
return false;
|
|
|
|
@@ -271,7 +278,7 @@ static bool nested_vmcb_checks(struct vcpu_svm *svm, struct vmcb *vmcb12)
|
|
if (kvm_valid_cr4(&svm->vcpu, vmcb12->save.cr4))
|
|
return false;
|
|
|
|
- return nested_vmcb_check_controls(&vmcb12->control);
|
|
+ return true;
|
|
}
|
|
|
|
static void load_nested_vmcb_control(struct vcpu_svm *svm,
|
|
@@ -396,7 +403,14 @@ static void nested_prepare_vmcb_save(struct vcpu_svm *svm, struct vmcb *vmcb12)
|
|
svm->vmcb->save.gdtr = vmcb12->save.gdtr;
|
|
svm->vmcb->save.idtr = vmcb12->save.idtr;
|
|
kvm_set_rflags(&svm->vcpu, vmcb12->save.rflags);
|
|
- svm_set_efer(&svm->vcpu, vmcb12->save.efer);
|
|
+
|
|
+ /*
|
|
+ * Force-set EFER_SVME even though it is checked earlier on the
|
|
+ * VMCB12, because the guest can flip the bit between the check
|
|
+ * and now. Clearing EFER_SVME would call svm_free_nested.
|
|
+ */
|
|
+ svm_set_efer(&svm->vcpu, vmcb12->save.efer | EFER_SVME);
|
|
+
|
|
svm_set_cr0(&svm->vcpu, vmcb12->save.cr0);
|
|
svm_set_cr4(&svm->vcpu, vmcb12->save.cr4);
|
|
svm->vmcb->save.cr2 = svm->vcpu.arch.cr2 = vmcb12->save.cr2;
|
|
@@ -454,7 +468,6 @@ int enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb12_gpa,
|
|
int ret;
|
|
|
|
svm->nested.vmcb12_gpa = vmcb12_gpa;
|
|
- load_nested_vmcb_control(svm, &vmcb12->control);
|
|
nested_prepare_vmcb_save(svm, vmcb12);
|
|
nested_prepare_vmcb_control(svm);
|
|
|
|
@@ -501,7 +514,10 @@ int nested_svm_vmrun(struct vcpu_svm *svm)
|
|
if (WARN_ON_ONCE(!svm->nested.initialized))
|
|
return -EINVAL;
|
|
|
|
- if (!nested_vmcb_checks(svm, vmcb12)) {
|
|
+ load_nested_vmcb_control(svm, &vmcb12->control);
|
|
+
|
|
+ if (!nested_vmcb_check_save(svm, vmcb12) ||
|
|
+ !nested_vmcb_check_controls(&svm->nested.ctl)) {
|
|
vmcb12->control.exit_code = SVM_EXIT_ERR;
|
|
vmcb12->control.exit_code_hi = 0;
|
|
vmcb12->control.exit_info_1 = 0;
|
|
@@ -1205,6 +1221,8 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
|
|
*/
|
|
if (!(save->cr0 & X86_CR0_PG))
|
|
goto out_free;
|
|
+ if (!(save->efer & EFER_SVME))
|
|
+ goto out_free;
|
|
|
|
/*
|
|
* All checks done, we can enter guest mode. L1 control fields
|
|
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
|
|
index 796506dcfc42e..023ac12f54a29 100644
|
|
--- a/arch/x86/net/bpf_jit_comp.c
|
|
+++ b/arch/x86/net/bpf_jit_comp.c
|
|
@@ -1735,7 +1735,7 @@ static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog,
|
|
* add rsp, 8 // skip eth_type_trans's frame
|
|
* ret // return to its caller
|
|
*/
|
|
-int arch_prepare_bpf_trampoline(void *image, void *image_end,
|
|
+int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end,
|
|
const struct btf_func_model *m, u32 flags,
|
|
struct bpf_tramp_progs *tprogs,
|
|
void *orig_call)
|
|
@@ -1774,6 +1774,15 @@ int arch_prepare_bpf_trampoline(void *image, void *image_end,
|
|
|
|
save_regs(m, &prog, nr_args, stack_size);
|
|
|
|
+ if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
|
+ /* arg1: mov rdi, im */
|
|
+ emit_mov_imm64(&prog, BPF_REG_1, (long) im >> 32, (u32) (long) im);
|
|
+ if (emit_call(&prog, __bpf_tramp_enter, prog)) {
|
|
+ ret = -EINVAL;
|
|
+ goto cleanup;
|
|
+ }
|
|
+ }
|
|
+
|
|
if (fentry->nr_progs)
|
|
if (invoke_bpf(m, &prog, fentry, stack_size))
|
|
return -EINVAL;
|
|
@@ -1792,8 +1801,7 @@ int arch_prepare_bpf_trampoline(void *image, void *image_end,
|
|
}
|
|
|
|
if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
|
- if (fentry->nr_progs || fmod_ret->nr_progs)
|
|
- restore_regs(m, &prog, nr_args, stack_size);
|
|
+ restore_regs(m, &prog, nr_args, stack_size);
|
|
|
|
/* call original function */
|
|
if (emit_call(&prog, orig_call, prog)) {
|
|
@@ -1802,6 +1810,9 @@ int arch_prepare_bpf_trampoline(void *image, void *image_end,
|
|
}
|
|
/* remember return value in a stack for bpf prog to access */
|
|
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -8);
|
|
+ im->ip_after_call = prog;
|
|
+ memcpy(prog, ideal_nops[NOP_ATOMIC5], X86_PATCH_SIZE);
|
|
+ prog += X86_PATCH_SIZE;
|
|
}
|
|
|
|
if (fmod_ret->nr_progs) {
|
|
@@ -1832,9 +1843,17 @@ int arch_prepare_bpf_trampoline(void *image, void *image_end,
|
|
* the return value is only updated on the stack and still needs to be
|
|
* restored to R0.
|
|
*/
|
|
- if (flags & BPF_TRAMP_F_CALL_ORIG)
|
|
+ if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
|
+ im->ip_epilogue = prog;
|
|
+ /* arg1: mov rdi, im */
|
|
+ emit_mov_imm64(&prog, BPF_REG_1, (long) im >> 32, (u32) (long) im);
|
|
+ if (emit_call(&prog, __bpf_tramp_exit, prog)) {
|
|
+ ret = -EINVAL;
|
|
+ goto cleanup;
|
|
+ }
|
|
/* restore original return value back into RAX */
|
|
emit_ldx(&prog, BPF_DW, BPF_REG_0, BPF_REG_FP, -8);
|
|
+ }
|
|
|
|
EMIT1(0x5B); /* pop rbx */
|
|
EMIT1(0xC9); /* leave */
|
|
diff --git a/arch/xtensa/kernel/coprocessor.S b/arch/xtensa/kernel/coprocessor.S
|
|
index c426b846beefb..45cc0ae0af6f9 100644
|
|
--- a/arch/xtensa/kernel/coprocessor.S
|
|
+++ b/arch/xtensa/kernel/coprocessor.S
|
|
@@ -99,37 +99,6 @@
|
|
LOAD_CP_REGS_TAB(6)
|
|
LOAD_CP_REGS_TAB(7)
|
|
|
|
-/*
|
|
- * coprocessor_flush(struct thread_info*, index)
|
|
- * a2 a3
|
|
- *
|
|
- * Save coprocessor registers for coprocessor 'index'.
|
|
- * The register values are saved to or loaded from the coprocessor area
|
|
- * inside the task_info structure.
|
|
- *
|
|
- * Note that this function doesn't update the coprocessor_owner information!
|
|
- *
|
|
- */
|
|
-
|
|
-ENTRY(coprocessor_flush)
|
|
-
|
|
- /* reserve 4 bytes on stack to save a0 */
|
|
- abi_entry(4)
|
|
-
|
|
- s32i a0, a1, 0
|
|
- movi a0, .Lsave_cp_regs_jump_table
|
|
- addx8 a3, a3, a0
|
|
- l32i a4, a3, 4
|
|
- l32i a3, a3, 0
|
|
- add a2, a2, a4
|
|
- beqz a3, 1f
|
|
- callx0 a3
|
|
-1: l32i a0, a1, 0
|
|
-
|
|
- abi_ret(4)
|
|
-
|
|
-ENDPROC(coprocessor_flush)
|
|
-
|
|
/*
|
|
* Entry condition:
|
|
*
|
|
@@ -245,6 +214,39 @@ ENTRY(fast_coprocessor)
|
|
|
|
ENDPROC(fast_coprocessor)
|
|
|
|
+ .text
|
|
+
|
|
+/*
|
|
+ * coprocessor_flush(struct thread_info*, index)
|
|
+ * a2 a3
|
|
+ *
|
|
+ * Save coprocessor registers for coprocessor 'index'.
|
|
+ * The register values are saved to or loaded from the coprocessor area
|
|
+ * inside the task_info structure.
|
|
+ *
|
|
+ * Note that this function doesn't update the coprocessor_owner information!
|
|
+ *
|
|
+ */
|
|
+
|
|
+ENTRY(coprocessor_flush)
|
|
+
|
|
+ /* reserve 4 bytes on stack to save a0 */
|
|
+ abi_entry(4)
|
|
+
|
|
+ s32i a0, a1, 0
|
|
+ movi a0, .Lsave_cp_regs_jump_table
|
|
+ addx8 a3, a3, a0
|
|
+ l32i a4, a3, 4
|
|
+ l32i a3, a3, 0
|
|
+ add a2, a2, a4
|
|
+ beqz a3, 1f
|
|
+ callx0 a3
|
|
+1: l32i a0, a1, 0
|
|
+
|
|
+ abi_ret(4)
|
|
+
|
|
+ENDPROC(coprocessor_flush)
|
|
+
|
|
.data
|
|
|
|
ENTRY(coprocessor_owner)
|
|
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
|
|
index 7666408ce12a4..95a74890c7e99 100644
|
|
--- a/arch/xtensa/mm/fault.c
|
|
+++ b/arch/xtensa/mm/fault.c
|
|
@@ -112,8 +112,11 @@ good_area:
|
|
*/
|
|
fault = handle_mm_fault(vma, address, flags, regs);
|
|
|
|
- if (fault_signal_pending(fault, regs))
|
|
+ if (fault_signal_pending(fault, regs)) {
|
|
+ if (!user_mode(regs))
|
|
+ goto bad_page_fault;
|
|
return;
|
|
+ }
|
|
|
|
if (unlikely(fault & VM_FAULT_ERROR)) {
|
|
if (fault & VM_FAULT_OOM)
|
|
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
|
|
index f66236cff69b0..4e303964f7e7f 100644
|
|
--- a/drivers/acpi/processor_idle.c
|
|
+++ b/drivers/acpi/processor_idle.c
|
|
@@ -29,6 +29,7 @@
|
|
*/
|
|
#ifdef CONFIG_X86
|
|
#include <asm/apic.h>
|
|
+#include <asm/cpu.h>
|
|
#endif
|
|
|
|
#define ACPI_PROCESSOR_CLASS "processor"
|
|
@@ -542,6 +543,12 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
|
|
wait_for_freeze();
|
|
} else
|
|
return -ENODEV;
|
|
+
|
|
+#if defined(CONFIG_X86) && defined(CONFIG_HOTPLUG_CPU)
|
|
+ /* If NMI wants to wake up CPU0, start CPU0. */
|
|
+ if (wakeup_cpu0())
|
|
+ start_cpu0();
|
|
+#endif
|
|
}
|
|
|
|
/* Never reached */
|
|
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
|
|
index e48690a006a4e..9d581045acff0 100644
|
|
--- a/drivers/acpi/tables.c
|
|
+++ b/drivers/acpi/tables.c
|
|
@@ -780,7 +780,7 @@ acpi_status acpi_os_table_override(struct acpi_table_header *existing_table,
|
|
}
|
|
|
|
/*
|
|
- * acpi_table_init()
|
|
+ * acpi_locate_initial_tables()
|
|
*
|
|
* find RSDP, find and checksum SDT/XSDT.
|
|
* checksum all tables, print SDT/XSDT
|
|
@@ -788,7 +788,7 @@ acpi_status acpi_os_table_override(struct acpi_table_header *existing_table,
|
|
* result: sdt_entry[] is initialized
|
|
*/
|
|
|
|
-int __init acpi_table_init(void)
|
|
+int __init acpi_locate_initial_tables(void)
|
|
{
|
|
acpi_status status;
|
|
|
|
@@ -803,9 +803,45 @@ int __init acpi_table_init(void)
|
|
status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
|
|
if (ACPI_FAILURE(status))
|
|
return -EINVAL;
|
|
- acpi_table_initrd_scan();
|
|
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void __init acpi_reserve_initial_tables(void)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < ACPI_MAX_TABLES; i++) {
|
|
+ struct acpi_table_desc *table_desc = &initial_tables[i];
|
|
+ u64 start = table_desc->address;
|
|
+ u64 size = table_desc->length;
|
|
+
|
|
+ if (!start || !size)
|
|
+ break;
|
|
+
|
|
+ pr_info("Reserving %4s table memory at [mem 0x%llx-0x%llx]\n",
|
|
+ table_desc->signature.ascii, start, start + size - 1);
|
|
+
|
|
+ memblock_reserve(start, size);
|
|
+ }
|
|
+}
|
|
+
|
|
+void __init acpi_table_init_complete(void)
|
|
+{
|
|
+ acpi_table_initrd_scan();
|
|
check_multiple_madt();
|
|
+}
|
|
+
|
|
+int __init acpi_table_init(void)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = acpi_locate_initial_tables();
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ acpi_table_init_complete();
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
|
|
index 3c94ebc8d4bb0..43130d64e213d 100644
|
|
--- a/drivers/base/dd.c
|
|
+++ b/drivers/base/dd.c
|
|
@@ -97,6 +97,9 @@ static void deferred_probe_work_func(struct work_struct *work)
|
|
|
|
get_device(dev);
|
|
|
|
+ kfree(dev->p->deferred_probe_reason);
|
|
+ dev->p->deferred_probe_reason = NULL;
|
|
+
|
|
/*
|
|
* Drop the mutex while probing each device; the probe path may
|
|
* manipulate the deferred list
|
|
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
|
|
index 5ef67bacb585e..d6d73ff94e88f 100644
|
|
--- a/drivers/base/power/runtime.c
|
|
+++ b/drivers/base/power/runtime.c
|
|
@@ -1690,8 +1690,8 @@ void pm_runtime_get_suppliers(struct device *dev)
|
|
device_links_read_lock_held())
|
|
if (link->flags & DL_FLAG_PM_RUNTIME) {
|
|
link->supplier_preactivated = true;
|
|
- refcount_inc(&link->rpm_active);
|
|
pm_runtime_get_sync(link->supplier);
|
|
+ refcount_inc(&link->rpm_active);
|
|
}
|
|
|
|
device_links_read_unlock(idx);
|
|
@@ -1704,6 +1704,8 @@ void pm_runtime_get_suppliers(struct device *dev)
|
|
void pm_runtime_put_suppliers(struct device *dev)
|
|
{
|
|
struct device_link *link;
|
|
+ unsigned long flags;
|
|
+ bool put;
|
|
int idx;
|
|
|
|
idx = device_links_read_lock();
|
|
@@ -1712,7 +1714,11 @@ void pm_runtime_put_suppliers(struct device *dev)
|
|
device_links_read_lock_held())
|
|
if (link->supplier_preactivated) {
|
|
link->supplier_preactivated = false;
|
|
- if (refcount_dec_not_one(&link->rpm_active))
|
|
+ spin_lock_irqsave(&dev->power.lock, flags);
|
|
+ put = pm_runtime_status_suspended(dev) &&
|
|
+ refcount_dec_not_one(&link->rpm_active);
|
|
+ spin_unlock_irqrestore(&dev->power.lock, flags);
|
|
+ if (put)
|
|
pm_runtime_put(link->supplier);
|
|
}
|
|
|
|
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c
|
|
index 0a6438cbb3f30..e7a9561a826d3 100644
|
|
--- a/drivers/extcon/extcon.c
|
|
+++ b/drivers/extcon/extcon.c
|
|
@@ -1241,6 +1241,7 @@ int extcon_dev_register(struct extcon_dev *edev)
|
|
sizeof(*edev->nh), GFP_KERNEL);
|
|
if (!edev->nh) {
|
|
ret = -ENOMEM;
|
|
+ device_unregister(&edev->dev);
|
|
goto err_dev;
|
|
}
|
|
|
|
diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c
|
|
index 5fd6a60b67410..88ed971e32c0d 100644
|
|
--- a/drivers/firewire/nosy.c
|
|
+++ b/drivers/firewire/nosy.c
|
|
@@ -346,6 +346,7 @@ nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
struct client *client = file->private_data;
|
|
spinlock_t *client_list_lock = &client->lynx->client_list_lock;
|
|
struct nosy_stats stats;
|
|
+ int ret;
|
|
|
|
switch (cmd) {
|
|
case NOSY_IOC_GET_STATS:
|
|
@@ -360,11 +361,15 @@ nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
return 0;
|
|
|
|
case NOSY_IOC_START:
|
|
+ ret = -EBUSY;
|
|
spin_lock_irq(client_list_lock);
|
|
- list_add_tail(&client->link, &client->lynx->client_list);
|
|
+ if (list_empty(&client->link)) {
|
|
+ list_add_tail(&client->link, &client->lynx->client_list);
|
|
+ ret = 0;
|
|
+ }
|
|
spin_unlock_irq(client_list_lock);
|
|
|
|
- return 0;
|
|
+ return ret;
|
|
|
|
case NOSY_IOC_STOP:
|
|
spin_lock_irq(client_list_lock);
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
|
|
index df110afa97bf4..605d1545274c2 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
|
|
@@ -2223,8 +2223,8 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
|
|
uint64_t eaddr;
|
|
|
|
/* validate the parameters */
|
|
- if (saddr & AMDGPU_GPU_PAGE_MASK || offset & AMDGPU_GPU_PAGE_MASK ||
|
|
- size == 0 || size & AMDGPU_GPU_PAGE_MASK)
|
|
+ if (saddr & ~PAGE_MASK || offset & ~PAGE_MASK ||
|
|
+ size == 0 || size & ~PAGE_MASK)
|
|
return -EINVAL;
|
|
|
|
/* make sure object fit at this offset */
|
|
@@ -2289,8 +2289,8 @@ int amdgpu_vm_bo_replace_map(struct amdgpu_device *adev,
|
|
int r;
|
|
|
|
/* validate the parameters */
|
|
- if (saddr & AMDGPU_GPU_PAGE_MASK || offset & AMDGPU_GPU_PAGE_MASK ||
|
|
- size == 0 || size & AMDGPU_GPU_PAGE_MASK)
|
|
+ if (saddr & ~PAGE_MASK || offset & ~PAGE_MASK ||
|
|
+ size == 0 || size & ~PAGE_MASK)
|
|
return -EINVAL;
|
|
|
|
/* make sure object fit at this offset */
|
|
@@ -2435,7 +2435,7 @@ int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev,
|
|
after->start = eaddr + 1;
|
|
after->last = tmp->last;
|
|
after->offset = tmp->offset;
|
|
- after->offset += after->start - tmp->start;
|
|
+ after->offset += (after->start - tmp->start) << PAGE_SHIFT;
|
|
after->flags = tmp->flags;
|
|
after->bo_va = tmp->bo_va;
|
|
list_add(&after->list, &tmp->bo_va->invalids);
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c b/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c
|
|
index b258a3dae767f..159add0f5aaae 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c
|
|
@@ -155,7 +155,7 @@ static int dbgdev_diq_submit_ib(struct kfd_dbgdev *dbgdev,
|
|
|
|
/* Wait till CP writes sync code: */
|
|
status = amdkfd_fence_wait_timeout(
|
|
- (unsigned int *) rm_state,
|
|
+ rm_state,
|
|
QUEUESTATE__ACTIVE, 1500);
|
|
|
|
kfd_gtt_sa_free(dbgdev->dev, mem_obj);
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
|
|
index c0ae04a08625c..8e5cfb1f8a512 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
|
|
@@ -1167,7 +1167,7 @@ static int start_cpsch(struct device_queue_manager *dqm)
|
|
if (retval)
|
|
goto fail_allocate_vidmem;
|
|
|
|
- dqm->fence_addr = dqm->fence_mem->cpu_ptr;
|
|
+ dqm->fence_addr = (uint64_t *)dqm->fence_mem->cpu_ptr;
|
|
dqm->fence_gpu_addr = dqm->fence_mem->gpu_addr;
|
|
|
|
init_interrupts(dqm);
|
|
@@ -1340,8 +1340,8 @@ out:
|
|
return retval;
|
|
}
|
|
|
|
-int amdkfd_fence_wait_timeout(unsigned int *fence_addr,
|
|
- unsigned int fence_value,
|
|
+int amdkfd_fence_wait_timeout(uint64_t *fence_addr,
|
|
+ uint64_t fence_value,
|
|
unsigned int timeout_ms)
|
|
{
|
|
unsigned long end_jiffies = msecs_to_jiffies(timeout_ms) + jiffies;
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
|
|
index 7351dd195274e..45f8159465544 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
|
|
@@ -192,7 +192,7 @@ struct device_queue_manager {
|
|
uint16_t vmid_pasid[VMID_NUM];
|
|
uint64_t pipelines_addr;
|
|
uint64_t fence_gpu_addr;
|
|
- unsigned int *fence_addr;
|
|
+ uint64_t *fence_addr;
|
|
struct kfd_mem_obj *fence_mem;
|
|
bool active_runlist;
|
|
int sched_policy;
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c
|
|
index 47ee40fbbd86c..c85e4f9d92cf2 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c
|
|
@@ -345,7 +345,7 @@ fail_create_runlist_ib:
|
|
}
|
|
|
|
int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address,
|
|
- uint32_t fence_value)
|
|
+ uint64_t fence_value)
|
|
{
|
|
uint32_t *buffer, size;
|
|
int retval = 0;
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c
|
|
index dfaf771a42e66..e3ba0cd3b6fa7 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c
|
|
@@ -283,7 +283,7 @@ static int pm_unmap_queues_v9(struct packet_manager *pm, uint32_t *buffer,
|
|
}
|
|
|
|
static int pm_query_status_v9(struct packet_manager *pm, uint32_t *buffer,
|
|
- uint64_t fence_address, uint32_t fence_value)
|
|
+ uint64_t fence_address, uint64_t fence_value)
|
|
{
|
|
struct pm4_mes_query_status *packet;
|
|
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_vi.c
|
|
index a852e0d7d804f..08442e7d99440 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_vi.c
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_vi.c
|
|
@@ -263,7 +263,7 @@ static int pm_unmap_queues_vi(struct packet_manager *pm, uint32_t *buffer,
|
|
}
|
|
|
|
static int pm_query_status_vi(struct packet_manager *pm, uint32_t *buffer,
|
|
- uint64_t fence_address, uint32_t fence_value)
|
|
+ uint64_t fence_address, uint64_t fence_value)
|
|
{
|
|
struct pm4_mes_query_status *packet;
|
|
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
|
|
index c77cf23032ac5..057c48a9b53a7 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
|
|
@@ -1006,8 +1006,8 @@ int pqm_get_wave_state(struct process_queue_manager *pqm,
|
|
u32 *ctl_stack_used_size,
|
|
u32 *save_area_used_size);
|
|
|
|
-int amdkfd_fence_wait_timeout(unsigned int *fence_addr,
|
|
- unsigned int fence_value,
|
|
+int amdkfd_fence_wait_timeout(uint64_t *fence_addr,
|
|
+ uint64_t fence_value,
|
|
unsigned int timeout_ms);
|
|
|
|
/* Packet Manager */
|
|
@@ -1043,7 +1043,7 @@ struct packet_manager_funcs {
|
|
uint32_t filter_param, bool reset,
|
|
unsigned int sdma_engine);
|
|
int (*query_status)(struct packet_manager *pm, uint32_t *buffer,
|
|
- uint64_t fence_address, uint32_t fence_value);
|
|
+ uint64_t fence_address, uint64_t fence_value);
|
|
int (*release_mem)(uint64_t gpu_addr, uint32_t *buffer);
|
|
|
|
/* Packet sizes */
|
|
@@ -1065,7 +1065,7 @@ int pm_send_set_resources(struct packet_manager *pm,
|
|
struct scheduling_resources *res);
|
|
int pm_send_runlist(struct packet_manager *pm, struct list_head *dqm_queues);
|
|
int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address,
|
|
- uint32_t fence_value);
|
|
+ uint64_t fence_value);
|
|
|
|
int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type,
|
|
enum kfd_unmap_queues_filter mode,
|
|
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
|
|
index 9bf5ad6d18a22..a1423be70721a 100644
|
|
--- a/drivers/gpu/drm/imx/imx-drm-core.c
|
|
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
|
|
@@ -215,7 +215,7 @@ static int imx_drm_bind(struct device *dev)
|
|
|
|
ret = drmm_mode_config_init(drm);
|
|
if (ret)
|
|
- return ret;
|
|
+ goto err_kms;
|
|
|
|
ret = drm_vblank_init(drm, MAX_CRTC);
|
|
if (ret)
|
|
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
|
|
index b2c8c68b7e261..3a244ef7f30f3 100644
|
|
--- a/drivers/gpu/drm/tegra/dc.c
|
|
+++ b/drivers/gpu/drm/tegra/dc.c
|
|
@@ -2499,22 +2499,18 @@ static int tegra_dc_couple(struct tegra_dc *dc)
|
|
* POWER_CONTROL registers during CRTC enabling.
|
|
*/
|
|
if (dc->soc->coupled_pm && dc->pipe == 1) {
|
|
- u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_CONSUMER;
|
|
- struct device_link *link;
|
|
- struct device *partner;
|
|
+ struct device *companion;
|
|
+ struct tegra_dc *parent;
|
|
|
|
- partner = driver_find_device(dc->dev->driver, NULL, NULL,
|
|
- tegra_dc_match_by_pipe);
|
|
- if (!partner)
|
|
+ companion = driver_find_device(dc->dev->driver, NULL, (const void *)0,
|
|
+ tegra_dc_match_by_pipe);
|
|
+ if (!companion)
|
|
return -EPROBE_DEFER;
|
|
|
|
- link = device_link_add(dc->dev, partner, flags);
|
|
- if (!link) {
|
|
- dev_err(dc->dev, "failed to link controllers\n");
|
|
- return -EINVAL;
|
|
- }
|
|
+ parent = dev_get_drvdata(companion);
|
|
+ dc->client.parent = &parent->client;
|
|
|
|
- dev_dbg(dc->dev, "coupled to %s\n", dev_name(partner));
|
|
+ dev_dbg(dc->dev, "coupled to %s\n", dev_name(companion));
|
|
}
|
|
|
|
return 0;
|
|
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
|
|
index f02a035dda453..7b88261f57bb6 100644
|
|
--- a/drivers/gpu/drm/tegra/sor.c
|
|
+++ b/drivers/gpu/drm/tegra/sor.c
|
|
@@ -3115,6 +3115,12 @@ static int tegra_sor_init(struct host1x_client *client)
|
|
* kernel is possible.
|
|
*/
|
|
if (sor->rst) {
|
|
+ err = pm_runtime_resume_and_get(sor->dev);
|
|
+ if (err < 0) {
|
|
+ dev_err(sor->dev, "failed to get runtime PM: %d\n", err);
|
|
+ return err;
|
|
+ }
|
|
+
|
|
err = reset_control_acquire(sor->rst);
|
|
if (err < 0) {
|
|
dev_err(sor->dev, "failed to acquire SOR reset: %d\n",
|
|
@@ -3148,6 +3154,7 @@ static int tegra_sor_init(struct host1x_client *client)
|
|
}
|
|
|
|
reset_control_release(sor->rst);
|
|
+ pm_runtime_put(sor->dev);
|
|
}
|
|
|
|
err = clk_prepare_enable(sor->clk_safe);
|
|
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
|
|
index 22164300122d5..a2b4463d84802 100644
|
|
--- a/drivers/net/can/Makefile
|
|
+++ b/drivers/net/can/Makefile
|
|
@@ -7,12 +7,7 @@ obj-$(CONFIG_CAN_VCAN) += vcan.o
|
|
obj-$(CONFIG_CAN_VXCAN) += vxcan.o
|
|
obj-$(CONFIG_CAN_SLCAN) += slcan.o
|
|
|
|
-obj-$(CONFIG_CAN_DEV) += can-dev.o
|
|
-can-dev-y += dev.o
|
|
-can-dev-y += rx-offload.o
|
|
-
|
|
-can-dev-$(CONFIG_CAN_LEDS) += led.o
|
|
-
|
|
+obj-y += dev/
|
|
obj-y += rcar/
|
|
obj-y += spi/
|
|
obj-y += usb/
|
|
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
|
|
deleted file mode 100644
|
|
index dc9b4aae3abb6..0000000000000
|
|
--- a/drivers/net/can/dev.c
|
|
+++ /dev/null
|
|
@@ -1,1339 +0,0 @@
|
|
-// SPDX-License-Identifier: GPL-2.0-only
|
|
-/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
|
|
- * Copyright (C) 2006 Andrey Volkov, Varma Electronics
|
|
- * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
|
- */
|
|
-
|
|
-#include <linux/module.h>
|
|
-#include <linux/kernel.h>
|
|
-#include <linux/slab.h>
|
|
-#include <linux/netdevice.h>
|
|
-#include <linux/if_arp.h>
|
|
-#include <linux/workqueue.h>
|
|
-#include <linux/can.h>
|
|
-#include <linux/can/can-ml.h>
|
|
-#include <linux/can/dev.h>
|
|
-#include <linux/can/skb.h>
|
|
-#include <linux/can/netlink.h>
|
|
-#include <linux/can/led.h>
|
|
-#include <linux/of.h>
|
|
-#include <net/rtnetlink.h>
|
|
-
|
|
-#define MOD_DESC "CAN device driver interface"
|
|
-
|
|
-MODULE_DESCRIPTION(MOD_DESC);
|
|
-MODULE_LICENSE("GPL v2");
|
|
-MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
|
|
-
|
|
-/* CAN DLC to real data length conversion helpers */
|
|
-
|
|
-static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
|
|
- 8, 12, 16, 20, 24, 32, 48, 64};
|
|
-
|
|
-/* get data length from can_dlc with sanitized can_dlc */
|
|
-u8 can_dlc2len(u8 can_dlc)
|
|
-{
|
|
- return dlc2len[can_dlc & 0x0F];
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_dlc2len);
|
|
-
|
|
-static const u8 len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
|
- 9, 9, 9, 9, /* 9 - 12 */
|
|
- 10, 10, 10, 10, /* 13 - 16 */
|
|
- 11, 11, 11, 11, /* 17 - 20 */
|
|
- 12, 12, 12, 12, /* 21 - 24 */
|
|
- 13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */
|
|
- 14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */
|
|
- 14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */
|
|
- 15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */
|
|
- 15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
|
|
-
|
|
-/* map the sanitized data length to an appropriate data length code */
|
|
-u8 can_len2dlc(u8 len)
|
|
-{
|
|
- if (unlikely(len > 64))
|
|
- return 0xF;
|
|
-
|
|
- return len2dlc[len];
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_len2dlc);
|
|
-
|
|
-#ifdef CONFIG_CAN_CALC_BITTIMING
|
|
-#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
|
|
-
|
|
-/* Bit-timing calculation derived from:
|
|
- *
|
|
- * Code based on LinCAN sources and H8S2638 project
|
|
- * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
|
- * Copyright 2005 Stanislav Marek
|
|
- * email: pisa@cmp.felk.cvut.cz
|
|
- *
|
|
- * Calculates proper bit-timing parameters for a specified bit-rate
|
|
- * and sample-point, which can then be used to set the bit-timing
|
|
- * registers of the CAN controller. You can find more information
|
|
- * in the header file linux/can/netlink.h.
|
|
- */
|
|
-static int
|
|
-can_update_sample_point(const struct can_bittiming_const *btc,
|
|
- unsigned int sample_point_nominal, unsigned int tseg,
|
|
- unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
|
|
- unsigned int *sample_point_error_ptr)
|
|
-{
|
|
- unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
|
|
- unsigned int sample_point, best_sample_point = 0;
|
|
- unsigned int tseg1, tseg2;
|
|
- int i;
|
|
-
|
|
- for (i = 0; i <= 1; i++) {
|
|
- tseg2 = tseg + CAN_SYNC_SEG -
|
|
- (sample_point_nominal * (tseg + CAN_SYNC_SEG)) /
|
|
- 1000 - i;
|
|
- tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
|
|
- tseg1 = tseg - tseg2;
|
|
- if (tseg1 > btc->tseg1_max) {
|
|
- tseg1 = btc->tseg1_max;
|
|
- tseg2 = tseg - tseg1;
|
|
- }
|
|
-
|
|
- sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) /
|
|
- (tseg + CAN_SYNC_SEG);
|
|
- sample_point_error = abs(sample_point_nominal - sample_point);
|
|
-
|
|
- if (sample_point <= sample_point_nominal &&
|
|
- sample_point_error < best_sample_point_error) {
|
|
- best_sample_point = sample_point;
|
|
- best_sample_point_error = sample_point_error;
|
|
- *tseg1_ptr = tseg1;
|
|
- *tseg2_ptr = tseg2;
|
|
- }
|
|
- }
|
|
-
|
|
- if (sample_point_error_ptr)
|
|
- *sample_point_error_ptr = best_sample_point_error;
|
|
-
|
|
- return best_sample_point;
|
|
-}
|
|
-
|
|
-static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
|
- const struct can_bittiming_const *btc)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
- unsigned int bitrate; /* current bitrate */
|
|
- unsigned int bitrate_error; /* difference between current and nominal value */
|
|
- unsigned int best_bitrate_error = UINT_MAX;
|
|
- unsigned int sample_point_error; /* difference between current and nominal value */
|
|
- unsigned int best_sample_point_error = UINT_MAX;
|
|
- unsigned int sample_point_nominal; /* nominal sample point */
|
|
- unsigned int best_tseg = 0; /* current best value for tseg */
|
|
- unsigned int best_brp = 0; /* current best value for brp */
|
|
- unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
|
|
- u64 v64;
|
|
-
|
|
- /* Use CiA recommended sample points */
|
|
- if (bt->sample_point) {
|
|
- sample_point_nominal = bt->sample_point;
|
|
- } else {
|
|
- if (bt->bitrate > 800000)
|
|
- sample_point_nominal = 750;
|
|
- else if (bt->bitrate > 500000)
|
|
- sample_point_nominal = 800;
|
|
- else
|
|
- sample_point_nominal = 875;
|
|
- }
|
|
-
|
|
- /* tseg even = round down, odd = round up */
|
|
- for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
|
|
- tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
|
|
- tsegall = CAN_SYNC_SEG + tseg / 2;
|
|
-
|
|
- /* Compute all possible tseg choices (tseg=tseg1+tseg2) */
|
|
- brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
|
|
-
|
|
- /* choose brp step which is possible in system */
|
|
- brp = (brp / btc->brp_inc) * btc->brp_inc;
|
|
- if (brp < btc->brp_min || brp > btc->brp_max)
|
|
- continue;
|
|
-
|
|
- bitrate = priv->clock.freq / (brp * tsegall);
|
|
- bitrate_error = abs(bt->bitrate - bitrate);
|
|
-
|
|
- /* tseg brp biterror */
|
|
- if (bitrate_error > best_bitrate_error)
|
|
- continue;
|
|
-
|
|
- /* reset sample point error if we have a better bitrate */
|
|
- if (bitrate_error < best_bitrate_error)
|
|
- best_sample_point_error = UINT_MAX;
|
|
-
|
|
- can_update_sample_point(btc, sample_point_nominal, tseg / 2,
|
|
- &tseg1, &tseg2, &sample_point_error);
|
|
- if (sample_point_error > best_sample_point_error)
|
|
- continue;
|
|
-
|
|
- best_sample_point_error = sample_point_error;
|
|
- best_bitrate_error = bitrate_error;
|
|
- best_tseg = tseg / 2;
|
|
- best_brp = brp;
|
|
-
|
|
- if (bitrate_error == 0 && sample_point_error == 0)
|
|
- break;
|
|
- }
|
|
-
|
|
- if (best_bitrate_error) {
|
|
- /* Error in one-tenth of a percent */
|
|
- v64 = (u64)best_bitrate_error * 1000;
|
|
- do_div(v64, bt->bitrate);
|
|
- bitrate_error = (u32)v64;
|
|
- if (bitrate_error > CAN_CALC_MAX_ERROR) {
|
|
- netdev_err(dev,
|
|
- "bitrate error %d.%d%% too high\n",
|
|
- bitrate_error / 10, bitrate_error % 10);
|
|
- return -EDOM;
|
|
- }
|
|
- netdev_warn(dev, "bitrate error %d.%d%%\n",
|
|
- bitrate_error / 10, bitrate_error % 10);
|
|
- }
|
|
-
|
|
- /* real sample point */
|
|
- bt->sample_point = can_update_sample_point(btc, sample_point_nominal,
|
|
- best_tseg, &tseg1, &tseg2,
|
|
- NULL);
|
|
-
|
|
- v64 = (u64)best_brp * 1000 * 1000 * 1000;
|
|
- do_div(v64, priv->clock.freq);
|
|
- bt->tq = (u32)v64;
|
|
- bt->prop_seg = tseg1 / 2;
|
|
- bt->phase_seg1 = tseg1 - bt->prop_seg;
|
|
- bt->phase_seg2 = tseg2;
|
|
-
|
|
- /* check for sjw user settings */
|
|
- if (!bt->sjw || !btc->sjw_max) {
|
|
- bt->sjw = 1;
|
|
- } else {
|
|
- /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
|
|
- if (bt->sjw > btc->sjw_max)
|
|
- bt->sjw = btc->sjw_max;
|
|
- /* bt->sjw must not be higher than tseg2 */
|
|
- if (tseg2 < bt->sjw)
|
|
- bt->sjw = tseg2;
|
|
- }
|
|
-
|
|
- bt->brp = best_brp;
|
|
-
|
|
- /* real bitrate */
|
|
- bt->bitrate = priv->clock.freq /
|
|
- (bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2));
|
|
-
|
|
- return 0;
|
|
-}
|
|
-#else /* !CONFIG_CAN_CALC_BITTIMING */
|
|
-static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
|
- const struct can_bittiming_const *btc)
|
|
-{
|
|
- netdev_err(dev, "bit-timing calculation not available\n");
|
|
- return -EINVAL;
|
|
-}
|
|
-#endif /* CONFIG_CAN_CALC_BITTIMING */
|
|
-
|
|
-/* Checks the validity of the specified bit-timing parameters prop_seg,
|
|
- * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
|
|
- * prescaler value brp. You can find more information in the header
|
|
- * file linux/can/netlink.h.
|
|
- */
|
|
-static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
|
- const struct can_bittiming_const *btc)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
- int tseg1, alltseg;
|
|
- u64 brp64;
|
|
-
|
|
- tseg1 = bt->prop_seg + bt->phase_seg1;
|
|
- if (!bt->sjw)
|
|
- bt->sjw = 1;
|
|
- if (bt->sjw > btc->sjw_max ||
|
|
- tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max ||
|
|
- bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max)
|
|
- return -ERANGE;
|
|
-
|
|
- brp64 = (u64)priv->clock.freq * (u64)bt->tq;
|
|
- if (btc->brp_inc > 1)
|
|
- do_div(brp64, btc->brp_inc);
|
|
- brp64 += 500000000UL - 1;
|
|
- do_div(brp64, 1000000000UL); /* the practicable BRP */
|
|
- if (btc->brp_inc > 1)
|
|
- brp64 *= btc->brp_inc;
|
|
- bt->brp = (u32)brp64;
|
|
-
|
|
- if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
|
|
- return -EINVAL;
|
|
-
|
|
- alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
|
|
- bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
|
|
- bt->sample_point = ((tseg1 + 1) * 1000) / alltseg;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/* Checks the validity of predefined bitrate settings */
|
|
-static int
|
|
-can_validate_bitrate(struct net_device *dev, struct can_bittiming *bt,
|
|
- const u32 *bitrate_const,
|
|
- const unsigned int bitrate_const_cnt)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
- unsigned int i;
|
|
-
|
|
- for (i = 0; i < bitrate_const_cnt; i++) {
|
|
- if (bt->bitrate == bitrate_const[i])
|
|
- break;
|
|
- }
|
|
-
|
|
- if (i >= priv->bitrate_const_cnt)
|
|
- return -EINVAL;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
|
- const struct can_bittiming_const *btc,
|
|
- const u32 *bitrate_const,
|
|
- const unsigned int bitrate_const_cnt)
|
|
-{
|
|
- int err;
|
|
-
|
|
- /* Depending on the given can_bittiming parameter structure the CAN
|
|
- * timing parameters are calculated based on the provided bitrate OR
|
|
- * alternatively the CAN timing parameters (tq, prop_seg, etc.) are
|
|
- * provided directly which are then checked and fixed up.
|
|
- */
|
|
- if (!bt->tq && bt->bitrate && btc)
|
|
- err = can_calc_bittiming(dev, bt, btc);
|
|
- else if (bt->tq && !bt->bitrate && btc)
|
|
- err = can_fixup_bittiming(dev, bt, btc);
|
|
- else if (!bt->tq && bt->bitrate && bitrate_const)
|
|
- err = can_validate_bitrate(dev, bt, bitrate_const,
|
|
- bitrate_const_cnt);
|
|
- else
|
|
- err = -EINVAL;
|
|
-
|
|
- return err;
|
|
-}
|
|
-
|
|
-static void can_update_state_error_stats(struct net_device *dev,
|
|
- enum can_state new_state)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
-
|
|
- if (new_state <= priv->state)
|
|
- return;
|
|
-
|
|
- switch (new_state) {
|
|
- case CAN_STATE_ERROR_WARNING:
|
|
- priv->can_stats.error_warning++;
|
|
- break;
|
|
- case CAN_STATE_ERROR_PASSIVE:
|
|
- priv->can_stats.error_passive++;
|
|
- break;
|
|
- case CAN_STATE_BUS_OFF:
|
|
- priv->can_stats.bus_off++;
|
|
- break;
|
|
- default:
|
|
- break;
|
|
- }
|
|
-}
|
|
-
|
|
-static int can_tx_state_to_frame(struct net_device *dev, enum can_state state)
|
|
-{
|
|
- switch (state) {
|
|
- case CAN_STATE_ERROR_ACTIVE:
|
|
- return CAN_ERR_CRTL_ACTIVE;
|
|
- case CAN_STATE_ERROR_WARNING:
|
|
- return CAN_ERR_CRTL_TX_WARNING;
|
|
- case CAN_STATE_ERROR_PASSIVE:
|
|
- return CAN_ERR_CRTL_TX_PASSIVE;
|
|
- default:
|
|
- return 0;
|
|
- }
|
|
-}
|
|
-
|
|
-static int can_rx_state_to_frame(struct net_device *dev, enum can_state state)
|
|
-{
|
|
- switch (state) {
|
|
- case CAN_STATE_ERROR_ACTIVE:
|
|
- return CAN_ERR_CRTL_ACTIVE;
|
|
- case CAN_STATE_ERROR_WARNING:
|
|
- return CAN_ERR_CRTL_RX_WARNING;
|
|
- case CAN_STATE_ERROR_PASSIVE:
|
|
- return CAN_ERR_CRTL_RX_PASSIVE;
|
|
- default:
|
|
- return 0;
|
|
- }
|
|
-}
|
|
-
|
|
-static const char *can_get_state_str(const enum can_state state)
|
|
-{
|
|
- switch (state) {
|
|
- case CAN_STATE_ERROR_ACTIVE:
|
|
- return "Error Active";
|
|
- case CAN_STATE_ERROR_WARNING:
|
|
- return "Error Warning";
|
|
- case CAN_STATE_ERROR_PASSIVE:
|
|
- return "Error Passive";
|
|
- case CAN_STATE_BUS_OFF:
|
|
- return "Bus Off";
|
|
- case CAN_STATE_STOPPED:
|
|
- return "Stopped";
|
|
- case CAN_STATE_SLEEPING:
|
|
- return "Sleeping";
|
|
- default:
|
|
- return "<unknown>";
|
|
- }
|
|
-
|
|
- return "<unknown>";
|
|
-}
|
|
-
|
|
-void can_change_state(struct net_device *dev, struct can_frame *cf,
|
|
- enum can_state tx_state, enum can_state rx_state)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
- enum can_state new_state = max(tx_state, rx_state);
|
|
-
|
|
- if (unlikely(new_state == priv->state)) {
|
|
- netdev_warn(dev, "%s: oops, state did not change", __func__);
|
|
- return;
|
|
- }
|
|
-
|
|
- netdev_dbg(dev, "Controller changed from %s State (%d) into %s State (%d).\n",
|
|
- can_get_state_str(priv->state), priv->state,
|
|
- can_get_state_str(new_state), new_state);
|
|
-
|
|
- can_update_state_error_stats(dev, new_state);
|
|
- priv->state = new_state;
|
|
-
|
|
- if (!cf)
|
|
- return;
|
|
-
|
|
- if (unlikely(new_state == CAN_STATE_BUS_OFF)) {
|
|
- cf->can_id |= CAN_ERR_BUSOFF;
|
|
- return;
|
|
- }
|
|
-
|
|
- cf->can_id |= CAN_ERR_CRTL;
|
|
- cf->data[1] |= tx_state >= rx_state ?
|
|
- can_tx_state_to_frame(dev, tx_state) : 0;
|
|
- cf->data[1] |= tx_state <= rx_state ?
|
|
- can_rx_state_to_frame(dev, rx_state) : 0;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_change_state);
|
|
-
|
|
-/* Local echo of CAN messages
|
|
- *
|
|
- * CAN network devices *should* support a local echo functionality
|
|
- * (see Documentation/networking/can.rst). To test the handling of CAN
|
|
- * interfaces that do not support the local echo both driver types are
|
|
- * implemented. In the case that the driver does not support the echo
|
|
- * the IFF_ECHO remains clear in dev->flags. This causes the PF_CAN core
|
|
- * to perform the echo as a fallback solution.
|
|
- */
|
|
-static void can_flush_echo_skb(struct net_device *dev)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
- struct net_device_stats *stats = &dev->stats;
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < priv->echo_skb_max; i++) {
|
|
- if (priv->echo_skb[i]) {
|
|
- kfree_skb(priv->echo_skb[i]);
|
|
- priv->echo_skb[i] = NULL;
|
|
- stats->tx_dropped++;
|
|
- stats->tx_aborted_errors++;
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
-/* Put the skb on the stack to be looped backed locally lateron
|
|
- *
|
|
- * The function is typically called in the start_xmit function
|
|
- * of the device driver. The driver must protect access to
|
|
- * priv->echo_skb, if necessary.
|
|
- */
|
|
-int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
|
- unsigned int idx)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
-
|
|
- BUG_ON(idx >= priv->echo_skb_max);
|
|
-
|
|
- /* check flag whether this packet has to be looped back */
|
|
- if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK ||
|
|
- (skb->protocol != htons(ETH_P_CAN) &&
|
|
- skb->protocol != htons(ETH_P_CANFD))) {
|
|
- kfree_skb(skb);
|
|
- return 0;
|
|
- }
|
|
-
|
|
- if (!priv->echo_skb[idx]) {
|
|
- skb = can_create_echo_skb(skb);
|
|
- if (!skb)
|
|
- return -ENOMEM;
|
|
-
|
|
- /* make settings for echo to reduce code in irq context */
|
|
- skb->pkt_type = PACKET_BROADCAST;
|
|
- skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
- skb->dev = dev;
|
|
-
|
|
- /* save this skb for tx interrupt echo handling */
|
|
- priv->echo_skb[idx] = skb;
|
|
- } else {
|
|
- /* locking problem with netif_stop_queue() ?? */
|
|
- netdev_err(dev, "%s: BUG! echo_skb %d is occupied!\n", __func__, idx);
|
|
- kfree_skb(skb);
|
|
- return -EBUSY;
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_put_echo_skb);
|
|
-
|
|
-struct sk_buff *
|
|
-__can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
-
|
|
- if (idx >= priv->echo_skb_max) {
|
|
- netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
|
|
- __func__, idx, priv->echo_skb_max);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- if (priv->echo_skb[idx]) {
|
|
- /* Using "struct canfd_frame::len" for the frame
|
|
- * length is supported on both CAN and CANFD frames.
|
|
- */
|
|
- struct sk_buff *skb = priv->echo_skb[idx];
|
|
- struct canfd_frame *cf = (struct canfd_frame *)skb->data;
|
|
-
|
|
- /* get the real payload length for netdev statistics */
|
|
- if (cf->can_id & CAN_RTR_FLAG)
|
|
- *len_ptr = 0;
|
|
- else
|
|
- *len_ptr = cf->len;
|
|
-
|
|
- priv->echo_skb[idx] = NULL;
|
|
-
|
|
- return skb;
|
|
- }
|
|
-
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-/* Get the skb from the stack and loop it back locally
|
|
- *
|
|
- * The function is typically called when the TX done interrupt
|
|
- * is handled in the device driver. The driver must protect
|
|
- * access to priv->echo_skb, if necessary.
|
|
- */
|
|
-unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx)
|
|
-{
|
|
- struct sk_buff *skb;
|
|
- u8 len;
|
|
-
|
|
- skb = __can_get_echo_skb(dev, idx, &len);
|
|
- if (!skb)
|
|
- return 0;
|
|
-
|
|
- skb_get(skb);
|
|
- if (netif_rx(skb) == NET_RX_SUCCESS)
|
|
- dev_consume_skb_any(skb);
|
|
- else
|
|
- dev_kfree_skb_any(skb);
|
|
-
|
|
- return len;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_get_echo_skb);
|
|
-
|
|
-/* Remove the skb from the stack and free it.
|
|
- *
|
|
- * The function is typically called when TX failed.
|
|
- */
|
|
-void can_free_echo_skb(struct net_device *dev, unsigned int idx)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
-
|
|
- BUG_ON(idx >= priv->echo_skb_max);
|
|
-
|
|
- if (priv->echo_skb[idx]) {
|
|
- dev_kfree_skb_any(priv->echo_skb[idx]);
|
|
- priv->echo_skb[idx] = NULL;
|
|
- }
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_free_echo_skb);
|
|
-
|
|
-/* CAN device restart for bus-off recovery */
|
|
-static void can_restart(struct net_device *dev)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
- struct net_device_stats *stats = &dev->stats;
|
|
- struct sk_buff *skb;
|
|
- struct can_frame *cf;
|
|
- int err;
|
|
-
|
|
- BUG_ON(netif_carrier_ok(dev));
|
|
-
|
|
- /* No synchronization needed because the device is bus-off and
|
|
- * no messages can come in or go out.
|
|
- */
|
|
- can_flush_echo_skb(dev);
|
|
-
|
|
- /* send restart message upstream */
|
|
- skb = alloc_can_err_skb(dev, &cf);
|
|
- if (!skb)
|
|
- goto restart;
|
|
-
|
|
- cf->can_id |= CAN_ERR_RESTARTED;
|
|
-
|
|
- stats->rx_packets++;
|
|
- stats->rx_bytes += cf->can_dlc;
|
|
-
|
|
- netif_rx_ni(skb);
|
|
-
|
|
-restart:
|
|
- netdev_dbg(dev, "restarted\n");
|
|
- priv->can_stats.restarts++;
|
|
-
|
|
- /* Now restart the device */
|
|
- err = priv->do_set_mode(dev, CAN_MODE_START);
|
|
-
|
|
- netif_carrier_on(dev);
|
|
- if (err)
|
|
- netdev_err(dev, "Error %d during restart", err);
|
|
-}
|
|
-
|
|
-static void can_restart_work(struct work_struct *work)
|
|
-{
|
|
- struct delayed_work *dwork = to_delayed_work(work);
|
|
- struct can_priv *priv = container_of(dwork, struct can_priv,
|
|
- restart_work);
|
|
-
|
|
- can_restart(priv->dev);
|
|
-}
|
|
-
|
|
-int can_restart_now(struct net_device *dev)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
-
|
|
- /* A manual restart is only permitted if automatic restart is
|
|
- * disabled and the device is in the bus-off state
|
|
- */
|
|
- if (priv->restart_ms)
|
|
- return -EINVAL;
|
|
- if (priv->state != CAN_STATE_BUS_OFF)
|
|
- return -EBUSY;
|
|
-
|
|
- cancel_delayed_work_sync(&priv->restart_work);
|
|
- can_restart(dev);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/* CAN bus-off
|
|
- *
|
|
- * This functions should be called when the device goes bus-off to
|
|
- * tell the netif layer that no more packets can be sent or received.
|
|
- * If enabled, a timer is started to trigger bus-off recovery.
|
|
- */
|
|
-void can_bus_off(struct net_device *dev)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
-
|
|
- if (priv->restart_ms)
|
|
- netdev_info(dev, "bus-off, scheduling restart in %d ms\n",
|
|
- priv->restart_ms);
|
|
- else
|
|
- netdev_info(dev, "bus-off\n");
|
|
-
|
|
- netif_carrier_off(dev);
|
|
-
|
|
- if (priv->restart_ms)
|
|
- schedule_delayed_work(&priv->restart_work,
|
|
- msecs_to_jiffies(priv->restart_ms));
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_bus_off);
|
|
-
|
|
-static void can_setup(struct net_device *dev)
|
|
-{
|
|
- dev->type = ARPHRD_CAN;
|
|
- dev->mtu = CAN_MTU;
|
|
- dev->hard_header_len = 0;
|
|
- dev->addr_len = 0;
|
|
- dev->tx_queue_len = 10;
|
|
-
|
|
- /* New-style flags. */
|
|
- dev->flags = IFF_NOARP;
|
|
- dev->features = NETIF_F_HW_CSUM;
|
|
-}
|
|
-
|
|
-struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
|
|
-{
|
|
- struct sk_buff *skb;
|
|
-
|
|
- skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
|
|
- sizeof(struct can_frame));
|
|
- if (unlikely(!skb))
|
|
- return NULL;
|
|
-
|
|
- skb->protocol = htons(ETH_P_CAN);
|
|
- skb->pkt_type = PACKET_BROADCAST;
|
|
- skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
-
|
|
- skb_reset_mac_header(skb);
|
|
- skb_reset_network_header(skb);
|
|
- skb_reset_transport_header(skb);
|
|
-
|
|
- can_skb_reserve(skb);
|
|
- can_skb_prv(skb)->ifindex = dev->ifindex;
|
|
- can_skb_prv(skb)->skbcnt = 0;
|
|
-
|
|
- *cf = skb_put_zero(skb, sizeof(struct can_frame));
|
|
-
|
|
- return skb;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(alloc_can_skb);
|
|
-
|
|
-struct sk_buff *alloc_canfd_skb(struct net_device *dev,
|
|
- struct canfd_frame **cfd)
|
|
-{
|
|
- struct sk_buff *skb;
|
|
-
|
|
- skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
|
|
- sizeof(struct canfd_frame));
|
|
- if (unlikely(!skb))
|
|
- return NULL;
|
|
-
|
|
- skb->protocol = htons(ETH_P_CANFD);
|
|
- skb->pkt_type = PACKET_BROADCAST;
|
|
- skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
-
|
|
- skb_reset_mac_header(skb);
|
|
- skb_reset_network_header(skb);
|
|
- skb_reset_transport_header(skb);
|
|
-
|
|
- can_skb_reserve(skb);
|
|
- can_skb_prv(skb)->ifindex = dev->ifindex;
|
|
- can_skb_prv(skb)->skbcnt = 0;
|
|
-
|
|
- *cfd = skb_put_zero(skb, sizeof(struct canfd_frame));
|
|
-
|
|
- return skb;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(alloc_canfd_skb);
|
|
-
|
|
-struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
|
|
-{
|
|
- struct sk_buff *skb;
|
|
-
|
|
- skb = alloc_can_skb(dev, cf);
|
|
- if (unlikely(!skb))
|
|
- return NULL;
|
|
-
|
|
- (*cf)->can_id = CAN_ERR_FLAG;
|
|
- (*cf)->can_dlc = CAN_ERR_DLC;
|
|
-
|
|
- return skb;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(alloc_can_err_skb);
|
|
-
|
|
-/* Allocate and setup space for the CAN network device */
|
|
-struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,
|
|
- unsigned int txqs, unsigned int rxqs)
|
|
-{
|
|
- struct net_device *dev;
|
|
- struct can_priv *priv;
|
|
- int size;
|
|
-
|
|
- /* We put the driver's priv, the CAN mid layer priv and the
|
|
- * echo skb into the netdevice's priv. The memory layout for
|
|
- * the netdev_priv is like this:
|
|
- *
|
|
- * +-------------------------+
|
|
- * | driver's priv |
|
|
- * +-------------------------+
|
|
- * | struct can_ml_priv |
|
|
- * +-------------------------+
|
|
- * | array of struct sk_buff |
|
|
- * +-------------------------+
|
|
- */
|
|
-
|
|
- size = ALIGN(sizeof_priv, NETDEV_ALIGN) + sizeof(struct can_ml_priv);
|
|
-
|
|
- if (echo_skb_max)
|
|
- size = ALIGN(size, sizeof(struct sk_buff *)) +
|
|
- echo_skb_max * sizeof(struct sk_buff *);
|
|
-
|
|
- dev = alloc_netdev_mqs(size, "can%d", NET_NAME_UNKNOWN, can_setup,
|
|
- txqs, rxqs);
|
|
- if (!dev)
|
|
- return NULL;
|
|
-
|
|
- priv = netdev_priv(dev);
|
|
- priv->dev = dev;
|
|
-
|
|
- dev->ml_priv = (void *)priv + ALIGN(sizeof_priv, NETDEV_ALIGN);
|
|
-
|
|
- if (echo_skb_max) {
|
|
- priv->echo_skb_max = echo_skb_max;
|
|
- priv->echo_skb = (void *)priv +
|
|
- (size - echo_skb_max * sizeof(struct sk_buff *));
|
|
- }
|
|
-
|
|
- priv->state = CAN_STATE_STOPPED;
|
|
-
|
|
- INIT_DELAYED_WORK(&priv->restart_work, can_restart_work);
|
|
-
|
|
- return dev;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(alloc_candev_mqs);
|
|
-
|
|
-/* Free space of the CAN network device */
|
|
-void free_candev(struct net_device *dev)
|
|
-{
|
|
- free_netdev(dev);
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(free_candev);
|
|
-
|
|
-/* changing MTU and control mode for CAN/CANFD devices */
|
|
-int can_change_mtu(struct net_device *dev, int new_mtu)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
-
|
|
- /* Do not allow changing the MTU while running */
|
|
- if (dev->flags & IFF_UP)
|
|
- return -EBUSY;
|
|
-
|
|
- /* allow change of MTU according to the CANFD ability of the device */
|
|
- switch (new_mtu) {
|
|
- case CAN_MTU:
|
|
- /* 'CANFD-only' controllers can not switch to CAN_MTU */
|
|
- if (priv->ctrlmode_static & CAN_CTRLMODE_FD)
|
|
- return -EINVAL;
|
|
-
|
|
- priv->ctrlmode &= ~CAN_CTRLMODE_FD;
|
|
- break;
|
|
-
|
|
- case CANFD_MTU:
|
|
- /* check for potential CANFD ability */
|
|
- if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD) &&
|
|
- !(priv->ctrlmode_static & CAN_CTRLMODE_FD))
|
|
- return -EINVAL;
|
|
-
|
|
- priv->ctrlmode |= CAN_CTRLMODE_FD;
|
|
- break;
|
|
-
|
|
- default:
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- dev->mtu = new_mtu;
|
|
- return 0;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_change_mtu);
|
|
-
|
|
-/* Common open function when the device gets opened.
|
|
- *
|
|
- * This function should be called in the open function of the device
|
|
- * driver.
|
|
- */
|
|
-int open_candev(struct net_device *dev)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
-
|
|
- if (!priv->bittiming.bitrate) {
|
|
- netdev_err(dev, "bit-timing not yet defined\n");
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- /* For CAN FD the data bitrate has to be >= the arbitration bitrate */
|
|
- if ((priv->ctrlmode & CAN_CTRLMODE_FD) &&
|
|
- (!priv->data_bittiming.bitrate ||
|
|
- priv->data_bittiming.bitrate < priv->bittiming.bitrate)) {
|
|
- netdev_err(dev, "incorrect/missing data bit-timing\n");
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- /* Switch carrier on if device was stopped while in bus-off state */
|
|
- if (!netif_carrier_ok(dev))
|
|
- netif_carrier_on(dev);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(open_candev);
|
|
-
|
|
-#ifdef CONFIG_OF
|
|
-/* Common function that can be used to understand the limitation of
|
|
- * a transceiver when it provides no means to determine these limitations
|
|
- * at runtime.
|
|
- */
|
|
-void of_can_transceiver(struct net_device *dev)
|
|
-{
|
|
- struct device_node *dn;
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
- struct device_node *np = dev->dev.parent->of_node;
|
|
- int ret;
|
|
-
|
|
- dn = of_get_child_by_name(np, "can-transceiver");
|
|
- if (!dn)
|
|
- return;
|
|
-
|
|
- ret = of_property_read_u32(dn, "max-bitrate", &priv->bitrate_max);
|
|
- of_node_put(dn);
|
|
- if ((ret && ret != -EINVAL) || (!ret && !priv->bitrate_max))
|
|
- netdev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit.\n");
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(of_can_transceiver);
|
|
-#endif
|
|
-
|
|
-/* Common close function for cleanup before the device gets closed.
|
|
- *
|
|
- * This function should be called in the close function of the device
|
|
- * driver.
|
|
- */
|
|
-void close_candev(struct net_device *dev)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
-
|
|
- cancel_delayed_work_sync(&priv->restart_work);
|
|
- can_flush_echo_skb(dev);
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(close_candev);
|
|
-
|
|
-/* CAN netlink interface */
|
|
-static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
|
|
- [IFLA_CAN_STATE] = { .type = NLA_U32 },
|
|
- [IFLA_CAN_CTRLMODE] = { .len = sizeof(struct can_ctrlmode) },
|
|
- [IFLA_CAN_RESTART_MS] = { .type = NLA_U32 },
|
|
- [IFLA_CAN_RESTART] = { .type = NLA_U32 },
|
|
- [IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) },
|
|
- [IFLA_CAN_BITTIMING_CONST]
|
|
- = { .len = sizeof(struct can_bittiming_const) },
|
|
- [IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) },
|
|
- [IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
|
|
- [IFLA_CAN_DATA_BITTIMING]
|
|
- = { .len = sizeof(struct can_bittiming) },
|
|
- [IFLA_CAN_DATA_BITTIMING_CONST]
|
|
- = { .len = sizeof(struct can_bittiming_const) },
|
|
- [IFLA_CAN_TERMINATION] = { .type = NLA_U16 },
|
|
-};
|
|
-
|
|
-static int can_validate(struct nlattr *tb[], struct nlattr *data[],
|
|
- struct netlink_ext_ack *extack)
|
|
-{
|
|
- bool is_can_fd = false;
|
|
-
|
|
- /* Make sure that valid CAN FD configurations always consist of
|
|
- * - nominal/arbitration bittiming
|
|
- * - data bittiming
|
|
- * - control mode with CAN_CTRLMODE_FD set
|
|
- */
|
|
-
|
|
- if (!data)
|
|
- return 0;
|
|
-
|
|
- if (data[IFLA_CAN_CTRLMODE]) {
|
|
- struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
|
|
-
|
|
- is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD;
|
|
- }
|
|
-
|
|
- if (is_can_fd) {
|
|
- if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING])
|
|
- return -EOPNOTSUPP;
|
|
- }
|
|
-
|
|
- if (data[IFLA_CAN_DATA_BITTIMING]) {
|
|
- if (!is_can_fd || !data[IFLA_CAN_BITTIMING])
|
|
- return -EOPNOTSUPP;
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
|
- struct nlattr *data[],
|
|
- struct netlink_ext_ack *extack)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
- int err;
|
|
-
|
|
- /* We need synchronization with dev->stop() */
|
|
- ASSERT_RTNL();
|
|
-
|
|
- if (data[IFLA_CAN_BITTIMING]) {
|
|
- struct can_bittiming bt;
|
|
-
|
|
- /* Do not allow changing bittiming while running */
|
|
- if (dev->flags & IFF_UP)
|
|
- return -EBUSY;
|
|
-
|
|
- /* Calculate bittiming parameters based on
|
|
- * bittiming_const if set, otherwise pass bitrate
|
|
- * directly via do_set_bitrate(). Bail out if neither
|
|
- * is given.
|
|
- */
|
|
- if (!priv->bittiming_const && !priv->do_set_bittiming)
|
|
- return -EOPNOTSUPP;
|
|
-
|
|
- memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
|
|
- err = can_get_bittiming(dev, &bt,
|
|
- priv->bittiming_const,
|
|
- priv->bitrate_const,
|
|
- priv->bitrate_const_cnt);
|
|
- if (err)
|
|
- return err;
|
|
-
|
|
- if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
|
|
- netdev_err(dev, "arbitration bitrate surpasses transceiver capabilities of %d bps\n",
|
|
- priv->bitrate_max);
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- memcpy(&priv->bittiming, &bt, sizeof(bt));
|
|
-
|
|
- if (priv->do_set_bittiming) {
|
|
- /* Finally, set the bit-timing registers */
|
|
- err = priv->do_set_bittiming(dev);
|
|
- if (err)
|
|
- return err;
|
|
- }
|
|
- }
|
|
-
|
|
- if (data[IFLA_CAN_CTRLMODE]) {
|
|
- struct can_ctrlmode *cm;
|
|
- u32 ctrlstatic;
|
|
- u32 maskedflags;
|
|
-
|
|
- /* Do not allow changing controller mode while running */
|
|
- if (dev->flags & IFF_UP)
|
|
- return -EBUSY;
|
|
- cm = nla_data(data[IFLA_CAN_CTRLMODE]);
|
|
- ctrlstatic = priv->ctrlmode_static;
|
|
- maskedflags = cm->flags & cm->mask;
|
|
-
|
|
- /* check whether provided bits are allowed to be passed */
|
|
- if (cm->mask & ~(priv->ctrlmode_supported | ctrlstatic))
|
|
- return -EOPNOTSUPP;
|
|
-
|
|
- /* do not check for static fd-non-iso if 'fd' is disabled */
|
|
- if (!(maskedflags & CAN_CTRLMODE_FD))
|
|
- ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO;
|
|
-
|
|
- /* make sure static options are provided by configuration */
|
|
- if ((maskedflags & ctrlstatic) != ctrlstatic)
|
|
- return -EOPNOTSUPP;
|
|
-
|
|
- /* clear bits to be modified and copy the flag values */
|
|
- priv->ctrlmode &= ~cm->mask;
|
|
- priv->ctrlmode |= maskedflags;
|
|
-
|
|
- /* CAN_CTRLMODE_FD can only be set when driver supports FD */
|
|
- if (priv->ctrlmode & CAN_CTRLMODE_FD)
|
|
- dev->mtu = CANFD_MTU;
|
|
- else
|
|
- dev->mtu = CAN_MTU;
|
|
- }
|
|
-
|
|
- if (data[IFLA_CAN_RESTART_MS]) {
|
|
- /* Do not allow changing restart delay while running */
|
|
- if (dev->flags & IFF_UP)
|
|
- return -EBUSY;
|
|
- priv->restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]);
|
|
- }
|
|
-
|
|
- if (data[IFLA_CAN_RESTART]) {
|
|
- /* Do not allow a restart while not running */
|
|
- if (!(dev->flags & IFF_UP))
|
|
- return -EINVAL;
|
|
- err = can_restart_now(dev);
|
|
- if (err)
|
|
- return err;
|
|
- }
|
|
-
|
|
- if (data[IFLA_CAN_DATA_BITTIMING]) {
|
|
- struct can_bittiming dbt;
|
|
-
|
|
- /* Do not allow changing bittiming while running */
|
|
- if (dev->flags & IFF_UP)
|
|
- return -EBUSY;
|
|
-
|
|
- /* Calculate bittiming parameters based on
|
|
- * data_bittiming_const if set, otherwise pass bitrate
|
|
- * directly via do_set_bitrate(). Bail out if neither
|
|
- * is given.
|
|
- */
|
|
- if (!priv->data_bittiming_const && !priv->do_set_data_bittiming)
|
|
- return -EOPNOTSUPP;
|
|
-
|
|
- memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
|
|
- sizeof(dbt));
|
|
- err = can_get_bittiming(dev, &dbt,
|
|
- priv->data_bittiming_const,
|
|
- priv->data_bitrate_const,
|
|
- priv->data_bitrate_const_cnt);
|
|
- if (err)
|
|
- return err;
|
|
-
|
|
- if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) {
|
|
- netdev_err(dev, "canfd data bitrate surpasses transceiver capabilities of %d bps\n",
|
|
- priv->bitrate_max);
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
|
|
-
|
|
- if (priv->do_set_data_bittiming) {
|
|
- /* Finally, set the bit-timing registers */
|
|
- err = priv->do_set_data_bittiming(dev);
|
|
- if (err)
|
|
- return err;
|
|
- }
|
|
- }
|
|
-
|
|
- if (data[IFLA_CAN_TERMINATION]) {
|
|
- const u16 termval = nla_get_u16(data[IFLA_CAN_TERMINATION]);
|
|
- const unsigned int num_term = priv->termination_const_cnt;
|
|
- unsigned int i;
|
|
-
|
|
- if (!priv->do_set_termination)
|
|
- return -EOPNOTSUPP;
|
|
-
|
|
- /* check whether given value is supported by the interface */
|
|
- for (i = 0; i < num_term; i++) {
|
|
- if (termval == priv->termination_const[i])
|
|
- break;
|
|
- }
|
|
- if (i >= num_term)
|
|
- return -EINVAL;
|
|
-
|
|
- /* Finally, set the termination value */
|
|
- err = priv->do_set_termination(dev, termval);
|
|
- if (err)
|
|
- return err;
|
|
-
|
|
- priv->termination = termval;
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static size_t can_get_size(const struct net_device *dev)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
- size_t size = 0;
|
|
-
|
|
- if (priv->bittiming.bitrate) /* IFLA_CAN_BITTIMING */
|
|
- size += nla_total_size(sizeof(struct can_bittiming));
|
|
- if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */
|
|
- size += nla_total_size(sizeof(struct can_bittiming_const));
|
|
- size += nla_total_size(sizeof(struct can_clock)); /* IFLA_CAN_CLOCK */
|
|
- size += nla_total_size(sizeof(u32)); /* IFLA_CAN_STATE */
|
|
- size += nla_total_size(sizeof(struct can_ctrlmode)); /* IFLA_CAN_CTRLMODE */
|
|
- size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */
|
|
- if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */
|
|
- size += nla_total_size(sizeof(struct can_berr_counter));
|
|
- if (priv->data_bittiming.bitrate) /* IFLA_CAN_DATA_BITTIMING */
|
|
- size += nla_total_size(sizeof(struct can_bittiming));
|
|
- if (priv->data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */
|
|
- size += nla_total_size(sizeof(struct can_bittiming_const));
|
|
- if (priv->termination_const) {
|
|
- size += nla_total_size(sizeof(priv->termination)); /* IFLA_CAN_TERMINATION */
|
|
- size += nla_total_size(sizeof(*priv->termination_const) * /* IFLA_CAN_TERMINATION_CONST */
|
|
- priv->termination_const_cnt);
|
|
- }
|
|
- if (priv->bitrate_const) /* IFLA_CAN_BITRATE_CONST */
|
|
- size += nla_total_size(sizeof(*priv->bitrate_const) *
|
|
- priv->bitrate_const_cnt);
|
|
- if (priv->data_bitrate_const) /* IFLA_CAN_DATA_BITRATE_CONST */
|
|
- size += nla_total_size(sizeof(*priv->data_bitrate_const) *
|
|
- priv->data_bitrate_const_cnt);
|
|
- size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */
|
|
-
|
|
- return size;
|
|
-}
|
|
-
|
|
-static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
- struct can_ctrlmode cm = {.flags = priv->ctrlmode};
|
|
- struct can_berr_counter bec = { };
|
|
- enum can_state state = priv->state;
|
|
-
|
|
- if (priv->do_get_state)
|
|
- priv->do_get_state(dev, &state);
|
|
-
|
|
- if ((priv->bittiming.bitrate &&
|
|
- nla_put(skb, IFLA_CAN_BITTIMING,
|
|
- sizeof(priv->bittiming), &priv->bittiming)) ||
|
|
-
|
|
- (priv->bittiming_const &&
|
|
- nla_put(skb, IFLA_CAN_BITTIMING_CONST,
|
|
- sizeof(*priv->bittiming_const), priv->bittiming_const)) ||
|
|
-
|
|
- nla_put(skb, IFLA_CAN_CLOCK, sizeof(priv->clock), &priv->clock) ||
|
|
- nla_put_u32(skb, IFLA_CAN_STATE, state) ||
|
|
- nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
|
|
- nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
|
|
-
|
|
- (priv->do_get_berr_counter &&
|
|
- !priv->do_get_berr_counter(dev, &bec) &&
|
|
- nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
|
|
-
|
|
- (priv->data_bittiming.bitrate &&
|
|
- nla_put(skb, IFLA_CAN_DATA_BITTIMING,
|
|
- sizeof(priv->data_bittiming), &priv->data_bittiming)) ||
|
|
-
|
|
- (priv->data_bittiming_const &&
|
|
- nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST,
|
|
- sizeof(*priv->data_bittiming_const),
|
|
- priv->data_bittiming_const)) ||
|
|
-
|
|
- (priv->termination_const &&
|
|
- (nla_put_u16(skb, IFLA_CAN_TERMINATION, priv->termination) ||
|
|
- nla_put(skb, IFLA_CAN_TERMINATION_CONST,
|
|
- sizeof(*priv->termination_const) *
|
|
- priv->termination_const_cnt,
|
|
- priv->termination_const))) ||
|
|
-
|
|
- (priv->bitrate_const &&
|
|
- nla_put(skb, IFLA_CAN_BITRATE_CONST,
|
|
- sizeof(*priv->bitrate_const) *
|
|
- priv->bitrate_const_cnt,
|
|
- priv->bitrate_const)) ||
|
|
-
|
|
- (priv->data_bitrate_const &&
|
|
- nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST,
|
|
- sizeof(*priv->data_bitrate_const) *
|
|
- priv->data_bitrate_const_cnt,
|
|
- priv->data_bitrate_const)) ||
|
|
-
|
|
- (nla_put(skb, IFLA_CAN_BITRATE_MAX,
|
|
- sizeof(priv->bitrate_max),
|
|
- &priv->bitrate_max))
|
|
- )
|
|
-
|
|
- return -EMSGSIZE;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static size_t can_get_xstats_size(const struct net_device *dev)
|
|
-{
|
|
- return sizeof(struct can_device_stats);
|
|
-}
|
|
-
|
|
-static int can_fill_xstats(struct sk_buff *skb, const struct net_device *dev)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
-
|
|
- if (nla_put(skb, IFLA_INFO_XSTATS,
|
|
- sizeof(priv->can_stats), &priv->can_stats))
|
|
- goto nla_put_failure;
|
|
- return 0;
|
|
-
|
|
-nla_put_failure:
|
|
- return -EMSGSIZE;
|
|
-}
|
|
-
|
|
-static int can_newlink(struct net *src_net, struct net_device *dev,
|
|
- struct nlattr *tb[], struct nlattr *data[],
|
|
- struct netlink_ext_ack *extack)
|
|
-{
|
|
- return -EOPNOTSUPP;
|
|
-}
|
|
-
|
|
-static void can_dellink(struct net_device *dev, struct list_head *head)
|
|
-{
|
|
-}
|
|
-
|
|
-static struct rtnl_link_ops can_link_ops __read_mostly = {
|
|
- .kind = "can",
|
|
- .netns_refund = true,
|
|
- .maxtype = IFLA_CAN_MAX,
|
|
- .policy = can_policy,
|
|
- .setup = can_setup,
|
|
- .validate = can_validate,
|
|
- .newlink = can_newlink,
|
|
- .changelink = can_changelink,
|
|
- .dellink = can_dellink,
|
|
- .get_size = can_get_size,
|
|
- .fill_info = can_fill_info,
|
|
- .get_xstats_size = can_get_xstats_size,
|
|
- .fill_xstats = can_fill_xstats,
|
|
-};
|
|
-
|
|
-/* Register the CAN network device */
|
|
-int register_candev(struct net_device *dev)
|
|
-{
|
|
- struct can_priv *priv = netdev_priv(dev);
|
|
-
|
|
- /* Ensure termination_const, termination_const_cnt and
|
|
- * do_set_termination consistency. All must be either set or
|
|
- * unset.
|
|
- */
|
|
- if ((!priv->termination_const != !priv->termination_const_cnt) ||
|
|
- (!priv->termination_const != !priv->do_set_termination))
|
|
- return -EINVAL;
|
|
-
|
|
- if (!priv->bitrate_const != !priv->bitrate_const_cnt)
|
|
- return -EINVAL;
|
|
-
|
|
- if (!priv->data_bitrate_const != !priv->data_bitrate_const_cnt)
|
|
- return -EINVAL;
|
|
-
|
|
- dev->rtnl_link_ops = &can_link_ops;
|
|
- netif_carrier_off(dev);
|
|
-
|
|
- return register_netdev(dev);
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(register_candev);
|
|
-
|
|
-/* Unregister the CAN network device */
|
|
-void unregister_candev(struct net_device *dev)
|
|
-{
|
|
- unregister_netdev(dev);
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(unregister_candev);
|
|
-
|
|
-/* Test if a network device is a candev based device
|
|
- * and return the can_priv* if so.
|
|
- */
|
|
-struct can_priv *safe_candev_priv(struct net_device *dev)
|
|
-{
|
|
- if (dev->type != ARPHRD_CAN || dev->rtnl_link_ops != &can_link_ops)
|
|
- return NULL;
|
|
-
|
|
- return netdev_priv(dev);
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(safe_candev_priv);
|
|
-
|
|
-static __init int can_dev_init(void)
|
|
-{
|
|
- int err;
|
|
-
|
|
- can_led_notifier_init();
|
|
-
|
|
- err = rtnl_link_register(&can_link_ops);
|
|
- if (!err)
|
|
- pr_info(MOD_DESC "\n");
|
|
-
|
|
- return err;
|
|
-}
|
|
-module_init(can_dev_init);
|
|
-
|
|
-static __exit void can_dev_exit(void)
|
|
-{
|
|
- rtnl_link_unregister(&can_link_ops);
|
|
-
|
|
- can_led_notifier_exit();
|
|
-}
|
|
-module_exit(can_dev_exit);
|
|
-
|
|
-MODULE_ALIAS_RTNL_LINK("can");
|
|
diff --git a/drivers/net/can/dev/Makefile b/drivers/net/can/dev/Makefile
|
|
new file mode 100644
|
|
index 0000000000000..cba92e6bcf6f5
|
|
--- /dev/null
|
|
+++ b/drivers/net/can/dev/Makefile
|
|
@@ -0,0 +1,7 @@
|
|
+# SPDX-License-Identifier: GPL-2.0
|
|
+
|
|
+obj-$(CONFIG_CAN_DEV) += can-dev.o
|
|
+can-dev-y += dev.o
|
|
+can-dev-y += rx-offload.o
|
|
+
|
|
+can-dev-$(CONFIG_CAN_LEDS) += led.o
|
|
diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c
|
|
new file mode 100644
|
|
index 0000000000000..2b38a99884f2f
|
|
--- /dev/null
|
|
+++ b/drivers/net/can/dev/dev.c
|
|
@@ -0,0 +1,1341 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-only
|
|
+/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
|
|
+ * Copyright (C) 2006 Andrey Volkov, Varma Electronics
|
|
+ * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
|
+ */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/netdevice.h>
|
|
+#include <linux/if_arp.h>
|
|
+#include <linux/workqueue.h>
|
|
+#include <linux/can.h>
|
|
+#include <linux/can/can-ml.h>
|
|
+#include <linux/can/dev.h>
|
|
+#include <linux/can/skb.h>
|
|
+#include <linux/can/netlink.h>
|
|
+#include <linux/can/led.h>
|
|
+#include <linux/of.h>
|
|
+#include <net/rtnetlink.h>
|
|
+
|
|
+#define MOD_DESC "CAN device driver interface"
|
|
+
|
|
+MODULE_DESCRIPTION(MOD_DESC);
|
|
+MODULE_LICENSE("GPL v2");
|
|
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
|
|
+
|
|
+/* CAN DLC to real data length conversion helpers */
|
|
+
|
|
+static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
|
|
+ 8, 12, 16, 20, 24, 32, 48, 64};
|
|
+
|
|
+/* get data length from can_dlc with sanitized can_dlc */
|
|
+u8 can_dlc2len(u8 can_dlc)
|
|
+{
|
|
+ return dlc2len[can_dlc & 0x0F];
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_dlc2len);
|
|
+
|
|
+static const u8 len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
|
+ 9, 9, 9, 9, /* 9 - 12 */
|
|
+ 10, 10, 10, 10, /* 13 - 16 */
|
|
+ 11, 11, 11, 11, /* 17 - 20 */
|
|
+ 12, 12, 12, 12, /* 21 - 24 */
|
|
+ 13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */
|
|
+ 14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */
|
|
+ 14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */
|
|
+ 15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */
|
|
+ 15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
|
|
+
|
|
+/* map the sanitized data length to an appropriate data length code */
|
|
+u8 can_len2dlc(u8 len)
|
|
+{
|
|
+ if (unlikely(len > 64))
|
|
+ return 0xF;
|
|
+
|
|
+ return len2dlc[len];
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_len2dlc);
|
|
+
|
|
+#ifdef CONFIG_CAN_CALC_BITTIMING
|
|
+#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
|
|
+
|
|
+/* Bit-timing calculation derived from:
|
|
+ *
|
|
+ * Code based on LinCAN sources and H8S2638 project
|
|
+ * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
|
+ * Copyright 2005 Stanislav Marek
|
|
+ * email: pisa@cmp.felk.cvut.cz
|
|
+ *
|
|
+ * Calculates proper bit-timing parameters for a specified bit-rate
|
|
+ * and sample-point, which can then be used to set the bit-timing
|
|
+ * registers of the CAN controller. You can find more information
|
|
+ * in the header file linux/can/netlink.h.
|
|
+ */
|
|
+static int
|
|
+can_update_sample_point(const struct can_bittiming_const *btc,
|
|
+ unsigned int sample_point_nominal, unsigned int tseg,
|
|
+ unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
|
|
+ unsigned int *sample_point_error_ptr)
|
|
+{
|
|
+ unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
|
|
+ unsigned int sample_point, best_sample_point = 0;
|
|
+ unsigned int tseg1, tseg2;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i <= 1; i++) {
|
|
+ tseg2 = tseg + CAN_SYNC_SEG -
|
|
+ (sample_point_nominal * (tseg + CAN_SYNC_SEG)) /
|
|
+ 1000 - i;
|
|
+ tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
|
|
+ tseg1 = tseg - tseg2;
|
|
+ if (tseg1 > btc->tseg1_max) {
|
|
+ tseg1 = btc->tseg1_max;
|
|
+ tseg2 = tseg - tseg1;
|
|
+ }
|
|
+
|
|
+ sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) /
|
|
+ (tseg + CAN_SYNC_SEG);
|
|
+ sample_point_error = abs(sample_point_nominal - sample_point);
|
|
+
|
|
+ if (sample_point <= sample_point_nominal &&
|
|
+ sample_point_error < best_sample_point_error) {
|
|
+ best_sample_point = sample_point;
|
|
+ best_sample_point_error = sample_point_error;
|
|
+ *tseg1_ptr = tseg1;
|
|
+ *tseg2_ptr = tseg2;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (sample_point_error_ptr)
|
|
+ *sample_point_error_ptr = best_sample_point_error;
|
|
+
|
|
+ return best_sample_point;
|
|
+}
|
|
+
|
|
+static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
|
+ const struct can_bittiming_const *btc)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+ unsigned int bitrate; /* current bitrate */
|
|
+ unsigned int bitrate_error; /* difference between current and nominal value */
|
|
+ unsigned int best_bitrate_error = UINT_MAX;
|
|
+ unsigned int sample_point_error; /* difference between current and nominal value */
|
|
+ unsigned int best_sample_point_error = UINT_MAX;
|
|
+ unsigned int sample_point_nominal; /* nominal sample point */
|
|
+ unsigned int best_tseg = 0; /* current best value for tseg */
|
|
+ unsigned int best_brp = 0; /* current best value for brp */
|
|
+ unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
|
|
+ u64 v64;
|
|
+
|
|
+ /* Use CiA recommended sample points */
|
|
+ if (bt->sample_point) {
|
|
+ sample_point_nominal = bt->sample_point;
|
|
+ } else {
|
|
+ if (bt->bitrate > 800000)
|
|
+ sample_point_nominal = 750;
|
|
+ else if (bt->bitrate > 500000)
|
|
+ sample_point_nominal = 800;
|
|
+ else
|
|
+ sample_point_nominal = 875;
|
|
+ }
|
|
+
|
|
+ /* tseg even = round down, odd = round up */
|
|
+ for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
|
|
+ tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
|
|
+ tsegall = CAN_SYNC_SEG + tseg / 2;
|
|
+
|
|
+ /* Compute all possible tseg choices (tseg=tseg1+tseg2) */
|
|
+ brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
|
|
+
|
|
+ /* choose brp step which is possible in system */
|
|
+ brp = (brp / btc->brp_inc) * btc->brp_inc;
|
|
+ if (brp < btc->brp_min || brp > btc->brp_max)
|
|
+ continue;
|
|
+
|
|
+ bitrate = priv->clock.freq / (brp * tsegall);
|
|
+ bitrate_error = abs(bt->bitrate - bitrate);
|
|
+
|
|
+ /* tseg brp biterror */
|
|
+ if (bitrate_error > best_bitrate_error)
|
|
+ continue;
|
|
+
|
|
+ /* reset sample point error if we have a better bitrate */
|
|
+ if (bitrate_error < best_bitrate_error)
|
|
+ best_sample_point_error = UINT_MAX;
|
|
+
|
|
+ can_update_sample_point(btc, sample_point_nominal, tseg / 2,
|
|
+ &tseg1, &tseg2, &sample_point_error);
|
|
+ if (sample_point_error > best_sample_point_error)
|
|
+ continue;
|
|
+
|
|
+ best_sample_point_error = sample_point_error;
|
|
+ best_bitrate_error = bitrate_error;
|
|
+ best_tseg = tseg / 2;
|
|
+ best_brp = brp;
|
|
+
|
|
+ if (bitrate_error == 0 && sample_point_error == 0)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (best_bitrate_error) {
|
|
+ /* Error in one-tenth of a percent */
|
|
+ v64 = (u64)best_bitrate_error * 1000;
|
|
+ do_div(v64, bt->bitrate);
|
|
+ bitrate_error = (u32)v64;
|
|
+ if (bitrate_error > CAN_CALC_MAX_ERROR) {
|
|
+ netdev_err(dev,
|
|
+ "bitrate error %d.%d%% too high\n",
|
|
+ bitrate_error / 10, bitrate_error % 10);
|
|
+ return -EDOM;
|
|
+ }
|
|
+ netdev_warn(dev, "bitrate error %d.%d%%\n",
|
|
+ bitrate_error / 10, bitrate_error % 10);
|
|
+ }
|
|
+
|
|
+ /* real sample point */
|
|
+ bt->sample_point = can_update_sample_point(btc, sample_point_nominal,
|
|
+ best_tseg, &tseg1, &tseg2,
|
|
+ NULL);
|
|
+
|
|
+ v64 = (u64)best_brp * 1000 * 1000 * 1000;
|
|
+ do_div(v64, priv->clock.freq);
|
|
+ bt->tq = (u32)v64;
|
|
+ bt->prop_seg = tseg1 / 2;
|
|
+ bt->phase_seg1 = tseg1 - bt->prop_seg;
|
|
+ bt->phase_seg2 = tseg2;
|
|
+
|
|
+ /* check for sjw user settings */
|
|
+ if (!bt->sjw || !btc->sjw_max) {
|
|
+ bt->sjw = 1;
|
|
+ } else {
|
|
+ /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
|
|
+ if (bt->sjw > btc->sjw_max)
|
|
+ bt->sjw = btc->sjw_max;
|
|
+ /* bt->sjw must not be higher than tseg2 */
|
|
+ if (tseg2 < bt->sjw)
|
|
+ bt->sjw = tseg2;
|
|
+ }
|
|
+
|
|
+ bt->brp = best_brp;
|
|
+
|
|
+ /* real bitrate */
|
|
+ bt->bitrate = priv->clock.freq /
|
|
+ (bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#else /* !CONFIG_CAN_CALC_BITTIMING */
|
|
+static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
|
+ const struct can_bittiming_const *btc)
|
|
+{
|
|
+ netdev_err(dev, "bit-timing calculation not available\n");
|
|
+ return -EINVAL;
|
|
+}
|
|
+#endif /* CONFIG_CAN_CALC_BITTIMING */
|
|
+
|
|
+/* Checks the validity of the specified bit-timing parameters prop_seg,
|
|
+ * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
|
|
+ * prescaler value brp. You can find more information in the header
|
|
+ * file linux/can/netlink.h.
|
|
+ */
|
|
+static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
|
+ const struct can_bittiming_const *btc)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+ int tseg1, alltseg;
|
|
+ u64 brp64;
|
|
+
|
|
+ tseg1 = bt->prop_seg + bt->phase_seg1;
|
|
+ if (!bt->sjw)
|
|
+ bt->sjw = 1;
|
|
+ if (bt->sjw > btc->sjw_max ||
|
|
+ tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max ||
|
|
+ bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max)
|
|
+ return -ERANGE;
|
|
+
|
|
+ brp64 = (u64)priv->clock.freq * (u64)bt->tq;
|
|
+ if (btc->brp_inc > 1)
|
|
+ do_div(brp64, btc->brp_inc);
|
|
+ brp64 += 500000000UL - 1;
|
|
+ do_div(brp64, 1000000000UL); /* the practicable BRP */
|
|
+ if (btc->brp_inc > 1)
|
|
+ brp64 *= btc->brp_inc;
|
|
+ bt->brp = (u32)brp64;
|
|
+
|
|
+ if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
|
|
+ return -EINVAL;
|
|
+
|
|
+ alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
|
|
+ bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
|
|
+ bt->sample_point = ((tseg1 + 1) * 1000) / alltseg;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Checks the validity of predefined bitrate settings */
|
|
+static int
|
|
+can_validate_bitrate(struct net_device *dev, struct can_bittiming *bt,
|
|
+ const u32 *bitrate_const,
|
|
+ const unsigned int bitrate_const_cnt)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+ unsigned int i;
|
|
+
|
|
+ for (i = 0; i < bitrate_const_cnt; i++) {
|
|
+ if (bt->bitrate == bitrate_const[i])
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (i >= priv->bitrate_const_cnt)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
|
+ const struct can_bittiming_const *btc,
|
|
+ const u32 *bitrate_const,
|
|
+ const unsigned int bitrate_const_cnt)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ /* Depending on the given can_bittiming parameter structure the CAN
|
|
+ * timing parameters are calculated based on the provided bitrate OR
|
|
+ * alternatively the CAN timing parameters (tq, prop_seg, etc.) are
|
|
+ * provided directly which are then checked and fixed up.
|
|
+ */
|
|
+ if (!bt->tq && bt->bitrate && btc)
|
|
+ err = can_calc_bittiming(dev, bt, btc);
|
|
+ else if (bt->tq && !bt->bitrate && btc)
|
|
+ err = can_fixup_bittiming(dev, bt, btc);
|
|
+ else if (!bt->tq && bt->bitrate && bitrate_const)
|
|
+ err = can_validate_bitrate(dev, bt, bitrate_const,
|
|
+ bitrate_const_cnt);
|
|
+ else
|
|
+ err = -EINVAL;
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static void can_update_state_error_stats(struct net_device *dev,
|
|
+ enum can_state new_state)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+
|
|
+ if (new_state <= priv->state)
|
|
+ return;
|
|
+
|
|
+ switch (new_state) {
|
|
+ case CAN_STATE_ERROR_WARNING:
|
|
+ priv->can_stats.error_warning++;
|
|
+ break;
|
|
+ case CAN_STATE_ERROR_PASSIVE:
|
|
+ priv->can_stats.error_passive++;
|
|
+ break;
|
|
+ case CAN_STATE_BUS_OFF:
|
|
+ priv->can_stats.bus_off++;
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int can_tx_state_to_frame(struct net_device *dev, enum can_state state)
|
|
+{
|
|
+ switch (state) {
|
|
+ case CAN_STATE_ERROR_ACTIVE:
|
|
+ return CAN_ERR_CRTL_ACTIVE;
|
|
+ case CAN_STATE_ERROR_WARNING:
|
|
+ return CAN_ERR_CRTL_TX_WARNING;
|
|
+ case CAN_STATE_ERROR_PASSIVE:
|
|
+ return CAN_ERR_CRTL_TX_PASSIVE;
|
|
+ default:
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int can_rx_state_to_frame(struct net_device *dev, enum can_state state)
|
|
+{
|
|
+ switch (state) {
|
|
+ case CAN_STATE_ERROR_ACTIVE:
|
|
+ return CAN_ERR_CRTL_ACTIVE;
|
|
+ case CAN_STATE_ERROR_WARNING:
|
|
+ return CAN_ERR_CRTL_RX_WARNING;
|
|
+ case CAN_STATE_ERROR_PASSIVE:
|
|
+ return CAN_ERR_CRTL_RX_PASSIVE;
|
|
+ default:
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+static const char *can_get_state_str(const enum can_state state)
|
|
+{
|
|
+ switch (state) {
|
|
+ case CAN_STATE_ERROR_ACTIVE:
|
|
+ return "Error Active";
|
|
+ case CAN_STATE_ERROR_WARNING:
|
|
+ return "Error Warning";
|
|
+ case CAN_STATE_ERROR_PASSIVE:
|
|
+ return "Error Passive";
|
|
+ case CAN_STATE_BUS_OFF:
|
|
+ return "Bus Off";
|
|
+ case CAN_STATE_STOPPED:
|
|
+ return "Stopped";
|
|
+ case CAN_STATE_SLEEPING:
|
|
+ return "Sleeping";
|
|
+ default:
|
|
+ return "<unknown>";
|
|
+ }
|
|
+
|
|
+ return "<unknown>";
|
|
+}
|
|
+
|
|
+void can_change_state(struct net_device *dev, struct can_frame *cf,
|
|
+ enum can_state tx_state, enum can_state rx_state)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+ enum can_state new_state = max(tx_state, rx_state);
|
|
+
|
|
+ if (unlikely(new_state == priv->state)) {
|
|
+ netdev_warn(dev, "%s: oops, state did not change", __func__);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ netdev_dbg(dev, "Controller changed from %s State (%d) into %s State (%d).\n",
|
|
+ can_get_state_str(priv->state), priv->state,
|
|
+ can_get_state_str(new_state), new_state);
|
|
+
|
|
+ can_update_state_error_stats(dev, new_state);
|
|
+ priv->state = new_state;
|
|
+
|
|
+ if (!cf)
|
|
+ return;
|
|
+
|
|
+ if (unlikely(new_state == CAN_STATE_BUS_OFF)) {
|
|
+ cf->can_id |= CAN_ERR_BUSOFF;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ cf->can_id |= CAN_ERR_CRTL;
|
|
+ cf->data[1] |= tx_state >= rx_state ?
|
|
+ can_tx_state_to_frame(dev, tx_state) : 0;
|
|
+ cf->data[1] |= tx_state <= rx_state ?
|
|
+ can_rx_state_to_frame(dev, rx_state) : 0;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_change_state);
|
|
+
|
|
+/* Local echo of CAN messages
|
|
+ *
|
|
+ * CAN network devices *should* support a local echo functionality
|
|
+ * (see Documentation/networking/can.rst). To test the handling of CAN
|
|
+ * interfaces that do not support the local echo both driver types are
|
|
+ * implemented. In the case that the driver does not support the echo
|
|
+ * the IFF_ECHO remains clear in dev->flags. This causes the PF_CAN core
|
|
+ * to perform the echo as a fallback solution.
|
|
+ */
|
|
+static void can_flush_echo_skb(struct net_device *dev)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+ struct net_device_stats *stats = &dev->stats;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < priv->echo_skb_max; i++) {
|
|
+ if (priv->echo_skb[i]) {
|
|
+ kfree_skb(priv->echo_skb[i]);
|
|
+ priv->echo_skb[i] = NULL;
|
|
+ stats->tx_dropped++;
|
|
+ stats->tx_aborted_errors++;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Put the skb on the stack to be looped backed locally lateron
|
|
+ *
|
|
+ * The function is typically called in the start_xmit function
|
|
+ * of the device driver. The driver must protect access to
|
|
+ * priv->echo_skb, if necessary.
|
|
+ */
|
|
+int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
|
+ unsigned int idx)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+
|
|
+ BUG_ON(idx >= priv->echo_skb_max);
|
|
+
|
|
+ /* check flag whether this packet has to be looped back */
|
|
+ if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK ||
|
|
+ (skb->protocol != htons(ETH_P_CAN) &&
|
|
+ skb->protocol != htons(ETH_P_CANFD))) {
|
|
+ kfree_skb(skb);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!priv->echo_skb[idx]) {
|
|
+ skb = can_create_echo_skb(skb);
|
|
+ if (!skb)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ /* make settings for echo to reduce code in irq context */
|
|
+ skb->pkt_type = PACKET_BROADCAST;
|
|
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
+ skb->dev = dev;
|
|
+
|
|
+ /* save this skb for tx interrupt echo handling */
|
|
+ priv->echo_skb[idx] = skb;
|
|
+ } else {
|
|
+ /* locking problem with netif_stop_queue() ?? */
|
|
+ netdev_err(dev, "%s: BUG! echo_skb %d is occupied!\n", __func__, idx);
|
|
+ kfree_skb(skb);
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_put_echo_skb);
|
|
+
|
|
+struct sk_buff *
|
|
+__can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+
|
|
+ if (idx >= priv->echo_skb_max) {
|
|
+ netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
|
|
+ __func__, idx, priv->echo_skb_max);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (priv->echo_skb[idx]) {
|
|
+ /* Using "struct canfd_frame::len" for the frame
|
|
+ * length is supported on both CAN and CANFD frames.
|
|
+ */
|
|
+ struct sk_buff *skb = priv->echo_skb[idx];
|
|
+ struct canfd_frame *cf = (struct canfd_frame *)skb->data;
|
|
+
|
|
+ /* get the real payload length for netdev statistics */
|
|
+ if (cf->can_id & CAN_RTR_FLAG)
|
|
+ *len_ptr = 0;
|
|
+ else
|
|
+ *len_ptr = cf->len;
|
|
+
|
|
+ priv->echo_skb[idx] = NULL;
|
|
+
|
|
+ return skb;
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/* Get the skb from the stack and loop it back locally
|
|
+ *
|
|
+ * The function is typically called when the TX done interrupt
|
|
+ * is handled in the device driver. The driver must protect
|
|
+ * access to priv->echo_skb, if necessary.
|
|
+ */
|
|
+unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx)
|
|
+{
|
|
+ struct sk_buff *skb;
|
|
+ u8 len;
|
|
+
|
|
+ skb = __can_get_echo_skb(dev, idx, &len);
|
|
+ if (!skb)
|
|
+ return 0;
|
|
+
|
|
+ skb_get(skb);
|
|
+ if (netif_rx(skb) == NET_RX_SUCCESS)
|
|
+ dev_consume_skb_any(skb);
|
|
+ else
|
|
+ dev_kfree_skb_any(skb);
|
|
+
|
|
+ return len;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_get_echo_skb);
|
|
+
|
|
+/* Remove the skb from the stack and free it.
|
|
+ *
|
|
+ * The function is typically called when TX failed.
|
|
+ */
|
|
+void can_free_echo_skb(struct net_device *dev, unsigned int idx)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+
|
|
+ BUG_ON(idx >= priv->echo_skb_max);
|
|
+
|
|
+ if (priv->echo_skb[idx]) {
|
|
+ dev_kfree_skb_any(priv->echo_skb[idx]);
|
|
+ priv->echo_skb[idx] = NULL;
|
|
+ }
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_free_echo_skb);
|
|
+
|
|
+/* CAN device restart for bus-off recovery */
|
|
+static void can_restart(struct net_device *dev)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+ struct net_device_stats *stats = &dev->stats;
|
|
+ struct sk_buff *skb;
|
|
+ struct can_frame *cf;
|
|
+ int err;
|
|
+
|
|
+ BUG_ON(netif_carrier_ok(dev));
|
|
+
|
|
+ /* No synchronization needed because the device is bus-off and
|
|
+ * no messages can come in or go out.
|
|
+ */
|
|
+ can_flush_echo_skb(dev);
|
|
+
|
|
+ /* send restart message upstream */
|
|
+ skb = alloc_can_err_skb(dev, &cf);
|
|
+ if (!skb)
|
|
+ goto restart;
|
|
+
|
|
+ cf->can_id |= CAN_ERR_RESTARTED;
|
|
+
|
|
+ stats->rx_packets++;
|
|
+ stats->rx_bytes += cf->can_dlc;
|
|
+
|
|
+ netif_rx_ni(skb);
|
|
+
|
|
+restart:
|
|
+ netdev_dbg(dev, "restarted\n");
|
|
+ priv->can_stats.restarts++;
|
|
+
|
|
+ /* Now restart the device */
|
|
+ err = priv->do_set_mode(dev, CAN_MODE_START);
|
|
+
|
|
+ netif_carrier_on(dev);
|
|
+ if (err)
|
|
+ netdev_err(dev, "Error %d during restart", err);
|
|
+}
|
|
+
|
|
+static void can_restart_work(struct work_struct *work)
|
|
+{
|
|
+ struct delayed_work *dwork = to_delayed_work(work);
|
|
+ struct can_priv *priv = container_of(dwork, struct can_priv,
|
|
+ restart_work);
|
|
+
|
|
+ can_restart(priv->dev);
|
|
+}
|
|
+
|
|
+int can_restart_now(struct net_device *dev)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+
|
|
+ /* A manual restart is only permitted if automatic restart is
|
|
+ * disabled and the device is in the bus-off state
|
|
+ */
|
|
+ if (priv->restart_ms)
|
|
+ return -EINVAL;
|
|
+ if (priv->state != CAN_STATE_BUS_OFF)
|
|
+ return -EBUSY;
|
|
+
|
|
+ cancel_delayed_work_sync(&priv->restart_work);
|
|
+ can_restart(dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* CAN bus-off
|
|
+ *
|
|
+ * This functions should be called when the device goes bus-off to
|
|
+ * tell the netif layer that no more packets can be sent or received.
|
|
+ * If enabled, a timer is started to trigger bus-off recovery.
|
|
+ */
|
|
+void can_bus_off(struct net_device *dev)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+
|
|
+ if (priv->restart_ms)
|
|
+ netdev_info(dev, "bus-off, scheduling restart in %d ms\n",
|
|
+ priv->restart_ms);
|
|
+ else
|
|
+ netdev_info(dev, "bus-off\n");
|
|
+
|
|
+ netif_carrier_off(dev);
|
|
+
|
|
+ if (priv->restart_ms)
|
|
+ schedule_delayed_work(&priv->restart_work,
|
|
+ msecs_to_jiffies(priv->restart_ms));
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_bus_off);
|
|
+
|
|
+static void can_setup(struct net_device *dev)
|
|
+{
|
|
+ dev->type = ARPHRD_CAN;
|
|
+ dev->mtu = CAN_MTU;
|
|
+ dev->hard_header_len = 0;
|
|
+ dev->addr_len = 0;
|
|
+ dev->tx_queue_len = 10;
|
|
+
|
|
+ /* New-style flags. */
|
|
+ dev->flags = IFF_NOARP;
|
|
+ dev->features = NETIF_F_HW_CSUM;
|
|
+}
|
|
+
|
|
+struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
|
|
+{
|
|
+ struct sk_buff *skb;
|
|
+
|
|
+ skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
|
|
+ sizeof(struct can_frame));
|
|
+ if (unlikely(!skb))
|
|
+ return NULL;
|
|
+
|
|
+ skb->protocol = htons(ETH_P_CAN);
|
|
+ skb->pkt_type = PACKET_BROADCAST;
|
|
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
+
|
|
+ skb_reset_mac_header(skb);
|
|
+ skb_reset_network_header(skb);
|
|
+ skb_reset_transport_header(skb);
|
|
+
|
|
+ can_skb_reserve(skb);
|
|
+ can_skb_prv(skb)->ifindex = dev->ifindex;
|
|
+ can_skb_prv(skb)->skbcnt = 0;
|
|
+
|
|
+ *cf = skb_put_zero(skb, sizeof(struct can_frame));
|
|
+
|
|
+ return skb;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(alloc_can_skb);
|
|
+
|
|
+struct sk_buff *alloc_canfd_skb(struct net_device *dev,
|
|
+ struct canfd_frame **cfd)
|
|
+{
|
|
+ struct sk_buff *skb;
|
|
+
|
|
+ skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
|
|
+ sizeof(struct canfd_frame));
|
|
+ if (unlikely(!skb))
|
|
+ return NULL;
|
|
+
|
|
+ skb->protocol = htons(ETH_P_CANFD);
|
|
+ skb->pkt_type = PACKET_BROADCAST;
|
|
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
+
|
|
+ skb_reset_mac_header(skb);
|
|
+ skb_reset_network_header(skb);
|
|
+ skb_reset_transport_header(skb);
|
|
+
|
|
+ can_skb_reserve(skb);
|
|
+ can_skb_prv(skb)->ifindex = dev->ifindex;
|
|
+ can_skb_prv(skb)->skbcnt = 0;
|
|
+
|
|
+ *cfd = skb_put_zero(skb, sizeof(struct canfd_frame));
|
|
+
|
|
+ return skb;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(alloc_canfd_skb);
|
|
+
|
|
+struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
|
|
+{
|
|
+ struct sk_buff *skb;
|
|
+
|
|
+ skb = alloc_can_skb(dev, cf);
|
|
+ if (unlikely(!skb))
|
|
+ return NULL;
|
|
+
|
|
+ (*cf)->can_id = CAN_ERR_FLAG;
|
|
+ (*cf)->can_dlc = CAN_ERR_DLC;
|
|
+
|
|
+ return skb;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(alloc_can_err_skb);
|
|
+
|
|
+/* Allocate and setup space for the CAN network device */
|
|
+struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,
|
|
+ unsigned int txqs, unsigned int rxqs)
|
|
+{
|
|
+ struct can_ml_priv *can_ml;
|
|
+ struct net_device *dev;
|
|
+ struct can_priv *priv;
|
|
+ int size;
|
|
+
|
|
+ /* We put the driver's priv, the CAN mid layer priv and the
|
|
+ * echo skb into the netdevice's priv. The memory layout for
|
|
+ * the netdev_priv is like this:
|
|
+ *
|
|
+ * +-------------------------+
|
|
+ * | driver's priv |
|
|
+ * +-------------------------+
|
|
+ * | struct can_ml_priv |
|
|
+ * +-------------------------+
|
|
+ * | array of struct sk_buff |
|
|
+ * +-------------------------+
|
|
+ */
|
|
+
|
|
+ size = ALIGN(sizeof_priv, NETDEV_ALIGN) + sizeof(struct can_ml_priv);
|
|
+
|
|
+ if (echo_skb_max)
|
|
+ size = ALIGN(size, sizeof(struct sk_buff *)) +
|
|
+ echo_skb_max * sizeof(struct sk_buff *);
|
|
+
|
|
+ dev = alloc_netdev_mqs(size, "can%d", NET_NAME_UNKNOWN, can_setup,
|
|
+ txqs, rxqs);
|
|
+ if (!dev)
|
|
+ return NULL;
|
|
+
|
|
+ priv = netdev_priv(dev);
|
|
+ priv->dev = dev;
|
|
+
|
|
+ can_ml = (void *)priv + ALIGN(sizeof_priv, NETDEV_ALIGN);
|
|
+ can_set_ml_priv(dev, can_ml);
|
|
+
|
|
+ if (echo_skb_max) {
|
|
+ priv->echo_skb_max = echo_skb_max;
|
|
+ priv->echo_skb = (void *)priv +
|
|
+ (size - echo_skb_max * sizeof(struct sk_buff *));
|
|
+ }
|
|
+
|
|
+ priv->state = CAN_STATE_STOPPED;
|
|
+
|
|
+ INIT_DELAYED_WORK(&priv->restart_work, can_restart_work);
|
|
+
|
|
+ return dev;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(alloc_candev_mqs);
|
|
+
|
|
+/* Free space of the CAN network device */
|
|
+void free_candev(struct net_device *dev)
|
|
+{
|
|
+ free_netdev(dev);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(free_candev);
|
|
+
|
|
+/* changing MTU and control mode for CAN/CANFD devices */
|
|
+int can_change_mtu(struct net_device *dev, int new_mtu)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+
|
|
+ /* Do not allow changing the MTU while running */
|
|
+ if (dev->flags & IFF_UP)
|
|
+ return -EBUSY;
|
|
+
|
|
+ /* allow change of MTU according to the CANFD ability of the device */
|
|
+ switch (new_mtu) {
|
|
+ case CAN_MTU:
|
|
+ /* 'CANFD-only' controllers can not switch to CAN_MTU */
|
|
+ if (priv->ctrlmode_static & CAN_CTRLMODE_FD)
|
|
+ return -EINVAL;
|
|
+
|
|
+ priv->ctrlmode &= ~CAN_CTRLMODE_FD;
|
|
+ break;
|
|
+
|
|
+ case CANFD_MTU:
|
|
+ /* check for potential CANFD ability */
|
|
+ if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD) &&
|
|
+ !(priv->ctrlmode_static & CAN_CTRLMODE_FD))
|
|
+ return -EINVAL;
|
|
+
|
|
+ priv->ctrlmode |= CAN_CTRLMODE_FD;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ dev->mtu = new_mtu;
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_change_mtu);
|
|
+
|
|
+/* Common open function when the device gets opened.
|
|
+ *
|
|
+ * This function should be called in the open function of the device
|
|
+ * driver.
|
|
+ */
|
|
+int open_candev(struct net_device *dev)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+
|
|
+ if (!priv->bittiming.bitrate) {
|
|
+ netdev_err(dev, "bit-timing not yet defined\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* For CAN FD the data bitrate has to be >= the arbitration bitrate */
|
|
+ if ((priv->ctrlmode & CAN_CTRLMODE_FD) &&
|
|
+ (!priv->data_bittiming.bitrate ||
|
|
+ priv->data_bittiming.bitrate < priv->bittiming.bitrate)) {
|
|
+ netdev_err(dev, "incorrect/missing data bit-timing\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Switch carrier on if device was stopped while in bus-off state */
|
|
+ if (!netif_carrier_ok(dev))
|
|
+ netif_carrier_on(dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(open_candev);
|
|
+
|
|
+#ifdef CONFIG_OF
|
|
+/* Common function that can be used to understand the limitation of
|
|
+ * a transceiver when it provides no means to determine these limitations
|
|
+ * at runtime.
|
|
+ */
|
|
+void of_can_transceiver(struct net_device *dev)
|
|
+{
|
|
+ struct device_node *dn;
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+ struct device_node *np = dev->dev.parent->of_node;
|
|
+ int ret;
|
|
+
|
|
+ dn = of_get_child_by_name(np, "can-transceiver");
|
|
+ if (!dn)
|
|
+ return;
|
|
+
|
|
+ ret = of_property_read_u32(dn, "max-bitrate", &priv->bitrate_max);
|
|
+ of_node_put(dn);
|
|
+ if ((ret && ret != -EINVAL) || (!ret && !priv->bitrate_max))
|
|
+ netdev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit.\n");
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(of_can_transceiver);
|
|
+#endif
|
|
+
|
|
+/* Common close function for cleanup before the device gets closed.
|
|
+ *
|
|
+ * This function should be called in the close function of the device
|
|
+ * driver.
|
|
+ */
|
|
+void close_candev(struct net_device *dev)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+
|
|
+ cancel_delayed_work_sync(&priv->restart_work);
|
|
+ can_flush_echo_skb(dev);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(close_candev);
|
|
+
|
|
+/* CAN netlink interface */
|
|
+static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
|
|
+ [IFLA_CAN_STATE] = { .type = NLA_U32 },
|
|
+ [IFLA_CAN_CTRLMODE] = { .len = sizeof(struct can_ctrlmode) },
|
|
+ [IFLA_CAN_RESTART_MS] = { .type = NLA_U32 },
|
|
+ [IFLA_CAN_RESTART] = { .type = NLA_U32 },
|
|
+ [IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) },
|
|
+ [IFLA_CAN_BITTIMING_CONST]
|
|
+ = { .len = sizeof(struct can_bittiming_const) },
|
|
+ [IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) },
|
|
+ [IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
|
|
+ [IFLA_CAN_DATA_BITTIMING]
|
|
+ = { .len = sizeof(struct can_bittiming) },
|
|
+ [IFLA_CAN_DATA_BITTIMING_CONST]
|
|
+ = { .len = sizeof(struct can_bittiming_const) },
|
|
+ [IFLA_CAN_TERMINATION] = { .type = NLA_U16 },
|
|
+};
|
|
+
|
|
+static int can_validate(struct nlattr *tb[], struct nlattr *data[],
|
|
+ struct netlink_ext_ack *extack)
|
|
+{
|
|
+ bool is_can_fd = false;
|
|
+
|
|
+ /* Make sure that valid CAN FD configurations always consist of
|
|
+ * - nominal/arbitration bittiming
|
|
+ * - data bittiming
|
|
+ * - control mode with CAN_CTRLMODE_FD set
|
|
+ */
|
|
+
|
|
+ if (!data)
|
|
+ return 0;
|
|
+
|
|
+ if (data[IFLA_CAN_CTRLMODE]) {
|
|
+ struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
|
|
+
|
|
+ is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD;
|
|
+ }
|
|
+
|
|
+ if (is_can_fd) {
|
|
+ if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING])
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+ if (data[IFLA_CAN_DATA_BITTIMING]) {
|
|
+ if (!is_can_fd || !data[IFLA_CAN_BITTIMING])
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
|
+ struct nlattr *data[],
|
|
+ struct netlink_ext_ack *extack)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+ int err;
|
|
+
|
|
+ /* We need synchronization with dev->stop() */
|
|
+ ASSERT_RTNL();
|
|
+
|
|
+ if (data[IFLA_CAN_BITTIMING]) {
|
|
+ struct can_bittiming bt;
|
|
+
|
|
+ /* Do not allow changing bittiming while running */
|
|
+ if (dev->flags & IFF_UP)
|
|
+ return -EBUSY;
|
|
+
|
|
+ /* Calculate bittiming parameters based on
|
|
+ * bittiming_const if set, otherwise pass bitrate
|
|
+ * directly via do_set_bitrate(). Bail out if neither
|
|
+ * is given.
|
|
+ */
|
|
+ if (!priv->bittiming_const && !priv->do_set_bittiming)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
|
|
+ err = can_get_bittiming(dev, &bt,
|
|
+ priv->bittiming_const,
|
|
+ priv->bitrate_const,
|
|
+ priv->bitrate_const_cnt);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
|
|
+ netdev_err(dev, "arbitration bitrate surpasses transceiver capabilities of %d bps\n",
|
|
+ priv->bitrate_max);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ memcpy(&priv->bittiming, &bt, sizeof(bt));
|
|
+
|
|
+ if (priv->do_set_bittiming) {
|
|
+ /* Finally, set the bit-timing registers */
|
|
+ err = priv->do_set_bittiming(dev);
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (data[IFLA_CAN_CTRLMODE]) {
|
|
+ struct can_ctrlmode *cm;
|
|
+ u32 ctrlstatic;
|
|
+ u32 maskedflags;
|
|
+
|
|
+ /* Do not allow changing controller mode while running */
|
|
+ if (dev->flags & IFF_UP)
|
|
+ return -EBUSY;
|
|
+ cm = nla_data(data[IFLA_CAN_CTRLMODE]);
|
|
+ ctrlstatic = priv->ctrlmode_static;
|
|
+ maskedflags = cm->flags & cm->mask;
|
|
+
|
|
+ /* check whether provided bits are allowed to be passed */
|
|
+ if (cm->mask & ~(priv->ctrlmode_supported | ctrlstatic))
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ /* do not check for static fd-non-iso if 'fd' is disabled */
|
|
+ if (!(maskedflags & CAN_CTRLMODE_FD))
|
|
+ ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO;
|
|
+
|
|
+ /* make sure static options are provided by configuration */
|
|
+ if ((maskedflags & ctrlstatic) != ctrlstatic)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ /* clear bits to be modified and copy the flag values */
|
|
+ priv->ctrlmode &= ~cm->mask;
|
|
+ priv->ctrlmode |= maskedflags;
|
|
+
|
|
+ /* CAN_CTRLMODE_FD can only be set when driver supports FD */
|
|
+ if (priv->ctrlmode & CAN_CTRLMODE_FD)
|
|
+ dev->mtu = CANFD_MTU;
|
|
+ else
|
|
+ dev->mtu = CAN_MTU;
|
|
+ }
|
|
+
|
|
+ if (data[IFLA_CAN_RESTART_MS]) {
|
|
+ /* Do not allow changing restart delay while running */
|
|
+ if (dev->flags & IFF_UP)
|
|
+ return -EBUSY;
|
|
+ priv->restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]);
|
|
+ }
|
|
+
|
|
+ if (data[IFLA_CAN_RESTART]) {
|
|
+ /* Do not allow a restart while not running */
|
|
+ if (!(dev->flags & IFF_UP))
|
|
+ return -EINVAL;
|
|
+ err = can_restart_now(dev);
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ if (data[IFLA_CAN_DATA_BITTIMING]) {
|
|
+ struct can_bittiming dbt;
|
|
+
|
|
+ /* Do not allow changing bittiming while running */
|
|
+ if (dev->flags & IFF_UP)
|
|
+ return -EBUSY;
|
|
+
|
|
+ /* Calculate bittiming parameters based on
|
|
+ * data_bittiming_const if set, otherwise pass bitrate
|
|
+ * directly via do_set_bitrate(). Bail out if neither
|
|
+ * is given.
|
|
+ */
|
|
+ if (!priv->data_bittiming_const && !priv->do_set_data_bittiming)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
|
|
+ sizeof(dbt));
|
|
+ err = can_get_bittiming(dev, &dbt,
|
|
+ priv->data_bittiming_const,
|
|
+ priv->data_bitrate_const,
|
|
+ priv->data_bitrate_const_cnt);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) {
|
|
+ netdev_err(dev, "canfd data bitrate surpasses transceiver capabilities of %d bps\n",
|
|
+ priv->bitrate_max);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
|
|
+
|
|
+ if (priv->do_set_data_bittiming) {
|
|
+ /* Finally, set the bit-timing registers */
|
|
+ err = priv->do_set_data_bittiming(dev);
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (data[IFLA_CAN_TERMINATION]) {
|
|
+ const u16 termval = nla_get_u16(data[IFLA_CAN_TERMINATION]);
|
|
+ const unsigned int num_term = priv->termination_const_cnt;
|
|
+ unsigned int i;
|
|
+
|
|
+ if (!priv->do_set_termination)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ /* check whether given value is supported by the interface */
|
|
+ for (i = 0; i < num_term; i++) {
|
|
+ if (termval == priv->termination_const[i])
|
|
+ break;
|
|
+ }
|
|
+ if (i >= num_term)
|
|
+ return -EINVAL;
|
|
+
|
|
+ /* Finally, set the termination value */
|
|
+ err = priv->do_set_termination(dev, termval);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ priv->termination = termval;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static size_t can_get_size(const struct net_device *dev)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+ size_t size = 0;
|
|
+
|
|
+ if (priv->bittiming.bitrate) /* IFLA_CAN_BITTIMING */
|
|
+ size += nla_total_size(sizeof(struct can_bittiming));
|
|
+ if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */
|
|
+ size += nla_total_size(sizeof(struct can_bittiming_const));
|
|
+ size += nla_total_size(sizeof(struct can_clock)); /* IFLA_CAN_CLOCK */
|
|
+ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_STATE */
|
|
+ size += nla_total_size(sizeof(struct can_ctrlmode)); /* IFLA_CAN_CTRLMODE */
|
|
+ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */
|
|
+ if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */
|
|
+ size += nla_total_size(sizeof(struct can_berr_counter));
|
|
+ if (priv->data_bittiming.bitrate) /* IFLA_CAN_DATA_BITTIMING */
|
|
+ size += nla_total_size(sizeof(struct can_bittiming));
|
|
+ if (priv->data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */
|
|
+ size += nla_total_size(sizeof(struct can_bittiming_const));
|
|
+ if (priv->termination_const) {
|
|
+ size += nla_total_size(sizeof(priv->termination)); /* IFLA_CAN_TERMINATION */
|
|
+ size += nla_total_size(sizeof(*priv->termination_const) * /* IFLA_CAN_TERMINATION_CONST */
|
|
+ priv->termination_const_cnt);
|
|
+ }
|
|
+ if (priv->bitrate_const) /* IFLA_CAN_BITRATE_CONST */
|
|
+ size += nla_total_size(sizeof(*priv->bitrate_const) *
|
|
+ priv->bitrate_const_cnt);
|
|
+ if (priv->data_bitrate_const) /* IFLA_CAN_DATA_BITRATE_CONST */
|
|
+ size += nla_total_size(sizeof(*priv->data_bitrate_const) *
|
|
+ priv->data_bitrate_const_cnt);
|
|
+ size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */
|
|
+
|
|
+ return size;
|
|
+}
|
|
+
|
|
+static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+ struct can_ctrlmode cm = {.flags = priv->ctrlmode};
|
|
+ struct can_berr_counter bec = { };
|
|
+ enum can_state state = priv->state;
|
|
+
|
|
+ if (priv->do_get_state)
|
|
+ priv->do_get_state(dev, &state);
|
|
+
|
|
+ if ((priv->bittiming.bitrate &&
|
|
+ nla_put(skb, IFLA_CAN_BITTIMING,
|
|
+ sizeof(priv->bittiming), &priv->bittiming)) ||
|
|
+
|
|
+ (priv->bittiming_const &&
|
|
+ nla_put(skb, IFLA_CAN_BITTIMING_CONST,
|
|
+ sizeof(*priv->bittiming_const), priv->bittiming_const)) ||
|
|
+
|
|
+ nla_put(skb, IFLA_CAN_CLOCK, sizeof(priv->clock), &priv->clock) ||
|
|
+ nla_put_u32(skb, IFLA_CAN_STATE, state) ||
|
|
+ nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
|
|
+ nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
|
|
+
|
|
+ (priv->do_get_berr_counter &&
|
|
+ !priv->do_get_berr_counter(dev, &bec) &&
|
|
+ nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
|
|
+
|
|
+ (priv->data_bittiming.bitrate &&
|
|
+ nla_put(skb, IFLA_CAN_DATA_BITTIMING,
|
|
+ sizeof(priv->data_bittiming), &priv->data_bittiming)) ||
|
|
+
|
|
+ (priv->data_bittiming_const &&
|
|
+ nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST,
|
|
+ sizeof(*priv->data_bittiming_const),
|
|
+ priv->data_bittiming_const)) ||
|
|
+
|
|
+ (priv->termination_const &&
|
|
+ (nla_put_u16(skb, IFLA_CAN_TERMINATION, priv->termination) ||
|
|
+ nla_put(skb, IFLA_CAN_TERMINATION_CONST,
|
|
+ sizeof(*priv->termination_const) *
|
|
+ priv->termination_const_cnt,
|
|
+ priv->termination_const))) ||
|
|
+
|
|
+ (priv->bitrate_const &&
|
|
+ nla_put(skb, IFLA_CAN_BITRATE_CONST,
|
|
+ sizeof(*priv->bitrate_const) *
|
|
+ priv->bitrate_const_cnt,
|
|
+ priv->bitrate_const)) ||
|
|
+
|
|
+ (priv->data_bitrate_const &&
|
|
+ nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST,
|
|
+ sizeof(*priv->data_bitrate_const) *
|
|
+ priv->data_bitrate_const_cnt,
|
|
+ priv->data_bitrate_const)) ||
|
|
+
|
|
+ (nla_put(skb, IFLA_CAN_BITRATE_MAX,
|
|
+ sizeof(priv->bitrate_max),
|
|
+ &priv->bitrate_max))
|
|
+ )
|
|
+
|
|
+ return -EMSGSIZE;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static size_t can_get_xstats_size(const struct net_device *dev)
|
|
+{
|
|
+ return sizeof(struct can_device_stats);
|
|
+}
|
|
+
|
|
+static int can_fill_xstats(struct sk_buff *skb, const struct net_device *dev)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+
|
|
+ if (nla_put(skb, IFLA_INFO_XSTATS,
|
|
+ sizeof(priv->can_stats), &priv->can_stats))
|
|
+ goto nla_put_failure;
|
|
+ return 0;
|
|
+
|
|
+nla_put_failure:
|
|
+ return -EMSGSIZE;
|
|
+}
|
|
+
|
|
+static int can_newlink(struct net *src_net, struct net_device *dev,
|
|
+ struct nlattr *tb[], struct nlattr *data[],
|
|
+ struct netlink_ext_ack *extack)
|
|
+{
|
|
+ return -EOPNOTSUPP;
|
|
+}
|
|
+
|
|
+static void can_dellink(struct net_device *dev, struct list_head *head)
|
|
+{
|
|
+}
|
|
+
|
|
+static struct rtnl_link_ops can_link_ops __read_mostly = {
|
|
+ .kind = "can",
|
|
+ .netns_refund = true,
|
|
+ .maxtype = IFLA_CAN_MAX,
|
|
+ .policy = can_policy,
|
|
+ .setup = can_setup,
|
|
+ .validate = can_validate,
|
|
+ .newlink = can_newlink,
|
|
+ .changelink = can_changelink,
|
|
+ .dellink = can_dellink,
|
|
+ .get_size = can_get_size,
|
|
+ .fill_info = can_fill_info,
|
|
+ .get_xstats_size = can_get_xstats_size,
|
|
+ .fill_xstats = can_fill_xstats,
|
|
+};
|
|
+
|
|
+/* Register the CAN network device */
|
|
+int register_candev(struct net_device *dev)
|
|
+{
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
+
|
|
+ /* Ensure termination_const, termination_const_cnt and
|
|
+ * do_set_termination consistency. All must be either set or
|
|
+ * unset.
|
|
+ */
|
|
+ if ((!priv->termination_const != !priv->termination_const_cnt) ||
|
|
+ (!priv->termination_const != !priv->do_set_termination))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!priv->bitrate_const != !priv->bitrate_const_cnt)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!priv->data_bitrate_const != !priv->data_bitrate_const_cnt)
|
|
+ return -EINVAL;
|
|
+
|
|
+ dev->rtnl_link_ops = &can_link_ops;
|
|
+ netif_carrier_off(dev);
|
|
+
|
|
+ return register_netdev(dev);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(register_candev);
|
|
+
|
|
+/* Unregister the CAN network device */
|
|
+void unregister_candev(struct net_device *dev)
|
|
+{
|
|
+ unregister_netdev(dev);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(unregister_candev);
|
|
+
|
|
+/* Test if a network device is a candev based device
|
|
+ * and return the can_priv* if so.
|
|
+ */
|
|
+struct can_priv *safe_candev_priv(struct net_device *dev)
|
|
+{
|
|
+ if (dev->type != ARPHRD_CAN || dev->rtnl_link_ops != &can_link_ops)
|
|
+ return NULL;
|
|
+
|
|
+ return netdev_priv(dev);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(safe_candev_priv);
|
|
+
|
|
+static __init int can_dev_init(void)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ can_led_notifier_init();
|
|
+
|
|
+ err = rtnl_link_register(&can_link_ops);
|
|
+ if (!err)
|
|
+ pr_info(MOD_DESC "\n");
|
|
+
|
|
+ return err;
|
|
+}
|
|
+module_init(can_dev_init);
|
|
+
|
|
+static __exit void can_dev_exit(void)
|
|
+{
|
|
+ rtnl_link_unregister(&can_link_ops);
|
|
+
|
|
+ can_led_notifier_exit();
|
|
+}
|
|
+module_exit(can_dev_exit);
|
|
+
|
|
+MODULE_ALIAS_RTNL_LINK("can");
|
|
diff --git a/drivers/net/can/dev/rx-offload.c b/drivers/net/can/dev/rx-offload.c
|
|
new file mode 100644
|
|
index 0000000000000..6e95193b215ba
|
|
--- /dev/null
|
|
+++ b/drivers/net/can/dev/rx-offload.c
|
|
@@ -0,0 +1,376 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-only
|
|
+/* Copyright (c) 2014 Protonic Holland,
|
|
+ * David Jander
|
|
+ * Copyright (C) 2014-2017 Pengutronix,
|
|
+ * Marc Kleine-Budde <kernel@pengutronix.de>
|
|
+ */
|
|
+
|
|
+#include <linux/can/dev.h>
|
|
+#include <linux/can/rx-offload.h>
|
|
+
|
|
+struct can_rx_offload_cb {
|
|
+ u32 timestamp;
|
|
+};
|
|
+
|
|
+static inline struct can_rx_offload_cb *
|
|
+can_rx_offload_get_cb(struct sk_buff *skb)
|
|
+{
|
|
+ BUILD_BUG_ON(sizeof(struct can_rx_offload_cb) > sizeof(skb->cb));
|
|
+
|
|
+ return (struct can_rx_offload_cb *)skb->cb;
|
|
+}
|
|
+
|
|
+static inline bool
|
|
+can_rx_offload_le(struct can_rx_offload *offload,
|
|
+ unsigned int a, unsigned int b)
|
|
+{
|
|
+ if (offload->inc)
|
|
+ return a <= b;
|
|
+ else
|
|
+ return a >= b;
|
|
+}
|
|
+
|
|
+static inline unsigned int
|
|
+can_rx_offload_inc(struct can_rx_offload *offload, unsigned int *val)
|
|
+{
|
|
+ if (offload->inc)
|
|
+ return (*val)++;
|
|
+ else
|
|
+ return (*val)--;
|
|
+}
|
|
+
|
|
+static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota)
|
|
+{
|
|
+ struct can_rx_offload *offload = container_of(napi,
|
|
+ struct can_rx_offload,
|
|
+ napi);
|
|
+ struct net_device *dev = offload->dev;
|
|
+ struct net_device_stats *stats = &dev->stats;
|
|
+ struct sk_buff *skb;
|
|
+ int work_done = 0;
|
|
+
|
|
+ while ((work_done < quota) &&
|
|
+ (skb = skb_dequeue(&offload->skb_queue))) {
|
|
+ struct can_frame *cf = (struct can_frame *)skb->data;
|
|
+
|
|
+ work_done++;
|
|
+ stats->rx_packets++;
|
|
+ stats->rx_bytes += cf->can_dlc;
|
|
+ netif_receive_skb(skb);
|
|
+ }
|
|
+
|
|
+ if (work_done < quota) {
|
|
+ napi_complete_done(napi, work_done);
|
|
+
|
|
+ /* Check if there was another interrupt */
|
|
+ if (!skb_queue_empty(&offload->skb_queue))
|
|
+ napi_reschedule(&offload->napi);
|
|
+ }
|
|
+
|
|
+ can_led_event(offload->dev, CAN_LED_EVENT_RX);
|
|
+
|
|
+ return work_done;
|
|
+}
|
|
+
|
|
+static inline void
|
|
+__skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new,
|
|
+ int (*compare)(struct sk_buff *a, struct sk_buff *b))
|
|
+{
|
|
+ struct sk_buff *pos, *insert = NULL;
|
|
+
|
|
+ skb_queue_reverse_walk(head, pos) {
|
|
+ const struct can_rx_offload_cb *cb_pos, *cb_new;
|
|
+
|
|
+ cb_pos = can_rx_offload_get_cb(pos);
|
|
+ cb_new = can_rx_offload_get_cb(new);
|
|
+
|
|
+ netdev_dbg(new->dev,
|
|
+ "%s: pos=0x%08x, new=0x%08x, diff=%10d, queue_len=%d\n",
|
|
+ __func__,
|
|
+ cb_pos->timestamp, cb_new->timestamp,
|
|
+ cb_new->timestamp - cb_pos->timestamp,
|
|
+ skb_queue_len(head));
|
|
+
|
|
+ if (compare(pos, new) < 0)
|
|
+ continue;
|
|
+ insert = pos;
|
|
+ break;
|
|
+ }
|
|
+ if (!insert)
|
|
+ __skb_queue_head(head, new);
|
|
+ else
|
|
+ __skb_queue_after(head, insert, new);
|
|
+}
|
|
+
|
|
+static int can_rx_offload_compare(struct sk_buff *a, struct sk_buff *b)
|
|
+{
|
|
+ const struct can_rx_offload_cb *cb_a, *cb_b;
|
|
+
|
|
+ cb_a = can_rx_offload_get_cb(a);
|
|
+ cb_b = can_rx_offload_get_cb(b);
|
|
+
|
|
+ /* Subtract two u32 and return result as int, to keep
|
|
+ * difference steady around the u32 overflow.
|
|
+ */
|
|
+ return cb_b->timestamp - cb_a->timestamp;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * can_rx_offload_offload_one() - Read one CAN frame from HW
|
|
+ * @offload: pointer to rx_offload context
|
|
+ * @n: number of mailbox to read
|
|
+ *
|
|
+ * The task of this function is to read a CAN frame from mailbox @n
|
|
+ * from the device and return the mailbox's content as a struct
|
|
+ * sk_buff.
|
|
+ *
|
|
+ * If the struct can_rx_offload::skb_queue exceeds the maximal queue
|
|
+ * length (struct can_rx_offload::skb_queue_len_max) or no skb can be
|
|
+ * allocated, the mailbox contents is discarded by reading it into an
|
|
+ * overflow buffer. This way the mailbox is marked as free by the
|
|
+ * driver.
|
|
+ *
|
|
+ * Return: A pointer to skb containing the CAN frame on success.
|
|
+ *
|
|
+ * NULL if the mailbox @n is empty.
|
|
+ *
|
|
+ * ERR_PTR() in case of an error
|
|
+ */
|
|
+static struct sk_buff *
|
|
+can_rx_offload_offload_one(struct can_rx_offload *offload, unsigned int n)
|
|
+{
|
|
+ struct sk_buff *skb;
|
|
+ struct can_rx_offload_cb *cb;
|
|
+ bool drop = false;
|
|
+ u32 timestamp;
|
|
+
|
|
+ /* If queue is full drop frame */
|
|
+ if (unlikely(skb_queue_len(&offload->skb_queue) >
|
|
+ offload->skb_queue_len_max))
|
|
+ drop = true;
|
|
+
|
|
+ skb = offload->mailbox_read(offload, n, ×tamp, drop);
|
|
+ /* Mailbox was empty. */
|
|
+ if (unlikely(!skb))
|
|
+ return NULL;
|
|
+
|
|
+ /* There was a problem reading the mailbox, propagate
|
|
+ * error value.
|
|
+ */
|
|
+ if (unlikely(IS_ERR(skb))) {
|
|
+ offload->dev->stats.rx_dropped++;
|
|
+ offload->dev->stats.rx_fifo_errors++;
|
|
+
|
|
+ return skb;
|
|
+ }
|
|
+
|
|
+ /* Mailbox was read. */
|
|
+ cb = can_rx_offload_get_cb(skb);
|
|
+ cb->timestamp = timestamp;
|
|
+
|
|
+ return skb;
|
|
+}
|
|
+
|
|
+int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
|
|
+ u64 pending)
|
|
+{
|
|
+ struct sk_buff_head skb_queue;
|
|
+ unsigned int i;
|
|
+
|
|
+ __skb_queue_head_init(&skb_queue);
|
|
+
|
|
+ for (i = offload->mb_first;
|
|
+ can_rx_offload_le(offload, i, offload->mb_last);
|
|
+ can_rx_offload_inc(offload, &i)) {
|
|
+ struct sk_buff *skb;
|
|
+
|
|
+ if (!(pending & BIT_ULL(i)))
|
|
+ continue;
|
|
+
|
|
+ skb = can_rx_offload_offload_one(offload, i);
|
|
+ if (IS_ERR_OR_NULL(skb))
|
|
+ continue;
|
|
+
|
|
+ __skb_queue_add_sort(&skb_queue, skb, can_rx_offload_compare);
|
|
+ }
|
|
+
|
|
+ if (!skb_queue_empty(&skb_queue)) {
|
|
+ unsigned long flags;
|
|
+ u32 queue_len;
|
|
+
|
|
+ spin_lock_irqsave(&offload->skb_queue.lock, flags);
|
|
+ skb_queue_splice_tail(&skb_queue, &offload->skb_queue);
|
|
+ spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
|
|
+
|
|
+ queue_len = skb_queue_len(&offload->skb_queue);
|
|
+ if (queue_len > offload->skb_queue_len_max / 8)
|
|
+ netdev_dbg(offload->dev, "%s: queue_len=%d\n",
|
|
+ __func__, queue_len);
|
|
+
|
|
+ can_rx_offload_schedule(offload);
|
|
+ }
|
|
+
|
|
+ return skb_queue_len(&skb_queue);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_timestamp);
|
|
+
|
|
+int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload)
|
|
+{
|
|
+ struct sk_buff *skb;
|
|
+ int received = 0;
|
|
+
|
|
+ while (1) {
|
|
+ skb = can_rx_offload_offload_one(offload, 0);
|
|
+ if (IS_ERR(skb))
|
|
+ continue;
|
|
+ if (!skb)
|
|
+ break;
|
|
+
|
|
+ skb_queue_tail(&offload->skb_queue, skb);
|
|
+ received++;
|
|
+ }
|
|
+
|
|
+ if (received)
|
|
+ can_rx_offload_schedule(offload);
|
|
+
|
|
+ return received;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_fifo);
|
|
+
|
|
+int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
|
|
+ struct sk_buff *skb, u32 timestamp)
|
|
+{
|
|
+ struct can_rx_offload_cb *cb;
|
|
+ unsigned long flags;
|
|
+
|
|
+ if (skb_queue_len(&offload->skb_queue) >
|
|
+ offload->skb_queue_len_max) {
|
|
+ dev_kfree_skb_any(skb);
|
|
+ return -ENOBUFS;
|
|
+ }
|
|
+
|
|
+ cb = can_rx_offload_get_cb(skb);
|
|
+ cb->timestamp = timestamp;
|
|
+
|
|
+ spin_lock_irqsave(&offload->skb_queue.lock, flags);
|
|
+ __skb_queue_add_sort(&offload->skb_queue, skb, can_rx_offload_compare);
|
|
+ spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
|
|
+
|
|
+ can_rx_offload_schedule(offload);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_rx_offload_queue_sorted);
|
|
+
|
|
+unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
|
|
+ unsigned int idx, u32 timestamp)
|
|
+{
|
|
+ struct net_device *dev = offload->dev;
|
|
+ struct net_device_stats *stats = &dev->stats;
|
|
+ struct sk_buff *skb;
|
|
+ u8 len;
|
|
+ int err;
|
|
+
|
|
+ skb = __can_get_echo_skb(dev, idx, &len);
|
|
+ if (!skb)
|
|
+ return 0;
|
|
+
|
|
+ err = can_rx_offload_queue_sorted(offload, skb, timestamp);
|
|
+ if (err) {
|
|
+ stats->rx_errors++;
|
|
+ stats->tx_fifo_errors++;
|
|
+ }
|
|
+
|
|
+ return len;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_rx_offload_get_echo_skb);
|
|
+
|
|
+int can_rx_offload_queue_tail(struct can_rx_offload *offload,
|
|
+ struct sk_buff *skb)
|
|
+{
|
|
+ if (skb_queue_len(&offload->skb_queue) >
|
|
+ offload->skb_queue_len_max) {
|
|
+ dev_kfree_skb_any(skb);
|
|
+ return -ENOBUFS;
|
|
+ }
|
|
+
|
|
+ skb_queue_tail(&offload->skb_queue, skb);
|
|
+ can_rx_offload_schedule(offload);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail);
|
|
+
|
|
+static int can_rx_offload_init_queue(struct net_device *dev,
|
|
+ struct can_rx_offload *offload,
|
|
+ unsigned int weight)
|
|
+{
|
|
+ offload->dev = dev;
|
|
+
|
|
+ /* Limit queue len to 4x the weight (rounted to next power of two) */
|
|
+ offload->skb_queue_len_max = 2 << fls(weight);
|
|
+ offload->skb_queue_len_max *= 4;
|
|
+ skb_queue_head_init(&offload->skb_queue);
|
|
+
|
|
+ netif_napi_add(dev, &offload->napi, can_rx_offload_napi_poll, weight);
|
|
+
|
|
+ dev_dbg(dev->dev.parent, "%s: skb_queue_len_max=%d\n",
|
|
+ __func__, offload->skb_queue_len_max);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int can_rx_offload_add_timestamp(struct net_device *dev,
|
|
+ struct can_rx_offload *offload)
|
|
+{
|
|
+ unsigned int weight;
|
|
+
|
|
+ if (offload->mb_first > BITS_PER_LONG_LONG ||
|
|
+ offload->mb_last > BITS_PER_LONG_LONG || !offload->mailbox_read)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (offload->mb_first < offload->mb_last) {
|
|
+ offload->inc = true;
|
|
+ weight = offload->mb_last - offload->mb_first;
|
|
+ } else {
|
|
+ offload->inc = false;
|
|
+ weight = offload->mb_first - offload->mb_last;
|
|
+ }
|
|
+
|
|
+ return can_rx_offload_init_queue(dev, offload, weight);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_rx_offload_add_timestamp);
|
|
+
|
|
+int can_rx_offload_add_fifo(struct net_device *dev,
|
|
+ struct can_rx_offload *offload, unsigned int weight)
|
|
+{
|
|
+ if (!offload->mailbox_read)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return can_rx_offload_init_queue(dev, offload, weight);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_rx_offload_add_fifo);
|
|
+
|
|
+int can_rx_offload_add_manual(struct net_device *dev,
|
|
+ struct can_rx_offload *offload,
|
|
+ unsigned int weight)
|
|
+{
|
|
+ if (offload->mailbox_read)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return can_rx_offload_init_queue(dev, offload, weight);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_rx_offload_add_manual);
|
|
+
|
|
+void can_rx_offload_enable(struct can_rx_offload *offload)
|
|
+{
|
|
+ napi_enable(&offload->napi);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_rx_offload_enable);
|
|
+
|
|
+void can_rx_offload_del(struct can_rx_offload *offload)
|
|
+{
|
|
+ netif_napi_del(&offload->napi);
|
|
+ skb_queue_purge(&offload->skb_queue);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(can_rx_offload_del);
|
|
diff --git a/drivers/net/can/m_can/tcan4x5x.c b/drivers/net/can/m_can/tcan4x5x.c
|
|
index 01f5b6e03a2dd..f169d9090e52f 100644
|
|
--- a/drivers/net/can/m_can/tcan4x5x.c
|
|
+++ b/drivers/net/can/m_can/tcan4x5x.c
|
|
@@ -88,7 +88,7 @@
|
|
|
|
#define TCAN4X5X_MRAM_START 0x8000
|
|
#define TCAN4X5X_MCAN_OFFSET 0x1000
|
|
-#define TCAN4X5X_MAX_REGISTER 0x8fff
|
|
+#define TCAN4X5X_MAX_REGISTER 0x8ffc
|
|
|
|
#define TCAN4X5X_CLEAR_ALL_INT 0xffffffff
|
|
#define TCAN4X5X_SET_ALL_INT 0xffffffff
|
|
diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c
|
|
deleted file mode 100644
|
|
index 6e95193b215ba..0000000000000
|
|
--- a/drivers/net/can/rx-offload.c
|
|
+++ /dev/null
|
|
@@ -1,376 +0,0 @@
|
|
-// SPDX-License-Identifier: GPL-2.0-only
|
|
-/* Copyright (c) 2014 Protonic Holland,
|
|
- * David Jander
|
|
- * Copyright (C) 2014-2017 Pengutronix,
|
|
- * Marc Kleine-Budde <kernel@pengutronix.de>
|
|
- */
|
|
-
|
|
-#include <linux/can/dev.h>
|
|
-#include <linux/can/rx-offload.h>
|
|
-
|
|
-struct can_rx_offload_cb {
|
|
- u32 timestamp;
|
|
-};
|
|
-
|
|
-static inline struct can_rx_offload_cb *
|
|
-can_rx_offload_get_cb(struct sk_buff *skb)
|
|
-{
|
|
- BUILD_BUG_ON(sizeof(struct can_rx_offload_cb) > sizeof(skb->cb));
|
|
-
|
|
- return (struct can_rx_offload_cb *)skb->cb;
|
|
-}
|
|
-
|
|
-static inline bool
|
|
-can_rx_offload_le(struct can_rx_offload *offload,
|
|
- unsigned int a, unsigned int b)
|
|
-{
|
|
- if (offload->inc)
|
|
- return a <= b;
|
|
- else
|
|
- return a >= b;
|
|
-}
|
|
-
|
|
-static inline unsigned int
|
|
-can_rx_offload_inc(struct can_rx_offload *offload, unsigned int *val)
|
|
-{
|
|
- if (offload->inc)
|
|
- return (*val)++;
|
|
- else
|
|
- return (*val)--;
|
|
-}
|
|
-
|
|
-static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota)
|
|
-{
|
|
- struct can_rx_offload *offload = container_of(napi,
|
|
- struct can_rx_offload,
|
|
- napi);
|
|
- struct net_device *dev = offload->dev;
|
|
- struct net_device_stats *stats = &dev->stats;
|
|
- struct sk_buff *skb;
|
|
- int work_done = 0;
|
|
-
|
|
- while ((work_done < quota) &&
|
|
- (skb = skb_dequeue(&offload->skb_queue))) {
|
|
- struct can_frame *cf = (struct can_frame *)skb->data;
|
|
-
|
|
- work_done++;
|
|
- stats->rx_packets++;
|
|
- stats->rx_bytes += cf->can_dlc;
|
|
- netif_receive_skb(skb);
|
|
- }
|
|
-
|
|
- if (work_done < quota) {
|
|
- napi_complete_done(napi, work_done);
|
|
-
|
|
- /* Check if there was another interrupt */
|
|
- if (!skb_queue_empty(&offload->skb_queue))
|
|
- napi_reschedule(&offload->napi);
|
|
- }
|
|
-
|
|
- can_led_event(offload->dev, CAN_LED_EVENT_RX);
|
|
-
|
|
- return work_done;
|
|
-}
|
|
-
|
|
-static inline void
|
|
-__skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new,
|
|
- int (*compare)(struct sk_buff *a, struct sk_buff *b))
|
|
-{
|
|
- struct sk_buff *pos, *insert = NULL;
|
|
-
|
|
- skb_queue_reverse_walk(head, pos) {
|
|
- const struct can_rx_offload_cb *cb_pos, *cb_new;
|
|
-
|
|
- cb_pos = can_rx_offload_get_cb(pos);
|
|
- cb_new = can_rx_offload_get_cb(new);
|
|
-
|
|
- netdev_dbg(new->dev,
|
|
- "%s: pos=0x%08x, new=0x%08x, diff=%10d, queue_len=%d\n",
|
|
- __func__,
|
|
- cb_pos->timestamp, cb_new->timestamp,
|
|
- cb_new->timestamp - cb_pos->timestamp,
|
|
- skb_queue_len(head));
|
|
-
|
|
- if (compare(pos, new) < 0)
|
|
- continue;
|
|
- insert = pos;
|
|
- break;
|
|
- }
|
|
- if (!insert)
|
|
- __skb_queue_head(head, new);
|
|
- else
|
|
- __skb_queue_after(head, insert, new);
|
|
-}
|
|
-
|
|
-static int can_rx_offload_compare(struct sk_buff *a, struct sk_buff *b)
|
|
-{
|
|
- const struct can_rx_offload_cb *cb_a, *cb_b;
|
|
-
|
|
- cb_a = can_rx_offload_get_cb(a);
|
|
- cb_b = can_rx_offload_get_cb(b);
|
|
-
|
|
- /* Subtract two u32 and return result as int, to keep
|
|
- * difference steady around the u32 overflow.
|
|
- */
|
|
- return cb_b->timestamp - cb_a->timestamp;
|
|
-}
|
|
-
|
|
-/**
|
|
- * can_rx_offload_offload_one() - Read one CAN frame from HW
|
|
- * @offload: pointer to rx_offload context
|
|
- * @n: number of mailbox to read
|
|
- *
|
|
- * The task of this function is to read a CAN frame from mailbox @n
|
|
- * from the device and return the mailbox's content as a struct
|
|
- * sk_buff.
|
|
- *
|
|
- * If the struct can_rx_offload::skb_queue exceeds the maximal queue
|
|
- * length (struct can_rx_offload::skb_queue_len_max) or no skb can be
|
|
- * allocated, the mailbox contents is discarded by reading it into an
|
|
- * overflow buffer. This way the mailbox is marked as free by the
|
|
- * driver.
|
|
- *
|
|
- * Return: A pointer to skb containing the CAN frame on success.
|
|
- *
|
|
- * NULL if the mailbox @n is empty.
|
|
- *
|
|
- * ERR_PTR() in case of an error
|
|
- */
|
|
-static struct sk_buff *
|
|
-can_rx_offload_offload_one(struct can_rx_offload *offload, unsigned int n)
|
|
-{
|
|
- struct sk_buff *skb;
|
|
- struct can_rx_offload_cb *cb;
|
|
- bool drop = false;
|
|
- u32 timestamp;
|
|
-
|
|
- /* If queue is full drop frame */
|
|
- if (unlikely(skb_queue_len(&offload->skb_queue) >
|
|
- offload->skb_queue_len_max))
|
|
- drop = true;
|
|
-
|
|
- skb = offload->mailbox_read(offload, n, ×tamp, drop);
|
|
- /* Mailbox was empty. */
|
|
- if (unlikely(!skb))
|
|
- return NULL;
|
|
-
|
|
- /* There was a problem reading the mailbox, propagate
|
|
- * error value.
|
|
- */
|
|
- if (unlikely(IS_ERR(skb))) {
|
|
- offload->dev->stats.rx_dropped++;
|
|
- offload->dev->stats.rx_fifo_errors++;
|
|
-
|
|
- return skb;
|
|
- }
|
|
-
|
|
- /* Mailbox was read. */
|
|
- cb = can_rx_offload_get_cb(skb);
|
|
- cb->timestamp = timestamp;
|
|
-
|
|
- return skb;
|
|
-}
|
|
-
|
|
-int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
|
|
- u64 pending)
|
|
-{
|
|
- struct sk_buff_head skb_queue;
|
|
- unsigned int i;
|
|
-
|
|
- __skb_queue_head_init(&skb_queue);
|
|
-
|
|
- for (i = offload->mb_first;
|
|
- can_rx_offload_le(offload, i, offload->mb_last);
|
|
- can_rx_offload_inc(offload, &i)) {
|
|
- struct sk_buff *skb;
|
|
-
|
|
- if (!(pending & BIT_ULL(i)))
|
|
- continue;
|
|
-
|
|
- skb = can_rx_offload_offload_one(offload, i);
|
|
- if (IS_ERR_OR_NULL(skb))
|
|
- continue;
|
|
-
|
|
- __skb_queue_add_sort(&skb_queue, skb, can_rx_offload_compare);
|
|
- }
|
|
-
|
|
- if (!skb_queue_empty(&skb_queue)) {
|
|
- unsigned long flags;
|
|
- u32 queue_len;
|
|
-
|
|
- spin_lock_irqsave(&offload->skb_queue.lock, flags);
|
|
- skb_queue_splice_tail(&skb_queue, &offload->skb_queue);
|
|
- spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
|
|
-
|
|
- queue_len = skb_queue_len(&offload->skb_queue);
|
|
- if (queue_len > offload->skb_queue_len_max / 8)
|
|
- netdev_dbg(offload->dev, "%s: queue_len=%d\n",
|
|
- __func__, queue_len);
|
|
-
|
|
- can_rx_offload_schedule(offload);
|
|
- }
|
|
-
|
|
- return skb_queue_len(&skb_queue);
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_timestamp);
|
|
-
|
|
-int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload)
|
|
-{
|
|
- struct sk_buff *skb;
|
|
- int received = 0;
|
|
-
|
|
- while (1) {
|
|
- skb = can_rx_offload_offload_one(offload, 0);
|
|
- if (IS_ERR(skb))
|
|
- continue;
|
|
- if (!skb)
|
|
- break;
|
|
-
|
|
- skb_queue_tail(&offload->skb_queue, skb);
|
|
- received++;
|
|
- }
|
|
-
|
|
- if (received)
|
|
- can_rx_offload_schedule(offload);
|
|
-
|
|
- return received;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_fifo);
|
|
-
|
|
-int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
|
|
- struct sk_buff *skb, u32 timestamp)
|
|
-{
|
|
- struct can_rx_offload_cb *cb;
|
|
- unsigned long flags;
|
|
-
|
|
- if (skb_queue_len(&offload->skb_queue) >
|
|
- offload->skb_queue_len_max) {
|
|
- dev_kfree_skb_any(skb);
|
|
- return -ENOBUFS;
|
|
- }
|
|
-
|
|
- cb = can_rx_offload_get_cb(skb);
|
|
- cb->timestamp = timestamp;
|
|
-
|
|
- spin_lock_irqsave(&offload->skb_queue.lock, flags);
|
|
- __skb_queue_add_sort(&offload->skb_queue, skb, can_rx_offload_compare);
|
|
- spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
|
|
-
|
|
- can_rx_offload_schedule(offload);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_rx_offload_queue_sorted);
|
|
-
|
|
-unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
|
|
- unsigned int idx, u32 timestamp)
|
|
-{
|
|
- struct net_device *dev = offload->dev;
|
|
- struct net_device_stats *stats = &dev->stats;
|
|
- struct sk_buff *skb;
|
|
- u8 len;
|
|
- int err;
|
|
-
|
|
- skb = __can_get_echo_skb(dev, idx, &len);
|
|
- if (!skb)
|
|
- return 0;
|
|
-
|
|
- err = can_rx_offload_queue_sorted(offload, skb, timestamp);
|
|
- if (err) {
|
|
- stats->rx_errors++;
|
|
- stats->tx_fifo_errors++;
|
|
- }
|
|
-
|
|
- return len;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_rx_offload_get_echo_skb);
|
|
-
|
|
-int can_rx_offload_queue_tail(struct can_rx_offload *offload,
|
|
- struct sk_buff *skb)
|
|
-{
|
|
- if (skb_queue_len(&offload->skb_queue) >
|
|
- offload->skb_queue_len_max) {
|
|
- dev_kfree_skb_any(skb);
|
|
- return -ENOBUFS;
|
|
- }
|
|
-
|
|
- skb_queue_tail(&offload->skb_queue, skb);
|
|
- can_rx_offload_schedule(offload);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail);
|
|
-
|
|
-static int can_rx_offload_init_queue(struct net_device *dev,
|
|
- struct can_rx_offload *offload,
|
|
- unsigned int weight)
|
|
-{
|
|
- offload->dev = dev;
|
|
-
|
|
- /* Limit queue len to 4x the weight (rounted to next power of two) */
|
|
- offload->skb_queue_len_max = 2 << fls(weight);
|
|
- offload->skb_queue_len_max *= 4;
|
|
- skb_queue_head_init(&offload->skb_queue);
|
|
-
|
|
- netif_napi_add(dev, &offload->napi, can_rx_offload_napi_poll, weight);
|
|
-
|
|
- dev_dbg(dev->dev.parent, "%s: skb_queue_len_max=%d\n",
|
|
- __func__, offload->skb_queue_len_max);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-int can_rx_offload_add_timestamp(struct net_device *dev,
|
|
- struct can_rx_offload *offload)
|
|
-{
|
|
- unsigned int weight;
|
|
-
|
|
- if (offload->mb_first > BITS_PER_LONG_LONG ||
|
|
- offload->mb_last > BITS_PER_LONG_LONG || !offload->mailbox_read)
|
|
- return -EINVAL;
|
|
-
|
|
- if (offload->mb_first < offload->mb_last) {
|
|
- offload->inc = true;
|
|
- weight = offload->mb_last - offload->mb_first;
|
|
- } else {
|
|
- offload->inc = false;
|
|
- weight = offload->mb_first - offload->mb_last;
|
|
- }
|
|
-
|
|
- return can_rx_offload_init_queue(dev, offload, weight);
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_rx_offload_add_timestamp);
|
|
-
|
|
-int can_rx_offload_add_fifo(struct net_device *dev,
|
|
- struct can_rx_offload *offload, unsigned int weight)
|
|
-{
|
|
- if (!offload->mailbox_read)
|
|
- return -EINVAL;
|
|
-
|
|
- return can_rx_offload_init_queue(dev, offload, weight);
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_rx_offload_add_fifo);
|
|
-
|
|
-int can_rx_offload_add_manual(struct net_device *dev,
|
|
- struct can_rx_offload *offload,
|
|
- unsigned int weight)
|
|
-{
|
|
- if (offload->mailbox_read)
|
|
- return -EINVAL;
|
|
-
|
|
- return can_rx_offload_init_queue(dev, offload, weight);
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_rx_offload_add_manual);
|
|
-
|
|
-void can_rx_offload_enable(struct can_rx_offload *offload)
|
|
-{
|
|
- napi_enable(&offload->napi);
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_rx_offload_enable);
|
|
-
|
|
-void can_rx_offload_del(struct can_rx_offload *offload)
|
|
-{
|
|
- netif_napi_del(&offload->napi);
|
|
- skb_queue_purge(&offload->skb_queue);
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(can_rx_offload_del);
|
|
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
|
|
index b4a39f0449ba4..6471a71c2ee6d 100644
|
|
--- a/drivers/net/can/slcan.c
|
|
+++ b/drivers/net/can/slcan.c
|
|
@@ -516,6 +516,7 @@ static struct slcan *slc_alloc(void)
|
|
int i;
|
|
char name[IFNAMSIZ];
|
|
struct net_device *dev = NULL;
|
|
+ struct can_ml_priv *can_ml;
|
|
struct slcan *sl;
|
|
int size;
|
|
|
|
@@ -538,7 +539,8 @@ static struct slcan *slc_alloc(void)
|
|
|
|
dev->base_addr = i;
|
|
sl = netdev_priv(dev);
|
|
- dev->ml_priv = (void *)sl + ALIGN(sizeof(*sl), NETDEV_ALIGN);
|
|
+ can_ml = (void *)sl + ALIGN(sizeof(*sl), NETDEV_ALIGN);
|
|
+ can_set_ml_priv(dev, can_ml);
|
|
|
|
/* Initialize channel control data */
|
|
sl->magic = SLCAN_MAGIC;
|
|
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
|
|
index 39ca14b0585dc..067705e2850b3 100644
|
|
--- a/drivers/net/can/vcan.c
|
|
+++ b/drivers/net/can/vcan.c
|
|
@@ -153,7 +153,7 @@ static void vcan_setup(struct net_device *dev)
|
|
dev->addr_len = 0;
|
|
dev->tx_queue_len = 0;
|
|
dev->flags = IFF_NOARP;
|
|
- dev->ml_priv = netdev_priv(dev);
|
|
+ can_set_ml_priv(dev, netdev_priv(dev));
|
|
|
|
/* set flags according to driver capabilities */
|
|
if (echo)
|
|
diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c
|
|
index b1baa4ac1d537..7000c6cd1e48b 100644
|
|
--- a/drivers/net/can/vxcan.c
|
|
+++ b/drivers/net/can/vxcan.c
|
|
@@ -141,6 +141,8 @@ static const struct net_device_ops vxcan_netdev_ops = {
|
|
|
|
static void vxcan_setup(struct net_device *dev)
|
|
{
|
|
+ struct can_ml_priv *can_ml;
|
|
+
|
|
dev->type = ARPHRD_CAN;
|
|
dev->mtu = CANFD_MTU;
|
|
dev->hard_header_len = 0;
|
|
@@ -149,7 +151,9 @@ static void vxcan_setup(struct net_device *dev)
|
|
dev->flags = (IFF_NOARP|IFF_ECHO);
|
|
dev->netdev_ops = &vxcan_netdev_ops;
|
|
dev->needs_free_netdev = true;
|
|
- dev->ml_priv = netdev_priv(dev) + ALIGN(sizeof(struct vxcan_priv), NETDEV_ALIGN);
|
|
+
|
|
+ can_ml = netdev_priv(dev) + ALIGN(sizeof(struct vxcan_priv), NETDEV_ALIGN);
|
|
+ can_set_ml_priv(dev, can_ml);
|
|
}
|
|
|
|
/* forward declaration for rtnl_create_link() */
|
|
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
|
|
index 8f70a3909929a..4af0cd9530de6 100644
|
|
--- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c
|
|
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
|
|
@@ -71,8 +71,10 @@ static int aq_ndev_open(struct net_device *ndev)
|
|
goto err_exit;
|
|
|
|
err = aq_nic_start(aq_nic);
|
|
- if (err < 0)
|
|
+ if (err < 0) {
|
|
+ aq_nic_stop(aq_nic);
|
|
goto err_exit;
|
|
+ }
|
|
|
|
err_exit:
|
|
if (err < 0)
|
|
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
|
|
index d1f7b51cab620..f5333fc27e14f 100644
|
|
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
|
|
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
|
|
@@ -1153,7 +1153,7 @@ static void mvpp2_interrupts_unmask(void *arg)
|
|
u32 val;
|
|
|
|
/* If the thread isn't used, don't do anything */
|
|
- if (smp_processor_id() > port->priv->nthreads)
|
|
+ if (smp_processor_id() >= port->priv->nthreads)
|
|
return;
|
|
|
|
val = MVPP2_CAUSE_MISC_SUM_MASK |
|
|
@@ -2287,7 +2287,7 @@ static void mvpp2_txq_sent_counter_clear(void *arg)
|
|
int queue;
|
|
|
|
/* If the thread isn't used, don't do anything */
|
|
- if (smp_processor_id() > port->priv->nthreads)
|
|
+ if (smp_processor_id() >= port->priv->nthreads)
|
|
return;
|
|
|
|
for (queue = 0; queue < port->ntxqs; queue++) {
|
|
diff --git a/drivers/net/ipa/gsi_reg.h b/drivers/net/ipa/gsi_reg.h
|
|
index 8e0e9350c3831..42e5a8b8d3240 100644
|
|
--- a/drivers/net/ipa/gsi_reg.h
|
|
+++ b/drivers/net/ipa/gsi_reg.h
|
|
@@ -48,16 +48,6 @@
|
|
#define GSI_INTER_EE_N_SRC_EV_CH_IRQ_OFFSET(ee) \
|
|
(0x0000c01c + 0x1000 * (ee))
|
|
|
|
-#define GSI_INTER_EE_SRC_CH_IRQ_CLR_OFFSET \
|
|
- GSI_INTER_EE_N_SRC_CH_IRQ_CLR_OFFSET(GSI_EE_AP)
|
|
-#define GSI_INTER_EE_N_SRC_CH_IRQ_CLR_OFFSET(ee) \
|
|
- (0x0000c028 + 0x1000 * (ee))
|
|
-
|
|
-#define GSI_INTER_EE_SRC_EV_CH_IRQ_CLR_OFFSET \
|
|
- GSI_INTER_EE_N_SRC_EV_CH_IRQ_CLR_OFFSET(GSI_EE_AP)
|
|
-#define GSI_INTER_EE_N_SRC_EV_CH_IRQ_CLR_OFFSET(ee) \
|
|
- (0x0000c02c + 0x1000 * (ee))
|
|
-
|
|
#define GSI_CH_C_CNTXT_0_OFFSET(ch) \
|
|
GSI_EE_N_CH_C_CNTXT_0_OFFSET((ch), GSI_EE_AP)
|
|
#define GSI_EE_N_CH_C_CNTXT_0_OFFSET(ch, ee) \
|
|
diff --git a/drivers/net/ipa/ipa_cmd.c b/drivers/net/ipa/ipa_cmd.c
|
|
index d92dd3f09b735..46d8b7336d8f2 100644
|
|
--- a/drivers/net/ipa/ipa_cmd.c
|
|
+++ b/drivers/net/ipa/ipa_cmd.c
|
|
@@ -1,7 +1,7 @@
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
|
|
- * Copyright (C) 2019-2020 Linaro Ltd.
|
|
+ * Copyright (C) 2019-2021 Linaro Ltd.
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
@@ -244,11 +244,15 @@ static bool ipa_cmd_register_write_offset_valid(struct ipa *ipa,
|
|
if (ipa->version != IPA_VERSION_3_5_1)
|
|
bit_count += hweight32(REGISTER_WRITE_FLAGS_OFFSET_HIGH_FMASK);
|
|
BUILD_BUG_ON(bit_count > 32);
|
|
- offset_max = ~0 >> (32 - bit_count);
|
|
+ offset_max = ~0U >> (32 - bit_count);
|
|
|
|
+ /* Make sure the offset can be represented by the field(s)
|
|
+ * that holds it. Also make sure the offset is not outside
|
|
+ * the overall IPA memory range.
|
|
+ */
|
|
if (offset > offset_max || ipa->mem_offset > offset_max - offset) {
|
|
dev_err(dev, "%s offset too large 0x%04x + 0x%04x > 0x%04x)\n",
|
|
- ipa->mem_offset + offset, offset_max);
|
|
+ name, ipa->mem_offset, offset, offset_max);
|
|
return false;
|
|
}
|
|
|
|
@@ -261,12 +265,24 @@ static bool ipa_cmd_register_write_valid(struct ipa *ipa)
|
|
const char *name;
|
|
u32 offset;
|
|
|
|
- offset = ipa_reg_filt_rout_hash_flush_offset(ipa->version);
|
|
- name = "filter/route hash flush";
|
|
- if (!ipa_cmd_register_write_offset_valid(ipa, name, offset))
|
|
- return false;
|
|
+ /* If hashed tables are supported, ensure the hash flush register
|
|
+ * offset will fit in a register write IPA immediate command.
|
|
+ */
|
|
+ if (ipa->version != IPA_VERSION_4_2) {
|
|
+ offset = ipa_reg_filt_rout_hash_flush_offset(ipa->version);
|
|
+ name = "filter/route hash flush";
|
|
+ if (!ipa_cmd_register_write_offset_valid(ipa, name, offset))
|
|
+ return false;
|
|
+ }
|
|
|
|
- offset = IPA_REG_ENDP_STATUS_N_OFFSET(IPA_ENDPOINT_COUNT);
|
|
+ /* Each endpoint can have a status endpoint associated with it,
|
|
+ * and this is recorded in an endpoint register. If the modem
|
|
+ * crashes, we reset the status endpoint for all modem endpoints
|
|
+ * using a register write IPA immediate command. Make sure the
|
|
+ * worst case (highest endpoint number) offset of that endpoint
|
|
+ * fits in the register write command field(s) that must hold it.
|
|
+ */
|
|
+ offset = IPA_REG_ENDP_STATUS_N_OFFSET(IPA_ENDPOINT_COUNT - 1);
|
|
name = "maximal endpoint status";
|
|
if (!ipa_cmd_register_write_offset_valid(ipa, name, offset))
|
|
return false;
|
|
diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
|
|
index e7972e88ffe0b..9bbecf4d159b4 100644
|
|
--- a/drivers/net/netdevsim/dev.c
|
|
+++ b/drivers/net/netdevsim/dev.c
|
|
@@ -1008,23 +1008,25 @@ static int nsim_dev_reload_create(struct nsim_dev *nsim_dev,
|
|
nsim_dev->fw_update_status = true;
|
|
nsim_dev->fw_update_overwrite_mask = 0;
|
|
|
|
- nsim_dev->fib_data = nsim_fib_create(devlink, extack);
|
|
- if (IS_ERR(nsim_dev->fib_data))
|
|
- return PTR_ERR(nsim_dev->fib_data);
|
|
-
|
|
nsim_devlink_param_load_driverinit_values(devlink);
|
|
|
|
err = nsim_dev_dummy_region_init(nsim_dev, devlink);
|
|
if (err)
|
|
- goto err_fib_destroy;
|
|
+ return err;
|
|
|
|
err = nsim_dev_traps_init(devlink);
|
|
if (err)
|
|
goto err_dummy_region_exit;
|
|
|
|
+ nsim_dev->fib_data = nsim_fib_create(devlink, extack);
|
|
+ if (IS_ERR(nsim_dev->fib_data)) {
|
|
+ err = PTR_ERR(nsim_dev->fib_data);
|
|
+ goto err_traps_exit;
|
|
+ }
|
|
+
|
|
err = nsim_dev_health_init(nsim_dev, devlink);
|
|
if (err)
|
|
- goto err_traps_exit;
|
|
+ goto err_fib_destroy;
|
|
|
|
err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count);
|
|
if (err)
|
|
@@ -1039,12 +1041,12 @@ static int nsim_dev_reload_create(struct nsim_dev *nsim_dev,
|
|
|
|
err_health_exit:
|
|
nsim_dev_health_exit(nsim_dev);
|
|
+err_fib_destroy:
|
|
+ nsim_fib_destroy(devlink, nsim_dev->fib_data);
|
|
err_traps_exit:
|
|
nsim_dev_traps_exit(devlink);
|
|
err_dummy_region_exit:
|
|
nsim_dev_dummy_region_exit(nsim_dev);
|
|
-err_fib_destroy:
|
|
- nsim_fib_destroy(devlink, nsim_dev->fib_data);
|
|
return err;
|
|
}
|
|
|
|
@@ -1076,15 +1078,9 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev)
|
|
if (err)
|
|
goto err_devlink_free;
|
|
|
|
- nsim_dev->fib_data = nsim_fib_create(devlink, NULL);
|
|
- if (IS_ERR(nsim_dev->fib_data)) {
|
|
- err = PTR_ERR(nsim_dev->fib_data);
|
|
- goto err_resources_unregister;
|
|
- }
|
|
-
|
|
err = devlink_register(devlink, &nsim_bus_dev->dev);
|
|
if (err)
|
|
- goto err_fib_destroy;
|
|
+ goto err_resources_unregister;
|
|
|
|
err = devlink_params_register(devlink, nsim_devlink_params,
|
|
ARRAY_SIZE(nsim_devlink_params));
|
|
@@ -1104,9 +1100,15 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev)
|
|
if (err)
|
|
goto err_traps_exit;
|
|
|
|
+ nsim_dev->fib_data = nsim_fib_create(devlink, NULL);
|
|
+ if (IS_ERR(nsim_dev->fib_data)) {
|
|
+ err = PTR_ERR(nsim_dev->fib_data);
|
|
+ goto err_debugfs_exit;
|
|
+ }
|
|
+
|
|
err = nsim_dev_health_init(nsim_dev, devlink);
|
|
if (err)
|
|
- goto err_debugfs_exit;
|
|
+ goto err_fib_destroy;
|
|
|
|
err = nsim_bpf_dev_init(nsim_dev);
|
|
if (err)
|
|
@@ -1124,6 +1126,8 @@ err_bpf_dev_exit:
|
|
nsim_bpf_dev_exit(nsim_dev);
|
|
err_health_exit:
|
|
nsim_dev_health_exit(nsim_dev);
|
|
+err_fib_destroy:
|
|
+ nsim_fib_destroy(devlink, nsim_dev->fib_data);
|
|
err_debugfs_exit:
|
|
nsim_dev_debugfs_exit(nsim_dev);
|
|
err_traps_exit:
|
|
@@ -1135,8 +1139,6 @@ err_params_unregister:
|
|
ARRAY_SIZE(nsim_devlink_params));
|
|
err_dl_unregister:
|
|
devlink_unregister(devlink);
|
|
-err_fib_destroy:
|
|
- nsim_fib_destroy(devlink, nsim_dev->fib_data);
|
|
err_resources_unregister:
|
|
devlink_resources_unregister(devlink, NULL);
|
|
err_devlink_free:
|
|
@@ -1153,10 +1155,10 @@ static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev)
|
|
debugfs_remove(nsim_dev->take_snapshot);
|
|
nsim_dev_port_del_all(nsim_dev);
|
|
nsim_dev_health_exit(nsim_dev);
|
|
+ nsim_fib_destroy(devlink, nsim_dev->fib_data);
|
|
nsim_dev_traps_exit(devlink);
|
|
nsim_dev_dummy_region_exit(nsim_dev);
|
|
mutex_destroy(&nsim_dev->port_list_lock);
|
|
- nsim_fib_destroy(devlink, nsim_dev->fib_data);
|
|
}
|
|
|
|
void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)
|
|
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
|
|
index 36600b0a0ab06..1ee4c8a906320 100644
|
|
--- a/drivers/net/wan/lmc/lmc_main.c
|
|
+++ b/drivers/net/wan/lmc/lmc_main.c
|
|
@@ -901,6 +901,8 @@ static int lmc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
break;
|
|
default:
|
|
printk(KERN_WARNING "%s: LMC UNKNOWN CARD!\n", dev->name);
|
|
+ unregister_hdlc_device(dev);
|
|
+ return -EIO;
|
|
break;
|
|
}
|
|
|
|
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
|
|
index e6135795719a1..e7072fc4f487a 100644
|
|
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
|
|
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
|
|
@@ -576,13 +576,13 @@ static void ath10k_wmi_event_tdls_peer(struct ath10k *ar, struct sk_buff *skb)
|
|
case WMI_TDLS_TEARDOWN_REASON_TX:
|
|
case WMI_TDLS_TEARDOWN_REASON_RSSI:
|
|
case WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT:
|
|
+ rcu_read_lock();
|
|
station = ieee80211_find_sta_by_ifaddr(ar->hw,
|
|
ev->peer_macaddr.addr,
|
|
NULL);
|
|
if (!station) {
|
|
ath10k_warn(ar, "did not find station from tdls peer event");
|
|
- kfree(tb);
|
|
- return;
|
|
+ goto exit;
|
|
}
|
|
arvif = ath10k_get_arvif(ar, __le32_to_cpu(ev->vdev_id));
|
|
ieee80211_tdls_oper_request(
|
|
@@ -593,6 +593,9 @@ static void ath10k_wmi_event_tdls_peer(struct ath10k *ar, struct sk_buff *skb)
|
|
);
|
|
break;
|
|
}
|
|
+
|
|
+exit:
|
|
+ rcu_read_unlock();
|
|
kfree(tb);
|
|
}
|
|
|
|
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
|
|
index ee0edd9185604..e9e6b0c4de220 100644
|
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
|
@@ -6317,17 +6317,20 @@ static int __ath11k_mac_register(struct ath11k *ar)
|
|
ret = ath11k_regd_update(ar, true);
|
|
if (ret) {
|
|
ath11k_err(ar->ab, "ath11k regd update failed: %d\n", ret);
|
|
- goto err_free_if_combs;
|
|
+ goto err_unregister_hw;
|
|
}
|
|
|
|
ret = ath11k_debugfs_register(ar);
|
|
if (ret) {
|
|
ath11k_err(ar->ab, "debugfs registration failed: %d\n", ret);
|
|
- goto err_free_if_combs;
|
|
+ goto err_unregister_hw;
|
|
}
|
|
|
|
return 0;
|
|
|
|
+err_unregister_hw:
|
|
+ ieee80211_unregister_hw(ar->hw);
|
|
+
|
|
err_free_if_combs:
|
|
kfree(ar->hw->wiphy->iface_combinations[0].limits);
|
|
kfree(ar->hw->wiphy->iface_combinations);
|
|
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
index 0ee421f30aa24..23e6422c2251b 100644
|
|
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
@@ -5611,7 +5611,8 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
|
|
return false;
|
|
}
|
|
|
|
-static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
|
|
+static bool brcmf_is_linkdown(struct brcmf_cfg80211_vif *vif,
|
|
+ const struct brcmf_event_msg *e)
|
|
{
|
|
u32 event = e->event_code;
|
|
u16 flags = e->flags;
|
|
@@ -5620,6 +5621,8 @@ static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
|
|
(event == BRCMF_E_DISASSOC_IND) ||
|
|
((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
|
|
brcmf_dbg(CONN, "Processing link down\n");
|
|
+ clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
|
|
+ clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
|
|
return true;
|
|
}
|
|
return false;
|
|
@@ -6067,7 +6070,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
|
|
} else
|
|
brcmf_bss_connect_done(cfg, ndev, e, true);
|
|
brcmf_net_setcarrier(ifp, true);
|
|
- } else if (brcmf_is_linkdown(e)) {
|
|
+ } else if (brcmf_is_linkdown(ifp->vif, e)) {
|
|
brcmf_dbg(CONN, "Linkdown\n");
|
|
if (!brcmf_is_ibssmode(ifp->vif) &&
|
|
test_bit(BRCMF_VIF_STATUS_CONNECTED,
|
|
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
|
|
index 1a222469b5b4e..bb990be7c870b 100644
|
|
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
|
|
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
|
|
@@ -2026,7 +2026,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans,
|
|
int ret;
|
|
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
|
|
|
- spin_lock_irqsave(&trans_pcie->reg_lock, *flags);
|
|
+ spin_lock_bh(&trans_pcie->reg_lock);
|
|
|
|
if (trans_pcie->cmd_hold_nic_awake)
|
|
goto out;
|
|
@@ -2111,7 +2111,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans,
|
|
}
|
|
|
|
err:
|
|
- spin_unlock_irqrestore(&trans_pcie->reg_lock, *flags);
|
|
+ spin_unlock_bh(&trans_pcie->reg_lock);
|
|
return false;
|
|
}
|
|
|
|
@@ -2149,7 +2149,7 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans,
|
|
* scheduled on different CPUs (after we drop reg_lock).
|
|
*/
|
|
out:
|
|
- spin_unlock_irqrestore(&trans_pcie->reg_lock, *flags);
|
|
+ spin_unlock_bh(&trans_pcie->reg_lock);
|
|
}
|
|
|
|
static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
|
|
@@ -2403,11 +2403,10 @@ static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg,
|
|
u32 mask, u32 value)
|
|
{
|
|
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
|
- unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&trans_pcie->reg_lock, flags);
|
|
+ spin_lock_bh(&trans_pcie->reg_lock);
|
|
__iwl_trans_pcie_set_bits_mask(trans, reg, mask, value);
|
|
- spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
|
|
+ spin_unlock_bh(&trans_pcie->reg_lock);
|
|
}
|
|
|
|
static const char *get_csr_string(int cmd)
|
|
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
|
|
index baa83a0b85934..8c7138247869a 100644
|
|
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
|
|
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
|
|
@@ -78,7 +78,6 @@ static int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans,
|
|
struct iwl_txq *txq = trans->txqs.txq[trans->txqs.cmd.q_id];
|
|
struct iwl_device_cmd *out_cmd;
|
|
struct iwl_cmd_meta *out_meta;
|
|
- unsigned long flags;
|
|
void *dup_buf = NULL;
|
|
dma_addr_t phys_addr;
|
|
int i, cmd_pos, idx;
|
|
@@ -291,11 +290,11 @@ static int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans,
|
|
if (txq->read_ptr == txq->write_ptr && txq->wd_timeout)
|
|
mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);
|
|
|
|
- spin_lock_irqsave(&trans_pcie->reg_lock, flags);
|
|
+ spin_lock(&trans_pcie->reg_lock);
|
|
/* Increment and update queue's write index */
|
|
txq->write_ptr = iwl_txq_inc_wrap(trans, txq->write_ptr);
|
|
iwl_txq_inc_wr_ptr(trans, txq);
|
|
- spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
|
|
+ spin_unlock(&trans_pcie->reg_lock);
|
|
|
|
out:
|
|
spin_unlock_bh(&txq->lock);
|
|
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
|
|
index ed54d04e43964..50133c09a7805 100644
|
|
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
|
|
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
|
|
@@ -321,12 +321,10 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
|
|
txq->read_ptr = iwl_txq_inc_wrap(trans, txq->read_ptr);
|
|
|
|
if (txq->read_ptr == txq->write_ptr) {
|
|
- unsigned long flags;
|
|
-
|
|
- spin_lock_irqsave(&trans_pcie->reg_lock, flags);
|
|
+ spin_lock(&trans_pcie->reg_lock);
|
|
if (txq_id == trans->txqs.cmd.q_id)
|
|
iwl_pcie_clear_cmd_in_flight(trans);
|
|
- spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
|
|
+ spin_unlock(&trans_pcie->reg_lock);
|
|
}
|
|
}
|
|
|
|
@@ -931,7 +929,6 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
|
|
{
|
|
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
|
struct iwl_txq *txq = trans->txqs.txq[txq_id];
|
|
- unsigned long flags;
|
|
int nfreed = 0;
|
|
u16 r;
|
|
|
|
@@ -962,9 +959,10 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
|
|
}
|
|
|
|
if (txq->read_ptr == txq->write_ptr) {
|
|
- spin_lock_irqsave(&trans_pcie->reg_lock, flags);
|
|
+ /* BHs are also disabled due to txq->lock */
|
|
+ spin_lock(&trans_pcie->reg_lock);
|
|
iwl_pcie_clear_cmd_in_flight(trans);
|
|
- spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
|
|
+ spin_unlock(&trans_pcie->reg_lock);
|
|
}
|
|
|
|
iwl_pcie_txq_progress(txq);
|
|
@@ -1173,7 +1171,6 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
|
|
struct iwl_txq *txq = trans->txqs.txq[trans->txqs.cmd.q_id];
|
|
struct iwl_device_cmd *out_cmd;
|
|
struct iwl_cmd_meta *out_meta;
|
|
- unsigned long flags;
|
|
void *dup_buf = NULL;
|
|
dma_addr_t phys_addr;
|
|
int idx;
|
|
@@ -1416,20 +1413,19 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
|
|
if (txq->read_ptr == txq->write_ptr && txq->wd_timeout)
|
|
mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);
|
|
|
|
- spin_lock_irqsave(&trans_pcie->reg_lock, flags);
|
|
+ spin_lock(&trans_pcie->reg_lock);
|
|
ret = iwl_pcie_set_cmd_in_flight(trans, cmd);
|
|
if (ret < 0) {
|
|
idx = ret;
|
|
- spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
|
|
- goto out;
|
|
+ goto unlock_reg;
|
|
}
|
|
|
|
/* Increment and update queue's write index */
|
|
txq->write_ptr = iwl_txq_inc_wrap(trans, txq->write_ptr);
|
|
iwl_pcie_txq_inc_wr_ptr(trans, txq);
|
|
|
|
- spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
|
|
-
|
|
+ unlock_reg:
|
|
+ spin_unlock(&trans_pcie->reg_lock);
|
|
out:
|
|
spin_unlock_bh(&txq->lock);
|
|
free_dup_buf:
|
|
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
|
|
index da2e7415be8fe..f9615f76f1734 100644
|
|
--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c
|
|
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
|
|
@@ -720,8 +720,8 @@ static void rtw8821c_coex_cfg_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type,
|
|
regval = (!polarity_inverse ? 0x1 : 0x2);
|
|
}
|
|
|
|
- rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_R_RFE_SEL_15,
|
|
- regval);
|
|
+ rtw_write32_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_R_RFE_SEL_15,
|
|
+ regval);
|
|
break;
|
|
case COEX_SWITCH_CTRL_BY_PTA:
|
|
rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN);
|
|
@@ -731,8 +731,8 @@ static void rtw8821c_coex_cfg_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type,
|
|
PTA_CTRL_PIN);
|
|
|
|
regval = (!polarity_inverse ? 0x2 : 0x1);
|
|
- rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_R_RFE_SEL_15,
|
|
- regval);
|
|
+ rtw_write32_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_R_RFE_SEL_15,
|
|
+ regval);
|
|
break;
|
|
case COEX_SWITCH_CTRL_BY_ANTDIV:
|
|
rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN);
|
|
@@ -758,11 +758,11 @@ static void rtw8821c_coex_cfg_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type,
|
|
}
|
|
|
|
if (ctrl_type == COEX_SWITCH_CTRL_BY_BT) {
|
|
- rtw_write32_clr(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE1);
|
|
- rtw_write32_clr(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE2);
|
|
+ rtw_write8_clr(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE1);
|
|
+ rtw_write8_clr(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE2);
|
|
} else {
|
|
- rtw_write32_set(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE1);
|
|
- rtw_write32_set(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE2);
|
|
+ rtw_write8_set(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE1);
|
|
+ rtw_write8_set(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE2);
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
|
|
index 8b0485ada315b..d658c6e8263af 100644
|
|
--- a/drivers/nvme/target/tcp.c
|
|
+++ b/drivers/nvme/target/tcp.c
|
|
@@ -1098,11 +1098,11 @@ static int nvmet_tcp_try_recv_data(struct nvmet_tcp_queue *queue)
|
|
cmd->rbytes_done += ret;
|
|
}
|
|
|
|
+ nvmet_tcp_unmap_pdu_iovec(cmd);
|
|
if (queue->data_digest) {
|
|
nvmet_tcp_prep_recv_ddgst(cmd);
|
|
return 0;
|
|
}
|
|
- nvmet_tcp_unmap_pdu_iovec(cmd);
|
|
|
|
if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED) &&
|
|
cmd->rbytes_done == cmd->req.transfer_len) {
|
|
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
|
|
index aa1a1c850d057..53a0badc6b035 100644
|
|
--- a/drivers/pinctrl/pinctrl-rockchip.c
|
|
+++ b/drivers/pinctrl/pinctrl-rockchip.c
|
|
@@ -3727,12 +3727,15 @@ static int __maybe_unused rockchip_pinctrl_suspend(struct device *dev)
|
|
static int __maybe_unused rockchip_pinctrl_resume(struct device *dev)
|
|
{
|
|
struct rockchip_pinctrl *info = dev_get_drvdata(dev);
|
|
- int ret = regmap_write(info->regmap_base, RK3288_GRF_GPIO6C_IOMUX,
|
|
- rk3288_grf_gpio6c_iomux |
|
|
- GPIO6C6_SEL_WRITE_ENABLE);
|
|
+ int ret;
|
|
|
|
- if (ret)
|
|
- return ret;
|
|
+ if (info->ctrl->type == RK3288) {
|
|
+ ret = regmap_write(info->regmap_base, RK3288_GRF_GPIO6C_IOMUX,
|
|
+ rk3288_grf_gpio6c_iomux |
|
|
+ GPIO6C6_SEL_WRITE_ENABLE);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ }
|
|
|
|
return pinctrl_force_default(info->pctl_dev);
|
|
}
|
|
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
|
|
index 1cff7c69d4483..1e94586c7eb21 100644
|
|
--- a/drivers/scsi/qla2xxx/qla_target.h
|
|
+++ b/drivers/scsi/qla2xxx/qla_target.h
|
|
@@ -116,7 +116,6 @@
|
|
(min(1270, ((ql) > 0) ? (QLA_TGT_DATASEGS_PER_CMD_24XX + \
|
|
QLA_TGT_DATASEGS_PER_CONT_24XX*((ql) - 1)) : 0))
|
|
#endif
|
|
-#endif
|
|
|
|
#define GET_TARGET_ID(ha, iocb) ((HAS_EXTENDED_IDS(ha)) \
|
|
? le16_to_cpu((iocb)->u.isp2x.target.extended) \
|
|
@@ -244,6 +243,7 @@ struct ctio_to_2xxx {
|
|
#ifndef CTIO_RET_TYPE
|
|
#define CTIO_RET_TYPE 0x17 /* CTIO return entry */
|
|
#define ATIO_TYPE7 0x06 /* Accept target I/O entry for 24xx */
|
|
+#endif
|
|
|
|
struct fcp_hdr {
|
|
uint8_t r_ctl;
|
|
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
|
|
index e2e5356a997de..19bc8c923fce5 100644
|
|
--- a/drivers/scsi/st.c
|
|
+++ b/drivers/scsi/st.c
|
|
@@ -1269,8 +1269,8 @@ static int st_open(struct inode *inode, struct file *filp)
|
|
spin_lock(&st_use_lock);
|
|
if (STp->in_use) {
|
|
spin_unlock(&st_use_lock);
|
|
- scsi_tape_put(STp);
|
|
DEBC_printk(STp, "Device already in use.\n");
|
|
+ scsi_tape_put(STp);
|
|
return (-EBUSY);
|
|
}
|
|
|
|
diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c
|
|
index 751a49f6534f4..be76fddbf524b 100644
|
|
--- a/drivers/soc/qcom/qcom-geni-se.c
|
|
+++ b/drivers/soc/qcom/qcom-geni-se.c
|
|
@@ -3,7 +3,6 @@
|
|
|
|
#include <linux/acpi.h>
|
|
#include <linux/clk.h>
|
|
-#include <linux/console.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/io.h>
|
|
@@ -91,14 +90,11 @@ struct geni_wrapper {
|
|
struct device *dev;
|
|
void __iomem *base;
|
|
struct clk_bulk_data ahb_clks[NUM_AHB_CLKS];
|
|
- struct geni_icc_path to_core;
|
|
};
|
|
|
|
static const char * const icc_path_names[] = {"qup-core", "qup-config",
|
|
"qup-memory"};
|
|
|
|
-static struct geni_wrapper *earlycon_wrapper;
|
|
-
|
|
#define QUP_HW_VER_REG 0x4
|
|
|
|
/* Common SE registers */
|
|
@@ -828,44 +824,11 @@ int geni_icc_disable(struct geni_se *se)
|
|
}
|
|
EXPORT_SYMBOL(geni_icc_disable);
|
|
|
|
-void geni_remove_earlycon_icc_vote(void)
|
|
-{
|
|
- struct platform_device *pdev;
|
|
- struct geni_wrapper *wrapper;
|
|
- struct device_node *parent;
|
|
- struct device_node *child;
|
|
-
|
|
- if (!earlycon_wrapper)
|
|
- return;
|
|
-
|
|
- wrapper = earlycon_wrapper;
|
|
- parent = of_get_next_parent(wrapper->dev->of_node);
|
|
- for_each_child_of_node(parent, child) {
|
|
- if (!of_device_is_compatible(child, "qcom,geni-se-qup"))
|
|
- continue;
|
|
-
|
|
- pdev = of_find_device_by_node(child);
|
|
- if (!pdev)
|
|
- continue;
|
|
-
|
|
- wrapper = platform_get_drvdata(pdev);
|
|
- icc_put(wrapper->to_core.path);
|
|
- wrapper->to_core.path = NULL;
|
|
-
|
|
- }
|
|
- of_node_put(parent);
|
|
-
|
|
- earlycon_wrapper = NULL;
|
|
-}
|
|
-EXPORT_SYMBOL(geni_remove_earlycon_icc_vote);
|
|
-
|
|
static int geni_se_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct resource *res;
|
|
struct geni_wrapper *wrapper;
|
|
- struct console __maybe_unused *bcon;
|
|
- bool __maybe_unused has_earlycon = false;
|
|
int ret;
|
|
|
|
wrapper = devm_kzalloc(dev, sizeof(*wrapper), GFP_KERNEL);
|
|
@@ -888,43 +851,6 @@ static int geni_se_probe(struct platform_device *pdev)
|
|
}
|
|
}
|
|
|
|
-#ifdef CONFIG_SERIAL_EARLYCON
|
|
- for_each_console(bcon) {
|
|
- if (!strcmp(bcon->name, "qcom_geni")) {
|
|
- has_earlycon = true;
|
|
- break;
|
|
- }
|
|
- }
|
|
- if (!has_earlycon)
|
|
- goto exit;
|
|
-
|
|
- wrapper->to_core.path = devm_of_icc_get(dev, "qup-core");
|
|
- if (IS_ERR(wrapper->to_core.path))
|
|
- return PTR_ERR(wrapper->to_core.path);
|
|
- /*
|
|
- * Put minmal BW request on core clocks on behalf of early console.
|
|
- * The vote will be removed earlycon exit function.
|
|
- *
|
|
- * Note: We are putting vote on each QUP wrapper instead only to which
|
|
- * earlycon is connected because QUP core clock of different wrapper
|
|
- * share same voltage domain. If core1 is put to 0, then core2 will
|
|
- * also run at 0, if not voted. Default ICC vote will be removed ASA
|
|
- * we touch any of the core clock.
|
|
- * core1 = core2 = max(core1, core2)
|
|
- */
|
|
- ret = icc_set_bw(wrapper->to_core.path, GENI_DEFAULT_BW,
|
|
- GENI_DEFAULT_BW);
|
|
- if (ret) {
|
|
- dev_err(&pdev->dev, "%s: ICC BW voting failed for core: %d\n",
|
|
- __func__, ret);
|
|
- return ret;
|
|
- }
|
|
-
|
|
- if (of_get_compatible_child(pdev->dev.of_node, "qcom,geni-debug-uart"))
|
|
- earlycon_wrapper = wrapper;
|
|
- of_node_put(pdev->dev.of_node);
|
|
-exit:
|
|
-#endif
|
|
dev_set_drvdata(dev, wrapper);
|
|
dev_dbg(dev, "GENI SE Driver probed\n");
|
|
return devm_of_platform_populate(dev);
|
|
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
|
|
index d740c47827751..2f20bd56ec6ca 100644
|
|
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
|
|
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
|
|
@@ -1281,7 +1281,7 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
|
|
devpriv->amcc + AMCC_OP_REG_INTCSR);
|
|
|
|
ret = request_irq(pcidev->irq, cb_pcidas_interrupt, IRQF_SHARED,
|
|
- dev->board_name, dev);
|
|
+ "cb_pcidas", dev);
|
|
if (ret) {
|
|
dev_dbg(dev->class_dev, "unable to allocate irq %d\n",
|
|
pcidev->irq);
|
|
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
|
|
index fa987bb0e7cd4..6d3ba399a7f0b 100644
|
|
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
|
|
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
|
|
@@ -4035,7 +4035,7 @@ static int auto_attach(struct comedi_device *dev,
|
|
init_stc_registers(dev);
|
|
|
|
retval = request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED,
|
|
- dev->board_name, dev);
|
|
+ "cb_pcidas64", dev);
|
|
if (retval) {
|
|
dev_dbg(dev->class_dev, "unable to allocate irq %u\n",
|
|
pcidev->irq);
|
|
diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h
|
|
index b84f00b8d18bc..4cabaf21c1ca0 100644
|
|
--- a/drivers/staging/rtl8192e/rtllib.h
|
|
+++ b/drivers/staging/rtl8192e/rtllib.h
|
|
@@ -1105,7 +1105,7 @@ struct rtllib_network {
|
|
bool bWithAironetIE;
|
|
bool bCkipSupported;
|
|
bool bCcxRmEnable;
|
|
- u16 CcxRmState[2];
|
|
+ u8 CcxRmState[2];
|
|
bool bMBssidValid;
|
|
u8 MBssidMask;
|
|
u8 MBssid[ETH_ALEN];
|
|
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
|
|
index d31b5e1c8df47..63752233e551f 100644
|
|
--- a/drivers/staging/rtl8192e/rtllib_rx.c
|
|
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
|
|
@@ -1968,7 +1968,7 @@ static void rtllib_parse_mife_generic(struct rtllib_device *ieee,
|
|
info_element->data[2] == 0x96 &&
|
|
info_element->data[3] == 0x01) {
|
|
if (info_element->len == 6) {
|
|
- memcpy(network->CcxRmState, &info_element[4], 2);
|
|
+ memcpy(network->CcxRmState, &info_element->data[4], 2);
|
|
if (network->CcxRmState[0] != 0)
|
|
network->bCcxRmEnable = true;
|
|
else
|
|
diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
|
|
index a6f371fc9af27..f52708f310e03 100644
|
|
--- a/drivers/thermal/thermal_sysfs.c
|
|
+++ b/drivers/thermal/thermal_sysfs.c
|
|
@@ -754,6 +754,9 @@ void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
|
|
{
|
|
struct cooling_dev_stats *stats = cdev->stats;
|
|
|
|
+ if (!stats)
|
|
+ return;
|
|
+
|
|
spin_lock(&stats->lock);
|
|
|
|
if (stats->state == new_state)
|
|
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
|
|
index 291649f028213..0d85b55ea8233 100644
|
|
--- a/drivers/tty/serial/qcom_geni_serial.c
|
|
+++ b/drivers/tty/serial/qcom_geni_serial.c
|
|
@@ -1177,12 +1177,6 @@ static inline void qcom_geni_serial_enable_early_read(struct geni_se *se,
|
|
struct console *con) { }
|
|
#endif
|
|
|
|
-static int qcom_geni_serial_earlycon_exit(struct console *con)
|
|
-{
|
|
- geni_remove_earlycon_icc_vote();
|
|
- return 0;
|
|
-}
|
|
-
|
|
static struct qcom_geni_private_data earlycon_private_data;
|
|
|
|
static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev,
|
|
@@ -1233,7 +1227,6 @@ static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev,
|
|
writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN);
|
|
|
|
dev->con->write = qcom_geni_serial_earlycon_write;
|
|
- dev->con->exit = qcom_geni_serial_earlycon_exit;
|
|
dev->con->setup = NULL;
|
|
qcom_geni_serial_enable_early_read(&se, dev->con);
|
|
|
|
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
|
|
index 2f4e5174e78c8..e79359326411a 100644
|
|
--- a/drivers/usb/class/cdc-acm.c
|
|
+++ b/drivers/usb/class/cdc-acm.c
|
|
@@ -147,17 +147,29 @@ static inline int acm_set_control(struct acm *acm, int control)
|
|
#define acm_send_break(acm, ms) \
|
|
acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
|
|
|
|
-static void acm_kill_urbs(struct acm *acm)
|
|
+static void acm_poison_urbs(struct acm *acm)
|
|
{
|
|
int i;
|
|
|
|
- usb_kill_urb(acm->ctrlurb);
|
|
+ usb_poison_urb(acm->ctrlurb);
|
|
for (i = 0; i < ACM_NW; i++)
|
|
- usb_kill_urb(acm->wb[i].urb);
|
|
+ usb_poison_urb(acm->wb[i].urb);
|
|
for (i = 0; i < acm->rx_buflimit; i++)
|
|
- usb_kill_urb(acm->read_urbs[i]);
|
|
+ usb_poison_urb(acm->read_urbs[i]);
|
|
}
|
|
|
|
+static void acm_unpoison_urbs(struct acm *acm)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < acm->rx_buflimit; i++)
|
|
+ usb_unpoison_urb(acm->read_urbs[i]);
|
|
+ for (i = 0; i < ACM_NW; i++)
|
|
+ usb_unpoison_urb(acm->wb[i].urb);
|
|
+ usb_unpoison_urb(acm->ctrlurb);
|
|
+}
|
|
+
|
|
+
|
|
/*
|
|
* Write buffer management.
|
|
* All of these assume proper locks taken by the caller.
|
|
@@ -226,9 +238,10 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
|
|
|
|
rc = usb_submit_urb(wb->urb, GFP_ATOMIC);
|
|
if (rc < 0) {
|
|
- dev_err(&acm->data->dev,
|
|
- "%s - usb_submit_urb(write bulk) failed: %d\n",
|
|
- __func__, rc);
|
|
+ if (rc != -EPERM)
|
|
+ dev_err(&acm->data->dev,
|
|
+ "%s - usb_submit_urb(write bulk) failed: %d\n",
|
|
+ __func__, rc);
|
|
acm_write_done(acm, wb);
|
|
}
|
|
return rc;
|
|
@@ -313,8 +326,10 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
|
|
acm->iocount.dsr++;
|
|
if (difference & ACM_CTRL_DCD)
|
|
acm->iocount.dcd++;
|
|
- if (newctrl & ACM_CTRL_BRK)
|
|
+ if (newctrl & ACM_CTRL_BRK) {
|
|
acm->iocount.brk++;
|
|
+ tty_insert_flip_char(&acm->port, 0, TTY_BREAK);
|
|
+ }
|
|
if (newctrl & ACM_CTRL_RI)
|
|
acm->iocount.rng++;
|
|
if (newctrl & ACM_CTRL_FRAMING)
|
|
@@ -480,11 +495,6 @@ static void acm_read_bulk_callback(struct urb *urb)
|
|
dev_vdbg(&acm->data->dev, "got urb %d, len %d, status %d\n",
|
|
rb->index, urb->actual_length, status);
|
|
|
|
- if (!acm->dev) {
|
|
- dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__);
|
|
- return;
|
|
- }
|
|
-
|
|
switch (status) {
|
|
case 0:
|
|
usb_mark_last_busy(acm->dev);
|
|
@@ -649,7 +659,8 @@ static void acm_port_dtr_rts(struct tty_port *port, int raise)
|
|
|
|
res = acm_set_control(acm, val);
|
|
if (res && (acm->ctrl_caps & USB_CDC_CAP_LINE))
|
|
- dev_err(&acm->control->dev, "failed to set dtr/rts\n");
|
|
+ /* This is broken in too many devices to spam the logs */
|
|
+ dev_dbg(&acm->control->dev, "failed to set dtr/rts\n");
|
|
}
|
|
|
|
static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)
|
|
@@ -731,6 +742,7 @@ static void acm_port_shutdown(struct tty_port *port)
|
|
* Need to grab write_lock to prevent race with resume, but no need to
|
|
* hold it due to the tty-port initialised flag.
|
|
*/
|
|
+ acm_poison_urbs(acm);
|
|
spin_lock_irq(&acm->write_lock);
|
|
spin_unlock_irq(&acm->write_lock);
|
|
|
|
@@ -747,7 +759,8 @@ static void acm_port_shutdown(struct tty_port *port)
|
|
usb_autopm_put_interface_async(acm->control);
|
|
}
|
|
|
|
- acm_kill_urbs(acm);
|
|
+ acm_unpoison_urbs(acm);
|
|
+
|
|
}
|
|
|
|
static void acm_tty_cleanup(struct tty_struct *tty)
|
|
@@ -1503,12 +1516,16 @@ skip_countries:
|
|
|
|
return 0;
|
|
alloc_fail6:
|
|
+ if (!acm->combined_interfaces) {
|
|
+ /* Clear driver data so that disconnect() returns early. */
|
|
+ usb_set_intfdata(data_interface, NULL);
|
|
+ usb_driver_release_interface(&acm_driver, data_interface);
|
|
+ }
|
|
if (acm->country_codes) {
|
|
device_remove_file(&acm->control->dev,
|
|
&dev_attr_wCountryCodes);
|
|
device_remove_file(&acm->control->dev,
|
|
&dev_attr_iCountryCodeRelDate);
|
|
- kfree(acm->country_codes);
|
|
}
|
|
device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
|
|
alloc_fail5:
|
|
@@ -1540,8 +1557,14 @@ static void acm_disconnect(struct usb_interface *intf)
|
|
if (!acm)
|
|
return;
|
|
|
|
- mutex_lock(&acm->mutex);
|
|
acm->disconnected = true;
|
|
+ /*
|
|
+ * there is a circular dependency. acm_softint() can resubmit
|
|
+ * the URBs in error handling so we need to block any
|
|
+ * submission right away
|
|
+ */
|
|
+ acm_poison_urbs(acm);
|
|
+ mutex_lock(&acm->mutex);
|
|
if (acm->country_codes) {
|
|
device_remove_file(&acm->control->dev,
|
|
&dev_attr_wCountryCodes);
|
|
@@ -1560,7 +1583,6 @@ static void acm_disconnect(struct usb_interface *intf)
|
|
tty_kref_put(tty);
|
|
}
|
|
|
|
- acm_kill_urbs(acm);
|
|
cancel_delayed_work_sync(&acm->dwork);
|
|
|
|
tty_unregister_device(acm_tty_driver, acm->minor);
|
|
@@ -1602,7 +1624,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
|
|
if (cnt)
|
|
return 0;
|
|
|
|
- acm_kill_urbs(acm);
|
|
+ acm_poison_urbs(acm);
|
|
cancel_delayed_work_sync(&acm->dwork);
|
|
acm->urbs_in_error_delay = 0;
|
|
|
|
@@ -1615,6 +1637,7 @@ static int acm_resume(struct usb_interface *intf)
|
|
struct urb *urb;
|
|
int rv = 0;
|
|
|
|
+ acm_unpoison_urbs(acm);
|
|
spin_lock_irq(&acm->write_lock);
|
|
|
|
if (--acm->susp_count)
|
|
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
|
|
index 6ade3daf78584..76ac5d6555ae4 100644
|
|
--- a/drivers/usb/core/quirks.c
|
|
+++ b/drivers/usb/core/quirks.c
|
|
@@ -498,6 +498,10 @@ static const struct usb_device_id usb_quirk_list[] = {
|
|
/* DJI CineSSD */
|
|
{ USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },
|
|
|
|
+ /* Fibocom L850-GL LTE Modem */
|
|
+ { USB_DEVICE(0x2cb7, 0x0007), .driver_info =
|
|
+ USB_QUIRK_IGNORE_REMOTE_WAKEUP },
|
|
+
|
|
/* INTEL VALUE SSD */
|
|
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
|
|
|
|
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
|
|
index fc3269f5faf19..1a9789ec5847f 100644
|
|
--- a/drivers/usb/dwc2/hcd.c
|
|
+++ b/drivers/usb/dwc2/hcd.c
|
|
@@ -4322,7 +4322,8 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
|
|
if (hsotg->op_state == OTG_STATE_B_PERIPHERAL)
|
|
goto unlock;
|
|
|
|
- if (hsotg->params.power_down > DWC2_POWER_DOWN_PARAM_PARTIAL)
|
|
+ if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL ||
|
|
+ hsotg->flags.b.port_connect_status == 0)
|
|
goto skip_power_saving;
|
|
|
|
/*
|
|
@@ -5398,7 +5399,7 @@ int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
|
|
dwc2_writel(hsotg, hprt0, HPRT0);
|
|
|
|
/* Wait for the HPRT0.PrtSusp register field to be set */
|
|
- if (dwc2_hsotg_wait_bit_set(hsotg, HPRT0, HPRT0_SUSP, 3000))
|
|
+ if (dwc2_hsotg_wait_bit_set(hsotg, HPRT0, HPRT0_SUSP, 5000))
|
|
dev_warn(hsotg->dev, "Suspend wasn't generated\n");
|
|
|
|
/*
|
|
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
|
|
index bae6a70664c80..598daed8086f6 100644
|
|
--- a/drivers/usb/dwc3/dwc3-pci.c
|
|
+++ b/drivers/usb/dwc3/dwc3-pci.c
|
|
@@ -118,6 +118,8 @@ static const struct property_entry dwc3_pci_intel_properties[] = {
|
|
static const struct property_entry dwc3_pci_mrfld_properties[] = {
|
|
PROPERTY_ENTRY_STRING("dr_mode", "otg"),
|
|
PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"),
|
|
+ PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
|
|
+ PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
|
|
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
|
|
{}
|
|
};
|
|
diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
|
|
index c00c4fa139b88..8bd077fb1190f 100644
|
|
--- a/drivers/usb/dwc3/dwc3-qcom.c
|
|
+++ b/drivers/usb/dwc3/dwc3-qcom.c
|
|
@@ -244,6 +244,9 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
|
|
struct device *dev = qcom->dev;
|
|
int ret;
|
|
|
|
+ if (has_acpi_companion(dev))
|
|
+ return 0;
|
|
+
|
|
qcom->icc_path_ddr = of_icc_get(dev, "usb-ddr");
|
|
if (IS_ERR(qcom->icc_path_ddr)) {
|
|
dev_err(dev, "failed to get usb-ddr path: %ld\n",
|
|
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
|
|
index 2a86ad4b12b34..65ff41e3a18eb 100644
|
|
--- a/drivers/usb/dwc3/gadget.c
|
|
+++ b/drivers/usb/dwc3/gadget.c
|
|
@@ -791,10 +791,6 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
|
|
reg &= ~DWC3_DALEPENA_EP(dep->number);
|
|
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
|
|
|
|
- dep->stream_capable = false;
|
|
- dep->type = 0;
|
|
- dep->flags = 0;
|
|
-
|
|
/* Clear out the ep descriptors for non-ep0 */
|
|
if (dep->number > 1) {
|
|
dep->endpoint.comp_desc = NULL;
|
|
@@ -803,6 +799,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
|
|
|
|
dwc3_remove_requests(dwc, dep);
|
|
|
|
+ dep->stream_capable = false;
|
|
+ dep->type = 0;
|
|
+ dep->flags = 0;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/usb/gadget/udc/amd5536udc_pci.c b/drivers/usb/gadget/udc/amd5536udc_pci.c
|
|
index 8d387e0e4d91f..c80f9bd51b750 100644
|
|
--- a/drivers/usb/gadget/udc/amd5536udc_pci.c
|
|
+++ b/drivers/usb/gadget/udc/amd5536udc_pci.c
|
|
@@ -153,6 +153,11 @@ static int udc_pci_probe(
|
|
pci_set_master(pdev);
|
|
pci_try_set_mwi(pdev);
|
|
|
|
+ dev->phys_addr = resource;
|
|
+ dev->irq = pdev->irq;
|
|
+ dev->pdev = pdev;
|
|
+ dev->dev = &pdev->dev;
|
|
+
|
|
/* init dma pools */
|
|
if (use_dma) {
|
|
retval = init_dma_pools(dev);
|
|
@@ -160,11 +165,6 @@ static int udc_pci_probe(
|
|
goto err_dma;
|
|
}
|
|
|
|
- dev->phys_addr = resource;
|
|
- dev->irq = pdev->irq;
|
|
- dev->pdev = pdev;
|
|
- dev->dev = &pdev->dev;
|
|
-
|
|
/* general probing */
|
|
if (udc_probe(dev)) {
|
|
retval = -ENODEV;
|
|
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
|
|
index fe010cc61f19b..2f27dc0d9c6bd 100644
|
|
--- a/drivers/usb/host/xhci-mtk.c
|
|
+++ b/drivers/usb/host/xhci-mtk.c
|
|
@@ -397,6 +397,13 @@ static void xhci_mtk_quirks(struct device *dev, struct xhci_hcd *xhci)
|
|
xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
|
|
if (mtk->lpm_support)
|
|
xhci->quirks |= XHCI_LPM_SUPPORT;
|
|
+
|
|
+ /*
|
|
+ * MTK xHCI 0.96: PSA is 1 by default even if doesn't support stream,
|
|
+ * and it's 3 when support it.
|
|
+ */
|
|
+ if (xhci->hci_version < 0x100 && HCC_MAX_PSA(xhci->hcc_params) == 4)
|
|
+ xhci->quirks |= XHCI_BROKEN_STREAMS;
|
|
}
|
|
|
|
/* called during probe() after chip reset completes */
|
|
@@ -548,7 +555,8 @@ static int xhci_mtk_probe(struct platform_device *pdev)
|
|
if (ret)
|
|
goto put_usb3_hcd;
|
|
|
|
- if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
|
|
+ if (HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
|
|
+ !(xhci->quirks & XHCI_BROKEN_STREAMS))
|
|
xhci->shared_hcd->can_do_streams = 1;
|
|
|
|
ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
|
|
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
|
|
index 3209b5ddd30c9..a20a8380ca0c9 100644
|
|
--- a/drivers/usb/usbip/vhci_hcd.c
|
|
+++ b/drivers/usb/usbip/vhci_hcd.c
|
|
@@ -594,6 +594,8 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|
pr_err("invalid port number %d\n", wIndex);
|
|
goto error;
|
|
}
|
|
+ if (wValue >= 32)
|
|
+ goto error;
|
|
if (hcd->speed == HCD_USB3) {
|
|
if ((vhci_hcd->port_status[rhport] &
|
|
USB_SS_PORT_STAT_POWER) != 0) {
|
|
diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig
|
|
index 40a223381ab61..0f28bf99efebc 100644
|
|
--- a/drivers/vfio/pci/Kconfig
|
|
+++ b/drivers/vfio/pci/Kconfig
|
|
@@ -42,7 +42,7 @@ config VFIO_PCI_IGD
|
|
|
|
config VFIO_PCI_NVLINK2
|
|
def_bool y
|
|
- depends on VFIO_PCI && PPC_POWERNV
|
|
+ depends on VFIO_PCI && PPC_POWERNV && SPAPR_TCE_IOMMU
|
|
help
|
|
VFIO PCI support for P9 Witherspoon machine with NVIDIA V100 GPUs
|
|
|
|
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
|
|
index a262e12c6dc26..5ccb0705beae1 100644
|
|
--- a/drivers/vhost/vhost.c
|
|
+++ b/drivers/vhost/vhost.c
|
|
@@ -332,8 +332,8 @@ static void vhost_vq_reset(struct vhost_dev *dev,
|
|
vq->error_ctx = NULL;
|
|
vq->kick = NULL;
|
|
vq->log_ctx = NULL;
|
|
- vhost_reset_is_le(vq);
|
|
vhost_disable_cross_endian(vq);
|
|
+ vhost_reset_is_le(vq);
|
|
vq->busyloop_timeout = 0;
|
|
vq->umem = NULL;
|
|
vq->iotlb = NULL;
|
|
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
|
|
index 8d1ae973041ae..26581194fdf81 100644
|
|
--- a/drivers/video/fbdev/core/fbcon.c
|
|
+++ b/drivers/video/fbdev/core/fbcon.c
|
|
@@ -1344,6 +1344,9 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
|
|
|
|
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
|
|
|
|
+ if (!ops->cursor)
|
|
+ return;
|
|
+
|
|
if (mode & CM_SOFTBACK) {
|
|
mode &= ~CM_SOFTBACK;
|
|
y = softback_lines;
|
|
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
|
|
index c8b0ae676809b..4dc9077dd2ac0 100644
|
|
--- a/drivers/video/fbdev/hyperv_fb.c
|
|
+++ b/drivers/video/fbdev/hyperv_fb.c
|
|
@@ -1031,7 +1031,6 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
|
|
PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
|
|
if (!pdev) {
|
|
pr_err("Unable to find PCI Hyper-V video\n");
|
|
- kfree(info->apertures);
|
|
return -ENODEV;
|
|
}
|
|
|
|
@@ -1129,7 +1128,6 @@ getmem_done:
|
|
} else {
|
|
pci_dev_put(pdev);
|
|
}
|
|
- kfree(info->apertures);
|
|
|
|
return 0;
|
|
|
|
@@ -1141,7 +1139,6 @@ err2:
|
|
err1:
|
|
if (!gen2vm)
|
|
pci_dev_put(pdev);
|
|
- kfree(info->apertures);
|
|
|
|
return -ENOMEM;
|
|
}
|
|
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
|
|
index 1d640b1456375..1afd60fcd7723 100644
|
|
--- a/fs/ext4/balloc.c
|
|
+++ b/fs/ext4/balloc.c
|
|
@@ -626,27 +626,41 @@ int ext4_claim_free_clusters(struct ext4_sb_info *sbi,
|
|
|
|
/**
|
|
* ext4_should_retry_alloc() - check if a block allocation should be retried
|
|
- * @sb: super block
|
|
- * @retries: number of attemps has been made
|
|
+ * @sb: superblock
|
|
+ * @retries: number of retry attempts made so far
|
|
*
|
|
- * ext4_should_retry_alloc() is called when ENOSPC is returned, and if
|
|
- * it is profitable to retry the operation, this function will wait
|
|
- * for the current or committing transaction to complete, and then
|
|
- * return TRUE. We will only retry once.
|
|
+ * ext4_should_retry_alloc() is called when ENOSPC is returned while
|
|
+ * attempting to allocate blocks. If there's an indication that a pending
|
|
+ * journal transaction might free some space and allow another attempt to
|
|
+ * succeed, this function will wait for the current or committing transaction
|
|
+ * to complete and then return TRUE.
|
|
*/
|
|
int ext4_should_retry_alloc(struct super_block *sb, int *retries)
|
|
{
|
|
- if (!ext4_has_free_clusters(EXT4_SB(sb), 1, 0) ||
|
|
- (*retries)++ > 1 ||
|
|
- !EXT4_SB(sb)->s_journal)
|
|
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
|
|
+
|
|
+ if (!sbi->s_journal)
|
|
return 0;
|
|
|
|
- smp_mb();
|
|
- if (EXT4_SB(sb)->s_mb_free_pending == 0)
|
|
+ if (++(*retries) > 3) {
|
|
+ percpu_counter_inc(&sbi->s_sra_exceeded_retry_limit);
|
|
return 0;
|
|
+ }
|
|
|
|
+ /*
|
|
+ * if there's no indication that blocks are about to be freed it's
|
|
+ * possible we just missed a transaction commit that did so
|
|
+ */
|
|
+ smp_mb();
|
|
+ if (sbi->s_mb_free_pending == 0)
|
|
+ return ext4_has_free_clusters(sbi, 1, 0);
|
|
+
|
|
+ /*
|
|
+ * it's possible we've just missed a transaction commit here,
|
|
+ * so ignore the returned status
|
|
+ */
|
|
jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id);
|
|
- jbd2_journal_force_commit_nested(EXT4_SB(sb)->s_journal);
|
|
+ (void) jbd2_journal_force_commit_nested(sbi->s_journal);
|
|
return 1;
|
|
}
|
|
|
|
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
|
|
index b92acb6603139..7cae226b000f7 100644
|
|
--- a/fs/ext4/ext4.h
|
|
+++ b/fs/ext4/ext4.h
|
|
@@ -1474,6 +1474,7 @@ struct ext4_sb_info {
|
|
struct percpu_counter s_freeinodes_counter;
|
|
struct percpu_counter s_dirs_counter;
|
|
struct percpu_counter s_dirtyclusters_counter;
|
|
+ struct percpu_counter s_sra_exceeded_retry_limit;
|
|
struct blockgroup_lock *s_blockgroup_lock;
|
|
struct proc_dir_entry *s_proc;
|
|
struct kobject s_kobj;
|
|
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
|
|
index c2b8ba343bb4b..3f11c948feb02 100644
|
|
--- a/fs/ext4/inode.c
|
|
+++ b/fs/ext4/inode.c
|
|
@@ -1937,13 +1937,13 @@ static int __ext4_journalled_writepage(struct page *page,
|
|
if (!ret)
|
|
ret = err;
|
|
|
|
- if (!ext4_has_inline_data(inode))
|
|
- ext4_walk_page_buffers(NULL, page_bufs, 0, len,
|
|
- NULL, bput_one);
|
|
ext4_set_inode_state(inode, EXT4_STATE_JDATA);
|
|
out:
|
|
unlock_page(page);
|
|
out_no_pagelock:
|
|
+ if (!inline_data && page_bufs)
|
|
+ ext4_walk_page_buffers(NULL, page_bufs, 0, len,
|
|
+ NULL, bput_one);
|
|
brelse(inode_bh);
|
|
return ret;
|
|
}
|
|
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
|
|
index 6c7eba426a678..ab7baf5299176 100644
|
|
--- a/fs/ext4/namei.c
|
|
+++ b/fs/ext4/namei.c
|
|
@@ -3788,14 +3788,14 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
*/
|
|
retval = -ENOENT;
|
|
if (!old.bh || le32_to_cpu(old.de->inode) != old.inode->i_ino)
|
|
- goto end_rename;
|
|
+ goto release_bh;
|
|
|
|
new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
|
|
&new.de, &new.inlined);
|
|
if (IS_ERR(new.bh)) {
|
|
retval = PTR_ERR(new.bh);
|
|
new.bh = NULL;
|
|
- goto end_rename;
|
|
+ goto release_bh;
|
|
}
|
|
if (new.bh) {
|
|
if (!new.inode) {
|
|
@@ -3812,15 +3812,13 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
handle = ext4_journal_start(old.dir, EXT4_HT_DIR, credits);
|
|
if (IS_ERR(handle)) {
|
|
retval = PTR_ERR(handle);
|
|
- handle = NULL;
|
|
- goto end_rename;
|
|
+ goto release_bh;
|
|
}
|
|
} else {
|
|
whiteout = ext4_whiteout_for_rename(&old, credits, &handle);
|
|
if (IS_ERR(whiteout)) {
|
|
retval = PTR_ERR(whiteout);
|
|
- whiteout = NULL;
|
|
- goto end_rename;
|
|
+ goto release_bh;
|
|
}
|
|
}
|
|
|
|
@@ -3957,16 +3955,18 @@ end_rename:
|
|
ext4_resetent(handle, &old,
|
|
old.inode->i_ino, old_file_type);
|
|
drop_nlink(whiteout);
|
|
+ ext4_orphan_add(handle, whiteout);
|
|
}
|
|
unlock_new_inode(whiteout);
|
|
+ ext4_journal_stop(handle);
|
|
iput(whiteout);
|
|
-
|
|
+ } else {
|
|
+ ext4_journal_stop(handle);
|
|
}
|
|
+release_bh:
|
|
brelse(old.dir_bh);
|
|
brelse(old.bh);
|
|
brelse(new.bh);
|
|
- if (handle)
|
|
- ext4_journal_stop(handle);
|
|
return retval;
|
|
}
|
|
|
|
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
|
|
index e30bf8f342c2a..594300d315ef2 100644
|
|
--- a/fs/ext4/super.c
|
|
+++ b/fs/ext4/super.c
|
|
@@ -1226,6 +1226,7 @@ static void ext4_put_super(struct super_block *sb)
|
|
percpu_counter_destroy(&sbi->s_freeinodes_counter);
|
|
percpu_counter_destroy(&sbi->s_dirs_counter);
|
|
percpu_counter_destroy(&sbi->s_dirtyclusters_counter);
|
|
+ percpu_counter_destroy(&sbi->s_sra_exceeded_retry_limit);
|
|
percpu_free_rwsem(&sbi->s_writepages_rwsem);
|
|
#ifdef CONFIG_QUOTA
|
|
for (i = 0; i < EXT4_MAXQUOTAS; i++)
|
|
@@ -5019,6 +5020,9 @@ no_journal:
|
|
if (!err)
|
|
err = percpu_counter_init(&sbi->s_dirtyclusters_counter, 0,
|
|
GFP_KERNEL);
|
|
+ if (!err)
|
|
+ err = percpu_counter_init(&sbi->s_sra_exceeded_retry_limit, 0,
|
|
+ GFP_KERNEL);
|
|
if (!err)
|
|
err = percpu_init_rwsem(&sbi->s_writepages_rwsem);
|
|
|
|
@@ -5131,6 +5135,7 @@ failed_mount6:
|
|
percpu_counter_destroy(&sbi->s_freeinodes_counter);
|
|
percpu_counter_destroy(&sbi->s_dirs_counter);
|
|
percpu_counter_destroy(&sbi->s_dirtyclusters_counter);
|
|
+ percpu_counter_destroy(&sbi->s_sra_exceeded_retry_limit);
|
|
percpu_free_rwsem(&sbi->s_writepages_rwsem);
|
|
failed_mount5:
|
|
ext4_ext_release(sb);
|
|
diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c
|
|
index 4e27fe6ed3ae6..f24bef3be48a3 100644
|
|
--- a/fs/ext4/sysfs.c
|
|
+++ b/fs/ext4/sysfs.c
|
|
@@ -24,6 +24,7 @@ typedef enum {
|
|
attr_session_write_kbytes,
|
|
attr_lifetime_write_kbytes,
|
|
attr_reserved_clusters,
|
|
+ attr_sra_exceeded_retry_limit,
|
|
attr_inode_readahead,
|
|
attr_trigger_test_error,
|
|
attr_first_error_time,
|
|
@@ -208,6 +209,7 @@ EXT4_ATTR_FUNC(delayed_allocation_blocks, 0444);
|
|
EXT4_ATTR_FUNC(session_write_kbytes, 0444);
|
|
EXT4_ATTR_FUNC(lifetime_write_kbytes, 0444);
|
|
EXT4_ATTR_FUNC(reserved_clusters, 0644);
|
|
+EXT4_ATTR_FUNC(sra_exceeded_retry_limit, 0444);
|
|
|
|
EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, inode_readahead,
|
|
ext4_sb_info, s_inode_readahead_blks);
|
|
@@ -257,6 +259,7 @@ static struct attribute *ext4_attrs[] = {
|
|
ATTR_LIST(session_write_kbytes),
|
|
ATTR_LIST(lifetime_write_kbytes),
|
|
ATTR_LIST(reserved_clusters),
|
|
+ ATTR_LIST(sra_exceeded_retry_limit),
|
|
ATTR_LIST(inode_readahead_blks),
|
|
ATTR_LIST(inode_goal),
|
|
ATTR_LIST(mb_stats),
|
|
@@ -380,6 +383,10 @@ static ssize_t ext4_attr_show(struct kobject *kobj,
|
|
return snprintf(buf, PAGE_SIZE, "%llu\n",
|
|
(unsigned long long)
|
|
atomic64_read(&sbi->s_resv_clusters));
|
|
+ case attr_sra_exceeded_retry_limit:
|
|
+ return snprintf(buf, PAGE_SIZE, "%llu\n",
|
|
+ (unsigned long long)
|
|
+ percpu_counter_sum(&sbi->s_sra_exceeded_retry_limit));
|
|
case attr_inode_readahead:
|
|
case attr_pointer_ui:
|
|
if (!ptr)
|
|
diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c
|
|
index d2c0e58c6416f..3d83c9e128487 100644
|
|
--- a/fs/fuse/virtio_fs.c
|
|
+++ b/fs/fuse/virtio_fs.c
|
|
@@ -1324,8 +1324,15 @@ static int virtio_fs_fill_super(struct super_block *sb, struct fs_context *fsc)
|
|
|
|
/* virtiofs allocates and installs its own fuse devices */
|
|
ctx->fudptr = NULL;
|
|
- if (ctx->dax)
|
|
+ if (ctx->dax) {
|
|
+ if (!fs->dax_dev) {
|
|
+ err = -EINVAL;
|
|
+ pr_err("virtio-fs: dax can't be enabled as filesystem"
|
|
+ " device does not support it.\n");
|
|
+ goto err_free_fuse_devs;
|
|
+ }
|
|
ctx->dax_dev = fs->dax_dev;
|
|
+ }
|
|
err = fuse_fill_super_common(sb, ctx);
|
|
if (err < 0)
|
|
goto err_free_fuse_devs;
|
|
diff --git a/fs/io_uring.c b/fs/io_uring.c
|
|
index dde290eb7dd0c..4ccf99cb8cdc0 100644
|
|
--- a/fs/io_uring.c
|
|
+++ b/fs/io_uring.c
|
|
@@ -4401,6 +4401,7 @@ static int io_sendmsg(struct io_kiocb *req, bool force_nonblock,
|
|
struct io_async_msghdr iomsg, *kmsg;
|
|
struct socket *sock;
|
|
unsigned flags;
|
|
+ int min_ret = 0;
|
|
int ret;
|
|
|
|
sock = sock_from_file(req->file, &ret);
|
|
@@ -4421,12 +4422,15 @@ static int io_sendmsg(struct io_kiocb *req, bool force_nonblock,
|
|
kmsg = &iomsg;
|
|
}
|
|
|
|
- flags = req->sr_msg.msg_flags;
|
|
+ flags = req->sr_msg.msg_flags | MSG_NOSIGNAL;
|
|
if (flags & MSG_DONTWAIT)
|
|
req->flags |= REQ_F_NOWAIT;
|
|
else if (force_nonblock)
|
|
flags |= MSG_DONTWAIT;
|
|
|
|
+ if (flags & MSG_WAITALL)
|
|
+ min_ret = iov_iter_count(&kmsg->msg.msg_iter);
|
|
+
|
|
ret = __sys_sendmsg_sock(sock, &kmsg->msg, flags);
|
|
if (force_nonblock && ret == -EAGAIN)
|
|
return io_setup_async_msg(req, kmsg);
|
|
@@ -4436,7 +4440,7 @@ static int io_sendmsg(struct io_kiocb *req, bool force_nonblock,
|
|
if (kmsg->iov != kmsg->fast_iov)
|
|
kfree(kmsg->iov);
|
|
req->flags &= ~REQ_F_NEED_CLEANUP;
|
|
- if (ret < 0)
|
|
+ if (ret < min_ret)
|
|
req_set_fail_links(req);
|
|
__io_req_complete(req, ret, 0, cs);
|
|
return 0;
|
|
@@ -4450,6 +4454,7 @@ static int io_send(struct io_kiocb *req, bool force_nonblock,
|
|
struct iovec iov;
|
|
struct socket *sock;
|
|
unsigned flags;
|
|
+ int min_ret = 0;
|
|
int ret;
|
|
|
|
sock = sock_from_file(req->file, &ret);
|
|
@@ -4465,12 +4470,15 @@ static int io_send(struct io_kiocb *req, bool force_nonblock,
|
|
msg.msg_controllen = 0;
|
|
msg.msg_namelen = 0;
|
|
|
|
- flags = req->sr_msg.msg_flags;
|
|
+ flags = req->sr_msg.msg_flags | MSG_NOSIGNAL;
|
|
if (flags & MSG_DONTWAIT)
|
|
req->flags |= REQ_F_NOWAIT;
|
|
else if (force_nonblock)
|
|
flags |= MSG_DONTWAIT;
|
|
|
|
+ if (flags & MSG_WAITALL)
|
|
+ min_ret = iov_iter_count(&msg.msg_iter);
|
|
+
|
|
msg.msg_flags = flags;
|
|
ret = sock_sendmsg(sock, &msg);
|
|
if (force_nonblock && ret == -EAGAIN)
|
|
@@ -4478,7 +4486,7 @@ static int io_send(struct io_kiocb *req, bool force_nonblock,
|
|
if (ret == -ERESTARTSYS)
|
|
ret = -EINTR;
|
|
|
|
- if (ret < 0)
|
|
+ if (ret < min_ret)
|
|
req_set_fail_links(req);
|
|
__io_req_complete(req, ret, 0, cs);
|
|
return 0;
|
|
@@ -4630,6 +4638,7 @@ static int io_recvmsg(struct io_kiocb *req, bool force_nonblock,
|
|
struct socket *sock;
|
|
struct io_buffer *kbuf;
|
|
unsigned flags;
|
|
+ int min_ret = 0;
|
|
int ret, cflags = 0;
|
|
|
|
sock = sock_from_file(req->file, &ret);
|
|
@@ -4659,12 +4668,15 @@ static int io_recvmsg(struct io_kiocb *req, bool force_nonblock,
|
|
1, req->sr_msg.len);
|
|
}
|
|
|
|
- flags = req->sr_msg.msg_flags;
|
|
+ flags = req->sr_msg.msg_flags | MSG_NOSIGNAL;
|
|
if (flags & MSG_DONTWAIT)
|
|
req->flags |= REQ_F_NOWAIT;
|
|
else if (force_nonblock)
|
|
flags |= MSG_DONTWAIT;
|
|
|
|
+ if (flags & MSG_WAITALL)
|
|
+ min_ret = iov_iter_count(&kmsg->msg.msg_iter);
|
|
+
|
|
ret = __sys_recvmsg_sock(sock, &kmsg->msg, req->sr_msg.umsg,
|
|
kmsg->uaddr, flags);
|
|
if (force_nonblock && ret == -EAGAIN)
|
|
@@ -4677,7 +4689,7 @@ static int io_recvmsg(struct io_kiocb *req, bool force_nonblock,
|
|
if (kmsg->iov != kmsg->fast_iov)
|
|
kfree(kmsg->iov);
|
|
req->flags &= ~REQ_F_NEED_CLEANUP;
|
|
- if (ret < 0)
|
|
+ if (ret < min_ret || ((flags & MSG_WAITALL) && (kmsg->msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))))
|
|
req_set_fail_links(req);
|
|
__io_req_complete(req, ret, cflags, cs);
|
|
return 0;
|
|
@@ -4693,6 +4705,7 @@ static int io_recv(struct io_kiocb *req, bool force_nonblock,
|
|
struct socket *sock;
|
|
struct iovec iov;
|
|
unsigned flags;
|
|
+ int min_ret = 0;
|
|
int ret, cflags = 0;
|
|
|
|
sock = sock_from_file(req->file, &ret);
|
|
@@ -4717,12 +4730,15 @@ static int io_recv(struct io_kiocb *req, bool force_nonblock,
|
|
msg.msg_iocb = NULL;
|
|
msg.msg_flags = 0;
|
|
|
|
- flags = req->sr_msg.msg_flags;
|
|
+ flags = req->sr_msg.msg_flags | MSG_NOSIGNAL;
|
|
if (flags & MSG_DONTWAIT)
|
|
req->flags |= REQ_F_NOWAIT;
|
|
else if (force_nonblock)
|
|
flags |= MSG_DONTWAIT;
|
|
|
|
+ if (flags & MSG_WAITALL)
|
|
+ min_ret = iov_iter_count(&msg.msg_iter);
|
|
+
|
|
ret = sock_recvmsg(sock, &msg, flags);
|
|
if (force_nonblock && ret == -EAGAIN)
|
|
return -EAGAIN;
|
|
@@ -4731,7 +4747,7 @@ static int io_recv(struct io_kiocb *req, bool force_nonblock,
|
|
out_free:
|
|
if (req->flags & REQ_F_BUFFER_SELECTED)
|
|
cflags = io_put_recv_kbuf(req);
|
|
- if (ret < 0)
|
|
+ if (ret < min_ret || ((flags & MSG_WAITALL) && (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))))
|
|
req_set_fail_links(req);
|
|
__io_req_complete(req, ret, cflags, cs);
|
|
return 0;
|
|
@@ -6242,7 +6258,6 @@ static enum hrtimer_restart io_link_timeout_fn(struct hrtimer *timer)
|
|
spin_unlock_irqrestore(&ctx->completion_lock, flags);
|
|
|
|
if (prev) {
|
|
- req_set_fail_links(prev);
|
|
io_async_find_and_cancel(ctx, req, prev->user_data, -ETIME);
|
|
io_put_req_deferred(prev, 1);
|
|
} else {
|
|
diff --git a/fs/iomap/swapfile.c b/fs/iomap/swapfile.c
|
|
index a648dbf6991e4..a5e478de14174 100644
|
|
--- a/fs/iomap/swapfile.c
|
|
+++ b/fs/iomap/swapfile.c
|
|
@@ -170,6 +170,16 @@ int iomap_swapfile_activate(struct swap_info_struct *sis,
|
|
return ret;
|
|
}
|
|
|
|
+ /*
|
|
+ * If this swapfile doesn't contain even a single page-aligned
|
|
+ * contiguous range of blocks, reject this useless swapfile to
|
|
+ * prevent confusion later on.
|
|
+ */
|
|
+ if (isi.nr_pages == 0) {
|
|
+ pr_warn("swapon: Cannot find a single usable page in file.\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
*pagespan = 1 + isi.highest_ppage - isi.lowest_ppage;
|
|
sis->max = isi.nr_pages;
|
|
sis->pages = isi.nr_pages - 1;
|
|
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
|
|
index dbbc583d62730..248f1459c0399 100644
|
|
--- a/fs/nfsd/Kconfig
|
|
+++ b/fs/nfsd/Kconfig
|
|
@@ -73,6 +73,7 @@ config NFSD_V4
|
|
select NFSD_V3
|
|
select FS_POSIX_ACL
|
|
select SUNRPC_GSS
|
|
+ select CRYPTO
|
|
select CRYPTO_MD5
|
|
select CRYPTO_SHA256
|
|
select GRACE_PERIOD
|
|
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
|
|
index 052be5bf9ef50..7325592b456e5 100644
|
|
--- a/fs/nfsd/nfs4callback.c
|
|
+++ b/fs/nfsd/nfs4callback.c
|
|
@@ -1189,6 +1189,7 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
|
|
switch (task->tk_status) {
|
|
case -EIO:
|
|
case -ETIMEDOUT:
|
|
+ case -EACCES:
|
|
nfsd4_mark_cb_down(clp, task->tk_status);
|
|
}
|
|
break;
|
|
diff --git a/fs/reiserfs/xattr.h b/fs/reiserfs/xattr.h
|
|
index c764352447ba1..81bec2c80b25c 100644
|
|
--- a/fs/reiserfs/xattr.h
|
|
+++ b/fs/reiserfs/xattr.h
|
|
@@ -43,7 +43,7 @@ void reiserfs_security_free(struct reiserfs_security_handle *sec);
|
|
|
|
static inline int reiserfs_xattrs_initialized(struct super_block *sb)
|
|
{
|
|
- return REISERFS_SB(sb)->priv_root != NULL;
|
|
+ return REISERFS_SB(sb)->priv_root && REISERFS_SB(sb)->xattr_root;
|
|
}
|
|
|
|
#define xattr_size(size) ((size) + sizeof(struct reiserfs_xattr_header))
|
|
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
|
|
index 9e173c6f312dc..fdb1d5262ce84 100644
|
|
--- a/include/linux/acpi.h
|
|
+++ b/include/linux/acpi.h
|
|
@@ -222,10 +222,14 @@ void __iomem *__acpi_map_table(unsigned long phys, unsigned long size);
|
|
void __acpi_unmap_table(void __iomem *map, unsigned long size);
|
|
int early_acpi_boot_init(void);
|
|
int acpi_boot_init (void);
|
|
+void acpi_boot_table_prepare (void);
|
|
void acpi_boot_table_init (void);
|
|
int acpi_mps_check (void);
|
|
int acpi_numa_init (void);
|
|
|
|
+int acpi_locate_initial_tables (void);
|
|
+void acpi_reserve_initial_tables (void);
|
|
+void acpi_table_init_complete (void);
|
|
int acpi_table_init (void);
|
|
int acpi_table_parse(char *id, acpi_tbl_table_handler handler);
|
|
int __init acpi_table_parse_entries(char *id, unsigned long table_size,
|
|
@@ -807,9 +811,12 @@ static inline int acpi_boot_init(void)
|
|
return 0;
|
|
}
|
|
|
|
+static inline void acpi_boot_table_prepare(void)
|
|
+{
|
|
+}
|
|
+
|
|
static inline void acpi_boot_table_init(void)
|
|
{
|
|
- return;
|
|
}
|
|
|
|
static inline int acpi_mps_check(void)
|
|
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
|
|
index dd236ef59db3e..b416bba3a62b5 100644
|
|
--- a/include/linux/bpf.h
|
|
+++ b/include/linux/bpf.h
|
|
@@ -20,6 +20,7 @@
|
|
#include <linux/module.h>
|
|
#include <linux/kallsyms.h>
|
|
#include <linux/capability.h>
|
|
+#include <linux/percpu-refcount.h>
|
|
|
|
struct bpf_verifier_env;
|
|
struct bpf_verifier_log;
|
|
@@ -556,7 +557,8 @@ struct bpf_tramp_progs {
|
|
* fentry = a set of program to run before calling original function
|
|
* fexit = a set of program to run after original function
|
|
*/
|
|
-int arch_prepare_bpf_trampoline(void *image, void *image_end,
|
|
+struct bpf_tramp_image;
|
|
+int arch_prepare_bpf_trampoline(struct bpf_tramp_image *tr, void *image, void *image_end,
|
|
const struct btf_func_model *m, u32 flags,
|
|
struct bpf_tramp_progs *tprogs,
|
|
void *orig_call);
|
|
@@ -565,6 +567,8 @@ u64 notrace __bpf_prog_enter(void);
|
|
void notrace __bpf_prog_exit(struct bpf_prog *prog, u64 start);
|
|
void notrace __bpf_prog_enter_sleepable(void);
|
|
void notrace __bpf_prog_exit_sleepable(void);
|
|
+void notrace __bpf_tramp_enter(struct bpf_tramp_image *tr);
|
|
+void notrace __bpf_tramp_exit(struct bpf_tramp_image *tr);
|
|
|
|
struct bpf_ksym {
|
|
unsigned long start;
|
|
@@ -583,6 +587,18 @@ enum bpf_tramp_prog_type {
|
|
BPF_TRAMP_REPLACE, /* more than MAX */
|
|
};
|
|
|
|
+struct bpf_tramp_image {
|
|
+ void *image;
|
|
+ struct bpf_ksym ksym;
|
|
+ struct percpu_ref pcref;
|
|
+ void *ip_after_call;
|
|
+ void *ip_epilogue;
|
|
+ union {
|
|
+ struct rcu_head rcu;
|
|
+ struct work_struct work;
|
|
+ };
|
|
+};
|
|
+
|
|
struct bpf_trampoline {
|
|
/* hlist for trampoline_table */
|
|
struct hlist_node hlist;
|
|
@@ -605,9 +621,8 @@ struct bpf_trampoline {
|
|
/* Number of attached programs. A counter per kind. */
|
|
int progs_cnt[BPF_TRAMP_MAX];
|
|
/* Executable image of trampoline */
|
|
- void *image;
|
|
+ struct bpf_tramp_image *cur_image;
|
|
u64 selector;
|
|
- struct bpf_ksym ksym;
|
|
};
|
|
|
|
struct bpf_attach_target_info {
|
|
@@ -691,6 +706,8 @@ void bpf_image_ksym_add(void *data, struct bpf_ksym *ksym);
|
|
void bpf_image_ksym_del(struct bpf_ksym *ksym);
|
|
void bpf_ksym_add(struct bpf_ksym *ksym);
|
|
void bpf_ksym_del(struct bpf_ksym *ksym);
|
|
+int bpf_jit_charge_modmem(u32 pages);
|
|
+void bpf_jit_uncharge_modmem(u32 pages);
|
|
#else
|
|
static inline int bpf_trampoline_link_prog(struct bpf_prog *prog,
|
|
struct bpf_trampoline *tr)
|
|
@@ -780,7 +797,6 @@ struct bpf_prog_aux {
|
|
bool func_proto_unreliable;
|
|
bool sleepable;
|
|
bool tail_call_reachable;
|
|
- enum bpf_tramp_prog_type trampoline_prog_type;
|
|
struct hlist_node tramp_hlist;
|
|
/* BTF_KIND_FUNC_PROTO for valid attach_btf_id */
|
|
const struct btf_type *attach_func_proto;
|
|
diff --git a/include/linux/can/can-ml.h b/include/linux/can/can-ml.h
|
|
index 2f5d731ae251d..8afa92d15a664 100644
|
|
--- a/include/linux/can/can-ml.h
|
|
+++ b/include/linux/can/can-ml.h
|
|
@@ -44,6 +44,7 @@
|
|
|
|
#include <linux/can.h>
|
|
#include <linux/list.h>
|
|
+#include <linux/netdevice.h>
|
|
|
|
#define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS)
|
|
#define CAN_EFF_RCV_HASH_BITS 10
|
|
@@ -65,4 +66,15 @@ struct can_ml_priv {
|
|
#endif
|
|
};
|
|
|
|
+static inline struct can_ml_priv *can_get_ml_priv(struct net_device *dev)
|
|
+{
|
|
+ return netdev_get_ml_priv(dev, ML_PRIV_CAN);
|
|
+}
|
|
+
|
|
+static inline void can_set_ml_priv(struct net_device *dev,
|
|
+ struct can_ml_priv *ml_priv)
|
|
+{
|
|
+ netdev_set_ml_priv(dev, ml_priv, ML_PRIV_CAN);
|
|
+}
|
|
+
|
|
#endif /* CAN_ML_H */
|
|
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
|
|
index fd183fb9c20f7..0c19010da77fa 100644
|
|
--- a/include/linux/extcon.h
|
|
+++ b/include/linux/extcon.h
|
|
@@ -271,6 +271,29 @@ static inline void devm_extcon_unregister_notifier(struct device *dev,
|
|
struct extcon_dev *edev, unsigned int id,
|
|
struct notifier_block *nb) { }
|
|
|
|
+static inline int extcon_register_notifier_all(struct extcon_dev *edev,
|
|
+ struct notifier_block *nb)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline int extcon_unregister_notifier_all(struct extcon_dev *edev,
|
|
+ struct notifier_block *nb)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline int devm_extcon_register_notifier_all(struct device *dev,
|
|
+ struct extcon_dev *edev,
|
|
+ struct notifier_block *nb)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline void devm_extcon_unregister_notifier_all(struct device *dev,
|
|
+ struct extcon_dev *edev,
|
|
+ struct notifier_block *nb) { }
|
|
+
|
|
static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
|
|
{
|
|
return ERR_PTR(-ENODEV);
|
|
diff --git a/include/linux/firmware/intel/stratix10-svc-client.h b/include/linux/firmware/intel/stratix10-svc-client.h
|
|
index a93d85932eb92..f843c6a10cf36 100644
|
|
--- a/include/linux/firmware/intel/stratix10-svc-client.h
|
|
+++ b/include/linux/firmware/intel/stratix10-svc-client.h
|
|
@@ -56,7 +56,7 @@
|
|
* COMMAND_RECONFIG_FLAG_PARTIAL:
|
|
* Set to FPGA configuration type (full or partial).
|
|
*/
|
|
-#define COMMAND_RECONFIG_FLAG_PARTIAL 1
|
|
+#define COMMAND_RECONFIG_FLAG_PARTIAL 0
|
|
|
|
/**
|
|
* Timeout settings for service clients:
|
|
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
|
|
index 8753e98a8d58a..e37480b5f4c0e 100644
|
|
--- a/include/linux/netdevice.h
|
|
+++ b/include/linux/netdevice.h
|
|
@@ -1600,6 +1600,12 @@ enum netdev_priv_flags {
|
|
#define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER
|
|
#define IFF_LIVE_RENAME_OK IFF_LIVE_RENAME_OK
|
|
|
|
+/* Specifies the type of the struct net_device::ml_priv pointer */
|
|
+enum netdev_ml_priv_type {
|
|
+ ML_PRIV_NONE,
|
|
+ ML_PRIV_CAN,
|
|
+};
|
|
+
|
|
/**
|
|
* struct net_device - The DEVICE structure.
|
|
*
|
|
@@ -1795,6 +1801,7 @@ enum netdev_priv_flags {
|
|
* @nd_net: Network namespace this network device is inside
|
|
*
|
|
* @ml_priv: Mid-layer private
|
|
+ * @ml_priv_type: Mid-layer private type
|
|
* @lstats: Loopback statistics
|
|
* @tstats: Tunnel statistics
|
|
* @dstats: Dummy statistics
|
|
@@ -2107,8 +2114,10 @@ struct net_device {
|
|
possible_net_t nd_net;
|
|
|
|
/* mid-layer private */
|
|
+ void *ml_priv;
|
|
+ enum netdev_ml_priv_type ml_priv_type;
|
|
+
|
|
union {
|
|
- void *ml_priv;
|
|
struct pcpu_lstats __percpu *lstats;
|
|
struct pcpu_sw_netstats __percpu *tstats;
|
|
struct pcpu_dstats __percpu *dstats;
|
|
@@ -2298,6 +2307,29 @@ static inline void netdev_reset_rx_headroom(struct net_device *dev)
|
|
netdev_set_rx_headroom(dev, -1);
|
|
}
|
|
|
|
+static inline void *netdev_get_ml_priv(struct net_device *dev,
|
|
+ enum netdev_ml_priv_type type)
|
|
+{
|
|
+ if (dev->ml_priv_type != type)
|
|
+ return NULL;
|
|
+
|
|
+ return dev->ml_priv;
|
|
+}
|
|
+
|
|
+static inline void netdev_set_ml_priv(struct net_device *dev,
|
|
+ void *ml_priv,
|
|
+ enum netdev_ml_priv_type type)
|
|
+{
|
|
+ WARN(dev->ml_priv_type && dev->ml_priv_type != type,
|
|
+ "Overwriting already set ml_priv_type (%u) with different ml_priv_type (%u)!\n",
|
|
+ dev->ml_priv_type, type);
|
|
+ WARN(!dev->ml_priv_type && dev->ml_priv,
|
|
+ "Overwriting already set ml_priv and ml_priv_type is ML_PRIV_NONE!\n");
|
|
+
|
|
+ dev->ml_priv = ml_priv;
|
|
+ dev->ml_priv_type = type;
|
|
+}
|
|
+
|
|
/*
|
|
* Net namespace inlines
|
|
*/
|
|
diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h
|
|
index f7bbea3f09ca9..964cfe68f72cc 100644
|
|
--- a/include/linux/qcom-geni-se.h
|
|
+++ b/include/linux/qcom-geni-se.h
|
|
@@ -462,7 +462,5 @@ void geni_icc_set_tag(struct geni_se *se, u32 tag);
|
|
int geni_icc_enable(struct geni_se *se);
|
|
|
|
int geni_icc_disable(struct geni_se *se);
|
|
-
|
|
-void geni_remove_earlycon_icc_vote(void);
|
|
#endif
|
|
#endif
|
|
diff --git a/include/linux/ww_mutex.h b/include/linux/ww_mutex.h
|
|
index 850424e5d0306..6ecf2a0220dbe 100644
|
|
--- a/include/linux/ww_mutex.h
|
|
+++ b/include/linux/ww_mutex.h
|
|
@@ -173,9 +173,10 @@ static inline void ww_acquire_done(struct ww_acquire_ctx *ctx)
|
|
*/
|
|
static inline void ww_acquire_fini(struct ww_acquire_ctx *ctx)
|
|
{
|
|
-#ifdef CONFIG_DEBUG_MUTEXES
|
|
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
mutex_release(&ctx->dep_map, _THIS_IP_);
|
|
-
|
|
+#endif
|
|
+#ifdef CONFIG_DEBUG_MUTEXES
|
|
DEBUG_LOCKS_WARN_ON(ctx->acquired);
|
|
if (!IS_ENABLED(CONFIG_PROVE_LOCKING))
|
|
/*
|
|
diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
|
|
index 4c3b543bb33b7..f527063864b55 100644
|
|
--- a/kernel/bpf/bpf_struct_ops.c
|
|
+++ b/kernel/bpf/bpf_struct_ops.c
|
|
@@ -430,7 +430,7 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
|
|
|
|
tprogs[BPF_TRAMP_FENTRY].progs[0] = prog;
|
|
tprogs[BPF_TRAMP_FENTRY].nr_progs = 1;
|
|
- err = arch_prepare_bpf_trampoline(image,
|
|
+ err = arch_prepare_bpf_trampoline(NULL, image,
|
|
st_map->image + PAGE_SIZE,
|
|
&st_ops->func_models[i], 0,
|
|
tprogs, NULL);
|
|
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
|
|
index 55454d2278b17..182e162f8fd0b 100644
|
|
--- a/kernel/bpf/core.c
|
|
+++ b/kernel/bpf/core.c
|
|
@@ -825,7 +825,7 @@ static int __init bpf_jit_charge_init(void)
|
|
}
|
|
pure_initcall(bpf_jit_charge_init);
|
|
|
|
-static int bpf_jit_charge_modmem(u32 pages)
|
|
+int bpf_jit_charge_modmem(u32 pages)
|
|
{
|
|
if (atomic_long_add_return(pages, &bpf_jit_current) >
|
|
(bpf_jit_limit >> PAGE_SHIFT)) {
|
|
@@ -838,7 +838,7 @@ static int bpf_jit_charge_modmem(u32 pages)
|
|
return 0;
|
|
}
|
|
|
|
-static void bpf_jit_uncharge_modmem(u32 pages)
|
|
+void bpf_jit_uncharge_modmem(u32 pages)
|
|
{
|
|
atomic_long_sub(pages, &bpf_jit_current);
|
|
}
|
|
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
|
|
index 35c5887d82ffe..986dabc3d11f0 100644
|
|
--- a/kernel/bpf/trampoline.c
|
|
+++ b/kernel/bpf/trampoline.c
|
|
@@ -57,19 +57,10 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
|
|
PAGE_SIZE, true, ksym->name);
|
|
}
|
|
|
|
-static void bpf_trampoline_ksym_add(struct bpf_trampoline *tr)
|
|
-{
|
|
- struct bpf_ksym *ksym = &tr->ksym;
|
|
-
|
|
- snprintf(ksym->name, KSYM_NAME_LEN, "bpf_trampoline_%llu", tr->key);
|
|
- bpf_image_ksym_add(tr->image, ksym);
|
|
-}
|
|
-
|
|
static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
|
|
{
|
|
struct bpf_trampoline *tr;
|
|
struct hlist_head *head;
|
|
- void *image;
|
|
int i;
|
|
|
|
mutex_lock(&trampoline_mutex);
|
|
@@ -84,14 +75,6 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
|
|
if (!tr)
|
|
goto out;
|
|
|
|
- /* is_root was checked earlier. No need for bpf_jit_charge_modmem() */
|
|
- image = bpf_jit_alloc_exec_page();
|
|
- if (!image) {
|
|
- kfree(tr);
|
|
- tr = NULL;
|
|
- goto out;
|
|
- }
|
|
-
|
|
tr->key = key;
|
|
INIT_HLIST_NODE(&tr->hlist);
|
|
hlist_add_head(&tr->hlist, head);
|
|
@@ -99,9 +82,6 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
|
|
mutex_init(&tr->mutex);
|
|
for (i = 0; i < BPF_TRAMP_MAX; i++)
|
|
INIT_HLIST_HEAD(&tr->progs_hlist[i]);
|
|
- tr->image = image;
|
|
- INIT_LIST_HEAD_RCU(&tr->ksym.lnode);
|
|
- bpf_trampoline_ksym_add(tr);
|
|
out:
|
|
mutex_unlock(&trampoline_mutex);
|
|
return tr;
|
|
@@ -185,10 +165,142 @@ bpf_trampoline_get_progs(const struct bpf_trampoline *tr, int *total)
|
|
return tprogs;
|
|
}
|
|
|
|
+static void __bpf_tramp_image_put_deferred(struct work_struct *work)
|
|
+{
|
|
+ struct bpf_tramp_image *im;
|
|
+
|
|
+ im = container_of(work, struct bpf_tramp_image, work);
|
|
+ bpf_image_ksym_del(&im->ksym);
|
|
+ bpf_jit_free_exec(im->image);
|
|
+ bpf_jit_uncharge_modmem(1);
|
|
+ percpu_ref_exit(&im->pcref);
|
|
+ kfree_rcu(im, rcu);
|
|
+}
|
|
+
|
|
+/* callback, fexit step 3 or fentry step 2 */
|
|
+static void __bpf_tramp_image_put_rcu(struct rcu_head *rcu)
|
|
+{
|
|
+ struct bpf_tramp_image *im;
|
|
+
|
|
+ im = container_of(rcu, struct bpf_tramp_image, rcu);
|
|
+ INIT_WORK(&im->work, __bpf_tramp_image_put_deferred);
|
|
+ schedule_work(&im->work);
|
|
+}
|
|
+
|
|
+/* callback, fexit step 2. Called after percpu_ref_kill confirms. */
|
|
+static void __bpf_tramp_image_release(struct percpu_ref *pcref)
|
|
+{
|
|
+ struct bpf_tramp_image *im;
|
|
+
|
|
+ im = container_of(pcref, struct bpf_tramp_image, pcref);
|
|
+ call_rcu_tasks(&im->rcu, __bpf_tramp_image_put_rcu);
|
|
+}
|
|
+
|
|
+/* callback, fexit or fentry step 1 */
|
|
+static void __bpf_tramp_image_put_rcu_tasks(struct rcu_head *rcu)
|
|
+{
|
|
+ struct bpf_tramp_image *im;
|
|
+
|
|
+ im = container_of(rcu, struct bpf_tramp_image, rcu);
|
|
+ if (im->ip_after_call)
|
|
+ /* the case of fmod_ret/fexit trampoline and CONFIG_PREEMPTION=y */
|
|
+ percpu_ref_kill(&im->pcref);
|
|
+ else
|
|
+ /* the case of fentry trampoline */
|
|
+ call_rcu_tasks(&im->rcu, __bpf_tramp_image_put_rcu);
|
|
+}
|
|
+
|
|
+static void bpf_tramp_image_put(struct bpf_tramp_image *im)
|
|
+{
|
|
+ /* The trampoline image that calls original function is using:
|
|
+ * rcu_read_lock_trace to protect sleepable bpf progs
|
|
+ * rcu_read_lock to protect normal bpf progs
|
|
+ * percpu_ref to protect trampoline itself
|
|
+ * rcu tasks to protect trampoline asm not covered by percpu_ref
|
|
+ * (which are few asm insns before __bpf_tramp_enter and
|
|
+ * after __bpf_tramp_exit)
|
|
+ *
|
|
+ * The trampoline is unreachable before bpf_tramp_image_put().
|
|
+ *
|
|
+ * First, patch the trampoline to avoid calling into fexit progs.
|
|
+ * The progs will be freed even if the original function is still
|
|
+ * executing or sleeping.
|
|
+ * In case of CONFIG_PREEMPT=y use call_rcu_tasks() to wait on
|
|
+ * first few asm instructions to execute and call into
|
|
+ * __bpf_tramp_enter->percpu_ref_get.
|
|
+ * Then use percpu_ref_kill to wait for the trampoline and the original
|
|
+ * function to finish.
|
|
+ * Then use call_rcu_tasks() to make sure few asm insns in
|
|
+ * the trampoline epilogue are done as well.
|
|
+ *
|
|
+ * In !PREEMPT case the task that got interrupted in the first asm
|
|
+ * insns won't go through an RCU quiescent state which the
|
|
+ * percpu_ref_kill will be waiting for. Hence the first
|
|
+ * call_rcu_tasks() is not necessary.
|
|
+ */
|
|
+ if (im->ip_after_call) {
|
|
+ int err = bpf_arch_text_poke(im->ip_after_call, BPF_MOD_JUMP,
|
|
+ NULL, im->ip_epilogue);
|
|
+ WARN_ON(err);
|
|
+ if (IS_ENABLED(CONFIG_PREEMPTION))
|
|
+ call_rcu_tasks(&im->rcu, __bpf_tramp_image_put_rcu_tasks);
|
|
+ else
|
|
+ percpu_ref_kill(&im->pcref);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* The trampoline without fexit and fmod_ret progs doesn't call original
|
|
+ * function and doesn't use percpu_ref.
|
|
+ * Use call_rcu_tasks_trace() to wait for sleepable progs to finish.
|
|
+ * Then use call_rcu_tasks() to wait for the rest of trampoline asm
|
|
+ * and normal progs.
|
|
+ */
|
|
+ call_rcu_tasks_trace(&im->rcu, __bpf_tramp_image_put_rcu_tasks);
|
|
+}
|
|
+
|
|
+static struct bpf_tramp_image *bpf_tramp_image_alloc(u64 key, u32 idx)
|
|
+{
|
|
+ struct bpf_tramp_image *im;
|
|
+ struct bpf_ksym *ksym;
|
|
+ void *image;
|
|
+ int err = -ENOMEM;
|
|
+
|
|
+ im = kzalloc(sizeof(*im), GFP_KERNEL);
|
|
+ if (!im)
|
|
+ goto out;
|
|
+
|
|
+ err = bpf_jit_charge_modmem(1);
|
|
+ if (err)
|
|
+ goto out_free_im;
|
|
+
|
|
+ err = -ENOMEM;
|
|
+ im->image = image = bpf_jit_alloc_exec_page();
|
|
+ if (!image)
|
|
+ goto out_uncharge;
|
|
+
|
|
+ err = percpu_ref_init(&im->pcref, __bpf_tramp_image_release, 0, GFP_KERNEL);
|
|
+ if (err)
|
|
+ goto out_free_image;
|
|
+
|
|
+ ksym = &im->ksym;
|
|
+ INIT_LIST_HEAD_RCU(&ksym->lnode);
|
|
+ snprintf(ksym->name, KSYM_NAME_LEN, "bpf_trampoline_%llu_%u", key, idx);
|
|
+ bpf_image_ksym_add(image, ksym);
|
|
+ return im;
|
|
+
|
|
+out_free_image:
|
|
+ bpf_jit_free_exec(im->image);
|
|
+out_uncharge:
|
|
+ bpf_jit_uncharge_modmem(1);
|
|
+out_free_im:
|
|
+ kfree(im);
|
|
+out:
|
|
+ return ERR_PTR(err);
|
|
+}
|
|
+
|
|
static int bpf_trampoline_update(struct bpf_trampoline *tr)
|
|
{
|
|
- void *old_image = tr->image + ((tr->selector + 1) & 1) * PAGE_SIZE/2;
|
|
- void *new_image = tr->image + (tr->selector & 1) * PAGE_SIZE/2;
|
|
+ struct bpf_tramp_image *im;
|
|
struct bpf_tramp_progs *tprogs;
|
|
u32 flags = BPF_TRAMP_F_RESTORE_REGS;
|
|
int err, total;
|
|
@@ -198,41 +310,42 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr)
|
|
return PTR_ERR(tprogs);
|
|
|
|
if (total == 0) {
|
|
- err = unregister_fentry(tr, old_image);
|
|
+ err = unregister_fentry(tr, tr->cur_image->image);
|
|
+ bpf_tramp_image_put(tr->cur_image);
|
|
+ tr->cur_image = NULL;
|
|
tr->selector = 0;
|
|
goto out;
|
|
}
|
|
|
|
+ im = bpf_tramp_image_alloc(tr->key, tr->selector);
|
|
+ if (IS_ERR(im)) {
|
|
+ err = PTR_ERR(im);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
if (tprogs[BPF_TRAMP_FEXIT].nr_progs ||
|
|
tprogs[BPF_TRAMP_MODIFY_RETURN].nr_progs)
|
|
flags = BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_SKIP_FRAME;
|
|
|
|
- /* Though the second half of trampoline page is unused a task could be
|
|
- * preempted in the middle of the first half of trampoline and two
|
|
- * updates to trampoline would change the code from underneath the
|
|
- * preempted task. Hence wait for tasks to voluntarily schedule or go
|
|
- * to userspace.
|
|
- * The same trampoline can hold both sleepable and non-sleepable progs.
|
|
- * synchronize_rcu_tasks_trace() is needed to make sure all sleepable
|
|
- * programs finish executing.
|
|
- * Wait for these two grace periods together.
|
|
- */
|
|
- synchronize_rcu_mult(call_rcu_tasks, call_rcu_tasks_trace);
|
|
-
|
|
- err = arch_prepare_bpf_trampoline(new_image, new_image + PAGE_SIZE / 2,
|
|
+ err = arch_prepare_bpf_trampoline(im, im->image, im->image + PAGE_SIZE,
|
|
&tr->func.model, flags, tprogs,
|
|
tr->func.addr);
|
|
if (err < 0)
|
|
goto out;
|
|
|
|
- if (tr->selector)
|
|
+ WARN_ON(tr->cur_image && tr->selector == 0);
|
|
+ WARN_ON(!tr->cur_image && tr->selector);
|
|
+ if (tr->cur_image)
|
|
/* progs already running at this address */
|
|
- err = modify_fentry(tr, old_image, new_image);
|
|
+ err = modify_fentry(tr, tr->cur_image->image, im->image);
|
|
else
|
|
/* first time registering */
|
|
- err = register_fentry(tr, new_image);
|
|
+ err = register_fentry(tr, im->image);
|
|
if (err)
|
|
goto out;
|
|
+ if (tr->cur_image)
|
|
+ bpf_tramp_image_put(tr->cur_image);
|
|
+ tr->cur_image = im;
|
|
tr->selector++;
|
|
out:
|
|
kfree(tprogs);
|
|
@@ -364,17 +477,12 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
|
|
goto out;
|
|
if (WARN_ON_ONCE(!hlist_empty(&tr->progs_hlist[BPF_TRAMP_FEXIT])))
|
|
goto out;
|
|
- bpf_image_ksym_del(&tr->ksym);
|
|
- /* This code will be executed when all bpf progs (both sleepable and
|
|
- * non-sleepable) went through
|
|
- * bpf_prog_put()->call_rcu[_tasks_trace]()->bpf_prog_free_deferred().
|
|
- * Hence no need for another synchronize_rcu_tasks_trace() here,
|
|
- * but synchronize_rcu_tasks() is still needed, since trampoline
|
|
- * may not have had any sleepable programs and we need to wait
|
|
- * for tasks to get out of trampoline code before freeing it.
|
|
+ /* This code will be executed even when the last bpf_tramp_image
|
|
+ * is alive. All progs are detached from the trampoline and the
|
|
+ * trampoline image is patched with jmp into epilogue to skip
|
|
+ * fexit progs. The fentry-only trampoline will be freed via
|
|
+ * multiple rcu callbacks.
|
|
*/
|
|
- synchronize_rcu_tasks();
|
|
- bpf_jit_free_exec(tr->image);
|
|
hlist_del(&tr->hlist);
|
|
kfree(tr);
|
|
out:
|
|
@@ -433,8 +541,18 @@ void notrace __bpf_prog_exit_sleepable(void)
|
|
rcu_read_unlock_trace();
|
|
}
|
|
|
|
+void notrace __bpf_tramp_enter(struct bpf_tramp_image *tr)
|
|
+{
|
|
+ percpu_ref_get(&tr->pcref);
|
|
+}
|
|
+
|
|
+void notrace __bpf_tramp_exit(struct bpf_tramp_image *tr)
|
|
+{
|
|
+ percpu_ref_put(&tr->pcref);
|
|
+}
|
|
+
|
|
int __weak
|
|
-arch_prepare_bpf_trampoline(void *image, void *image_end,
|
|
+arch_prepare_bpf_trampoline(struct bpf_tramp_image *tr, void *image, void *image_end,
|
|
const struct btf_func_model *m, u32 flags,
|
|
struct bpf_tramp_progs *tprogs,
|
|
void *orig_call)
|
|
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
|
|
index 5352ce50a97e3..2c25b830203cd 100644
|
|
--- a/kernel/locking/mutex.c
|
|
+++ b/kernel/locking/mutex.c
|
|
@@ -636,7 +636,7 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock)
|
|
*/
|
|
static __always_inline bool
|
|
mutex_optimistic_spin(struct mutex *lock, struct ww_acquire_ctx *ww_ctx,
|
|
- const bool use_ww_ctx, struct mutex_waiter *waiter)
|
|
+ struct mutex_waiter *waiter)
|
|
{
|
|
if (!waiter) {
|
|
/*
|
|
@@ -712,7 +712,7 @@ fail:
|
|
#else
|
|
static __always_inline bool
|
|
mutex_optimistic_spin(struct mutex *lock, struct ww_acquire_ctx *ww_ctx,
|
|
- const bool use_ww_ctx, struct mutex_waiter *waiter)
|
|
+ struct mutex_waiter *waiter)
|
|
{
|
|
return false;
|
|
}
|
|
@@ -932,6 +932,9 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
|
struct ww_mutex *ww;
|
|
int ret;
|
|
|
|
+ if (!use_ww_ctx)
|
|
+ ww_ctx = NULL;
|
|
+
|
|
might_sleep();
|
|
|
|
#ifdef CONFIG_DEBUG_MUTEXES
|
|
@@ -939,7 +942,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
|
#endif
|
|
|
|
ww = container_of(lock, struct ww_mutex, base);
|
|
- if (use_ww_ctx && ww_ctx) {
|
|
+ if (ww_ctx) {
|
|
if (unlikely(ww_ctx == READ_ONCE(ww->ctx)))
|
|
return -EALREADY;
|
|
|
|
@@ -956,10 +959,10 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
|
mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);
|
|
|
|
if (__mutex_trylock(lock) ||
|
|
- mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, NULL)) {
|
|
+ mutex_optimistic_spin(lock, ww_ctx, NULL)) {
|
|
/* got the lock, yay! */
|
|
lock_acquired(&lock->dep_map, ip);
|
|
- if (use_ww_ctx && ww_ctx)
|
|
+ if (ww_ctx)
|
|
ww_mutex_set_context_fastpath(ww, ww_ctx);
|
|
preempt_enable();
|
|
return 0;
|
|
@@ -970,7 +973,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
|
* After waiting to acquire the wait_lock, try again.
|
|
*/
|
|
if (__mutex_trylock(lock)) {
|
|
- if (use_ww_ctx && ww_ctx)
|
|
+ if (ww_ctx)
|
|
__ww_mutex_check_waiters(lock, ww_ctx);
|
|
|
|
goto skip_wait;
|
|
@@ -1023,7 +1026,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
|
goto err;
|
|
}
|
|
|
|
- if (use_ww_ctx && ww_ctx) {
|
|
+ if (ww_ctx) {
|
|
ret = __ww_mutex_check_kill(lock, &waiter, ww_ctx);
|
|
if (ret)
|
|
goto err;
|
|
@@ -1036,7 +1039,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
|
* ww_mutex needs to always recheck its position since its waiter
|
|
* list is not FIFO ordered.
|
|
*/
|
|
- if ((use_ww_ctx && ww_ctx) || !first) {
|
|
+ if (ww_ctx || !first) {
|
|
first = __mutex_waiter_is_first(lock, &waiter);
|
|
if (first)
|
|
__mutex_set_flag(lock, MUTEX_FLAG_HANDOFF);
|
|
@@ -1049,7 +1052,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
|
* or we must see its unlock and acquire.
|
|
*/
|
|
if (__mutex_trylock(lock) ||
|
|
- (first && mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, &waiter)))
|
|
+ (first && mutex_optimistic_spin(lock, ww_ctx, &waiter)))
|
|
break;
|
|
|
|
spin_lock(&lock->wait_lock);
|
|
@@ -1058,7 +1061,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
|
acquired:
|
|
__set_current_state(TASK_RUNNING);
|
|
|
|
- if (use_ww_ctx && ww_ctx) {
|
|
+ if (ww_ctx) {
|
|
/*
|
|
* Wound-Wait; we stole the lock (!first_waiter), check the
|
|
* waiters as anyone might want to wound us.
|
|
@@ -1078,7 +1081,7 @@ skip_wait:
|
|
/* got the lock - cleanup and rejoice! */
|
|
lock_acquired(&lock->dep_map, ip);
|
|
|
|
- if (use_ww_ctx && ww_ctx)
|
|
+ if (ww_ctx)
|
|
ww_mutex_lock_acquired(ww, ww_ctx);
|
|
|
|
spin_unlock(&lock->wait_lock);
|
|
diff --git a/kernel/static_call.c b/kernel/static_call.c
|
|
index 49efbdc5b4800..f59089a122319 100644
|
|
--- a/kernel/static_call.c
|
|
+++ b/kernel/static_call.c
|
|
@@ -149,6 +149,7 @@ void __static_call_update(struct static_call_key *key, void *tramp, void *func)
|
|
};
|
|
|
|
for (site_mod = &first; site_mod; site_mod = site_mod->next) {
|
|
+ bool init = system_state < SYSTEM_RUNNING;
|
|
struct module *mod = site_mod->mod;
|
|
|
|
if (!site_mod->sites) {
|
|
@@ -168,6 +169,7 @@ void __static_call_update(struct static_call_key *key, void *tramp, void *func)
|
|
if (mod) {
|
|
stop = mod->static_call_sites +
|
|
mod->num_static_call_sites;
|
|
+ init = mod->state == MODULE_STATE_COMING;
|
|
}
|
|
#endif
|
|
|
|
@@ -175,16 +177,8 @@ void __static_call_update(struct static_call_key *key, void *tramp, void *func)
|
|
site < stop && static_call_key(site) == key; site++) {
|
|
void *site_addr = static_call_addr(site);
|
|
|
|
- if (static_call_is_init(site)) {
|
|
- /*
|
|
- * Don't write to call sites which were in
|
|
- * initmem and have since been freed.
|
|
- */
|
|
- if (!mod && system_state >= SYSTEM_RUNNING)
|
|
- continue;
|
|
- if (mod && !within_module_init((unsigned long)site_addr, mod))
|
|
- continue;
|
|
- }
|
|
+ if (!init && static_call_is_init(site))
|
|
+ continue;
|
|
|
|
if (!kernel_text_address((unsigned long)site_addr)) {
|
|
/*
|
|
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
|
|
index ee4be813ba85b..8bfa4e78d8951 100644
|
|
--- a/kernel/trace/trace.c
|
|
+++ b/kernel/trace/trace.c
|
|
@@ -2984,7 +2984,8 @@ static void __ftrace_trace_stack(struct trace_buffer *buffer,
|
|
|
|
size = nr_entries * sizeof(unsigned long);
|
|
event = __trace_buffer_lock_reserve(buffer, TRACE_STACK,
|
|
- sizeof(*entry) + size, flags, pc);
|
|
+ (sizeof(*entry) - sizeof(entry->caller)) + size,
|
|
+ flags, pc);
|
|
if (!event)
|
|
goto out;
|
|
entry = ring_buffer_event_data(event);
|
|
diff --git a/mm/memory.c b/mm/memory.c
|
|
index 4d565d7c80169..b70bd3ba33888 100644
|
|
--- a/mm/memory.c
|
|
+++ b/mm/memory.c
|
|
@@ -154,7 +154,7 @@ static int __init init_zero_pfn(void)
|
|
zero_pfn = page_to_pfn(ZERO_PAGE(0));
|
|
return 0;
|
|
}
|
|
-core_initcall(init_zero_pfn);
|
|
+early_initcall(init_zero_pfn);
|
|
|
|
void mm_trace_rss_stat(struct mm_struct *mm, int member, long count)
|
|
{
|
|
diff --git a/net/9p/client.c b/net/9p/client.c
|
|
index 09f1ec589b80b..eb42bbb72f523 100644
|
|
--- a/net/9p/client.c
|
|
+++ b/net/9p/client.c
|
|
@@ -1617,10 +1617,6 @@ p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to,
|
|
}
|
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
|
|
- if (!count) {
|
|
- p9_tag_remove(clnt, req);
|
|
- return 0;
|
|
- }
|
|
|
|
if (non_zc) {
|
|
int n = copy_to_iter(dataptr, count, to);
|
|
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
|
|
index 1d48708c5a2eb..c94b212d8e7ca 100644
|
|
--- a/net/appletalk/ddp.c
|
|
+++ b/net/appletalk/ddp.c
|
|
@@ -1576,8 +1576,8 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
|
|
struct sk_buff *skb;
|
|
struct net_device *dev;
|
|
struct ddpehdr *ddp;
|
|
- int size;
|
|
- struct atalk_route *rt;
|
|
+ int size, hard_header_len;
|
|
+ struct atalk_route *rt, *rt_lo = NULL;
|
|
int err;
|
|
|
|
if (flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
|
|
@@ -1640,7 +1640,22 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
|
|
SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n",
|
|
sk, size, dev->name);
|
|
|
|
- size += dev->hard_header_len;
|
|
+ hard_header_len = dev->hard_header_len;
|
|
+ /* Leave room for loopback hardware header if necessary */
|
|
+ if (usat->sat_addr.s_node == ATADDR_BCAST &&
|
|
+ (dev->flags & IFF_LOOPBACK || !(rt->flags & RTF_GATEWAY))) {
|
|
+ struct atalk_addr at_lo;
|
|
+
|
|
+ at_lo.s_node = 0;
|
|
+ at_lo.s_net = 0;
|
|
+
|
|
+ rt_lo = atrtr_find(&at_lo);
|
|
+
|
|
+ if (rt_lo && rt_lo->dev->hard_header_len > hard_header_len)
|
|
+ hard_header_len = rt_lo->dev->hard_header_len;
|
|
+ }
|
|
+
|
|
+ size += hard_header_len;
|
|
release_sock(sk);
|
|
skb = sock_alloc_send_skb(sk, size, (flags & MSG_DONTWAIT), &err);
|
|
lock_sock(sk);
|
|
@@ -1648,7 +1663,7 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
|
|
goto out;
|
|
|
|
skb_reserve(skb, ddp_dl->header_length);
|
|
- skb_reserve(skb, dev->hard_header_len);
|
|
+ skb_reserve(skb, hard_header_len);
|
|
skb->dev = dev;
|
|
|
|
SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk);
|
|
@@ -1699,18 +1714,12 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
|
|
/* loop back */
|
|
skb_orphan(skb);
|
|
if (ddp->deh_dnode == ATADDR_BCAST) {
|
|
- struct atalk_addr at_lo;
|
|
-
|
|
- at_lo.s_node = 0;
|
|
- at_lo.s_net = 0;
|
|
-
|
|
- rt = atrtr_find(&at_lo);
|
|
- if (!rt) {
|
|
+ if (!rt_lo) {
|
|
kfree_skb(skb);
|
|
err = -ENETUNREACH;
|
|
goto out;
|
|
}
|
|
- dev = rt->dev;
|
|
+ dev = rt_lo->dev;
|
|
skb->dev = dev;
|
|
}
|
|
ddp_dl->request(ddp_dl, skb, dev->dev_addr);
|
|
diff --git a/net/can/af_can.c b/net/can/af_can.c
|
|
index 4c343b43067f6..1c95ede2c9a6e 100644
|
|
--- a/net/can/af_can.c
|
|
+++ b/net/can/af_can.c
|
|
@@ -304,8 +304,8 @@ static struct can_dev_rcv_lists *can_dev_rcv_lists_find(struct net *net,
|
|
struct net_device *dev)
|
|
{
|
|
if (dev) {
|
|
- struct can_ml_priv *ml_priv = dev->ml_priv;
|
|
- return &ml_priv->dev_rcv_lists;
|
|
+ struct can_ml_priv *can_ml = can_get_ml_priv(dev);
|
|
+ return &can_ml->dev_rcv_lists;
|
|
} else {
|
|
return net->can.rx_alldev_list;
|
|
}
|
|
@@ -790,25 +790,6 @@ void can_proto_unregister(const struct can_proto *cp)
|
|
}
|
|
EXPORT_SYMBOL(can_proto_unregister);
|
|
|
|
-/* af_can notifier to create/remove CAN netdevice specific structs */
|
|
-static int can_notifier(struct notifier_block *nb, unsigned long msg,
|
|
- void *ptr)
|
|
-{
|
|
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
|
-
|
|
- if (dev->type != ARPHRD_CAN)
|
|
- return NOTIFY_DONE;
|
|
-
|
|
- switch (msg) {
|
|
- case NETDEV_REGISTER:
|
|
- WARN(!dev->ml_priv,
|
|
- "No CAN mid layer private allocated, please fix your driver and use alloc_candev()!\n");
|
|
- break;
|
|
- }
|
|
-
|
|
- return NOTIFY_DONE;
|
|
-}
|
|
-
|
|
static int can_pernet_init(struct net *net)
|
|
{
|
|
spin_lock_init(&net->can.rcvlists_lock);
|
|
@@ -876,11 +857,6 @@ static const struct net_proto_family can_family_ops = {
|
|
.owner = THIS_MODULE,
|
|
};
|
|
|
|
-/* notifier block for netdevice event */
|
|
-static struct notifier_block can_netdev_notifier __read_mostly = {
|
|
- .notifier_call = can_notifier,
|
|
-};
|
|
-
|
|
static struct pernet_operations can_pernet_ops __read_mostly = {
|
|
.init = can_pernet_init,
|
|
.exit = can_pernet_exit,
|
|
@@ -911,17 +887,12 @@ static __init int can_init(void)
|
|
err = sock_register(&can_family_ops);
|
|
if (err)
|
|
goto out_sock;
|
|
- err = register_netdevice_notifier(&can_netdev_notifier);
|
|
- if (err)
|
|
- goto out_notifier;
|
|
|
|
dev_add_pack(&can_packet);
|
|
dev_add_pack(&canfd_packet);
|
|
|
|
return 0;
|
|
|
|
-out_notifier:
|
|
- sock_unregister(PF_CAN);
|
|
out_sock:
|
|
unregister_pernet_subsys(&can_pernet_ops);
|
|
out_pernet:
|
|
@@ -935,7 +906,6 @@ static __exit void can_exit(void)
|
|
/* protocol unregister */
|
|
dev_remove_pack(&canfd_packet);
|
|
dev_remove_pack(&can_packet);
|
|
- unregister_netdevice_notifier(&can_netdev_notifier);
|
|
sock_unregister(PF_CAN);
|
|
|
|
unregister_pernet_subsys(&can_pernet_ops);
|
|
diff --git a/net/can/j1939/main.c b/net/can/j1939/main.c
|
|
index 137054bff9ec7..e52330f628c9f 100644
|
|
--- a/net/can/j1939/main.c
|
|
+++ b/net/can/j1939/main.c
|
|
@@ -140,9 +140,9 @@ static struct j1939_priv *j1939_priv_create(struct net_device *ndev)
|
|
static inline void j1939_priv_set(struct net_device *ndev,
|
|
struct j1939_priv *priv)
|
|
{
|
|
- struct can_ml_priv *can_ml_priv = ndev->ml_priv;
|
|
+ struct can_ml_priv *can_ml = can_get_ml_priv(ndev);
|
|
|
|
- can_ml_priv->j1939_priv = priv;
|
|
+ can_ml->j1939_priv = priv;
|
|
}
|
|
|
|
static void __j1939_priv_release(struct kref *kref)
|
|
@@ -211,12 +211,9 @@ static void __j1939_rx_release(struct kref *kref)
|
|
/* get pointer to priv without increasing ref counter */
|
|
static inline struct j1939_priv *j1939_ndev_to_priv(struct net_device *ndev)
|
|
{
|
|
- struct can_ml_priv *can_ml_priv = ndev->ml_priv;
|
|
+ struct can_ml_priv *can_ml = can_get_ml_priv(ndev);
|
|
|
|
- if (!can_ml_priv)
|
|
- return NULL;
|
|
-
|
|
- return can_ml_priv->j1939_priv;
|
|
+ return can_ml->j1939_priv;
|
|
}
|
|
|
|
static struct j1939_priv *j1939_priv_get_by_ndev_locked(struct net_device *ndev)
|
|
@@ -225,9 +222,6 @@ static struct j1939_priv *j1939_priv_get_by_ndev_locked(struct net_device *ndev)
|
|
|
|
lockdep_assert_held(&j1939_netdev_lock);
|
|
|
|
- if (ndev->type != ARPHRD_CAN)
|
|
- return NULL;
|
|
-
|
|
priv = j1939_ndev_to_priv(ndev);
|
|
if (priv)
|
|
j1939_priv_get(priv);
|
|
@@ -348,15 +342,16 @@ static int j1939_netdev_notify(struct notifier_block *nb,
|
|
unsigned long msg, void *data)
|
|
{
|
|
struct net_device *ndev = netdev_notifier_info_to_dev(data);
|
|
+ struct can_ml_priv *can_ml = can_get_ml_priv(ndev);
|
|
struct j1939_priv *priv;
|
|
|
|
+ if (!can_ml)
|
|
+ goto notify_done;
|
|
+
|
|
priv = j1939_priv_get_by_ndev(ndev);
|
|
if (!priv)
|
|
goto notify_done;
|
|
|
|
- if (ndev->type != ARPHRD_CAN)
|
|
- goto notify_put;
|
|
-
|
|
switch (msg) {
|
|
case NETDEV_DOWN:
|
|
j1939_cancel_active_session(priv, NULL);
|
|
@@ -365,7 +360,6 @@ static int j1939_netdev_notify(struct notifier_block *nb,
|
|
break;
|
|
}
|
|
|
|
-notify_put:
|
|
j1939_priv_put(priv);
|
|
|
|
notify_done:
|
|
diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c
|
|
index f23966526a885..56aa66147d5ac 100644
|
|
--- a/net/can/j1939/socket.c
|
|
+++ b/net/can/j1939/socket.c
|
|
@@ -12,6 +12,7 @@
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
+#include <linux/can/can-ml.h>
|
|
#include <linux/can/core.h>
|
|
#include <linux/can/skb.h>
|
|
#include <linux/errqueue.h>
|
|
@@ -453,6 +454,7 @@ static int j1939_sk_bind(struct socket *sock, struct sockaddr *uaddr, int len)
|
|
j1939_jsk_del(priv, jsk);
|
|
j1939_local_ecu_put(priv, jsk->addr.src_name, jsk->addr.sa);
|
|
} else {
|
|
+ struct can_ml_priv *can_ml;
|
|
struct net_device *ndev;
|
|
|
|
ndev = dev_get_by_index(net, addr->can_ifindex);
|
|
@@ -461,15 +463,8 @@ static int j1939_sk_bind(struct socket *sock, struct sockaddr *uaddr, int len)
|
|
goto out_release_sock;
|
|
}
|
|
|
|
- if (ndev->type != ARPHRD_CAN) {
|
|
- dev_put(ndev);
|
|
- ret = -ENODEV;
|
|
- goto out_release_sock;
|
|
- }
|
|
-
|
|
- if (!ndev->ml_priv) {
|
|
- netdev_warn_once(ndev,
|
|
- "No CAN mid layer private allocated, please fix your driver and use alloc_candev()!\n");
|
|
+ can_ml = can_get_ml_priv(ndev);
|
|
+ if (!can_ml) {
|
|
dev_put(ndev);
|
|
ret = -ENODEV;
|
|
goto out_release_sock;
|
|
diff --git a/net/can/proc.c b/net/can/proc.c
|
|
index 5ea8695f507eb..b15760b5c1cce 100644
|
|
--- a/net/can/proc.c
|
|
+++ b/net/can/proc.c
|
|
@@ -322,8 +322,11 @@ static int can_rcvlist_proc_show(struct seq_file *m, void *v)
|
|
|
|
/* receive list for registered CAN devices */
|
|
for_each_netdev_rcu(net, dev) {
|
|
- if (dev->type == ARPHRD_CAN && dev->ml_priv)
|
|
- can_rcvlist_proc_show_one(m, idx, dev, dev->ml_priv);
|
|
+ struct can_ml_priv *can_ml = can_get_ml_priv(dev);
|
|
+
|
|
+ if (can_ml)
|
|
+ can_rcvlist_proc_show_one(m, idx, dev,
|
|
+ &can_ml->dev_rcv_lists);
|
|
}
|
|
|
|
rcu_read_unlock();
|
|
@@ -375,8 +378,10 @@ static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v)
|
|
|
|
/* sff receive list for registered CAN devices */
|
|
for_each_netdev_rcu(net, dev) {
|
|
- if (dev->type == ARPHRD_CAN && dev->ml_priv) {
|
|
- dev_rcv_lists = dev->ml_priv;
|
|
+ struct can_ml_priv *can_ml = can_get_ml_priv(dev);
|
|
+
|
|
+ if (can_ml) {
|
|
+ dev_rcv_lists = &can_ml->dev_rcv_lists;
|
|
can_rcvlist_proc_show_array(m, dev, dev_rcv_lists->rx_sff,
|
|
ARRAY_SIZE(dev_rcv_lists->rx_sff));
|
|
}
|
|
@@ -406,8 +411,10 @@ static int can_rcvlist_eff_proc_show(struct seq_file *m, void *v)
|
|
|
|
/* eff receive list for registered CAN devices */
|
|
for_each_netdev_rcu(net, dev) {
|
|
- if (dev->type == ARPHRD_CAN && dev->ml_priv) {
|
|
- dev_rcv_lists = dev->ml_priv;
|
|
+ struct can_ml_priv *can_ml = can_get_ml_priv(dev);
|
|
+
|
|
+ if (can_ml) {
|
|
+ dev_rcv_lists = &can_ml->dev_rcv_lists;
|
|
can_rcvlist_proc_show_array(m, dev, dev_rcv_lists->rx_eff,
|
|
ARRAY_SIZE(dev_rcv_lists->rx_eff));
|
|
}
|
|
diff --git a/net/core/filter.c b/net/core/filter.c
|
|
index f0a19a48c0481..9358bc4a3711f 100644
|
|
--- a/net/core/filter.c
|
|
+++ b/net/core/filter.c
|
|
@@ -3552,11 +3552,7 @@ static int bpf_skb_net_shrink(struct sk_buff *skb, u32 off, u32 len_diff,
|
|
return 0;
|
|
}
|
|
|
|
-static u32 __bpf_skb_max_len(const struct sk_buff *skb)
|
|
-{
|
|
- return skb->dev ? skb->dev->mtu + skb->dev->hard_header_len :
|
|
- SKB_MAX_ALLOC;
|
|
-}
|
|
+#define BPF_SKB_MAX_LEN SKB_MAX_ALLOC
|
|
|
|
BPF_CALL_4(sk_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,
|
|
u32, mode, u64, flags)
|
|
@@ -3605,7 +3601,7 @@ BPF_CALL_4(bpf_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,
|
|
{
|
|
u32 len_cur, len_diff_abs = abs(len_diff);
|
|
u32 len_min = bpf_skb_net_base_len(skb);
|
|
- u32 len_max = __bpf_skb_max_len(skb);
|
|
+ u32 len_max = BPF_SKB_MAX_LEN;
|
|
__be16 proto = skb->protocol;
|
|
bool shrink = len_diff < 0;
|
|
u32 off;
|
|
@@ -3688,7 +3684,7 @@ static int bpf_skb_trim_rcsum(struct sk_buff *skb, unsigned int new_len)
|
|
static inline int __bpf_skb_change_tail(struct sk_buff *skb, u32 new_len,
|
|
u64 flags)
|
|
{
|
|
- u32 max_len = __bpf_skb_max_len(skb);
|
|
+ u32 max_len = BPF_SKB_MAX_LEN;
|
|
u32 min_len = __bpf_skb_min_len(skb);
|
|
int ret;
|
|
|
|
@@ -3764,7 +3760,7 @@ static const struct bpf_func_proto sk_skb_change_tail_proto = {
|
|
static inline int __bpf_skb_change_head(struct sk_buff *skb, u32 head_room,
|
|
u64 flags)
|
|
{
|
|
- u32 max_len = __bpf_skb_max_len(skb);
|
|
+ u32 max_len = BPF_SKB_MAX_LEN;
|
|
u32 new_len = skb->len + head_room;
|
|
int ret;
|
|
|
|
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
|
|
index c79be25b2e0c2..d48b37b15b276 100644
|
|
--- a/net/core/flow_dissector.c
|
|
+++ b/net/core/flow_dissector.c
|
|
@@ -1050,6 +1050,9 @@ proto_again:
|
|
key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
|
|
}
|
|
|
|
+ __skb_flow_dissect_ipv4(skb, flow_dissector,
|
|
+ target_container, data, iph);
|
|
+
|
|
if (ip_is_fragment(iph)) {
|
|
key_control->flags |= FLOW_DIS_IS_FRAGMENT;
|
|
|
|
@@ -1066,9 +1069,6 @@ proto_again:
|
|
}
|
|
}
|
|
|
|
- __skb_flow_dissect_ipv4(skb, flow_dissector,
|
|
- target_container, data, iph);
|
|
-
|
|
break;
|
|
}
|
|
case htons(ETH_P_IPV6): {
|
|
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
|
|
index bd4678db9d76b..6dff64374bfe1 100644
|
|
--- a/net/sunrpc/auth_gss/svcauth_gss.c
|
|
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
|
|
@@ -1825,11 +1825,14 @@ static int
|
|
svcauth_gss_release(struct svc_rqst *rqstp)
|
|
{
|
|
struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
|
|
- struct rpc_gss_wire_cred *gc = &gsd->clcred;
|
|
+ struct rpc_gss_wire_cred *gc;
|
|
struct xdr_buf *resbuf = &rqstp->rq_res;
|
|
int stat = -EINVAL;
|
|
struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
|
|
|
|
+ if (!gsd)
|
|
+ goto out;
|
|
+ gc = &gsd->clcred;
|
|
if (gc->gc_proc != RPC_GSS_PROC_DATA)
|
|
goto out;
|
|
/* Release can be called twice, but we only wrap once. */
|
|
@@ -1870,10 +1873,10 @@ out_err:
|
|
if (rqstp->rq_cred.cr_group_info)
|
|
put_group_info(rqstp->rq_cred.cr_group_info);
|
|
rqstp->rq_cred.cr_group_info = NULL;
|
|
- if (gsd->rsci)
|
|
+ if (gsd && gsd->rsci) {
|
|
cache_put(&gsd->rsci->h, sn->rsc_cache);
|
|
- gsd->rsci = NULL;
|
|
-
|
|
+ gsd->rsci = NULL;
|
|
+ }
|
|
return stat;
|
|
}
|
|
|
|
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
|
|
index d244616d28d88..4c8b281c39921 100644
|
|
--- a/sound/pci/hda/hda_intel.c
|
|
+++ b/sound/pci/hda/hda_intel.c
|
|
@@ -1023,8 +1023,12 @@ static int azx_prepare(struct device *dev)
|
|
struct snd_card *card = dev_get_drvdata(dev);
|
|
struct azx *chip;
|
|
|
|
+ if (!azx_is_pm_ready(card))
|
|
+ return 0;
|
|
+
|
|
chip = card->private_data;
|
|
chip->pm_prepared = 1;
|
|
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
|
|
|
flush_work(&azx_bus(chip)->unsol_work);
|
|
|
|
@@ -1039,7 +1043,11 @@ static void azx_complete(struct device *dev)
|
|
struct snd_card *card = dev_get_drvdata(dev);
|
|
struct azx *chip;
|
|
|
|
+ if (!azx_is_pm_ready(card))
|
|
+ return;
|
|
+
|
|
chip = card->private_data;
|
|
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
|
chip->pm_prepared = 0;
|
|
}
|
|
|
|
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
|
|
index 316b9b4ccb32d..58946d069ee59 100644
|
|
--- a/sound/pci/hda/patch_realtek.c
|
|
+++ b/sound/pci/hda/patch_realtek.c
|
|
@@ -5256,7 +5256,7 @@ static void alc_determine_headset_type(struct hda_codec *codec)
|
|
case 0x10ec0274:
|
|
case 0x10ec0294:
|
|
alc_process_coef_fw(codec, coef0274);
|
|
- msleep(80);
|
|
+ msleep(850);
|
|
val = alc_read_coef_idx(codec, 0x46);
|
|
is_ctia = (val & 0x00f0) == 0x00f0;
|
|
break;
|
|
@@ -5440,6 +5440,7 @@ static void alc_update_headset_jack_cb(struct hda_codec *codec,
|
|
struct hda_jack_callback *jack)
|
|
{
|
|
snd_hda_gen_hp_automute(codec, jack);
|
|
+ alc_update_headset_mode(codec);
|
|
}
|
|
|
|
static void alc_probe_headset_mode(struct hda_codec *codec)
|
|
@@ -8057,6 +8058,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|
ALC285_FIXUP_HP_GPIO_AMP_INIT),
|
|
SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
|
|
SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
|
|
+ SND_PCI_QUIRK(0x103c, 0x87f2, "HP ProBook 640 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
|
|
SND_PCI_QUIRK(0x103c, 0x87f4, "HP", ALC287_FIXUP_HP_GPIO_LED),
|
|
SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED),
|
|
SND_PCI_QUIRK(0x103c, 0x87f7, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP),
|
|
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
|
|
index 210fcbedf2413..4d82d24c7828d 100644
|
|
--- a/sound/soc/codecs/cs42l42.c
|
|
+++ b/sound/soc/codecs/cs42l42.c
|
|
@@ -401,7 +401,7 @@ static const struct regmap_config cs42l42_regmap = {
|
|
};
|
|
|
|
static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, false);
|
|
-static DECLARE_TLV_DB_SCALE(mixer_tlv, -6200, 100, false);
|
|
+static DECLARE_TLV_DB_SCALE(mixer_tlv, -6300, 100, true);
|
|
|
|
static const char * const cs42l42_hpf_freq_text[] = {
|
|
"1.86Hz", "120Hz", "235Hz", "466Hz"
|
|
@@ -458,7 +458,7 @@ static const struct snd_kcontrol_new cs42l42_snd_controls[] = {
|
|
CS42L42_DAC_HPF_EN_SHIFT, true, false),
|
|
SOC_DOUBLE_R_TLV("Mixer Volume", CS42L42_MIXER_CHA_VOL,
|
|
CS42L42_MIXER_CHB_VOL, CS42L42_MIXER_CH_VOL_SHIFT,
|
|
- 0x3e, 1, mixer_tlv)
|
|
+ 0x3f, 1, mixer_tlv)
|
|
};
|
|
|
|
static int cs42l42_hpdrv_evt(struct snd_soc_dapm_widget *w,
|
|
@@ -691,24 +691,6 @@ static int cs42l42_pll_config(struct snd_soc_component *component)
|
|
CS42L42_CLK_OASRC_SEL_MASK,
|
|
CS42L42_CLK_OASRC_SEL_12 <<
|
|
CS42L42_CLK_OASRC_SEL_SHIFT);
|
|
- /* channel 1 on low LRCLK, 32 bit */
|
|
- snd_soc_component_update_bits(component,
|
|
- CS42L42_ASP_RX_DAI0_CH1_AP_RES,
|
|
- CS42L42_ASP_RX_CH_AP_MASK |
|
|
- CS42L42_ASP_RX_CH_RES_MASK,
|
|
- (CS42L42_ASP_RX_CH_AP_LOW <<
|
|
- CS42L42_ASP_RX_CH_AP_SHIFT) |
|
|
- (CS42L42_ASP_RX_CH_RES_32 <<
|
|
- CS42L42_ASP_RX_CH_RES_SHIFT));
|
|
- /* Channel 2 on high LRCLK, 32 bit */
|
|
- snd_soc_component_update_bits(component,
|
|
- CS42L42_ASP_RX_DAI0_CH2_AP_RES,
|
|
- CS42L42_ASP_RX_CH_AP_MASK |
|
|
- CS42L42_ASP_RX_CH_RES_MASK,
|
|
- (CS42L42_ASP_RX_CH_AP_HI <<
|
|
- CS42L42_ASP_RX_CH_AP_SHIFT) |
|
|
- (CS42L42_ASP_RX_CH_RES_32 <<
|
|
- CS42L42_ASP_RX_CH_RES_SHIFT));
|
|
if (pll_ratio_table[i].mclk_src_sel == 0) {
|
|
/* Pass the clock straight through */
|
|
snd_soc_component_update_bits(component,
|
|
@@ -797,27 +779,23 @@ static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
|
|
/* Bitclock/frame inversion */
|
|
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
|
case SND_SOC_DAIFMT_NB_NF:
|
|
+ asp_cfg_val |= CS42L42_ASP_SCPOL_NOR << CS42L42_ASP_SCPOL_SHIFT;
|
|
break;
|
|
case SND_SOC_DAIFMT_NB_IF:
|
|
- asp_cfg_val |= CS42L42_ASP_POL_INV <<
|
|
- CS42L42_ASP_LCPOL_IN_SHIFT;
|
|
+ asp_cfg_val |= CS42L42_ASP_SCPOL_NOR << CS42L42_ASP_SCPOL_SHIFT;
|
|
+ asp_cfg_val |= CS42L42_ASP_LCPOL_INV << CS42L42_ASP_LCPOL_SHIFT;
|
|
break;
|
|
case SND_SOC_DAIFMT_IB_NF:
|
|
- asp_cfg_val |= CS42L42_ASP_POL_INV <<
|
|
- CS42L42_ASP_SCPOL_IN_DAC_SHIFT;
|
|
break;
|
|
case SND_SOC_DAIFMT_IB_IF:
|
|
- asp_cfg_val |= CS42L42_ASP_POL_INV <<
|
|
- CS42L42_ASP_LCPOL_IN_SHIFT;
|
|
- asp_cfg_val |= CS42L42_ASP_POL_INV <<
|
|
- CS42L42_ASP_SCPOL_IN_DAC_SHIFT;
|
|
+ asp_cfg_val |= CS42L42_ASP_LCPOL_INV << CS42L42_ASP_LCPOL_SHIFT;
|
|
break;
|
|
}
|
|
|
|
- snd_soc_component_update_bits(component, CS42L42_ASP_CLK_CFG,
|
|
- CS42L42_ASP_MODE_MASK |
|
|
- CS42L42_ASP_SCPOL_IN_DAC_MASK |
|
|
- CS42L42_ASP_LCPOL_IN_MASK, asp_cfg_val);
|
|
+ snd_soc_component_update_bits(component, CS42L42_ASP_CLK_CFG, CS42L42_ASP_MODE_MASK |
|
|
+ CS42L42_ASP_SCPOL_MASK |
|
|
+ CS42L42_ASP_LCPOL_MASK,
|
|
+ asp_cfg_val);
|
|
|
|
return 0;
|
|
}
|
|
@@ -828,14 +806,29 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
|
|
{
|
|
struct snd_soc_component *component = dai->component;
|
|
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
|
|
- int retval;
|
|
+ unsigned int width = (params_width(params) / 8) - 1;
|
|
+ unsigned int val = 0;
|
|
|
|
cs42l42->srate = params_rate(params);
|
|
- cs42l42->swidth = params_width(params);
|
|
|
|
- retval = cs42l42_pll_config(component);
|
|
+ switch(substream->stream) {
|
|
+ case SNDRV_PCM_STREAM_PLAYBACK:
|
|
+ val |= width << CS42L42_ASP_RX_CH_RES_SHIFT;
|
|
+ /* channel 1 on low LRCLK */
|
|
+ snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_CH1_AP_RES,
|
|
+ CS42L42_ASP_RX_CH_AP_MASK |
|
|
+ CS42L42_ASP_RX_CH_RES_MASK, val);
|
|
+ /* Channel 2 on high LRCLK */
|
|
+ val |= CS42L42_ASP_RX_CH_AP_HI << CS42L42_ASP_RX_CH_AP_SHIFT;
|
|
+ snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_CH2_AP_RES,
|
|
+ CS42L42_ASP_RX_CH_AP_MASK |
|
|
+ CS42L42_ASP_RX_CH_RES_MASK, val);
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
|
|
- return retval;
|
|
+ return cs42l42_pll_config(component);
|
|
}
|
|
|
|
static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
|
|
@@ -900,9 +893,9 @@ static int cs42l42_mute(struct snd_soc_dai *dai, int mute, int direction)
|
|
return 0;
|
|
}
|
|
|
|
-#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
|
|
- SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
|
|
- SNDRV_PCM_FMTBIT_S32_LE)
|
|
+#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
|
|
+ SNDRV_PCM_FMTBIT_S24_LE |\
|
|
+ SNDRV_PCM_FMTBIT_S32_LE )
|
|
|
|
|
|
static const struct snd_soc_dai_ops cs42l42_ops = {
|
|
@@ -1801,7 +1794,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
|
|
dev_dbg(&i2c_client->dev, "Found reset GPIO\n");
|
|
gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
|
|
}
|
|
- mdelay(3);
|
|
+ usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
|
|
|
|
/* Request IRQ */
|
|
ret = devm_request_threaded_irq(&i2c_client->dev,
|
|
@@ -1926,6 +1919,7 @@ static int cs42l42_runtime_resume(struct device *dev)
|
|
}
|
|
|
|
gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
|
|
+ usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
|
|
|
|
regcache_cache_only(cs42l42->regmap, false);
|
|
regcache_sync(cs42l42->regmap);
|
|
diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h
|
|
index 9e3cc528dcff0..866d7c873e3c9 100644
|
|
--- a/sound/soc/codecs/cs42l42.h
|
|
+++ b/sound/soc/codecs/cs42l42.h
|
|
@@ -258,11 +258,12 @@
|
|
#define CS42L42_ASP_SLAVE_MODE 0x00
|
|
#define CS42L42_ASP_MODE_SHIFT 4
|
|
#define CS42L42_ASP_MODE_MASK (1 << CS42L42_ASP_MODE_SHIFT)
|
|
-#define CS42L42_ASP_SCPOL_IN_DAC_SHIFT 2
|
|
-#define CS42L42_ASP_SCPOL_IN_DAC_MASK (1 << CS42L42_ASP_SCPOL_IN_DAC_SHIFT)
|
|
-#define CS42L42_ASP_LCPOL_IN_SHIFT 0
|
|
-#define CS42L42_ASP_LCPOL_IN_MASK (1 << CS42L42_ASP_LCPOL_IN_SHIFT)
|
|
-#define CS42L42_ASP_POL_INV 1
|
|
+#define CS42L42_ASP_SCPOL_SHIFT 2
|
|
+#define CS42L42_ASP_SCPOL_MASK (3 << CS42L42_ASP_SCPOL_SHIFT)
|
|
+#define CS42L42_ASP_SCPOL_NOR 3
|
|
+#define CS42L42_ASP_LCPOL_SHIFT 0
|
|
+#define CS42L42_ASP_LCPOL_MASK (3 << CS42L42_ASP_LCPOL_SHIFT)
|
|
+#define CS42L42_ASP_LCPOL_INV 3
|
|
|
|
#define CS42L42_ASP_FRM_CFG (CS42L42_PAGE_12 + 0x08)
|
|
#define CS42L42_ASP_STP_SHIFT 4
|
|
@@ -739,6 +740,7 @@
|
|
#define CS42L42_FRAC2_VAL(val) (((val) & 0xff0000) >> 16)
|
|
|
|
#define CS42L42_NUM_SUPPLIES 5
|
|
+#define CS42L42_BOOT_TIME_US 3000
|
|
|
|
static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = {
|
|
"VA",
|
|
@@ -756,7 +758,6 @@ struct cs42l42_private {
|
|
struct completion pdn_done;
|
|
u32 sclk;
|
|
u32 srate;
|
|
- u32 swidth;
|
|
u8 plug_state;
|
|
u8 hs_type;
|
|
u8 ts_inv;
|
|
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
|
|
index bd5d230c5df2f..609459077f9d9 100644
|
|
--- a/sound/soc/codecs/es8316.c
|
|
+++ b/sound/soc/codecs/es8316.c
|
|
@@ -63,13 +63,8 @@ static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(adc_pga_gain_tlv,
|
|
1, 1, TLV_DB_SCALE_ITEM(0, 0, 0),
|
|
2, 2, TLV_DB_SCALE_ITEM(250, 0, 0),
|
|
3, 3, TLV_DB_SCALE_ITEM(450, 0, 0),
|
|
- 4, 4, TLV_DB_SCALE_ITEM(700, 0, 0),
|
|
- 5, 5, TLV_DB_SCALE_ITEM(1000, 0, 0),
|
|
- 6, 6, TLV_DB_SCALE_ITEM(1300, 0, 0),
|
|
- 7, 7, TLV_DB_SCALE_ITEM(1600, 0, 0),
|
|
- 8, 8, TLV_DB_SCALE_ITEM(1800, 0, 0),
|
|
- 9, 9, TLV_DB_SCALE_ITEM(2100, 0, 0),
|
|
- 10, 10, TLV_DB_SCALE_ITEM(2400, 0, 0),
|
|
+ 4, 7, TLV_DB_SCALE_ITEM(700, 300, 0),
|
|
+ 8, 10, TLV_DB_SCALE_ITEM(1800, 300, 0),
|
|
);
|
|
|
|
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(hpout_vol_tlv,
|
|
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c
|
|
index 3db07293c70b6..2627910060dc1 100644
|
|
--- a/sound/soc/codecs/rt1015.c
|
|
+++ b/sound/soc/codecs/rt1015.c
|
|
@@ -209,6 +209,7 @@ static bool rt1015_volatile_register(struct device *dev, unsigned int reg)
|
|
case RT1015_VENDOR_ID:
|
|
case RT1015_DEVICE_ID:
|
|
case RT1015_PRO_ALT:
|
|
+ case RT1015_MAN_I2C:
|
|
case RT1015_DAC3:
|
|
case RT1015_VBAT_TEST_OUT1:
|
|
case RT1015_VBAT_TEST_OUT2:
|
|
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
|
|
index 1414ad15d01cf..a5674c227b3a6 100644
|
|
--- a/sound/soc/codecs/rt5640.c
|
|
+++ b/sound/soc/codecs/rt5640.c
|
|
@@ -339,9 +339,9 @@ static bool rt5640_readable_register(struct device *dev, unsigned int reg)
|
|
}
|
|
|
|
static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
|
|
-static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
|
|
+static const DECLARE_TLV_DB_MINMAX(dac_vol_tlv, -6562, 0);
|
|
static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
|
|
-static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
|
|
+static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -1762, 3000);
|
|
static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
|
|
|
|
/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
|
|
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
|
|
index d198e191fb0c9..e59fdc81dbd45 100644
|
|
--- a/sound/soc/codecs/rt5651.c
|
|
+++ b/sound/soc/codecs/rt5651.c
|
|
@@ -285,9 +285,9 @@ static bool rt5651_readable_register(struct device *dev, unsigned int reg)
|
|
}
|
|
|
|
static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
|
|
-static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
|
|
+static const DECLARE_TLV_DB_MINMAX(dac_vol_tlv, -6562, 0);
|
|
static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
|
|
-static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
|
|
+static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -1762, 3000);
|
|
static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
|
|
|
|
/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
|
|
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
|
|
index 41e5917b16a5e..91a4ef7f620ca 100644
|
|
--- a/sound/soc/codecs/rt5659.c
|
|
+++ b/sound/soc/codecs/rt5659.c
|
|
@@ -3426,12 +3426,17 @@ static int rt5659_set_component_sysclk(struct snd_soc_component *component, int
|
|
{
|
|
struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
|
|
unsigned int reg_val = 0;
|
|
+ int ret;
|
|
|
|
if (freq == rt5659->sysclk && clk_id == rt5659->sysclk_src)
|
|
return 0;
|
|
|
|
switch (clk_id) {
|
|
case RT5659_SCLK_S_MCLK:
|
|
+ ret = clk_set_rate(rt5659->mclk, freq);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
reg_val |= RT5659_SCLK_SRC_MCLK;
|
|
break;
|
|
case RT5659_SCLK_S_PLL1:
|
|
diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c
|
|
index a9b1b4180c471..93d86f7558e0a 100644
|
|
--- a/sound/soc/codecs/rt711.c
|
|
+++ b/sound/soc/codecs/rt711.c
|
|
@@ -895,6 +895,13 @@ static int rt711_probe(struct snd_soc_component *component)
|
|
return 0;
|
|
}
|
|
|
|
+static void rt711_remove(struct snd_soc_component *component)
|
|
+{
|
|
+ struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
|
|
+
|
|
+ regcache_cache_only(rt711->regmap, true);
|
|
+}
|
|
+
|
|
static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
|
|
.probe = rt711_probe,
|
|
.set_bias_level = rt711_set_bias_level,
|
|
@@ -905,6 +912,7 @@ static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
|
|
.dapm_routes = rt711_audio_map,
|
|
.num_dapm_routes = ARRAY_SIZE(rt711_audio_map),
|
|
.set_jack = rt711_set_jack_detect,
|
|
+ .remove = rt711_remove,
|
|
};
|
|
|
|
static int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
|
|
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
|
|
index 4d6ff81146228..4c0e87e22b97b 100644
|
|
--- a/sound/soc/codecs/sgtl5000.c
|
|
+++ b/sound/soc/codecs/sgtl5000.c
|
|
@@ -71,7 +71,7 @@ static const struct reg_default sgtl5000_reg_defaults[] = {
|
|
{ SGTL5000_DAP_EQ_BASS_BAND4, 0x002f },
|
|
{ SGTL5000_DAP_MAIN_CHAN, 0x8000 },
|
|
{ SGTL5000_DAP_MIX_CHAN, 0x0000 },
|
|
- { SGTL5000_DAP_AVC_CTRL, 0x0510 },
|
|
+ { SGTL5000_DAP_AVC_CTRL, 0x5100 },
|
|
{ SGTL5000_DAP_AVC_THRESHOLD, 0x1473 },
|
|
{ SGTL5000_DAP_AVC_ATTACK, 0x0028 },
|
|
{ SGTL5000_DAP_AVC_DECAY, 0x0050 },
|
|
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
|
|
index 05a085f6dc7ce..bf65cba232e67 100644
|
|
--- a/sound/soc/soc-core.c
|
|
+++ b/sound/soc/soc-core.c
|
|
@@ -31,6 +31,7 @@
|
|
#include <linux/of.h>
|
|
#include <linux/of_graph.h>
|
|
#include <linux/dmi.h>
|
|
+#include <linux/acpi.h>
|
|
#include <sound/core.h>
|
|
#include <sound/jack.h>
|
|
#include <sound/pcm.h>
|
|
@@ -1581,6 +1582,9 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
|
|
if (card->long_name)
|
|
return 0; /* long name already set by driver or from DMI */
|
|
|
|
+ if (!is_acpi_device_node(card->dev->fwnode))
|
|
+ return 0;
|
|
+
|
|
/* make up dmi long name as: vendor-product-version-board */
|
|
vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
|
|
if (!vendor || !is_dmi_valid(vendor)) {
|
|
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
|
|
index 10b3a8006bdb3..5ab2a4580bfb2 100644
|
|
--- a/sound/usb/quirks.c
|
|
+++ b/sound/usb/quirks.c
|
|
@@ -1521,6 +1521,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
|
|
case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */
|
|
case USB_ID(0x2912, 0x30c8): /* Audioengine D1 */
|
|
case USB_ID(0x413c, 0xa506): /* Dell AE515 sound bar */
|
|
+ case USB_ID(0x046d, 0x084c): /* Logitech ConferenceCam Connect */
|
|
return true;
|
|
}
|
|
|
|
diff --git a/tools/testing/selftests/net/forwarding/tc_flower.sh b/tools/testing/selftests/net/forwarding/tc_flower.sh
|
|
index 058c746ee3006..b11d8e6b5bc14 100755
|
|
--- a/tools/testing/selftests/net/forwarding/tc_flower.sh
|
|
+++ b/tools/testing/selftests/net/forwarding/tc_flower.sh
|
|
@@ -3,7 +3,7 @@
|
|
|
|
ALL_TESTS="match_dst_mac_test match_src_mac_test match_dst_ip_test \
|
|
match_src_ip_test match_ip_flags_test match_pcp_test match_vlan_test \
|
|
- match_ip_tos_test match_indev_test"
|
|
+ match_ip_tos_test match_indev_test match_ip_ttl_test"
|
|
NUM_NETIFS=2
|
|
source tc_common.sh
|
|
source lib.sh
|
|
@@ -310,6 +310,42 @@ match_ip_tos_test()
|
|
log_test "ip_tos match ($tcflags)"
|
|
}
|
|
|
|
+match_ip_ttl_test()
|
|
+{
|
|
+ RET=0
|
|
+
|
|
+ tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
|
|
+ $tcflags dst_ip 192.0.2.2 ip_ttl 63 action drop
|
|
+ tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
|
|
+ $tcflags dst_ip 192.0.2.2 action drop
|
|
+
|
|
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
|
+ -t ip "ttl=63" -q
|
|
+
|
|
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
|
+ -t ip "ttl=63,mf,frag=256" -q
|
|
+
|
|
+ tc_check_packets "dev $h2 ingress" 102 1
|
|
+ check_fail $? "Matched on the wrong filter (no check on ttl)"
|
|
+
|
|
+ tc_check_packets "dev $h2 ingress" 101 2
|
|
+ check_err $? "Did not match on correct filter (ttl=63)"
|
|
+
|
|
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
|
|
+ -t ip "ttl=255" -q
|
|
+
|
|
+ tc_check_packets "dev $h2 ingress" 101 3
|
|
+ check_fail $? "Matched on a wrong filter (ttl=63)"
|
|
+
|
|
+ tc_check_packets "dev $h2 ingress" 102 1
|
|
+ check_err $? "Did not match on correct filter (no check on ttl)"
|
|
+
|
|
+ tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
|
|
+ tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
|
|
+
|
|
+ log_test "ip_ttl match ($tcflags)"
|
|
+}
|
|
+
|
|
match_indev_test()
|
|
{
|
|
RET=0
|